How to check relation data of a collection before sending it to view - php

I have a Controller method like this:
public function awaiting()
{
$producers = Producer::where('producer_process',4)->get();
$producers_list = [];
foreach($producers as $producer){
if($producer->brand->brand_rejected == 0){
array_push($producers_list, $producer);
}
}
return view('admin.brands.awaiting', compact('producers_list'));
}
So basically there's One To One relationship between Producer model & Brand model.
In order to get the collection of brands table records that has producer_process of 4 and ALSO the brand_rejected field of related brands table record must be set to 0, I added an array_push and check the condition.
Now this works fine and properly shows the correct data but I wanted to know, what is the shorthand method of doing this with Eloquent relationships?
I mean is there any concise and useful method written in Eloquent relationships that can do this without using array_push or another foreach loop?

You can use whereHas to constrain the result set based on the existence of a relationship. Here we are saying we only want producers that have the field 'produce_process' set to 4 and have a brand with a field of 'brand_rejected' set to 0:
$producers = Producer::where('producer_process', 4)
->whereHas('brand', function ($q) { $q->where('brand_rejected', 0); })
->get();
If you want these producers to have their brand relationship loaded to use you should eager load that. Before the get call you can tell it to load the relationship:
$producers = Producer::where(...)->whereHas(...)->with('brand')->get();
Laravel 5.8 Docs - Eloquent - Relationships - Querying Relationship Existence whereHas
Laravel 5.8 Docs - Eloquent - Relationships - Eager Loading with

You can try this:
public function awaiting()
{
$producers = Producer::where('producer_process',4)
->with('brand', function($q) {
$q->where('brand_rejected', 0);
})->get();
// dd($producers);
dd($producers->pluck(brand));

Sure you can use the method with() also with the where() clause to can apply some conditions to the relationship
Example
$yourQuery->with('brand', function($query){
$query->where('brand_rejected', 0);
});
check this for more info
https://laravel.com/docs/9.x/eloquent-relationships#constraining-eager-loads
I hope it's helpful

Related

sum data from multiple relation in multiple relation in laravel

I have a User model, who hasMany categories and category hasMany posts and post hasOne Product
Now I want to sum all of the product->price of Auth::user()
how can i do that withSum or withCount function. in Laravel
Since your question doesnt present any details, I will assume that you have all the relations well set up.
You can get the sum using the relations like this
$sum = Product::query()
->whereHas('post', function($post) {
$post->whereHas('category', function($category) {
$category->whereHas('user', function($user) {
$user->where('id',auth()->id());
});
});
})
->sum('price');

Laravel eloquent how to get relationships relationship?

I have Users table,Jobs table and JobStatus table. I get user jobs using relationship
return User::find($dto->getUserId())
->jobs()
This will return all user jobs as collection, not as relationship inside user model.
Now I need to get jobs statuses, but when I try this
User::find($dto->getUserId())
->jobs()
->statuses()
I get error Call to undefined method. I need to get statuses as collection so I can use where,sort by etc while getting them from db. Is there any way to do so?
I need to do something like this , but with statuses
return User::find($dto->getUserId())
->jobs()
->has('status')
->where('role','responsible')
->where('jobs.created_at','>=',Carbon::now()->subDays($dto->getPeriod())->toDateString())
->get();
To retrieve the jobs by filtering on the statuses relationship, you can do it like this:
$user->jobs()->whereHas('statuses', function ($query) {
// Perform filter on the query for jobs->statuses
})->get();
For more information about querying relationship existence: https://laravel.com/docs/7.x/eloquent-relationships#querying-relationship-existence
If you want to retrieve the statuses instances, you can do it like this:
$statuses = JobStatus::where('created_at', '>=', now())
->whereHas('jobs', function ($query) use ($user) {
$query->whereUserId($user->id);
})
->get();
Just use jobs without parenthesises to get the model itself :
User::find($dto->getUserId())
->jobs
->statuses;
define your statuses() function first with the relations in your model with the jobs
like many to many or one to many relationship
public function statuses(){
return $this->belongsToMany('App\Job')->withTimestamps();
}

Laravel relationships orderBy

I have a simple belongsToMany relationship in model OrderProduct:
public function statuses()
{
return $this->belongsToMany(OrderProductStatusName::class, 'order_product_statuses')
->withPivot('created_at');
}
I want to have all statuses for one product, but I want them to orderBy by pivot table on created_at.
I was trying to do like this:
$orderProduct = OrderProduct::find($productId);
$statuses = $orderProduct->statuses->orderBy('pivot_created_at', 'DESC');
But i have error 500 that method orderBy doesn't exist. How can I do this?
Relations in laravel can be used as property or method. If relations used as property then returns a collection. if used as methods then returns query builder object and you can chain methods like orderBy. So in this case you should use the below code :
$statuses = $orderProduct->statuses()->orderBy('pivot_created_at', 'DESC')->get();

laravel 5.2 eloquent order by on relationship result count

I have two tables website_link and website_links_type. website_link is related website_links_type with hasmany relationship.
$this->website_links->where('id',1)->Paginate(10);
and relationship
public function broken()
{
return $this->hasMany('App\Website_links_type')->where('status_code','!=',"200");
}
Now I want to get result from website_link table but Orderby that result on count of broken relationship result.
There are many ways to solve this problem. In my answer I'll use two I know.
You can eagerload your relationship and use the function sortBy(). However I don't think you can use the paginate() functionality with this solution.
Example:
$results = Website_link::with('website_links_type')->get()->sortBy(function ($website_link) {
return $website_link->website_links_type->count();
});
See this answer
You can also use raw queries to solve this problem. With this solution you can still use the pagination functionality (I think).
Example:
$results = Website_link
::select([
'*',
'(
SELECT COUNT(*)
FROM website_links_type
WHERE
website_links_type.website_link_id = website_link.id
AND
status_code <> 200
) as broken_count'
])
->orderBy('broken_count')
->paginate(10);
You may have to change the column names to match your database.
You can not put WHERE condition in model file.
You just give relationship hasMany in model file.
And use where condition in controller side.
Refer this document.
Try this
Model file:
public function broken()
{
return $this->hasMany('App\Website_links_type');
}
Controller file:
$model_name->website_links->where('id',1)
->where('status_code','!=',"200")
->orderBy('name', 'desc')
->Paginate(10);

