Laravel4, eager loading is not working - php

I'm trying to get "reviews" from my database where the user is from MX (for example) so, I have this:
Review::with(array('user' => function($query)
{
$query->where('country_code', '=', 'MX');
}))
->with('user.country','pictures')
->where('shop_id',Input::get('id'))
->orderBy('id','DESC'))
->get()
->toArray()
But seems to be like where('country_code', '=', 'MX') is not taken into account because retrieve all reviews and I just want the reviews written by the user from MX.
user and picture inside with are functions within my User model
country_code is a field from users table
The goal is: Just get the reviews written by a user from the country specified, and was testing something like this:
Review::where('shop_id',Input::get('id'))
->with('user.country','pictures')
->where('users.country_code','MX')
->orderBy('id','DESC'))
->get()
->toArray()
But is not working as well because says: Unknow column users.country_code in where....

You want to do a query that filters based on the relation. Eager loading constraints only constrain the records that come with your main result set.
Review::whereHas('users', function ($q)
{
$q->where('country_code', 'MX');
})
->with('user','pictures')
->where('shop_id',Input::get('id'))
->orderBy('id','DESC'))
->get();
The whereHas is saying ... give me only Reviews that have a User with country_code=MX.
Reference
Laravel Docs - Eloquent - Querying Relations

If you want reviews written by a certain user or group of users you don't want to use eager loading. Try this:
Review::with(array('user', 'pictures'))
->join('users', 'reviews.user_id', '=', 'users.id)
->where('users.country_code', '=', 'MX')
->where('reviews.shop_id', Input::get('id'))
->orderBy('reviews.id', 'DESC'))
->get();

Related

laravel elequent way to find single row from table

hello I am new to laravel and maybe I am a bit confused between eloquent and query builder way for writing a query but anyway can you please tell me what could be the best eloquent way to retrieve info like this in laravel 6 or 7
User > hasMany > Recipes
Recipe > belongsTo > User
I want to check if user id 2 present in users table then get only one post which id is 3
Query builder is for explicitly building SQL queries, and does not return instances of your models. Eloquent query builder, is similar but the result will contain the model(s) loaded with all their attributes, and has some handy functions for querying the relations you define in your models.
Given the limited information in your post, I am assuming when you say a post, you mean a recipe:
Query Builder:
DB::table('users')
->join('recipes', 'recipes.user_id', '=', 'users.id')
->select(['users.some_col', ... 'recipes.some_col'])
->where('users.id', 2)
->get();
If you have your models setup with the relations. You can use Eloquent like so:
User::where('id', 2)->with('recipes')->get();
If I understand you correctly it would be like this:
User::whereId($userId) //asuming it is 2
->with(['recipes' => function($q) use($recipeId) {
$q->where('id', $recipeId); //assuming it is 3
}])->first();
you can do this if i understand correctly:
$user = User::findOrFail(2); //auto 404 if user not found
$recipe = $user->Recipes()->where('id',3)->first();
You may use conditional eager loading for better performance.
$userId = 2;
$receiptId = 3;
$user = User::with(['receipts'=> function ($query) use($receiptId){
$query->where('id', $receiptId);
}
])->find($userId)

Laravel: Orderby in related table and with

This is my model
User
Role
and relationship between of those models are many to many.
I want to create query like this:
return User::with('roles')->orderBy('roles.id')->paginate();
I don't want join because I created a base class for every model. I also don't want use orderBy after get because it must load all of my data and after that I should be able to sort and paginate it. So it is not a very good idea.
You can try something like this:
return User::with(['roles' => function ($query) {
$query->orderBy('id', 'desc');
}])->paginate();
But this will only order the eager loading attributes, but if you are interested to use join you can have something like this:
return User::with('roles')
->join('roles', 'user.id', '=', 'roles.user_id')
->orderBy('roles.id', 'desc')
->paginate();
In this you can easily use paginate which is your main concern.
Hope this helps.
User::where('role_id','!=','0')->orderBy('role_id','DESC')->paginate(10);

