/** * Attempt to match a url array. If the url matches the route parameters and settings, then * return a generated string url. If the url doesn't match the route parameters, false will be returned. * This method handles the reverse routing or conversion of url arrays into string urls. * * @param array $url An array of parameters to check matching with. * @return mixed Either a string url for the parameters if they match or false. * @access public */ function match($url) { if (!$this->compiled()) { $this->compile(); } $defaults = $this->defaults; if (isset($defaults['prefix'])) { $url['prefix'] = $defaults['prefix']; } //check that all the key names are in the url $keyNames = array_flip($this->keys); if (array_intersect_key($keyNames, $url) != $keyNames) { return false; } $diffUnfiltered = Set::diff($url, $defaults); $diff = array(); foreach ($diffUnfiltered as $key => $var) { if ($var === 0 || $var === '0' || !empty($var)) { $diff[$key] = $var; } } //if a not a greedy route, no extra params are allowed. if (!$this->_greedy && array_diff_key($diff, $keyNames) != array()) { return false; } //remove defaults that are also keys. They can cause match failures foreach ($this->keys as $key) { unset($defaults[$key]); } $filteredDefaults = array_filter($defaults); //if the difference between the url diff and defaults contains keys from defaults its not a match if (array_intersect_key($filteredDefaults, $diffUnfiltered) !== array()) { return false; } $passedArgsAndParams = array_diff_key($diff, $filteredDefaults, $keyNames); list($named, $params) = Router::getNamedElements($passedArgsAndParams, $url['controller'], $url['action']); //remove any pass params, they have numeric indexes, skip any params that are in the defaults $pass = array(); $i = 0; while (isset($url[$i])) { if (!isset($diff[$i])) { $i++; continue; } $pass[] = $url[$i]; unset($url[$i], $params[$i]); $i++; } //still some left over parameters that weren't named or passed args, bail. if (!empty($params)) { return false; } //check patterns for routed params if (!empty($this->options)) { foreach ($this->options as $key => $pattern) { if (array_key_exists($key, $url) && !preg_match('#^' . $pattern . '$#', $url[$key])) { return false; } } } return $this->_writeUrl(array_merge($url, compact('pass', 'named'))); }
/** * Maps a URL array onto a route and returns the string result, or false if no match * * @param array $route Route Route * @param array $url URL URL to map * @return mixed Result (as string) or false if no match * @access public * @static */ function mapRouteElements($route, $url) { if (isset($route[3]['prefix'])) { $prefix = $route[3]['prefix']; unset($route[3]['prefix']); } $pass = array(); $defaults = $route[3]; $routeParams = $route[2]; $params = Set::diff($url, $defaults); $urlInv = array_combine(array_values($url), array_keys($url)); $i = 0; while (isset($defaults[$i])) { if (isset($urlInv[$defaults[$i]])) { if (!in_array($defaults[$i], $url) && is_int($urlInv[$defaults[$i]])) { return false; } unset($urlInv[$defaults[$i]], $defaults[$i]); } else { return false; } $i++; } foreach ($params as $key => $value) { if (is_int($key)) { $pass[] = $value; unset($params[$key]); } } list($named, $params) = Router::getNamedElements($params); if (!strpos($route[0], '*') && (!empty($pass) || !empty($named))) { return false; } $urlKeys = array_keys($url); $paramsKeys = array_keys($params); $defaultsKeys = array_keys($defaults); if (!empty($params)) { if (array_diff($paramsKeys, $routeParams) != array()) { return false; } $required = array_values(array_diff($routeParams, $urlKeys)); $reqCount = count($required); for ($i = 0; $i < $reqCount; $i++) { if (array_key_exists($required[$i], $defaults) && $defaults[$required[$i]] === null) { unset($required[$i]); } } } $isFilled = true; if (!empty($routeParams)) { $filled = array_intersect_key($url, array_combine($routeParams, array_keys($routeParams))); $isFilled = array_diff($routeParams, array_keys($filled)) === array(); if (!$isFilled && empty($params)) { return false; } } if (empty($params)) { return Router::__mapRoute($route, array_merge($url, compact('pass', 'named', 'prefix'))); } elseif (!empty($routeParams) && !empty($route[3])) { if (!empty($required)) { return false; } foreach ($params as $key => $val) { if (!isset($url[$key]) || $url[$key] != $val || (!isset($defaults[$key]) || $defaults[$key] != $val) && !in_array($key, $routeParams)) { if (!isset($defaults[$key])) { continue; } return false; } } } else { if (empty($required) && $defaults['plugin'] === $url['plugin'] && $defaults['controller'] === $url['controller'] && $defaults['action'] === $url['action']) { return Router::__mapRoute($route, array_merge($url, compact('pass', 'named', 'prefix'))); } return false; } if (!empty($route[4])) { foreach ($route[4] as $key => $reg) { if (array_key_exists($key, $url) && !preg_match('#' . $reg . '#', $url[$key])) { return false; } } } return Router::__mapRoute($route, array_merge($filled, compact('pass', 'named', 'prefix'))); }