Laravel 5.5 many to many relationship with an intermediate table - laravel

Please help,
I have these relationship in laravel between ITEMS, SUPPLIERS and PURCHASE_ORDERS
As ITEMS and SUPPLIERS has many to many relationship, I created an intermediate table between them, called ITEM_SUPPLIER.
Now I need to make a many to many relationship between PURCHASE_ORDERS and the intermediate table ITEM_SUPPLIER.
How do I make the relationship?
Should I create an intermediate table between them, what's the best way to name it?

Add a model for pivot table ItemSupplier whth extra column id which extends Pivot
use Illuminate\Database\Eloquent\Relations\Pivot;
class ItemSupplier extends Pivot
{
public function purchaseOrder()
{
return $this->belongsToMany(PURCHASE_ORDERS::class, item_supplier_purchase_order);
}
}
As you see you need to create a new item_supplier_purchase_order pivot table and add the relationships
class PURCHASE_ORDERS extends Model
{
public function purchaseOrder()
{
return $this->belongsToMany(ItemSupplier::class, item_supplier_purchase_order);
}
}

Add id column to the item_supplier and create ItemSupplier model for the pivot table. Then create a new item_supplier_purchase_order pivot table and two belongsToMany() relationships between ItemSupplier and PurchaseOrder models.
Also, don't forget to use cascade deleting to delete records from new pivot table when a related record is deleted from item_supplier pivot table.

Related

Can we use an observer on the attach method in Laravel?

I would like to observe a pivot table in which, rows are created with an attach method in a specific model, is there a way to Observe that pivot table through the attach method that is responsible for creating rows?
after struggling some time, I came to answer my question,
so in order to observe a table whose rows are created by the attach method, we will need to do 3 things
1- we will need to create a model that extends
$Illuminate\Database\Eloquent\Relations\Pivot
2- Connect the model to the database table with this line:
protected $table = 'data_base_table_name';
3- use the method 'using' at the end of the BelongsToMany relationship in each model that is related to the pivot table
Example:
let's say we have a model called Student and another one called Group, we have also a pivot table called group_students that is filled with the attach method since we have a student BelongsToMany groups and Group BelongsToMany Students,
we will need to create a model named GroupStudent that extends
Illuminate\Database\Eloquent\Relations\Pivot
and link it to the group_students by adding the following line in the GroupStudent Class:
protected $table = 'group_student'
After that, we will need to add the using method The BelongsToMany relations in the Student Model and the Group Model like the following:
public function students()
{
return $this->BelongsToMany(Student::class)->using(GroupStudent::class);
}
and
public function groups()
{
return $this->belongsToMany(Group::class)->using(GroupStudent::class);
}
And here we go, now whenever I create a row in the group_students table through the attach method, this will be observed and the method created will be executed.

Laravel - Eloquent relation - many-to-many - get intermediate table columns

I have a question about Laravel Eloquent Relations.
I have the following table situation:
Table guests:
id
name
...
Table landing_pages:
id
name
...
A guest can have several landing pages. And a landing page will have multiple guests.
So I thought, I can use a many-to-many relationship there and I created a new table
Table guests_landing_pages:
id
guest_id
landing_page_id
...
I would be able to use this the following way:
In guest Model I can do this, to create the many-to-many relationship:
public function landing_pages()
{
return $this->belongsToMany(\App\Models\LandingPage\LandingPage::class, 'guests_landing_pages','landing_page_id','guest_id');
}
... and the other way round in landing_page model.
But actually the table guests_landing_pages contains more data than just the guest_id and landing_page_id relation.
There are several other fields in it:
Table guests_landing_pages:
id
guest_id
landing_page_id
identifier_token
max_persons
answer
...
My question is now, how can I realize this best. If I would use the many-to-many relation as described above, I will not be able to access the fields in the intermediate table, won't I?
Or will the best solution to this to create a GuestLandingPages model with all the fields and create hasMany relations to/in both?
Laravel Eloquent has features for retrieving intermediate columns.
public function landing_pages()
{
return $this->belongsToMany(\App\Models\LandingPage\LandingPage::class, 'guests_landing_pages','landing_page_id','guest_id')
->withPivot('max_persons', 'answers');
}

Laravel Relationships with 3 tables problem

I don't understand how to connect three tables in Laravel.
users> id, ...
groups> id, ...
group_user> id_group, id_user
I want to return all groups to me auth()->user()->groups.
Thanks in advance.
According to your explanation, group_user table holds many-to-many relationship between Group and User model. In case of a many-to-many relationship, you actually don't need a GroupMember model. This kind of table which holds many-to-many relationship is called pivot table. Read more from the Official Documentation
The first argument is the Model you are relating to, the second one is the name of the pivot table, and third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to
User.php
class User
{
public function groups()
{
return $this->belongsToMany(Group::class,'group_user','id_user','id_group');
}
}

Laravel delete all belongsToMany relations in belongsToMany relation

