Calling relations on other relations of model yii 1.1 - php

I have 3 model Price, Description and Product
the Description model has relationship on Price model and Price model has relationship on Product.
Can I call the product when I try to get it on Description model using the relationship of Price?
here's what I'm trying to do
$description = Description::model()->with('Price')->findAll();
// after that I want to call the product which is on price.
they're all connection using their id. product_id, description_id and price_id
How can I achieve this? is there a way?

First of all, JFYI when you use with() method to establish join part from ActiveRecord's query builder, please just double check also the relations() method from the specific AR model to see the actual defined relations. I pointed to this because defining relations into model and access them in later stage via query builder is case-sensitive.
Back to your question.
If you have already fetched your Description model joined eagerly with() your Price model, when you call $description->price->product, behind the scenes ActiveRecord will perform the so-called lazy-loading approach.
According to Yii 1.1 docs -> https://www.yiiframework.com/doc/guide/1.1/en/database.arr :
Performing Relational Query
The simplest way of performing relational query is by reading a relational property of an AR instance. If the property is not accessed previously, a relational query will be initiated, which joins the two related tables and filters with the primary key of the current AR instance. The query result will be saved to the property as instance(s) of the related AR class. This is known as the lazy loading approach, i.e., the relational query is performed only when the related objects are initially accessed.
The example below shows how to use this approach:
// retrieve the post whose ID is 10
$post = Post::model()->findByPk(10);
// retrieve the post's author: a relational query will be performed here
$author = $post->author;
Hope this helps.

Related

Relationship of a Post model to both city and country (from Location model)

I have a Post model and a Location model. I have setup the many-to-many relationship so that $post->getCities and $location->getPosts work by introducing an intermediate table. This is the Locations table:
Now, what I want to do is to get all the posts that belong to a country? Is this possible with the existing tables and relationships that I have?
If your $post->getCities looks something like that
return $this->hasMany(Location::class, ...);
Then QueryBuilder is returned, allowing you to filter your query in a casual way before executing request to the database:
$post->getCities()->where('country', $yourCountry)->get();
Otherwise, if your $post->getCities already returns a collection, you can apply where method on the collection and filter it on the side of your application:
$locations = $post->getCities(...);
$locationsByCountry = $locations->where('country', $youtCountry);

Connecting database fields and model attributes in Laravel

