Laravel map(): How to alter objects and arrays? - php

I have a multidimensional collection. I want to iterate it and alter some of its child objects and arrays using the map() function: https://laravel.com/docs/5.1/collections#method-map
Sample content:
[
{
'address': 'Somestreet 99'
'orders': [
{'id': 11},
{'id': 67}
]
}
]
Example
$deliveries = $delivery_addresses->map(function($delivery_address){
$orders = $delivery_address->orders->filter(function($order){
return $order->id == 67;
});
$delivery_address['address'] = 'A different street 44'
$delivery_address['orders'] = $orders;
$delivery_address['a_new_attribute'] = 'Some data...';
return $delivery_address;
});
Expected result:
[
{
'address': 'A different street 44'
'orders': [
{'id': 67}
],
'a_new_attribute': 'Some data...;
}
]
The result is that only string type variables will be changed. Any arrays or objects will stay the same. Why is this and how to get around it? Thanks! =)

collect($deliver_addresses)->map(function ($address) use ($input) {
$address['id'] = $input['id'];
$address['a_new_attribute'] = $input['a_new_attribute'];
return $address;
});

Addressing your recent edits, try this:
$deliveries = $deliver_addresses->map(function($da) {
$orders = $da->orders->filter(function($order) {
return $order->id == 67;
});
$da->unused_attribute = $orders->all();
return $da;
});
What the case most likely is here is that you are correctly overwriting that attribute. Then when you are attempting to access it Laravel is querying the orders() relationship and undoing your changes. As far as Laravel is concerned these are the same:
$delivery_address->orders;
$delivery_address['orders'];
This is why the changes are only working on objects. If you want to save that permanently then actually save it, if not use a temporary attribute to contain that data.

$paymentMethods = $user->paymentMethods()->map(function($paymentMethod){
return $paymentMethod->asStripePaymentMethod();
});

Eloquent collections has a put method (since v5.1), that can be used to add a field to a collection while keeping the 'pipe-style' chaining. It can also be used with the new arrow functions syntax:
$deliveries = $delivery_addresses
->map(fn ($delivery_address) => collect($delivery_address)
->put('orders', Orders::where('delivery_addresses_id', '=', $delivery_address->id))
->toArray()
);

Related

Dynamic Create $input in Laravel Controller to Insert data into table ( Error due to Foreach loop not working properly)

Respected Sir/Ma'am, I have different product and I want to create a dynamic $input in controller to save product information into database
Example
$imput['name'] = $request->get('name');
$imput['price'] = $request->get('price');
$imput['description'] = $request->get('description');
To create above input dynamically in controller I try to use foreach loop and pass Input key and value from Frontend side
Example
[["name", "biryani"], ["size", "full"], ["price", "200"], ["description", "chicken + rice"], ["url",
…],…]
0: ["name", "biryani"]
1: ["size", "full"]
2: ["price", "200"]
3: ["description", "chicken + rice"]
4: ["url",…]
5: ["modelName", "chickenBiryani"]
Code i write in controller
(where i do mistake , this code not working also please give answer which I mention in below code comment , Thank You)
public function upload($productInfo)
{
$input=[];
foreach ($productInfo as $data) {
// return $productInfo -- this return data
// return $data -- this return throw error , why this happen
foreach ($data as $val) {
// return $val -- this return data
if ($val[0] == 'modelName') {
$modelName = '\\App\\' . $val[1];
} else {
$input[$val[0]] = $val[1];
}
}
}
$model = new $modelName;
$model::create($input);
return response()->json(['msg' => 'Profile Image Upload Succeessfully']);
}
Please help me sir i am new in Laravel
In your code, you declared $input = [], but using $imput in the loop. That means $input will always be an empty array.
Secondly, Model::create() accepts a single associative array, not multidimensional array e.g:
[
"name" => "Name",
"user_id" => 23
]
Finally, you might need to fletch out your code to eliminate that double loop. But I'm not sure what you're trying to achieve, so can't suggest edits

Remove row from pagination inside of transform

