Query relationship Eloquent - php

I have News model, and News has many comments, so I did this in News model:
public function comments(){
$this->hasMany('Comment', 'news_id');
}
But I also have field trashed in comments table, and I only want to select comments that are not trashed. So trashed <> 1. So I wonder is there a way to do something like this:
$news = News::find(123);
$news->comments->where('trashed', '<>', 1); //some sort of pseudo-code
Is there a way to use above method or should I just write something like this:
$comments = Comment::where('trashed', '<>', 1)
->where('news_id', '=', $news->id)
->get();

Any of these should work for you, pick the one you like the most:
Eager-loading.
$comments = News::find(123)->with(['comments' => function ($query) {
$query->where('trashed', '<>', 1);
}])->get();
You can inject the parameter to query function by use($param) method, that allows you to use dynemic query value at runtime.
Lazy-loading
$news = News::find(123);
$comments = $news->comments()->where('trashed', '<>', 1)->get();
I couldn't help but notice, though, that what you're probably trying to do is handle soft deleting, and that Laravel has built-in functionality to help you with that: http://laravel.com/docs/eloquent#soft-deleting

You can do simply in your eloquent model file.
do like this :
public function comments_with_deleted()
{
return $this->belongsTo('Comments', 'id')->where('deleted', 1);
}
public function comments()
{
return $this->belongsTo('Comments', 'id');
}
call like this :
// for show comments with deleted
$comments = News::find(123)->with('comments_with_deleted');
// for show comments without deleted
$comments = News::find(123)->with('comments');

rmobis's answer was what I needed, but it throws an error in current Laravel 5. You have to use it as an associatve array now:
$comments = News::find(123)->with(
['comments' => function ($query) {$query->where('trashed', '<>', 1);}]
);
Took me some time to figure it out, hope this will help others.
Read more in Laravel's Docs (5.6): https://laravel.com/docs/5.6/eloquent-relationships#querying-relations

Related

Using Model Relationship in a Single Query

Consider the following:
$posts = $this->model->newQuery()
->whereIn('user_id', $user->following) // specifically this line
->orWhere('user_id', $user->id)
->get();
The problem with the above is that there are two queries:
Get following: $user->following
Get posts: Above
This would be much more efficient with the use of a subquery, however, I cannot actually remember the correct way to do it...
I have tried all of the following:
// This was a long-shot...
...->whereIn('user_id', function ($query) use ($user) {
$query->raw($user->following()->toSql());
});
// This works but pretty sure it can be done better with eloquent...
...->whereIn('user_id', function ($query) use ($user) {
$query->select('follow_id')
->from('user_follows')
->where('user_id', $user->id);
});
Is there a way that this can be achieved by using the previously defined relationship $user->following() instead of manually defining the relationship query like the last example above?
Reference
The following relationship is defined as follows:
/**
* Get the users that the user follows.
*/
public function following()
{
return $this->belongsToMany('SomeApp\User\Models\User', 'user_follows', 'user_id', 'follow_id')
->withTimestamps();
}
Use this:
->whereIn('user_id', $user->following()->getQuery()->select('id'))

How to fetch users not assigned to a particular role in Laravel [duplicate]

In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?
Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.
For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();
It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();
How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.
Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres
This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();

Sorting users through relation in laravel

