Laravel 7 Illegal offset type - php

I am having an error when I try to when updating multiple names of filters.
public function update(Request $request, Filter $filter)
{
$filters = collect([$request->filters]);
$filters->each(function ($item) use ($request, $filter) {
if (!isset($item['name']) && !isset($item['latin'])) {
foreach ($item as $key) {
$data = [
'category_id' => $request->category_id,
'name' => $item[$key]['name'],
'latin' => $item[$key]['latin'],
'field' => $item[$key]['field'],
];
$filter->update($data);
}
} else {
return ;
}
}
}
When I change this, the first record is updated.
'name' => $item[1]['name'],
'latin' => $item[1]['latin'],
'field' => $item[1]['field'],
I now had three records and I changed all three folds and hit the reserve. The first record changed, the second and the third did not change. I want it to be n.
When I try this
$filters->each(function ($item) use ($request, $filter) {
if (!isset($item['field'])) {
dd($item);
}
I see this message
array:2 [▼
5 => array:4 [▼
"name" => "Value RAM"
"latin" => "ram"
"field" => "0"
"value" => array:2 [▼
0 => "One Gigabayte"
1 => "Twoo Gigabayte"
]
]
6 => array:3 [▼
"name" => "Color"
"latin" => "color"
"field" => "1"
]
]

#irankhostravi you are trying to get the wrong key from the array:
You are calling 'latin' => $item[$key]['latin'] but $key is not an integer but the value, because you are looping too many times trough the array.
If I dump the output of the $key this is what I get:
array:3 [▼
"latin" => "ram"
"field" => "0"
"value" => array:2 [▶]
]
// dump($key)
"key: ram"
So you need to remove that extra foreach(), which isn't necessary.
Besides of that, your are checking if 'name' and 'latin' are not set, if so, then you try to get the value of these non-existing keys..
I've refactored some of your code and I think this is what you need:
public function update(Request $request, Filter $filter)
{
collect($request->filters)
->each(function ($item) use ($request, $filter) {
// Check if the keys exists in the $item, otherwise return.
// Changed && to || because if one of them is missing, you want to abort,
// unless your database is accepting empty/nullable values.
// But please use validation rules here instead: https://laravel.com/docs/master/validation#quick-writing-the-validation-logic
if (! isset($item['name']) || ! isset($item['latin']) || ! isset($item['field'])) {
return;
}
$filter->update([
'category_id' => $request->category_id,
'name' => $item['name'],
'latin' => $item['latin'],
'field' => $item['field'],
]);
});
}

Related

Eloquent query being modified twice without evidence of the method being called twice

I am calling a method to apply a filter to a query through pass by reference, I can see that the query is modified correctly but then it is seemingly reverts back to the original unfiltered query result. It seems that that section after query modification block is run twice after testing with some dump() statements
This is the result of my testing:
Method where the pass by reference is being done:
public function processFilter(Builder &$query, array $resourceOptions)
{
if ($resourceOptions['query'] === null) {
return $query;
}
$conditionQueryApplier = new ConditionQueryApplier($this);
$conditionQueryApplier->apply($query, $resourceOptions['query']);
dump($query->get()->toArray());
}
Method called to modify query:
public function apply(&$baseQuery, $filter, array $options = [], $or = false)
{
dump('foo');
if (is_string($filter)) {
$filter = ConditionParser::parseQuery($filter);
}
$method = $or ? 'orwhere' : 'where';
$baseQuery->{$method}(function ($query) use ($filter, $options, $baseQuery) {
$or = false;
foreach ($filter as $filterBlock) {
if (isset($filterBlock['type'])) {
switch ($filterBlock['type']) {
case 'pair':
$or = $filterBlock['value'] === 'OR';
break;
case 'operation':
$config = $this->getMatchingConfig($filterBlock);
$this->validateFilter($filterBlock, $config);
if ($config['query_callback']) {
$functionPath = '\\' . $config['query_callback'];
$functionPath($baseQuery, $filterBlock, $config, $or);
}
break;
}
} else {
$this->apply($query, $filterBlock, $options, $or);
}
}
});
dump($baseQuery->get()->toArray());
}
Query callback filter called:
public static function latestScoreQuery($query, $filter, $config, $or){
$value = $filter['value'];
$operator = $filter['operator'];
$query->select(DB::raw('"location_id", ROUND(AVG("score"), 2) AS "average_score", COUNT("score") AS "total_scores", MAX("created") AS "latest"'))
->groupBy('location_id')
->having('location_id', '=', 'some_id');
}
And the results of the dump() statements are:
foo
foo
array:1 [
0 => array:4 [
"location_id" => "some_id"
"average_score" => "3.71"
"total_scores" => 7
"latest" => "2021-09-06 14:08:03"
]
]
array:2 [
0 => array:4 [
"location_id" => "some_id"
"average_score" => "3.71"
"total_scores" => 7
"latest" => "2021-09-06 14:08:03"
]
1 => array:4 [
"location_id" => "some_id2"
"average_score" => "2.00"
"total_scores" => 1
"latest" => "2021-09-03 11:22:41"
]
]
array:2 [
0 => array:4 [
"location_id" => "some_id"
"average_score" => "3.71"
"total_scores" => 7
"latest" => "2021-09-06 14:08:03"
]
1 => array:4 [
"location_id" => "some_id2"
"average_score" => "2.00"
"total_scores" => 1
"latest" => "2021-09-03 11:22:41"
]
]
So as can be seen by the results, there is no foo between the 2 arrays dumped which would indicate that the method was run twice. The filtered result is the array of length one but then the value is reverted for some reason to the unfiltered array of 2 and when checking the value after the pass by reference call, we can see that the query has indeed not been filtered.
I've tried logging as well to ensure that the dump() function itself is not the issue

how to add an item to array in laravel

i have a function that it fills the one array like below :
if (isset($options[$attribute->id][$optionId])) {
foreach ($options[$attribute->id][$optionId] as $item) {
. . . .
$attributeOptionsData[] = [
'id' => $optionId,
'label' => $attributeOption->label ? $attributeOption->label : $attributeOption->admin_name,
'swatch_value' => $attribute->swatch_type == 'image' ? $attributeOption->swatch_value_url : $attributeOption->swatch_value,
'products' => $options[$attribute->id][$optionId],
'images' => $productImage ?? null,
];
dd($attributeOptionsData);
}
the result of this dd is like below :
array:1 [▼
0 => array:5 [▼
"id" => 1
"label" => "black"
"swatch_value" => "#000000"
"products" => array:1 [▶]
"images" => "product/4618/rAkC2aC3QJB6kMiAAzIGk6nUzGHxpdfIS55g3T0P.jpeg"
]
]
now what i want to do is that after the last line add some content to this array and make it like below:
array:1 [▼
0 => array:5 [▼
"id" => 1
"label" => "مشکی"
"swatch_value" => "#000000"
"products" => array:1 [▶]
"images" => "product/4618/rAkC2aC3QJB6kMiAAzIGk6nUzGHxpdfIS55g3T0P.jpeg"
"custom_field" => "some value"
]
]
on the line that i dd the array i want add the customfield to it . how can i do that thanks in advance.
the reason i dont insert like others in that i want to add the custom field in a foreach loop based on 1 field of that array
So, if you simply want to add something at the bottom of an array, just use array_push().
In your case, you would need to retrieve the whole $attributeOptionsData[] in a foreach loop and append the array to the key you're in, during that loop. Be aware that this is somehow inefficient. If you want to add a line based on a value you can retrieve in the first foreach loop, you could've just made an if-statement asking for that value and add it with array_push() afterwards.
Either way, I think this is what you're looking for:
if (isset($options[$attribute->id][$optionId])) {
foreach ($options[$attribute->id][$optionId] as $item) {
$attributeOptionsData[] = [
'id' => $optionId,
'label' => $attributeOption->label ? $attributeOption->label : $attributeOption->admin_name,
'swatch_value' => $attribute->swatch_type == 'image' ? $attributeOption->swatch_value_url : $attributeOption->swatch_value,
'products' => $options[$attribute->id][$optionId],
'images' => $productImage ?? null,
];
}
foreach($attributeOptionsData as $key=>$data){
array_push($attributeOptionsData[$key], ["custom_field" => "some value"])
}
}
$attributeOptionsData is an associative array. You can assign values to it by specifying the array $key:
$attributeOptionsData[$key] = $value;

How to access the array inside the array

I don't know why I can't figure this out.
In my controller, how can I loop through this array and only get the values for name and url.
both of those values will be passed to insert a new record.
array:3 [▼
0 => array:2 [▼
"name" => "Discogs"
"url" => "https://www.discogs.com/artist/267549"
]
1 => "2"
2 => array:2 [▼
"name" => "Official homepage"
"url" => "http://www.blackmetal.com/~mega/TBD/"
]
]
You can do with this code:
foreach ($array as $value) {
if (is_array($value) && isset($value['name']) && isset($value['url'])) {
// Do whatever you want
}
}
You can try utilising Laravel's collection for this...
$items = collect($array)
->filter(function($item) {
return is_array($item);
});
If you have extra attributes to the ones you listed then you can use map() to for this:
$items = collect($array)
->filter(function($item) {
return is_array($item);
})
->map(function($item) {
return Arr::only($item, [
'name',
'url',
];
});
p.s. don't forget to add use Illuminate\Support\Arr; to use Arr

Wrong array detail in laravel

I want get my product conditions as array in order to add them in cart, this is dd of my product when I try to add it in my cart:
array:6 [▼
"id" => 4
"name" => "product four"
"price" => null
"quantity" => "1"
"attributes" => array:1 [▼
"attr" => array:2 [▼
"name" => "weight"
"value" => "45"
]
]
"conditions" => array:2 [▼
0 => CartCondition {#685 ▼ // need to add this
-args: array:4 [▼
"name" => "Black"
"value" => "10000"
"type" => "additional"
"target" => "item"
]
-parsedRawValue: null
}
1 => CartCondition {#692 ▼ // need to add this
-args: array:4 [▼
"name" => "12 inch"
"value" => "25000"
"type" => "additional"
"target" => "item"
]
-parsedRawValue: null
}
]
]
As you see unlike my attributes my conditions not show just as
array but get values in -args: and -parsedRawValue: null
When I try to add product in cart I get this error:
Darryldecode \ Cart \ Exceptions \ InvalidItemException
validation.required
Error
This is my function (how I get my conditions and where i use them:
public function addingItem(Request $request, $id)
{
//finding product
$product = Product::findOrFail($id);
//get product weight
$weight = $product->weight;
//list of discounts
$discounts = Discount::all();
//get current time
$mytime = Carbon::now();
// get product weight in cart as attribute
$weightArray = [
'attr' => [
'name' => 'weight',
'value' => $weight,
]
];
$customAttributes = []; // my conditions comes from here
if(!empty($request->attr)){
foreach($request->attr as $sub) {
// find the suboption
$sub = Suboption::find($sub);
if (!empty($sub->id)) {
$itemCondition1 = new \Darryldecode\Cart\CartCondition(array(
'name' => $sub->title,
'value' => $sub->price,
'type' => 'additional',
'target' => 'item',
));
array_push($customAttributes, $itemCondition1);
}
}
}
//adding product, options and conditions to cart
Cart::add(array(
'id' => $product->id,
'name' => $product->title,
'price' => $request->input('harga'),
'quantity' => $request->input('quantity'),
'attributes' => $weightArray,
'conditions' => $customAttributes, // added here
));
Session::flash('success', 'This product added to your cart successfully.');
return redirect()->back();
}
any idea why i get this error and how to fix it?
SOLVED
validation issue was caused by empty price value and that was because my loop in front end while getting diffirent price on discounts time and other times, by fixing my price loop i have my product price all the time and it not return null in my function anymore.
thanks for helps.
if you want to convert a collection to array just use ->toarray()
Also it is a bad practice to run a query inside a foreach loop because of N + 1 query problem you may want to consider using of findMany() rather than find()
also you may want to read about array_filter too

Laravel collection contains

I'm using the Laravel contains method on a collection https://laravel.com/docs/5.3/collections#method-contains. But it does not work for me.
foreach ($this->options as $option) {
if($options->contains($option->id)) {
dd('test');
}
}
dd($options); looks like this:
Collection {#390
#items: array:1 [
0 => array:3 [
0 => array:7 [
"id" => 10
"slug" => "test"
"name" => "test"
"poll_id" => 4
"created_at" => "2016-11-12 20:42:42"
"updated_at" => "2016-11-12 20:42:42"
"votes" => []
]
1 => array:7 [
"id" => 11
"slug" => "test-1"
"name" => "test"
"poll_id" => 4
"created_at" => "2016-11-12 20:42:42"
"updated_at" => "2016-11-12 20:42:42"
"votes" => []
]
2 => array:7 [
"id" => 12
"slug" => "test-2"
"name" => "test"
"poll_id" => 4
"created_at" => "2016-11-12 20:42:42"
"updated_at" => "2016-11-12 20:42:42"
"votes" => []
]
]
]
}
Result of dd($option->id); is 10.
What could be wrong? Or is there a better way?
You should pass a key / value pair to the contains method, which will
determine if the given pair exists in the collection. Use contains() method in this way:
foreach ($this->options as $option) {
// Pass key inside contains method
if($option->contains('id', $option->id)) {
dd('test');
}
}
Use the following, which tells Laravel you want to match the 'id':
$options->contains('id', $option->id);
Docs
foreach ($this->options as $option) {
if(!$options->flatten(1)->where('id',$option->id)->isEmpty()) {
dd('test');
}
}
The contains method determines whether the collection contains a given item.
There are basically three ways in which it can be used :
simply checking the item
$collection = collect(['name' => 'Sarah', 'age' => 23]);
$collection->contains('Desk');
// false
$collection->contains('Sarah');
// true
checking the key/value pair :
$collection = collect([
['name' => 'Sarah', 'age' => 23],
['name' => 'Vicky', 'age' => 34],
]);
$collection->contains('name', 'Hank');
// false
checking via callback function :
$collection = collect([3, 5, 7, 9, 11]);
$collection->contains(function ($value, $key) {
return $value < 2;
});
// false
Now, for your problem, we will use the second category, i.e :
foreach ($this->options as $option) {
// here id is key and $option->id is value
if($option->contains('id', $option->id)) {
dd('test');
}
}
Link to docs

Categories