Laravel - belongsTo relationship in custom pivot model not working - php

Edit:
I dont think its the same issue as:
https://stackoverflow.com/questions/40022929/laravel-relationship-error-undefined-property-illuminate-database-eloquent-col
because in that issue hasMany relationship is used which returns an array but i used belongsTo which should return a certain object.
I have a database structure where i have a many to many relationship between users and companies table. For that i have a crossreference table company_user. Also each user has a certain role in a company so the crossreference table also has a role_id. The problem is that for some reason i get an exception when i try retrieve the role from the crossreference table.
Here is how i defined the relationship in Company model:
public function users() {
return $this->belongsToMany('App\User')->withPivot('role_id')->using('App\CompanyUser');
}
Now if i just try to get role_id from pivot everything works fine:
#foreach($company->users as $user)
{{$user->pivot->role_id}} // this displays correct role_id
#endforeach
But i also need the data of the role so i defined a relationship in my custom pivot. Here is the whole model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CompanyUser extends Pivot
{
public function role()
{
return $this->belongsTo('App\Role');
}
}
And i tried to access it like this:
#foreach($company->users as $user)
{{$user->pivot->role()->id}}
#endforeach
But this gives me an exception:
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$id
What am I missing?

try changing to
#foreach($company->users as $user)
{{$user->pivot->role->id}}
#endforeach

The exception itself gives you your answer.
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$id
It's telling you you're trying to access the $id property on the belongs to builder instance and not the actual related model.
The difference is small but is worth understanding as it will make your laravel life much happier.
Access the relation builder: $user->role()
This will directly call the role() method and return exactly what you see in your definition. Accessing this method is handy for aggregate functions - things like getting the count of related records for HasMany or BelongsToMany relations. eg: $user->role()->count().
Access the related record: $user->role
This will actually retrieve the related record from the database and hydrate it for you, thus giving you the power of your related eloquent model and access to it's columns as properties. :D
You can see why/how this works by diving into Laravel's source and checking out the Illuminate\Database\Eloquent\Model class. Specifically the getAttribute() method.

Related

What is the real query behind Laravel's Model::belongsTo() method?

For example, let's take a look at this model in a laravel project:
<?php
//...
class Post extends Model
{
//...
public function user()
{
return $this->belongsTo(User::class); // User model is previously defined
}
}
Now I can get the user (author) info of a specific post:
Post::find(1)->user()->username;
Of course laravel has to run some DB queries to get the data; and I wanna know what is the query behind this belongsTo() method.
You cant use the toSql() method to check query will run on laravel illuminate,
$sql = Person::query()->with('user')->find(1)->toSql();
dd($sql);
try use this
$result=Post::with('user')->find(1);
dd($result);
and look the response
belongs to is meaning to relation between tables
if the relation is one to one use belongsTo and hasOne
if the relation is one to many use belongsTo and hasMany

BelongsTo return class

When I use belongsTo without default keys it won't connect..
My users table has user_id which is some rand and unique string that presents that user. My urls table has user_id and uri columns where user_id contains users table user_id.
In Url model I have:
public function user() {
return $this->belongsTo('App\User','user_id','user_id');
}
In User model I have:
public function uri() {
return $this->hasOne('App\Url', 'user_id', 'user_id')->first()->uri;
}
By using $user->uri() I get uri from urls table connected with user_id.
But when I use $url->user() I get return null or BelongsTo class inside laravel tinker.
Anyone know why?
Your User::uri() method is not a relationship method.
You are utilizing a relationship method inside of it, but you are querying it for the first result and returning the uri property.
Your Url::user() method IS a relationship method because you are actually returning a relationship (BelongsTo) instance. Eloquent relationships are used as follows:
// To get a related entity on a BelongsTo relationship, you access it as a property:
$url->user
// To query a relationship, you use it as a method:
$url->user()->where(...)->first();

Trouble understanding laravel eloquent models

