DB::get is Array in Laravel but it says it is not array - laravel

I thought the data which is from DB::get() is Array.
However , the console says it is not array.
$fruitList = Food::where('id' => 300)->get(['id']);
shuffle($fruitList);
ErrorException: shuffle() expects parameter 1 to be array, object given in file

The return value of get() is not an array. it's Laravel array collection you can convert it to an array or use shuffle of array collection:
$fruitList = Food::where('id' => 300)->get(['id'])->toArray();
shuffle($fruitList);
with array collection:
$fruitList = Food::where('id' => 300)->get(['id'])->shuffle();

Just like #A.seddighi mentioned, using get() or all() gives you a collection. It may seem like an array when you output it using return or print but it is different.
Collections can be filtered, queried and so on. e.g
$fruitList->has('price')
etc.
To get an array simply called the toArray() method on it, you may also use flatMap(), mapWithKeys() etc. Make sure you follow the documentation that is suitable for your version of laravel.

Related

Laravel create collection with named properties from scratch

My question is similar to this question Adding new property to Eloquent Collection, but I need some further explanation.
In many occasions it would be really useful to be able to construct your own collections and use Laravel collection methods. The docs only explain how to make a simple collection of nameless items (a 1 dimensional data set), but I'm interested in 2 dimensional data sets.
For example when you use Laravel validator, it takes your named array of inputs and spits out a Illuminate\Support\ValidatedInput object, which is a collection. Then you can access your properties as properties in any object and also use collection methods such as only() or except().
$safe = $request->safe(); //returns a Illuminate\Support\ValidatedInput collection
//$safe = $request->validate(); //returns an associative array
echo $safe->my_prop;
Model::create( $safe->only(['prop1', 'prop2']) );
My objective is to transform an associative array such as:
$a = [
'prop1' => 'val1',
'prop2' => 3656,
'prop3' => ['stuff', 'more']
];
Into a collection that can be used like the Illuminate\Support\ValidatedInput object.
PS I'm currently using arrays and array functions (like array_intersect_key() as a substitute to ->only()), but would rather use collections.
Using
$c = collect( $a );
you cannot access the properties of $c like $c->prop, you still need to use $c['prop']. Which is confusing, given that many objects in laravel are both objects (which allow $object->property) AND collections.

Laravel Collection Filter breaking serialization format

I have a serialized String like this
$string = '[{"name":"FOO"},{"name":""},{"name":"BAR"}]';
I am trying to process it via Laravel Collection's filter method and eliminate items without a defined "name" property.
$collection = collect(\json_decode($string));
$collection = $collection->filter(function($v){
return !empty($v->name);
});
$string = \json_encode($collection->toArray());
dd($string);
Normally I am expecting something like this:
[{"name":"FOO"},{"name":"BAR"}]
But I'm getting something like this:
{"0":{"name":"FOO"},"2":{"name":"BAR"}}
Funny thing is, if I skip the filtering process or return true every time, I keep getting the string in the desired format. Removing the toArray() call has the same result. I don't want to keep the numeric indices as associative object keys.
Why this anomaly? And what should I do to get the serialized data in desired format?
In PHP arrays the index key must be unique.
In your case you have the key 'name' and collection automatically assigns the index key to all items in the collection.
To overcome that problem just call
$string = \json_encode($collection->values());

Convert Array of objects to array of integers

I need to convert the following array of objects to array of integers in laravel. Below is the code which I need to convert as an array.
$idArray = DB::table('booking_header')
->select('booking_header.id')
->where('booking_header.parent_booking_id', $oldId)
->get();
I tried with pluck(). But it doesn't work. Can anyone help me?
Use pluck() insted of get() to get a simple array of ids.
$idArray = DB::table('booking_header')
->select('booking_header.id')
->where('booking_header.parent_booking_id', $oldId)->pluck('booking_header.id');

Laravel | groupBy returning as object

