Laravel Non-Mutating Collection `put()` Method - php

Does Laravel have a collection method that does the same thing as ->put() but does not mutate the original collection?
What I'm looking for:
<?php
$collection = collect(['key' => 'value']);
$new = $collection->putProperly('another', 'pair');
$collection // => ['key' => 'value']
$new // => ['key' => 'value', 'another' => 'pair']
I already know I can do this:
$new = $collection->merge(['another' => 'pair'])

There is no such method as seen in the list of available methods on the official doc but you can achieve the desired result easily by using the clone keyword like this:
$new = (clone $collection)->put('another', 'pair');
Keep in mind that clone performs a shallow copy, therefore be careful if your collection contains objects which you also want to clone.

Related

UpdateOrCreate with model instance

I am using PHP 7.1.33 and Laravel Framework 5.8.36.
I am getting receiving data from a database row-by-row and I am creating a model using updateOrCreate() like the following:
foreach ($arr as $v) {
$product = new Product();
$product->name = $v['name'];
$product->url = $v['url'];
$product->price = $v['price'];
// save
$matchThese = ['name' => $name, 'url' => $url];
$product->updateOrCreate($matchThese);
}
However, nothing gets created.
Any suggestions what I am doing wrong?
I appreciate your replies!
updateOrCreate takes 2 parameters ($attributes, $values).
$attributes is an array containing key-value pairs which will basically be used for where clauses i.e. it will check the database for the attributes passed in this array.
$values is an array containing key-value pairs of what to update in the database.
If it can't find a row in the database matching the first array it will combine the values in the arrays to create a new row.
To achieve what you're after you can do:
Product::updateOrCreate(
['name' => $v['name'], 'url' => $v['url']],
['price' => $v['price']]
);
Try this way
Product::updateOrCreate(
['name' => $name, 'url' => $url],
['price' => v['price']],
)
First parameter is for search the register.
Second parameter set new values.
For more information, you can read Eloquent: Getting Started - Documentation

Difference between $object->attribute and $object['attribute'] in Laravel

I'm developing with DataTables in Laravel and trying to make an object manually using collect() to create a collection. When I push the collection into the DataTable, there is something wrong, and I can't call my object with this $object->attribute.
After I get the error with that, I already tried to call an attribute with $object['attribute'], and it works well.
Can someone give me insight about the differences and how I can convert $object['attribute'] into $object->attribute?
This is my query to create object
$result = collect();
$item = collect([
'row' => ($key+1),
'item_id' => $value->uid,
'item' => $value->nama_item,
'sub_kategori' => $value->sub_jenis_item->sub_jenis_item,
'kategori' => $value->jenis_item->jenis_item,
'gudang_id' => $id_gudang
]);
$result->push($item);
Accessing $object['attribute'] means $object is an array and accessing $object->attribute means $object is an object.
To convert array to object:
$object = (object) $object;
Additionally, to convert object to array:
$object = (array) $object;
DataTables calls internally toArray() on the collection items when you build the table. This happens during transformation of the data. It will also flatten nested objects (e.g. loaded Eloquent relations in case of an EloquentDataTable) into an array with depth 1 (per row of the table).
You can try the following way,
$result = collect();
$item = collect([
'row' => ($key+1),
'item_id' => $value->uid,
'item' => $value->nama_item,
'sub_kategori' => $value->sub_jenis_item->sub_jenis_item,
'kategori' => $value->jenis_item->jenis_item,
'gudang_id' => $id_gudang
]
);
$result->push($item);
$resultObj = json_decode($result);
foreach($resultObj as $obj){
echo $obj->row;
}

(Laravel 5.3) How to add new key and value to existing sub array in existing Collection?

