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.
Related
I'm confused on how to get my model setup in laravel with a table that is connected to a pivot table.
Here's the problem
Say I have
Locations
id
name
area_types
id
name
area_type_location (Pivot table)
id
location_id
area_type_id
area_test
id
area_type_location_id
clean
headCount
Relationship between the tables are different areas type belongs to different locations.
i.e: beach, 25m pools, kids pools, bbq, etc
area_test is connected to the pivot table because the test has to be generated from area that exists, in this case it is area that is registered under different locations. Thus it has to be tested daily, measured, etc.
I understand the structure between area_types and locations for many to many relationship, however I can't get over my head of how do i structure my area_test model? How do I get the data from locations table -> where are my test?
Should I create a model for my pivot table? Is that a good practice in laravel?
Does anyone has the same use case?
I read about eloquent has many through
relationship but I understand that it does not mention about getting through pivot table. I don't quite get if my use case is the same.
Thanks
Finally, apparently there are a couple of way to get data from locations table to area_tests
Tried at tinker and it works,
First Option
I need to create a Pivot model for my Pivot table:
class LocationAreaType extends Pivot{
public function location(){
return $this->belongsTo(Location::class);
}
public function areaType(){
return $this->belongsTo(AreaType::class);
}
public function AreaTests(){
return $this->hasMany(AreaTest::class, 'area_type_location_id');
}
}
I can use hasManyThrough relation that I need to create in my Location table
public function areaTests()
{
return $this->hasManyThrough(
AreaTest::class,
LocationAreaType::class,
'location_id',
'area_type_location_id');
}
this way I can get the areaTests easily by $location->areaTests, My problem was not determining the area_type_location_id as foreign. You need to determine this, apparently when I extends pivot and use hasMany laravel does not auto recognise the Foreign key by itself.
Second option
Another way to access it is from the relation table, I can define withPivot in the areaTypes() relation then access it like this:
$location->areaType[0]->pivot->areaTests
Since laravel only recognise foreign key from both tables location_id and area_type_id, I have to include the id of the pivot table to get the AreaTest table data
So in the Location model I have to get the column
public function areaTypes()
{
// Get the ID of the pivot table to get the poolTests table (connected with ID column)
return $this->belongsToMany(AreaType::class)
->using(AreaTypeLocation::class)
->withPivot('id');
}
There is no need to create a new model for pivot table.
Just declare in Location model below code:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function area_types()
{
return $this->belongsToMany('App\AreaType', 'area_type_location', 'location_id', 'area_type_id');
}
and declare below code in AreaType model:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function locations()
{
return $this->belongsToMany('App\Location', 'area_type_location', 'area_type_id', 'location_id');
}
every time you need to get for example the locations of an area_type in every controller, you can call the function like this: $areatype->locations()->get();
Don't forget to create area_type_location table migration.
I'm trying to get information associated with an application in my database.
Each application has 1 applicant.
Each application has 1 puppy.
I'm returning a view with an eloquent query like this:
$active_applications = Application::with('applicant', 'puppy')->where('kennel_id', '=', $user_kennel->id)->get();
And I have some relationships defined in my application model like so:
public function puppy(){
return $this->belongsTo('App\Puppy');
}
public function applicant(){
return $this->belongsTo('App\User');
}
When the view loads, I'm able to get the information associated with 'puppy'. It retrieves properly. The applicant, however stays null.
I have, in my applications table, a column named "user_id", which I was hoping it would use value in that column to search the users table 'id', and retrieve information on the user. It stays null, however. The following is a dd() of the variable in question:
Am I missing something obvious? Why would it retrieve one and not the other?
EDIT: the puppy table
Your relation is wrong -
public function applicant(){
return $this->belongsTo('App\User');
}
When you don't pass the foreign key as a parameter, laravel looks for the method name + '_id'. Therefore in your case laravel is looking for the column applicant_id in your application table.
So, to get results there are two ways -
1) You need to either change your method name -
public function user(){
return $this->belongsTo('App\User');
}
**2) Pass foreign key as the second parameter - **
public function applicant(){
return $this->belongsTo('App\User', 'user_id');
}
Laravel 5.6 doc - belongsTo
If its a One to Many(Inverse) Relation -
Eloquent determines the default foreign key name by examining the name
of the relationship method and suffixing the method name with a _
followed by the name of the primary key column.
If its a One to One Relation -
Eloquent determines the default foreign key name by examining the name
of the relationship method and suffixing the method name with _id.
Review Laravel doc for more details
Try the following line instead:
$active_applications = Application::with(['applicant', 'puppy'])->where('kennel_id', '=', $user_kennel->id)->get();
As far as I know, multiple "with" should be passed as array.
Adjust the relationship as well
public function applicant(){
return $this->belongsTo('App\User', 'user_id');
}
I can't figure out how to make aliases for my table column names such that I can use Laravel's Eloquent belongsTo() functionality.
I have a groups table and and an activities table. The activities table references the groups table by organization_id rather than groups_id.
How do I write belongsTo in my Activity model as the following doesn't work.
public function group()
{
return $this->belongsTo('App\Group', 'organization_id');
}
What I'd like to write is:
App\Activity->group
In the code you have pasted laravel will think that the organization id is the column in your activities table which your are using as foreign key what you should do is :
public function group()
{
return $this->belongsTo('App\Group', 'organization_id', 'id');
}
in the above code you will get all results where activies.id = groups.organization_id;
UPDATE by Tim Peterson
My original code works. I migrated my DB for something else so that must have fixed everything.
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!
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();