3

I want to create a Class Table Inheritance model in CakePHP.

I would like to have a Model called something like ProductBase with the table product_bases to hold all the base information every product should have, like upc, price, etc.

Then have specific product type models extend that. For example ProductRing with the table product_rings to hold specific ring information like ring_size, center_stone, etc.

Then if I retrieve data directly from the ProductBase model, have it pull all types:

// pull all product types
$this->ProductBase->find('all'); 

Or find specific types only:

// pull only Rings or descendants of the Ring type.
$this->ProductRing->find('all'); 

Is anything like this possible in CakePHP? If not, what should I be doing instead?

What is the proper Cake way of doing something like this?

tereško
  • 58,060
  • 25
  • 98
  • 150
JD Isaacks
  • 56,088
  • 93
  • 276
  • 422

2 Answers2

1

I worked with CakePHP for two years, and found no satisfactory solution for this, so one day I wrote a solution for it. I built a new kind of ORM that work as a plugin on top of CakePHP 2.x. I called it "Cream".

It works similar to the entities of CakePHP 3.0, but in addition supports multi table inheritance. It also supports very convenient data structure browsing (lazy loading) and is very easy to configure. In my opinion it is more powerful than what CakePHP 3.0 offers right now. Data structure browsing works as follows:

$entity = new Entity('SomeModel', $somePrimaryKeyValue);
$foo = $entity->RelatedModel()->YetAnotherRelatedModel()->someProperty(); 

However, it is important to notice, that in Cream, each entity object is a compund of a series of models and primary key values that are merged together. At least in the case where model inheritance is used. Such a compound looks like:

[<'SomeConcreteModel', primaryKeyValueA>, <'IntermediaryModel', primaryKeyValueB>, <'BaseModel', primaryKeyValueC>]

It is important to notice that you can pick up this entity by any of the given model/primaryKeyValue combinations. They all refer to the same entity.

Using this you can also solve your problem. You can use standard CakePHP find methods to find all primary key values you want from the base model, or you can use the find methods models that inherit from it, and then go along and create the entities.

You set up the chain of inheritance/extension by simply writing in your model class:

public $extends = 'YourBaseModel';

In addition you also needs to setup an ordinary CakePHP relationship between the models (hasOne or belongsTo). It works just like in normal OOP, with a chain of models that inherit from their bases. If you just use vanilla CakePHP you will just notice that these models are related, but when you start using the Cream interface, all entities merge model/primaryKeyValue pairs into one single object.

Within my github repository there is a powerpoint file that explain most of the basic features.

https://github.com/erobwen/Cream

Perhaps I should fork the CakePHP project and make a pull request, but for now It is a separate repository. Please feel free to comment or participate in developing "Cream".

Also, for those suggesting that it is best to just "work with the CakePHP flow as intended" I would argue the following. Common estimates suggest that C programs are 2.5 times bigger than the C++ counterpart. Given that the only feature that separates these languages is the OOP with inheritance etc, we can deduce that the lack of proper OOP with inheritance etc requires the programmer to do 150% additional work with repetition code etc. Therefore I would argue that a proper model inheritance mechanism in CakePHP is very much needed. Cream is an attempt at this.

erobwen
  • 71
  • 3
1

You are referring to an ARC relationship (or at least a variation of it). Cake does not handle these types of relationships on the fly. This means you will have to implement your own logic to handle this.

The other option is to categorize the products. If the product can fit into multiple categories, then you will want a HABTM categories for each product. Otherwise, you can use a category column. I suspect it will be a HABTM you are looking for.

  • PRODUCTS: The table that holds the products.
  • CATEGORIES: The list of categories any given product can belong to.
  • CATEGORIES_PRODUCTS: The link between each product and their various categories.
  • TYPE: This is the flag that will define the type of product (i.e. ring, shoe, pants, etc.)

Then when you want ALL products, you query the products table. When you want a slice of the products (i.e. Rings) you select all the products that belongs to the RING category.

Now, we need to address the information about the product. For example, not all information will apply to every product. There are a number of ways to do this.

  1. You can build multiple tables to hold the product information. When you pull a product of a given type, you pull its companion information from the table.
  2. Store the information in a text field as serialized data. All of the information can be defined in a settings var and then you can use the serialized data to map to the information.

I hope this helps. Happy coding!

Community
  • 1
  • 1
Chuck Burgess
  • 11,600
  • 5
  • 41
  • 74