infos)) throw new InvalidArgumentException('A URL with $name has already been registered.'); if($path === '') throw new InvalidArgumentException('$path may not be empty.'); if($path[0] !== '/') throw new InvalidArgumentException('$path must begin with /.'); $this->infos[$name] = new URLInfo($name, $path, $query, $fragment); } public function format(string $name, array $vars = [], bool $spacesAsPlus = false): string { if(!array_key_exists($name, $this->infos)) return ''; $urlInfo = $this->infos[$name]; $urlStr = self::replaceVariables($urlInfo->getPath(), $vars); if($urlInfo->hasQuery()) { $query = []; $queryParts = $urlInfo->getQuery(); foreach($queryParts as $name => $value) { $value = self::replaceVariables($value, $vars); if($value !== '' && !($name === 'page' && (int)$value <= 1)) $query[$name] = $value; } if(!empty($query)) $urlStr .= '?' . http_build_query($query, '', '&', $spacesAsPlus ? PHP_QUERY_RFC1738 : PHP_QUERY_RFC3986); } if($urlInfo->hasFragment()) { $fragment = self::replaceVariables($urlInfo->getFragment(), $vars); if($fragment !== '') $urlStr .= '#' . $fragment; } return $urlStr; } public static function replaceVariables(string $str, array $vars): string { // i: have no idea what i'm doing $out = ''; $varName = ''; $inVarName = false; $length = strlen($str); for($i = 0; $i < $length; ++$i) { $char = $str[$i]; if($inVarName) { if($char === '>') { $inVarName = false; if(array_key_exists($varName, $vars)) { $varValue = $vars[$varName]; if(is_array($varValue)) $varValue = empty($varValue) ? '' : implode(',', $varValue); elseif(is_int($varValue)) $varValue = $varValue < ($varName === 'page' ? 2 : 1) ? '' : (string)$varValue; else $varValue = (string)$varValue; } else $varValue = ''; $out .= $varValue; $varName = ''; continue; } if($char === '<') { $out .= '<' . $varName; $varName = ''; continue; } $varName .= $char; } else $inVarName = $char === '<'; if(!$inVarName) $out .= $char; } if($varName !== '') $out .= $varName; return $out; } }