Accessing Eloquent Relationship Automatically when loaded - php

I am working on a project which requires me to get all the list of all information from a table --Just like in a blog, i used the all() method to do this but when i try to get the method i declared in my Model i get an error, saying
the collection instance does not exists
But when i use The
Model::find($id)->relationship()->name;
it works fine. Is there any way to load all relationship with the all() function in laravel.
Thanks for your help..

When you perform Model::find($id)->relationship(); you are actually accesing to the Dynamic relationships Properties
You need to convert it into a collection using Model::find($id)->relationship()->get();
Then you can perform any collection method to get the result you want. After doing this you can access to its attributes like this:
$model_varible = Model::find($id)->relationship()->get();
$model_variable = $model_variable->find($id)->name;
Let me know if this works for you.

You should use relationship without brackets to access the model:
Model::find($id)->relationship->name;
And use "with()" to populate the relationships:
Model::where('published', 1)->with('relationship')

Related

Does a one-to-one relationship in Laravel always need first()?

I have a one-to-one relationship between User and UserSettings models,
But (after $user = auth()->user()) when I try $user->settings()->something it throws an Undefined property error.
It's gone when I use $user->settings()->first()->something...
My question is, is this how it's supposed to work? or am I doing something wrong?
You cannot directly run $user->settings()->something.
Because when you call $user->settings(), it just return Illuminate\Database\Eloquent\Relations\HasOne object.
So it is not the model's object, you need to take the model's object and call its attribute like this.
$user->settings()->first()->something;
Dynamic Properties
Since you have one-to-one relationship between User and UserSettings.
If you have a one-to-one relationship in your User model:
public function settings()
{
return $this->hasOne('App\Models\UserSettings', 'user_id', 'id');
}
According to Laravel doc
Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model:
Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method. It will then be accessible via a dynamic property by the same name as the relation.
So you can use eloquent's dynamic properties like this:
$user->settings->something; // settings is the dynamic property of $user.
This code will give you a result of collection.
$user->settings;
So calling 'something' is not available or it will return you of null, unless you get the specific index of it.
$user->settings()->something
while this one works because you used first() to get the first data of collection and accessed the properties of it .
$user->settings()->first()->something
The first method returns the first element in the collection that passes a given truth test
see docs here laravel docs
If you want to get the user settings itself simply do this:
$user->settings
Then you can get the fields of the settings doing this:
$user->settings->something
When you do this $user->settings() you can chain query after that. E.g.
$user->settings()->where('something', 'hello')->first()
That's why the output of $user->settings and $user->settings()->first() are the same.
Auth only gives you user info;
Try the following code:
$user = User::find(auth()->user()->id);//and then
$user->settings->something;

save a belongsTo relationship

