get models submodels and their submodels laravel - php

Can anyone tell me how to get models submodels and their submodels in the controller using eloquent? I have Organization model, Car, CarPrice, ModelDetails and Car images, so far I managed to get all the data using
$cars = $organization->cars()->with('model_details')->with('car_price')->with('car_images')->get();
But I want also to get submodels of ModelDetails, Manufacturer for example, is there any nicer way to do it without looping through all cars? I've set relations properly in models.

You can use . operator for nested relations as:
$cars = $organization->cars()
->with('model_details.manufacturer')
->with('car_price')
->with('car_images')
->get();
Docs scroll down to Nested Eager Loading

Related

Query More than one relationship from a model with() in Laravel

I need help to query a model base on its relationship:
I have a model called StoreStock, this model is related to a Product model, which has two model relationships, MasterList and Price.
I want to get all storeStock with two Product relationships.
I know i can do something like
StoreStock::all()->with('product.price')
->get()
With this, i can only pick either price or masterlist
Pass array of relationship to with method
StoreStock::with(['product.price','product.masterlist']) ->get()
A little bit explanation here, many of the Laravel methods which support string, also support arrays. You can hover over the specific method and get the intellisense. In your case, it can be written like:
StoreStock::with(['product.price','product.masterlist'])->get()
If you want to run a specific action over any specific relation, you can also write it like this:
StoreStock::with(['product.price' => function(Builder $query) {
// your action required with the query
},'product.masterlist']) ->get()
Hope someone finds this helpful

Merge models according to desc order for view - create an Activity page

So I have two models like and follow models, and I want to create an activity page where the user can see his latest activity accordingly. I thought about merging the two models in the view using laravel's merge function but I'm lost on how to indicate if a user liked the post or followed a blog.
$like= Like::where('user_id', '=', auth()->user()->id)->orderBy('created_at','desc')->get();
$follow = Follow::where('user_id', '=', auth()->user()->id)->orderBy('created_at','desc')->get();
$all = $like->merge($follow);
If I use an if statement in the view, it will group the different datas in the view rather than combining them together to make an activity timeline.
If you could help thanks
You can merge these collections together and order/sort them how you wish. I highly recommend not merging an Eloquent Collection into another Eloquent Collection of different types. Unlike the Base Collection type (Illuminate\Support\Collection) which the Eloquent Collection (Illuminate\Database\Eloquent\Collection) extends from it takes into account the models' keys. So if you have 2 collections and any models have the same key in them they will get overwritten. You want to convert one of these collections to a Base Collection then merge in the other one:
$merged = $like->toBase()->merge($follow);
$sorted = $merged->sortByDesc('created_at');
Or even convert them both to base Collections and merge:
$merged = $like->toBase()->merge($follow->toBase());

laravel Eloquent join and Object-relationship mapping

