public function constructUrl(array $params, Nette\Http\Url $refUrl)
{
if ($this->flags & self::ONE_WAY) {
return NULL;
}
$metadata = $this->metadata;
if (isset($metadata[NULL][self::FILTER_OUT])) {
$params = call_user_func($metadata[NULL][self::FILTER_OUT], $params);
if ($params === NULL) {
return NULL;
}
}
foreach ($metadata as $name => $meta) {
if (!isset($params[$name])) {
continue;
// retains NULL values
}
if (isset($meta['fixity'])) {
if ($params[$name] === FALSE) {
$params[$name] = '0';
} elseif (is_scalar($params[$name])) {
$params[$name] = (string) $params[$name];
}
if ($params[$name] === $meta[self::VALUE]) {
// remove default values; NULL values are retain
unset($params[$name]);
continue;
} elseif ($meta['fixity'] === self::CONSTANT) {
return NULL;
// missing or wrong parameter '$name'
}
}
if (is_scalar($params[$name]) && isset($meta['filterTable2'][$params[$name]])) {
$params[$name] = $meta['filterTable2'][$params[$name]];
} elseif (isset($meta['filterTable2']) && !empty($meta[self::FILTER_STRICT])) {
return NULL;
} elseif (isset($meta[self::FILTER_OUT])) {
$params[$name] = call_user_func($meta[self::FILTER_OUT], $params[$name]);
}
if (isset($meta[self::PATTERN]) && !preg_match($meta[self::PATTERN], rawurldecode($params[$name]))) {
return NULL;
// pattern not match
}
}
// compositing path
$sequence = $this->sequence;
$brackets = [];
$required = NULL;
// NULL for auto-optional
$url = '';
$i = count($sequence) - 1;
do {
$url = $sequence[$i] . $url;
if ($i === 0) {
break;
}
$i--;
$name = $sequence[$i];
$i--;
// parameter name
if ($name === ']') {
// opening optional part
$brackets[] = $url;
} elseif ($name[0] === '[') {
// closing optional part
$tmp = array_pop($brackets);
if ($required < count($brackets) + 1) {
// is this level optional?
if ($name !== '[!') {
// and not "required"-optional
$url = $tmp;
}
} else {
$required = count($brackets);
}
} elseif ($name[0] === '?') {
// "foo" parameter
continue;
} elseif (isset($params[$name]) && $params[$name] != '') {
// intentionally ==
$required = count($brackets);
// make this level required
$url = $params[$name] . $url;
unset($params[$name]);
} elseif (isset($metadata[$name]['fixity'])) {
// has default value?
if ($required === NULL && !$brackets) {
// auto-optional
$url = '';
} else {
$url = $metadata[$name]['defOut'] . $url;
}
} else {
return NULL;
// missing parameter '$name'
}
} while (TRUE);
if ($this->type === self::HOST) {
$host = $refUrl->getHost();
$parts = ip2long($host) ? [$host] : array_reverse(explode('.', $host));
$url = strtr($url, ['/%basePath%/' => $refUrl->getBasePath(), '%tld%' => $parts[0], '%domain%' => isset($parts[1]) ? "{$parts['1']}.{$parts['0']}" : $parts[0], '%sld%' => isset($parts[1]) ? $parts[1] : '', '%host%' => $host]);
$url = ($this->scheme ?: $refUrl->getScheme()) . ':' . $url;
} else {
if ($this->lastRefUrl !== $refUrl) {
$scheme = $this->scheme ?: $refUrl->getScheme();
$basePath = $this->type === self::RELATIVE ? $refUrl->getBasePath() : '';
$this->lastBaseUrl = $scheme . '://' . $refUrl->getAuthority() . $basePath;
$this->lastRefUrl = $refUrl;
}
$url = $this->lastBaseUrl . $url;
}
if (strpos($url, '//', 7) !== FALSE) {
return NULL;
}
// build query string
if ($this->xlat) {
$params = self::renameKeys($params, $this->xlat);
}
$sep = ini_get('arg_separator.input');
$query = http_build_query($params, '', $sep ? $sep[0] : '&');
if ($query != '') {
// intentionally ==
$url .= '?' . $query;
}
return $url;
}