I'm trying to get my head around using polymorphic relationships for a many-to-many relationship between suppliers and products:
products
id
name
suppliers
id
name
product_supplier
id
product_id // belongsToMany easily takes care of this id
supplier_id // and this id
price // this can be fetched using withPivot('price')
deliverymethod_id // I'm having difficulties "joining" this one.
I'm confident in using belongsToMany(), I can easily do something like this:
public function products()
{
return $this
->belongsToMany('Supplier')
->withPivot('price');
}
But the catch here is joining to that third column in the relationship table:
deliverymethods
id
name
I am unsure how to do this. I've been told that Polymorphic Relationships are what I'm after however I'm unsure how to implement them for my situation.
http://laravel.com/docs/4.2/eloquent#many-to-many-polymorphic-relations
According to the documentation, I would have to rename my table columns to include *able_id and *able_type. This is really confusing.
I was expecting laravel to having something like belongsToMany('Supplier')->withAlso('Deliverymethod')
I'm afraid that method does not exist (yet?).
What I fall back to is manually filling in the 3rd relation:
public function products()
{
return $this
->belongsToMany('Supplier')
->withPivot('price', 'delivermethod_id');
}
Now I can access ->pivot->deliverymethod_id on every Product that I get via Supplier.
You could even add a function in your Product model that fills this in automatically:
Class Product ... {
protected $appends = array('deliverymethod');
public function getDeliverymethodAttribute()
{
return Deliverymethod::find($this->pivot->delivermethod_id);
}
Now every time you request a product via it's relation to the supplier, it automatically includes a deliverymethod attribute with the object in it.
(To have it not throw an error when you get a Product directly, just remove the $appends variable from the Product model and call the getDeliverymethodAttribute() method manually whenever you need it.)
Short explanation about polymorphic relations:
Polymorphic relations are for relations, where two models are related to a third model at the same time. So for example both a User and a Product can have a Picture of them. Now, it doesn't make sense to have two models for the pictures (UserPicture and ProductPicture), since they both have the same characteristics. This would be a perfect reason to use a polymorphic relation, where the Picture can both belong to a User or a Product.
However, in your case the Deliverymethod applies directly to the relation between Supplier and Product. So this is not where polymorphic relations would work, but it has instead to be done the way you did it.
Related
In my app, you can create lists of roles that are attached to contacts. So you can assign the contact "Bob" the roles of "Gardener" and "Pet Sitter". Then you can create the list "People" and add "Gardener (Bob)" and "Pet Sitter (Bob)" to it.
I have the following tables:
contacts
id
name
roles
id
name
contact_role (pivot)
id
contact_id
role_id
lists
id
name
contact_role_list (pivot)
id
contact_role_id
list_id
Everything was working smoothly until the second pivot table linked to the first pivot table. My pivot tables are (currently) not having any models so I'm not sure if there is a built-in feature to tackle this in Laravel or if I need to think differently.
I currently have this in my List model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(XYZ::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
Is this even close? What do I put where it says XYZ::class?
Ok, so the below is doing what I want, but is there an even better way to do it? The key to solving my problem was to create a Model for ContactRole and changing extends Model to extends Pivot.
I placed this in my List Model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(ContactRole::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
And this in my ContactRole Model:
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
Now I could reach the contact data by using something like this: List::first()->contact_roles->first()->contact
Any way to use with, pivot or similar to tidy this up even more? Thanks!
I like to approach these issues in terms of Models rather than pivots. I think many new Developers in Laravel get over obsessed with what's going on in the Database which is fine, but theres a lot of Magic going on so you can write very simple code that does a lot of Heavy lifting, so that being said if I fully understand your problem
You have a Contacts Model
This model can have many roles
so in your contacts Model you need a role relationship
public function roles()
{
return $this->belongsToMany(Roles::class);
}
next of course you have a role Model (pun intended)
your each role can have many list
public function lists()
{
return $this->hasMany(List::class)
}
then the idea is now that you have roles on contacts and lists on roles you should be able to have many lists through contact
public function lists()
{
return $this->hasManyThrough(List::class, Role::class);
}
I've done similar things before and for your description it seems like that's the approach you might need to take.
I'm actually trying to create an E-Commerce application in Laravel and have the following database layout...
TABLE PRODUCTS:
product_id PK,
material,
description,
brand_id,
category_id,
TABLE PRODUCTS_CHILDREN:
id,
sku,
color,
price,
size,
qty,
product_id (FK to products table)
Now I'm a beginner in Laravel, but I was thinking to build an E-Commerce application and just wanted solve this issue before going to far.
My question is, is there a way, when displaying the products, to also retrieve the products children?
My thought process was:
Products -> get( product_id, $product_id ) -> getChildren ( product_id, product_id );
I know the syntax is not correct, I was just wondering if this was a possible solution in Laravel - by chaining the query ( as I believe is common with the Laravel framework ).
I guess what I'm asking is, what would the blade syntax look when displaying the data?
Judging from what I've seen from tutorials, it seems this would work, but I just wanted to confirm. Thank you for any help!
Yeah it would work once you set up relationships by following the documentation.
For instance, in your example you would have two models, one for the products table and another for the products_children table (I would call them: Product and Variant respectively).
Between them you would have a 1:N relation (one product can have many variants, one variants belongs to one and only one product).
So you could model the relation as following:
Model: Product
class Product
{
// Other methods/properties...
public function variants()
{
return $this->hasMany(Variant::class);
}
}
Model: Variant
class Variant
{
// This is needed, otherwise Laravel would search for a
// table called as the pluralized model name's (eg: variants)
protected $table = 'products_children';
// Other methods/properties...
public function product()
{
return $this->belongsTo(Product::class, 'products_children');
}
}
Once you set up relations like so you can chain methods like your example:
// Assuming $id is the variable holding the product id you want to retrive
$product = Product::find($id);
$variants = $product->variants;
// You can now access the main Product properties, but you can also
// iterate through each Variant entity linked to that product.
Depending on the query use case, the last query might not be the optimal way to do it. You sometimes have to eager-load the relation for all of entities you are querying. If you want to look more in depth about this topic, refer to the official documentation.
Disclaimer: The code I wrote it's just a PoC and hasn't been tested. It was written to give a quick overview about how simple is to setup and use relationships among models.
I am designing shop solution in Laravel 5.2.
Now, I am stuck with a problem. I am creating self relation (one product can have many related products), like this
public function related()
{
return $this->belongsToMany(self::class, 'related', 'product_id', 'related_id');
}
Now, let's presume I got array of related products ids from form. How can I mass assign them? Seems I cannot do this without creating model for Related. Or can I?
The pivot table for many to many relation doesn't need model.
So you have to create pivot table "related" and make on it "product" function to set the relation.
and this link discuss that point: https://laravel.com/docs/5.2/eloquent-relationships#many-to-many.
You can use sync function like $product->related()->sync(/* product ids array */); to manage the relation.
I have the next tables:
pages
id
title
...
dynamic_table_1_infos
id
page_id
image_id
dynamic_field_1
dynamic_field_2
...
dynamic_table_2_infos
...
So there are "one to many" relationships.
Is there any way to use a general approach without creating a DynamicTable[No]Info model "on the fly" for each table?
And what if I will need some extra methods in these models?
The "Page" model will have many relationships with "dynamic_table_[no]_infos" tables. So I will probably need a general method for doing this.
(Has many dynamic_table_1_infos / has many dynamic_table_2_infos ...)
What I am trying to do is somehow inspired by Dupal`s content types.
If you want to save a single model data to multiple tables depending on the value of some model attribute, you'll need to override model's getTable() method to return the name of the table it should write to.
I'm not sure how you want to decide to which table Eloquent should save to - for example, if you had an attribute called segment in your mode, you could just do:
public function getTable() {
return 'dynamic_table_' . $this->segment . '_infos';
}
I would like to have a one to one relationship with a pivot table or by referencing an ID in a table.
I currently have a Films table that has a one to many relationship with a Stock table, each stock item needs a format, however I would like the formats to be a set list of formats so I created a Formats table that only has 2 columns ID and Name
Normally I would just add a Format_ID column to the Stock table however I'm unsure how this would work with the Eloquent ORM or if it's even possible / best practice
Sorry if this is hard to understand, cant quite figure out the best way of explaining it
The structure you desire is pretty standard practice. It's quite possible!
Which Eloquent relationship you'd use depends on the direction of the relationship. Each Stock has one Format (one-to-one). But each Format can be assigned to multiple Stock (one-to-many).
For the former, your Stock Eloquent model would have a hasOne() one-to-one relationship.
class Stock extends Eloquent {
public function format()
{
return $this->hasOne('Format');
}
}
For the latter, your Format eloquent model would have a hasMany() one-to-many relationship.
class Format extends Eloquent {
public function stock()
{
return $this->hasMany('Stock');
}
}
Note that having both of these defined is totally acceptable and normal. It really just depends on which direction you need your relationship to go. If you never need to look up what Stock belongs to a specific Format, you don't need the one-to-many relationship.
Also note that you may need to add a column key parameter if your column names are not easily guessable by Eloquent. E.g.:
return $this->hasOne('Format', 'my_format_id');