Ok so i'm kind of newish to eloquent and laravel (not frameworks tho) but i hit a wall here.
I need to perform some queries with conditions on different tables, so the eager load (::with()) is useless as it creates multiples queries.
Fine, let use the join. But in that case, it seems that Laravel/Eloquent just drops the concept of Object-relationship and just return a flat row.
By exemple:
if i set something like
$allInvoicesQuery = Invoice::join('contacts', 'contacts.id', '=', 'invoices.contact_id')->get();
and then looping such as
foreach ($allInvoicesQuery as $oneInvoice) {
... working with fields
}
There is no more concept of $oneInvoice->invoiceFieldName and $oneInvoice->contact->contactFieldName
I have to get the contacts fields directly by $oneInvoice->contactFieldName
On top of that the same named columns will be overwrited (such as id or created_at).
So my questions are:
Am i right assuming there is no solution to this and i must define manually the field in a select to avoid the same name overwritting like
Invoice::select('invoices.created_at as invoice.create, contacts.created_at as contact_create)
In case of multiple joins, it makes the all query building process long and complex. But mainly, it just ruins all the Model relationship work that a framework should brings no?
Is there any more Model relationship oriented solution to work with laravel or within the Eloquent ORM?
Instead of performing this join, you can use Eloquent's relationships in order to achieve this.
In your Invoice model it would be:
public function contact(){
return $this->belongsTo('\App\Contact');
}
And then of course inside of your Contact model:
public function invoices(){
return $this->hasMany('\App\Invoice');
}
If you want to make sure all queries always have these active, then you'd want the following in your models:
protected $with = ['Invoice']
protected $with = ['Contact'];
Finally, with our relationships well defined, we can do the following:
$invoices = Invoice::all();
And then you can do:
foreach($invoices as $invoice)[
$invoice->contact->name;
$invoice->contact->phone;
//etc
}
Which is what I believe you are looking for.
Furthermore, you can find all this and much more in The Eloquent ORM Guide on Laravel's site.
Maybe a bit old, but I've been in the same situation before.
At least in Laravel 5.2 (and up, presumably), the Eloquent relationships that you have defined should still exist. The objects that are returned should be Invoice objects in your case, you could check by dd($allInvoiceQuery); and see what the objects are in the collection. If they are Invoice objects (and you haven't done ->toArray() or something), you can treat them as such.
To force only having the properties in those objects that are related to the Invoice object you can select them with a wildcard: $allInvoicesQuery = Invoice::select('invoices.*')->join('contacts', 'contacts.id', '=', 'invoices.contact_id')->get();, assuming your corresponding table is called invoices.
Hope this helps.

Retrieve nested relationships for a model instance in Laravel's Eloquent

My scenario is this:
I have a Course model
Each Course can have many CourseTopics, through a topics() relationship
Each CourseTopic can have many Lessons, through a lessons() relationship
Is there a compact way to retrieve and handle all the Lessons associated with a single Course (for example, to list them, or to count their total number)?
My aim would be to have a very brief syntax to use in Blade templates; I don't want to involve logic (or at least, keep it to a bare minimum) or raw SQL queries into my template.
What I've tried:
$course->with("topics.lessons")
where $course is the current instance of the course in a template, doesn't work (gives to me all the courses with all their topics and lessons).
EDIT:
A solution is to define a hasManyThrough() relationship like:
$this->hasManyThrough("Lessons", "CourseTopics");
This solves the problem for a 2-level nested relationship. How about a 3-level instead?

One-to-many then eager load an array with Laravel Eloquent ORM

With Laravel and the eloquent ORM, I want to create an array or object of all posts and corresponding comments that belong to a specific user (the logged in one). The result will then be used with Response::eloquent(); to return JSON.
Basically in pseudo-code:
All Posts by user ::with('comments').
or
Posts by Auth::user()->id ::with('comments').
I have my database setup per the usual with a user's table, comments table and posts table. The comments table has a post_id and the posts table has a user_id.
The long way of doing this without Laravel would be something like:
SELECT * FROM posts WHERE user_id = 'user_id'
foreach($result as $post) {
SELECT * FROM comments WHERE posts_id = $post->id
foreach($query as $comment) {
$result[$i]->comments[$n] = $comment
}
}
But I want to accomplish it with Laravel's Eloquent ORM.
It looks like you don't even need a nested eager load, you just need to modify the query that with returns, so:
$posts = Post::with('comments')->where('user_id', '=', 1)->get();
You can daisy chain most of the methods in the Eloquent system, generally they're just returning a Fluent query object.
(I haven't tested it but I'm fairly certain that'll work. Also, you can't do it on ::all() because that calls ->get() for you. You have to dig in the source code to find this, I don't think the Eloquent documentation mentions that's what it's doing.)
Also the Eager Loading Documentation covers nested eager loading, so you could load all users, with their posts, with the comments:
You may even eager load nested relationships. For example, let's
assume our Author model has a "contacts" relationship. We can eager
load both of the relationships from our Book model like so:
$books = Book::with(array('author', 'author.contacts'))->get();

Categories