Laravel Eloquent collection attributes - php

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');

Related

Why is it not possible to use groupBy() in an eager loading query - Laravel

ErrorException:
stripos() expects parameter 1 to be string, object given
For the groupBy() call in the with() method
$user = User::with([
'pricelists' => function($query) {
$query->groupBy(function($var) {
return Carbon::parse($var->pivot->created_at)->format('m');
});
}
])->where('id', $id)->get();
I already saw a few posts talking about how to manage this problem and that it shall not be possible to use groupBy() in eloquent but I do not really understand why...
To be clear:
User and Pricelist model got a many-to-many relationship with the default timestamps() method. I am trying to get the downloaded pricelists grouped by their months they were downloaded from the current user.
After a few attempts I just deleted the above shown => function($query... statement from the with() method and just left the with(['pricelist']) to fetch all datasets and tried this:
$user->pricelists = $user->pricelists->groupBy(function($var) {
return Carbon::parse($var->pivot->created_at)->format('m');
});
return $user->pricelists;
And it works fine and returns an array with multiple arrays for each month... But returning it like this:
return $user;
returns just 1 array with all entries... I do not really get the sense behind it right now...
The two groupBy() method that you are using in the two code you provide are totally different methods.
The first groupBy() where you use it in the callback is actually being called by $query which is a query builder object. The groupBy() here is used to add SQL GROUP BY Statement into the query. And as per the documentation, it only take string variables as parameter.
The groupBy() in your second code is being called by $user->pricelists which is a laravel eloquent collection. The groupBy() method here is actually from the base collection class and is used to group the items inside the collection into multiple collections under the different key defined by the parameter passed to the function. Please read the documentation here.
For your case, the second groupBy() is the one you should be using since you plan to use a callback and will allow you to use more complicated logic.

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;

Accessing Eloquent Relationship Automatically when loaded

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')

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();

Querying on related models using Laravel 4 and Eloquent

Using Laravel 4 I have the following models and relations: Event which hasMany Record which hasMany Item. What I would like to do is something like this
Item::where('events.event_type_id', 2)->paginate(50);
This of cause doesn't work as Eloquent doesn't JOIN the models together when retrieving the records. So how do I go about this without just writing the SQL myself (which I would like to avoid as I want to use pagination).
What you want is eager loading.
It works like this if you want to specify additional constraints:
Item::with(array('events' => function($query) {
return $query->where('event_type_id', 2);
}))->paginate(50);
There is a pull request pending here https://github.com/laravel/framework/pull/1951.
This will allow you to use a constraint on the has() method, something like this:
$results = Foo::has(array('bars' => function($query)
{
$query->where('title', 'LIKE', '%baz%');
}))
->with('bars')
->get();
The idea being you only return Foos that have related Bars that contain the string 'baz' in its title column.
It's also discussed here: https://github.com/laravel/framework/issues/1166. Hopefully it will be merged in soon. Works fine for me when I update my local copy of the Builder class with the updated code in the pull request.

Categories