CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • Dispatcher
  • DispatcherFactory
  • DispatcherFilter
  • RouteBuilder
  • Router

Traits

  • RequestActionTrait
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   5:  *
   6:  * Licensed under The MIT License
   7:  * For full copyright and license information, please see the LICENSE.txt
   8:  * Redistributions of files must retain the above copyright notice.
   9:  *
  10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11:  * @link          https://cakephp.org CakePHP(tm) Project
  12:  * @since         3.0.0
  13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  14:  */
  15: namespace Cake\Routing;
  16: 
  17: use BadMethodCallException;
  18: use Cake\Core\App;
  19: use Cake\Core\Exception\MissingPluginException;
  20: use Cake\Core\Plugin;
  21: use Cake\Routing\Route\Route;
  22: use Cake\Utility\Inflector;
  23: use InvalidArgumentException;
  24: use RuntimeException;
  25: 
  26: /**
  27:  * Provides features for building routes inside scopes.
  28:  *
  29:  * Gives an easy to use way to build routes and append them
  30:  * into a route collection.
  31:  */
  32: class RouteBuilder
  33: {
  34:     /**
  35:      * Regular expression for auto increment IDs
  36:      *
  37:      * @var string
  38:      */
  39:     const ID = '[0-9]+';
  40: 
  41:     /**
  42:      * Regular expression for UUIDs
  43:      *
  44:      * @var string
  45:      */
  46:     const UUID = '[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}';
  47: 
  48:     /**
  49:      * Default HTTP request method => controller action map.
  50:      *
  51:      * @var array
  52:      */
  53:     protected static $_resourceMap = [
  54:         'index' => ['action' => 'index', 'method' => 'GET', 'path' => ''],
  55:         'create' => ['action' => 'add', 'method' => 'POST', 'path' => ''],
  56:         'view' => ['action' => 'view', 'method' => 'GET', 'path' => ':id'],
  57:         'update' => ['action' => 'edit', 'method' => ['PUT', 'PATCH'], 'path' => ':id'],
  58:         'delete' => ['action' => 'delete', 'method' => 'DELETE', 'path' => ':id'],
  59:     ];
  60: 
  61:     /**
  62:      * Default route class to use if none is provided in connect() options.
  63:      *
  64:      * @var string
  65:      */
  66:     protected $_routeClass = 'Cake\Routing\Route\Route';
  67: 
  68:     /**
  69:      * The extensions that should be set into the routes connected.
  70:      *
  71:      * @var string[]
  72:      */
  73:     protected $_extensions = [];
  74: 
  75:     /**
  76:      * The path prefix scope that this collection uses.
  77:      *
  78:      * @var string
  79:      */
  80:     protected $_path;
  81: 
  82:     /**
  83:      * The scope parameters if there are any.
  84:      *
  85:      * @var array
  86:      */
  87:     protected $_params;
  88: 
  89:     /**
  90:      * Name prefix for connected routes.
  91:      *
  92:      * @var string
  93:      */
  94:     protected $_namePrefix = '';
  95: 
  96:     /**
  97:      * The route collection routes should be added to.
  98:      *
  99:      * @var \Cake\Routing\RouteCollection
 100:      */
 101:     protected $_collection;
 102: 
 103:     /**
 104:      * The list of middleware that routes in this builder get
 105:      * added during construction.
 106:      *
 107:      * @var array
 108:      */
 109:     protected $middleware = [];
 110: 
 111:     /**
 112:      * Constructor
 113:      *
 114:      * ### Options
 115:      *
 116:      * - `routeClass` - The default route class to use when adding routes.
 117:      * - `extensions` - The extensions to connect when adding routes.
 118:      * - `namePrefix` - The prefix to prepend to all route names.
 119:      * - `middleware` - The names of the middleware routes should have applied.
 120:      *
 121:      * @param \Cake\Routing\RouteCollection $collection The route collection to append routes into.
 122:      * @param string $path The path prefix the scope is for.
 123:      * @param array $params The scope's routing parameters.
 124:      * @param array $options Options list.
 125:      */
 126:     public function __construct(RouteCollection $collection, $path, array $params = [], array $options = [])
 127:     {
 128:         $this->_collection = $collection;
 129:         $this->_path = $path;
 130:         $this->_params = $params;
 131:         if (isset($options['routeClass'])) {
 132:             $this->_routeClass = $options['routeClass'];
 133:         }
 134:         if (isset($options['extensions'])) {
 135:             $this->_extensions = $options['extensions'];
 136:         }
 137:         if (isset($options['namePrefix'])) {
 138:             $this->_namePrefix = $options['namePrefix'];
 139:         }
 140:         if (isset($options['middleware'])) {
 141:             $this->middleware = (array)$options['middleware'];
 142:         }
 143:     }
 144: 
 145:     /**
 146:      * Get or set default route class.
 147:      *
 148:      * @deprecated 3.5.0 Use getRouteClass/setRouteClass instead.
 149:      * @param string|null $routeClass Class name.
 150:      * @return string|null
 151:      */
 152:     public function routeClass($routeClass = null)
 153:     {
 154:         deprecationWarning(
 155:             'RouteBuilder::routeClass() is deprecated. ' .
 156:             'Use RouteBuilder::setRouteClass()/getRouteClass() instead.'
 157:         );
 158:         if ($routeClass === null) {
 159:             return $this->getRouteClass();
 160:         }
 161:         $this->setRouteClass($routeClass);
 162:     }
 163: 
 164:     /**
 165:      * Set default route class.
 166:      *
 167:      * @param string $routeClass Class name.
 168:      * @return $this
 169:      */
 170:     public function setRouteClass($routeClass)
 171:     {
 172:         $this->_routeClass = $routeClass;
 173: 
 174:         return $this;
 175:     }
 176: 
 177:     /**
 178:      * Get default route class.
 179:      *
 180:      * @return string
 181:      */
 182:     public function getRouteClass()
 183:     {
 184:         return $this->_routeClass;
 185:     }
 186: 
 187:     /**
 188:      * Get or set the extensions in this route builder's scope.
 189:      *
 190:      * Future routes connected in through this builder will have the connected
 191:      * extensions applied. However, setting extensions does not modify existing routes.
 192:      *
 193:      * @deprecated 3.5.0 Use getExtensions/setExtensions instead.
 194:      * @param array|string|null $extensions Either the extensions to use or null.
 195:      * @return array|null
 196:      */
 197:     public function extensions($extensions = null)
 198:     {
 199:         deprecationWarning(
 200:             'RouteBuilder::extensions() is deprecated. ' .
 201:             'Use RouteBuilder::setExtensions()/getExtensions() instead.'
 202:         );
 203:         if ($extensions === null) {
 204:             return $this->getExtensions();
 205:         }
 206:         $this->setExtensions($extensions);
 207:     }
 208: 
 209:     /**
 210:      * Set the extensions in this route builder's scope.
 211:      *
 212:      * Future routes connected in through this builder will have the connected
 213:      * extensions applied. However, setting extensions does not modify existing routes.
 214:      *
 215:      * @param string|string[] $extensions The extensions to set.
 216:      * @return $this
 217:      */
 218:     public function setExtensions($extensions)
 219:     {
 220:         $this->_extensions = (array)$extensions;
 221: 
 222:         return $this;
 223:     }
 224: 
 225:     /**
 226:      * Get the extensions in this route builder's scope.
 227:      *
 228:      * @return string[]
 229:      */
 230:     public function getExtensions()
 231:     {
 232:         return $this->_extensions;
 233:     }
 234: 
 235:     /**
 236:      * Add additional extensions to what is already in current scope
 237:      *
 238:      * @param string|array $extensions One or more extensions to add
 239:      * @return void
 240:      */
 241:     public function addExtensions($extensions)
 242:     {
 243:         $extensions = array_merge($this->_extensions, (array)$extensions);
 244:         $this->_extensions = array_unique($extensions);
 245:     }
 246: 
 247:     /**
 248:      * Get the path this scope is for.
 249:      *
 250:      * @return string
 251:      */
 252:     public function path()
 253:     {
 254:         $routeKey = strpos($this->_path, ':');
 255:         if ($routeKey !== false) {
 256:             return substr($this->_path, 0, $routeKey);
 257:         }
 258: 
 259:         return $this->_path;
 260:     }
 261: 
 262:     /**
 263:      * Get the parameter names/values for this scope.
 264:      *
 265:      * @return array
 266:      */
 267:     public function params()
 268:     {
 269:         return $this->_params;
 270:     }
 271: 
 272:     /**
 273:      * Checks if there is already a route with a given name.
 274:      *
 275:      * @param string $name Name.
 276:      * @return bool
 277:      */
 278:     public function nameExists($name)
 279:     {
 280:         return array_key_exists($name, $this->_collection->named());
 281:     }
 282: 
 283:     /**
 284:      * Get/set the name prefix for this scope.
 285:      *
 286:      * Modifying the name prefix will only change the prefix
 287:      * used for routes connected after the prefix is changed.
 288:      *
 289:      * @param string|null $value Either the value to set or null.
 290:      * @return string
 291:      */
 292:     public function namePrefix($value = null)
 293:     {
 294:         if ($value !== null) {
 295:             $this->_namePrefix = $value;
 296:         }
 297: 
 298:         return $this->_namePrefix;
 299:     }
 300: 
 301:     /**
 302:      * Generate REST resource routes for the given controller(s).
 303:      *
 304:      * A quick way to generate a default routes to a set of REST resources (controller(s)).
 305:      *
 306:      * ### Usage
 307:      *
 308:      * Connect resource routes for an app controller:
 309:      *
 310:      * ```
 311:      * $routes->resources('Posts');
 312:      * ```
 313:      *
 314:      * Connect resource routes for the Comments controller in the
 315:      * Comments plugin:
 316:      *
 317:      * ```
 318:      * Router::plugin('Comments', function ($routes) {
 319:      *   $routes->resources('Comments');
 320:      * });
 321:      * ```
 322:      *
 323:      * Plugins will create lower_case underscored resource routes. e.g
 324:      * `/comments/comments`
 325:      *
 326:      * Connect resource routes for the Articles controller in the
 327:      * Admin prefix:
 328:      *
 329:      * ```
 330:      * Router::prefix('admin', function ($routes) {
 331:      *   $routes->resources('Articles');
 332:      * });
 333:      * ```
 334:      *
 335:      * Prefixes will create lower_case underscored resource routes. e.g
 336:      * `/admin/posts`
 337:      *
 338:      * You can create nested resources by passing a callback in:
 339:      *
 340:      * ```
 341:      * $routes->resources('Articles', function ($routes) {
 342:      *   $routes->resources('Comments');
 343:      * });
 344:      * ```
 345:      *
 346:      * The above would generate both resource routes for `/articles`, and `/articles/:article_id/comments`.
 347:      * You can use the `map` option to connect additional resource methods:
 348:      *
 349:      * ```
 350:      * $routes->resources('Articles', [
 351:      *   'map' => ['deleteAll' => ['action' => 'deleteAll', 'method' => 'DELETE']]
 352:      * ]);
 353:      * ```
 354:      *
 355:      * In addition to the default routes, this would also connect a route for `/articles/delete_all`.
 356:      * By default the path segment will match the key name. You can use the 'path' key inside the resource
 357:      * definition to customize the path name.
 358:      *
 359:      * You can use the `inflect` option to change how path segments are generated:
 360:      *
 361:      * ```
 362:      * $routes->resources('PaymentTypes', ['inflect' => 'dasherize']);
 363:      * ```
 364:      *
 365:      * Will generate routes like `/payment-types` instead of `/payment_types`
 366:      *
 367:      * ### Options:
 368:      *
 369:      * - 'id' - The regular expression fragment to use when matching IDs. By default, matches
 370:      *    integer values and UUIDs.
 371:      * - 'inflect' - Choose the inflection method used on the resource name. Defaults to 'underscore'.
 372:      * - 'only' - Only connect the specific list of actions.
 373:      * - 'actions' - Override the method names used for connecting actions.
 374:      * - 'map' - Additional resource routes that should be connected. If you define 'only' and 'map',
 375:      *   make sure that your mapped methods are also in the 'only' list.
 376:      * - 'prefix' - Define a routing prefix for the resource controller. If the current scope
 377:      *   defines a prefix, this prefix will be appended to it.
 378:      * - 'connectOptions' - Custom options for connecting the routes.
 379:      * - 'path' - Change the path so it doesn't match the resource name. E.g ArticlesController
 380:      *   is available at `/posts`
 381:      *
 382:      * @param string $name A controller name to connect resource routes for.
 383:      * @param array|callable $options Options to use when generating REST routes, or a callback.
 384:      * @param callable|null $callback An optional callback to be executed in a nested scope. Nested
 385:      *   scopes inherit the existing path and 'id' parameter.
 386:      * @return void
 387:      */
 388:     public function resources($name, $options = [], $callback = null)
 389:     {
 390:         if (is_callable($options)) {
 391:             $callback = $options;
 392:             $options = [];
 393:         }
 394:         $options += [
 395:             'connectOptions' => [],
 396:             'inflect' => 'underscore',
 397:             'id' => static::ID . '|' . static::UUID,
 398:             'only' => [],
 399:             'actions' => [],
 400:             'map' => [],
 401:             'prefix' => null,
 402:             'path' => null,
 403:         ];
 404: 
 405:         foreach ($options['map'] as $k => $mapped) {
 406:             $options['map'][$k] += ['method' => 'GET', 'path' => $k, 'action' => ''];
 407:         }
 408: 
 409:         $ext = null;
 410:         if (!empty($options['_ext'])) {
 411:             $ext = $options['_ext'];
 412:         }
 413: 
 414:         $connectOptions = $options['connectOptions'];
 415:         if (empty($options['path'])) {
 416:             $method = $options['inflect'];
 417:             $options['path'] = Inflector::$method($name);
 418:         }
 419:         $resourceMap = array_merge(static::$_resourceMap, $options['map']);
 420: 
 421:         $only = (array)$options['only'];
 422:         if (empty($only)) {
 423:             $only = array_keys($resourceMap);
 424:         }
 425: 
 426:         $prefix = '';
 427:         if ($options['prefix']) {
 428:             $prefix = $options['prefix'];
 429:         }
 430:         if (isset($this->_params['prefix']) && $prefix) {
 431:             $prefix = $this->_params['prefix'] . '/' . $prefix;
 432:         }
 433: 
 434:         foreach ($resourceMap as $method => $params) {
 435:             if (!in_array($method, $only, true)) {
 436:                 continue;
 437:             }
 438: 
 439:             $action = $params['action'];
 440:             if (isset($options['actions'][$method])) {
 441:                 $action = $options['actions'][$method];
 442:             }
 443: 
 444:             $url = '/' . implode('/', array_filter([$options['path'], $params['path']]));
 445:             $params = [
 446:                 'controller' => $name,
 447:                 'action' => $action,
 448:                 '_method' => $params['method'],
 449:             ];
 450:             if ($prefix) {
 451:                 $params['prefix'] = $prefix;
 452:             }
 453:             $routeOptions = $connectOptions + [
 454:                 'id' => $options['id'],
 455:                 'pass' => ['id'],
 456:                 '_ext' => $ext,
 457:             ];
 458:             $this->connect($url, $params, $routeOptions);
 459:         }
 460: 
 461:         if (is_callable($callback)) {
 462:             $idName = Inflector::singularize(Inflector::underscore($name)) . '_id';
 463:             $path = '/' . $options['path'] . '/:' . $idName;
 464:             $this->scope($path, [], $callback);
 465:         }
 466:     }
 467: 
 468:     /**
 469:      * Create a route that only responds to GET requests.
 470:      *
 471:      * @param string $template The URL template to use.
 472:      * @param array $target An array describing the target route parameters. These parameters
 473:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 474:      * @param string $name The name of the route.
 475:      * @return \Cake\Routing\Route\Route
 476:      */
 477:     public function get($template, $target, $name = null)
 478:     {
 479:         return $this->_methodRoute('GET', $template, $target, $name);
 480:     }
 481: 
 482:     /**
 483:      * Create a route that only responds to POST requests.
 484:      *
 485:      * @param string $template The URL template to use.
 486:      * @param array $target An array describing the target route parameters. These parameters
 487:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 488:      * @param string $name The name of the route.
 489:      * @return \Cake\Routing\Route\Route
 490:      */
 491:     public function post($template, $target, $name = null)
 492:     {
 493:         return $this->_methodRoute('POST', $template, $target, $name);
 494:     }
 495: 
 496:     /**
 497:      * Create a route that only responds to PUT requests.
 498:      *
 499:      * @param string $template The URL template to use.
 500:      * @param array $target An array describing the target route parameters. These parameters
 501:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 502:      * @param string $name The name of the route.
 503:      * @return \Cake\Routing\Route\Route
 504:      */
 505:     public function put($template, $target, $name = null)
 506:     {
 507:         return $this->_methodRoute('PUT', $template, $target, $name);
 508:     }
 509: 
 510:     /**
 511:      * Create a route that only responds to PATCH requests.
 512:      *
 513:      * @param string $template The URL template to use.
 514:      * @param array $target An array describing the target route parameters. These parameters
 515:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 516:      * @param string $name The name of the route.
 517:      * @return \Cake\Routing\Route\Route
 518:      */
 519:     public function patch($template, $target, $name = null)
 520:     {
 521:         return $this->_methodRoute('PATCH', $template, $target, $name);
 522:     }
 523: 
 524:     /**
 525:      * Create a route that only responds to DELETE requests.
 526:      *
 527:      * @param string $template The URL template to use.
 528:      * @param array $target An array describing the target route parameters. These parameters
 529:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 530:      * @param string $name The name of the route.
 531:      * @return \Cake\Routing\Route\Route
 532:      */
 533:     public function delete($template, $target, $name = null)
 534:     {
 535:         return $this->_methodRoute('DELETE', $template, $target, $name);
 536:     }
 537: 
 538:     /**
 539:      * Create a route that only responds to HEAD requests.
 540:      *
 541:      * @param string $template The URL template to use.
 542:      * @param array $target An array describing the target route parameters. These parameters
 543:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 544:      * @param string $name The name of the route.
 545:      * @return \Cake\Routing\Route\Route
 546:      */
 547:     public function head($template, $target, $name = null)
 548:     {
 549:         return $this->_methodRoute('HEAD', $template, $target, $name);
 550:     }
 551: 
 552:     /**
 553:      * Create a route that only responds to OPTIONS requests.
 554:      *
 555:      * @param string $template The URL template to use.
 556:      * @param array $target An array describing the target route parameters. These parameters
 557:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 558:      * @param string $name The name of the route.
 559:      * @return \Cake\Routing\Route\Route
 560:      */
 561:     public function options($template, $target, $name = null)
 562:     {
 563:         return $this->_methodRoute('OPTIONS', $template, $target, $name);
 564:     }
 565: 
 566:     /**
 567:      * Helper to create routes that only respond to a single HTTP method.
 568:      *
 569:      * @param string $method The HTTP method name to match.
 570:      * @param string $template The URL template to use.
 571:      * @param array $target An array describing the target route parameters. These parameters
 572:      *   should indicate the plugin, prefix, controller, and action that this route points to.
 573:      * @param string $name The name of the route.
 574:      * @return \Cake\Routing\Route\Route
 575:      */
 576:     protected function _methodRoute($method, $template, $target, $name)
 577:     {
 578:         if ($name !== null) {
 579:             $name = $this->_namePrefix . $name;
 580:         }
 581:         $options = [
 582:             '_name' => $name,
 583:             '_ext' => $this->_extensions,
 584:             '_middleware' => $this->middleware,
 585:             'routeClass' => $this->_routeClass,
 586:         ];
 587: 
 588:         $target = $this->parseDefaults($target);
 589:         $target['_method'] = $method;
 590: 
 591:         $route = $this->_makeRoute($template, $target, $options);
 592:         $this->_collection->add($route, $options);
 593: 
 594:         return $route;
 595:     }
 596: 
 597:     /**
 598:      * Load routes from a plugin.
 599:      *
 600:      * The routes file will have a local variable named `$routes` made available which contains
 601:      * the current RouteBuilder instance.
 602:      *
 603:      * @param string $name The plugin name
 604:      * @param string $file The routes file to load. Defaults to `routes.php`. This parameter
 605:      *   is deprecated and will be removed in 4.0
 606:      * @return void
 607:      * @throws \Cake\Core\Exception\MissingPluginException When the plugin has not been loaded.
 608:      * @throws \InvalidArgumentException When the plugin does not have a routes file.
 609:      */
 610:     public function loadPlugin($name, $file = 'routes.php')
 611:     {
 612:         $plugins = Plugin::getCollection();
 613:         if (!$plugins->has($name)) {
 614:             throw new MissingPluginException(['plugin' => $name]);
 615:         }
 616:         $plugin = $plugins->get($name);
 617: 
 618:         // @deprecated This block should be removed in 4.0
 619:         if ($file !== 'routes.php') {
 620:             deprecationWarning(
 621:                 'Loading plugin routes now uses the routes() hook method on the plugin class. ' .
 622:                 'Loading non-standard files will be removed in 4.0'
 623:             );
 624: 
 625:             $path = $plugin->getConfigPath() . DIRECTORY_SEPARATOR . $file;
 626:             if (!file_exists($path)) {
 627:                 throw new InvalidArgumentException(sprintf(
 628:                     'Cannot load routes for the plugin named %s. The %s file does not exist.',
 629:                     $name,
 630:                     $path
 631:                 ));
 632:             }
 633: 
 634:             $routes = $this;
 635:             include $path;
 636: 
 637:             return;
 638:         }
 639:         $plugin->routes($this);
 640: 
 641:         // Disable the routes hook to prevent duplicate route issues.
 642:         $plugin->disable('routes');
 643:     }
 644: 
 645:     /**
 646:      * Connects a new Route.
 647:      *
 648:      * Routes are a way of connecting request URLs to objects in your application.
 649:      * At their core routes are a set or regular expressions that are used to
 650:      * match requests to destinations.
 651:      *
 652:      * Examples:
 653:      *
 654:      * ```
 655:      * $routes->connect('/:controller/:action/*');
 656:      * ```
 657:      *
 658:      * The first parameter will be used as a controller name while the second is
 659:      * used as the action name. The '/*' syntax makes this route greedy in that
 660:      * it will match requests like `/posts/index` as well as requests
 661:      * like `/posts/edit/1/foo/bar`.
 662:      *
 663:      * ```
 664:      * $routes->connect('/home-page', ['controller' => 'Pages', 'action' => 'display', 'home']);
 665:      * ```
 666:      *
 667:      * The above shows the use of route parameter defaults. And providing routing
 668:      * parameters for a static route.
 669:      *
 670:      * ```
 671:      * $routes->connect(
 672:      *   '/:lang/:controller/:action/:id',
 673:      *   [],
 674:      *   ['id' => '[0-9]+', 'lang' => '[a-z]{3}']
 675:      * );
 676:      * ```
 677:      *
 678:      * Shows connecting a route with custom route parameters as well as
 679:      * providing patterns for those parameters. Patterns for routing parameters
 680:      * do not need capturing groups, as one will be added for each route params.
 681:      *
 682:      * $options offers several 'special' keys that have special meaning
 683:      * in the $options array.
 684:      *
 685:      * - `routeClass` is used to extend and change how individual routes parse requests
 686:      *   and handle reverse routing, via a custom routing class.
 687:      *   Ex. `'routeClass' => 'SlugRoute'`
 688:      * - `pass` is used to define which of the routed parameters should be shifted
 689:      *   into the pass array. Adding a parameter to pass will remove it from the
 690:      *   regular route array. Ex. `'pass' => ['slug']`.
 691:      * -  `persist` is used to define which route parameters should be automatically
 692:      *   included when generating new URLs. You can override persistent parameters
 693:      *   by redefining them in a URL or remove them by setting the parameter to `false`.
 694:      *   Ex. `'persist' => ['lang']`
 695:      * - `multibytePattern` Set to true to enable multibyte pattern support in route
 696:      *   parameter patterns.
 697:      * - `_name` is used to define a specific name for routes. This can be used to optimize
 698:      *   reverse routing lookups. If undefined a name will be generated for each
 699:      *   connected route.
 700:      * - `_ext` is an array of filename extensions that will be parsed out of the url if present.
 701:      *   See {@link \Cake\Routing\RouteCollection::setExtensions()}.
 702:      * - `_method` Only match requests with specific HTTP verbs.
 703:      *
 704:      * Example of using the `_method` condition:
 705:      *
 706:      * ```
 707:      * $routes->connect('/tasks', ['controller' => 'Tasks', 'action' => 'index', '_method' => 'GET']);
 708:      * ```
 709:      *
 710:      * The above route will only be matched for GET requests. POST requests will fail to match this route.
 711:      *
 712:      * @param string $route A string describing the template of the route
 713:      * @param array|string $defaults An array describing the default route parameters. These parameters will be used by default
 714:      *   and can supply routing parameters that are not dynamic. See above.
 715:      * @param array $options An array matching the named elements in the route to regular expressions which that
 716:      *   element should match. Also contains additional parameters such as which routed parameters should be
 717:      *   shifted into the passed arguments, supplying patterns for routing parameters and supplying the name of a
 718:      *   custom routing class.
 719:      * @return \Cake\Routing\Route\Route
 720:      * @throws \InvalidArgumentException
 721:      * @throws \BadMethodCallException
 722:      */
 723:     public function connect($route, $defaults = [], array $options = [])
 724:     {
 725:         $defaults = $this->parseDefaults($defaults);
 726:         if (empty($options['_ext'])) {
 727:             $options['_ext'] = $this->_extensions;
 728:         }
 729:         if (empty($options['routeClass'])) {
 730:             $options['routeClass'] = $this->_routeClass;
 731:         }
 732:         if (isset($options['_name']) && $this->_namePrefix) {
 733:             $options['_name'] = $this->_namePrefix . $options['_name'];
 734:         }
 735:         if (empty($options['_middleware'])) {
 736:             $options['_middleware'] = $this->middleware;
 737:         }
 738: 
 739:         $route = $this->_makeRoute($route, $defaults, $options);
 740:         $this->_collection->add($route, $options);
 741: 
 742:         return $route;
 743:     }
 744: 
 745:     /**
 746:      * Parse the defaults if they're a string
 747:      *
 748:      * @param string|array $defaults Defaults array from the connect() method.
 749:      * @return string|array
 750:      */
 751:     protected static function parseDefaults($defaults)
 752:     {
 753:         if (!is_string($defaults)) {
 754:             return $defaults;
 755:         }
 756: 
 757:         $regex = '/(?:(?<plugin>[a-zA-Z0-9\/]*)\.)?(?<prefix>[a-zA-Z0-9\/]*?)' .
 758:             '(?:\/)?(?<controller>[a-zA-Z0-9]*):{2}(?<action>[a-zA-Z0-9_]*)/i';
 759: 
 760:         if (preg_match($regex, $defaults, $matches)) {
 761:             foreach ($matches as $key => $value) {
 762:                 // Remove numeric keys and empty values.
 763:                 if (is_int($key) || $value === '' || $value === '::') {
 764:                     unset($matches[$key]);
 765:                 }
 766:             }
 767:             $length = count($matches);
 768: 
 769:             if (isset($matches['prefix'])) {
 770:                 $matches['prefix'] = strtolower($matches['prefix']);
 771:             }
 772: 
 773:             if ($length >= 2 || $length <= 4) {
 774:                 return $matches;
 775:             }
 776:         }
 777:         throw new RuntimeException("Could not parse `{$defaults}` route destination string.");
 778:     }
 779: 
 780:     /**
 781:      * Create a route object, or return the provided object.
 782:      *
 783:      * @param string|\Cake\Routing\Route\Route $route The route template or route object.
 784:      * @param array $defaults Default parameters.
 785:      * @param array $options Additional options parameters.
 786:      * @return \Cake\Routing\Route\Route
 787:      * @throws \InvalidArgumentException when route class or route object is invalid.
 788:      * @throws \BadMethodCallException when the route to make conflicts with the current scope
 789:      */
 790:     protected function _makeRoute($route, $defaults, $options)
 791:     {
 792:         if (is_string($route)) {
 793:             $routeClass = App::className($options['routeClass'], 'Routing/Route');
 794:             if ($routeClass === false) {
 795:                 throw new InvalidArgumentException(sprintf(
 796:                     'Cannot find route class %s',
 797:                     $options['routeClass']
 798:                 ));
 799:             }
 800: 
 801:             $route = str_replace('//', '/', $this->_path . $route);
 802:             if ($route !== '/') {
 803:                 $route = rtrim($route, '/');
 804:             }
 805: 
 806:             foreach ($this->_params as $param => $val) {
 807:                 if (isset($defaults[$param]) && $param !== 'prefix' && $defaults[$param] !== $val) {
 808:                     $msg = 'You cannot define routes that conflict with the scope. ' .
 809:                         'Scope had %s = %s, while route had %s = %s';
 810:                     throw new BadMethodCallException(sprintf(
 811:                         $msg,
 812:                         $param,
 813:                         $val,
 814:                         $param,
 815:                         $defaults[$param]
 816:                     ));
 817:                 }
 818:             }
 819:             $defaults += $this->_params + ['plugin' => null];
 820:             if (!isset($defaults['action']) && !isset($options['action'])) {
 821:                 $defaults['action'] = 'index';
 822:             }
 823: 
 824:             $route = new $routeClass($route, $defaults, $options);
 825:         }
 826: 
 827:         if ($route instanceof Route) {
 828:             return $route;
 829:         }
 830:         throw new InvalidArgumentException(
 831:             'Route class not found, or route class is not a subclass of Cake\Routing\Route\Route'
 832:         );
 833:     }
 834: 
 835:     /**
 836:      * Connects a new redirection Route in the router.
 837:      *
 838:      * Redirection routes are different from normal routes as they perform an actual
 839:      * header redirection if a match is found. The redirection can occur within your
 840:      * application or redirect to an outside location.
 841:      *
 842:      * Examples:
 843:      *
 844:      * ```
 845:      * $routes->redirect('/home/*', ['controller' => 'posts', 'action' => 'view']);
 846:      * ```
 847:      *
 848:      * Redirects /home/* to /posts/view and passes the parameters to /posts/view. Using an array as the
 849:      * redirect destination allows you to use other routes to define where a URL string should be redirected to.
 850:      *
 851:      * ```
 852:      * $routes->redirect('/posts/*', 'http://google.com', ['status' => 302]);
 853:      * ```
 854:      *
 855:      * Redirects /posts/* to http://google.com with a HTTP status of 302
 856:      *
 857:      * ### Options:
 858:      *
 859:      * - `status` Sets the HTTP status (default 301)
 860:      * - `persist` Passes the params to the redirected route, if it can. This is useful with greedy routes,
 861:      *   routes that end in `*` are greedy. As you can remap URLs and not lose any passed args.
 862:      *
 863:      * @param string $route A string describing the template of the route
 864:      * @param array|string $url A URL to redirect to. Can be a string or a Cake array-based URL
 865:      * @param array $options An array matching the named elements in the route to regular expressions which that
 866:      *   element should match. Also contains additional parameters such as which routed parameters should be
 867:      *   shifted into the passed arguments. As well as supplying patterns for routing parameters.
 868:      * @return \Cake\Routing\Route\Route|\Cake\Routing\Route\RedirectRoute
 869:      */
 870:     public function redirect($route, $url, array $options = [])
 871:     {
 872:         if (!isset($options['routeClass'])) {
 873:             $options['routeClass'] = 'Cake\Routing\Route\RedirectRoute';
 874:         }
 875:         if (is_string($url)) {
 876:             $url = ['redirect' => $url];
 877:         }
 878: 
 879:         return $this->connect($route, $url, $options);
 880:     }
 881: 
 882:     /**
 883:      * Add prefixed routes.
 884:      *
 885:      * This method creates a scoped route collection that includes
 886:      * relevant prefix information.
 887:      *
 888:      * The $name parameter is used to generate the routing parameter name.
 889:      * For example a path of `admin` would result in `'prefix' => 'admin'` being
 890:      * applied to all connected routes.
 891:      *
 892:      * You can re-open a prefix as many times as necessary, as well as nest prefixes.
 893:      * Nested prefixes will result in prefix values like `admin/api` which translates
 894:      * to the `Controller\Admin\Api\` namespace.
 895:      *
 896:      * If you need to have prefix with dots, eg: '/api/v1.0', use 'path' key
 897:      * for $params argument:
 898:      *
 899:      * ```
 900:      * $route->prefix('api', function($route) {
 901:      *     $route->prefix('v10', ['path' => '/v1.0'], function($route) {
 902:      *         // Translates to `Controller\Api\V10\` namespace
 903:      *     });
 904:      * });
 905:      * ```
 906:      *
 907:      * @param string $name The prefix name to use.
 908:      * @param array|callable $params An array of routing defaults to add to each connected route.
 909:      *   If you have no parameters, this argument can be a callable.
 910:      * @param callable|null $callback The callback to invoke that builds the prefixed routes.
 911:      * @return void
 912:      * @throws \InvalidArgumentException If a valid callback is not passed
 913:      */
 914:     public function prefix($name, $params = [], callable $callback = null)
 915:     {
 916:         if ($callback === null) {
 917:             if (!is_callable($params)) {
 918:                 throw new InvalidArgumentException('A valid callback is expected');
 919:             }
 920:             $callback = $params;
 921:             $params = [];
 922:         }
 923:         $name = Inflector::underscore($name);
 924:         $path = '/' . $name;
 925:         if (isset($params['path'])) {
 926:             $path = $params['path'];
 927:             unset($params['path']);
 928:         }
 929:         if (isset($this->_params['prefix'])) {
 930:             $name = $this->_params['prefix'] . '/' . $name;
 931:         }
 932:         $params = array_merge($params, ['prefix' => $name]);
 933:         $this->scope($path, $params, $callback);
 934:     }
 935: 
 936:     /**
 937:      * Add plugin routes.
 938:      *
 939:      * This method creates a new scoped route collection that includes
 940:      * relevant plugin information.
 941:      *
 942:      * The plugin name will be inflected to the underscore version to create
 943:      * the routing path. If you want a custom path name, use the `path` option.
 944:      *
 945:      * Routes connected in the scoped collection will have the correct path segment
 946:      * prepended, and have a matching plugin routing key set.
 947:      *
 948:      * @param string $name The plugin name to build routes for
 949:      * @param array|callable $options Either the options to use, or a callback
 950:      * @param callable|null $callback The callback to invoke that builds the plugin routes
 951:      *   Only required when $options is defined.
 952:      * @return void
 953:      */
 954:     public function plugin($name, $options = [], $callback = null)
 955:     {
 956:         if ($callback === null) {
 957:             $callback = $options;
 958:             $options = [];
 959:         }
 960:         $params = ['plugin' => $name] + $this->_params;
 961:         if (empty($options['path'])) {
 962:             $options['path'] = '/' . Inflector::underscore($name);
 963:         }
 964:         $this->scope($options['path'], $params, $callback);
 965:     }
 966: 
 967:     /**
 968:      * Create a new routing scope.
 969:      *
 970:      * Scopes created with this method will inherit the properties of the scope they are
 971:      * added to. This means that both the current path and parameters will be appended
 972:      * to the supplied parameters.
 973:      *
 974:      * @param string $path The path to create a scope for.
 975:      * @param array|callable $params Either the parameters to add to routes, or a callback.
 976:      * @param callable|null $callback The callback to invoke that builds the plugin routes.
 977:      *   Only required when $params is defined.
 978:      * @return void
 979:      * @throws \InvalidArgumentException when there is no callable parameter.
 980:      */
 981:     public function scope($path, $params, $callback = null)
 982:     {
 983:         if (is_callable($params)) {
 984:             $callback = $params;
 985:             $params = [];
 986:         }
 987:         if (!is_callable($callback)) {
 988:             $msg = 'Need a callable function/object to connect routes.';
 989:             throw new InvalidArgumentException($msg);
 990:         }
 991: 
 992:         if ($this->_path !== '/') {
 993:             $path = $this->_path . $path;
 994:         }
 995:         $namePrefix = $this->_namePrefix;
 996:         if (isset($params['_namePrefix'])) {
 997:             $namePrefix .= $params['_namePrefix'];
 998:         }
 999:         unset($params['_namePrefix']);
1000: 
1001:         $params += $this->_params;
1002:         $builder = new static($this->_collection, $path, $params, [
1003:             'routeClass' => $this->_routeClass,
1004:             'extensions' => $this->_extensions,
1005:             'namePrefix' => $namePrefix,
1006:             'middleware' => $this->middleware,
1007:         ]);
1008:         $callback($builder);
1009:     }
1010: 
1011:     /**
1012:      * Connect the `/:controller` and `/:controller/:action/*` fallback routes.
1013:      *
1014:      * This is a shortcut method for connecting fallback routes in a given scope.
1015:      *
1016:      * @param string|null $routeClass the route class to use, uses the default routeClass
1017:      *   if not specified
1018:      * @return void
1019:      */
1020:     public function fallbacks($routeClass = null)
1021:     {
1022:         $routeClass = $routeClass ?: $this->_routeClass;
1023:         $this->connect('/:controller', ['action' => 'index'], compact('routeClass'));
1024:         $this->connect('/:controller/:action/*', [], compact('routeClass'));
1025:     }
1026: 
1027:     /**
1028:      * Register a middleware with the RouteCollection.
1029:      *
1030:      * Once middleware has been registered, it can be applied to the current routing
1031:      * scope or any child scopes that share the same RouteCollection.
1032:      *
1033:      * @param string $name The name of the middleware. Used when applying middleware to a scope.
1034:      * @param callable|string $middleware The middleware callable or class name to register.
1035:      * @return $this
1036:      * @see \Cake\Routing\RouteCollection
1037:      */
1038:     public function registerMiddleware($name, $middleware)
1039:     {
1040:         $this->_collection->registerMiddleware($name, $middleware);
1041: 
1042:         return $this;
1043:     }
1044: 
1045:     /**
1046:      * Apply a middleware to the current route scope.
1047:      *
1048:      * Requires middleware to be registered via `registerMiddleware()`
1049:      *
1050:      * @param string ...$names The names of the middleware to apply to the current scope.
1051:      * @return $this
1052:      * @see \Cake\Routing\RouteCollection::addMiddlewareToScope()
1053:      */
1054:     public function applyMiddleware(...$names)
1055:     {
1056:         foreach ($names as $name) {
1057:             if (!$this->_collection->middlewareExists($name)) {
1058:                 $message = "Cannot apply '$name' middleware or middleware group. " .
1059:                     'Use registerMiddleware() to register middleware.';
1060:                 throw new RuntimeException($message);
1061:             }
1062:         }
1063:         $this->middleware = array_unique(array_merge($this->middleware, $names));
1064: 
1065:         return $this;
1066:     }
1067: 
1068:     /**
1069:      * Apply a set of middleware to a group
1070:      *
1071:      * @param string $name Name of the middleware group
1072:      * @param string[] $middlewareNames Names of the middleware
1073:      * @return $this
1074:      */
1075:     public function middlewareGroup($name, array $middlewareNames)
1076:     {
1077:         $this->_collection->middlewareGroup($name, $middlewareNames);
1078: 
1079:         return $this;
1080:     }
1081: }
1082: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs