diff --git a/CHANGELOG.md b/CHANGELOG.md index ab730497075..2afd88ba409 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # [3.0.2](https://github.com/phalcon/cphalcon/releases/tag/v3.0.2) (2016-XX-XX) +- Fixed saving snapshot data while caching model [#12170](https://github.com/phalcon/cphalcon/issues/12170), [#12000](https://github.com/phalcon/cphalcon/issues/12000) # [3.0.1](https://github.com/phalcon/cphalcon/releases/tag/v3.0.1) (2016-08-24) - Fixed `Phalcon\Cache\Backend\Redis::flush` in order to flush cache correctly diff --git a/phalcon/mvc/model.zep b/phalcon/mvc/model.zep index bae9dfd631f..8796ccf8dcb 100644 --- a/phalcon/mvc/model.zep +++ b/phalcon/mvc/model.zep @@ -4303,7 +4303,22 @@ abstract class Model implements EntityInterface, ModelInterface, ResultInterface /** * Use the standard serialize function to serialize the array data */ - return serialize(this->toArray()); + var attributes, snapshot, manager; + + let attributes = this->toArray(), + manager = this->getModelsManager(); + + if manager->isKeepingSnapshots(this) { + let snapshot = this->_snapshot; + /** + * If attributes is not the same as snapshot then save snapshot too + */ + if attributes != snapshot { + return serialize(["_attributes": attributes, "_snapshot": snapshot]); + } + } + + return serialize(attributes); } /** @@ -4311,7 +4326,7 @@ abstract class Model implements EntityInterface, ModelInterface, ResultInterface */ public function unserialize(string! data) { - var attributes, dependencyInjector, manager, key, value; + var attributes, dependencyInjector, manager, key, value, snapshot; let attributes = unserialize(data); if typeof attributes == "array" { @@ -4346,6 +4361,15 @@ abstract class Model implements EntityInterface, ModelInterface, ResultInterface * Try to initialize the model */ manager->initialize(this); + if manager->isKeepingSnapshots(this) { + if fetch snapshot, attributes["_snapshot"] { + let this->_snapshot = snapshot; + let attributes = attributes["_attributes"]; + } + else { + let this->_snapshot = attributes; + } + } /** * Update the objects attributes diff --git a/tests/_data/models/Robots.php b/tests/_data/models/Robots.php index 262bafb1b5e..7bc29725f46 100644 --- a/tests/_data/models/Robots.php +++ b/tests/_data/models/Robots.php @@ -25,6 +25,7 @@ class Robots extends Model { public function initialize() { + $this->keepSnapshots(true); $this->hasMany('id',RobotsParts::class, 'robots_id', ['foreignKey' => true, 'reusable' => false, 'alias' => 'parts']); } } diff --git a/tests/unit/Mvc/ModelTest.php b/tests/unit/Mvc/ModelTest.php index 96b161d10bc..b363e939ccd 100644 --- a/tests/unit/Mvc/ModelTest.php +++ b/tests/unit/Mvc/ModelTest.php @@ -2,6 +2,9 @@ namespace Phalcon\Test\Unit\Mvc; +use Phalcon\Cache\Backend\Apc; +use Phalcon\Cache\Frontend\Data; +use Phalcon\Test\Models\Robots; use Phalcon\Test\Models\Users; use Phalcon\Test\Models\Customers; use Phalcon\Test\Models\Packages; @@ -187,4 +190,39 @@ function () { } ); } + + /** + * Tests serializing model while using cache and keeping snapshots + * + * The snapshot should be saved while using cache + * + * @issue 12170, 12000 + * @author Wojciech Ĺšlawski + * @since 2016-08-26 + */ + public function testSerializeSnapshotCache() + { + $this->specify( + 'Snapshot data should be saved while saving model to cache', + function () { + $cache = new Apc(new Data(['lifetime' => 20])); + $robot = Robots::findFirst(); + expect($robot)->isInstanceOf(Robots::class); + expect($robot->getSnapshotData())->notEmpty(); + $cache->save('robot', $robot); + /** @var Robots $robot */ + $robot = $cache->get('robot'); + expect($robot)->isInstanceOf(Robots::class); + expect($robot->getSnapshotData())->notEmpty(); + expect($robot->getSnapshotData())->equals($robot->toArray()); + $robot->text = 'abc'; + $cache->save('robot', $robot); + /** @var Robots $robot */ + $robot = $cache->get('robot'); + expect($robot)->isInstanceOf(Robots::class); + expect($robot->getSnapshotData())->notEmpty(); + expect($robot->getSnapshotData())->notEquals($robot->toArray()); + } + ); + } }