Permalink
Browse files

handling of nested modified data in documents when calling document->…

…modified()
  • Loading branch information...
1 parent 3e58f83 commit 568cf961c912c8a5f80e75f65eab79840e9b2dd2 @rmarscher rmarscher committed Apr 26, 2012
Showing with 119 additions and 15 deletions.
  1. +4 −0 data/Entity.php
  2. +58 −1 data/collection/DocumentArray.php
  3. +57 −14 tests/cases/data/entity/DocumentTest.php
View
@@ -371,6 +371,10 @@ public function modified() {
$fields = array_fill_keys(array_keys($this->_data), false);
foreach ($this->_updated as $field => $value) {
if (is_object($value) && method_exists($value, 'modified')) {
+ if (!isset($this->_data[$field])) {
+ $fields[$field] = true;
+ continue;
+ }
$modified = $value->modified();
$fields[$field] = $modified === true || is_array($modified) && in_array(true, $modified, true);
} else {
@@ -46,12 +46,69 @@ public function exists() {
return $this->_exists;
}
- public function sync($id = null, array $data = array()) {
+ /**
+ * Called after an `Entity` is saved. Updates the object's internal state to reflect the
+ * corresponding database entity. **Do not** call this method if you intend
+ * to update the database's copy of the entity. Instead, see `Model::save()`.
+ *
+ * @see lithium\data\Model::save()
+ * @see lithium\data\Entity::sync()
+ * @param mixed $id Ignored, used to compatibility with `Entity::sync()`
+ * @param array $data Ignored, used to compatibility with `Entity::sync()`
+ * @param array $options Options when calling this method:
+ * - `'recursive'` _boolean_: If `true` attempts to sync nested objects as well.
+ * Otherwise, only syncs the current object. Defaults to `true`.
+ * @return void
+ */
+ public function sync($id = null, array $data = array(), array $options = array()) {
+ $defaults = array('recursive' => true);
+ $options += $defaults;
$this->_exists = true;
+
+ if (!$options['recursive']) {
+ $this->_original = $this->_data;
+ return;
+ }
+
+ foreach ($this->_data as $key => $val) {
+ if (is_object($val) && method_exists($val, 'sync')) {
+ $nested = isset($data[$key]) ? $data[$key] : array();
+ $this->_data[$key]->sync(null, $nested, $options);
+ }
+ }
+
$this->_original = $this->_data;
}
/**
+ * Determines if the `DocumentArray` has been modified since it was last saved
+ *
+ * @return boolean
+ */
+ public function modified() {
+ if (count($this->_original) !== count($this->_data)) {
+ return true;
+ }
+ foreach ($this->_original as $key => $doc) {
+ $updated = $this->_data[$key];
+ if (!isset($updated)) {
+ return true;
+ }
+ if ($doc !== $updated) {
+ return true;
+ }
+ if (!is_object($updated) || !method_exists($updated, 'modified')) {
+ continue;
+ }
+ $modified = $this->_data[$key]->modified();
+ if (in_array(true, $modified)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Adds conversions checks to ensure certain class types and embedded values are properly cast.
*
* @param string $format Currently only `array` is supported.
@@ -116,34 +116,77 @@ public function testSetField() {
public function testSyncModified() {
- $doc = new Document();
+ $doc = new Document(array('model' => $this->_model));
$doc->id = 4;
$doc->name = 'Four';
$doc->content = 'Lorem ipsum four';
+ $doc->array = array(1, 2, 3, 4);
+ $doc->subdoc = array(
+ 'setting' => 'something',
+ 'foo' => 'bar',
+ 'sub' => array(
+ 'name' => 'A sub sub doc'
+ )
+ );
+ $doc->subdocs = array(
+ array(
+ 'id' => 1
+ ),
+ array(
+ 'id' => 2
+ ),
+ array(
+ 'id' => 3
+ ),
+ array(
+ 'id' => 4
+ )
+ );
- $expected = array(
- 'id' => true,
- 'name' => true,
- 'content' => true,
+ $fields = array(
+ 'id', 'name', 'content',
+ 'array', 'subdoc', 'subdocs'
);
-
+ $expected = array_fill_keys($fields, true);
+
$this->assertEqual($expected, $doc->modified());
$doc->sync();
- $this->assertEqual(array_fill_keys(array_keys($expected), false), $doc->modified());
-
+ $this->assertEqual(array_fill_keys($fields, false), $doc->modified());
$doc->id = 5;
$doc->content = null;
$doc->new = null;
- $expected = array(
- 'id' => true,
- 'name' => false,
- 'content' => true,
- 'new' => true,
+ $doc->subdoc->foo = 'baz';
+ $doc->array[] = 5;
+ $doc->subdocs[] = array('id' => 5);
+ $expected['name'] = false;
+ $expected['new'] = true;
+ $fields[] = 'new';
+
+ $this->assertEqual($expected, $doc->modified());
+ $doc->sync();
+
+ $expected = array_fill_keys($fields, false);
+
+ $this->assertEqual($expected, $doc->modified());
+ $doc->sync();
+
+ $doc->subdocs[1]->updated = true;
+ $expected['subdocs'] = true;
+
+ $this->assertEqual($expected, $doc->modified());
+ $doc->sync();
+
+ $expected = array_fill_keys($fields, false);
+
+ $doc->array[1] = array(
+ 'foo' => 'bar'
);
-
+ $expected['array'] = true;
+
$this->assertEqual($expected, $doc->modified());
+ $doc->sync();
}
public function testNestedKeyGetSet() {

0 comments on commit 568cf96

Please sign in to comment.