I have a classic one-to-many relationships, and I am trying to save the model of the belongsTo side.
The 2 models have these relationships:
// Model myModel
function domicile()
{
return $this->belongsTo('App\Address', 'domicile_id');
}
// Model Address
function myModels()
{
return $this->hasMany('App\MyModel', 'domicile_id');
}
This is what I am tryng to do to save it:
$myModel->domicile()->save($my_array);
With this code I get the error:
Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::save()
if I use this code (without the brackets):
$myModel->domicile->save($my_array);
I do not get any error but the model is not saved.
I know there is the method associate, but I need to update an existent record, not to save a new one.
Because $myModel->domicile()->save($my_array); is totally different to $myModel->domicile->save($my_array); :
$myModel->domicile() will produce a BelongsTo object, doesn't support the save because save is a method of HasMany instances, instead for BelongsTo instances you should use associate(YourModel)
$myModel->domicile will produce a Model object of the associated element, which support the save(array) method, but that array is a options array, as api says https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Model.html#method_save
So in other words, if you have a one (address) to many (domicile) relation, if you want to associate to the address one or many domiciles, you have to use save or saveMany (https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Relations/HasMany.html#method_save), instead if you want to associate to a domicile a address, you should use associate (https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Relations/BelongsTo.html#method_associate)... keep in mind that if you want to do this, you should call the properties with the brackets, in order to have back a HasMany object or a BelongsTo object, and not a Model or a Collection (which you will get if you call the properties without the brackets)
Instead of using the save function, in order to save a belongsTo relationships you have to use the fill function.
In this way:
$myModel->domicile->fill($my_array);
$myModel->domicile->save();
You must use associate() + save() in order to store a BelongsTo relationship:
$myModel->domicile()->associate($domicile);
$myModel->save();
See Laravel Docs

When not or should use get() in Laravel 5

I need to understand when/not to use get(); in Laravel 5.
PHP warning: Missing argument 1 for Illuminate\Support\Collection::get()
Google shows me answers to their issue but no one really explains when you should/not use it.
Example:
App\User::first()->timesheets->where('is_completed', true)->get(); // error
App\Timesheet::where('is_completed', true)->get(); // no error
Fix:
App\User::first()->timesheets()->where('is_completed', true)->get(); // no error
Noticed the timesheets() and not timesheets? Could I have a detail explanation for what is going on, please?
I'm coming from a Ruby background and my code is failing as I do not know when to use () or not.
I'll try to describe this as best I can, this () notation after a property returns an instance of a builder, let's take an example on relationships,
Say you have a User model that has a one-to-many relationship with Posts,
If you did it like this:
$user = App\User::first();
$user->posts();
This here will return a relationship instance because you appended the (), now when should you append the ()? you should do it whenever you want to chain other methods on it, for example:
$user->posts()->where('some query here')->first();
Now I will have a the one item I wanted.
And if I needed say all posts I can do this:
$user->posts;
or this
$user->posts()->latest()->get();
$user->posts()->all()->get();
So the key thing here is, whenever you want to chain methods onto an eloquent query use the (), if you just want to retrieve records or access properties directly on those records then do it like this:
$user->posts->title;
Well, ->timesheet returns a collection, where ->timesheet() returns a builder.
On a Collection you can use ->where(), and ->get('fieldname'), but no ->get().
The ->get() method can be used on a builder though, but this will return a collection based on the builder.
Hope this helps.
The 'problem' you are facing is due to the feature of being able to query relations
When accessing a relation like a property, ->timesheets, the query defined in the relationship is executed and the result (in the form of a Collection) is returned to you.
When accessing it like a method, ->timesheets(), the query builder is returned instead of the resulting collection, allowing you to modify the query if you desire. Since it is then a Builder object, you need to call get() to get the actual result, which is not needed in the first case.
When you use ->timesheets you are accessing a variable, which returns the value of it (in this case an instance of Collection).
When you use ->timesheets() you are invoking whatever is assigned to the variable, which in this case returns an instance of Builder.
whilst pascalvgemert's answer does answer your problem regarding Laravel, it does not explain the difference between accessing or invoking a variable.
In simple term
$user = App\User::get();
is used to fetch multiple data from database
rather
$user = App\User::first();
is used to fetch single record from database

Laravel Eloquent collection attributes

I'm developing a webapp with Laravel 5.2 but there is an issue that I can't solve.
I have a model which extends Eloquent Model but when I try to output my database table with "where", for example
\App\MyModel::where('id_table', 23)->first();
It return a collection with many informations not useful for me at this moment like 'guarded', 'keytype'... and my table's data are under 'attributes'.
Following laravel's guide I see everybody use simply where like me and then output with $mytable->myvalue, but this cannot work for me of course.
Here a screenshot with the collection I'm talking about:
How can I get always just attributes when I use something like "::where()"?
I've tried getAttributes() but it gives me a 500 error.
If you want to get just couple of attributes do many things. Probably first way will be the best for you:
Use pluck():
\App\MyModel::where('id_table', 23)->pluck('id', 'name');
Use select():
\App\MyModel::select('id', 'name')->where('id_table', 23)->get();
Use get() with parameters:
\App\MyModel::where('id_table', 23)->get(['id', 'name']);
If you want to get Eloquent collection and only then build an array with just attributes, you can use toArray():
\App\MyModel::where('id_table', 23)->get()->toArray();
If you want to get some attributes to a new collection, use pluck() on collection:
$collection = \App\MyModel::where('id_table', 23)->get();
$names = $collection->pluck('name');

Searching relationship collection for attribute value in Eloquent Laravel5

This should be simple but for some reason I am unable to get the expected response. I have a model (App\Product) that has many permissions (App\ProductPermission) and my objective is to check if a product holds a particular permission described by a text string. I can access these fine like..
\App\Product::find($id)->permissions
This will give me the collection of ProductPermission objects as expected. One of the attributes of the ProductPermission model is 'permission' which is the text string. For example "users*".
I want to be able to do something similar to this
\App\Product::find(3)->permissions->search($permission) //$permission = "users*"
But this returns false despite a ProductPermission object with the attribute permission=users* existing. How can I search the attributes (or the specific attribute) of all the objects in the relationship collection?
Thanks in advance..
This works...
\App\Product::find($id)->permissions->where('permission',$permission)->count();
But its not as pretty
You may use whereHas like follows:
$productsWithPermissionsCount = Product::whereHas('permissions', function ($query) {
$query->where('permission', '=', $permission);
})->count();

Categories