HasMany on Pivot Table uses wrong ID - php

I have a ManyToMany relationship between Election and Party to connect parties to multiple elections.
public function parties(): BelongsToMany
{
return $this
->belongsToMany(Party::class)
->using(ElectionParty::class)
->withPivot('has_no_answers', 'published', 'program_pdf', 'program', 'id');
}
On the pivot table election_party I added an auto incrementing id.
Parties can give answers to each election, for which reason I created a hasMany relationship to Answer on the pivot table, referenced by electionparty_id
class ElectionParty extends Pivot
{
public function answers(): HasMany
{
return $this->hasMany(Answer::class);
}
}
Now, to get the answers or in this case it's count, i do this in Blade:
#foreach($election->parties as $party)
{{ $party->pivot->answers->count() }}
#endforeach
This however, does not work, because it does not try to get answers by the pivot table id, which I assumed it would be but by the id of the election:
SQLSTATE[42703]: Undefined column: 7 ERROR: column answers.election_id does not exist LINE 1: select * from "answers" where "answers"."election_id" = $1 a... ^ HINT: Perhaps you meant to reference the column "answers.question_id". (SQL: select * from "answers" where "answers"."election_id" = 16 and "answers"."election_id" is not null)
Am I missing something here or doing something not how it's supposed to be done?

The default keys are generated differently in pivot models. Specify the foreign key:
class ElectionParty extends Pivot
{
public function answers(): HasMany
{
return $this->hasMany(Answer::class, 'electionparty_id');
}
}

Related

Laravel Eloquent finding models with more than one relation to another model on another table [duplicate]

