Laravel Eloquent column cast as array, cannot access array - php

I have a table with a json column cast as array.
In my class:
protected $casts = [
'row_ids' => 'array',
];
I access this column via a relationship in another class:
public function table_rows()
{
return $this->hasMany(TableChannelRow::class, 'channel_api_id', 'api_id');
}
When I dd the relationship I can see the columns in the target table OK, with one of the columns containing an array as expected:
dd($channel->table_rows);
#attributes: array:4 [▼
"api_id" => 2
"table_api_id" => 1
"channel_api_id" => 6
"row_ids" => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ▶"
]
In my Blade template page I check whether the current record id is in the column array like this:
#foreach($channels as $channel)
#if(in_array($row->api_id, $channel->table_rows->row_ids)) true #endif
#endif
But this fails with:
Property [row_ids] does not exist on this collection instance.
What have I missed? Thanks.

Your table_rows relationship returns a collection. So you have to loop through the collection or grab the first instance in your collection:
$channel->table_rows->first()->row_ids

Related

Wordpress incorrect query ordering by meta key numeric

I'm trying to order a custom taxonomy by a custom meta key. That meta key is the number of edition. Weekly, my client adds a new edition (the term of the "edition" taxonomy), and this number increases. At the moment, it is at 124.
So, I'm trying to order the admin list by this numeric meta key, this way:
add_filter("get_terms_args", "mytheme_get_terms_args", 10, 2);
static function mytheme_get_terms_args($args, $taxonomies)
{
if(is_admin() && in_array("edition", $taxonomies)){
$args['order'] = "ASC";
$args['orderby'] = "meta_value";
$args['meta_key'] = "_edition";
$args['meta_type'] = "DECIMAL";
}
return $args;
}
The expected result is all editions ordered as follows:
1, 2, 3, [...], 9, 10, 11, 12, 13, [...] 19, 20...
But, I'm getting this ordering instead:
1, 2, 3, [...], 9, 10, 100, 101, 102 , [...] 109, 11, 110, 111, 112, [...], 118, 119, 12, 120, 121, 122, 123, 13, 14, 15...
After the 10, instead following to 11, this crazy ordering goes to 100, 101, 102.
How can I order this correctly?
Thanks!

Compare the new array with the previous one

I have an array with 4 elements
[1, 2, 3, 4]
So far I am printing several arrays, all with different elements in each array, to a limit set by me.
for($i = 0; $i<=100; $i++){//...
Output so far:
[11, 22, 32, 44]
[22, 33, 44, 45]
[12, 24, 25, 31]
[15, 16, 31, 41]
[22, 33, 44, 45]//already exist
[11, 22, 32, 44]//already exist
...
How can I compare an outgoing array to the next one going out and delete the new one if is equal to the previous array?
You could create a key for an array with the help of implode() and have a set array which has this key. If key is already present, then the current array in iteration is a duplicate one, else it's a new one. Remember to sort the current array as the order of the numbers matter here for proper key check.
<?php
$arr = [
[11, 22, 32, 44],
[22, 33, 44, 45],
[12, 24, 25, 31],
[15, 16, 31, 41],
[22, 33, 44, 45],
[44, 22, 32, 11]
];
$set = [];
foreach($arr as $curr_array){
sort($curr_array);
$hash = implode("|",$curr_array);
if(isset($set[$hash])) echo "Duplicate",PHP_EOL;
else{
print_r($curr_array);
$set[$hash] = true;
}
}
Demo: https://3v4l.org/EXXRu

Laravel 5.8 update mysql json column cast as array changes data stored format

I have a table with a json column cast as array. The Schema creation has the column defined like this:
$table->json('row_ids');
In my class:
protected $casts = [
'row_ids' => 'array',
];
I generate the data in this array / column by getting every row id from another table like this:
$id_array = DB::table($table->name)->pluck('api_id')->toArray();
TableChannelRow::create([
'table_api_id' => $table->api_id,
'channel_api_id' => $channel->api_id,
'row_ids' => $id_array,
]);
When I dd a collection record I can see the columns in the target table OK, with one of the columns containing an array as expected:
#attributes: array:4 [▼
"api_id" => 2
"table_api_id" => 1
"channel_api_id" => 6
"row_ids" => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ▶"
]
When I check in MySQLWorkbench the data looks like this:
In another controller I want to add or remove entries from the array in this column like this:
$table_channel_row = TableChannelRow::where('table_api_id', '=', $rowId)
->where('channel_api_id', '=', $channelId)
->first();
$row_ids = $table_channel_row->row_ids;
if ($is_checked == 'yes') {
// Add value to array if it does not already exist
if (!in_array($row_id, $row_ids)) {
array_push($row_ids, $row_id);
}
} else {
// Remove value from array
$row_id_array[] = $row_id;
$row_ids = array_diff($row_ids, $row_id_array);
}
$table_channel_row->update([
'row_ids' => $row_ids,
]);
Now the data in MySQLWorkbench looks like this:
Why does it get stored looking like a PHP array in the first instance, then later on update it gets stored as a json object?
Additionally the remove PHP code is working, yet the add is not, though it does not trigger an exception (you can see the first value is removed in the second image, but I cannot find it in the object in MySQL when I trigger the code to add it)
What did I miss? Thanks!
The reason why it's saving differently is because array_diff returns an associative array whereas your initial data is an indexed array. Take the following for example:
$ids = [1, 2, 3, 4, 5];
$ids2 = [1, 2, 3];
Then if you perform an array_diff($ids, $ids2), it would return the following:
[
3 => 4,
4 => 5
]
So if you want to save as the same format as your initial one, you have to retrieve the values of the array using array_values:
$row_ids = array_values(array_diff($row_ids, $row_id_array));

