Adding an extra parameter to eloquent relation - php

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??

Related

how to show this one to many relation data in hierarchical order in laravel?

Need tips for displaying this one to many related data on a heirarchical
order in laravel view page. Here vegetable, groceries are category and
other's are there related product.
Here is the image for data.
Need to show this every 1 to many related data on a hierarchical order on
a single view page. I want to loop through these array and
want my result like tree view:
Based on your given information I will try to help you as much as possible.
Looking at your image, shows me that you already have duplicated data in your database. Where possible try to use different tables for different entities. In this case your Category is used over and over again. So try to create a new table for it.
That being said, you still have 2 options for this. A one to many or many to many relationship between your ingredient and category. This depends on what you want, do you want an ingredient to be able to have one or many categories. I have added a image below to show the 2 types of database structures for this. (Left: One to many, Right: Many to many)
You will have to create 2 models for both the Category and the Ingredient and make sure that you can use those models to store and receive data from your database. If you would like some more information about models take a look here:
https://laravel.com/docs/6.x/eloquent#defining-models
After creating your models, you should define your relation methods inside your models. This is different based on the choice you have made. (many to many or one to many).
One to many:
In the one to many example an ingredient can have only 1 category. Therefor you have to create a method in your ingredient called category and this should return a HasOne:
/**
* #return HasOne
*/
public function category(): HasOne
{
return $this->hasOne(Category::class);
}
Then your category can have multiple Ingredients so your Category should get a method called ingredients and it must return a BelongsToMany:
/**
* #return BelongsToMany
*/
public function ingredients(): BelongsToMany
{
return $this->belongsToMany(Ingredient::class);
}
Many to many:
In a many to many relation your category will be the same because it still has many ingredients. Only the ingredient will change because it not also has many categories. The method for the categories will now just be the same as the one for the ingredients:
/**
* #return BelongsToMany
*/
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
That is that! Now how to use this (and hopefully the answer to your question). When you have a category like:
$category = Category::first();
You are able to use the ingredients method to get all the ingredients having this category:
$category = Category::first();
$ingredients = $category->ingredients;
This will give you a Collection with all the ingredients of this category.
You could also use this for every category.
$categories = Category::all(); //Get all categories
foreach ($categories as $category) {
$ingredients = $category->ingredients; //Get all ingredients
}
Extra:
Note that i'm not using the () after ingredients, this has to do with the mysql queries that are executed (Without () it will look if it has results (if yes it will use these of no it will query your database and then use the results)).

How to grab children from parent in E-Commerce application

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.

Laravel Voyager: Dropdown that shows conditional relations

I am using Laravel with Voyager for the back-end.
I made a relationship between Posts model and Categories model.
When adding a new Post, I can choose an according category using a dropdown.
How can I make this dropdown show Categories according to certain conditions? (Let's say, only subcategories)
You can easily filter the shown relationship options by defining a local scope in the foreign model. For example, if you want to only show active entries of categories in a relationship input, create a scope as given in your Category model,
public function scopeSubcategories($query){
return $query->where('parent_id', '!=' , null);
}
Now, go to the BREAD builder and add the following to the relationship options
{
"scope": "subcategories"
}
The value is the name of your scope-method without the word scope.
The value for scopeSubcategories() is subcategories.

How to set up database relation so that a category may belong to multiple parent category

I am currently using Laravel (PHP framework) in order to construct an ecommerce site.
The site will have a lot of categories(for products) of which there is ruffly 100-150 and will probably be more as there will be a backend site to add more.
Some times it will be necessary for a category to appear in more than 1 parent category on the site.
Category Relationships I am trying to achieve:
A category can have many child categories.
A category may have more than one parent category.
I am very confused as to how to set up the second of these two relationships correctly within Laravel.
So my question is:
How do I set up a database structure and Model relations so that a category can belong to many other category without any duplication in the categories table.
I would like to know what tables/columns I need and also what types of relationships need to be set in the models please.
This model seems to work:
I have a table called category_category and relation:
public function parentCategories()
{
return $this->belongsToMany('TottonTimber\Category', 'category_category', 'category_id', 'parent_id');
}
public function childCategories()
{
return $this->belongsToMany('TottonTimber\Category', 'category_category', 'parent_id', 'category_id');
}
Yet this doesn't seem like the correct way of doing it as both are "belongsTo"
In Many to Many to relations. Both models do have a belongs to relation with the other. For example in classic User & Roles Scenerio, User Belongs to Many Roles & Roles Belongs to Many Users.. So as you see 'Belongs to' relationship both sides. Here as you have same model for both ends of your relations, you have to put 'belongsto' for both your relation definations. That is perfectly ok it seems.

Is this many-to-many relationship possible in Laravel?

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.

Categories