I have a variable that is a pagination object
$pagination
I am changing things inside of it using transform
$pagination->getCollection()->transform(function ($item, $key) use(&$data, &$pagination) {
$item->foo = 'bar';
}
I want to remove an item from the pagination if it meets a certain condition. I don't want it removed until after I've been able to use the data. Following is an example.
$pagination->getCollection()->transform(function ($item, $key) use(&$data, &$pagination) {
$data[] = $item->foo;
if ($item->foo === 'bar') {
$item->remove();
}
}
I've also tried using $pagination->getCollection()->forget($key); inside of the transform
$pagination->getCollection()->transform(function ($item, $key) use(&$data, &$pagination) {
$data[] = $item->foo;
if ($item->foo === 'bar') {
$pagination->getCollection()->forget($key);
}
}
That's from this question.
How to unset (remove) a collection element after fetching it?
I'm guessing the fact I'm dealing with a pagination may be making these answers not apply to my situation.
Doing a separate collection of pagination with filter() allows removing items from the pagination based on complex conditions. I return false in the transform and then simply target it in the filter.
$pagination = $pagination->getCollection()->filter(function ($item) {
return $item;
});
Edit: This actually removed the pagination properties, so I've recreated the pagination afterwards like so
// Remove already merged rows
$itemsTransformed = $pagination->getCollection()->filter(function ($item) {
return $item;
});
// Recreate because filter removed pagination properties
$itemsTransformedAndPaginated = new \Illuminate\Pagination\LengthAwarePaginator(
$itemsTransformed,
$pagination->total(),
$pagination->perPage(),
$pagination->currentPage(), [
'path' => \Request::url(),
'query' => [
'page' => $pagination->currentPage()
]
]
);

Laravel Collection Loop to another Collection

How to loop the eloquent collection from one to another? I'm just getting first line of array. I have more than 4 array in the collection.
$queries = Students::where('year',"=", 1)->get();
$students = new Students();
foreach ($queries as $query) {
$students->name = $query->name;
$students->faculty = $query->faculty ."Add something";
$students->year = $query->year;
}
dd($students);
I want to change the collection a bit before I print to json. For example, I want add something behind the faculty
Use the transform() method to modify collection:
$students = Students::where('year', 1)->get();
$students->transform(function($i) {
$i->faculty = $i->faculty . 'add something';
return $i;
});
You also can use resource classes to transform the data before returning JSON response.
You could use map() to modify collection-
$queries = $queries->map(function($query){
$query->faculty = $query->faculty."kfjhgli";
return $query;
});
return $queries;

Laravel show data from database and convert to json

i'm trying show data from database on laravel, but don't show anything in view blade. Every group hasMany lapangan(eng: court) data
$groups_resource = Groups::all();
$groups = [];
foreach($groups_resource as $group)
{
$g = new Groups();
$g->id_group = "Group_".$group['id_group'];
$g->name = $group['nama'];
$g->expanded = true;
$g->eventHeight = 25;
$g->children = array();
$groups[] = $g;
$lapangan_resource = Lapangan::with('groups')->orderBy('nama')->get();
foreach($lapangan_resource as $lapangan)
{
$l = new Lapangan();
$l->id_lapangan = $lapangan['id_lapangan'];
$l->name = $lapangan['nama_lapangan'];
$g->children[] = $l;
}
}
return json_encode($groups);
output
[{"id_group":"Group_1","name":"Lapangan Badminton","expanded":true,"eventHeight":25,"children":[]},{"id_group":"Group_2","name":"Lapangan Tenis","expanded":true,"eventHeight":25,"children":[]}]
There is no children output for every id_group
.what i want
{"id":"group_1","name":"Indoor","expanded":true,"eventHeight":25,"children":[
{"id":"1","name":"Court 1"},
{"id":"2","name":"Court 2"},
{"id":"3","name":"Court 3"},
{"id":"4","name":"Court 4"}]},
{"id":"group_2","name":"Outdoor","expanded":true,"eventHeight":25,"children":[
{"id":"11","name":"Court 5"},
{"id":"12","name":"Court 6"},
{"id":"13","name":"Court 7"},
{"id":"14","name":"Court 8"}]}
]
Any idea?
If you want to return a response in JSON format than you can use json() method as:
return response()->json($datagrup);
OR
To convert a model to JSON, you should use the toJson method. Like toArray, the toJson method is recursive, so all attributes and relations will be converted to JSON:
$user = App\User::find(1);
return $user->toJson();
Even though, you code seems to really fixed... I still feel the below code should work for you :)
I am not sure what exactly you mean by $datagroup[] = $dataresource? Do you want to add datagroup to dataresource or dataresource to datagroup... Your code shows something and the output desired is something else.
$datagroup = array_map(function($groups) use ($scheduler_resources) {
return [
'id' => $group['id_group'],
'name' => $group['nama'],
'expanded' => true,
'children' => $scheduler_resources->map(function($resource) {
return [
'id' => $resource->id_lapangan,
'name' => $resource->nama_lapangan,
];
}),
'eventHeight' => 25
];
}, $scheduler_groups);
echo json_encode($datagroup);
// or
// return response()->json($datagroup);
Note :- Please ensure $scheduler_resources is different for each $datagroup

How to `count` a query result and send it as an array in JSON format?

Details
I want to
Count all my distributors that I query
Send it along within the JSON file
I know that I have 89 distributors in total, I did this dd(count($distributors));
I am sure what is the best practice for this.
Here is what I have tried
I initialize $count = 0;
Increment by 1 every time the loop execute $count = $count + 1;
Send the result toArray 'count' => $count->toArray() as part of my distributors array
Here is my code
public function index()
{
$distributors = [];
$count = 0;
foreach(
// Specific Distributors
Distributor::where('type','!=','OEM')->where('type','!=','MKP')
->get() as $distributor){
// Variables
$count = $count + 1;
$user = $distributor->user()->first();
$distributors[$distributor->id] = [
'user' => $user->toArray(),
'distributor' => $distributor->toArray(),
'hq_country' => $distributor->country()->first(),
'address' => $distributor->addresses()
->where('type','=','Hq')->first()->toArray(),
'count' => $count->toArray()
];
}
return Response::json($distributors);
}
Result
The code won't run, due to my $distributor array is not exist ...
It will run, if I take 'count' => $count->toArray() off .
Updated
I am using Laravel 4.0
The code is part of my UrlController.php
It really doesn't make a lot of sense to add this kind of count to your result. It is much simpler to just send the result and let the client do the counting. Because the information on how much distributors you actually have is right in your array of distributors. It's just it's length.
Here's an example with javascript (and $.ajax although that doesn't really matter)
$.ajax({
url: 'get/distributors',
method: 'GET'
}).done(function(data){
var count = data.length;
});
Model:
class Distributor extends Eloquent {
public function country()
{
return $this->hasOne('Country');
}
public function addresses()
{
return $this->hasMany('Address');
}
public function hqAddress()
{
return $this->addresses()->where('type', 'Hq')->first();
}
public function user()
{
return $this->hasOne('User');
}
}
Controller:
$distributors = Distributor::whereNotIn('type', ['OEM', 'MKP'])
->with('country', 'user')->get();
$count = 0;
$distributors->each(function(Distributor $distributor) use(&$count) {
$distributor->count = $count;
$count++;
});
return Response::json($distributors);
Sorry, I can be wrong.
I am not laravel expert.
But what is this fragment is about?
this Index function is part of Model?
#evoque2015 is trying to put some custom array into $distributors[$distributor->id]?
if that is the goal, could you do any test with any simple value of 'count' that sholud work in your opinion?
My guess is : 'count' index is not acceptable for your Distributor::where function
(if it is acceptable - show as the value of 'count' that doesn't break your code even if return wrong result/data ).
So I would try to change the name of this parameter either to 'my_custom_count',
should it be declared somewhere in Distributor model declaration?
Found this :
Add a custom attribute to a Laravel / Eloquent model on load?
It seems to prove my guess.
So we need to change model class like:
class Distributor extends Eloquent {
protected $table = 'distributors';//or any you have already
public function toArray()
{
$array = parent::toArray();
$array['count'] = $this->count;
return $array;
}
.....
}
and probably more changes in model or just add 'count' column to the table :-)

Categories