Browse Source

Merge branch 'master' of github.com:cakephp/cakephp

Mark Story 11 years ago
parent
commit
acabf50ec9

+ 6 - 6
src/Controller/Component/RequestHandlerComponent.php

@@ -31,7 +31,7 @@ use Cake\Utility\Xml;
  * Request object for handling alternative HTTP requests
  *
  * Alternative HTTP requests can come from wireless units like mobile phones, palmtop computers,
- * and the like. These units have no use for Ajax requests, and this Component can tell how Cake
+ * and the like. These units have no use for AJAX requests, and this Component can tell how Cake
  * should respond to the different needs of a handheld computer and a desktop machine.
  *
  * @link http://book.cakephp.org/3.0/en/controllers/components/request-handling.html
@@ -142,7 +142,7 @@ class RequestHandlerComponent extends Component
      * Checks to see if a specific content type has been requested and sets RequestHandler::$ext
      * accordingly. Checks the following in order: 1. The '_ext' value parsed by the Router. 2. A specific
      * AJAX type request indicated by the presence of a header. 3. The Accept header. With the exception
-     * of an ajax request indicated using the second header based method above, the type must have
+     * of an AJAX request indicated using the second header based method above, the type must have
      * been configured in {@link Cake\Routing\Router}.
      *
      * @param array $config The config data.
@@ -273,12 +273,12 @@ class RequestHandlerComponent extends Component
     }
 
     /**
-     * Handles (fakes) redirects for Ajax requests using requestAction()
+     * Handles (fakes) redirects for AJAX requests using requestAction()
      *
      * @param Event $event The Controller.beforeRedirect event.
      * @param string|array $url A string or array containing the redirect location
      * @param \Cake\Network\Response $response The response object.
-     * @return void
+     * @return void|\Cake\Network\Response The response object if the redirect is caught.
      */
     public function beforeRedirect(Event $event, $url, Response $response)
     {
@@ -300,8 +300,8 @@ class RequestHandlerComponent extends Component
                 'REQUEST_METHOD' => 'GET'
             ]
         ]));
-        $response->send();
-        $response->stop();
+        $response->statusCode(200);
+        return $response;
     }
 
     /**

+ 9 - 2
src/I18n/Time.php

@@ -246,6 +246,8 @@ class Time extends Carbon implements JsonSerializable
      */
     public function timeAgoInWords(array $options = [])
     {
+        $time = $this;
+        
         $timezone = null;
         $format = static::$wordFormat;
         $end = static::$wordEnd;
@@ -272,8 +274,13 @@ class Time extends Carbon implements JsonSerializable
             }
         }
 
+        if ($timezone) {
+            $time = clone $this;
+            $time->timezone($timezone);
+        }
+
         $now = $from->format('U');
-        $inSeconds = $this->format('U');
+        $inSeconds = $time->format('U');
         $backwards = ($inSeconds > $now);
 
         $futureTime = $now;
@@ -289,7 +296,7 @@ class Time extends Carbon implements JsonSerializable
         }
 
         if ($diff > abs($now - (new static($end))->format('U'))) {
-            return sprintf($absoluteString, $this->i18nFormat($format));
+            return sprintf($absoluteString, $time->i18nFormat($format));
         }
 
         // If more than a week, then take into account the length of months

+ 2 - 3
src/ORM/Marshaller.php

@@ -437,9 +437,8 @@ class Marshaller
         foreach ((array)$options['fieldList'] as $field) {
             if (array_key_exists($field, $properties)) {
                 $entity->set($field, $properties[$field]);
-                if ($properties[$field] instanceof EntityInterface &&
-                    isset($marshalledAssocs[$field])) {
-                    $entity->dirty($assoc, $properties[$field]->dirty());
+                if ($properties[$field] instanceof EntityInterface && isset($marshalledAssocs[$field])) {
+                    $entity->dirty($field, $properties[$field]->dirty());
                 }
             }
         }

+ 3 - 0
src/View/Widget/BasicWidget.php

@@ -85,6 +85,9 @@ class BasicWidget implements WidgetInterface
      */
     public function secureFields(array $data)
     {
+        if (!isset($data['name']) || $data['name'] === '') {
+            return [];
+        }
         return [$data['name']];
     }
 }

+ 2 - 30
src/View/Widget/ButtonWidget.php

@@ -15,7 +15,7 @@
 namespace Cake\View\Widget;
 
 use Cake\View\Form\ContextInterface;
-use Cake\View\Widget\WidgetInterface;
+use Cake\View\Widget\BasicWidget;
 
 /**
  * Button input class
@@ -24,27 +24,10 @@ use Cake\View\Widget\WidgetInterface;
  * If you need to make basic submit inputs with type=submit,
  * use the Basic input widget.
  */