Laravel Eloquent Retrieving only certain rows basing on relation field

I have a number of models and I have the relationships set up correctly I believe.
I want to retrieve all of the models from a table if and only if the active column of a foreign key table is true.
I have tried a number of variations but to no avail.
Below is the set up.
The table is question is called device, which points to a table called dep.
The DEVICE model has the following relationship to DEP
public function dep() {
return $this->belongsTo('App\Dep');
}
The DEP model has a column called active, which is set to true or false.
What eloquent command should I use to return all Devices where the active field of the DEP table is true?
At the moment I am having to get all the DEP models and then only get the devices if the active field is set to true but I am sure there must be a more elegant approach.
Thanks.
If you want to limit the results based on the existence of a field in a related model, you want to take a look at the whereHas method.
$devices = Device::whereHas('dep', function($query) {
$query->where('active', '=', true); // Replace true with 1 if you aren't using casts
})->get();
This will get all devices that have a dep with the active field of true. This will not fetch dep along with the Device though. If you want that, then just use whereHas with eager loading as you normally would do like this:
$devices = Device::with('dep')->whereHas('dep', function($query) {
$query->where('active', '=', true);
})->get();
You can simply add a filter to your relationship:
public function dep() {
return $this->belongsTo('App\Dep')->where('active', true);
}
Or, if you prefer to keep the dep relation unaltered, you can consider to add another relation to retrieve only the active models:
public function depActive() {
return $this->belongsTo('App\Dep')->where('active', true);
}
This will return all the DEP models related to a Device, having active = 1.
You can use the relation as follow:
$depActives = $device->depActive;
or
$depActives = $device->depActive()->get();
boh of them will do the same

Categories