I have a Tournament model which contains a belongsToMany relationship with a Session model:
class Tournament extends Model{
public function sessions(){
return $this->belongsToMany(Session::class, 'tournament_has_sessions');
}
}
Then my sessions model contains a belongsToMany relationship with the User model:
class Session extends Model{
public function users(){
return $this->belongsToMany(User::class, 'session_has_users');
}
}
Now when I delete a Tournament, I want to delete all sessions and all information in the session_has_users table with it.
I have tried:
$tournament->sessions()->with('users')->delete(); -- < This
$tournament->sessions()->delete();
$tournament->users()->detach();
$tournament->delete();
But it does't work. The data in the session_has_users table persists
I realize i could do something like this:
DB::table('session_has_users')->whereIn('session_id', $this->sessions()->pluck('id'))->delete();
But is there a more efficient/handy (or even alternative if not more efficient) way to accomplish this?
Using RDBMS Referential Actions on the Foreign Key
In the database schema, you should define the foreign key with the ON DELETE CASCADE action. This will automatically delete the related records when the referenced id is deleted.
(See dbudimir's answer for the example lines from a Laravel migration file)
Using Eloquent to Detach All Related Models
If you aren't using foreign keys or your database lacks the support for referential actions, you can use this:
$tourament->sessions()->sync([]);
The sync method accepts an array of IDs to place on the intermediate table. Any IDs that are not in the given array will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given array will exist in the intermediate table:
https://laravel.com/docs/5.5/eloquent-relationships#updating-many-to-many-relationships
Providing an empty array should then remove all the relations.
In the table 'tournament_has_sessions' you can set onDelete('cascade') like this
$table->integer('tournament_id')->unsigned()->nullable();
$table->foreign('tournament_id')->references('id')->on('tournaments')->onDelete('cascade');
$table->integer('session_id')->unsigned()->nullable();
$table->foreign('session_id')->references('id')->on('sessions')->onDelete('cascade');
And when delete tournaments automaticly deleted all records in this table
you can use any of these:
$tourament->sessions()->detach();
or
$tourament->sessions()->sync([]);
or you can define the foreign key with the ON DELETE CASCADE like the answers above

Laravel Eloquent ORM - Many to Many Delete Pivot Table Values left over

Using Laravel, I have the following code
$review = Review::find(1);
$review->delete();
Review has a many to many relationship defined with a Product entity. When I delete a review, I'd expect it to be detached from the associated products in the pivot table, but this isn't the case. When I run the code above, I still see the linking row in the pivot table.
Have I missed something out here or is this the way Laravel works? I'm aware of the detach() method, but I thought that deleting an entity would also detach it from any related entities automatically.
Review is defined like this:
<?php
class Review extends Eloquent
{
public function products()
{
return $this->belongsToMany('Product');
}
}
Product is defined like this:
<?php
class Product extends Eloquent
{
public function reviews()
{
return $this->belongsToMany('Review');
}
}
Thanks in advance.
The detach method is used to release a relationship from the pivot table, whilst delete will delete the model record itself i.e. the record in the reviews table. My understanding is that delete won't trigger the detach implicitly. You can use model events to trigger a cleanup of the pivot table, though, using something like:
protected static function booted()
{
static::deleting(function ($review) {
$review->product()->detach()
});
}
Also, I would suggest that the relationship would be a one to many, as one product would have many reviews, but one review wouldn't belong to many products (usually).
class Review extends \Eloquent {
public function product()
{
return $this->belongsTo('Product');
}
}
class Product extends \Eloquent {
public function reviews()
{
return $this->hasMany('Review');
}
}
Of course, this would then require that you tweak your database structure. If you wanted to leave the database structure and your current relationships as they are, the other option would be to apply a foreign key constraint on the pivot table, such that when either a review or product is removed, you could cascade the delete on the pivot table.
// Part of a database migration
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('review_id')->references('id')->on('reviews')->onDelete('cascade');
Edit: In adding the constraint, you push the cleanup work onto the database, and don't have to worry about handling it in code.
Simpler Steps:
In this example an Account has many Tags:
To delete the Tags, then the Account do this:
// delete the relationships with Tags (Pivot table) first.
$account->find($this->accountId)->tags()->detach();
// delete the record from the account table.
$account->delete($this->accountId);
On the Pivot Table make sure you have ->onDelete('cascade');
$table->integer('account_id')->unsigned()->index();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->integer('tag_id')->unsigned()->index();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
$review->product()->sync([]) also works.
However $review->product()->detach() is much more explicit.
public function destroy($id)
{
$review = Review::find($id);
$review ->tagged_users()->detach();
return $review ->delete();
}
also works
If that way doesn't solve your problem, you can delete Pivot table records to using the DB option like below ;
DB::table('any_pivot_table')->where('x_column', $xParameter)->delete();
You can solve the problem just like this.
Enjoy your coding !
i guess you have a error in your models relationship conception, the product has many reviews but the review associated with one product so you have here one to many relationship.
but in general the answer in the general case will be using:
$product->reviews()->sync([]);

Resources