I am outputting a query which has a relationship with another model.
One of the fields I need is within the relationship
$officeFlagMap = $officeFlagQuery->map(function ($item) {
return [
'propagent_id' => $propagent_id,
];
$item->theAgent->map(function ($inner){
return [
'agtFullName' => $inner->agtFullName,
];
});
});
I have checked that both values are correct but I am only getting the output for the
$inner->agtFullName.
How can I modify this to chain the returns and show both fields?
an ideal code would be,
$officeFlagMap = $officeFlagQuery->map(function ($item) {
return [
'propagent_id' => $item->propagent_id, // use the appropriate variable here
'agtFullName' => $item->theAgent->map(function ($inner){
return [
'agtFullName' => $inner->agtFullName,
];
});
];
});
this will map over the original collection and again on the theAgent collection and will return the result.
Related
Laravel: 8.51
Nova: 3.24
PHP Version: 7.4.20
I have problem with trying to solve this situation:
I have a action that uses a KeyValue to handle array of pairs: "product_id" and "amount"
field looks like:
KeyValue::make(__('Order details'), 'details')
->rules('json'),
also in model i added cast:
protected $casts = [
'details' => 'array',
];
I convert it to json and store in database like that
foreach ($fields->details as $key => $value)
{
$order_details[$key] = $value;
}
//(...)
DB::table('orders')->InsertGetId([
'details' => json_encode($order_details),
]);
finnaly my json field in database looks like:
{"1":"6","2":"7","3":"8"}
To this point everything works great.
Now I want to change what I see as product_id (in above example 1, 2, 3) to be from other resource like belongsTo('products')
I was considering how to be able to use BelongsTo or Select in key part of KeyValue field.
I tried few ways to display it somehow in stack field like:
Stack::make('Details', [
Text::make('details', function () {
return $this->details($key); // how to properly read $key from json in fields?
}),
Text::make('amount',function () {
return $this->details($value); // how to properly read $value from json in fields?
}),
]),
or
BelongsTo::make(__('Product'), 'user', Products::class)
->withMeta([
'belongsToId' => $this->details($key), // again i dont know how to properly read $key here from json.
]),
I have data like this:
array:1 [
0 => "No Brand,ddfg"
]
First of all this data is wrong, what I want is to have something like this:
array:2 [
0 => "No Brand"
1 => "ddfg"
]
So now its really an array :)
Then I need my array data transform to lower case like:
array:2 [
0 => "no brand"
1 => "ddfg"
]
Code
$sibarBrandsArray = SidebarManager::first()->pluck('brands')->toArray();
This return data like:
array:1 [
0 => "No Brand,ddfg"
]
And this is how my data looks like in database:
Any idea?
Solved
// get my table row
$sibarBrandsArray = SidebarManager::first();
// get my row column
$getBrandColumn = $sibarBrandsArray->brands;
// separate data in that column with comma
$separateBrands = explode(',', $getBrandColumn);
// lowercase each separated data
$brandsArray = array_map('strtolower', $separateBrands);
// dump the result
dd($brandsArray);
Result
array:2 [
0 => "no brand"
1 => "ddfg"
]
Laravel has a very efficient and easy way to work with arrays. It's called a collection. Click here to learn more. Don't convert your response to the array, use collection directly.
$sibarBrandsCollection = SidebarManager::first()->pluck('brands');
Laravel eloquent by default gives you collection instance when you get a response. so pluck in above call is nothing but calling pluck on collection instance. We can chain method to the collection and do manipulation as needed.
$sibarBrandsCollection = $sibarBrandsCollection->map(function ($name) {
return strtolower($name);
});
Above code will automatically convert all of your values to lowercase. Similarly, you can explode the value to get your intended result. At last, if you have to send data as array to the browser just add toArray() method at the end of your collection.
I would not use core PHP array function unless needed, Laravel collection is great way to work with arrays.
$yourArray = array_map('strtolower', $yourArray);
$yourArray = array_map('nestedLowercase', $yourArray);
function nestedLowercase($value) {
if (is_array($value)) {
return array_map('nestedLowercase', $value);
}
return strtolower($value);
}
or you can use:
$query->whereRaw('LOWER(`newsTitle`) LIKE ? ',[trim(strtolower($newsTitle)).'%']);
I have a form that posts a structure field as an array. The structure array contains definitions of database table columns.
$validator = Validator::make($request->all(), [
'structure' => 'required|array|min:1',
'structure.*.name' => 'required|regex:/^[a-z]+[a-z0-9_]+$/',
'structure.*.type' => 'required|in:integer,decimal,string,text,date,datetime',
'structure.*.length' => 'nullable|numeric|required_if:structure.*.type,decimal',
'structure.*.default' => '',
'structure.*.index' => 'required_if:is_auto_increment,false|boolean',
'structure.*.is_nullable' => 'required_if:is_auto_increment,false|boolean',
'structure.*.is_primary' => 'required_if:is_auto_increment,false|boolean',
'structure.*.is_auto_increment' => 'required_if:structure.type,integer|boolean',
'structure.*.is_unique' => 'required_if:is_auto_increment,false|boolean',
'structure.*.decimal' => 'nullable|numeric|required_if:structure.*.type,decimal|lt:structure.*.length',
]);
Without going into explanation of all the rules, one thing should be made sure that the length field is always null when the type is not string or decimal as you cannot assign a length to columns other than these types. So, I am trying to use the sometimes method on the $validator instance.
$validator->sometimes('structure.*.length', 'in:null', function ($input) {
// how to access the structure type here?
});
My question is inside the closure, how do I make sure that the length is null only for the array element that has the type set to other than string or decimal.
I have tried the dd function and it seems the whole input array is passed to the closure.
$validator->sometimes('structure.*.length', 'in:null', function ($input) {
dd($input);
});
Here is the output of the dd method.
I can use a foreach construct but wouldn't that be inefficient? Checking all the elements for a single element?
How do I check the type only for the array element under consideration?
Is there a Laravel way to do this?
How about thinking opposite? if the Type is String or Decimal, the Length field will become Required.
$validator->sometimes('structure.*.length', 'required', function ($input) {
return $input->type == 'string' or $input->type == 'decimal';
});
This is a great question. I took a look at the API for sometimes(). It seems, what you want to do, is currently not possible with it.
A possible alternative could be to use an After Validation Hook. For example:
$validator->after(function ($validator) {
$attributes = $validator->getData()['structure'];
foreach($attributes as $key => $value) {
if(! in_array($value['type'], ['string', 'decimal']) && ! is_null($value['length'])) {
$validator->errors()->add("structure.{$key}.length", 'Should be null');
}
}
});
I've got the following Laravel collection of between 800 and 4000 items:
[
{
"date": "2017-05-26",
"departure_time": "14:50:00",
"arrival_time": "09:20:02",
"departure_place_id": 16
},
{
"date": "2017-05-26",
"departure_time": "15:20:00",
"arrival_time": "15:20:00",
"departure_place_id": 15
},
...
]
I need to merge always merge two items of the collection into one. So that a collection of 10 items, after merge, is a collection of 5 items with the follwing structure.
[
{
"date": "2017-05-26",
"departure_time": "14:50:00", // from first item
"arrival_time": "15:20:00", // from second item
"departure_place_id": 16, // from first item
"arrival_place_id": 15 // from second item
},
...
]
As you can see I need to merge data from two consecutive items to one.
I already tried two extend use Laravels custom collection feature but cannot really achieve what I want.
Any clue?
You can solve it by using laravel collection chunk
public function formatCollection($collection)
{
$results = [];
foreach (collect($collection)->chunk(2) as $chunk)
{
$results[] = [
'date' => $chunk[0]['date'],
'departure_time' => $chunk[0]['departure_time'],
'arrival_time' => $chunk[1]['arrival_time'],
'departure_place_id'=> $chunk[0]['departure_place_id'],
'arrival_place_id' => $chunk[1]['departure_place_id']
];
}
return collect($results);
}
Call this function to format the data
IMO, if you only had two items, you should create a class which will "merge" your two items in one as you do.
Collection are made to treat a collection of items, so 1 to N items not only two.
After the tip from #Vikash with using chunk() and some research I came up with the following solution which suits my needs best:
public function convert() : \Illuminate\Support\Collection
{
/** #var \Illuminate\Database\Eloquent\Collection $collection */
$collection = $this->cruise->where('line_id', $lineId)->get();
return $collection->chunk(2)->map(function ($chunk) {
/** #var Collection $chunk */
return [
'date' => $chunk->first()->date,
'downriver' => $chunk->last()->departure_place_id < $this->departure_place_id,
'departure_time' => $chunk->first()->departure_time,
'arrival_time' => $chunk->last()->departure_time,
'departure_place_id' => $chunk->first()->departure_place_id,
'arrival_place_id' => $chunk->last()->departure_place_id,
];
});
}
I put that into a repository which is a nice way to decouple the logic. It utilizes the collection functions instead of dealing with arrays which I definately wanted to avoid.
Lets assume, the return value of an search-fuction is something like this
// If only one record is found
$value = [
'records' => [
'record' => ['some', 'Important', 'Information']
]
]
// If multiple records are found
$value = [
'records' => [
'record' => [
0 => ['some', 'important', 'information'],
1 => ['some', 'information', 'I dont care']
]
]
]
what woul'd be the best way to get the important information (in case of multiple records, it is always the first one)?
Should I check something like
if (array_values($value['record']['records'])[0] == 0){//do something};
But I guess, there is a way more elegant solution.
Edit:
And btw, this is not realy a duplicate of the refered question which only covers the multiple records.
If you want the first element of an array, you should use reset. This function sets the pointer to the first element and returns it.
$firstValue = reset($value['record']['records']);
Edit.. after reading your question again, it seems, you dont want the first element.
You rather want this
if (isset($value['record']['records'][0]) && is_array($value['record']['records'][0])) {
// multiple return values
} else {
// single return value
}
Doing this is kind of error proun and i wouldn't suggest that one function returns different kinds of array structures.
check like this..
if(is_array($value['records']['record'][0])) {
// multiple records
} else {
// single record
}