Eloquent - Having problems using eager loading on nested relationships - php

I'm trying to eager load nested relationships, but I'm having trouble returning the correct results.
Here are the models:
User.php
class User extends Model
{
public function universities()
{
return $this->hasMany('\StudentApp\Models\UserUniversity');
}
}
UserUniversity.php
class UserUniversity extends Model
{
protected $fillable = [ 'user_id', 'university_id', 'choice' ];
public function university()
{
return $this->hasOne('\StudentApp\Models\University');
}
}
University.php
class University extends Model
{
protected $table = 'university';
}
What I want to do is get a user by ID, fetch the users universities from the UserUniversity pivot table, and then fetch the name of that university from the University table.
I've tried the following to test if it works:
$user = User::with('universities')->find($this->jwtObject->uid);
return $response->withJson($user->universities[0]->university);
But I get the following error:
Column not found: 1054 Unknown column 'university.user_university_id' in 'where clause' (SQL: select * from `university` where `university`.`user_university_id` = 10 and `university`.`user_university_id` is not null limit 1) [] {"uid":"28c5a97"}
user.user_university_id is incorrect. That column doesn't exist and I'm not sure why it's trying to use that column.
What it should be using is user.university_id
How can I do this?

You should add foreign key and primary key in relation:
public function universities()
{
return $this->hasMany('\StudentApp\Models\University', 'university_id', 'id');
}

Correct nested eager loading syntax is:
User::with('universities.university')
Also, make sure you've using the correct foreign key in the university table:
user_university_id
Or define another key in the relationship:
public function university()
{
return $this->hasOne('\StudentApp\Models\University', 'another_foreign_key');
}

Related

protected $table = 'users'; Not being respected in relationship on a model extending from User?

Currently I have this "ContactLine" model that is extending from the User model
class ContactLine extends User
{
use HasFactory;
protected $table = 'users';
public function organizations(): BelongsToMany
{
return $this->belongsToMany(Organization::class);
}
}
I have written a test controller where I am trying to inject the ContactLine into the method via route model binding.
class TestContactlineControler extends Controller
{
public function __invoke(ContactLine $contact)
{
return $contact;
}
}
However I am currently getting this error whenever I try to hit the route for this controller
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'incidents.contact_line_id' in 'where clause' (SQL: select count(*) as aggregate from `incidents` where `incidents`.`contact_line_id` = 1 and `incidents`.`contact_line_id` is not null and `closed_at` is null and `incidents`.`deleted_at` is null)
However if I change the controller to inject the User model instead it works fine.
In my user model I have this relationship which I think is causing the error.
public function incidents(): HasMany
{
return $this->hasMany(Incident::class);
}
However I thought setting the table to users in either User or ContactLine model should make it so it looks for incidents.user_id not incidents.contact_line_id
You can define the fields that are used to lookup a releation by settings the second and third param of hasMany
https://laravel.com/docs/9.x/eloquent-relationships#one-to-many
By default, laravel will do a lookup depending on your ClassName, by settings the params you can bypass this.

Join with relation between two models not working using non integer primary keys

I have two models: Holiday and HolidayInfo. These look like as follow:
Holiday:
class Holiday extends Model
{
protected $table = 'holidays';
protected $primaryKey = 'holiday_id';
public $timestamps = false;
public function dates(){
return $this->hasOne('App\HolidayDates', 'holiday_id');
}
public function images(){
return $this->hasMany('App\HolidayImages', 'holiday_id');
}
public function info(){
return $this->hasOne('App\HolidayInfo', 'holiday_id');
}
public function pricing(){
return $this->hasOne('App\HolidayPricing', 'holiday_id');
}
}
HolidayInfo:
class HolidayInfo extends Model
{
protected $table = 'holiday_info';
public $timestamps = false;
protected $primaryKey = 'holiday_id';
public function holiday(){
return $this->hasOne('App\Holiday', 'holiday_id');
}
}
My tables:
How can I make use of these models in relation to each-other in my controller while also using a simple where clause? In other words, HolidayInfo has some information which I need as-well as Holiday but it would be more efficient to perform a join somehow and then perform a where statement to narrow the data.
This is what i've tried but it didn't return the correct data:
$holidays = Holidays::with('info')->get();
This is what was returned - as you can see 'info' was returned null.
I have also tried adding a conditional as suggested by iCoders:
Holidays::where('country', $country)->with('info')->get();
Which returns the following suggesting that a join hasnt been performed:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'country' in 'where clause' (SQL: select * from holidays where country = australia)
Country is part of the 'holiday_info' table.
However; performing this query returns the data I need from Holiday Info Table, but it leaves out the Holiday Table data.
$holiday_info = Holidays::find(0)->info()->where('country', $country)->get();
After running the following, over 60 results appear, so the SQL works fine just not the laravel:
SELECT * from holidays JOIN holiday_info ON holidays.holiday_id = holiday_info.holiday_id
How can I combine both models/relations and their data so I can use it in one place?
Yuo have already added relation in Holiday model
public function info(){
return $this->hasOne('App\HolidayInfo', 'holiday_id');
}
You can do something like this using with
Holiday::where(your condition)->with('info')->get();
Updated
public function info(){
return $this->hasOne('App\HolidayInfo', 'holiday_id','holiday_id');
}
if you are not using laravel convention for table fields then you to pass primary key and foreign key to relation
Has One Relation
hasOne($related, $foreignKey, $localKey )
Thanks to #iCoders for helping me crack this case.
The issue was public $incrementing = false; should have been set in the Holiday modal because its a non-integer primary key.
Just use eloquent
$holidays = Holiday::where(your condition)->with("info")->get();
Then when getting the value on your info, just use:
foreach($holidays as $holiday){
$holiday->info->youInfoFieldHere
}