-class ButtonWidget implements WidgetInterface
+class ButtonWidget extends BasicWidget
 {
 
     /**
-     * StringTemplate instance.
-     *
-     * @var \Cake\View\StringTemplate
-     */
-    protected $_templates;
-
-    /**
-     * Constructor.
-     *
-     * @param \Cake\View\StringTemplate $templates Templates list.
-     */
-    public function __construct($templates)
-    {
-        $this->_templates = $templates;
-    }
-
-    /**
      * Render a button.
      *
      * This method accepts a number of keys:
@@ -72,15 +55,4 @@ class ButtonWidget implements WidgetInterface
             'attrs' => $this->_templates->formatAttributes($data, ['text']),
         ]);
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function secureFields(array $data)
-    {
-        if (!isset($data['name'])) {
-            return [];
-        }
-        return [$data['name']];
-    }
 }

+ 2 - 27
src/View/Widget/CheckboxWidget.php

@@ -15,32 +15,15 @@
 namespace Cake\View\Widget;
 
 use Cake\View\Form\ContextInterface;
-use Cake\View\Widget\WidgetInterface;
+use Cake\View\Widget\BasicWidget;
 
 /**
  * Input widget for creating checkbox widgets.
  */
-class CheckboxWidget implements WidgetInterface
+class CheckboxWidget extends BasicWidget
 {
 
     /**
-     * Template instance.
-     *
-     * @var \Cake\View\StringTemplate
-     */
-    protected $_templates;
-
-    /**
-     * Constructor
-     *
-     * @param \Cake\View\StringTemplate $templates Templates list.
-     */
-    public function __construct($templates)
-    {
-        $this->_templates = $templates;
-    }
-
-    /**
      * Render a checkbox element.
      *
      * Data supports the following keys:
@@ -98,12 +81,4 @@ class CheckboxWidget implements WidgetInterface
         }
         return false;
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function secureFields(array $data)
-    {
-        return [$data['name']];
-    }
 }

+ 2 - 27
src/View/Widget/SelectBoxWidget.php

@@ -15,7 +15,7 @@
 namespace Cake\View\Widget;
 
 use Cake\View\Form\ContextInterface;
-use Cake\View\Widget\WidgetInterface;
+use Cake\View\Widget\BasicWidget;
 use Traversable;
 
 /**
@@ -24,27 +24,10 @@ use Traversable;
  * This class is intended as an internal implementation detail
  * of Cake\View\Helper\FormHelper and is not intended for direct use.
  */
-class SelectBoxWidget implements WidgetInterface
+class SelectBoxWidget extends BasicWidget
 {
 
     /**
-     * Template instance.
-     *
-     * @var \Cake\View\StringTemplate
-     */
-    protected $_templates;
-
-    /**
-     * Constructor
-     *
-     * @param \Cake\View\StringTemplate $templates Templates list.
-     */
-    public function __construct($templates)
-    {
-        $this->_templates = $templates;
-    }
-
-    /**
      * Render a select box form input.
      *
      * Render a select box input given a set of data. Supported keys
@@ -292,12 +275,4 @@ class SelectBoxWidget implements WidgetInterface
         $strict = !is_numeric($key);
         return in_array((string)$key, $disabled, $strict);
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function secureFields(array $data)
-    {
-        return [$data['name']];
-    }
 }

+ 2 - 21
src/View/Widget/TextareaWidget.php

@@ -15,7 +15,7 @@
 namespace Cake\View\Widget;
 
 use Cake\View\Form\ContextInterface;
-use Cake\View\Widget\WidgetInterface;
+use Cake\View\Widget\BasicWidget;
 
 /**
  * Input widget class for generating a textarea control.
@@ -23,19 +23,8 @@ use Cake\View\Widget\WidgetInterface;
  * This class is intended as an internal implementation detail
  * of Cake\View\Helper\FormHelper and is not intended for direct use.
  */
-class TextareaWidget implements WidgetInterface
+class TextareaWidget extends BasicWidget
 {
-
-    /**
-     * Constructor
-     *
-     * @param \Cake\View\StringTemplate $templates Templates list.
-     */
-    public function __construct($templates)
-    {
-        $this->_templates = $templates;
-    }
-
     /**
      * Render a text area form widget.
      *
@@ -68,12 +57,4 @@ class TextareaWidget implements WidgetInterface
             )
         ]);
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public function secureFields(array $data)
-    {
-        return [$data['name']];
-    }
 }

+ 38 - 15
tests/TestCase/Controller/Component/RequestHandlerComponentTest.php

@@ -793,7 +793,7 @@ class RequestHandlerComponentTest extends TestCase
     }
 
     /**
-     * test that ajax requests involving redirects trigger requestAction instead.
+     * test that AJAX requests involving redirects trigger requestAction instead.
      *
      * @return void
      * @triggers Controller.beforeRedirect $this->Controller
@@ -810,16 +810,42 @@ class RequestHandlerComponentTest extends TestCase
         $this->Controller->RequestHandler->request = $this->Controller->request;
         $this->Controller->RequestHandler->response = $this->Controller->response;
         $this->Controller->request->expects($this->any())->method('is')->will($this->returnValue(true));
-        $this->Controller->response->expects($this->once())->method('stop');
 
-        ob_start();
-        $this->Controller->RequestHandler->beforeRedirect(
+        $response = $this->Controller->RequestHandler->beforeRedirect(
             $event,
-            ['controller' => 'request_handler_test', 'action' => 'destination'],
+            ['controller' => 'RequestHandlerTest', 'action' => 'destination'],
             $this->Controller->response
         );
-        $result = ob_get_clean();
-        $this->assertRegExp('/posts index/', $result, 'RequestAction redirect failed.');
+        $this->assertRegExp('/posts index/', $response->body(), 'RequestAction redirect failed.');
+    }
+
+    /**
+     * Tests that AJAX requests involving redirects don't let the status code bleed through.
+     *
+     * @return void
+     * @triggers Controller.beforeRedirect $this->Controller
+     */
+    public function testAjaxRedirectAsRequestActionStatusCode()
+    {
+        Configure::write('App.namespace', 'TestApp');
+        Router::connect('/:controller/:action');
+        $event = new Event('Controller.beforeRedirect', $this->Controller);
+
+        $this->Controller->RequestHandler = new RequestHandlerComponent($this->Controller->components());
+        $this->Controller->request = $this->getMock('Cake\Network\Request', ['is']);
+        $this->Controller->response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'stop']);
+        $this->Controller->response->statusCode(302);
+        $this->Controller->RequestHandler->request = $this->Controller->request;
+        $this->Controller->RequestHandler->response = $this->Controller->response;
+        $this->Controller->request->expects($this->any())->method('is')->will($this->returnValue(true));
+
+        $response = $this->Controller->RequestHandler->beforeRedirect(
+            $event,
+            ['controller' => 'RequestHandlerTest', 'action' => 'destination'],
+            $this->Controller->response
+        );
+        $this->assertRegExp('/posts index/', $response->body(), 'RequestAction redirect failed.');
+        $this->assertSame(200, $response->statusCode());
     }
 
     /**
@@ -841,17 +867,14 @@ class RequestHandlerComponentTest extends TestCase
         $this->Controller->RequestHandler->request = $this->Controller->request;
         $this->Controller->RequestHandler->response = $this->Controller->response;
         $this->Controller->request->expects($this->any())->method('is')->will($this->returnValue(true));
-        $this->Controller->response->expects($this->once())->method('stop');
 
-        ob_start();
-        $this->Controller->RequestHandler->beforeRedirect(
+        $response = $this->Controller->RequestHandler->beforeRedirect(
             $event,
-            ['controller' => 'request_handler_test', 'action' => 'ajax2_layout'],
+            ['controller' => 'RequestHandlerTest', 'action' => 'ajax2_layout'],
             $this->Controller->response
         );
-        $result = ob_get_clean();
-        $this->assertRegExp('/posts index/', $result, 'RequestAction redirect failed.');
-        $this->assertRegExp('/Ajax!/', $result, 'Layout was not rendered.');
+        $this->assertRegExp('/posts index/', $response->body(), 'RequestAction redirect failed.');
+        $this->assertRegExp('/Ajax!/', $response->body(), 'Layout was not rendered.');
     }
 
     /**
@@ -882,7 +905,7 @@ class RequestHandlerComponentTest extends TestCase
         ob_start();
         $RequestHandler->beforeRedirect(
             $event,
-            ['controller' => 'request_handler_test', 'action' => 'param_method', 'first', 'second'],
+            ['controller' => 'RequestHandlerTest', 'action' => 'param_method', 'first', 'second'],
             $this->Controller->response
         );
         $result = ob_get_clean();

+ 18 - 1
tests/TestCase/I18n/TimeTest.php

@@ -174,7 +174,24 @@ class TimeTest extends TestCase
             ],
         ];
     }
-
+    /**
+     * test the timezone option for timeAgoInWords
+     *
+     * @return void
+     */
+    public function testTimeAgoInWordsTimezone()
+    {
+        $time = new Time('1990-07-31 20:33:00 UTC');
+        $result = $time->timeAgoInWords(
+            [
+                'timezone' => 'America/Vancouver',
+                'end' => '+1month',
+                'format' => 'dd-MM-YYYY HH:mm:ss'
+            ]
+        );
+        $this->assertEquals('on 31-07-1990 13:33:00', $result);
+    }
+     
     /**
      * test the end option for timeAgoInWords
      *

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

@@ -889,6 +889,40 @@ class MarshallerTest extends TestCase
     }
 
     /**
+     * Test merge when fieldList contains an association.
+     *
+     * @return void
+     */
+    public function testMergeWithSingleAssociationAndFieldLists()
+    {
+        $user = new Entity([
+           'username' => 'user',
+        ]);
+        $article = new Entity([
+           'title' => 'title for post',
+           'body' => 'body',
+           'user' => $user,
+        ]);
+
+        $user->accessible('*', true);
+        $article->accessible('*', true);
+
+        $data = [
+            'title' => 'Chelsea',
+            'user' => [
+                'username' => 'dee'
+            ]
+        ];
+
+        $marshall = new Marshaller($this->articles);
+        $marshall->merge($article, $data, [
+            'fieldList' => ['title', 'user'],
+            'associated' => ['Users' => []]
+        ]);
+        $this->assertSame($user, $article->user);
+    }
+
+    /**
      * Tests that fields with the same value are not marked as dirty
      *
      * @return void