Browse Source

Merge pull request #5677 from robertpustulka/3.0-before-marshal

3.0 beforeMarshal event
José Lorenzo Rodríguez 11 years ago
parent
commit
acbe91f9c5
2 changed files with 114 additions and 10 deletions
  1. 25 10
      src/ORM/Marshaller.php
  2. 89 0
      tests/TestCase/ORM/MarshallerTest.php

+ 25 - 10
src/ORM/Marshaller.php

@@ -104,21 +104,18 @@ class Marshaller
         $propertyMap = $this->_buildPropertyMap($options);
 
         $schema = $this->_table->schema();
-        $tableName = $this->_table->alias();
         $entityClass = $this->_table->entityClass();
         $entity = new $entityClass();
         $entity->source($this->_table->alias());
 
-        if (isset($data[$tableName])) {
-            $data = $data[$tableName];
-        }
-
         if (isset($options['accessibleFields'])) {
             foreach ((array)$options['accessibleFields'] as $key => $value) {
                 $entity->accessible($key, $value);
             }
         }
 
+        $data = $this->_prepareData($data, $options);
+
         $errors = $this->_validate($data, $options, true);
         $primaryKey = $schema->primaryKey();
         $properties = [];
@@ -186,6 +183,27 @@ class Marshaller
     }
 
     /**
+     * Returns data prepared to validate and marshall.
+     *
+     * @param array $data The data to prepare.
+     * @param array $options The options passed to this marshaller.
+     * @return array Prepared data.
+     */
+    protected function _prepareData($data, $options)
+    {
+        $tableName = $this->_table->alias();
+
+        if (isset($data[$tableName])) {
+            $data = $data[$tableName];
+        }
+
+        $dataObject = new \ArrayObject($data);
+        $this->_table->dispatchEvent('Model.beforeMarshal', compact('dataObject', 'options'));
+
+        return (array)$dataObject;
+    }
+
+    /**
      * Create a new sub-marshaller and marshal the associated data.
      *
      * @param \Cake\ORM\Association $assoc The association to marshall
@@ -326,18 +344,15 @@ class Marshaller
     {
         $options += ['validate' => true];
         $propertyMap = $this->_buildPropertyMap($options);
-        $tableName = $this->_table->alias();
         $isNew = $entity->isNew();
         $keys = [];
 
-        if (isset($data[$tableName])) {
-            $data = $data[$tableName];
-        }
-
         if (!$isNew) {
             $keys = $entity->extract((array)$this->_table->primaryKey());
         }
 
+        $data = $this->_prepareData($data, $options);
+
         $errors = $this->_validate($data + $keys, $options, $isNew);
         $schema = $this->_table->schema();
         $properties = [];

+ 89 - 0
tests/TestCase/ORM/MarshallerTest.php

@@ -1745,4 +1745,93 @@ class MarshallerTest extends TestCase
         $this->assertNotEmpty($result->errors('author_id'));
         $this->assertNotEmpty($result->errors('thing'));
     }
+
+    /**
+     * Test Model.beforeMarshal event.
+     *
+     * @return void
+     */
+    public function testBeforeMarshalEvent()
+    {
+        $data = [
+            'title' => 'My title',
+            'body' => 'My content',
+            'user' => [
+                'name' => 'Robert',
+                'username' => 'rob'
+            ]
+        ];
+
+        $marshall = new Marshaller($this->articles);
+
+        $this->articles->eventManager()->attach(function ($e, $data) {
+            $data['title'] = 'Modified title';
+            $data['user']['username'] = 'robert';
+        }, 'Model.beforeMarshal');
+
+        $entity = $marshall->one($data, [
+            'associated' => ['Users']
+        ]);
+
+        $this->assertEquals('Modified title', $entity->title);
+        $this->assertEquals('My content', $entity->body);
+        $this->assertEquals('Robert', $entity->user->name);
+        $this->assertEquals('robert', $entity->user->username);
+    }
+
+    /**
+     * Test Model.beforeMarshal event on associated tables.
+     *
+     * @return void
+     */
+    public function testBeforeMarshalEventOnAssociations()
+    {
+        $data = [
+            'title' => 'My title',
+            'body' => 'My content',
+            'author_id' => 1,
+            'user' => [
+                'username' => 'mark',
+                'password' => 'secret'
+            ],
+            'comments' => [
+                ['comment' => 'First post', 'user_id' => 2],
+                ['comment' => 'Second post', 'user_id' => 2],
+            ],
+            'tags' => [
+                ['tag' => 'news', '_joinData' => ['active' => 1]],
+                ['tag' => 'cakephp', '_joinData' => ['active' => 0]],
+            ],
+        ];
+
+        $marshall = new Marshaller($this->articles);
+
+        $this->articles->users->eventManager()->attach(function ($e, $data) {
+            $data['secret'] = 'h45h3d';
+        }, 'Model.beforeMarshal');
+
+        $this->articles->comments->eventManager()->attach(function ($e, $data) {
+            $data['comment'] .= ' (modified)';
+        }, 'Model.beforeMarshal');
+
+        $this->articles->tags->eventManager()->attach(function ($e, $data) {
+            $data['tag'] .= ' (modified)';
+        }, 'Model.beforeMarshal');
+
+        $this->articles->tags->junction()->eventManager()->attach(function ($e, $data) {
+            $data['modified_by'] = 1;
+        }, 'Model.beforeMarshal');
+
+        $entity = $marshall->one($data, [
+            'associated' => ['Users', 'Comments', 'Tags']
+        ]);
+
+        $this->assertEquals('h45h3d', $entity->user->secret);
+        $this->assertEquals('First post (modified)', $entity->comments[0]->comment);
+        $this->assertEquals('Second post (modified)', $entity->comments[1]->comment);
+        $this->assertEquals('news (modified)', $entity->tags[0]->tag);
+        $this->assertEquals('cakephp (modified)', $entity->tags[1]->tag);
+        $this->assertEquals(1, $entity->tags[0]->_joinData->modified_by);
+        $this->assertEquals(1, $entity->tags[1]->_joinData->modified_by);
+    }
 }