I'm just getting going with Laravel, and have used Eloquent to define my Campaign table. I have a Campaign model which is currently empty.
I'm not sure how to add attributes to this model to represent the fields in the db - or even if I should. The Laravel documentation seems thin on models and searches keep leading me to accessors and mutators.
If I have a database field called platform_type in my campaigns table, how do I link the PlatformType model attribute to this field?
To clarify:
This is not a question about relationships - there is only one entity in my solution thus far.
platform_type is a field in my campaigns table because it is an attribute of a campaign - I'm asking how to represent this in my model.
The model has an internal array which stores the attributes of a given row (it's called $attributes and replicated by $original if you look for them in the source code). The reason it's replicated is so when you call save() it will only do a save if you actually changed them from the originals.
You can access said attributes via $modelInstance->getAttribute("platform_type") or $modelInstance->platform_type which will call the magic __get method that in turn calls the getAttribute
So in your case you can have:
$campaign = Campaign::find($id);
echo $campaign->platform_type;
The ORM will automatically create the relevant SQL query and fill the model instance with the attributes of the row it finds.
You need to define relationships. In the PlatformType model:
public function campaigns()
{
return $this->hasMany(Campaign::class, 'platform_type');
}
And in the Campaign model:
public function platformType()
{
return $this->belongsTo(PlatformType::class, 'platform_type');
}
You also need to rename the campaign table to campaigns. Or you should add this to the model to be able to use a custom name:
protected $table = 'campaign';
At this point, these tables will be connected and relationships will work. However, it is recommended to add foreign key constraints.

Laravel model object retrieving relation model with where condition without "get" method

I'm working on octoberCMS(laravel framework), I have a doubt on retrieving relation model on where clause.
I have fetched a clothing_type record from "clothing type" model based on its primary key "id".
$clothing_type = ClothingType::where('id',post('clothingtype_id'))->where('status','Active')->first();
This "clothing type" model is related with "products" model, the relation is => each clothing type hasMany products.
Every thing works fine; Now my business logic has two cases, one is to get all the products of the clothing type and another is to get the first product of the clothing type. So I have used the $clothing_type->products to get all the products and $clothing_type->products->first() to get the first product.
Now I have to apply a condition for both the cases. The condition is that only the product whose status is "Active" should be fetched, hence
$products = $clothing_type->products->where('status','Active'); and$first_product_detail = $products->first();.
Every thing works as expected but how come the products are fetched without "get()" method. $clothing_type->products->where('status','Active')->get(); Since I'm new to relation I want to know how this works or is this a bad way to get records or improper assumption. But every thing works good.
$clothing_type = ClothingType::where('id',post('clothingtype_id'))->where('status','Active')->first();
if(count($clothing_type->products))
{
$products = $clothing_type->products->where('status','Active');
$first_product_detail = $products->first();
}
You are doing it the correct way. When you access the relationship as an attribute Eloquent automatically retrieves the records.
However, if you access the relationship as a method, you get the query itself, to which you can add your filters:
if(count($clothing_type->products))
{
$products = $clothing_type->products()->where('status','Active')->get();
$first_product_detail = $products->first();
}
This would solve your problems
(documentation is over here (see the first item))
Edit: Also note that the first method is not a method of Eloquent, but from Collection, which is pretty powerful!
Edit2:
I misread the part of your question where you want to know HOW this is possible. Both Eloquent and Collections have a where method. I assume you understand the working of the Eloquent one, but the one from Collection is pretty much the same (see documentation on the Collection where here)
I prefer the Eloquent one myself, because that limits the amount of records that is retrieved from the database. But if you need all the products (even the inactive ones) later on in your code, just use the Collection method to filter the active ones out
There is nothing to be afraid of...
first() and where()
are functions of both Illuminate\Database\Query\Builder as well as Illuminate\Support\Collection and all first does is limit the records to take 1 and then give you the first record. When you use Builder a query is made to get 1 record and 1 you use it on a collection, all records are first get() and then the first of those records is returned.
Here,
When you do,
$clothing_type->products, Laravel gives you a collection of products...
So...
$products is an object of Illuminate\Support\Collection
and
$products->first() calls for the first() function in that class.
Documentation on where and first methods of a collection...

Fetching all pivot table columns via custom pivot type

I have a many-to-many relationship where the pivot table has about 20 additional columns. I am using a custom pivot class, and I have successfully set up the code to return an instance of that class when the ->pivot property is accessed on the relation, e.g.
$supplier->products->pivot returns the custom pivot class.
However, when wanting to access the data, I can manually define all the individual attributes of the pivot class (which extends Pivot by the way) in the belongsToMany relationship like this:
return $this->belongsToMany(Product::class, ['prop1', 'prop2', 'prop3'])
...But, how can I retrieve all the pivot data of the class without manually defining them as it ties the relationship declaration very close to the class? Is this possible. If not, it's going to make maintainability a PITA! Ideally, it'd be really nice if withPivot just had a flag to get it all!
In my circumstances, I found it easier to separate all the data into a separate table and model, and add a foreign key in the pivot table to the additional table record. This allows me to use the 'normal' model handling in Laravel and means I don't have to mess around with problems like this!
My use case was a schema of product and supplier with a many-to-many, and each supplier having their own data for the product, namely price, stock, shipping cost / times etc, so I moved all this from the pivot to a SupplierProduct model.
I'll leave this question here, as although this isn't the direct answer to the question (which I fear the answer is 'no'), this is a solution which is viable and can save quite a bit of coding frustration!

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