public function match(array $url, array $context = [])
{
if (empty($this->_compiledRoute)) {
$this->compile();
}
$defaults = $this->defaults;
$context += ['params' => []];
if (!empty($this->options['persist']) && is_array($this->options['persist'])) {
$url = $this->_persistParams($url, $context['params']);
}
unset($context['params']);
$hostOptions = array_intersect_key($url, $context);
// Check for properties that will cause an
// absolute url. Copy the other properties over.
if (isset($hostOptions['_scheme']) || isset($hostOptions['_port']) || isset($hostOptions['_host'])) {
$hostOptions += $context;
if ($hostOptions['_port'] == $context['_port']) {
unset($hostOptions['_port']);
}
}
// If no base is set, copy one in.
if (!isset($hostOptions['_base']) && isset($context['_base'])) {
$hostOptions['_base'] = $context['_base'];
}
$query = !empty($url['?']) ? (array) $url['?'] : [];
unset($url['_host'], $url['_scheme'], $url['_port'], $url['_base'], $url['?']);
// Move extension into the hostOptions so its not part of
// reverse matches.
if (isset($url['_ext'])) {
$hostOptions['_ext'] = $url['_ext'];
unset($url['_ext']);
}
// Check the method first as it is special.
if (!$this->_matchMethod($url)) {
return false;
}
unset($url['_method'], $url['[method]'], $defaults['_method']);
// Missing defaults is a fail.
if (array_diff_key($defaults, $url) !== []) {
return false;
}
// Defaults with different values are a fail.
if (array_intersect_key($url, $defaults) != $defaults) {
return false;
}
// If this route uses pass option, and the passed elements are
// not set, rekey elements.
if (isset($this->options['pass'])) {
foreach ($this->options['pass'] as $i => $name) {
if (isset($url[$i]) && !isset($url[$name])) {
$url[$name] = $url[$i];
unset($url[$i]);
}
}
}
// check that all the key names are in the url
$keyNames = array_flip($this->keys);
if (array_intersect_key($keyNames, $url) !== $keyNames) {
return false;
}
$pass = [];
foreach ($url as $key => $value) {
// keys that exist in the defaults and have different values is a match failure.
$defaultExists = array_key_exists($key, $defaults);
// If the key is a routed key, it's not different yet.
if (array_key_exists($key, $keyNames)) {
continue;
}
// pull out passed args
$numeric = is_numeric($key);
if ($numeric && isset($defaults[$key]) && $defaults[$key] == $value) {
continue;
}
if ($numeric) {
$pass[] = $value;
unset($url[$key]);
continue;
}
// keys that don't exist are different.
if (!$defaultExists && ($value !== null && $value !== false && $value !== '')) {
$query[$key] = $value;
unset($url[$key]);
}
}
// if not a greedy route, no extra params are allowed.
if (!$this->_greedy && !empty($pass)) {
return false;
}
// check patterns for routed params
if (!empty($this->options)) {
foreach ($this->options as $key => $pattern) {
if (isset($url[$key]) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
return false;
}
}
}
$url += $hostOptions;
return $this->_writeUrl($url, $pass, $query);
}