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.7 Red Velvet API

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