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.
Related
I'm fairly new to Laravel and have primarily focused most of my development time on Codeigniter in the past as this is what my job involves for the most part.
I'm currently building a client's website and also building a custom CMS (for both experience and particular needs of the client).
Currently I'm stuggling to figure out how to deal with relationships in Laravel/Eloquent as for example, I have a products table. Each product can have a type. I'm storing these types in a separate table so I've got better control over them in the future when the content starts to build up. All I need is a query to fetch all products with their associated type. In other frameworks, I could simply do this using a query builder to define the columns and joins, however due to the way Eloquent works, I'm struggling to find the way to do this!
Just for a bit of context, in the CMS, there will be a products datatable which will show all products in the system and one of the columns will be type, however I want to show the name of the type, not the id.
Probably me being stupid so feel free to point out something obvious!
What you're looking for is "Eager Loading" which is here in the documentation: https://laravel.com/docs/5.8/eloquent-relationships#eager-loading
In their example on the website, you can replace their "Book" with your "Product" and then their "Author" with your "Type" and you will achieve what you are trying to do.
If you want to load the relationships in the views, i.e. using Blade, you would need to do something like the following:
#foreach($products as $product)
<div> {{ $product->type->name }} </div>
#endforeach
you can search for with() function it will be useful in this :
in your example you need to relate product model with type model so in product you will add
`public function type()
{
return $this->hasOne(Type::class);
}`
and in type add
public function Product()
{
return $this->belongsTo(Product::class);
}
and your query will be
$result=Product::with("type")->get();
this will return the related type row with each related product row as
this example get user with profile
and you can get type name for each product row from
foreach($result as $res){
$type_name=$res->type->name;
}
I am using Laravel 5.2 and have some relationships between my models setup.
I have a Product model and a Customer model (a product has a customer).
I am using the following to get a list of customers, however I am also using soft deletes. If the customer has been soft deleted (the relation), I don't want to return the product.
How do I achieve this in Laravel?
$products = Product::with('customer')->get(); --want to say "where customer.deleted_at is null"
You have to call has on the query:
$products = Product::with('customer')->has('customer')->get();
As #Lock put it, use
$products = Product::with('customer')->has('customer')->get();
TIP: For the opposite - i.e to get only the products with deleted customers (doesn't make much sense here but you may find this handy in future), use below
$deleted=Product::with(['customer' => function ($q) {
$q->withTrashed();
}])->onlyTrashed()->get();
This is a weird implementation that I am trying to do in eloquent.
So the concept here is:
I am trying to create a dynamic relation for a product and product instance.
Category has multiple products. Products have multiple types. I decided to create multiple product types depending on what the product is for.
For eg: There can be Food and Clothes. Food is a different class and has properties totally different for it. There are other things that I need to differentiate for food and clothes.
I obviously have two different tables for these but a single category table that has product type slug to differentiate which category is for which product.
There is a Product class that has general description, slugs etc. everything that a general product has. The Food and the Clothes class are for instance of these products with specific details for the particular instance
I have defined relation of product and product instance like this.
function instance( $productInstance ) {
return $this->hasMany( get_class( $productInstance) );
}
I can get relation like this. $product->instance( $instance )->get();, gives me the exact relation that I need, based on what class instance I pass in the relation.
This worked very smoothly. Until I needed to load multiple relations
This is where I am stuck.
I cannot pass the the model in the instance in with function to eager load or load function to lazy load relation. This function does not work as relation
$category->with(['subCategory.products' => function( $q ) use ($productModel ) {
$q->with( 'instance' );
}])->get();
I cannot pass the instanceModel class to tell the relation what table to fetch from.
Is there a way that I can pass the modelInstance so that I can get the two level relation loaded into subCategory
Or a different implementation of this?
Any Suggestions??
I am making an e-commerce web application. The following are the things that I have planned.
products table to contain only few columns viz. id, name, code, SKU_no.
meta_information_products table containing columns viz. id, product_id [foreign key to products table], meta_title, meta_keywords, meta_description.
measurement_product table containing columns viz. id, product_id, width, height, weight, length
And similarly other tables in relation to products.
So my questions are:
Shall I create different Model for each of the points above and
then create the One-To-One relationship with products and
related table ? Or shall I create only one Model called Product and declare all the fields in just one table product.
If I create different models for Product, what should be the name of the method to be declared for creating the One-To-One relationship, and same with Product Model.
For example, consider the following: I have created two models called Product and MetaInformationProduct and I have created relationship with both the tables. Now how do I name the method for the following:
class Product extends Model {
...
public function methodName() {
$this->belongsTo('App\Product');
}
...
}
And for MetaInformationProduct:
class MetaInformationProduct extends Model {
...
public function methodName() {
$this->hasOne('App\Product');
}
...
}
I guess Stack Overflow is not the best place to ask questions of this kind, since your questions do not necessarily have right or wrong answers. There are multiple possible ways to go about constructing your app's data structure, and ultimately it all boils down to one's personal style of coding. So almost every developer would have an original 'right answer' to your questions.
Here's what I think. Why do you need three separate tables for all that data? As far as I can see, all three tables contain data related one-to-one to a single product. That means more complicated models and relations in development, and more resources and longer execution time in production. You could avoid all that if you create one products table with the following columns: id, code, SKU_no, name, title, description, width, height, length, weight. That will simplify your models significantly and reduce the number of queries trifold.
Additionally, I think I can spot a piece of bad practice in your table structure. In your current meta_information_products table you have a column named meta_keywords. I'm guessing that that field would contain multiple keywords of a product. This negates the benefit of relational database structure and will give you headaches down the road. Instead, I would create one products table as I described in the previous paragraph, then another table titled keywords, with the following columns: id, keyword. Lastly, you'd need a relational table titled keyword_product with the following columns: id, keyword_id, product_id. This gives you the ability for one product to have multiple keywords, and for one keyword to be assigned to multiple products. It's a well known 'Many to many' relation, and you can read more about it in the Laravel's official documentation.
In general, you should create one model for one database table, except for the relational tables. So in case you do as I would, you would then need two models: Product and Keyword. For its content, it's best that you refer to the link in the previous paragraph.
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.