Skip to content

Commit

Permalink
Improve UriRenderer interface
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Jan 23, 2025
1 parent aaa43e1 commit da7a72d
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 69 deletions.
33 changes: 26 additions & 7 deletions docs/uri/7.0/rfc3986.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,26 @@ $uri = Uri::fromRfc8089('file:/etc/fstab');
echo $uri = //returns 'file:///etc/fstab'
~~~

<p class="message-notice"><code>fromRfc8089</code> is added since version <code>7.4.0</code></p>
<p class="message-info"><code>fromRfc8089</code> is added since version <code>7.4.0</code></p>

It is also possible to instantiate a new instance from the following HTTP related object or string>

~~~php
$uri = Uri::fromMarkdownAnchor('[overview](https://uri.thephpleague.com/uri/7.0/)');
echo $uri; //returns 'https://uri.thephpleague.com/uri/7.0/'

$uri = Uri::fromHeaderLinkValue('<https://example.org/>; rel="start"');
echo $uri = //returns 'https://example.org/'

$uri = Uri::fromHtmlAnchor('<a href="/domain-parser/1.0/">uri-hostname-parser</a>');
echo $uri; //returns '/domain-parser/1.0/'

$uri = Uri::fromHtmlLink('<link rel="icon" href="/assets/img/uri-logo.svg" type="image/svg+xml">');
echo $uri = //returns '/assets/img/uri-logo.svg'
~~~

<p class="message-info">The named constructor are available since version <code>7.6.0</code></p>
<p class="message-notice">To use the named constructor in relation to HTML tag, the <code>ext-dom</code> extension must be present.</p>

## URI string representation

Expand Down Expand Up @@ -147,23 +166,23 @@ HTML specific representation are added to allow adding URI to your HTML/Markdown

```php
$uri = Uri::new('eXAMPLE://a/./b/../b/%63/%7bfoo%7d?foo[]=bar');
echo $uri->toMarkdown();
echo $uri->toMarkdownAnchor();
//display '[example://a/b/c/{foo}?foo[]=bar](example://a/./b/../b/%63/%7bfoo%7d?foo%5B%5D=bar)
echo $uri->toMarkdown('my link');
echo $uri->toMarkdownAnchor('my link');
//display '[my link](example://a/./b/../b/%63/%7bfoo%7d?foo%5B%5D=bar)
echo $uri->toAnchorTag();
echo $uri->toHtmlAnchor();
// display '<a href="example://a/./b/../b/%63/%7bfoo%7d?foo%5B%5D=bar">example://a/b/c/{foo}?foo[]=bar</a>'
echo $uri->toAnchorTag('my link');
echo $uri->toHtmlAnchor('my link');
// display '<a href="example://a/./b/../b/%63/%7bfoo%7d?foo%5B%5D=bar">my link</a>'
```

You can also generate the Link `tag` and/or `header` depending on how you want your URI link to be rendered:

```php
$uri = Uri::new('https://example.com/my/css/v1.3');
echo $uri->toLinkTag(['rel' => 'stylesheet']);
echo $uri->toHtmlLink(['rel' => 'stylesheet']);
//display '<link href="https://example.com/my/css/v1.3" rel="stylesheet">
echo $uri->toLinkHeaderValue(['rel' => 'stylesheet']);
echo $uri->toHeaderLinkValue(['rel' => 'stylesheet']);
//display 'https://example.com/my/css/v1.3 ;rel=stylesheet'
```

Expand Down
1 change: 1 addition & 0 deletions interfaces/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ All Notable changes to `League\Uri\Interfaces` will be documented in this file
- `UriString::removeDotSegments`
- `UriString::normalize`
- `UriString::normalizeAuthority`
- `FeatureDetection::supportsDom`

### Fixed

Expand Down
8 changes: 4 additions & 4 deletions interfaces/Contracts/UriRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function jsonSerialize(): string;
/**
* Returns the markdown string representation of the anchor tag with the current instance as its href attribute.
*/
public function toMarkdown(?string $linkTextTemplate = null): string;
public function toMarkdownAnchor(?string $linkTextTemplate = null): string;

/**
* Returns the HTML string representation of the anchor tag with the current instance as its href attribute.
Expand All @@ -67,7 +67,7 @@ public function toMarkdown(?string $linkTextTemplate = null): string;
*
* @throws DOMException
*/
public function toAnchorTag(?string $linkTextTemplate = null, iterable $attributes = []): string;
public function toHtmlAnchor(?string $linkTextTemplate = null, iterable $attributes = []): string;

