I have a dictionaries table looks like this:
Here is the array result that I want:
I've already achieved the result by these ugly code:
$dictionaries = Dictionary::all();
$carriers_array = [];
$carriers = $dictionaries->unique('Carrier');
foreach($carriers as $carrier) {
$carriers_array[] = $carrier->Carrier;
}
$DOM_INLs_array = [];
foreach($carriers_array as $carrier_item) {
$DOM_INLs = $dictionaries->where('Carrier', $carrier_item)->unique('DOM_INL');
foreach($DOM_INLs as $DOM_INL) {
$DOM_INLs_array[$carrier_item][] = $DOM_INL->DOM_INL;
}
}
$groups_array = [];
foreach($DOM_INLs_array as $carrier => $DOM_INLs) {
foreach($DOM_INLs as $DOM_INL) {
$groups = $dictionaries->where('Carrier', $carrier)->where('DOM_INL', $DOM_INL)->unique('Group');
foreach($groups as $group) {
$groups_array[$carrier][$DOM_INL][] = $group->Group;
}
}
}
$routes_array = [];
foreach($groups_array as $carrier => $DOM_INLs) {
foreach($DOM_INLs as $DOM_INL => $groups) {
foreach($groups as $group) {
$routes = $dictionaries->where('Carrier', $carrier)->where('DOM_INL', $DOM_INL)->where('Group', $group)->unique('Route');
foreach($routes as $route) {
$routes_array[$carrier][$DOM_INL][$group][] = $route->Route;
}
}
}
}
$sectors_array = [];
foreach($routes_array as $carrier => $DOM_INLs) {
foreach($DOM_INLs as $DOM_INL => $groups) {
foreach($groups as $group => $routes) {
foreach($routes as $route) {
$sectors = $dictionaries->where('Carrier', $carrier)->where('DOM_INL', $DOM_INL)->where('Group', $group)->where('Route', $route)->unique('Sector');
foreach($sectors as $sector) {
$sectors_array[$carrier][$DOM_INL][$group][$route][] = $sector->Sector;
}
}
}
}
}
dd($sectors_array);
But it runs very slow, I want another way to get the same result but more efficient. Can anyone help?
This looks like a bunch of nested maps and groupBys with a pluck at the end:
Arrow functions, PHP 7.4+:
$dictionaries->groupBy('Carrier')
->map(fn ($i) => $i->groupBy('DOM_INL')
->map(fn ($i) => $i->groupBy('Group')
->map(fn ($i) => $i->groupBy('Route')
->map->pluck('Sector')
)
)
);
With anonymous functions:
$dictionaries->groupBy('Carrier')->map(function ($i) {
return $i->groupBy('DOM_INL')->map(function ($i) {
return $i->groupBy('Group')->map(function ($i) {
return $i->groupBy('Route')->map->pluck('Sector');
});
});
});
If you only needed these results grouped in this way and didn't need the leaves to just be the 'Sector' values this would be 1 call to groupBy:
$dictionary->groupBy(['Carrier', 'DOM_INL', 'Group', 'Route'])
Related
I have data in a table something like in this image. In this example, 87 is the main parent which have child category 92, 97, 100. Each child can also have sub categories.
This is my code so far I have tried, but I am not able implement level 3 of the array.
public function getList(int $id): array
{
$finalArray = [];
foreach ($result as $key => $value) {
if ($value['parent_id'] === '87') {
$finalArray[$value['id']] = [
'title' => $value['title'],
'subCategory' => []
];
continue;
}
// Extract parent
$parentId = $value['parent_id'];
if ($this->multiKeyExists($finalArray, $parentId)) {
$finalArray[$parentId]['subCategory'] = [
'title' => $value['title'],
'subCategory' => []
];
}
}
}
protected function multiKeyExists(array $arr, $key)
{
if (array_key_exists($key, $arr)) {
return true;
}
foreach ($arr as $element) {
if (is_array($element) && $this->multiKeyExists($element, $key)) {
return true;
}
}
return false;
}
Expected result:
- 92
- 93
- 95
-96
Can anyone help me with a simple way to solve the problem ?
function sortResult($result,$id=87){
$finalArr=[];
$finalArr['id']=$id;
foreach($result as $key=>$val){
if($val['id']==$id){
$finalArr['title']=$val['title'];
}
if($val['parent_id']==$id){
$finalArr['subs'][$val['id']]=sortResult($result,$val['id']);
}
}
return $finalArr;
}
The recursive function will look for a child and run itself
$createtree = function ($start = NULL) use ($result,&$createtree){
$start = $start ?? 0;
$part = $result[$start];
//has childs?
if($key = array_keys(array_column($result, 'parent_id'),$part['id'] )){
$part['sub'] = array_map(function($val) use ($result,&$createtree) {
return $createtree($val);
},$key);
}
return $part;
};
print_r($createtree());
Edit: working sample
https://onlinephp.io/c/1c7dd
I have a structure table like this
I want to change record data field goid = 1, but I as you can see my code bellow, there's limit looping. Is there a better way to do it?
public function actionShareGoid($folder)
{
$one = DokumenFolder::findOne($folder);
$one->goid = '1';
$one->update(false);
$models_1 = DokumenFolder::find()->where(['parent_id'=>$one->id])->all();
foreach ($models_1 as $key_1 => $model_1) {
$model_1->goid = '1';
$model_1->update(false);
$models_2 = DokumenFolder::find()->where(['parent_id'=>$model_1->id])->all();
foreach ($models_2 as $key_2 => $model_2) {
$model_2->goid = '1';
$model_2->update(false);
$models_3 = DokumenFolder::find()->where(['parent_id'=>$model_2->id])->all();
foreach ($models_3 as $key_3 => $model_3) {
$model_3->goid = '1';
$model_3->update(false);
$models_4 = DokumenFolder::find()->where(['parent_id'=>$model_3->id])->all();
foreach ($models_4 as $key_4 => $model_4) {
$model_4->goid = '1';
$model_4->update(false);
}
}
}
}
return $this->redirect(Yii::$app->request->referrer);
}
Thanks to someone, I got the answer. ^_^
So here it is...
public function folderParent($id)
{
$models = DokumenFolder::find()->where(['parent_id'=>$id])->all();
foreach ($models as $key => $model) {
$model->goid = '1';
$model->update(false);
}
}
public function actionShareGoid($id)
{
$models = DokumenFolder::find()->where(['parent_id'=>$id])->all();
foreach ($models as $key => $model) {
$this->folderParent($model->id);
}
return $this->redirect(Yii::$app->request->referrer);
}
I would like to split an array:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
based on the color attribute of each item, and fill corresponding sub arrays
$a = array("green", "yellow", "blue");
function isGreen($var){
return($var->color == "green");
}
$greens = array_filter($o, "isGreen");
$yellows = array_filter($o, "isYellow");
// and all possible categories in $a..
my $a has a length > 20, and could increase more, so I need a general way instead of writing functions by hand
There doesn't seem to exist a function array_split to generate all filtered arrays
or else I need a sort of lambda function maybe
You could do something like:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = array_filter($o, function($item) {
if ($item->color == 'green') {
return true;
}
return false;
});
Or if you want to create something really generic you could do something like the following:
function filterArray($array, $type, $value)
{
$result = array();
foreach($array as $item) {
if ($item->{$type} == $value) {
$result[] = $item;
}
}
return $result;
}
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = filterArray($o, 'color', 'green');
$yellows = filterArray($o, 'color', 'yellow');
In my second example you could just pass the array and tell the function what to filter (e.g. color or some other future property) on based on what value.
Note that I have not done any error checking whether properties really exist
I would not go down the road of creating a ton of functions, manually or dynamically.
Here's my idea, and the design could be modified so filters are chainable:
<?php
class ItemsFilter
{
protected $items = array();
public function __construct($items) {
$this->items = $items;
}
public function byColor($color)
{
$items = array();
foreach ($this->items as $item) {
// I don't like this: I would prefer each item was an object and had getColor()
if (empty($item->color) || $item->color != $color)
continue;
$items[] = $item;
}
return $items;
}
}
$items = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$filter = new ItemsFilter($items);
$greens = $filter->byColor('green');
echo '<pre>';
print_r($greens);
echo '</pre>';
If you need more arguments you could use this function:
function splitArray($array, $params) {
$result = array();
foreach ($array as $item) {
$status = true;
foreach ($params as $key => $value) {
if ($item[$key] != $value) {
$status = false;
continue;
}
}
if ($status == true) {
$result[] = $item;
}
}
return $result;
}
$greensAndID1 = splitArray($o, array('color' => 'green', 'id' => 1));
This is Database ERD that I use in application. I'm using Kohana 3.2. What I want to achieve is to generate menu for currently logged user. Each user can have many roles, so based on that user should get menu populated with modules (that are in relation with menu and user).
I have achieve this through several foreach loops. Is it possible to do this using ORM ?
*Table 'Modules' represents menu items.
Edit: this is my current code.
$conf_modules = Kohana::$config->load('modules');
$user_roles = $user->roles->find_all();
$result = array();
$array = array();
foreach($user_roles as $user_role)
{
$menus = $user_role->menus->find_all();
$modules = $user_role->modules->find_all();
}
foreach($menus as $menu)
{
$m = $menu->modules->find_all();
$result[]['name'] = $menu->name;
foreach ($m as $a)
{
foreach ($modules as $module)
{
if($a->name == $module->name)
{
foreach ($conf_modules as $key => $value)
{
if($module->name == $key)
{
$array = array(
'module_name' => $module->name,
'text' => $module->display_desc,
'url' => $value['url'],
);
}
}
}
}
array_push($result, $array);
}
}
I think this should be good solution.
$user = Auth::instance()->get_user();
$user_roles = $user->roles->find_all();
$conf_modules = Kohana::$config->load('modules');
$role_modules = ORM::factory('module')
->join('roles_modules')
->on('roles_modules.module_id','=','module.id')
->where('role_id','IN',$user_roles->as_array(NULL,'id'))
->find_all();
$role_menus = ORM::factory('menu')
->join('roles_menus')
->on('roles_menus.menu_id','=','menu.id')
->where('role_id','IN',$user_roles->as_array(NULL,'id'))
->find_all();
$result = array();
foreach ($role_menus as $role_menu)
{
$menu_modules = $role_menu->modules->find_all();
if ( ! isset($result[$role_menu->name]))
$result[$role_menu->name] = array('name' => $role_menu->name);
foreach ($menu_modules as $menu_module)
{
foreach ($role_modules as $role_module)
{
if($menu_module->name == $role_module->name)
{
foreach ($conf_modules as $key => $value)
{
if ($key == $role_module->name)
{
$result[$role_menu->name]['modules'][]['data'] = array('name' => $role_module->display_desc, 'url' => $value['url']);
}
}
}
}
}
}
return array_values($result);
I have a multi-dimension array like:
$fields =
Array (
[1] => Array
(
[field_special_features5_value] => Special Function 5
)
[2] => Array
(
[field_special_features6_value] => Special Function 6
)
[3] => Array
(
[field_opticalzoom_value] => Optical Zoom
)
)
I want to get the value by key, I tried the code below but not work
$tmp = array_search('field_special_features5_value' , $fields);
echo $tmp;
How can I get the value Special Function 5 of the key field_special_features5_value?
Thanks
print $fields[1]['field_special_features5_value'];
or if you don't know at which index your array is, something like this:
function GetKey($key, $search)
{
foreach ($search as $array)
{
if (array_key_exists($key, $array))
{
return $array[$key];
}
}
return false;
}
$tmp = GetKey('field_special_features5_value' , $fields);
echo $tmp;
If you know where it is located in the $fields array, try :
$value = $fields[1]['field_special_features5_value'];
If not, try :
function getSubkey($key,$inArray)
{
for ($fields as $field)
{
$keys = array_keys($field);
if (isset($keys[$key])) return $keys[$key];
}
return NULL;
}
And use it like this :
<?php
$value = getSubkey("field_special_features5_value",$fields);
?>
You need to search recursive:
function array_search_recursive(array $array, $key) {
foreach ($array as $k => $v) {
if (is_array($v)) {
if($found = array_search_recursive($v, $key)){
return $found;
}
} elseif ($k == $key) {
return $v;
} else {
return false;
}
}
}
$result = array_search_recursive($fields, 'field_special_features5_value');
Your problem is that you have a top-level index first before you can search you array. So to access that value you need to do this:
$tmp = $fields[1]['field_special_features5_value'];
You can do it with recursive function like this
<?php
function multi_array_key_exists($needle, $haystack) {
foreach ($haystack as $key=>$value) {
if ($needle===$key) {
return $key;
}
if (is_array($value)) {
if(multi_array_key_exists($needle, $value)) {
return multi_array_key_exists($needle, $value);
}
}
}
return false;
}
?>