Browse Source

Merge pull request #6373 from cakephp/widgets-securefields-2

Ensure widgets are rendered before secure field list is generated.
Mark Story 11 years ago
parent
commit
def326cbb6

+ 9 - 7
src/View/Helper/FormHelper.php

@@ -2519,17 +2519,19 @@ class FormHelper extends Helper
      */
     public function widget($name, array $data = [])
     {
+        $secure = null;
+        if (isset($data['secure'])) {
+            $secure = $data['secure'];
+            unset($data['secure']);
+        }
         $widget = $this->_registry->get($name);
-        if (isset($data['secure'], $data['name']) &&
-            $data['secure'] !== self::SECURE_SKIP
-        ) {
+        $out = $widget->render($data, $this->context());
+        if (isset($data['name']) && $secure !== null && $secure !== self::SECURE_SKIP) {
             foreach ($widget->secureFields($data) as $field) {
-                $this->_secure($data['secure'], $this->_secureFieldName($field));
+                $this->_secure($secure, $this->_secureFieldName($field));
             }
         }
-        unset($data['secure']);
-
-        return $widget->render($data, $this->context());
+        return $out;
     }
 
     /**

+ 40 - 27
src/View/Widget/DateTimeWidget.php

@@ -123,30 +123,10 @@ class DateTimeWidget implements WidgetInterface
      */
     public function render(array $data, ContextInterface $context)
     {
-        $data += [
-            'name' => '',
-            'empty' => false,
-            'disabled' => null,
-            'val' => null,
-            'year' => [],
-            'month' => [],
-            'day' => [],
-            'hour' => [],
-            'minute' => [],
-            'second' => [],
-            'meridian' => null,
-        ];
+        $data = $this->_normalizeData($data);
 
         $selected = $this->_deconstructDate($data['val'], $data);
 
-        $timeFormat = isset($data['hour']['format']) ? $data['hour']['format'] : null;
-        if ($timeFormat === 12 && !isset($data['meridian'])) {
-            $data['meridian'] = [];
-        }
-        if ($timeFormat === 24) {
-            $data['meridian'] = false;
-        }
-
         $templateOptions = [];
         foreach ($this->_selects as $select) {
             if ($data[$select] === false || $data[$select] === null) {
@@ -179,6 +159,39 @@ class DateTimeWidget implements WidgetInterface
     }
 
     /**
+     * Normalize data.
+     *
+     * @param array $data Data to normalize.
+     * @return array Normalized data.
+     */
+    protected function _normalizeData($data)
+    {
+        $data += [
+            'name' => '',
+            'empty' => false,
+            'disabled' => null,
+            'val' => null,
+            'year' => [],
+            'month' => [],
+            'day' => [],
+            'hour' => [],
+            'minute' => [],
+            'second' => [],
+            'meridian' => null,
+        ];
+
+        $timeFormat = isset($data['hour']['format']) ? $data['hour']['format'] : null;
+        if ($timeFormat === 12 && !isset($data['meridian'])) {
+            $data['meridian'] = [];
+        }
+        if ($timeFormat === 24) {
+            $data['meridian'] = false;
+        }
+
+        return $data;
+    }
+
+    /**
      * Deconstructs the passed date value into all time units
      *
      * @param string|int|array|\DateTime|null $value Value to deconstruct.
@@ -569,15 +582,15 @@ class DateTimeWidget implements WidgetInterface
      */
     public function secureFields(array $data)
     {
+        $data = $this->_normalizeData($data);
+
         $fields = [];
-        $hourFormat = isset($data['hour']['format']) ? $data['hour']['format'] : null;
-        foreach ($this->_selects as $type) {
-            if ($type === 'meridian' && ($hourFormat === null || $hourFormat === 24)) {
+        foreach ($this->_selects as $select) {
+            if ($data[$select] === false || $data[$select] === null) {
                 continue;
             }
-            if (!isset($data[$type]) || $data[$type] !== false) {
-                $fields[] = $data['name'] . '[' . $type . ']';
-            }
+
+            $fields[] = $data['name'] . '[' . $select . ']';
         }
         return $fields;
     }

+ 29 - 0
tests/TestCase/View/Helper/FormHelperTest.php

@@ -263,6 +263,35 @@ class FormHelperTest extends TestCase
     }
 
     /**
+     * Test that secureFields() of widget is called after calling render(),
+     * not before.
+     *
+     * @return void
+     */
+    public function testOrderForRenderingWidgetAndFetchingSecureFields()
+    {
+        $data = [
+            'val' => 1,
+            'name' => 'test'
+        ];
+        $mock = $this->getMock('Cake\View\Widget\WidgetInterface');
+        $this->assertNull($this->Form->addWidget('test', $mock));
+
+        $mock->expects($this->at(0))
+            ->method('render')
+            ->with($data)
+            ->will($this->returnValue('HTML'));
+
+        $mock->expects($this->at(1))
+            ->method('secureFields')
+            ->with($data)
+            ->will($this->returnValue(['test']));
+
+        $result = $this->Form->widget('test', $data + ['secure' => true]);
+        $this->assertEquals('HTML', $result);
+    }
+
+    /**
      * Test that empty string is not added to secure fields list when
      * rendering input widget without name.
      *