This problem is kinda hard to explain so bare with me, but I've got 3 models: User, Product, and ProductStatus. Each Product has one Status, and a User can have many Products.
class User extends \My\Models { //which extends \Phalcon\Mvc\Model
public function initialize() {
$this->hasMany("user_id", "Product", "user_id", array('alias'=>'products'));
}
}
class Product extends \My\Models {
public function initialize() {
$this->belongsTo("user_id", "User", "user_id", array('alias'=>'user'));
$this->hasOne("product_id", "ProductStatus", "product_id", array('alias'=>'status', 'reusable' => true));
}
}
class ProductStatus extends \My\Models {
public static $cacheable = true; //switch I added to turn off caching, not relevant but shown for completeness sake
public function initialize() {
$this->hasOne("product_id", "Product", "product_id", array('alias'=>'product'));
}
}
I'm also using a custom modelsManager to save models to a redis cache using the Backend\Redis class from Phalcon Incubator.
//In my setup
$di->setShared('modelsCache', function() {
$redis = new Redis();
$redis->connect(....);
$frontCache = new \Phalcon\Cache\Frontend\Data(array(
"lifetime" => 86400
));
$cache = new \Phalcon\Cache\Backend\Redis($frontCache, array(
'redis' => $redis
));
return $cache;
});
//mananger class (This is literally all it is, mostly copied from "Caching in the ORM" doc)
class Manager extends Phalcon\Mvc\Model\Manager {
public function getReusableRecords($modelName, $key) {
$cache = $this->getDI()->get('modelsCache');
if($search_result = $cache->exists($key) {
return $cache->get($key);
}
return parent::getReusableRecords($modelName, $key);
}
public function setReusableRecords($modelName, $key, $record) {
if(is_subclass_of($records,'\My\Models') && $records::$cacheable == true) {
$cache = $this->getDI()->get('modelsCache');
$cache->save($save_key, $records, 3600);
}
return parent::setReusableRecords($modelName, $key, $records);
}
}
So here's where it gets weird. Lets say $user->products = (Product id #5, #12, #27) and Product #5 is saved in cache from an earlier page load. And then I do this to update a user's statuses:
foreach($user->products as $p) {
$status = $p->status;
$status->date_updated = date('Y-m-d');
$status->save();
}
Every loop generates the exact same update sql:
UPDATE product_status VALUES (...) WHERE product_status_id = 5
What's happening is that on the first loop it finds the key in cache and returns. On the next loop though it MISSES CACHE of course and goes to parent::getReusableRecords(). Phalcon does whatever it does there, then it comes back to setReusableRecords(). However, if I var_dump the $record that's getting passed back to there, it looks like this:
My\Model\Product {
... bunch of other di stuff ...
[_uniqueKey:protected] => `product_status_id` = ?
[_uniqueParams:protected] => Array
(
[0] => 5
)
[product_status_id] => 12
[user_id] => 80112
[date_updated] => 2014-10-10
...
}
It seems as if it's reused the internals of the previous object to build the next one. This only happens with models marked as 'reusable' => true, anything else is fine. Doesn't seem to be a problem with redis either, the only thing in there is a serialized version of the model. Any ideas?