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

Serializing and caching ACL (database adapter)

Hi all! I've got a question about serializing and caching ACL from database adapter. I'm using postgresql. When I'm trying to do it like this:

$cache = $this->getDi()->get("cache");
$acl   = $cache->get("acl");
if($acl === null) {
    $cache->save("acl", serialize($this->rebuild()));
} else {
    $acl = unserialize($acl);
}

I'm getting:

You cannot serialize or unserialize PDO instances

I don't need a state of PDO instance, I only want ACL data. How can I do it right?

Would be nice to know the context of $this ;]

But anyway, you could try converting your results to an array first (Model::toArray() / SimpleResult::toArray() / fetchAll(Db::FETCH_ASSOC))

edited Sep '15

Thanks for your help! $this is an instance of SecurityPlugin (modified security plugin from INVO).

use Phalcon\Acl,
    Phalcon\Acl\Role,
    Phalcon\Acl\Resource,
    Phalcon\Events\Event,
    Phalcon\Mvc\User\Plugin,
    Phalcon\Mvc\Dispatcher;

class SecurityPlugin extends Plugin {
    public function getAcl() {
        $cache = $this->getDi()->get("cache");
        $acl   = $cache->get("acl");
        if($acl === null) {
            $cache->save("acl", serialize($this->rebuild()));
        } else {
            $acl = unserialize($acl);
        }
    return $acl;
    }
}    

etc. :) I'll try fetchAll as you've written, but I'm aiming at using database adapter just like memory adapter :)

edited Sep '15

Okay, so I ended at adding a property in which I'm storing access list and two methods which returns data from adapter (one as stdClass object and second as \Phalcon\Acl\Adapter\Memory - both are easily serializable).

Full code is there: click (updated: 08:17 24.09.2015).

I am open to fixes and proposals ;) Thanks for your attention.

edited Jul '16

The recommended way to handle "You cannot serialize..." issues is to mark properties not meant to serialize as transient. In PHP you would do it with the magic method "sleep()". However special care needs to be taken when unserializing such serialized instances. After unserialization transient properties will be NULL and need to get re-initialzed in the magic method "wakeup()". Take for example an instance of User stored in the HTTP session. Here I mark the protected property "password" as transient, otherwise everyone with read access to the temp directory can read the (hopefully not) plain text password in the session file.

/**
 * Prevent serialization of transient properties.
 *
 * @return string[] - array of property names to serialize     // access level encoding scheme:
 */                                                            // -----------------------------
public function __sleep() {                                    // private:    "\0{className}\0{propertyName}"
   $array = (array) $this;                                     // protected:  "\0*\0{propertyName}"
   unset($array["\0*\0password"]);                             // public:     "{propertyName}"
   return array_keys($array);
}

For the PDO adapter they are "probably" implemented similar to this:

/**
 * Prevent serialization of PDO instances.
 */
final public function __sleep() {
   throw new IllegalStateException('You cannot serialize or unserialize PDO instances');
}

/**
 * Prevent de-serialization of PDO instances.
 */
final public function __wakeUp() {
   throw new IllegalStateException('You cannot serialize or unserialize PDO instances');
}

So, find the offending property in your SecurityPlugin and mark it as transient. If you need it after de-serialization you have to re-initialize it manually.