Loach's avatar
Level 11

Setting up Ecommerce Database

Hello, This is a bit of a long post. I am modeling my database after the image on this stackoverflow thread. http://stackoverflow.com/questions/17711324/database-structure-for-customer-table-having-many-orders-per-customer-and-many

I am mapping that database as follows:

Customer = User (in my app) Order = Order (in my app) Product = Song(in my app) OrderItem = SongOrder(in my app)

I am not sure I am mapping all this out correctly with relationships, and getting the required data seems messy.

class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
      --SNIP--
    public function orders()
    {
        return $this->hasMany('App\Order');
    }

}

class Order extends Model {

    public function user()
    {
        return $this->belongsTo('App\User');
    }

    public function songorders()
    {
        return $this->hasMany('App\SongOrder');
    }

}

class Song extends Model {

    public function artist()
    {
        return $this->belongsTo('App\Artist');
    }

    public function songorders()
    {
        return $this->hasMany('App\SongOrder');
    }

}

class SongOrder extends Model {

    public function song()
    {
        return $this->belongsTo('App\Song');
    }

    public function order()
    {
        return $this->belongsTo('App\Order');
    }

}

For the migrations I do have the foreign key setup for the hasMany relationships for all models like so: (for example).

public function up()
    {
        Schema::create('orders', function(Blueprint $table)
        {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')
                  ->references('id')
                  ->on('users');
            $table->string('ordernumber');
            $table->timestamps();
        });
    }

So first off is this the correct way to set all that up according to the image? Secondly this is how I am retrieving the songs the user has ordered and it just feels messy.

$user = \Auth::user();
$orders = $user->orders;
foreach($orders as $order){
        $songs = App\SongOrder::where('order_id', $order->id)->get();
        echo '<h2>Songs</h2>';
        echo $songs;
        echo '<hr/>';
}
0 likes
3 replies
Loach's avatar
Level 11

After some further investigation, I have the following. It seems to work. What I am most interested in now is if I have the relationships setup right. The belongsTo and hasMany relationships?

    $user = \Auth::user();
    $orders = $user->orders;
    foreach($orders as $order){
        $songs = $order->songorders()->get();

        foreach($songs as $song) {
            $theSong = $song->song()->get();
            echo $theSong;
        }

    }
martinbean's avatar

@Loach I wouldn’t directly relate a Song model to an Order model. What happens if you expand your store to include say, videos? Or even something that isn’t a song like an audiobook?

Instead, you could create an interface that you could then apply to your concrete classes. I have a Purchasable interface or similar in e-commerce applications which mandates a couple of methods:

interface Purchasable {
    public function getIdentifier();
    public function getName();
    public function getPrice();
}

You can then apply it to your Song model:

class Song extends Model implements Purchasable {
    public function getIdentifier()
    {
        return $this->getKey();
    }

    public function getName()
    {
        return $this->name;
    }

    public function getPrice()
    {
        return $this->price;
    }
}

I then have my OrderItem with a polymorphic association so I can add any type of purchasable item to an order. A migration for the table may look like this:

$table->increments('id');
$table->integer('order_id')->unsigned();
$table->morphs('purchasable');
$table->integer('quantity')->unsigned();

$table->foreign('order_id');
      ->references('id')
      ->on('orders')
      ->onDelete('cascade');
Loach's avatar
Level 11

Thanks martinbean for the suggestion. It is much cleaner.

Please or to participate in this conversation.