Laravel wherehas ignored when using with - php

I have a Query where I want to see all Alert (relation) items for a User for a specific type.
I'm using the following query
$users = User::with('alerts')->whereHas('alerts', function($q) use ($type) {
$q->where('type', $type);
})->get();
The issue is it's ignoring my where subquery and returning the alerts for all types, not the type I'm passing into the whereHas.
Thank you!

Solution
whereHas limits the results of User, not the results of alerts
I had to use a subquery on the 'with' statement.
$users = User::whereHas('email_alerts')->with(['email_alerts' => function($q) use ($email_type) {
$q->where('email_type', $email_type);
}, 'company'])->get();

Related

Laravel retreive data from database order by creation date

I am trying to retrieve data orderby creation date desc and get the first one here is my code
$localnews = Articles::whereHas('sous_categories',
function ($query) {
$query->where('id', '15')->order_by('created_at', 'desc');
})->get()->first();
You must have got error when using order_by as its not the syntax in Laravel.
$localnews = Articles::whereHas('sous_categories',
function ($query) {
$query->where('id', '15')->orderBy('created_at', 'desc');
})->first();
Please have a look at official documentation to help you with.
And when using first() you don't need to use get().
get() we use to fetch multidimensional associative array.
first() we use to fetch one record which matches first.
Here is concise difference between all functions you will use then after. link.
It should be like this,
$localnews=Articles::whereHas('sous_categories', function($query) {
$query->where('id', '15')->orderBy('created_at', 'desc');
})->firstOrFail();

Laravel 5.3 Constraining Eager Loads not working

I have two model User and Profile in one to one relationship.
I want to retrieve all user where profile.status == TRUE using following code.
$users = User::with(['profile' => function ($query) {
$query->where('status', TRUE);
}])->get();
dd(count($users)); //50
I have 50 users and only among of them only 3 has status == TRUE. But always it display 50.
You are getting 50 users because you are applying condition to profile. dd($user->profile) you will get only the records of the profile whose status is true.
Use whereHas():
$users = User::whereHas('profile', function ($query) {
$query->where('status', TRUE);
})->get();
dd(count($users));
If you want to make it work with single Query, you can use Query Builder join like
\DB::table('users')->join('profile', function ($join){
$join->on('users.id', '=', 'profile.user_id')->where('profile.status', '=',TRUE);
})->get();
You said you're having N+1 problem, so you need to use both whereHas() and with() like this to get users with profiles and to solve N+1 problem:
$users = User::whereHas('profile', function ($query) {
$query->where('status', TRUE);
})
->with('profile')
->get();

Laravel OrderBy Nested Collection

I'm using a Roles package (similar to entrust). I'm trying to sort my User::all() query on roles.id or roles.name
The following is all working
User::with('roles');
This returns a Collection, with a Roles relation that also is a collection.. Like this:
I'm trying to get all users, but ordered by their role ID.
I tried the following without success
maybe because 'roles' returns a collection? And not the first role?
return App\User::with(['roles' => function($query) {
$query->orderBy('roles.id', 'asc');
}])->get();
And this
return App\User::with('roles')->orderBy('roles.id','DESC')->get();
None of them are working. I'm stuck! Can someone point me in the right direction please?
You can take the help of joins like this:
App\User::join('roles', 'users.role_id', '=', 'roles.id')
->orderBy('roles.id', 'desc')
->get();
Hope this helps!
You can make accessor which contains role id or name that you want to sort by.
Assume that the accessor name is roleCode. Then App\User::all()->sortBy('roleCode') will work.
Here's the dirty trick using collections. There might be a better way to achieve this(using Paginator class, I guess). This solution is definitely a disaster for huge tables.
$roles = Role::with('users')->orderBy('id', 'DESC')->get();
$sortedByRoleId = collect();
$roles->each(function ($role) use($sorted) {
$sortedByRoleId->push($role->users);
});
$sortedByRoleId = $sortedByRoleId->flatten()->keyBy('id');
You can sort your relations by using the query builder:
notice the difference with your own example: I don't set roles.id but just id
$users = App\User::with(['roles' => function ($query) {
$query->orderBy('id', 'desc');
}])->get();
See the Official Laravel Docs on Constraining Eager Loading
f you want to order the result based on nested relation column, you must use a chain of joins:
$values = User::query()->leftJoin('model_has_roles', function ($join)
{
$join>on('model_has_roles.model_id', '=', 'users.id')
->where('model_has_roles.model_type', '=', 'app\Models\User');})
->leftJoin('roles', 'roles.id', '=', 'model_has_roles.role_id')
->orderBy('roles.id')->get();
please note that if you want to order by multiple columns you could add 'orderBy' clause as much as you want:
->orderBy('roles.name', 'DESC')->orderby('teams.roles', 'ASC') //... ext
check my answer here:
https://stackoverflow.com/a/61194625/10573560

