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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.