We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Session with multi-level arrays

My current project needs to be able to store, access, and modify multi-level arrays in $_SESSION. Unfortunately, vanilla Phalcon only allows for single key-value pairs.

I've therefore built a wrapper for \Phalcon\Session\Adapter\Files that allows you to pass an array to get(), set(), and has() instead of a string. The array will contain the key at each level of the array. So ["filter","organization","name"] would reference the name element inside the organization array, which is inside the filter array.

Example set() usage

$this->session->set(['filter','organization','name'],'Widgets Inc.');

Contents of $_SESSION as a result:

Array
(
    [filter] => Array
        (
            [organization] => Array
                (
                    [name] => Widgets Inc.
                )
        )
)

You can overwrite and modify as well:

$this->session->set('filter',['organization'=>['name'=>'Humbug','city'=>'Edmonton']]);
$this->session->set(['filter','organization','city'],'Calgary');
Array
(
    [filter] => Array
        (
            [organization] => Array
                (
                    [name] => Humbug
                    [city] => Calgary
                )
        )
)

Note the first line of code uses just a simple string key, rather than an array. This is still supported.

You can also "deep-set" an element multiple levels down without having to create each level. So if you have an empty session & have this code:

$this->session->set(['filter','organization','city'],'Calgary');

this class will create $_SESSION["filter"] with one element, organization, that is itself an array with one element, city.

Example get() usage

Much less sexy, but it works the same.

With $_SESSION populated like this:

Array
(
    [filter] => Array
        (
            [organization] => Array
                (
                    [name] => Humbug
                    [city] => Calgary
                )
        )
)

this code:

$this->session->get(['filter','organization','name']);

would return Humbug.

You can also retrieve not just end values, but arrays too:

$this->session->get(['filter','organization']);

would return

Array
(
    [name] => Humbug
    [city] => Calgary
)

Example has() usage

has() works just like you'd expect. With $_SESSION populated like this:

Array
(
    [filter] => Array
        (
            [organization] => Array
                (
                    [name] => Humbug
                    [city] => Calgary
                )
        )
)

these codes:

$this->session->has(['filter','organization','name']);
$this->session->has(['filter','organization']);
$this->session->has('filter');

will all return TRUE, while this code

$this->session->has(['filter','organization','phone_number']);

will return FALSE.

Actual class code

class Session extends \Phalcon\Session\Adapter\Files{

    public function set($keys,$value = NULL){
        if(is_scalar($keys)){
            $_SESSION[$keys] = $value;
        }
        else if(is_array($keys)){
            $target =& $_SESSION;
            $setting = end($keys);

            foreach($keys as $key){
                if($key != $setting){
                    if(!isset($target[$key])){
                        $target[$key] = [];
                    }           
                }
                $target =& $target[$key];
            }

            $target = $value;
        }
    }

    public function get($keys,$defaultValue = NULL){
        if(is_scalar($keys)){
            return $_SESSION[$keys];
        }
        else if(is_array($keys)){
            $target =& $_SESSION;
            $getting = end($keys);

            foreach($keys as $key){
                if(isset($target[$key])){
                    if($key == $getting){
                        return $target[$key];
                    }
                    else if(is_array($target[$key])){
                        $target =& $target[$key];
                    }
                }
                else{
                    return $defaultValue;
                }
            }
        }
    }

    public function has($keys){
        if(is_scalar($keys)){
            return parent::has($keys);
        }
        else if(is_array($keys)){
            $target =& $_SESSION;

            foreach($keys as $key){
                if(isset($target[$key])){
                    $target =& $target[$key];
                }
                else{
                    return FALSE;
                }
            }
            return TRUE;
        }
    }
}
edited Sep '15

Neat! Have you tried it as a NFR on git? Or had Andres deemed it as too arbitrary? :]

Personally, I'd also love to see this logic implemented on other objects using set/has/get out of the box

No - I haven't submitted it. Wanted to see what people thought first.



1.5k

This is really helpful! Thank you!