Laravel fetch data from model where the condtions is from another model

I have a table called List which i planned to be displayed into view with this command : $lists= List::with('user', 'product.photodb', 'tagCloud.tagDetail')->get();. But, i want the data displayed is only those that has TagID equal to the one user inputted. Those data can be retrieved from TagCloud table.
What i am currently doing is :
$clouds = TagCloud::select('contentID')
->where('tagDetailID', '=', $tagID)
->get();
$lists = List::with('user', 'product.photodb', 'tagCloud.tagDetail')
->where('id', '=', $clouds->contentID)
->get();
But when i tried to run it, it only return a null value, even though when i am doing return $clouds, it does returned the desired ID.
Where did i do wrong ? Any help is appreciated !
A couple of gotchas with your current solution.
Using get() returns an Illuminate\Database\Eloquent\Collection object. Hence you can't use $clouds->contentID directly since $clouds is a collection (or array if you prefer). See Collection Documentation.
where(...) expects the third parameter to be a string or integer, aka single value. Instead, you are passing a collection, which won't work.
The correct way is to use whereHas() which allows you to filter through an eager loaded relationship.
Final Code:
$lists = List::with('user', 'product.photodb', 'tagCloud.tagDetail')
->whereHas('tagCloud',function($query) use ($tagID) {
return $query->where('contentID','=',$tagID);
})
->get();
See WhereHas Documentation.
What you want is whereHas()
$list = List::with(...)
->whereHas('relation', function($q) use($id) {
return $q->where('id', $id);
})->get();
Apply Where condition in you tagCloud model method tagDetail
public function tagDetail(){
return $q->where('id', $id);
}

Select all records where a relationship count is zero using Eloquent?

In plain English: I have three tables. subscription_type which has many email_subscriptions which has many emails.
I'm trying to select all email_subscription records that have a particular subscription_type, that also don't have any associated email records that have a status of Held.
The particular bit I am stuck on is only returning email_subscriptions which have zero emails (with an additional where clause stacked in there described above).
Using Eloquent, I've been able to get a bit of the way, but I don't have any idea how to select all the records that have a relationship count of zero:
$subscriptionsWithNoCorrespondingHeldEmail = EmailSubscriptions::whereHas('subscriptionType', function($q) {
$q->where('name', 'New Mission');
})-; // What do I chain here to complete my query?
Additionally, is this even possible with Eloquent or will I need to use Fluent syntax instead?
You can use the has() method to query the relationship existence:
has('emails', '=', 0)
Eg:
$tooLong = EmailSubscriptions::whereHas('subscriptionType', function($q) {
$q->where('name', 'New Mission');
})->has('emails', '=', 0)->get();
Edit
You can do more advanced queries with the whereHas() and whereDoesntHave() methods:
$tooLong = EmailSubscriptions::whereHas('subscriptionType', function($q) {
$q->where('name', 'New Mission');
})
->whereDoesntHave('emails', function ($query) {
$query->where('status', '=', 'whatever');
})->get();
OK what I have under stand from your Question is you would like to have a All Emails which have
specific subscription_type, Zero(0) association and status = status
If yes so you canuse array in where statement.
Like:
$q->->where(array('status' => 'status','subscription_type'=>'what ever you want));

Categories