Skip to content

Commit

Permalink
Adding new URI related interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Dec 25, 2024
1 parent d74c6b3 commit 0be0822
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 51 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ All Notable changes to `League\Uri` will be documented in this file
- `Uri::toUnixPath` returns the URI path as a Unix Path or `null`
- `Uri::toWindowsPath` returns the URI path as a Windows Path or `null`
- `Uri::toRfc8089` return the URI in a RFC8089 formator `null`
- `Uri::toAnchor` returns the HTML anchor string using the instance as the href attribute value
- `Uri::toMarkdown` returns the markdown link construct using the instance as the href attribute value

### Fixed

Expand Down
122 changes: 72 additions & 50 deletions Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@
namespace League\Uri;

use Deprecated;
use DOMDocument;
use DOMException;
use finfo;
use League\Uri\Contracts\Conditionable;
use League\Uri\Contracts\UriComponentInterface;
use League\Uri\Contracts\UriEncoder;
use League\Uri\Contracts\UriException;
use League\Uri\Contracts\UriInspector;
use League\Uri\Contracts\UriInterface;
use League\Uri\Exceptions\ConversionFailed;
use League\Uri\Exceptions\MissingFeature;
Expand Down Expand Up @@ -45,6 +49,7 @@
use function implode;
use function in_array;
use function inet_pton;
use function is_array;
use function is_bool;
use function ltrim;
use function preg_match;
Expand Down Expand Up @@ -75,7 +80,7 @@
* @phpstan-import-type ComponentMap from UriString
* @phpstan-import-type InputComponentMap from UriString
*/
final class Uri implements UriInterface, Conditionable
final class Uri implements Conditionable, UriInterface, UriEncoder, UriInspector
{
/**
* RFC3986 invalid characters.
Expand Down Expand Up @@ -428,10 +433,7 @@ public static function tryNew(Stringable|string|null $uri = ''): ?self
*/
public static function new(Stringable|string $uri = ''): self
{
$components = match (true) {
$uri instanceof UriInterface => $uri->toComponents(),
default => UriString::parse($uri),
};
$components = UriString::parse($uri);

return new self(
$components['scheme'],
Expand Down Expand Up @@ -475,7 +477,7 @@ public static function fromBaseUri(
public static function fromTemplate(UriTemplate|Stringable|string $template, iterable $variables = []): self
{
return match (true) {
$template instanceof UriTemplate => self::fromComponents($template->expand($variables)->toComponents()),
$template instanceof UriTemplate => self::new($template->expand($variables)),
$template instanceof UriTemplate\Template => self::new($template->expand($variables)),
default => self::new(UriTemplate\Template::new($template)->expand($variables)),
};
Expand Down Expand Up @@ -1039,6 +1041,49 @@ public function toDisplayString(): string
return UriString::build($components);
}

/**
* Returns the HTML string representation of the anchor tag with the current instance as its href attribute.
*
* @param list<string>|string|null $class
*
* @throws DOMException
*/
public function toAnchorTag(?string $linkText = null, array|string|null $class = null, ?string $target = null): string
{
$doc = new DOMDocument('1.0', 'utf-8');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$anchor = $doc->createElement('a');
$anchor->setAttribute('href', $this->toString());
if (null !== $class) {
$anchor->setAttribute('class', is_array($class) ? implode(' ', $class) : $class);
}

if (null !== $target) {
$anchor->setAttribute('target', $target);
}

$textNode = $doc->createTextNode($linkText ?? $this->toDisplayString());
if (false === $textNode) {
throw new DOMException('The link generation failed.');
}
$anchor->appendChild($textNode);
$anchor = $doc->saveHTML($anchor);
if (false === $anchor) {
throw new DOMException('The link generation failed.');
}

return $anchor;
}

/**
* Returns the markdown string representation of the anchor tag with the current instance as its href attribute.
*/
public function toMarkdown(?string $linkText = null): string
{
return '['.($linkText ?? $this->toDisplayString()).']('.$this->toString().')';
}

/**
* Returns the Unix filesystem path.
*
Expand Down Expand Up @@ -1125,65 +1170,41 @@ public function toComponents(): array
];
}

/**
* {@inheritDoc}
*/
public function getScheme(): ?string
{
return $this->scheme;
}

/**
* {@inheritDoc}
*/
public function getAuthority(): ?string
{
return $this->authority;
}

/**
* {@inheritDoc}
*/
public function getUsername(): ?string
public function getUser(): ?string
{
return $this->user;
}

/**
* {@inheritDoc}
*/
public function getPassword(): ?string
{
return $this->pass;
}

/**
* {@inheritDoc}
*/
public function getUserInfo(): ?string
{
return $this->userInfo;
}

/**
* {@inheritDoc}
*/
public function getHost(): ?string
{
return $this->host;
}

/**
* {@inheritDoc}
*/
public function getPort(): ?int
{
return $this->port;
}

/**
* {@inheritDoc}
*/
public function getPath(): string
{
return match (true) {
Expand All @@ -1192,25 +1213,19 @@ public function getPath(): string
};
}

/**
* {@inheritDoc}
*/
public function getQuery(): ?string
{
return $this->query;
}

/**
* {@inheritDoc}
*/
public function getFragment(): ?string
{
return $this->fragment;
}

public function getOrigin(): ?self
public function getOrigin(): ?string
{
return null === $this->origin ? null : Uri::new($this->origin);
return $this->origin;
}

public function when(callable|bool $condition, callable $onSuccess, ?callable $onFail = null): static
Expand All @@ -1226,9 +1241,6 @@ public function when(callable|bool $condition, callable $onSuccess, ?callable $o
} ?? $this;
}

/**
* {@inheritDoc}
*/
public function withScheme(Stringable|string|null $scheme): UriInterface
{
$scheme = $this->formatScheme($this->filterString($scheme));
Expand Down Expand Up @@ -1421,15 +1433,12 @@ public function isCrossOrigin(UriInterface|Stringable|string $uri): bool
return true;
}

if (!$uri instanceof UriInterface) {
$uri = self::tryNew($uri);
}

$uri = self::tryNew($uri);
if (null === $uri || null === ($origin = $uri->getOrigin())) {
return true;
}

return $this->origin !== (string) $origin;
return $this->origin !== $origin;
}

public function isSameOrigin(Stringable|string $uri): bool
Expand Down Expand Up @@ -1694,9 +1703,7 @@ private function resolvePathAndQuery(UriInterface $uri): array
*/
public function relativize(Stringable|string $uri): UriInterface
{
if (!$uri instanceof UriInterface) {
$uri = self::new($uri);
}
$uri = self::new($uri);

if (
$this->scheme !== $uri->getScheme() ||
Expand Down Expand Up @@ -1931,4 +1938,19 @@ public static function createFromServer(array $server): self
{
return self::fromServer($server);
}

/**
* DEPRECATION WARNING! This method will be removed in the next major point release.
*
* @deprecated Since version 7.6.0
* @codeCoverageIgnore
* @see Uri::getUser()
*
* Retuns the user component encoded value.
*/
#[Deprecated(message:'use League\Uri\Uri::getUser() instead', since:'league/uri:7.6.0')]
public function getUsername(): ?string
{
return $this->getUser();
}
}
93 changes: 92 additions & 1 deletion UriTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ public static function sameValueAsProvider(): array
#[DataProvider('getOriginProvider')]
public function testGetOrigin(Psr7UriInterface|Uri|string $uri, ?string $expectedOrigin): void
{
self::assertSame($expectedOrigin, Uri::new($uri)->getOrigin()?->toString());
self::assertSame($expectedOrigin, Uri::new($uri)->getOrigin());
}

public static function getOriginProvider(): array
Expand Down Expand Up @@ -981,4 +981,95 @@ public static function providesUriToDisplay(): iterable
'output' => 'http://bébé.be',
];
}

#[Test]
#[DataProvider('providesUriToMarkdown')]
public function it_will_generate_the_markdown_code_for_the_instance(string $uri, ?string $content, string $expected): void
{
self::assertSame($expected, Uri::new($uri)->toMarkdown($content));
}

public static function providesUriToMarkdown(): iterable
{
yield 'empty string' => [
'uri' => '',
'content' => '',
'expected' => '[]()',
];

yield 'URI with a specific content' => [
'uri' => 'http://example.com/foo/bar',
'content' => 'this is a link',
'expected' => '[this is a link](http://example.com/foo/bar)',
];

yield 'URI without content' => [
'uri' => 'http://Bébé.be',
'content' => null,
'expected' => '[http://bébé.be](http://xn--bb-bjab.be)',
];
}

#[Test]
#[DataProvider('providesUriToHTML')]
public function it_will_generate_the_html_code_for_the_instance(
string $uri,
?string $content,
?string $class,
?string $target,
string $expected
): void {
self::assertSame($expected, Uri::new($uri)->toAnchorTag($content, $class, $target));
}

public static function providesUriToHTML(): iterable
{
yield 'empty string' => [
'uri' => '',
'content' => '',
'class' => null,
'target' => null,
'expected' => '<a href=""></a>',
];

yield 'URI with a specific content' => [
'uri' => 'http://example.com/foo/bar',
'content' => 'this is a link',
'class' => null,
'target' => null,
'expected' => '<a href="http://example.com/foo/bar">this is a link</a>',
];

yield 'URI without content' => [
'uri' => 'http://Bébé.be',
'content' => null,
'class' => null,
'target' => null,
'expected' => '<a href="http://xn--bb-bjab.be">http://bébé.be</a>',
];

yield 'URI without content and with class' => [
'uri' => 'http://Bébé.be',
'content' => null,
'class' => 'foo bar',
'target' => null,
'expected' => '<a href="http://xn--bb-bjab.be" class="foo bar">http://bébé.be</a>',
];

yield 'URI without content and with target' => [
'uri' => 'http://Bébé.be',
'content' => null,
'class' => null,
'target' => '_blank',
'expected' => '<a href="http://xn--bb-bjab.be" target="_blank">http://bébé.be</a>',
];

yield 'URI without content, with target and class' => [
'uri' => 'http://Bébé.be',
'content' => null,
'class' => 'foo bar',
'target' => '_blank',
'expected' => '<a href="http://xn--bb-bjab.be" class="foo bar" target="_blank">http://bébé.be</a>',
];
}
}
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"league/uri-schemes": "^1.0"
},
"suggest": {
"ext-dom": "to convert the URI into an HTML anchor tag",
"ext-bcmath": "to improve IPV4 host parsing",
"ext-fileinfo": "to create Data URI from file contennts",
"ext-gmp": "to improve IPV4 host parsing",
Expand Down

0 comments on commit 0be0822

Please sign in to comment.