1

I have this example of array:

$roles = [
    "dashboard.read" => true,
    "dashboard.section1.read" => true,
    "members.member.create" => false,
    "members.member.read" => true,
    "members.member.view.update" => true,
    "members.member.view.section2.delete" => false,
    "members.member.view" => true
];

and I need a method to convert arrays of similar structure to this result :

$roles = [
    "dashboard" => [
        "read" => true,
        "section1" => [
            "read" => true
        ]
    ],
    "members" => [
        "member" => [
            "create" => false,
            "read" => true,
            "view" => [
                "update" => true,
                "section2" => [
                    "delete" => false
                ],
                true,
            ],
        ]
    ]
];

I can't figure out how to do this.

3
  • What have you got so far? Commented Sep 12, 2017 at 10:48
  • All I could do is this $arr = []; foreach($roles as $key => $value) { $result = explode('.', $key); $arr[$key] = $result; } return $arr; and it's far from what I need.. Commented Sep 12, 2017 at 10:54
  • $arr[$key] = $result; is wrong. You need to use $result to set $value. Commented Sep 12, 2017 at 12:25

2 Answers 2

1

I took it as a challenge to solve your question, here you go, I have added all the details right into the code:

// your defined roles, as stated above
$roles = [
    "dashboard.read" => true,
    "dashboard.section1.read" => true,
    "members.member.create" => false,
    "members.member.read" => true,
    "members.member.view.update" => true,
    "members.member.view.section2.delete" => false,
    "members.member.view" => true
];

// the magic array, which will have all the results later
$magic = array();

// iterate trough all the roles
foreach($roles as $key => $value) {
    // split the roles and reverse the array, so we can start with setting the value
    $roleNamePart = array_reverse(explode(".", $key));

    // this array is used to recursive create all the array in itself
    $magicCreationArray = array();

    // iterate trough those role name parts starting at the "bottom"
    foreach($roleNamePart as $keypart) {

        // if it is empty, it is really the bottom and you can set the value right there
        if(empty($magicCreationArray)) {
            $magicCreationArray[$keypart] = $value;

        // if its not, it must be something inbetween, go one level up. its needed to create a temporary value for this, i guess
        } else {
            $tmp = $magicCreationArray;
            unset($magicCreationArray);
            $magicCreationArray[$keypart] = $tmp;
        }
    }
    // merge all the data to the magic array, use array_merge_recursive so it does not override for example "dashboard" 
    $magic = array_merge_recursive($magic, $magicCreationArray);
}

// here you go fam
print_r($magic);

Hope I could help you with it.

Nice one to read: http://php.net/manual/en/function.array-merge-recursive.php

Sign up to request clarification or add additional context in comments.

Comments

0

It can be easily done through array references:

$input = [
    "dashboard.read" => true,
    "dashboard.section1.read" => true,
    "members.member.create" => false,
    "members.member.read" => true,
    "members.member.view.update" => true,
    "members.member.view.section2.delete" => false,
    "members.member.view" => true
];

$output = [];

foreach($input as $key => $value){
    $pointer =& $output;
    $keyParts = explode(".", $key);
    foreach(array_slice($keyParts, 0, -1) as $part){
        if(!isset($pointer[$part])) $pointer[$part] = [];
        $pointer =& $pointer[$part];

        // special case: If $key is a.b.c.d and a.b is already defined, convert the a.b value into an array
        if(!is_array($pointer)) $pointer = [$pointer];
    }
    $name = array_slice($keyParts, -1)[0];

    // special case: If $key is a.b and a.b.c.d is already defined, append to the array rather than overwriting it
    if(isset($pointer[$name])) $pointer[$name][] = $value;
    else $pointer[$name] = $value;
}

Test result:

{
    "dashboard": {
        "read": true,
        "section1": {
            "read": true
        }
    },
    "members": {
        "member": {
            "create": false,
            "read": true,
            "view": {
                "update": true,
                "section2": {
                    "delete": false
                },
                "0": true
            }
        }
    }
}

P.S. I didn't realize it took me 10 minutes to debug the special condition about members.member.view

2 Comments

Added elaboration for the tricky overwriting part. However, note that it is not nice to have such inconsistency in your input data.
I see. Thanks for the help, I really appreciate it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.