diff --git a/CHANGELOG.md b/CHANGELOG.md
index 522155c10..a39fab744 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/Uri.php b/Uri.php
index ee437ceb4..32398b8b7 100644
--- a/Uri.php
+++ b/Uri.php
@@ -14,11 +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\UriException;
use League\Uri\Contracts\UriInterface;
+use League\Uri\Contracts\UriStringProvider;
use League\Uri\Exceptions\ConversionFailed;
use League\Uri\Exceptions\MissingFeature;
use League\Uri\Exceptions\SyntaxError;
@@ -75,7 +78,7 @@
* @phpstan-import-type ComponentMap from UriString
* @phpstan-import-type InputComponentMap from UriString
*/
-final class Uri implements UriInterface, Conditionable
+final class Uri implements UriInterface, Conditionable, UriStringProvider
{
/**
* RFC3986 invalid characters.
@@ -1039,6 +1042,42 @@ 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.
+ *
+ * @throws DOMException
+ */
+ public function toAnchorTag(?string $content = null, ?string $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', $class);
+ }
+ if (null !== $target) {
+ $anchor->setAttribute('target', $target);
+ }
+
+ $anchor->appendChild($doc->createTextNode($content ?? $this->toDisplayString()));
+ $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 $content = null): string
+ {
+ return '['.($content ?? $this->toDisplayString()).']('.$this->toString().')';
+ }
+
/**
* Returns the Unix filesystem path.
*
@@ -1208,9 +1247,9 @@ 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
@@ -1429,7 +1468,7 @@ public function isCrossOrigin(UriInterface|Stringable|string $uri): bool
return true;
}
- return $this->origin !== (string) $origin;
+ return $this->origin !== $origin;
}
public function isSameOrigin(Stringable|string $uri): bool
diff --git a/UriTest.php b/UriTest.php
index 44564b627..587eca4d5 100644
--- a/UriTest.php
+++ b/UriTest.php
@@ -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
@@ -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' => '',
+ ];
+
+ yield 'URI with a specific content' => [
+ 'uri' => 'http://example.com/foo/bar',
+ 'content' => 'this is a link',
+ 'class' => null,
+ 'target' => null,
+ 'expected' => 'this is a link',
+ ];
+
+ yield 'URI without content' => [
+ 'uri' => 'http://Bébé.be',
+ 'content' => null,
+ 'class' => null,
+ 'target' => null,
+ 'expected' => 'http://bébé.be',
+ ];
+
+ yield 'URI without content and with class' => [
+ 'uri' => 'http://Bébé.be',
+ 'content' => null,
+ 'class' => 'foo bar',
+ 'target' => null,
+ 'expected' => 'http://bébé.be',
+ ];
+
+ yield 'URI without content and with target' => [
+ 'uri' => 'http://Bébé.be',
+ 'content' => null,
+ 'class' => null,
+ 'target' => '_blank',
+ 'expected' => 'http://bébé.be',
+ ];
+
+ yield 'URI without content, with target and class' => [
+ 'uri' => 'http://Bébé.be',
+ 'content' => null,
+ 'class' => 'foo bar',
+ 'target' => '_blank',
+ 'expected' => 'http://bébé.be',
+ ];
+ }
}
diff --git a/composer.json b/composer.json
index e1c4be3e9..d88b63436 100644
--- a/composer.json
+++ b/composer.json
@@ -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",