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

  • DashedRoute
  • EntityRoute
  • InflectedRoute
  • PluginShortRoute
  • RedirectRoute
  • Route
  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         1.3.0
 13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
 14:  */
 15: namespace Cake\Routing\Route;
 16: 
 17: use Cake\Http\ServerRequestFactory;
 18: use Cake\Routing\Router;
 19: use InvalidArgumentException;
 20: use Psr\Http\Message\ServerRequestInterface;
 21: 
 22: /**
 23:  * A single Route used by the Router to connect requests to
 24:  * parameter maps.
 25:  *
 26:  * Not normally created as a standalone. Use Router::connect() to create
 27:  * Routes for your application.
 28:  */
 29: class Route
 30: {
 31:     /**
 32:      * An array of named segments in a Route.
 33:      * `/:controller/:action/:id` has 3 key elements
 34:      *
 35:      * @var array
 36:      */
 37:     public $keys = [];
 38: 
 39:     /**
 40:      * An array of additional parameters for the Route.
 41:      *
 42:      * @var array
 43:      */
 44:     public $options = [];
 45: 
 46:     /**
 47:      * Default parameters for a Route
 48:      *
 49:      * @var array
 50:      */
 51:     public $defaults = [];
 52: 
 53:     /**
 54:      * The routes template string.
 55:      *
 56:      * @var string|null
 57:      */
 58:     public $template;
 59: 
 60:     /**
 61:      * Is this route a greedy route? Greedy routes have a `/*` in their
 62:      * template
 63:      *
 64:      * @var bool
 65:      */
 66:     protected $_greedy = false;
 67: 
 68:     /**
 69:      * The compiled route regular expression
 70:      *
 71:      * @var string|null
 72:      */
 73:     protected $_compiledRoute;
 74: 
 75:     /**
 76:      * The name for a route. Fetch with Route::getName();
 77:      *
 78:      * @var string|null
 79:      */
 80:     protected $_name;
 81: 
 82:     /**
 83:      * List of connected extensions for this route.
 84:      *
 85:      * @var string[]
 86:      */
 87:     protected $_extensions = [];
 88: 
 89:     /**
 90:      * List of middleware that should be applied.
 91:      *
 92:      * @var array
 93:      */
 94:     protected $middleware = [];
 95: 
 96:     /**
 97:      * Track whether or not brace keys `{var}` were used.
 98:      *
 99:      * @var bool
100:      */
101:     protected $braceKeys = false;
102: 
103:     /**
104:      * Valid HTTP methods.
105:      *
106:      * @var array
107:      */
108:     const VALID_METHODS = ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];
109: 
110:     /**
111:      * Constructor for a Route
112:      *
113:      * ### Options
114:      *
115:      * - `_ext` - Defines the extensions used for this route.
116:      * - `_middleware` - Define the middleware names for this route.
117:      * - `pass` - Copies the listed parameters into params['pass'].
118:      * - `_host` - Define the host name pattern if you want this route to only match
119:      *   specific host names. You can use `.*` and to create wildcard subdomains/hosts
120:      *   e.g. `*.example.com` matches all subdomains on `example.com`.
121:      *
122:      * @param string $template Template string with parameter placeholders
123:      * @param array|string $defaults Defaults for the route.
124:      * @param array $options Array of additional options for the Route
125:      */
126:     public function __construct($template, $defaults = [], array $options = [])
127:     {
128:         $this->template = $template;
129:         if (isset($defaults['[method]'])) {
130:             deprecationWarning('The `[method]` option is deprecated. Use `_method` instead.');
131:             $defaults['_method'] = $defaults['[method]'];
132:             unset($defaults['[method]']);
133:         }
134:         $this->defaults = (array)$defaults;
135:         $this->options = $options + ['_ext' => [], '_middleware' => []];
136:         $this->setExtensions((array)$this->options['_ext']);
137:         $this->setMiddleware((array)$this->options['_middleware']);
138:         unset($this->options['_middleware']);
139:     }
140: 
141:     /**
142:      * Get/Set the supported extensions for this route.
143:      *
144:      * @deprecated 3.3.9 Use getExtensions/setExtensions instead.
145:      * @param array|string|null $extensions The extensions to set. Use null to get.
146:      * @return array|null The extensions or null.
147:      */
148:     public function extensions($extensions = null)
149:     {
150:         deprecationWarning(
151:             'Route::extensions() is deprecated. ' .
152:             'Use Route::setExtensions()/getExtensions() instead.'
153:         );
154:         if ($extensions === null) {
155:             return $this->_extensions;
156:         }
157:         $this->_extensions = (array)$extensions;
158:     }
159: 
160:     /**
161:      * Set the supported extensions for this route.
162:      *
163:      * @param string[] $extensions The extensions to set.
164:      * @return $this
165:      */
166:     public function setExtensions(array $extensions)
167:     {
168:         $this->_extensions = [];
169:         foreach ($extensions as $ext) {
170:             $this->_extensions[] = strtolower($ext);
171:         }
172: 
173:         return $this;
174:     }
175: 
176:     /**
177:      * Get the supported extensions for this route.
178:      *
179:      * @return string[]
180:      */
181:     public function getExtensions()
182:     {
183:         return $this->_extensions;
184:     }
185: 
186:     /**
187:      * Set the accepted HTTP methods for this route.
188:      *
189:      * @param string[] $methods The HTTP methods to accept.
190:      * @return $this
191:      * @throws \InvalidArgumentException
192:      */
193:     public function setMethods(array $methods)
194:     {
195:         $methods = array_map('strtoupper', $methods);
196:         $diff = array_diff($methods, static::VALID_METHODS);
197:         if ($diff !== []) {
198:             throw new InvalidArgumentException(
199:                 sprintf('Invalid HTTP method received. %s is invalid.', implode(', ', $diff))
200:             );
201:         }
202:         $this->defaults['_method'] = $methods;
203: 
204:         return $this;
205:     }
206: 
207:     /**
208:      * Set regexp patterns for routing parameters
209:      *
210:      * If any of your patterns contain multibyte values, the `multibytePattern`
211:      * mode will be enabled.
212:      *
213:      * @param string[] $patterns The patterns to apply to routing elements
214:      * @return $this
215:      */
216:     public function setPatterns(array $patterns)
217:     {
218:         $patternValues = implode('', $patterns);
219:         if (mb_strlen($patternValues) < strlen($patternValues)) {
220:             $this->options['multibytePattern'] = true;
221:         }
222:         $this->options = array_merge($this->options, $patterns);
223: 
224:         return $this;
225:     }
226: 
227:     /**
228:      * Set host requirement
229:      *
230:      * @param string $host The host name this route is bound to
231:      * @return $this
232:      */
233:     public function setHost($host)
234:     {
235:         $this->options['_host'] = $host;
236: 
237:         return $this;
238:     }
239: 
240:     /**
241:      * Set the names of parameters that will be converted into passed parameters
242:      *
243:      * @param string[] $names The names of the parameters that should be passed.
244:      * @return $this
245:      */
246:     public function setPass(array $names)
247:     {
248:         $this->options['pass'] = $names;
249: 
250:         return $this;
251:     }
252: 
253:     /**
254:      * Set the names of parameters that will persisted automatically
255:      *
256:      * Persistent parameters allow you to define which route parameters should be automatically
257:      * included when generating new URLs. You can override persistent parameters
258:      * by redefining them in a URL or remove them by setting the persistent parameter to `false`.
259:      *
260:      * ```
261:      * // remove a persistent 'date' parameter
262:      * Router::url(['date' => false', ...]);
263:      * ```
264:      *
265:      * @param array $names The names of the parameters that should be passed.
266:      * @return $this
267:      */
268:     public function setPersist(array $names)
269:     {
270:         $this->options['persist'] = $names;
271: 
272:         return $this;
273:     }
274: 
275:     /**
276:      * Check if a Route has been compiled into a regular expression.
277:      *
278:      * @return bool
279:      */
280:     public function compiled()
281:     {
282:         return $this->_compiledRoute !== null;
283:     }
284: 
285:     /**
286:      * Compiles the route's regular expression.
287:      *
288:      * Modifies defaults property so all necessary keys are set
289:      * and populates $this->names with the named routing elements.
290:      *
291:      * @return string Returns a string regular expression of the compiled route.
292:      */
293:     public function compile()
294:     {
295:         if ($this->_compiledRoute) {
296:             return $this->_compiledRoute;
297:         }
298:         $this->_writeRoute();
299: 
300:         return $this->_compiledRoute;
301:     }
302: 
303:     /**
304:      * Builds a route regular expression.
305:      *
306:      * Uses the template, defaults and options properties to compile a
307:      * regular expression that can be used to parse request strings.
308:      *
309:      * @return void
310:      */
311:     protected function _writeRoute()
312:     {
313:         if (empty($this->template) || ($this->template === '/')) {
314:             $this->_compiledRoute = '#^/*$#';
315:             $this->keys = [];
316: 
317:             return;
318:         }
319:         $route = $this->template;
320:         $names = $routeParams = [];
321:         $parsed = preg_quote($this->template, '#');
322: 
323:         if (strpos($route, '{') !== false && strpos($route, '}') !== false) {
324:             preg_match_all('/\{([a-z][a-z0-9-_]*)\}/i', $route, $namedElements);
325:             $this->braceKeys = true;
326:         } else {
327:             preg_match_all('/:([a-z0-9-_]+(?<![-_]))/i', $route, $namedElements);
328:             $this->braceKeys = false;
329:         }
330:         foreach ($namedElements[1] as $i => $name) {
331:             $search = preg_quote($namedElements[0][$i]);
332:             if (isset($this->options[$name])) {
333:                 $option = null;
334:                 if ($name !== 'plugin' && array_key_exists($name, $this->defaults)) {
335:                     $option = '?';
336:                 }
337:                 $slashParam = '/' . $search;
338:                 if (strpos($parsed, $slashParam) !== false) {
339:                     $routeParams[$slashParam] = '(?:/(?P<' . $name . '>' . $this->options[$name] . ')' . $option . ')' . $option;
340:                 } else {
341:                     $routeParams[$search] = '(?:(?P<' . $name . '>' . $this->options[$name] . ')' . $option . ')' . $option;
342:                 }
343:             } else {
344:                 $routeParams[$search] = '(?:(?P<' . $name . '>[^/]+))';
345:             }
346:             $names[] = $name;
347:         }
348:         if (preg_match('#\/\*\*$#', $route)) {
349:             $parsed = preg_replace('#/\\\\\*\\\\\*$#', '(?:/(?P<_trailing_>.*))?', $parsed);
350:             $this->_greedy = true;
351:         }
352:         if (preg_match('#\/\*$#', $route)) {
353:             $parsed = preg_replace('#/\\\\\*$#', '(?:/(?P<_args_>.*))?', $parsed);
354:             $this->_greedy = true;
355:         }
356:         $mode = '';
357:         if (!empty($this->options['multibytePattern'])) {
358:             $mode = 'u';
359:         }
360:         krsort($routeParams);
361:         $parsed = str_replace(array_keys($routeParams), $routeParams, $parsed);
362:         $this->_compiledRoute = '#^' . $parsed . '[/]*$#' . $mode;
363:         $this->keys = $names;
364: 
365:         // Remove defaults that are also keys. They can cause match failures
366:         foreach ($this->keys as $key) {
367:             unset($this->defaults[$key]);
368:         }
369: 
370:         $keys = $this->keys;
371:         sort($keys);
372:         $this->keys = array_reverse($keys);
373:     }
374: 
375:     /**
376:      * Get the standardized plugin.controller:action name for a route.
377:      *
378:      * @return string
379:      */
380:     public function getName()
381:     {
382:         if (!empty($this->_name)) {
383:             return $this->_name;
384:         }
385:         $name = '';
386:         $keys = [
387:             'prefix' => ':',
388:             'plugin' => '.',
389:             'controller' => ':',
390:             'action' => ''
391:         ];
392:         foreach ($keys as $key => $glue) {
393:             $value = null;
394:             if (strpos($this->template, ':' . $key) !== false) {
395:                 $value = '_' . $key;
396:             } elseif (isset($this->defaults[$key])) {
397:                 $value = $this->defaults[$key];
398:             }
399: 
400:             if ($value === null) {
401:                 continue;
402:             }
403:             if ($value === true || $value === false) {
404:                 $value = $value ? '1' : '0';
405:             }
406:             $name .= $value . $glue;
407:         }
408: 
409:         return $this->_name = strtolower($name);
410:     }
411: 
412:     /**
413:      * Checks to see if the given URL can be parsed by this route.
414:      *
415:      * If the route can be parsed an array of parameters will be returned; if not
416:      * false will be returned.
417:      *
418:      * @param \Psr\Http\Message\ServerRequestInterface $request The URL to attempt to parse.
419:      * @return array|false An array of request parameters, or false on failure.
420:      */
421:     public function parseRequest(ServerRequestInterface $request)
422:     {
423:         $uri = $request->getUri();
424:         if (isset($this->options['_host']) && !$this->hostMatches($uri->getHost())) {
425:             return false;
426:         }
427: 
428:         return $this->parse($uri->getPath(), $request->getMethod());
429:     }
430: 
431:     /**
432:      * Checks to see if the given URL can be parsed by this route.
433:      *
434:      * If the route can be parsed an array of parameters will be returned; if not
435:      * false will be returned. String URLs are parsed if they match a routes regular expression.
436:      *
437:      * @param string $url The URL to attempt to parse.
438:      * @param string $method The HTTP method of the request being parsed.
439:      * @return array|false An array of request parameters, or false on failure.
440:      * @deprecated 3.4.0 Use/implement parseRequest() instead as it provides more flexibility/control.
441:      */
442:     public function parse($url, $method = '')
443:     {
444:         if (empty($this->_compiledRoute)) {
445:             $this->compile();
446:         }
447:         list($url, $ext) = $this->_parseExtension($url);
448: 
449:         if (!preg_match($this->_compiledRoute, urldecode($url), $route)) {
450:             return false;
451:         }
452: 
453:         if (isset($this->defaults['_method'])) {
454:             if (empty($method)) {
455:                 deprecationWarning(
456:                     'Extracting the request method from global state when parsing routes is deprecated. ' .
457:                     'Instead adopt Route::parseRequest() which extracts the method from the passed request.'
458:                 );
459:                 // Deprecated reading the global state is deprecated and will be removed in 4.x
460:                 $request = Router::getRequest(true) ?: ServerRequestFactory::fromGlobals();
461:                 $method = $request->getMethod();
462:             }
463:             if (!in_array($method, (array)$this->defaults['_method'], true)) {
464:                 return false;
465:             }
466:         }
467: 
468:         array_shift($route);
469:         $count = count($this->keys);
470:         for ($i = 0; $i <= $count; $i++) {
471:             unset($route[$i]);
472:         }
473:         $route['pass'] = [];
474: 
475:         // Assign defaults, set passed args to pass
476:         foreach ($this->defaults as $key => $value) {
477:             if (isset($route[$key])) {
478:                 continue;
479:             }
480:             if (is_int($key)) {
481:                 $route['pass'][] = $value;
482:                 continue;
483:             }
484:             $route[$key] = $value;
485:         }
486: 
487:         if (isset($route['_args_'])) {
488:             $pass = $this->_parseArgs($route['_args_'], $route);
489:             $route['pass'] = array_merge($route['pass'], $pass);
490:             unset($route['_args_']);
491:         }
492: 
493:         if (isset($route['_trailing_'])) {
494:             $route['pass'][] = $route['_trailing_'];
495:             unset($route['_trailing_']);
496:         }
497: 
498:         if (!empty($ext)) {
499:             $route['_ext'] = $ext;
500:         }
501: 
502:         // pass the name if set
503:         if (isset($this->options['_name'])) {
504:             $route['_name'] = $this->options['_name'];
505:         }
506: 
507:         // restructure 'pass' key route params
508:         if (isset($this->options['pass'])) {
509:             $j = count($this->options['pass']);
510:             while ($j--) {
511:                 if (isset($route[$this->options['pass'][$j]])) {
512:                     array_unshift($route['pass'], $route[$this->options['pass'][$j]]);
513:                 }
514:             }
515:         }
516:         $route['_matchedRoute'] = $this->template;
517:         if (count($this->middleware) > 0) {
518:             $route['_middleware'] = $this->middleware;
519:         }
520: 
521:         return $route;
522:     }
523: 
524:     /**
525:      * Check to see if the host matches the route requirements
526:      *
527:      * @param string $host The request's host name
528:      * @return bool Whether or not the host matches any conditions set in for this route.
529:      */
530:     public function hostMatches($host)
531:     {
532:         $pattern = '@^' . str_replace('\*', '.*', preg_quote($this->options['_host'], '@')) . '$@';
533: 
534:         return preg_match($pattern, $host) !== 0;
535:     }
536: 
537:     /**
538:      * Removes the extension from $url if it contains a registered extension.
539:      * If no registered extension is found, no extension is returned and the URL is returned unmodified.
540:      *
541:      * @param string $url The url to parse.
542:      * @return array containing url, extension
543:      */
544:     protected function _parseExtension($url)
545:     {
546:         if (count($this->_extensions) && strpos($url, '.') !== false) {
547:             foreach ($this->_extensions as $ext) {
548:                 $len = strlen($ext) + 1;
549:                 if (substr($url, -$len) === '.' . $ext) {
550:                     return [substr($url, 0, $len * -1), $ext];
551:                 }
552:             }
553:         }
554: 
555:         return [$url, null];
556:     }
557: 
558:     /**
559:      * Parse passed parameters into a list of passed args.
560:      *
561:      * Return true if a given named $param's $val matches a given $rule depending on $context.
562:      * Currently implemented rule types are controller, action and match that can be combined with each other.
563:      *
564:      * @param string $args A string with the passed params. eg. /1/foo
565:      * @param string $context The current route context, which should contain controller/action keys.
566:      * @return array Array of passed args.
567:      */
568:     protected function _parseArgs($args, $context)
569:     {
570:         $pass = [];
571:         $args = explode('/', $args);
572: 
573:         foreach ($args as $param) {
574:             if (empty($param) && $param !== '0' && $param !== 0) {
575:                 continue;
576:             }
577:             $pass[] = rawurldecode($param);
578:         }
579: 
580:         return $pass;
581:     }
582: 
583:     /**
584:      * Apply persistent parameters to a URL array. Persistent parameters are a
585:      * special key used during route creation to force route parameters to
586:      * persist when omitted from a URL array.
587:      *
588:      * @param array $url The array to apply persistent parameters to.
589:      * @param array $params An array of persistent values to replace persistent ones.
590:      * @return array An array with persistent parameters applied.
591:      */
592:     protected function _persistParams(array $url, array $params)
593:     {
594:         foreach ($this->options['persist'] as $persistKey) {
595:             if (array_key_exists($persistKey, $params) && !isset($url[$persistKey])) {
596:                 $url[$persistKey] = $params[$persistKey];
597:             }
598:         }
599: 
600:         return $url;
601:     }
602: 
603:     /**
604:      * Check if a URL array matches this route instance.
605:      *
606:      * If the URL matches the route parameters and settings, then
607:      * return a generated string URL. If the URL doesn't match the route parameters, false will be returned.
608:      * This method handles the reverse routing or conversion of URL arrays into string URLs.
609:      *
610:      * @param array $url An array of parameters to check matching with.
611:      * @param array $context An array of the current request context.
612:      *   Contains information such as the current host, scheme, port, base
613:      *   directory and other url params.
614:      * @return string|false Either a string URL for the parameters if they match or false.
615:      */
616:     public function match(array $url, array $context = [])
617:     {
618:         if (empty($this->_compiledRoute)) {
619:             $this->compile();
620:         }
621:         $defaults = $this->defaults;
622:         $context += ['params' => [], '_port' => null, '_scheme' => null, '_host' => null];
623: 
624:         if (!empty($this->options['persist']) &&
625:             is_array($this->options['persist'])
626:         ) {
627:             $url = $this->_persistParams($url, $context['params']);
628:         }
629:         unset($context['params']);
630:         $hostOptions = array_intersect_key($url, $context);
631: 
632:         // Apply the _host option if possible
633:         if (isset($this->options['_host'])) {
634:             if (!isset($hostOptions['_host']) && strpos($this->options['_host'], '*') === false) {
635:                 $hostOptions['_host'] = $this->options['_host'];
636:             }
637:             if (!isset($hostOptions['_host'])) {
638:                 $hostOptions['_host'] = $context['_host'];
639:             }
640: 
641:             // The host did not match the route preferences
642:             if (!$this->hostMatches($hostOptions['_host'])) {
643:                 return false;
644:             }
645:         }
646: 
647:         // Check for properties that will cause an
648:         // absolute url. Copy the other properties over.
649:         if (isset($hostOptions['_scheme']) ||
650:             isset($hostOptions['_port']) ||
651:             isset($hostOptions['_host'])
652:         ) {
653:             $hostOptions += $context;
654: 
655:             if (getservbyname($hostOptions['_scheme'], 'tcp') === $hostOptions['_port']) {
656:                 unset($hostOptions['_port']);
657:             }
658:         }
659: 
660:         // If no base is set, copy one in.
661:         if (!isset($hostOptions['_base']) && isset($context['_base'])) {
662:             $hostOptions['_base'] = $context['_base'];
663:         }
664: 
665:         $query = !empty($url['?']) ? (array)$url['?'] : [];
666:         unset($url['_host'], $url['_scheme'], $url['_port'], $url['_base'], $url['?']);
667: 
668:         // Move extension into the hostOptions so its not part of
669:         // reverse matches.
670:         if (isset($url['_ext'])) {
671:             $hostOptions['_ext'] = $url['_ext'];
672:             unset($url['_ext']);
673:         }
674: 
675:         // Check the method first as it is special.
676:         if (!$this->_matchMethod($url)) {
677:             return false;
678:         }
679:         unset($url['_method'], $url['[method]'], $defaults['_method']);
680: 
681:         // Missing defaults is a fail.
682:         if (array_diff_key($defaults, $url) !== []) {
683:             return false;
684:         }
685: 
686:         // Defaults with different values are a fail.
687:         if (array_intersect_key($url, $defaults) != $defaults) {
688:             return false;
689:         }
690: 
691:         // If this route uses pass option, and the passed elements are
692:         // not set, rekey elements.
693:         if (isset($this->options['pass'])) {
694:             foreach ($this->options['pass'] as $i => $name) {
695:                 if (isset($url[$i]) && !isset($url[$name])) {
696:                     $url[$name] = $url[$i];
697:                     unset($url[$i]);
698:                 }
699:             }
700:         }
701: 
702:         // check that all the key names are in the url
703:         $keyNames = array_flip($this->keys);
704:         if (array_intersect_key($keyNames, $url) !== $keyNames) {
705:             return false;
706:         }
707: 
708:         $pass = [];
709:         foreach ($url as $key => $value) {
710:             // keys that exist in the defaults and have different values is a match failure.
711:             $defaultExists = array_key_exists($key, $defaults);
712: 
713:             // If the key is a routed key, it's not different yet.
714:             if (array_key_exists($key, $keyNames)) {
715:                 continue;
716:             }
717: 
718:             // pull out passed args
719:             $numeric = is_numeric($key);
720:             if ($numeric && isset($defaults[$key]) && $defaults[$key] == $value) {
721:                 continue;
722:             }
723:             if ($numeric) {
724:                 $pass[] = $value;
725:                 unset($url[$key]);
726:                 continue;
727:             }
728: 
729:             // keys that don't exist are different.
730:             if (!$defaultExists && ($value !== null && $value !== false && $value !== '')) {
731:                 $query[$key] = $value;
732:                 unset($url[$key]);
733:             }
734:         }
735: 
736:         // if not a greedy route, no extra params are allowed.
737:         if (!$this->_greedy && !empty($pass)) {
738:             return false;
739:         }
740: 
741:         // check patterns for routed params
742:         if (!empty($this->options)) {
743:             foreach ($this->options as $key => $pattern) {
744:                 if (isset($url[$key]) && !preg_match('#^' . $pattern . '$#u', $url[$key])) {
745:                     return false;
746:                 }
747:             }
748:         }
749:         $url += $hostOptions;
750: 
751:         return $this->_writeUrl($url, $pass, $query);
752:     }
753: 
754:     /**
755:      * Check whether or not the URL's HTTP method matches.
756:      *
757:      * @param array $url The array for the URL being generated.
758:      * @return bool
759:      */
760:     protected function _matchMethod($url)
761:     {
762:         if (empty($this->defaults['_method'])) {
763:             return true;
764:         }
765:         // @deprecated The `[method]` support should be removed in 4.0.0
766:         if (isset($url['[method]'])) {
767:             deprecationWarning('The `[method]` key is deprecated. Use `_method` instead.');
768:             $url['_method'] = $url['[method]'];
769:         }
770:         if (empty($url['_method'])) {
771:             $url['_method'] = 'GET';
772:         }
773:         $methods = array_map('strtoupper', (array)$url['_method']);
774:         foreach ($methods as $value) {
775:             if (in_array($value, (array)$this->defaults['_method'])) {
776:                 return true;
777:             }
778:         }
779: 
780:         return false;
781:     }
782: 
783:     /**
784:      * Converts a matching route array into a URL string.
785:      *
786:      * Composes the string URL using the template
787:      * used to create the route.
788:      *
789:      * @param array $params The params to convert to a string url
790:      * @param array $pass The additional passed arguments
791:      * @param array $query An array of parameters
792:      * @return string Composed route string.
793:      */
794:     protected function _writeUrl($params, $pass = [], $query = [])
795:     {
796:         $pass = implode('/', array_map('rawurlencode', $pass));
797:         $out = $this->template;
798: 
799:         $search = $replace = [];
800:         foreach ($this->keys as $key) {
801:             $string = null;
802:             if (isset($params[$key])) {
803:                 $string = $params[$key];
804:             } elseif (strpos($out, $key) != strlen($out) - strlen($key)) {
805:                 $key .= '/';
806:             }
807:             if ($this->braceKeys) {
808:                 $search[] = "{{$key}}";
809:             } else {
810:                 $search[] = ':' . $key;
811:             }
812:             $replace[] = $string;
813:         }
814: 
815:         if (strpos($this->template, '**') !== false) {
816:             array_push($search, '**', '%2F');
817:             array_push($replace, $pass, '/');
818:         } elseif (strpos($this->template, '*') !== false) {
819:             $search[] = '*';
820:             $replace[] = $pass;
821:         }
822:         $out = str_replace($search, $replace, $out);
823: 
824:         // add base url if applicable.
825:         if (isset($params['_base'])) {
826:             $out = $params['_base'] . $out;
827:             unset($params['_base']);
828:         }
829: 
830:         $out = str_replace('//', '/', $out);
831:         if (isset($params['_scheme']) ||
832:             isset($params['_host']) ||
833:             isset($params['_port'])
834:         ) {
835:             $host = $params['_host'];
836: 
837:             // append the port & scheme if they exists.
838:             if (isset($params['_port'])) {
839:                 $host .= ':' . $params['_port'];
840:             }
841:             $scheme = isset($params['_scheme']) ? $params['_scheme'] : 'http';
842:             $out = "{$scheme}://{$host}{$out}";
843:         }
844:         if (!empty($params['_ext']) || !empty($query)) {
845:             $out = rtrim($out, '/');
846:         }
847:         if (!empty($params['_ext'])) {
848:             $out .= '.' . $params['_ext'];
849:         }
850:         if (!empty($query)) {
851:             $out .= rtrim('?' . http_build_query($query), '?');
852:         }
853: 
854:         return $out;
855:     }
856: 
857:     /**
858:      * Get the static path portion for this route.
859:      *
860:      * @return string
861:      */
862:     public function staticPath()
863:     {
864:         $routeKey = strpos($this->template, ':');
865:         if ($routeKey !== false) {
866:             return substr($this->template, 0, $routeKey);
867:         }
868:         $routeKey = strpos($this->template, '{');
869:         if ($routeKey !== false && strpos($this->template, '}') !== false) {
870:             return substr($this->template, 0, $routeKey);
871:         }
872:         $star = strpos($this->template, '*');
873:         if ($star !== false) {
874:             $path = rtrim(substr($this->template, 0, $star), '/');
875: 
876:             return $path === '' ? '/' : $path;
877:         }
878: 
879:         return $this->template;
880:     }
881: 
882:     /**
883:      * Set the names of the middleware that should be applied to this route.
884:      *
885:      * @param array $middleware The list of middleware names to apply to this route.
886:      *   Middleware names will not be checked until the route is matched.
887:      * @return $this
888:      */
889:     public function setMiddleware(array $middleware)
890:     {
891:         $this->middleware = $middleware;
892: 
893:         return $this;
894:     }
895: 
896:     /**
897:      * Get the names of the middleware that should be applied to this route.
898:      *
899:      * @return array
900:      */
901:     public function getMiddleware()
902:     {
903:         return $this->middleware;
904:     }
905: 
906:     /**
907:      * Set state magic method to support var_export
908:      *
909:      * This method helps for applications that want to implement
910:      * router caching.
911:      *
912:      * @param array $fields Key/Value of object attributes
913:      * @return \Cake\Routing\Route\Route A new instance of the route
914:      */
915:     public static function __set_state($fields)
916:     {
917:         $class = get_called_class();
918:         $obj = new $class('');
919:         foreach ($fields as $field => $value) {
920:             $obj->$field = $value;
921:         }
922: 
923:         return $obj;
924:     }
925: }
926: 
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