I am trying to use a Laravel collection to return a groupBy as an array. However, it always seems to be returned as an object no matter what. I have tried to do $posts->groupBy('category')->toArray() but this seems to still return as an object. I have also tried $posts->groupBy('category')->all() and still it is returning as an object.
I don't know if this is something to do with Laravel returning methods within the routes, but I need this to return as an array.
Here is the code:
public function getFeatures($id)
{
return Feature::query()->get()->groupBy('category')->toArray();
}
The actual code is working fine and I'm getting results back but it just doesn't seem to be converting to an array. Thanks.
When doing a query to get (possibly) several items using Eloquent, Laravel will always return an instance of the Collection class that contains all the model objects. If you need them converted to array to use them in a view you could compact the elements. compact will make an associative array of the elements of the collection:
public function getFeatures($id)
{
$features = Feature::all();
return view('my_cool_view', compact($features));
}
On the other hand, if you need them converted to array to return them through an API, Laravel convert the response to JSON by default:
public function getFeatures($id)
{
return Feature::all();
}
Now, if you somehow need the collection converted to an array, just use toArray() like you indicated:
public function getFeatures($id)
{
$collection_of_features = Feature::all();
$array_of_features = $collection_of_features->toArray();
// use it for wherever you want.
}
By reading your comment on other answer, I realized what you mean.
Hi #HCK, thanks for the answer. The ->toArray() method doesn't seem to work and still returns it like { "category_1": [], "category_2": [] } whereas I need it to do ["category_1": [], "category_2": []]
First, this answer is based on a guess that you are doing something like this on your controller (you didn't posted the controller code):
return reponse()->json($theResponseFromGetFeaturesMethod);
Since inside php the $theResponseFromGetFeaturesMethod variable contains an dictionary array (something like ["key"=>"value]), when you convert it to a JSON, you will notice that this "conversion" happens.
This happens because Javascript arrays (and JSON) doesn't support dictionary arrays. See this sample on javascript console:
> var a = [];
undefined
> a['key'] = "value"
"value"
> a
> key: "value"
length: 0
__proto__: Array(0)
Note that the a still have a length of zero, but it now have an key property.
This happens because almost everything on javascript is actually an object. So the array is a special kind of object that have push, pop and many other array methods. Doing array[] = 'somevalue' is actually a shortcut to array.push('somevalue').
So, the behavior that you are observing is right, the toArray() method work as expected, and the JSON conversion too.
Another weird behavior is when you try to convert this PHP array to an JSON:
[
0 => 'a'
1 => 'b'
9 => 'c'
]
You will note that in this case, PHP will convert this array to an object too. The result in JSON will be:
{
"0": "a",
"1": "b",
"2": "c"
}
This is also the expected behavior, since the JSON syntax doesn't support defining the index for a value.

select certain columns from eloquent collection after the query has executed

Using Laravel 5.3, I have a model with the following function
public function myData() {
return $this->hasMany(MyData::class);
}
and in my collection I have the following
$my_data = MyModel->myData()->get();
All good so far. If I return $my_data I get an eloquent collection with three items.
What I need now though is to create a duplicate of that collection but containing only three of the fields.
I have tried several different things, each of which return an error. The following is the closest I have got, but this returns an empty array - I assume because the fields are located one level deeper than the collection object.
$new_collection = $my_data->only(['field_1', 'field_2', 'field_3']);
What would be the correct way to create a new collection containing all three items, each with only the three selected fields?
Thanks for your help
You could use map:
$slimmed_down = $collection->map(function ($item, $key) {
return [
'field_1' => $item->field_1,
'field_2' => $item->field_2,
'field_3' => $item->field_3
];
});
This will return a new Collection with just the values you want. As far as I know there isn't any other method that does what you want, so iterating over every item and selecting the fields this way is one of the few solutions.
The advantage of using map instead of a standard foreach loop is that when you use map it returns a new instance of Collection.
Edit:
After some thoughts and research about this, the problem you'll have created is that the all the values in the Collection aren't instances of anything anymore. If you don't mind this effect, an even prettier and faster way would be to do this:
$slimmed_down = $collection->toArray()->only(['field_1', 'field_2', 'field_3']);
This basically has the same result.
Using Laravel 9, I just had the same issue :
$my_data->only(['field_1', 'field_2', 'field_3']);
returning an empty array.
I solved it with :
$my_data->map->only(['field_1', 'field_2', 'field_3']);

Resources