ulmus-api/src/Common/Uri.php
2026-07-14 15:53:21 +00:00

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()
]));
}
}