From 564245fd931ba912811c387a650dabe246d60fb4 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Mon, 30 Dec 2024 18:53:14 +0100 Subject: [PATCH] Simplify codebase --- components/Modifier.php | 9 +- uri/BaseUri.php | 276 +++++++++++++++++----------------------- uri/BaseUriTest.php | 67 +++++----- 3 files changed, 149 insertions(+), 203 deletions(-) diff --git a/components/Modifier.php b/components/Modifier.php index 1cc75091..3578fd8c 100644 --- a/components/Modifier.php +++ b/components/Modifier.php @@ -18,7 +18,6 @@ use JsonSerializable; use League\Uri\Components\DataPath; use League\Uri\Components\Domain; -use League\Uri\Components\Fragment; use League\Uri\Components\HierarchicalPath; use League\Uri\Components\Host; use League\Uri\Components\Path; @@ -28,7 +27,7 @@ use League\Uri\Contracts\UriAccess; use League\Uri\Contracts\UriInterface; use League\Uri\Exceptions\SyntaxError; -use League\Uri\Idna\Converter as IdnConverter; +use League\Uri\Idna\Converter as IdnaConverter; use League\Uri\IPv4\Converter as IPv4Converter; use League\Uri\IPv6\Converter as IPv6Converter; use League\Uri\KeyValuePair\Converter as KeyValuePairConverter; @@ -406,7 +405,7 @@ public function appendLabel(Stringable|string|null $label): static public function hostToAscii(): static { $currentHost = $this->uri->getHost(); - $host = IdnConverter::toAsciiOrFail((string) $currentHost); + $host = IdnaConverter::toAsciiOrFail((string) $currentHost); return match (true) { null === $currentHost, @@ -422,7 +421,7 @@ public function hostToAscii(): static public function hostToUnicode(): static { $currentHost = $this->uri->getHost(); - $host = IdnConverter::toUnicode((string) $currentHost)->domain(); + $host = IdnaConverter::toUnicode((string) $currentHost)->domain(); return match (true) { null === $currentHost, @@ -845,7 +844,7 @@ public function getIdnUriString(): string return $this->getUriString(); } - $host = IdnConverter::toUnicode($currentHost)->domain(); + $host = IdnaConverter::toUnicode($currentHost)->domain(); if ($host === $currentHost) { return $this->getUriString(); } diff --git a/uri/BaseUri.php b/uri/BaseUri.php index 6f622a36..c24240da 100644 --- a/uri/BaseUri.php +++ b/uri/BaseUri.php @@ -13,6 +13,7 @@ namespace League\Uri; +use Deprecated; use JsonSerializable; use League\Uri\Contracts\Conditionable; use League\Uri\Contracts\UriAccess; @@ -202,7 +203,7 @@ public function isLocalFile(): bool * Tells whether the URI is opaque or not. * * A URI is opaque if and only if it is absolute - * and does not has an authority path. + * and does not have an authority path. */ public function isOpaque(): bool { @@ -271,7 +272,10 @@ public function isRelativePath(): bool */ public function isSameDocument(Stringable|string $uri): bool { - return $this->normalize(static::filterUri($uri)) === $this->normalize($this->uri); + return (match (true) { + $this->uri instanceof Uri => $this->uri, + default => Uri::new($this->uri), + })->isSameDocument($uri); } /** @@ -301,44 +305,12 @@ public function hasIPv4(): bool */ public function resolve(Stringable|string $uri): static { - $uri = static::formatHost(static::filterUri($uri, $this->uriFactory)); - $null = $uri instanceof Psr7UriInterface ? '' : null; - - if ($null !== $uri->getScheme()) { - return new static( - $uri->withPath(static::removeDotSegments($uri->getPath())), - $this->uriFactory - ); - } - - if ($null !== $uri->getAuthority()) { - return new static( - $uri - ->withScheme($this->uri->getScheme()) - ->withPath(static::removeDotSegments($uri->getPath())), - $this->uriFactory - ); - } - - $user = $null; - $pass = null; - $userInfo = $this->uri->getUserInfo(); - if (null !== $userInfo) { - [$user, $pass] = explode(':', $userInfo, 2) + [1 => null]; - } - - [$path, $query] = $this->resolvePathAndQuery($uri); + $resolved = UriString::resolve($uri, $this->uri->__toString()); - return new static( - $uri - ->withPath($this->removeDotSegments($path)) - ->withQuery($query) - ->withHost($this->uri->getHost()) - ->withPort($this->uri->getPort()) - ->withUserInfo($user, $pass) - ->withScheme($this->uri->getScheme()), - $this->uriFactory - ); + return new static(match ($this->uriFactory) { + null => Uri::new($resolved), + default => $this->uriFactory->createUri($resolved), + }, $this->uriFactory); } /** @@ -419,42 +391,6 @@ final protected function computeOrigin(Psr7UriInterface|UriInterface $uri, ?stri }; } - /** - * Normalizes a URI for comparison; this URI string representation is not suitable for usage as per RFC guidelines. - */ - final protected function normalize(Psr7UriInterface|UriInterface $uri): string - { - $null = $uri instanceof Psr7UriInterface ? '' : null; - - $path = $uri->getPath(); - if ('/' === ($path[0] ?? '') || '' !== $uri->getScheme().$uri->getAuthority()) { - $path = $this->removeDotSegments($path); - } - - $query = $uri->getQuery(); - $pairs = null === $query ? [] : explode('&', $query); - sort($pairs); - - static $regexpEncodedChars = ',%(2[D|E]|3\d|4[1-9|A-F]|5[\d|AF]|6[1-9|A-F]|7[\d|E]),i'; - $value = preg_replace_callback( - $regexpEncodedChars, - static fn (array $matches): string => rawurldecode($matches[0]), - [$path, implode('&', $pairs)] - ) ?? ['', $null]; - - [$path, $query] = $value + ['', $null]; - if ($null !== $uri->getAuthority() && '' === $path) { - $path = '/'; - } - - return $uri - ->withHost(Uri::fromComponents(['host' => $uri->getHost()])->getHost()) - ->withPath($path) - ->withQuery([] === $pairs ? $null : $query) - ->withFragment($null) - ->__toString(); - } - /** * Input URI normalization to allow Stringable and string URI. */ @@ -469,92 +405,6 @@ final protected static function filterUri(Stringable|string $uri, UriFactoryInte }; } - /** - * Remove dot segments from the URI path as per RFC specification. - */ - final protected function removeDotSegments(string $path): string - { - if (!str_contains($path, '.')) { - return $path; - } - - $reducer = function (array $carry, string $segment): array { - if ('..' === $segment) { - array_pop($carry); - - return $carry; - } - - if (!isset(static::DOT_SEGMENTS[$segment])) { - $carry[] = $segment; - } - - return $carry; - }; - - $oldSegments = explode('/', $path); - $newPath = implode('/', array_reduce($oldSegments, $reducer(...), [])); - if (isset(static::DOT_SEGMENTS[end($oldSegments)])) { - $newPath .= '/'; - } - - // @codeCoverageIgnoreStart - // added because some PSR-7 implementations do not respect RFC3986 - if (str_starts_with($path, '/') && !str_starts_with($newPath, '/')) { - return '/'.$newPath; - } - // @codeCoverageIgnoreEnd - - return $newPath; - } - - /** - * Resolves an URI path and query component. - * - * @return array{0:string, 1:string|null} - */ - final protected function resolvePathAndQuery(Psr7UriInterface|UriInterface $uri): array - { - $targetPath = $uri->getPath(); - $null = $uri instanceof Psr7UriInterface ? '' : null; - - if (str_starts_with($targetPath, '/')) { - return [$targetPath, $uri->getQuery()]; - } - - if ('' === $targetPath) { - $targetQuery = $uri->getQuery(); - if ($null === $targetQuery) { - $targetQuery = $this->uri->getQuery(); - } - - $targetPath = $this->uri->getPath(); - //@codeCoverageIgnoreStart - //because some PSR-7 Uri implementations allow this RFC3986 forbidden construction - if (null !== $this->uri->getAuthority() && !str_starts_with($targetPath, '/')) { - $targetPath = '/'.$targetPath; - } - //@codeCoverageIgnoreEnd - - return [$targetPath, $targetQuery]; - } - - $basePath = $this->uri->getPath(); - if (null !== $this->uri->getAuthority() && '' === $basePath) { - $targetPath = '/'.$targetPath; - } - - if ('' !== $basePath) { - $segments = explode('/', $basePath); - array_pop($segments); - if ([] !== $segments) { - $targetPath = implode('/', $segments).'/'.$targetPath; - } - } - - return [$targetPath, $uri->getQuery()]; - } - /** * Tells whether the component value from both URI object equals. * @@ -681,4 +531,108 @@ final protected static function formatPathWithEmptyBaseQuery(string $path): stri return '' === $basename ? './' : $basename; } + + /** + * Normalizes a URI for comparison; this URI string representation is not suitable for usage as per RFC guidelines. + * + * @deprecated since version 7.6.0 + */ + #[Deprecated(message:'no longer used by the isSameDocument method', since:'league/uri-interfaces:7.6.0')] + final protected function normalize(Psr7UriInterface|UriInterface $uri): string + { + return UriString::normalize($uri->withScheme($uri instanceof Psr7UriInterface ? '' : null)); + } + + + /** + * Remove dot segments from the URI path as per RFC specification. + * + * @deprecated since version 7.6.0 + */ + #[Deprecated(message:'no longer used by the isSameDocument method', since:'league/uri-interfaces:7.6.0')] + final protected function removeDotSegments(string $path): string + { + if (!str_contains($path, '.')) { + return $path; + } + + $reducer = function (array $carry, string $segment): array { + if ('..' === $segment) { + array_pop($carry); + + return $carry; + } + + if (!isset(static::DOT_SEGMENTS[$segment])) { + $carry[] = $segment; + } + + return $carry; + }; + + $oldSegments = explode('/', $path); + $newPath = implode('/', array_reduce($oldSegments, $reducer(...), [])); + if (isset(static::DOT_SEGMENTS[end($oldSegments)])) { + $newPath .= '/'; + } + + // @codeCoverageIgnoreStart + // added because some PSR-7 implementations do not respect RFC3986 + if (str_starts_with($path, '/') && !str_starts_with($newPath, '/')) { + return '/'.$newPath; + } + // @codeCoverageIgnoreEnd + + return $newPath; + } + + /** + * Resolves an URI path and query component. + * + * @return array{0:string, 1:string|null} + * + * @deprecated since version 7.6.0 + */ + #[Deprecated(message:'no longer used by the isSameDocument method', since:'league/uri-interfaces:7.6.0')] + final protected function resolvePathAndQuery(Psr7UriInterface|UriInterface $uri): array + { + $targetPath = $uri->getPath(); + $null = $uri instanceof Psr7UriInterface ? '' : null; + + if (str_starts_with($targetPath, '/')) { + return [$targetPath, $uri->getQuery()]; + } + + if ('' === $targetPath) { + $targetQuery = $uri->getQuery(); + if ($null === $targetQuery) { + $targetQuery = $this->uri->getQuery(); + } + + $targetPath = $this->uri->getPath(); + //@codeCoverageIgnoreStart + //because some PSR-7 Uri implementations allow this RFC3986 forbidden construction + if (null !== $this->uri->getAuthority() && !str_starts_with($targetPath, '/')) { + $targetPath = '/'.$targetPath; + } + //@codeCoverageIgnoreEnd + + return [$targetPath, $targetQuery]; + } + + $basePath = $this->uri->getPath(); + if (null !== $this->uri->getAuthority() && '' === $basePath) { + $targetPath = '/'.$targetPath; + } + + if ('' !== $basePath) { + $segments = explode('/', $basePath); + array_pop($segments); + if ([] !== $segments) { + $targetPath = implode('/', $segments).'/'.$targetPath; + } + } + + return [$targetPath, $uri->getQuery()]; + } } diff --git a/uri/BaseUriTest.php b/uri/BaseUriTest.php index 2df8c63e..01588128 100644 --- a/uri/BaseUriTest.php +++ b/uri/BaseUriTest.php @@ -182,22 +182,23 @@ public static function relativizeAndResolveProvider(): array ]; } - /** - * @param array $infos - */ #[DataProvider('uriProvider')] public function testInfo( Psr7UriInterface|Uri $uri, Psr7UriInterface|Uri|null $base_uri, - array $infos + bool $absolute_uri, + bool $network_path, + bool $absolute_path, + bool $relative_path, + bool $same_document, ): void { if (null !== $base_uri) { - self::assertSame($infos['same_document'], BaseUri::from($base_uri)->isSameDocument($uri)); + self::assertSame($same_document, BaseUri::from($base_uri)->isSameDocument($uri)); } - self::assertSame($infos['relative_path'], BaseUri::from($uri)->isRelativePath()); - self::assertSame($infos['absolute_path'], BaseUri::from($uri)->isAbsolutePath()); - self::assertSame($infos['absolute_uri'], BaseUri::from($uri)->isAbsolute()); - self::assertSame($infos['network_path'], BaseUri::from($uri)->isNetworkPath()); + self::assertSame($relative_path, BaseUri::from($uri)->isRelativePath()); + self::assertSame($absolute_path, BaseUri::from($uri)->isAbsolutePath()); + self::assertSame($absolute_uri, BaseUri::from($uri)->isAbsolute()); + self::assertSame($network_path, BaseUri::from($uri)->isNetworkPath()); } public static function uriProvider(): array @@ -206,46 +207,38 @@ public static function uriProvider(): array 'absolute uri' => [ 'uri' => Http::new('http://a/p?q#f'), 'base_uri' => null, - 'infos' => [ - 'absolute_uri' => true, - 'network_path' => false, - 'absolute_path' => false, - 'relative_path' => false, - 'same_document' => false, - ], + 'absolute_uri' => true, + 'network_path' => false, + 'absolute_path' => false, + 'relative_path' => false, + 'same_document' => false, ], 'network relative uri' => [ 'uri' => Http::new('//스타벅스코리아.com/p?q#f'), 'base_uri' => Http::new('//xn--oy2b35ckwhba574atvuzkc.com/p?q#z'), - 'infos' => [ - 'absolute_uri' => false, - 'network_path' => true, - 'absolute_path' => false, - 'relative_path' => false, - 'same_document' => true, - ], + 'absolute_uri' => false, + 'network_path' => true, + 'absolute_path' => false, + 'relative_path' => false, + 'same_document' => true, ], 'path relative uri with non empty path' => [ 'uri' => Http::new('p?q#f'), 'base_uri' => null, - 'infos' => [ - 'absolute_uri' => false, - 'network_path' => false, - 'absolute_path' => false, - 'relative_path' => true, - 'same_document' => false, - ], + 'absolute_uri' => false, + 'network_path' => false, + 'absolute_path' => false, + 'relative_path' => true, + 'same_document' => false, ], 'path relative uri with empty' => [ 'uri' => Http::new('?q#f'), 'base_uri' => null, - 'infos' => [ - 'absolute_uri' => false, - 'network_path' => false, - 'absolute_path' => false, - 'relative_path' => true, - 'same_document' => false, - ], + 'absolute_uri' => false, + 'network_path' => false, + 'absolute_path' => false, + 'relative_path' => true, + 'same_document' => false, ], ]; }