Eloquent eager loading acting as explicit join

I am building a small blog and I would like to use the built-in Eloquent eager loading, but I would like it to act as an explicit join.
Here's what I'm trying to do, using a join, which works, but not in the way I want.
$posts = Post::join('users', function($join){
$join->on('users.id', '=', 'posts.user_id');
$join->on('users.status', '=', DB::raw('active'));
})
->get();
My problem with this is that I can't use the user model on my post like so:
$posts[0]->user->firstname;
With the join, the user's data is directly set on the post model, so I have to use it like so:
$posts[0]->firstname;
The thing is: I would like to use my User model because it has a few method inside that I'd like to use. One for printing the full name, one for printing its URL, etc..
What I am not able to do with eager loading, is to prevent a post from loading when it has no user attached to it. When the user associated with the post doesn't have the status 'active', I still get the post, and NULL for the user. But I don't want the post at all.
Is that something possible?
Am I being clear enough in my explications?
Thanks
You're overcomplicating things. Eloquent has everything you need:
// first make sure you load only posts of active users
$posts = Post::whereHas('user', function ($q) {
$q->where('status', 'active');
})
// then eager load the users
->with('user')
->get();
And by the way this is how you do, what you tried, in your join (w/o DB::raw):
$posts = Post::join('users', function($join){
// on() is for comparing fields
$join->on('users.id', '=', 'posts.user_id');
// while where is for comparing to provided values/strings
// just like simple query where()
$join->where('users.status', '=', 'active');
})

Laravel - constrain on eager loaded belongsTo relationship

My model Book
public function author()
{
return $this->belongsTo('Author');
}
I want to get all books which have authors that have column is_published == 1.
So I have tried this:
Book::with(['author' => function($query){
$query->where('is_published', '=', '1');
}]);
This works but really only gets me Books where SOME books have author model attached and some don't!
So, I tried this:
Book::with(['author' => function($query){
$query->where('is_published', '=', '1');
}])->has('author');
But I get this error:
Has method invalid on "belongsTo" relations
How can I be sure that my constraint on the foreign table reduces my final data set without having to loop through my data and check for the existence of the author? Thanks.
Book::whereHas('author' , function($query){
$query->where('is_published', '=', '1');
})->get();
Use this it worked for me.
The problem is that eager loading does not utilise the SQL JOIN (that I know of) if you head over to http://laravel.com/docs/eloquent#eager-loading you will see the example:
select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)
This does not allow the constraint of the author existing.
To do this it requires a JOIN if you want to do it efficiently (I assume so hence the eager loading).
Relevant Laravel Documentation: http://laravel.com/docs/queries#joins
Replace has('author') with whereNotNull('author_id').

Querying on related models using Laravel 4 and Eloquent

Using Laravel 4 I have the following models and relations: Event which hasMany Record which hasMany Item. What I would like to do is something like this
Item::where('events.event_type_id', 2)->paginate(50);
This of cause doesn't work as Eloquent doesn't JOIN the models together when retrieving the records. So how do I go about this without just writing the SQL myself (which I would like to avoid as I want to use pagination).
What you want is eager loading.
It works like this if you want to specify additional constraints:
Item::with(array('events' => function($query) {
return $query->where('event_type_id', 2);
}))->paginate(50);
There is a pull request pending here https://github.com/laravel/framework/pull/1951.
This will allow you to use a constraint on the has() method, something like this:
$results = Foo::has(array('bars' => function($query)
{
$query->where('title', 'LIKE', '%baz%');
}))
->with('bars')
->get();
The idea being you only return Foos that have related Bars that contain the string 'baz' in its title column.
It's also discussed here: https://github.com/laravel/framework/issues/1166. Hopefully it will be merged in soon. Works fine for me when I update my local copy of the Builder class with the updated code in the pull request.

Categories