I am using Laravel 5.3.
existing Collection $a is
$a = collect(
[
0 =>[
'firstName' => 'John',
'lastName' => 'Doe'
],
1 =>[
'firstName' => 'Mary',
'lastName' => 'Jane'
]
]);
and desired result is as below:
$a = collect(
[
0 => [
'firstName' => 'John',
'lastName' => 'Doe',
'occupation' => 'engineer'
],
1 => [
'firstName' => 'Mary',
'lastName' => 'Jane',
'occupation' => 'accountant'
]
]);
I tried to test ->push(), ->put(), ->prepend() but no success. Please let me know the best way to do this.
You can use transform method which iterates over the collection and calls the given callback with each item in the collection. The items in the collection will be replaced by the values returned by the callback:
$a->transform(function ($item, $key) {
$item['occupation'] = 'some_value';
retrun $item;
});
Then check the value of $a:
dd($a);
Note that you have a collection of arrays, not a collection of collections. Hence, you can't use push(), put(), etc., in the sub-arrays.
The easiest way is probably just to treat it as an array:
$a[0]['occupation'] = 'engineer';
But you can also access at least the first element through the getter if you'd like:
$a->get(0)['occupation'] = 'engineer';
If you have an existing collection then you can get all the arrays from it using something like this:
$items = $existingCollection->all();
Now, you have an array of arrays in $items. So you can add key/value using something like this:
$item[0]['occupation'] = 'engineer';
$item[1]['occupation'] = 'accountant';
Now, you've modified the arrays so if you want to turn it back into a collection then you can do it easily using this:
$existingCollection = collect($items);
You could've also used map on the collection directly, for example:
$existingCollection->map(function ($person) {
$person['occupation'] = 'engineer';
return $person;
});
In this case, you can see that, all the person's occupation is going to be same but you can find out a way to make the difference but I can't give you more precise solution because I don't know much about your situation (You didn't share much).

Laravel 5: How to saveMany() based on value

I need a little help with the following situation.
I am willing to saveMany based on the input value. Let me give code example.
I was experimenting with the following.
$data = [
'id' => 1,
'name' => 'example',
'number_of_slots' => 5,
'material' => 'Colo',
'equipment_status_code_id' => 1,
];
$platecontainer = PlateContainer::create($data);
foreach ($data as $key => $value) {
$platecontainer->containerSlots()->saveMany([
new ContainerSlot([
'plate_container_id' => $data['id'],
'slot' => $data['number_of_slots'],
'occuiped' => false,
])
]);
}
until $platecontainer everything works just great. What I want is when a PlateContainer is created using the data array, I want to create slots as well, but this one is based on number_of_slots
So for instance number_of_slots in the example is 5 so I want to save 5 records in (descending order) in the ContainerSlot table
so the containerslots table will end up looking something like this.
The save many method accepts an array of models, so just use a for loop for the $plateContainer's number_of_slots
$plateContainer = PlateContainer::create($data);
$containers = [];
// Need to add one to our number of slots because
// the $i count starts at one instead of zero.
$slots = $plateContainer->number_of_slots + 1;
for($i = 1; $i < $slots; $i++) {
$containers[] = new ContainerSlot([
'plate_container_id' => $plateContainer->getKey(),
'slot' => $i,
'occuiped' => false,
]);
}
$plateContainer->containerSlots()->saveMany($containers);
You can use createMany (array of arrays of attributes) instead of saveMany (array of models new or existing). Useful for API calls.
An alternative, if you want to insert data based on value, you can prepare your array and let the model insert in bulk.
$itemRebates = array_map(function ($rebateId) use ($payoutItem) {
return [
'rebate_id' => $rebateId,
'payout_item_id' => $payoutItem->id
];
}, $rebateIds);
PayoutItemRebate::insert($itemRebates);
This way you don't need to wrap your data in multiple model instances.
Additional details
I tried to use the insert method from $payoutItem->historyRebates() but it didn't take the payout_item_id from the relationship. So it's better to use the model itself.
My first attempt was to use saveMany, but even preparing the data, it doesn't work with arrays, only with model instances. I wanted to avoid that.

How to make associative array in Yii2?

I would like to make associative array using foreach to use in Yii 2 dropdownlist.
My goal is to make array like following using foreach-
$array= [
['id' => '123', 'name' => 'abc'],
['id' => '124', 'name' => 'def'],
];
And then I want to use them using Yii 2 ArrayHelper::map().
$result = ArrayHelper::map($array, 'id', 'name');
How do I make the array using foreach?
Yii way to build items for drop-down list is exactly as you described, using ArrayHelper::map():
$items = ArrayHelper::map($array, 'id', 'name');
You don't need to use foreach here, just pass results of ActiveQuery as array:
$array = YourModel::find()->all();
Update:
Thanks. But here, I am actually calculating custom value for 'name'
and for that reason I want to use foreach to generate the array after
the calculation
You definetely need to add this information to the question, but anyway, you can use the ArrayHelper for that too. Take a look at toArray method. It can be used for both object / array of objects. After processing with this method you can use map.
Official docs:
ArrayHelper::map()
ArrayHelper::toArray()

Categories