Call Eloquent collection functions - laravel

I have created a model relationship between 3 different tables/models.
Since I get a collection of objects due to hasMany-property I have to use a for-loop to access each of the Models methods in order to get the data I want.
Is there anyway to tell that I want it to run the same function on all the objects?
Pseudo code:
Model A //HasMany Model B
Model B //HasMany Model C, Belongs to A
Model C //BelongsTo C
$foo = new User::Find(Auth::id());
//Need to loop the collection of data in order to get the information
foreach($foo->permissions as $permission)
{
$name = $permission->permissionsTypes->name;
}
I have tried to do this:
$foo->permissions->permissionsTypes;
But since it is a collection it does not work.
Is there any other way to get this information without looping through the array?
Thanks for any guidance!

Use pluck() and collapse():
$permissionsTypes = $foo->permissions->pluck('permissionsTypes')->collapse();

Might be you have defined the hasMany relationship if yes then please change hasMany into hasOne then
foreach($foo->permissions as $permission)
{
$name = $permission->permissionsTypes->name;
}
Or you could just get one of objects by it's index:
{{ $permission[0]->name}}
Or get first object from collection:
{{ $permission->first() }}
When you're using find() or first() you get an object, so you can get properties with simple:
{{ $object->name}}

Related

Laravel Eager-loading works only when calling attribute

I've defined my Slot model to load the relations from User model like so :
public function userAssignedFull(): HasOne {
return $this->hasOne(User::class,'id','user_assigned');
}
('slots' table contains 'user_assigned' field by which I connect to User records on 'id')
The following code finds Slot model but without 'userAssignedFull'. I get only the user ID in 'user_assigned'.
$slot = Slot::with('userAssignedFull')->find($slot_id);
But calling this afterward returns me the wanted relation:
$fullUserModel = $slot->userAssignedFull;
Can anyone tell me what am I doing wrong ?
Builder::with() returns the Builder instance.
So you have to call $slot->userAssignedFull; to get the collection of data.
From the docs:
When accessing Eloquent relationships as properties, the relationship
data is "lazy loaded". This means the relationship data is not
actually loaded until you first access the property.
And this $slot->userAssignedFull; is your "first access the property".
Try this
$slot = Slot::where('id', $slot_id)->with('userAssignedFull')->first();
$slot->userAssignedFull;

Get specific values from controller function

I started learning Laravel and I am trying to achieve the following:
Get data from database and display specific field.
Here is my code in the controller:
public function show()
{
$students = DB::select('select * from students', [1]);
return $students;
}
Here is my route code:
Route::get('', "StudentController#show");
That all works for me and I get the following displayed:
[{"id":1,"firstname":"StudentFirstName","lastname":"StudentLastName"}]
How can I get only the "lastname" field displayed?
Thanks in advance!
DB::select('select * from students')
is a raw query that returns an array of stdClass objects, meaning you have to loop through the array and access properties:
$students[0]->lastname
You can also use the query builder to return a collection of objects:
$collection = DB::table('students')->get();
$student = $collection->first();
$student->lastname;
Lastly, using the query builder, you can use pluck or value to get just the last name. If you only have one user, you can use value to just get the first value of a field:
DB::table('students')->where('id', 1)->value('lastname');
I strongly advise you to read the Database section of the Laravel docs.
$students[0]['lastname'] will return the last name field, the [0] will get the first student in the array.
I would recommend creating a model for Students, which would make your controller something like this:
$student = Students::first(); // to get first student
$student->lastname; // get last names
If you only want the one column returned, you can use pluck()
public function show()
{
$last_names= DB::table('students')->pluck('lastname');
return $last_names;
}
This will return an array of all the students' lastname values.
If you want just one, you can access it with $last_names[0]
As a side note, your show() method usually takes a parameter to identify which student you want to show. This would most likely be the student's id.
There are several ways you can accomplish this task. Firstly, I advise you to use the model of your table (probably Students, in your case).
Thus, for example,to view this in the controller itself, you can do something like this using dd helper:
$student = Students::find(1);
dd($student->lastname);
or, using pluck method
$students = Students::all()->pluck('lastname');
foreach($students as $lastName) {
echo $lastName;
}
or, using selects
$students = DB::table('students')->select('lastname');
dd($students);
Anyway, what I want to say is that there are several ways of doing this, you just need to clarify if you want to debug the controller, display on the blade...
I hope this helps, regards!

Laravel: Eloquent "join", how to get only a property of the referred table