This question already has answers here:
laravel BelongsTo relationship with different databases not working
(13 answers)
Closed 2 years ago.
I have two models using different tables on two different connections, User and UserInfo.
User has a UserInfo hasMany relation:
public function userInfo()
{
return $this->hasMany('path\to\UserInfo','User_ID');
}
and UserInfo has a User belongsTo relation:
public function user()
{
return $this->belongsTo('anotherpath\to\User', 'User_ID', 'User_ID');
}
I would like to find the first user with more than one UserInfo, however I believe that because they are on different tables on the database I am having issues.
This call
$patient = Patient::with('UserInfo')
->withCount('UserInfo')
->having('UserInfo_count', '>', 1)
->first();
Works as expected for other relations and is what I am trying to achieve, but not with this one. The difference being that the two models are on different tables. When I call this in Tinker, I get the error:
Illuminate/Database/QueryException with message 'SQLSTATE[42S02]:
Base table or view not found: 1146 Table '(TableName).UserInfo'
doesn't exist (SQL: select `User`.*, (select count(*) from `UserInfo`
where `User`.`User_ID` = `eob`.`User_ID`) as `UserInfo_count `User`
having `UserInfo_count` > 1 limit 1)'
Any ideas? I'm very new to eloquent and Laravel in general, sorry if I've gotten any terminology wrong or am missing something simple. Thanks!
maybe your table names are not defined properly as standard. so you can use table property to bind table name in model.
what is the standard to define table name.
Illuminate/Database/Eloquent/Model.php
/**
* Get the table associated with the model.
*
* #return string
*/
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
Example
Table Model
users User
user_profiles UserProfile
Alternative
in your UserInfo model
protected $table = 'your table name';
In more thing you don't need to add with() method and with withCount() method.
$patient = Patient::withCount('UserInfo')->having('UserInfo_count', '>', 1)->first();

Laravel Model Relationships - What kind of relationship am I trying to create?

I have got 3 models associated with this question; Country, Manufacturer and Region.
I've simplified the tables for the sake of this question. I don't think anything else in the tables or any of the other models are anything to do with the problem.
My tables are set up like so;
manufacturers
- id
- name
countries
- id
- name
regions
- id
- name
- manufacturer_id
- country_id
What I want to be able to do is to write $manufacturer->countries in my blade and have it spit out the countries that are associated with a given manufacturer.
The models are currently related to each other like this;
Country.php
public function manufacturers()
{
return $this->hasMany(Manufacturer::class);
}
public function regions()
{
return $this->hasMany(Region::class);
}
Region.php
public function manufacturer()
{
return $this->belongsTo(Manufacturer::class);
}
public function country()
{
return $this->belongsTo(Country::class);
}
and where I'm having the problem, Manufacturer.php
I think I need a hasMany relationship. I've already got;
public function regions()
{
return $this->hasMany(Region::class);
}
and I would have thought I would have needed;
public function countries()
{
return $this->hasManyThrough(Country::class,Region::class);
}
but that leads to this error;
Column not found: 1054 Unknown column 'countries.region_id' in 'on clause' (SQL: select `countries`.*, `regions`.`manufacturer_id` as `laravel_through_key` from `countries` inner join `regions` on `regions`.`id` = `countries`.`region_id` where `regions`.`manufacturer_id` = 4)
so I tried swapping the classes round to give;
public function countries()
{
return $this->hasManyThrough(Region::class,Country::class);
}
but that leads to;
Column not found: 1054 Unknown column 'countries.manufacturer_id' in 'field list' (SQL: select `regions`.*, `countries`.`manufacturer_id` as `laravel_through_key` from `regions` inner join `countries` on `countries`.`id` = `regions`.`country_id` where `countries`.`manufacturer_id` = 4)
Does anyone know how I should be setting my relationships up in order to achieve what I want?
I also tried a belongsToMany relationship, which did bring back the countries, but multiple instances of the same country. I just want one instance of each country that appears in the regions table for any given manufacturer.
You are actually dealing with the many-to-many relationship.
In your case regions is a pivot table.
Kindly check belongsToMany.
In Laravel, the best relationship to apply is many to many relationship. What this means as applied to your case is that 1 country can have multiple manufacturers and 1 manufacturer can be in multiple countries.
If that is the case, you don't need to create a regions table, but rather a pivot table. The default naming convention in laravel is (singular and om alphabetic order), that is, country_manufacturer table and it will contain (You can always add an extra variable known as pivot value):
country_manufacturer
- id
- name // pivot value
- manufacturer_id
- country_id
Then, in the models, add belongsToMany relationship, i.e.
In Manufacturer model (without pivot) :
public function countries()
{
return $this->belongsToMany(Manufacturer::class);
}
In Country Model (With pivot):
public function manufacturers()
{
return $this->belongsToMany(Country::class)->withPivot('name');
}
Hence, you will be able to call $country->manufacturers() which will give you a list of all the manufacturers in the $country and the reverse is true: $manufacturer->countries will give you all the countries the manufacturer is based in.

Speed up query through laravel relationships

There are 3 models:
First (first_id)
Connection (connection_id, first_id, product_id)
Second (second_id, product_id)
I would like to connect the three models together using laravel relationships
First->joined to Connection though first_id
Connection->joined to First through first_id, & joined to Second through product_id
Second -> joined to Connection through product_id
So: First joined to Second through Connection first_id, product_id
Is this possible to do using something like HasManyThrough?
Thanks for your time
On your First model:
public function second () {
return $this->hasManyThrough(
Second::class,
Connection::class,
'product_id', // Foreign key on connection table
'product_id', // Foreign key on second table
'first_id', // Local key on first table
'first_id' // Local key on connection table
);
}
Based on your description the column names should work.
In tinker you can validate if it's hooked up correctly by doing something like First::first()->second.
It depends on what type of relationship Your first model and second model shares as well as what type of relation second and third model shares.
if consider your first model First and second model Second shares a one-to-one relation, as well as Second model and Third models shares one-to-one relationships.
It will be $first->second->third; //no has many through relationship requires
If your First model and Second models shares as hasMany-belongs to relation than you need to use hasManyThrough relationship
example from doc
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}
You can try using nested relationships.
Nested Eager Loading
To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement:
$books = App\Book::with('author.contacts')->get();
Book Model:
public function author()
{
return $this->hasOne('App\Author');
}
Author Model:
public function contacts()
{
return $this->hasMany('App\Author');
}
Documentation:
https://laravel.com/docs/5.8/eloquent-relationships

Laravel Relationship in a pivot model

I have three tables, one of them is pivot table (and pivot model) and trying to create belongsTo relationship in pivot model (foreign key in pivot table) so that I can get the relevant name from some other table(has primary key). What I want to do is illustrating by images below:
Pivot Table is:
And other table is:
It is pivot Model:
class MproductIngredient extends Model {
public function qtyType() {
return $this->belongsTo('App\TIngredientType','priQuantityTypeNo');
}
}
How to get the relevant name from other table(has primary key).
My code is:
#foreach($prd->ingredients a $ingredient)
"{!! $ingredient->pivot->priQuantityTypeNo !!}"
#endforeach
Please describe more as far i understand you can make below to relationships
for belongstoMany
public function qtyTypes()
{
return $this->belongsToMany('App\TIngredientType', 'pivot_table_name',
'main_table_id', 'TIngredientType_id');
}
for hasOne
public function qtyType()
{
return $this->hasOne('App\TIngredientType');
}

Retrieve distant relation through has-many-through for many-to-many relation in Laravel

I have the following models in my application
User
Group
Task
which have the following relationships
User and Group have a many-to-many relationship
Task and Group have a many-to-many relationship
So basically a user can belong to more than one group and each group can have more than one task.
Following is the table structure.
users
id
name
groups
id
name
tasks
id
name
group_user
id
group_id (foreign key with groups table)
user_id (foreign key with users table)
group_tasks
id
group_id (foreign key with groups table)
task_id (foreign key with tasks table)
Now I want to retrieve all the tasks for the user.
I tried the following approaches and both didn't work.
Approach 1
$user->groups() gives the list of groups for a user
$group->tasks() gives the list of tasks for a group
So I tried
$user->groups()->tasks() but it didn't work.
Approach 2
I tried Has Many Through by adding this to my User model
public function tasks()
{
return $this->hasManyThrough(Task::class, Group::class);
}
but even that didn't work. The following is the error that I am getting
QueryException in Connection.php line 713:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'groups.user_id' in 'field list' (SQL: select `tasks`.*, `groups`.`user_id` from `tasks` inner join `groups` on `groups`.`id` = `tasks`.`group_id` where `groups`.`user_id` = 1)
My guess is that this is happening because it is expecting one-to-many relationship, but I have a many-to-many relationship.
So is there a way to retrieve it without getting all groups and then looping through them?
User Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
Group Model
public function tasks()
{
return $this->belongsToMany('App\Task');
}
Task Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
Retrieving all tasks for a user.
$user = User::find(1);
$user->load('groups.tasks');
$tasks = $user->groups->pluck('tasks')->collapse();
You can also take a look at the extension of the HasManyThrough here: https://github.com/staudenmeir/eloquent-has-many-deep
It helps you to retrieve many sub-levels of your relationships.
In your case, it would be
User -> belongsToMany(Groups) -> blongsToMany (Tasks)
just add your method to the user model like:
public function tasks()
{
return $this->hasManyDeep(
'App\Task',['App\Group']
);
}

Categories