It's been a some time since I've programmed with Laravel and I'm stumped by the relations I need in order to create a foreign key -link with 2 models.
I have a database where there's a table "company" containing companies, and I also have a table called "projects", which contains projects.
So the Projects- table contains a column called "employercompany" with a foreign key constraint to the company-table.
I'm trying to print out the company's name in a project page in laravel with
{{$project->employercompany->name}}
But keep getting "Trying to get property of non-object"
My model pages look like this:
//Company
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
public function projects()
{
return $this->hasMany('App\Projects', 'employercompany', 'id');
}
}
and
// Projects
namespace App;
use Illuminate\Database\Eloquent\Model;
class Projects extends Model
{
public function employercompany()
{
return $this->belongsTo('App\Company');
}
}
I know this is an easy problem but I just can't wrap my head around it
*****EDIT*****
I found the solution. Thanks Radical for providing some insight.
I ended up changing the employercompany column to company_id and, all the others as such too.
After that I fiddled around what I'm guessing fixed the thing was that I changed my database search query from
DB::table('projects')->get();
into
Project::all();
Don't know if that was the change needed but it sure feels like it was.
When defining a belongsTo relation like you have done, Laravel will try and 'guess' the keys you are using based on the class name. In this case, it will look for a column company_id on your Projects model since your model is called Company.
Like you have done for the projects() method on your Company model, you should tell Laravel that you are using the employercompany column to reference the Company model:
public function employercompany()
{
return $this->belongsTo('App\Company', 'employercompany');
}
For more information, see the relevant documentation here.
In addition, to make things easier, it might be worthwhile to try - if possible - to adhere to what Laravel 'expects' your database columns to be called, so situations like this are resolved automatically.
It should be like
$project = Project::find($id); //id of project
$compnany_name = ($project->employercompany()->get())->name;

Call to undefined method Illuminate\Database\Query\Builder::vehicles()

I have two models.
A "Vehicle" and a "Tenant".
They have following relationships with each other.
A Tenant hasMany vehicles. A vehicle belongsTo a single Tenant.
For Tenant.php:
public function vehicles()
{
return $this->hasMany('\App\Models\Vehicle');
}
For Vehicle.php:
public function tenant()
{
return $this->belongsTo('\App\Models\Tenant');
}
Executing this :
$this->user = $request->user();
$userTenant = $this->user->tenant();
$vehicle= $userTenant->vehicles()->first();
results in an error
Call to undefined method Illuminate\Database\Query\Builder::vehicles()
Pointing to this line :
$vehicle= $userTenant->vehicles()->first();
I am not so sure why is this happening =\
I can't see from your post what the relations are with a User, but the tenant() (with parentheses) probably returns a BelongsTo or other Relation instance that is being assigned to $userTenant. Try changing that line to a version without parentheses after tenant to get the Tenant Model instance instead:
$userTenant = $this->user->tenant;
Update from comments
when you call a relation as method, e.g.
$myModel->relation()
you get the corresponding relation class. When used as a getter, e.g.
$myModel->relation
it's essentially the same thing as calling
$myModel->relation()->get() for relations that target multiple models, or calling
$myModel->relation()->first() for relations that target a single model.
Checkout the docs for more info on relationship methods vs. dynamic properties

Laravel 4 hasOne / belongsTo relationship

Get the feeling I'm being particularly dumb here but it's doing my nut in.
I have a candidate table with the country_id field as a foreign key to the countries table. A candidate has one linked country.
The Candidate model has a relationship defined as:
public function country()
{
return $this->belongsTo('App\Models\Country', 'country_id');
}
And the Country model has the following:
public function candidate()
{
return $this->hasMany('App\Models\Candidate');
}
On my listing page I'm using Candidate::with('country')->paginate(5) to provide a list of the Candidates on screen. When I come to display the country I use:
$candidate->country->country
But this returns the error:
Trying to get property of non-object
I can, however, use
$candidate->country['country']
Using var_dump on $candidate->country suggests that an object is returned, so why can't I access it as an object?
EDIT:
The candidates controller is namespaced to admin as follows:
namespace App\Controllers\Admin;
and as part of the declarations in the controller I have:
use App\Models\Candidate, App\Models\Manufacturer, App\Models\Make, App\Models\Country;
Each model is namespaced with
namespace App\Models
Have I even got the relationship set up correctly?
Thanks

Categories