241 lines
5.2 KiB
PHP
241 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Ulmus\Api\Common;
|
|
|
|
use Psr\Http\Message\UriInterface;
|
|
|
|
class Uri implements UriInterface
|
|
{
|
|
public const IGNORE_HTTP_PORT = [ 80, 443 ];
|
|
|
|
protected string $scheme;
|
|
|
|
protected null|string $user;
|
|
|
|
protected null|string $password;
|
|
|
|
protected string $host;
|
|
|
|
protected null|int $port;
|
|
|
|
protected null|string $path;
|
|
|
|
protected null|array $query;
|
|
|
|
protected null|string $fragment;
|
|
|
|
public function __construct(?string $uri = null)
|
|
{
|
|
$this->parse($uri);
|
|
}
|
|
|
|
public static function from(string|UriInterface $uri = "") : UriInterface
|
|
{
|
|
if ($uri instanceof UriInterface) {
|
|
return $uri;
|
|
}
|
|
|
|
return new static($uri);
|
|
}
|
|
|
|
protected function parse(string $uri): void
|
|
{
|
|
if (false === $parts = parse_url($uri)) {
|
|
throw new \InvalidArgumentException(sprintf("Malformed URIs was provided (%s)", $uri));
|
|
}
|
|
|
|
$this->setScheme($parts['scheme'] ?? "");
|
|
$this->setUserInfo($parts['user'] ?? null, $parts['pass'] ?? null);
|
|
$this->setHost($parts['host'] ?? "");
|
|
$this->setPort($parts['port'] ?? null);
|
|
$this->setPath($parts['path'] ?? null);
|
|
$this->setQuery($parts['query'] ?? []);
|
|
$this->setFragment($parts['fragment'] ?? null);
|
|
}
|
|
|
|
public function getScheme()
|
|
{
|
|
return $this->scheme;
|
|
}
|
|
|
|
public function renderScheme() : string
|
|
{
|
|
return $this->scheme ? "{$this->scheme}:" : "";
|
|
}
|
|
|
|
protected function setScheme(string $scheme) : self
|
|
{
|
|
$this->scheme = $scheme;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getAuthority() : string
|
|
{
|
|
return implode('', array_filter([
|
|
$this->getHost(), $this->renderUserInfo(), $this->renderPort(), $this->renderFragment()
|
|
]));
|
|
}
|
|
|
|
public function renderAuthority() : string
|
|
{
|
|
$authority = $this->getAuthority();
|
|
|
|
return $authority ? "//{$authority}" : $authority;
|
|
}
|
|
|
|
public function getUserInfo() : string
|
|
{
|
|
return $this->user . ( $this->password ? ":{$this->password}" : "" );
|
|
}
|
|
|
|
public function renderUserInfo() : string
|
|
{
|
|
return ( $info = $this->getUserInfo() ) ? "{$info}@" : "";
|
|
}
|
|
|
|
public function getHost()
|
|
{
|
|
return $this->host;
|
|
}
|
|
|
|
protected function setHost(string $host) : static
|
|
{
|
|
$this->host = $host;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getPort()
|
|
{
|
|
return $this->port;
|
|
}
|
|
|
|
public function renderPort(array $ignore = self::IGNORE_HTTP_PORT) : string
|
|
{
|
|
$port = $this->getPort();
|
|
|
|
return $port && ! in_array($port, $ignore) ? ":{$port}" : "";
|
|
}
|
|
|
|
public function getPath()
|
|
{
|
|
$path = implode('/', array_map('rawurlencode', explode('/', $this->path)));
|
|
|
|
return str_starts_with($this->path, '/') ? '/' . ltrim($this->path, '/.') : $this->path;
|
|
}
|
|
|
|
public function renderPath() : string
|
|
{
|
|
return $this->getPath();
|
|
}
|
|
|
|
public function getQuery()
|
|
{
|
|
return http_build_query($this->query, "", null, PHP_QUERY_RFC3986);
|
|
}
|
|
|
|
public function renderQuery() : string
|
|
{
|
|
$query = $this->getQuery();
|
|
|
|
return $query ? "?{$query}" : "";
|
|
}
|
|
|
|
public function getFragment()
|
|
{
|
|
return rawurlencode($this->fragment ? "#{$this->fragment}" : "");
|
|
}
|
|
|
|
public function renderFragment() : string
|
|
{
|
|
return $this->getFragment();
|
|
}
|
|
|
|
public function withScheme($scheme)
|
|
{
|
|
return (clone $this)->setScheme($scheme);
|
|
}
|
|
|
|
public function withUserInfo($user, $password = null)
|
|
{
|
|
return (clone $this)->setUserInfo($user, $password);
|
|
}
|
|
|
|
protected function setUserInfo(null|string $user, null|string $password) : static
|
|
{
|
|
$this->user = $user;
|
|
$this->password = $password;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function withHost($host)
|
|
{
|
|
return (clone $this)->setHost($host);
|
|
}
|
|
|
|
public function withPort($port)
|
|
{
|
|
return (clone $this)->setPort($port);
|
|
}
|
|
|
|
protected function setPort(null|int $port) : static
|
|
{
|
|
$this->port = $port;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function withPath($path)
|
|
{
|
|
return (clone $this)->setPath($path);
|
|
}
|
|
|
|
protected function setPath(null|string $path) : static
|
|
{
|
|
$this->path = $path;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function withQuery($query)
|
|
{
|
|
return $this->setQuery($query);
|
|
}
|
|
|
|
protected function setQuery(null|array|string $query) : static
|
|
{
|
|
if (is_string($query)) {
|
|
parse_str($query, $parsed);
|
|
}
|
|
|
|
$this->query = $parsed ?? $query;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function withFragment($fragment)
|
|
{
|
|
return (clone $this)->setFragment($fragment);
|
|
}
|
|
|
|
protected function setFragment(null|string $fragment) : static
|
|
{
|
|
$this->fragment = $fragment;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function __toString()
|
|
{
|
|
return $this->render();
|
|
}
|
|
|
|
public function render() : string
|
|
{
|
|
return implode('', array_filter([
|
|
$this->renderScheme(), $this->renderAuthority(), $this->renderPath(), $this->renderQuery(), $this->renderFragment()
|
|
]));
|
|
}
|
|
} |