How to define a relation between three tables and a junction table - yii2

Ok, I'm new to yii2 (and web development, as a matter of fact) so take it easy on me.
If I had a many-to-many relation between two tables, say, Environment and Category, and a junction table relEnvCat, I would have something like this:
public function getEnvironments()
{
return $this->hasMany(ENVIRONMENT::className(), ['PKENVIRONMENT' => 'FKENVIRONMENT'])
->viaTable('RELENVCAT', ['FKCATEGORY' => 'PKCATEGORY']);
}
But what should I do if I had three tables and a junction table. Exemple with their primary keys: CI(pkCi), Environment(pkEnvironment)and Context(pkContext).
Then I have a junction table, named relCiEnvCont with these foreign keys (fkCI, fkEnvironment, fkContext).
But, I don't know how to define this triple relation on yii... Can anybody help me?
As far as I know, which isn't much, all I can do is this:
class CI extends \yii\db\ActiveRecord
{
....
public function getRELCIENVCONTs()
{
return $this->hasMany(RELCIENVCONT::className(), ['FKCI' => 'PKCI']);
}
...
}
And that is not good at all... I'm thinking maybe these relations are far too complex for Active Records and I should ditch it and use query builder instead?

Related

Laravel Many To Many Merges Pivot?

I must be going insane or be really tired. So I have this situation where I get a collection of all the Roles assigned to the User. That part goes ok.... however I noticed something super strange.
I am using Laravel 8 and PHP8 (not the strange part).
For some reason, I do not get only the result from the other table but also pivot data is merged in. I can't tell why this is happening. Here is the example:
Relationship on user model:
/**
* Relationship with roles model.
*
* #return BelongsToMany
*/
public function roles(): BelongsToMany
{
return $this->belongsToMany(
Role::class,
'role_user',
'user_id',
'role_id'
)->withTimestamps();
}
Relationship on the Role model:
/**
* Relationship with users table.
*
* #return BelongsToMany
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(
User::class,
'role_user',
'role_id',
'user_id'
)->withTimestamps();
}
In the user model, I have this.
$this->roles->each(function($role) {
dd($role);
});
I was expecting to get a dump of related model however for some weird reason what I get is pivot table merged with the model:
"id" => 7 // this is the relation ID from the pivot table
"display_name" => "Administrator" // this is from Role model
"code" => "admin" // role model
"description" => "Super User - can do everything in the system. This role should only be assigned to IT staff member." // role model
"created_at" => "2021-10-01 11:00:00" // pivot table
"updated_at" => null // pivot table
"deleted_at" => null // pivot table
"role_id" => 1 // pivot table
"user_id" => 2 // pivot table
Either I am doing something very wrong or I am missing something very obvious. Does anyone know what in the world is happening here?
Just to add: the data is from both places but the result is just a Role model as expected.
Should I not just get the role model without the pivot stuff in it? It is overriding my role model fields.
EDIT:
Parenthesis seems to make a difference. The data is still merged. However, when I do it like this looks like data from end model is merged (so it overrides) to data from the pivot. So I get correct ID.
$this->roles()->each(function($role) {
echo $role;
});
But this gives me this weird pivot merged version with wrong ID.
$this->roles->each(function($role) {
echo $role;
});
I know what that was exactly. Without thinking I've added the ID column into the pivot table.
This ID from pivot was overriding my ID from my end model. After I've removed it the problem is gone.
I don't know why Laravel would by default add these fields and merge with pivot columns... I guess it just does that for no reason. Although I don't understand what's the point if there is a separate mechanism to access the pivot table (pivot relationship on the model).
This makes me think I did something wrong. But yeah, hope it helps. If anyone knows why Laravel automatically adds pivot stuff, let me know.

How can I create a list of model relationships in Laravel eloquent?

If I have a table called Master Index which has for example : Country Name = " USA ", and I want to have several models linked to it (GDP,Population,Inequality,etc) , how do I define that list of models in a field so that I can know which properties does that Country has?
Let me know if its possible, thanks!
You can read HERE
First you need to create table but make it in migration that the table you will create is base on the hierarchy example:
If you have Master Index as your general root of relationship young need to make it first in the migration. It will look like this on your Database > Migrations folder.
2020_07_14_0000001_create_master_indexs_table.php
2020_07_14_0000001_create_gdps_table.php
2020_07_14_0000001_create_populations_table.php
2020_07_14_0000001_create_inequalities_table.php
Master Index Model
You will specify the relationship it should look like this:
public function gdps() {
return $this->hasMany(Gdp::class); // if you have different foreign key you can specify it in the next argument return [$this->hasMany(Gdp::class, 'gdp_id');] like this
}
public function populations() {
return $this->hasMany(Population::class);
}
public function inequalities() {
return $this->hasMany(Inequality::class);
}
GDPS Model / Populations Model / Inequality Model
You need to specify where it belongs. It should be like this.
public function master_index() {
return $this->belongsTo(MasterIndex::class);
}
GDPS Migration / Population Migration / Inequality Migration
In your migration you should specify the foreign key.
If you're using Laravel 7.x you can do like this.
$table->foreignId('master_index_id')->constrained()->cascadeOnDelete();
If you're not familiar with the above code you can do also like this:
$table->unsignedBigInteger('master_index_id');
$table->foreign('master_index_id')->references('id')->on('master_indexs')->onDelete('cascade');

Laravel belongs to (more than 1 table)

has a rookie in laravel i don't no very well where and how to do this.
I have 3 tables that have almost the same fields, but they all have in comon ID
public function book(){
return $this->belongsTo('App\Models\table1', 'book_id', 'id');
}
this works but can i do something like this??
What should i use?
public function book(){
return $this->belongsTo('App\Models\table1','App\Models\table2', 'book_id', 'id');
}
Thanks for sharing your knowlege.
You may define 2 separate belongsTo functions
//...
public function book(){
return $this->belongsTo('App\Book', 'foreign_key', 'primary_key');
}
public function author(){
return $this->belongsTo('App\Author', 'foreign_key', 'primary_key');
}
//...
No, you can't create a single relationship with two tables in that way, that's not the way Laravel reads the method.
It would be pretty easy, and likely most clear for code readability to just make two separate relationships:
public function book(){
return $this->belongsTo('App\Models\table1', 'foreign_key');
}
public function otherBook(){
return $this->belongsTo('App\Models\table2', 'foreign_key');
}
But, it may be worth your time to consider the overall architecture of your models and tables first. If these tables share a common ID, that's going to get quite confusing over time, and carry a lot of overhead to make sure you don't over-write. Why not just make one table with some kind of flag to identify the different types of book?
Hope this helps.

Laravel eloquent: Save data with relationship

I created an invoice form which has a section where users can dynamically add (via jquery row add) items to be invoiced.
I need to save these data into two tables: Invoice and Invoiceitems. The two tables have one to many via MySQL relationship and Laravel models have hasMany and belongsTo relation assigned.
My question is how to save the data into Invoiceitems table.
In your App\Invoice, define your relationship with App\InvoiceItem as follows:
public function items()
{
return $this->hasMany(InvoiceItem::class);
}
In your App\InvoiceItem model, define your relationship with App\Invoice as follows:
public function invoice()
{
return $this->belongsTo(InvoiceItem::class);
}
To create an Invoice with many InvoiceItem, you would then do something like this:
$invoice->items()->saveMany([
new App\InvoiceItem(['title' => 'iPhone X']),
]);
Read more about Eloquent Relationships.

Laravel inserting into a three-way pivot table

Summary
I am building a music discovery service. My question is: How do I insert data into the three-way pivot table Tag_Track_User ?
Schema
I have this schema seen here at LaravelSD
It comprises of six main tables (and a few others):
Artists, Albums, Tracks, Tags, Users and Tag_Track_User
The Artists->Albums->Tracks relationship is straightforward and as you'd expect.
Tags, Tracks and Users all relate to one-another as no two can exist without the third.
Relationships
Artists hasMany() Albums
Albums hasMany() Tracks and belongsTo() an Artist
Tracks belongsTo() Albums
Tracks belongsToMany() Tags and belongsToMany() an Users
Tags belongsToMany() Tracks and belongsToMany() an Users
Users belongsToMany() Tags and belongsToMany() an Tracks
Models
User model
public function tags()
{
return $this->belongsToMany('Tag', 'tag_track_user', 'user_mdbid', 'tag_mdbid')->withPivot('track_mdbid');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tracks()
{
return $this->belongsToMany('Track', 'tag_track_user', 'user_mdbid', 'track_mdbid')->withPivot('tag_mdbid');
}
The Tag and Track model contain the same respective relationships.
Question
So my question is:
How do I insert data into the Tag_Track_User table? The tag_track_user table is a 3-way pivot table cointaining information about tracks that users have tagged.
You have to be logged in to tag a track (which means I have access to the user’s ID). The tracks ID is accessed as I am displaying it on the page where the form is contained. The tag on the other hand; if it already exists in the tags table, I want to get it’s ID and re-use that (as they are unique), if not, I want to create it, assign it an ID and insert that into the tag_track_user_table.
I need to check whether the Tag exists
If it does, get it's ID
Insert data into the Tag_Track_User table
Thank you
Any help I receive on this, is greatly appreciated.
Well:
$tag = Tag::firstOrCreate(array('text' => $tag_text));
TagTrackUser::create(array(
"tag_mdbid" => $tag->mdbid,
"track_mdbid" => $track->mdbid,
"user_mdbid" => Auth::user()->mdbid
));
Something like that? firstOrCreate does what the name says it does, the rest is pretty straightforward Eloquent.
Since seems that there is not an appropriate pattern in Laravel, the cleaner and easier way is to implement any three-pivot-relationships via a model dedicated to the pivot table:
class Track
public function trackTags()
{
return $this->hasMany('TagTrack');
}
...
class Tag
public function tagTracks()
{
return $this->hasMany('TagTrack');
}
...
class TagTrack
public function track()
{
return $this->belongsTo('Track');
}
public function tag()
{
return $this->belongsTo('Tag');
}
public function anotherRelationship(){
...
}
You can do:
$track->trackTags->myCustomPivotDataAndRelationship()
and in TagTrack you have freedom to add as many relationship and field I want
Note than you can still keep the many to many to use when you don't need to access pivot relationships