views:

115

answers:

4

Hello,

I have a ecommerce site that has 2 types of products: books & seminars participations. They are different, and have different attributes. I am curious how would you model this in the DB and as models (since you cannot inherit multiple classes)

Right now i have something like: DB

products (id, name ....)
seminars (id, title, date ....)
cart (id, session_id ...)
cart (id, cart_id, type, id_model) the type is product OR seminar

as for models i have a

cart_item_abstract
cart_item_product -> cart_item_abstract
cart_item_seminar -> cart_item_abstract
cart_order_product -> cart_item_product
cart_order_seminar -> cart_item_seminar

But that means i have to duplicate some of the code required by order objects.

A: 

One approach would be to simply create a product model, which things like books and seminars reference. So each record for both books and seminars has a product_id reference.

As far as your shopping-cart code is concerned, you mostly just care about a product_id, title, and price.

Your catalog code cares more about the differences, but you handle browsing/display differently for books than you do for seminar registrations. But both have a product ID, so if your user "add to cart"s, you just tell the cart "add product id #123". A little clever thinking about LEFT JOINs and conditionals should make it easy for the cart to figure out the title and cost for any given product ID, regardless of it's type.

Hope this helps.

timdev
so are you sugesting to have a single table ? otherwise i could not know if that id is for a product or seminar
solomongaby
Three tables: Products, Books, Seminars. Product contains any shared data (title, price, etc). Books and Seminars tables hold specific stuff, and have a product_id. SELECT * FROM Products LEFT JOIN Seminars LEFT JOIN Books WHERE product_id = 123 will basically get you whatever you need. You might have to do some conditional coding in your display code, but it should be pretty easy to handle books one way, and seminars another for display purposes, while treating them the same for cart-logic purposes.
timdev
A: 

In your DB couldn't you only have two tables, one for products(id, type, price, title) then and attributes(id, product_id, attribute, description)? That way you could have a one to many association between your products to attributes.

In your shopping cart model you could have just have a get-product() method that would return just the product id, title and price. In your model for actually displaying the products in your catalogue you could also have a get-product() method (or a get-product-attribute($product-id) ) method, but have that return the values from the products table and the attributes table with a left join as tim suggested.

iangraham
i tought about it .. but this would complicate the selects quite a lot, for example searching and filtering, and i fear it would have an impact on both performance and make the code more complicated to maintain
solomongaby
EAV is rightly considered an anti-pattern in database design.
Noah Goodrich
+3  A: 

You should google for Inheritance Mapping", it all boils down to these choices:

  • SINGLE_TABLE: Table-per-class-hierarchy, in this scenario the classes of one class erarchy are all mapped to one table.
  • JOINED: Table-per-subclass, in this strategy each subclass will have its own table. To retrieve an object from the database the superclass and subclass tables are joined. This also applies to subclasses of subclasses.
  • TABLE_PER_CLASS: table-per-class, each concrete class is stored in its own table. All properties (including inherited) are mapped to the table of the concrete class.

The selection depends on specific requirement - performance vs. simplicity, etc.

queen3
+1 for good, general response about how to think about the problem
timdev
A: 

Have you considered that your inheritance pattern may be flawed?

I would think that a cart could contain one or more items and that an order would be created once a user had completed the purchase of all items in the cart. So an order would likewise contain multiple items.

With that in mind you could use Inheritance Mapping to create a single table that holds all of the values that are common between item types as well as a type field (seminar, product). Then you create a table for each type to hold the unique values.

Your base item class should implement a set of polymorphic interfaces that will return the proper values such as Item Name, Item Description but will require different implementations in the various subclasses.

As an example, I recently worked on a project where I needed to return the user name for a name if the user was an admin or employer and I needed to return the first and last name concatenated if the user was a student. I created a function _getName() that returned the appropriate value and the code using it (in this case the view) didn't have to do any contextual processing.

It should be likewise with your Cart and Order classes. They should be able to interact with the Product and Seminar classes without having to perform any contextual processing.

Noah Goodrich