I have a model A and a model B.
I made the relations between them, so i can do A->B->property.
But now I'm facing some problems.
I need to make a query and get only that B->property, not the B object.
So i use this:
A::with(['B'])->get()
But then a get a property called B in A with the complete B model.
Is there anyway to achieve something like this.
A::with(['B->property'])->get()
So then in the B property inside A I get the B->property instead the B object.
Is it possible?
PS: I can't use the query builder because i need that eloquent model.
I think this article will help you out:
http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/
You can put
$appends = ['property'] in your model to add a property field to your model.
Then, with an accessor method in the model you can describe how to populate that field (ie: with a field from another model via relationship).
It seems like that ought to give you what you want.
Try below code
In your A model:
protected $appends = ['property'];
public function B()
{
return $this->hasOne('\App\B');
}
public function getPropertyAttribute()
{
return $this->B()->property;
}
then A->property will give you B->property. Change model name and property name as per your requirement.
The answer by #shoieb0101 did not work for me because I had a belongsTo relationship rather than hasOne. If this is the case for you too, you just need to modify the accessor function as illustrated below.
protected $appends = ['property'];
public function B()
{
return $this->belongsTo('\App\B');
}
public function getPropertyAttribute()
{
return $this->B()->first()->property;
}
Note: I added ->first() in since belongsTo returns an array of results, but we can get the property from a single result only.
You should be able to constrain eagerloaded queries:
try
A::with(["B" => function($query){
$query->select('property');
}])->get();

laravel access model properties

I am looking for solution how to access eloquent model items by 'alias' field.
There is no problem accessing items by 'id'. But building a custom query I find myself unable to access item properties.
This piece of code works perfect
$cat = Category::find(1);
return $cat->title;
But if I am querying items with any other argument - properties are inaccessible
This code
$cat = Category::where('alias','=','vodosnab')->get();
return $cat->title;
throws an exception
Undefined property: Illuminate\Database\Eloquent\Collection::$title
Could you please help.
You already got the answer but here are some insights, when you use get() or all(), it returns a collection of model objects, which is an instance of Illuminate\Database\Eloquent\Collection, so here you'll get a Collection object
$cat = Category::where('alias','=','vodosnab')->get();
Now, you can use, $cat->first() to get the first item (Category Model) from the collection and you may also use $cat->last() to get the last item or $cat->get(1) to get the second item from the collection. These methods are available in the Collection object.
Using the first() method like Category::where('alias','=','vodosnab')->first(); will return you only a single (the first mathing item) model which is an instance of your Category model. So, use all() or get() to get a collection of model objects and you can loop through the collection like:
foreach(Category::all() as $cat) { // or Category::get()
$cat->propertyName;
}
Or you may use:
$categories = Category::where('alias','=','vodosnab')->get();
foreach($categories as $category) {
$category->propertyName;
}
Also, you may use:
$categories = Category::where('alias','=','vodosnab')->get();
$firstModel = $categories->first();
$lastModel = $categories->last();
$thirdModel = $categories->get(2); // 0 is first
If you need to get only one then you may directly use:
$category = Category::where('alias','=','vodosnab')->first();
$category->fieldname;
Remember that, if you use get() you'll get a collection of Model objects even if there is only one record available in the database. So, in your example here:
$cat = Category::where('alias','=','vodosnab')->get();
return $cat->title;
You are trying to get a property from the Collection object and if you want you may use:
$cat = Category::where('alias','=','vodosnab')->get();
return $cat->first()->title; // first item/Category model's title
return $cat->last()->title; // last item/Category model's title
return $cat->get(0)->title; // first item/Category model's title
You may read this article written on Laravel's Collection object.
get() returns a Collection of items. You probably need first() that returns a single item.

'Method' vs 'Dynamic Property' in Eloquent ORM with Laravel?

I want to count the number of posts belongs to a tag. Should I use method or dynamic property?
<?php
class Tag extends Eloquent {
public function posts()
{
return $this->belongsToMany('Post');
}
public function postsCount()
{
return count($this->posts);
}
public function getPostsCountAttribute()
{
return count($this->posts);
}
}
So in template should I use dynamic property:
{{ $tag->postCount }}
or method:
{{ $tag->postCount() }}
Excerpt from the documentation of Laravel 4 regarding Eloquent's Dynamic Properties (accessor) in relationships (bold are mine):
Eloquent allows you to access your relations via dynamic properties. 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.
That said, using the method defined for the database relationship or the dynamic property (accessor) will behave differently.
If you issue the post count using the method as follows:
$count = $tag->posts()->count();
That will generate the proper SQL with the COUNT aggregate function.
In the other hand, if you issue the post count using the dynamic property (accessor) as follows:
$count = count($tag->posts);
That will fetch all the posts, convert them to an array of objects, then counting the number of element of the array.
In your case, the choice should depend of the usage of the posts related to a tag. If you just want to count, then use the method and the aggregate function. But, if apart from counting you will be doing something else with those posts, then use the dynamic property (accessor).

Resources