Browse Source

Merge pull request #10692 from cakephp/3next-fluent-route

3.5 - Add fluent setters to Route
Mark Story 8 years ago
parent
commit
f4c1470459
2 changed files with 136 additions and 4 deletions
  1. 61 4
      src/Routing/Route/Route.php
  2. 75 0
      tests/TestCase/Routing/Route/RouteTest.php

+ 61 - 4
src/Routing/Route/Route.php

@@ -16,6 +16,7 @@ namespace Cake\Routing\Route;
 
 use Cake\Http\ServerRequest;
 use Cake\Routing\Router;
+use InvalidArgumentException;
 use Psr\Http\Message\ServerRequestInterface;
 
 /**
@@ -87,6 +88,13 @@ class Route
     protected $_extensions = [];
 
     /**
+     * Valid HTTP methods.
+     *
+     * @var array
+     */
+    const VALID_METHODS = ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];
+
+    /**
      * Constructor for a Route
      *
      * ### Options
@@ -104,11 +112,12 @@ class Route
     public function __construct($template, $defaults = [], array $options = [])
     {
         $this->template = $template;
-        $this->defaults = (array)$defaults;
-        if (isset($this->defaults['[method]'])) {
-            $this->defaults['_method'] = $this->defaults['[method]'];
-            unset($this->defaults['[method]']);
+        // @deprecated The `[method]` format should be removed in 4.0.0
+        if (isset($defaults['[method]'])) {
+            $defaults['_method'] = $defaults['[method]'];
+            unset($defaults['[method]']);
         }
+        $this->defaults = (array)$defaults;
         $this->options = $options + ['_ext' => []];
         $this->setExtensions((array)$this->options['_ext']);
     }
@@ -152,6 +161,53 @@ class Route
     }
 
     /**
+     * Set the accepted HTTP methods for this route.
+     *
+     * @param array $methods The HTTP methods to accept.
+     * @return $this
+     * @throws \InvalidArgumentException
+     */
+    public function setMethods(array $methods)
+    {
+        $methods = array_map('strtoupper', $methods);
+        $diff = array_diff($methods, static::VALID_METHODS);
+        if ($diff !== []) {
+            throw new InvalidArgumentException(
+                sprintf('Invalid HTTP method received. %s is invalid.', implode(', ', $diff))
+            );
+        }
+        $this->defaults['_method'] = $methods;
+
+        return $this;
+    }
+
+    /**
+     * Set regexp patterns for routing parameters
+     *
+     * @param array $patterns The patterns to apply to routing elements
+     * @return $this
+     */
+    public function setPatterns(array $patterns)
+    {
+        $this->options = array_merge($this->options, $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Set host requirement
+     *
+     * @param string $host The host name this route is bound to
+     * @return $this
+     */
+    public function setHost($host)
+    {
+        $this->options['_host'] = $host;
+
+        return $this;
+    }
+
+    /**
      * Check if a Route has been compiled into a regular expression.
      *
      * @return bool
@@ -623,6 +679,7 @@ class Route
         if (empty($this->defaults['_method'])) {
             return true;
         }
+        // @deprecated The `[method]` support should be removed in 4.0.0
         if (isset($url['[method]'])) {
             $url['_method'] = $url['[method]'];
         }

+ 75 - 0
tests/TestCase/Routing/Route/RouteTest.php

@@ -1523,4 +1523,79 @@ class RouteTest extends TestCase
         ];
         $this->assertEquals($expected, $route->parse('/', 'GET'));
     }
+
+    /**
+     * Test setting the method on a route.
+     *
+     * @return void
+     */
+    public function testSetMethods()
+    {
+        $route = new Route('/books/reviews', ['controller' => 'Reviews', 'action' => 'index']);
+        $result = $route->setMethods(['put']);
+
+        $this->assertSame($result, $route, 'Should return this');
+        $this->assertSame(['PUT'], $route->defaults['_method'], 'method is wrong');
+
+        $route->setMethods(['post', 'get', 'patch']);
+        $this->assertSame(['POST', 'GET', 'PATCH'], $route->defaults['_method']);
+    }
+
+    /**
+     * Test setting the method on a route to an invalid method
+     *
+     * @expectedException InvalidArgumentException
+     * @expectedExceptionMessage Invalid HTTP method received. NOPE is invalid
+     * @return void
+     */
+    public function testSetMethodsInvalid()
+    {
+        $route = new Route('/books/reviews', ['controller' => 'Reviews', 'action' => 'index']);
+        $route->setMethods(['nope']);
+    }
+
+    /**
+     * Test setting patterns through the method
+     *
+     * @return void
+     */
+    public function testSetPatterns()
+    {
+        $route = new Route('/reviews/:date/:id', ['controller' => 'Reviews', 'action' => 'view']);
+        $result = $route->setPatterns([
+            'date' => '\d+\-\d+\-\d+',
+            'id' => '[a-z]+'
+        ]);
+        $this->assertSame($result, $route, 'Should return this');
+        $this->assertArrayHasKey('id', $route->options);
+        $this->assertArrayHasKey('date', $route->options);
+        $this->assertSame('[a-z]+', $route->options['id']);
+
+        $this->assertFalse($route->parse('/reviews/a-b-c/xyz'));
+        $this->assertNotEmpty($route->parse('/reviews/2016-05-12/xyz'));
+    }
+
+    /**
+     * Test setting host requirements
+     *
+     * @return void
+     */
+    public function testSetHost()
+    {
+        $route = new Route('/reviews', ['controller' => 'Reviews', 'action' => 'index']);
+        $result = $route->setHost('blog.example.com');
+        $this->assertSame($result, $route, 'Should return this');
+
+        $request = new ServerRequest([
+            'environment' => [
+                'HTTP_HOST' => 'a.example.com',
+                'PATH_INFO' => '/reviews'
+            ]
+        ]);
+        $this->assertFalse($route->parseRequest($request));
+
+        $uri = $request->getUri();
+        $request = $request->withUri($uri->withHost('blog.example.com'));
+        $this->assertNotEmpty($route->parseRequest($request));
+    }
 }