/**
* Returns the Link tag content for the current instance.
Expand All @@ -76,7 +76,7 @@ public function toAnchorTag(?string $linkTextTemplate = null, iterable $attribut
*
* @throws DOMException
*/
public function toLinkTag(iterable $attributes = []): string;
public function toHtmlLink(iterable $attributes = []): string;

/**
* Returns the Link header content for a single item.
Expand All @@ -85,7 +85,7 @@ public function toLinkTag(iterable $attributes = []): string;
*
* @see https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.6
*/
public function toLinkHeaderValue(iterable $parameters = []): string;
public function toHeaderLinkValue(iterable $parameters = []): string;

/**
* Returns the Unix filesystem path. The method returns null for any other scheme except the file scheme.
Expand Down
12 changes: 12 additions & 0 deletions interfaces/FeatureDetection.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use League\Uri\Exceptions\MissingFeature;
use League\Uri\IPv4\Calculator;

use function extension_loaded;

use const PHP_INT_SIZE;

/**
Expand Down Expand Up @@ -53,4 +55,14 @@ public static function supportsIPv4Conversion(): void
throw new MissingFeature('A '.Calculator::class.' implementation could not be automatically loaded. To perform IPv4 conversion use a x.64 PHP build or install one of the following extension GMP or BCMath. You can also ship your own implmentation.');
}
}

public static function supportsDom(): void
{
static $isSupported = null;
$isSupported = $isSupported ?? extension_loaded('dom');

if (!$isSupported) {
throw new MissingFeature('To use a DOM related feature, the DOM extension must be installed in your system.');
}
}
}
4 changes: 4 additions & 0 deletions uri/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ All Notable changes to `League\Uri` will be documented in this file
- `Uri` implements the new `League\Uri\Contract\UriInspector` interface
- `Uri` implements the new `League\Uri\Contract\UriRenderer` interface
- `Uri::getUser` returns the encoded user component of the URI an alias for `Uri::getUsername`
- `Uri::fromMarkdownAnchor`
- `Uri::fromHtmlAnchor`
- `Uri::fromHtmlLink`
- `Uri::fromHeaderLinkValue`

### Fixed

Expand Down
68 changes: 68 additions & 0 deletions uri/FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -569,4 +569,72 @@ public static function invalidUriWithWhitespaceProvider(): iterable
yield 'uri surrounded by whitespaces' => ['uri' => ' https://a/b?c '];
yield 'uri containing whitespaces' => ['uri' => 'https://a/b ?c'];
}

#[Test]
#[DataProvider('provideAnchorTagHtml')]
public function it_parses_uri_string_from_an_anchor_tag(string $html, ?string $baseUri, string $expected): void
{
self::assertSame($expected, Uri::fromHtmlAnchor($html, $baseUri)->toString());
}

public static function provideAnchorTagHtml(): iterable
{
yield 'empty string' => [
'html' => '<a href=""></a>',
'baseUri' => null,
'expected' => '',
];

yield 'empty string with base URI' => [
'html' => '<a href=""></a>',
'baseUri' => 'https://example.com/',
'expected' => 'https://example.com/',
];

yield 'anchor tag with no base URI' => [
'html' => '<a href="/">foobar</a>',
'baseUri' => null,
'expected' => '/',
];

yield 'multiple anchor tag' => [
'html' => '<a href="/foobar">foobar</a> <a href="https://example.com/yolo">foobar</a>',
'baseUri' => 'https://example.com/',
'expected' => 'https://example.com/foobar',
];
}

#[Test]
#[DataProvider('provideAnchorTagMarkdown')]
public function it_parses_uri_string_from_an_anchor_markdown(string $html, ?string $baseUri, string $expected): void
{
self::assertSame($expected, Uri::fromMarkdownAnchor($html, $baseUri)->toString());
}

public static function provideAnchorTagMarkdown(): iterable
{
yield 'empty string' => [
'html' => '[yolo]()',
'baseUri' => null,
'expected' => '',
];

yield 'empty string with base URI' => [
'html' => '[]()',
'baseUri' => 'https://example.com/',
'expected' => 'https://example.com/',
];

yield 'anchor tag with no base URI' => [
'html' => '[yolo](/)',
'baseUri' => null,
'expected' => '/',
];

yield 'multiple anchor tag' => [
'html' => '[foobar](/foobar) and then later on [foobar](https://example.com/yolo)',
'baseUri' => 'https://example.com/',
'expected' => 'https://example.com/foobar',
];
}
}
Loading

0 comments on commit da7a72d

Please sign in to comment.