How to Parse This Type of JSON String Data

Object {percentage: Array(9), projects: Array(9), colors: Array(9)}
colors:Array(9)
0:"#4d4d4d"
1:"#5da5da"
2:"#faa43a"
3:"#60bd68"
4:"#307d99"
5:"#0275d8"
6:"#cc4748"
7:"#fdd400"
8:"#f15854"
length:9
__proto__:Array(0)
percentage:Array(9)
0:3
1:6
2:13
3:12
4:0
5:47
6:14
7:4
8:1
length:9
__proto__:Array(0)
projects:Array(9)
0:"BHAWAN"
1:"CORE"
2:"DIST-NIC"
3:"DIST-NKN"
4:"FIREWALL"
5:"NKN"
6:"NMEICT"
7:"PRAGATI"
8:"WIFI"
length:9
__proto__:Array(0)
__proto__:Object
As for me, it's not the JSON, but the console output for an object:
{
percentage: [
"#4d4d4d",
"#5da5da",
"#faa43a",
"#60bd68",
"#307d99",
"#0275d8",
"#cc4748",
"#fdd400",
"#f15854",
],
projects: [
3,
6,
13,
12,
0,
47,
14,
4,
1,
],
colors: [
"BHAWAN",
"CORE",
"DIST-NIC",
"DIST-NKN",
"FIREWALL",
"NKN",
"NMEICT",
"PRAGATI",
"WIFI",
]
}
And it seems for me that this is already a JSON object. So what's your issue?

Get max value from each column of a 2-dimensional array

I have an array within an array, for example:
[
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
]
I need to get the max number in each column.
The max of [0 , 5 , 5] is 5, so that goes into the result array.
The max of [20, 0, 10] is 20, so that goes into the result array.
The max of [5, 15, 0] is 15, so that goes into the result array.
The final result array must contain [5, 20, 15].
First, the array has to be transposed (flip the rows and columns):
function array_transpose($arr) {
$map_args = array_merge(array(NULL), $arr);
return call_user_func_array('array_map', $map_args);
}
(taken from Is there better way to transpose a PHP 2D array? - read that question for an explanation of how it works)
Then, you can map the max function on the new array:
$maxes = array_map('max', array_transpose($arr));
Example: http://codepad.org/3gPExrhO
Output [I think this is what you meant instead of (5, 15, 20) because you said index 1 should be max of (20, 0, 10)]:
Array
(
[0] => 5
[1] => 20
[2] => 15
)
Without the splat operator, array_map() with max() will return the max value for each row. ([20, 15, 10])
With the splat operator to transpose the data structure, the max value for each column is returned.
Code: (Demo)
$array = [
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
];
var_export(
array_map('max', ...$array)
);
Output:
array (
0 => 5,
1 => 20,
2 => 15,
)

Categories