Laravel 5.1 - BelongsTo relationship returns null - php

\App\User
class User
public function status() {
return $this->belongsTo('App\UserStatus', 'user_status_id', 'id');
}
\App\UserStatus
class UserStatus
protected $fillable = ['id'];
public function user() {
return $this->hasMany('App\User', 'user_status_id', 'id');
}
I already have the $user object from a simple User::find() query with some fields, then I try to access the status object by lazy loading it with $user->load('status') method.
I'm following the docs, but it seems useless since $user->status still returns null.
public function foo(User $user) {
$user->load('status');
$user->status // returns null
}
What am I doing wrong?
--------- SOLUTION ---------
Actually, to lazy load any relationship, the foreign key value needs to be stored in the model object.
In my find operation, I wasn't querying the user_status_id field. When I added this field into the query, the $user->status statement started to return the UserStatus model.
I don't think this information is written on the Laravel docs, it may be simple, but it took me some time to figure that out.

Actually, to lazy load any relationship, the foreign key value needs to be stored in the model object.
In my find operation, I wasn't querying the user_status_id field. When I added this field into the query, the $user->status statement started to return the UserStatus model.
I don't think this information is written on the Laravel docs, it may be simple, but it took me some time to figure that out.

in status() relation replace the line with
return $this->belongsTo('\App\UserStatus', 'user_status_id');
in user() relation with this
return $this->hasMany('\App\User', 'user_status_id');
Long story short add a '\' before App and remove third parameter since it is not many-to-many relationship.
Also make sure that you actually use Eloquent so add on top of models
namespace App;
use Illuminate\Database\Eloquent\Model;
class MODELNAME extends Model
and assign a table
protected $table = 'model_table';

I was using Psy Shell to run it. For the first argument in belongsTo(), that could just be Classname::class. I encountered the case that I cannot perform belongsTo(), but if you restart your Psy Shell, it worked. It is weird though.

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

Eloquent relation collection not returning by property accessor but does if I use relation()->get();

I'm having an issue with eloquent whereby when I call $unit->assets I am receiving an empty collection. But if I call $unit->assets()->get() - I receive a collection with the correct results.
According to the documentation my relations are defined correctly, which also seems apparent given that I get correct results when calling get() on the relationship object.
class Unit extends Model
{
protected $table = 'organisation_units';
public function assets()
{
return $this->hasMany(MediaElement::class, 'owner_id');
}
}
class MediaElement extends Model
{
protected $table = 'template_elements';
public function owner()
{
return $this->belongsTo(Unit::class, 'owner_id');
}
}
Table structure is
organisation_units
id | name
template_elements
id | owner_id | name | filename
Turns out the issue was the fact that I use "assets" as the relation method name. "assets" must be a reserved or already used keyword within models or something. Will update the post when I find out exactly why.
Also had the same issue with the method names "colors" and "templates".
The real issue here, was that I was storing my organisation unit in the session and when retrieving that from the session, the relations were already loaded.
Calling $model->fresh() before saving to the session sorted out the issue.
Thanks to those who attempted to help.

Laravel - belongsTo relationship in custom pivot model not working

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.

Why eloquent model relationships do not use parenthesis and how do they work?

I kept searching the web for an hour but couldn't figure this out. If we look at the eloquent relationships documentation:
https://laravel.com/docs/5.2/eloquent-relationships
The example User model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('App\Phone');
}
}
Just below it, how to access the phone number of a user with id=1:
$phone = User::find(1)->phone;
Why is it phone and not phone() and what is the difference?
Also how does it work? If I try to call an object->name without parenthesis in my code PHP thinks I am looking for a class variable named name?
Some extra information:
It looks like phone is returning object(App\Models\Phone) and phone() is returning object(Illuminate\Database\Eloquent\Relations\HasOne)
If I run the code below:
User::find(1)->phone->count()
Framework executes following SQL statements:
select * from `phone` where `phone`.`user_id` = '1' and `phone`.`user_id` is not null limit 1
select count(*) as aggregate from `phone`
If I run the code below:
User::find(1)->phone()->count()
Framework executes following SQL statement:
select count(*) as aggregate from `phone` where `phone`.`user_id` = '1' and `phone`.`user_id` is not null
One way of thinking about it is that the public function phone() function defines the relationship, so using $obj->phone() would get you the Eloquent relationship itself (not the results of that relationship) which you could then modify with various query builder elements if you wanted.
Leaving out the brackets is the Eloquent shorthand for adding ->get() or ->first() at the end of the expression (Eloquent knows which to use based on if it's a hasOne, hasMany, etc. relationship, as defined in the function), which returns an Eloquent collection.
So, $obj->phone is the same as $obj->phone()->first().
I don't know Laravel/Eloquent and you would need to show the find() method for more information, but User::find(1) returns an object so the ->phone accesses the phone property of that object. This has nothing to do with the find() method that you have shown. It is shorter than this that would do the same:
$obj = User::find(1);
$phone = $obj->phone;
Do a var_dump($obj); and you should see a phone property. If not, then another possibility is that the class implements a __get() magic method so that when you attempt to access the phone property it runs the phone() method and returns the value.
As for the first explanation, the same can be done with arrays:
function test() { return array('phone'=>'713-555-1212'); }
echo test()['phone'];

Laravel 1-N relationship not working

I'm starting my first Laravel project. I set up and tested all the relationships between tables and all of them look fine but one 1-N relationship. I cannot find the error, could you please help me?
Tables:
User:
*id
*username
Feeling:
*id
*name
*user (it points to User:id)
Class User
<?php
class User extends Eloquent {
protected $table = 'User';
public function feelings() {
return $this->hasMany('Feeling', 'user');
}
}
Class Feeling
class Feeling extends Eloquent {
protected $table = 'Feeling';
public function user() {
return $this->belongsTo('User','user');
}
}
If I execute:
$feeling = Feeling::find(1);
echo($feeling->user->username);
I get an error "Trying to get property of non-object".
If I execute
$feeling = Feeling::find(1);
It prints the Json array of the feeling object and if I execute
$feeling = Feeling::find(1);
echo($feeling->user);
It prints "1". So I'm getting the user ID of the database, but not the user object. I would like to get the user object instead.
Thank you very much.
Problem:
Everything is fine but you have used user as your local key and that's why the confusion because, when you call $feeling->user the magic method __get() is called which is available in the Illuminate/Database/Eloquent and it; as given below:
public function __get($key)
{
return $this->getAttribute($key);
}
The getAttribute() method looks several places for the key and sequentially it looks into the Model itself at first and then looks into the relationship array and then at last checks if the key for examaple in your case user exists as a method in the Model which is Feeling in your case, then it gets the related model and finds the key value.
Hence, your Feeling has a field as user so before it goes to the related model it just finds the field in current Model's attributes so it thinks that, user field has been requested for and you get the numeric id instead if related model instance.
Solution:
Solution is pretty simple, change the related field name (user) to anything else, better is user_id but you are free to use anything but make sure that doesn't create any further confusions. So, if you change it to user_id then make changes to your both models, for example:
public function user() {
return $this->belongsTo('User','user_id');
}
But, if you use user_id then you may omit the second argument from both model's relationship method, so you may write:
// Feeling
return $this->belongsTo('User');
// User
return $this->hasMany('Feeling');

Categories