In a Laravel 5 Collection how do you return an array of objects instead of an array of arrays?
Solution 1
Figured out the problem. I was explicitly defining the attributes in the Model. Laravel uses __get() in a particular way which causes passed parameters to be overridden whatever attributes are explicitly defined.
In other words, I was getting null values in the partial because the info I was passing to the partial was overridden.
Solution 2
According to the Docs:
$array = $collection->all();
"The all method returns the underlying array represented by the collection."
Solution 3
Your code is just fine, except you don't need to call toArray
on your Eloquent query result. Let me explain what the code does, so you can understand why the following is what you want:
$models = Foo::where('id', '>', 5)->get();
return view('home.index', ['models' => $models]);
The first statememt Foo::where('id', '>', 5)->get();
returns a value of type Illuminate\Support\Collection
.
That Collection
class holds the collection elements in a protected property called $items
(as you could see from your dump protected 'items' =>
), which is of type array
. The class also implements an interface called IteratorAggregate, which basically means it allows any variable of that type to be iterated using a foreach
statement.
In your case this means that, even if $models
is of type Illuminate\Support\Collection
it will behave as an array when you go over it with foreach
:
@foreach ($models as $model)
{
{{ $model->foo }}
}
So in short Collection
is an iterable object that can be treated as an array, but is better than an array because if offers extra methods that allow you to manipulate the items from the collection. You can check the Collection API to see a complete list of available methods.
So in reality you're getting an improved array of models.
Also, don't worry that the properties are not filled, they are in fact filled, I just think you're looking in the wrong place.
If you look closely at your var_dump
, you'll see that you have some lines that start with public
, protected
or private
. Those keywords mean that those lines contain object properties. In the case of Laravel Eloquent models, the values fetched from the database are not stored directly in the properties that are named like the database columns. The values are in fact stored in a single property called attributes
and are fetched using PHP's magic _get
. Take a look at the comments on the code below:
object(Illuminate\Support\Collection)[164]
protected 'items' =>
array (size=3)
0 =>
object(App\Foo)[172]
public 'id' => null // <<< THE VALUES ARE
public 'foo' => null // <<< NOT STORED HERE
private 'created_at' => null
private 'updated_at' => null
protected 'connection' => null
protected 'table' => null
protected 'primaryKey' => string 'id' (length=2)
protected 'perPage' => int 15
public 'incrementing' => boolean true
public 'timestamps' => boolean true
protected 'attributes' =>
array (size=4)
'id' => int 1 // <<< THEY ARE HERE
'foo' => string 'Foo!' (length=4) // <<< AND HERE
'created_at' => string '2015-02-27 15:44:09' (length=19)
'updated_at' => null
Laravel does a lot of trickery behind the scenes to allow you to get things done with only a few lines of code. That's why a var_dump
will not always display the simple data structures that you might expect.
ebakunin
Updated on July 09, 2022Comments
-
ebakunin almost 2 years
I am using Laravel 5 and a Blade template. In a view I want to iterate over an array of Model objects, not an array of arrays. If I did want to iterate over an array of arrays I would do the following, which works as expected:
$models = Foo::where('id', '>', 5)->get(); return view('home.index', ['models' => $models->toArray()]);
However I want an array of objects with accessible properties. If I were to run:
$models = Foo::where('id', '>', 5)->get(); return view('home.index', ['models' => $models->all()]);
The
var_dump
would look like this:object(Illuminate\Support\Collection)[164] protected 'items' => array (size=3) 0 => object(App\Foo)[172] public 'id' => null public 'foo' => null private 'created_at' => null private 'updated_at' => null protected 'connection' => null protected 'table' => null protected 'primaryKey' => string 'id' (length=2) protected 'perPage' => int 15 public 'incrementing' => boolean true public 'timestamps' => boolean true protected 'attributes' => array (size=4) 'id' => int 1 'foo' => string 'Foo!' (length=4) 'created_at' => string '2015-02-27 15:44:09' (length=19) 'updated_at' => null
Not only is the Model in an 'items' object the properties are not filled.
In a view I would like to do something like this:
@foreach ($models as $model) @include('_partial') { 'id' => $model->id, 'foo' => $model->foo, } @endforeach
How do I get an array of Models instead of an array of an array of Models?
-
ebakunin about 9 yearsThe problem here is that the properties return empty values. In other words,
$model->id
and$model->foo
will always return null as shown in thevar_dump
above. -
Bogdan about 9 yearsI'll update my answer in a minute, explaining why that's not the case.
-
ebakunin about 9 yearsEven if I use
$Model->attributes
I am still relying on an array. What I want is to always have$model->id
, not$model['id']
or$model->attributes['id']
. The magic getter does not seem to return the needed values. Maybe I'm fundamentally misunderstanding something. -
Bogdan about 9 yearsYou can use
$model->id
. When you write$model->id
, the model class determines that you want the value of the columnid
and knows to find and return it from theattributes
array. It does this using the PHP _get method I referenced in the answer. Your code will work as you need it to, because Laravel does its magic behind the scenes. -
Bogdan about 9 yearsAlso, to pass data to partial views in Blade you need to pass it as a second parameter of type array, like so:
@include('_partial', ['id' => $model->id, 'foo' => $model->foo])
. -
Bogdan about 9 yearsAccording to the
var_dump
you posted the values are there, so the code must work. If it doesn't, it may mean your problem lies elsewere in your code. -
ebakunin about 9 yearsThis discussion is getting long but the "move this discussion to chat" is not working, so I will continue it in an another answer. Admins, please correct this as need be.
-
Bogdan about 9 yearsTry outputting your the data directly in the
@foreach
loop (like I wrote in my answer) without using the@include
. See if that works. And don't mind the move the discussion message, it's a suggestion not a requirement. -
Bogdan about 9 yearsLet us continue this discussion in chat.
-
Nurbol Alpysbayev about 6 yearsThis is correcct answer to the question. Thanks!
-
Serdar D. almost 3 yearsThanks! @ebakunin please mark this one as correct answer