Laravel eager loading, loaded table fields - php

how can I choose which fields I want to get from the with ORM eloquent. For example
$tourTeams = Tournament::with('teams')->where('id', $tourId)->first();
From the teams relation I want only to get the name (without the id and timestamps).
I didn't it in the documentation. For the Tournament eloquent I can do it via the get function while passing it an array of fields names, like this: get(array('name', 'id')). But how do I do this on the Team eloquent?
Note: here is how Team related to Tournament, this code taken from the Tournament eloquent file:
public function teams()
{
return $this->belongsToMany('Team', 'Tournament_Team');
}

You can get specific columns from the relation like this:
$tourTeams = Tournament::with(['teams'=>function($q){
$q->select('id','name');
}])->where('id', $tourId)->first();

Related

Laravel Many-to-many relationship using pivot table

I'm creating an application wherein users can be assigned to multiple organisations, and organisations can have many users - many-to-many relationships.
I want to be able to do something like this:
$user->organisations()->get() as well as $organisation->users()->get()
I have a users table...
I have an organisations table...
Uh! users-organisations, organisations-users!
and I have a user_orgs pivot/mapping/etc. table
Note
The user_orgs table has an org_id field, and a user_id field.
Eloquent assumes and expects organisation_user - but that is not what I have named my table, nor do I want to rename.
I set up the following
App/Organisation.php
public function users(){
return $this->belongsToMany("App\User");
}
and on user:
App/User.php
public function organisations(){
return $this->belongsToMany("App\Organisation");
}
And then I test this:
Route::get('/test-route', function(){
$u = App\User::first();
return $u->organisations()->get();
});
and get the following error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db.organisation_user' doesn't exist (SQL: select organisations.*, organisation_user.user_id as pivot_user_id, organisation_user.organisation_id as pivot_organisation_id from organisations inner join organisation_user on organisations.id = organisation_user.organisation_id where organisation_user.user_id = 1)
The two questions in my mind are, one; how do I specify to Eloquent, to use user_orgs instead of assuming organisation_user, the same way I can override the tableName or primaryKey on a model? Two: how can I specify the foreignKey column, such that it uses user_orgs.org_id and not user_orgs.organisation_id?
But please do suggest alternatives.
Thanks all, in advance.
You can set the name of the pivot table by passing it as the second argument to the belongsToMany() relationship, like below:
public function users(){
return $this->belongsToMany("App\User", "user_orgs");
}
public function organisations(){
return $this->belongsToMany("App\Organisation", "user_orgs");
}
Documentation:
https://laravel.com/docs/5.8/eloquent-relationships#many-to-many
As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the belongsToMany method.

Laravel: get a model through another table

I have gotten a model called User. in this model i have a function called UserActivity where i return this:
return $this->hasMany('App\UserActivity', 'userid');
After this i have a function that gets the activity name from the Activity table, but i do not know how to do this, i have currently gotten this:
public function Activity() {
return $this->hasManyThrough('App\UserActivity', 'App\Activity', 'userid', 'activityid');
}
And in my view i want to use this like this:
$activiteiten = \App\User::find(Auth::user()->id);
dd($activiteiten->UserActivity()->Activity());
But then i get an error saying this:
Call to undefined method Illuminate\Database\Query\Builder::Activity() (View: /var/www/vhosts/cpned.nl/intranet.cpned.nl/laravel/resources/views/dashboard.blade.php)
I can do it using inner joins but i am really wondering if i can do this with Laravel models. I do not know how currently, and because i don't know what the name is for the function in laravel i can't find it either, so I am sorry if this will be a duplicate.
My tables have the following keys and foreign keys:
Users: pk: id
user_activities: pk: userid, activityid
activities: pk: id
Thank you in advance!
You can try using eager loading.
So something like:
$activiteiten = \App\User::with('UserActivity.Activity')->find(Auth::user()->id);
dd($activiteiten->UserActivity->Activity);
Edit: So then you can do something like this:
foreach($activiteiten->UserActivity as $user_activity) {
foreach($user_activity->Activity as $activity) {
print_r($activity);
}
}
Shows how you can loop through the relationships.
The Activity function should be in the User model. So then you can call it this way:
$activiteiten = \App\User::find(Auth::user()->id);
dd($activiteiten->Activity); //gives you a collection of activities
However, you need belongsToMany function rather than hasManyThrough since the relationship between users and activities is many-to-many.
This mean you cut down going through the Intermediate model. You can check the doc on belongsToMany to understand what to do better.
A side note: Why are your functions name starting with capital letter?
Also using hasMany relations should affect the function name as well, so that 'activity' becomes 'activities' (just to keep the functionality and interpretation in sync).
Update:
//User model
public function activities() {
return $this->belongsToMany('App\Activity', 'user_activity', 'userid', 'activityid');
}
This uses the 'user_activity' table, to find the relationship between users and activities, so that you may now access by User::first()->activities for example.

Laravel eloquent multiple table join with filter

