Unexpected Results in Laravel Eager Loading With Constraints - laravel-4

I have two tables: assets and asset_classifications. The tables have one-to-many relationship, where an asset has one asset classification, and asset_classifications have many assets.
I'm trying to run a query to get all assets which has an asset_classification name of "laptops", for example. I'm trying to do this by running this eager load with a constraint:
$laptops = Asset::with(array('classification'=>function($query){
$query->where("name","=","laptops");
}))->get();
foreach($laptops as $laptop){
echo $laptop->serial_number."<br/>";
}
name is a column from asset_classifications table. I already formed the one-to-many relationship by setting up the needed methods for my Asset and AssetClassification models.
The problem with my eager load is that it gets all the assets, seeming to ignore my eager loading constraint which tries to get only the "laptops". I think the problem is in my code or my understanding of eager loading, but I don't know which. I'm still new to this and I hope someone can help me.

with is used to filter related models, while you need whereHas for filtering main queried model by related table constraints:
$laptops = Asset::whereHas('classification', function ($query) {
$query->where("name","=","laptops");
})->get();

Related

Eager Loading in Laravel Eloquent

I'm new in laravel. I want to ask for example I have report_type model and also report model which is one to many relationship. I want to show the report_types and also the reports too. What is the best practice for this one? Should I use report.report_type only or I also have to add report in eager loading.
$report_histories = Report_history::where('report_id', $report->id)->with(['employee', 'report', 'report.report_type'])->get();
$report_histories = Report_history::with('report.report_type','employee')
->where('report_id', $report->id)
->get();

How do the "has" and "whereHas" methods work in Eloquent?

I have a relationship defined between users and permisson, a user can have many permissions.
When I use "with" I get the data normally.
$user->with('permisson')->get();
I get the user with their permissions.
When I use "has" it only returns the user.
$user->has('permission')->get();
For what I've read, I should get the permissons if the user contains at least one permission.
I am using Postgres driver.
with is used for eager loading a relationship. You'd use it to fetch all of the specified relationships for each model (individually, or in a collection).
has is for using the relationship as a constraint or filter. As you said, using something like has('permission') will add a constraint to the query that says "only get Users that have at least one permission". This does not automatically load the relations like with(), it only creates the constraint.
You can combine the two if you want to take advantage of both the constraint and eager loading the results.
User::has('permission')->with('permission')->get();
Seems a bit redundant, I know.
From laravel docs:
If you wish to limit your results based on the existence of a relationship, you should use the has method. For example, if you want to retrieve all blog posts taht have at least one comment, yo may pass the name of the relationship to the has and orHas methods:
$posts = Post::has('comments')->get();
So, when you use the has method, it will not return the relationship, but just the post models which has at least one comment.
The whereHas and orWhereHas methods allows you to add customized constraints to a relationship constraint, such as checking the content of a comment (using the laravel example):
$posts = App\Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
})->get();
When you use the with method, you are loading the realtionship with the model:
$user->with('permission')->get()
This code will load the user and the permission relationship, while this one
$user->has('permission')->get();
will load the user who has some permission.
Hope it helps.

How to use eager loading with custom query builder in Laravel

I am new to Laravel 5.4 and working on some query manipulation. Now I have created an query using query builder which is shown below:
$view = DB::table('blocks')
->leftjoin('programmes', 'blocks.programme_id', '=', 'programmes.id')
->select('blocks.id', 'blocks.programme_id', 'blocks.name', 'blocks.colour', 'blocks.year', 'programmes.title AS programme');
I have two more table "dates" and "modules". Each dates as well as module belongs to blocks.
Now I want to fetch all blocks with programmes, dates and modules. I know i can use with() method to get all of these. But as per my knowledge on Laravel, I can use with() method only if I have model file of each table and have relationship between them.
But do not want to use model and define relationship between them. I just want to know How can I get block data with programmes, dates and modules without creating model and defining relationship betwen them in model? Is there any other way to use with() method without model?
Block dates and modules are conditional, Sometime I dont want get data of this table with block.
Please help me on this.
You can't do it automatically. Eager loading is only for Eloquent model so you cannot use it with query builder. However in most cases you can use Eloquent also for getting more complicated queries (you can also use joins when using Eloquent) so you will be able to use eager loading.
But if you don't want to use Eloquent at all, obviously you will need to create some custom mechanism for eager loading.

Load all relations and their children in Laravel

I have a rather complex structure that contains multiple relations. If my relations are defined this way, how can I load all of them in one call?
Model
(has many) ChildModels1
Child1a
Child1b
...
(has many) ChildModels2
Child2a
Child2b
...
(has many) ChildModels3
Child3a
Child3a
Child3aa
Child3ab
...
I'm able to do the following:
$entity = Entity::find($id)->load('ChildModels1', 'ChildModels2', 'ChildModels3');
But I'm not sure how to load all the child relations too.
This can be achieved with Eager Loading:
Entity::where('id', $id)->with('relation1.subrelation1', 'relation1.subrelation2', 'relation2.subrelation1', 'relation2.subrelation2')->get();
When accessing Eloquent relationships as properties, the relationship
data is "lazy loaded". This means the relationship data is not
actually loaded until you first access the property. However, Eloquent
can "eager load" relationships at the time you query the parent model.
Eager loading alleviates the N + 1 query problem.
You can read more about this in the Laravel documentation on eager loading.

How can I return Many to One relation data joined with One to One data?

I have a question concerning Laravel schema.
Was that a bad idea to create an additional one-to-one table user_description, to store additional user data? Here is my schema:
For example now I don't know how to use eager loading to get user_photos if at first I retrieve topics' data.
Here is the code I use to get the last topics with user data:
return Topic::with('blog', 'user')->orderBy('topics.id', 'DESC')->get();
assuming your User-Model has a relation description() I suppose this does what you want.
return Topic::with('blog', 'user', 'user.description')->orderBy('topics.id', 'DESC')->get();
the concept is called sth. like eager loading of nested-relationships and is documented at the bottom of the eager loading documentation of laravel

Resources