Laravel 5 – get particular many to many relation based on model and related model ID

I've got Tag and Attendee Eloquent models, they are in many-to-many relation. Pivot table has also two more attributes – value_int and value_string. My Attendee model looks like this:
class Attendee extends Model
{
public $timestamps = false;
protected $fillable = [
'event_id'
];
public function tags() {
return $this->belongsToMany('App\Models\Tag', 'attendee_tag', 'attendee_id', 'tag_id')
->withPivot(['value_string', 'value_int']);
}
public function scoreTagValue($tag_id) {
return $this->tags->where('tag_id', '=', $tag_id)->first();
}
}
What I want is to obtain pivot values based on Attendee model and variable tag_id, so I've written scoreTagValue function, but it always returns null and I don't know why :( I'm calling it this way:
$attendee->scoreTagValue($tag_id). Thanks for your help :)
You need to access the relation, not the property:
public function scoreTagValue($tag_id) {
return $this->tags()->where('tag_id', '=', $tag_id)->first();
}
Also, according to the docs, withPivot() does not take an array, so:
->withPivot('value_string', 'value_int');

How can i get the related data via the model?

I want to simply have a loop which have a sub-loop with all of the images link to the project. project.id = images.model_key in my case.
So i was trying to do something which didn't work.
function index()
{
$projects = Project::all();
foreach($projects as $project)
{
echo "<pre>";
print_r($project->images);
echo "</pre>";
}
}
Im the project model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\ProjectCategoryProject;
use App\Models\Image;
class Project extends Model
{
public $fillable = ['id', 'title','description', 'home_page', 'display'];
public function categories()
{
return $this->hasMany('App\ProjectCategoryProject');
}
public function images()
{
return $this->hasMany('App\Models\Image');
}
...
So i guess i have to specify in the model that project.id = images.model_key but how ?
Error :
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'images.project_id' in 'where clause' (SQL: select * from `images` where `images`.`project_id` = 4 and `images`.`project_id` is not null)
Thanks, sorry i'm guetting confused.
By default Laravel tries to guess the column name from current model, so in a model Project it will presume the column for it's ids in other models to be project_id. You can however override this and explicitly specity the columns to use for relationship:
public function images()
{
// specify a foreign key to use
return $this->hasMany('App\Models\Image', 'model_key');
}
Or this if you wanna be fully explicit.
public function images()
{
// specify a foreign key to use
return $this->hasMany('App\Models\Image', 'model_key', 'id');
}
I would however strongly encourage you to abide by laravel "convention" for better readability and easier maintenance. If possible, just rename the column :).

Laravel eager relationships empty query

I have 3 tables : hotels, hotels_data, hotels_types
Table hotels have id, type, stars, etc... type field is set as foreign key referencing type_id in hotels_types. I'm managing to get the correct data from hotels_data but have an empty result on getting hotels_types title and I don't understand why.
The code is the following :
class Hotel extends Eloquent {
public function getList() {
$data = Hotel::select('id','stars')->with('HotelData', 'HotelType')->paginate(10);
return View::make('hotels.index')->with('hotels', $data);
}
public function HotelData()
{
return $this->hasOne('HotelsData')->select('id','hotel_id','title');
}
public function HotelType()
{
return $this->hasOne('HotelType','type_id', 'type')->select('id','type_id','title');
}
}
You're using the wrong relationship for HotelType()
Your Hotel model should use the inverse of hasOne, which is belongsTo, because it contains the foreign key to HotelType (when a table contains a foreign key, it always belongs to the table being pointed to).
The following should work:
public function hotelType() {
return $this->belongsTo('HotelType','type', 'type_id')->select('id','type_id','title');
}
I've obtained the desired result with the following:
Hotel::select('hotels.*','hotels_types.title as type')
->join('hotels_types', 'hotels.type', '=', 'hotels_types.type_id')
->with('HotelData');

Categories