Dynamically set the table name in a "has many" relation model - laravel

In my database schema, I have multiple tables that hold generic data for objects, for instance I have a user table and a user_data, post table and post_data, and so. these *_data tables all hold a foreign key to the object and a pair of key-value. now in my laravel models I would like to have a single data models for these tables (rather than a model for every single one) and represent the has_many relation in a dynamic way where somehow I can define the table name according to the parent model. I think the parent model would have something like:
return $this->hasMany('data');
but I don't know how to express the inverse relation nor how to tell laravel which *_data table to use. so my question is, is it possible? and if so, how?

You have two options.
Either create a model for each data_* table and use the relation as stated with $this->hasMany('data'); and $this->belongsTo('User'); in the data table and the user table.
Or you can use Polymorphic relations, I personally prefer the polymorphic relations solution, more neat.

Related

When/why use the hasMany and belongsTo

In Laravel it is possible to use the hasMany() and belongsTo() methods in the Model to specify the relation between tables. This for one-to-many relations.
However in the migration files, this relation is also specified for the database by the
$table->foreign('userId')->references('id')->on('users')
Why does it to be specified double in Laravel?
Why does Laravel doesn't fetch the relationship from the database, and do we have to specify it double?
Laravel offers hasMany() and belongsTo() etc for quicker access to parent/child records between tables on the model level. For instance, you may access the child record with ->{attr}, which makes the child record as if an attribute of the parent record.
It also comes with other benefits, such as eager loading of child record by providing the relationship parameter into ->with() function.
In comparison, the usage of relation in migration files are to enforce relationship between tables on database level.

Creating a relationship from Pivot Table Field

I cannot find a solution, likely to how I am phrasing the question. I have a model called Invoice and it has the following relationship:
public function manifests(){
return $this->morphedByMany(carrier_manifest::class, 'invoiceable')->withPivot(['amount','rate_id','notes']);
}
As you can see, in the pivot, I have a table called rate_id. I would like to be able to add a relationship to another model based on the value of the rate_id (the model just being called ChargeRates). Is there a way I can do this in order to access a field in the ChargeRates model called label?
You'd want to actually implement the pivot table as a model if it has relationships and functionality on its own.
From a database concern, a many to many relationship between Table A and Table B is really just a one-to-many relationship between Table A and the pivot table and a one-to-many relationship between Table B and the pivot table.
Therefore, implementing your relationships with a pivot model using hasMany or morphMany is a way for you to accomplish what you're after.

Laravel Dynamic Eager Loading for Dynamic Relationships

Laravel Version: 5.5
PHP Version: 7+
Database Driver & Version: mysql 5.7+
Scenario:
I have a SaaS application that has flexible database structure, so its fields are bound to change, especially given it has a Json field (for any extra database structure to be created from client side of the application), including relationship based fields. so Account Table can have dynamically created employee_id field, and thus the need to access relationships dynamically
Problem:
I need to EagerLoad models based on this dynamic relationship. If I had something like this:
// Account Model
public function employee(){
return $this->belongsTo(App\Employee);
}
it would be easy. But what I have is this:
public function modelBelongsTo(){
return $this->belongsTo($dynamicClassName, $dynamicForeignKey);
}
Now if I eager load this, I'll get Account Model instance with related Employee on key modelBelongsTo. This is how Eloquent Names based on the function of eagerload. But after this I cannot use this function again to eagerload a second model because it'll just overwrite results on modelBelongsTo key.
Possible Solution Directions:
1) Can I Somehow change laravel's process to use a name I provide?
or
2) Can I write functions on the fly to overcome this so I'll write employee function on the fly?
or
3) Worst Case Scenario: I iterate over all records to rename their keys individually because I am using a pagination, it wouldn't that big of a deal to loop over 10 records.
Us a morph relationship
define the various dynamic classnames say
Employee
Boss
Morph works by having the related key and the table name stored in the parent table, it means to relate them you have to use a join or an orm and you cant have foreign key constraint on it as it links to different tables.
then have your account have morphs where
we have
Account
as top class
then we have
EmployeeAccount, BossAccount
which have their relation to boss and employee
then in Account have morphto relation call it specificAccount()
to which in its child morphs have the morph relation to Account
then add it to $with so to eager load them so when fetching account you could simply do
$account ->specificAccount
to get its morph child. which is nullable
This is totally dynamic such that if you have other classes in future you can just add and add the morph relationship. This may be applied to any reflection or runtime evaluated and loaded classes/code though it is not advisable to do this, as you can always edit code to create new functionality without affecting previous.

Laravel - Eloquent Models Relations, polymorphic or not?

I have this schema
All the relations here must be one-to-zero/one.
A user can be either an employee or a customer. The user_type ENUM gives me the type so I know where to go from there.
Then an employee can be either basic or a manager. The employee_type discriminator let's me know that.
How am I supposed to build the Eloquent Model relations?
Let's say I have a user that is an employee. I need to get it's common fields from the users table but also need to get common fields from employees table. Do I need to hard code, and know that when user_type=emp I need to select from the employees table? What if I need to add another user type later?
UPDATE
Would it make sense to change my schema into something simpler?
My problem is that by using, as suggested, polymorphic relations I would end up to something like this:
$user = new User::userable()->employable()->...
Would a schema in which I drop the employees table and have employee_managers and employee_basics linked straight to the users table?
this is an polymorphic relationship. but if you want to be easy, you need to fix some things.
in the table employees
- user_id
- employable_id
- employable_type enum(Manager, Basic) # References to the target model
.... this last two are for the polymorphic relation, this is the nomenclature
in the basics and managers table you could delete the user_id field, but you need an id field as increments type
and now in the model Employee you need to make this function
public function employable(){
return $this->morphTo();
}
I hope this works :)

GAS ORM many-many relation with attributes

I'm using CodeIgniter and I'm starting to work with gas orm.
One of my m-n-relationship-tables using a composite key has also some additional attributes to the releation.
For Example:
Table teams, Table employees, and a m-n table which binds them together + adding the attribute role
Is it possible to get the attribute using GAS ORM?
Yes, it is possible.
Simply create a new relationship in one of the two tables you are going to link with the pivot table that refers to the pivot table itself as a has_many relation. (But dont do the linking stuff in the model file, eg:
ORM::has_many('\\Model\\User\\Role')
instead of
ORM::has_many('\\Model\\User\\Role => \\Model\\Role')
See http://ellislab.com/forums/viewreply/1050559/ for exact the same question.

Resources