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

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