i want to sort the users through voornaam(firstname). but im getting the data via a relation.
How do i make my query so that, the relation users are sorted by firstname by alphabet
my function:
public function sortfirstname($id) {
$ingeschrevenspelers = UserToernooi::with('users')->where('toernooiid', '=', $id)->get()->all();
//This query ^^
$toernooi = Toernooi::findOrFail($id);
dd($ingeschrevenspelers);
return view('adminfeatures.generatespelerslijst', compact('ingeschrevenspelers', 'toernooi'));
}
What i want to sort
any help is appreciated
thanks in advance
Writing code in your own language doesn't make it very easy for other developers to understand your code.
That being said, you can try the orderBy() method on your relationship
In your model where you define the relationship:
public function relationship()
{
return $this->belongsTo(SomeClass::class)->orderBy('name', 'DESC');
}
Don't fire all() function at the end thus obtaining a Collection instance of result
//query without the all function
$ingeschrevenspelers = UserToernooi::with('users')->where('toernooiid', '=', $id)->get();
//
$ingeschrevenspelers = $ingeschrevenspelers->sortBy('users.firstname');
An alternative to Jordy Groote's answer if you do not want to modify the Model class itself, you can query it with a closure.
$ingeschrevenspelers = UserToernooi::with(['users' => function($q) {
$q->orderBy('voornaam', 'asc');
}])->where('toernooiid', '=', $id)->get()->all();
Reference: https://laravel.com/docs/5.3/eloquent-relationships#constraining-eager-loads
Sidenote: I don't think you need a ->all() when you already did a ->get()
$ingeschrevenspelers = UserToernooi::with(['users' => function($query){
$query->orderBy('voornaam', 'asc');
}])->where('toernooiid', '=', $id)->get()->all();

Laravel - Using a nested relationship with the query builder

I am working on an API but its starting to get a bit slow now that the data is increasing. I am moving some of the queries so that they use the DB query builder.
I have my last one which has a nested query:
$artists = Artist::with('performances', 'performances.stage')->get();
I have got so far:
$artists = \DB::table('artists')
->leftJoin('performances', 'artists.id', '=', 'performances.artist_id')
->get();
But now need to do the second relationship which in the Performance model is:
public function stage()
{
return $this->hasOne('App\Models\Stage', 'id', 'stage_id');
}
Any help on how I do this?
yes you can use eloquent relationship with query builder like this
$artists = Artist::join('performances', 'artists.id', '=', 'performances.artist_id')
->all();
foreach($artists as $artist){
$data = $artist->stage()->first();
}
It is very well covered in the official documentation, please, refer to this section of Documentation
I think that you want to achieve something like this:
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
And also, please, read carefully this section

Laravel Eloquent: How to order results of related models?

I have a model called School and it has many Students .
Here is the code in my model:
public function students()
{
return $this->hasMany('Student');
}
I am getting all the students with this code in my controller:
$school = School::find($schoolId);
and in the view:
#foreach ($school->students as $student)
Now I want to order the Students by some field in the students table. How can I do that?
You have a few ways of achieving this:
// when eager loading
$school = School::with(['students' => function ($q) {
$q->orderBy('whateverField', 'asc/desc');
}])->find($schoolId);
// when lazy loading
$school = School::find($schoolId);
$school->load(['students' => function ($q) {
$q->orderBy('whateverField', 'asc/desc');
}]);
// or on the collection
$school = School::find($schoolId);
// asc
$school->students->sortBy('whateverProperty');
// desc
$school->students->sortByDesc('whateverProperty');
// or querying students directly
$students = Student::whereHas('school', function ($q) use ($schoolId) {
$q->where('id', $schoolId);
})->orderBy('whateverField')->get();
you can add orderBy to your relation, so the only thing you need to change is
public function students()
{
return $this->hasMany('Student');
}
to
public function students()
{
return $this->hasMany('Student')->orderBy('id', 'desc');
}
To answer the original question, the students dynamic property can also be accessed as a relationship method.
So you have this to fetch all students:
$students = $school->students;
Now as a relationship method, this is equivalent:
$students = $school->students()->get();
Given this, you can now add in some ordering:
$students = $school->students()->orderBy('students.last_name')->get();
Since eloquent will be performing a join, make sure to include the table name when referencing the column to order by.
You can also add this to your students method if you want to set a default order that $school->students will always return. Check out the documentation for hasMany() to see how this works.
For Many to one relation I found one answer on:
https://laracasts.com/discuss/channels/eloquent/order-by-on-relationship
$order = 'desc';
$users = User::join('roles', 'users.role_id', '=', 'roles.id')
->orderBy('roles.label', $order)
->select('users.*')
->paginate(10);
this can save day... of anyone
You can use this like this:
$students = $school->students()->orderBy('id', 'desc');
You can also use
$students = $school->students()->orderBy('id', 'desc')->paginate(10);

Categories