There are theree tables in my system.
Students
Articles
categories
Student can write many articles and a article is belong to just one student. And A Article can have only one category.
Controller
public function all_articles_by_student_by_category(Request $request){
$students_id = $request->students_id;
$categories_id = $request->categories_id;
$article_list = Students::find($students_id)->articles->all();
//This return Something like, Select All Articles Written by Damith
}
Model
class Students extends Model
{
protected $fillable = ['id','first_name', 'last_name', 'age', 'created_at', 'updated_at'];
public function articles()
{
return $this->hasMany('App\Articles');
}
}
What I am try to get
Something like, Select All Articles Written by Damith for Technology Category (Category Name should be there)
What I able to do so far
Something like, Select All Articles Written by Damith using $article_list = Students::find($students_id)->articles->all(); (You can find this code from controller)
What I want from you
How do I modify $article_list = Students::find($students_id)->articles->all(); to get, something like, Select All Articles Written by Damith for Technology Category. (Category name must be there in result and it is on category table, and for where condtion you can use the category_id which is i the article table )
First off with what you have done so far the ->all() method is not needed when getting the records for a relation on a model, this would return all of the articles linked to that student:
Students::find($students_id)->articles
Go through Articles Model
You could do something like:
Article::where('student_id', $students_id)
->where('category_id', $category_id)->get();
Which would acheive the result you are after.
Go through Students Model
If you want to go through Students Model you can constrain the relation using the with method.
$student = Students::with(['articles' => function($query) use ($category_id) {
$query->where('category_id', $category_id);
}])->find($student_id);
$filteredArticles = $student->articles
Useful Links
Laravel Docs 5.5 for Eager Loading : https://laravel.com/docs/5.5/eloquent-relationships#eager-loading
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.
Laravel Docs 5.5 for Constraining Eager Loads: https://laravel.com/docs/5.5/eloquent-relationships#constraining-eager-loads
Sometimes you may wish to eager load a relationship, but also specify additional query constraints for the eager loading query.
Something like this should work:
$technologyArticles = Articles::where('student_id', '=', $students_id)->where('category_id', '=', $categories_id)->get();

Laravel eloquent model - get rows using intermediate table

I have 3 tables users, posts and photos.
post table has one - one relation to photos & users like, post.user_id=users.id and post_photo_id=photos._id.
I use
public function posts(){
return $this->hasMany('Post');
}
and I get all the posts by user using $user->posts().
What I need is to get all the photos by user, something like $user->photos.
SELECT photos.*
FROM photos
JOIN posts ON posts.photo_id=photos.id
JOIN users ON users.id=posts.user_id
WHERE user_id=1
Note: photos table has just 2 fields, id & photo.
In your User model, create a relationship like
Class User Extends Model
{
...
public function photos()
{
return $this->hasManyThrough('Photos','Posts','photo_id','id');
// Params (all strings): Final Model, Intermediate Model, Intermediate Model Key (posts), final Model Key (your photos)
}
public function Posts()
{
return $this->hasMany('Posts');
}
...
}// end class
Then in your controller, you'll just call your data with the relationships. This assumes you're hinting, but you get the idea...
$picturesByUser = $this->user->with(['posts','photos'])->find($id);
finally, in your blade, just eager load them...
#foreach(...)
$user->photos->pathToPicture;
$user->posts->pictureTitle;
#endforeach
Straight out of the Laravel Docs

How to assign relation when working with pivot table in Laravel 4?

Details
I have 3 tables :
catalog_downloads
export_frequencies
export_frequencies_catalog_downloads (Pivot Table)
Diagram
I am not sure if I set the relation between them correctly.
Please correct me if I am wrong.
Here is what I did
In CatalogDownload.php
public function export_frequencies(){
return $this->belongsToMany('ExportFrequency','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id');
}
In ExportFrequency.php
public function catalog_downloads(){
return $this->belongsToMany('CatalogDownload','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id');
}
Questions
According to my diagram - Did I assign the relationship correctly ?
I hope I didn't mix up between hasMany and belongsTo
Will I need a class or a model for a Pivot Table ?
Thanks
Since export_frequencies is in the CatalogDownload model you have to invert the ID's because the parameters of belongsToMany are as follows:
1. Name of the referenced (target) Model (ExportFrequency)
2. Name of the Pivot table
3. Name of the id colum of the referencing (local) Model (CatalogDownload in this case)
4. Name of the id colum of the referenced (target) Model (ExportFrequency in this case)
what leads to this function:
public function export_frequencies(){
return $this->belongsToMany('ExportFrequency','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id');
}
The other function was correct.
If you had some data in your pivot table, for instance a colum with the name someCounter then you will have to tell the relation to load that column when creating the pivot object like this:
public function export_frequencies(){
return $this->belongsToMany('ExportFrequency','export_frequencies_catalog_downloads','export_frequency_id','catalog_download_id')->withPivot('someCounter');
}
That will load the column and make it avalible like this:
$catalogDownload->export_frequencies()->first()->pivot->someCounter;
You will need a separate Pivot Model if you need to do some special handling for the fields or if that pivot itself has a relation of its own but then you might consider using a full blown model instead of a pure Pivot Model.
As an added note to the accepted answer, you are able to set up your many to many relationships without referencing the pivot table and the relevant id's as long as you follow a specific convention.
You can name your pivot table using singular references to the related tables, like 'catalog_download_export_frequency'. Notice the alphabetic order of the singular references.
Then you can simply do:
// CatalogDownload Model
public function exportFrequencies()
{
return $this->belongsToMany('ExportFrequency');
}
// ExportFrequency Model
public function catalogDownloads()
{
return $this->belongsToMany('CatalogDownload');
}
This will then allow you to run queries using the query builder or Eloquent like:
$catalogDownload->exportFrequencies()->get(); // Get all export frequencies for a specific CatalogDownload.
Or
$this->catalogDownload->with('exportFrequencies')->find($id); // Using eager loading and dependency injection, when CatalogDownload is assigned to $this->catalogDownload
Hope this helps!

Categories