i'm currently working with Laravel and I'm struggling with the fact that every model needs to extend from Eloquent and I'm not sure how to implement a model Hierarchy (with different tables)
For Example:
Let's say I have an abstract model Tool
, and then a Model Hammer
and a Model Screwdriver
that extend from Tool.
Now, Tool would extend Eloquent ... BUT, there is NO Table for Tools, there is a table for Hammers and another Table for Screwdrivers, because they have different attributes.
How do I specify that Hammer has a table and Screwdriver has a table when they both extend Tool? And how can I use Eloquent to call, For Example, All Tools?
Like:
Tools::all()
This Should bring all Hammers and Screwdrivers because they are all Tools
Is this possible using Eloquent?
I found a bug (feature?) where Laravel 5 looks up the incorrect class if ParentClass and ChildClass have the same $table string. So if you call ParentClass::all() in certain situations it can return ChildClass instances in the collection!!
The Alpha's answer led me to a workaround where you create the following class structure:
This seems to force Laravel to do the correct lookup when you call ParentClass::all() or ChildClass::all() since their common ancestor doesn't have a table declared. Just treat BaseObject as ParentObject and that way you don't have to muddy your inheritance concept with database details that shouldn't be relevant. I have not stress-tested this thoroughly yet, so be sure to note the reason for this class's existence in your code for future debugging breadcrumbs.
Even though I like the Polymorphic Relations (PR) approach slightly better than the Single Table Inheritance (STI), it still does not feel anything like a true inheritance approach. From the domain (e.g. a UML Class Diagram) point of view, it is like trying to use a composition relationship instead of inheritance.
From a database consistency point of view the polymorphic relation by itself is already a very weird solution in Laravel (IMHO). As there can be no single field that is a foreign key to multiple tables, this can lead to joining ID's that should not be joined. And inverse relationships that are not obeyed.
Although I'm not actually describing a solution to the problem, I'd propose a different approach than PR and STI. This solution would be similar to Hibernate's table-per-subclass approach. I think that Dauce's extension to Eloquent is going in the same direction, except there seem to be a few implementation issues still.
From a database point of view, a table per subclass would also mean that the super-class contains one column per direct subclass. Then you can put foreign key constraints on the (non-null) id's and properly use the relationships. However, there should still be some extra logic in Laravel's magic Eloquent class that turns the requested object into the right type.
So for me, functionally, the Eloquent models should properly inherit on the PHP side, while the database can still use the foreign key constraints.
If your
Tool
(abstract
) model doesn't have anytable
mapped to it then you don't need to useTool::all
and you can't directly use/instantiate anabstract
model but you may use an thatabstract
model as a base class like this:Use
Hammer
andScrewdriver
directly but never theTool
model/class because it's anabstract
class, for example:Or maybe something like this:
The only ORM in PHP that I know that does a one table per class hierarchy is Doctrine. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html. And I believe that it can map this kind of hierarchy you're planning to use, an abstract superclass that can access all subclasses.
To integrate Doctrine to Laravel, I suggest to use laravel-doctrine package which you have all needed info in this website http://www.laraveldoctrine.org/.