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

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?

Related

How can this be done with the relationship, and is it worth it? (Get all departments for clinic)

I have 3 tables:
clinics
departments
clinics_in_departments
Using Query Builder:
$department = ClinicsInDepartment::whereIn('clinic_id',[1,2,3])
->join('departments', 'clinics_in_departments.department_id', '=', 'departments.id')
->get();
How can this be done with the relationship, and is it worth it?
If you look at the documentation of Laravel at the Many to Many section https://laravel.com/docs/5.6/eloquent-relationships#many-to-many it's already explained in there. If you're planning to keep using Laravel I would recommend using the best practises of Eloquent. It's easier to understand and read for other developers. It's always worth to make your product the best you can. It also gives possibilities to quickly extend and maintain your application.
All you need to do is to define a relationship in your model clinics
// second, third and fourth parameter could also be optional
function departments(){
return $this->belongsToMany('App\Clinics', 'clinics_in_departments', 'department_id', 'clinic_id');
}
To retrieve the data you can use
$clinics = Clinics::with('departments')->get();
// this would hold a list of departments for each clinic
To get exactly the same data extend the query to this
$clinics = Clinics::with('departments')->whereIn('clinic_id',[1,2,3])->get();
Because it's a Many to Many relationship you could also define a relationship for the model Departments and do exactly the same as mentioned above.
You can define a belongs to many relation inside Clinics model like below code
function departments(){
return $this->belongsToMany('App\Clinics', 'clinics_in_departments');
}

Eloquent Models with hasMany WHERE condition

I'm fairly new to Laravel 5.5 and Eloquent, so I'm struggling to work out how to do this using Eloquent objects.
If I was going to do this in SQL it would be pretty simple, but I'd prefer to deal in Eloquent objects.
I have two tables, Lots and Bids and I have the models that go with these.
Is there a way to get any Lot model where a specific user has bid on it (user_id column in the bids table), and then get the maximum bid amount that the user has bid?
Thanks to Devon, I used the whereHas to return the models that I needed. I then added another method to the model that returned the max bid price.

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.

Doctrine 2 mapping process manipulation

I want to ask if its clean possible to change the mapping process.
For example, if i have an database, with products and offers, so the relation is 1 product n offers.
I want to get on fetch an product with multiple offers not an collection of offers, instead of i want to get an class named "AggregateOffers" which calculates the highest the lowest price and includes the offers collection.
Did anyone know an good/clean solution?
For an better understanding, schema.org defines the relation between an product an multiple offers, within an aggregateoffer, so i want to abstract them, to generate at the end an json-ld.
My actually design looks like schema, as you can see i have an 1-n relation from Product to Offer, what i actually want to get when i read from the DB, is an extended relation.
For example:
Product -> getOffers (should not return an collection of offers, instead it should return an "AggregateOffers" which hold the collection of offers).
The only idea, is to update the "getOffers" function and return die Aggregation class, but this acts not really good on me.

Difference between HABTM relationship and 2 $belongsTo relationship with a third model

I'm creating a project management system which projects are assigned to users
What's the difference between creating a Model ProjectsUser and defining 2 $belongsTo relationship and defining HABTM relationships in both Project and User models? What would be the most correct way, though? And how do I save the data in the projects_users table?
From my experience, if you want to be able to save or delete rows only from the join table (the one with 2 IDs), then it is much more simple using three models associated through both a hasMany and a belongsTo association.
You can also retrieve data from the join table directly and do the queries you want much more easily
This is what CakePHP documentation says refering to HABTM and saving data:
However, in most cases it’s easier to make a model for the join table and setup hasMany, belongsTo associations as shown in example above instead of using HABTM association.
Here you can find more the full text:
http://book.cakephp.org/2.0/en/models/saving-your-data.html#what-to-do-when-habtm-becomes-complicated
I have used this method for a "reads" table (with post_id and user_id) as well as for subscriptions and similar kind of relationships.
The first way is called "hasAndBelongsToMany" [details here].
The second is called "hasMany through" [details here].
The second link relating to "hasMany through" has details and a lengthy explanation about when and why you would want to use it.
Not sure about the specifics of cakephp, but in general defining the relation model explicitly gives you more control over it, for instance if you wanted to do some validation or add callbacks on creation of this relationship.

Categories