Skip to content

Commit 6bc654f

Browse files
committed
Move psr/http-factory requirement from the uri-interfaces to the uri package
1 parent 0fb0ee0 commit 6bc654f

File tree

9 files changed

+86
-161
lines changed

9 files changed

+86
-161
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ All Notable changes to `League\Uri` will be documented in this file
66

77
### Added
88

9-
- Added methods to align with the upcoming `Uri\Rfc3986Uri` PHP native class (see: https://wiki.php.net/rfc/url_parsing_api#proposal)
9+
- `Uri::parse` returns a new `Uri` instance on success or null on failure (ie: a Relax version of `Uri::fromBaseUri` and `Uri::new`) that mimics the behaviour of the upcoming native PHP URI parse method.
1010
- `Uri::tryNew` returns a new `Uri` instance on success or null on failure (ie: a Relax version of `Uri::new`).
1111
- `Http::tryNew` returns a new `Uri` instance on success or null on failure (ie: a Relax version of `Http::new`).
1212
- `Http::when` conditional method to ease component building logic.
@@ -16,6 +16,10 @@ All Notable changes to `League\Uri` will be documented in this file
1616
- `Uri::fromMarkdownAnchor`
1717
- `Uri::fromHtmlAnchor`
1818
- `UriTemplate` implements the `Stringable` interface
19+
- `Uri::resolve` returns a new `Uri` instance resolve against the current instance.
20+
- `Uri::normalize` returns a new `Uri` instance with a full “normalized-decoded” representation: The URI is normalized (when applicable), and components are percent-decoded. Normalization may contain destructive operation.
21+
- `Uri` and `Http` classes implement a serialize mechanism to safely serialize and unserialize the instance
22+
- Dependency to `psr/http-factory` package which is required for the package.
1923

2024
### Fixed
2125

FactoryTest.php

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPUnit\Framework\Attributes\DataProvider;
1919
use PHPUnit\Framework\Attributes\Group;
2020
use PHPUnit\Framework\Attributes\Test;
21+
use PHPUnit\Framework\Attributes\TestWith;
2122
use PHPUnit\Framework\TestCase;
2223
use Stringable;
2324

@@ -240,26 +241,15 @@ public static function rfc8089UriProvider(): iterable
240241
];
241242
}
242243

243-
#[DataProvider('invalidRfc8089UriProvider')]
244-
public function testIfFailsToGenerateAnUriFromRfc8089(string $invalidUri): void
244+
#[TestWith(['invalidUri' => 'http://www.example.com'], 'unsupported scheme')]
245+
#[TestWith(['invalidUri' => '//localhost/etc/fstab'], 'missing scheme')]
246+
public function it_fails_to_generate_an_uri_from_rfc8089(string $invalidUri): void
245247
{
246248
$this->expectException(SyntaxError::class);
247249

248250
Uri::fromRfc8089($invalidUri);
249251
}
250252

251-
public static function invalidRfc8089UriProvider(): iterable
252-
{
253-
return [
254-
'unsupported scheme' => [
255-
'invalidUri' => 'http://www.example.com',
256-
],
257-
'missing scheme' => [
258-
'invalidUri' => '//localhost/etc/fstab',
259-
],
260-
];
261-
}
262-
263253
public function testCreateFromUri(): void
264254
{
265255
$expected = 'https://login:pass@secure.example.com:443/test/query.php?kingkong=toto#doc3';
@@ -553,21 +543,16 @@ public function testICanBeInstantiateFromRFC6750(): void
553543
}
554544

555545
#[Test]
556-
#[DataProvider('invalidUriWithWhitespaceProvider')]
546+
#[TestWith(['uri' => ' '], 'uri containing only whitespaces')]
547+
#[TestWith(['uri' => ' https://a/b?c'], 'uri starting with whitespaces')]
548+
#[TestWith(['uri' => 'https://a/b?c '], 'uri ending with whitespaces')]
557549
public function it_fails_parsing_uri_string_with_whitespace(string $uri): void
558550
{
559551
$this->expectException(InvalidArgumentException::class);
560552

561553
Uri::new($uri);
562554
}
563555

564-
public static function invalidUriWithWhitespaceProvider(): iterable
565-
{
566-
yield 'uri containing only whitespaces' => ['uri' => ' '];
567-
yield 'uri starting with whitespaces' => ['uri' => ' https://a/b?c'];
568-
yield 'uri ending with whitespaces' => ['uri' => 'https://a/b?c '];
569-
}
570-
571556
#[Test]
572557
#[DataProvider('provideAnchorTagHtml')]
573558
public function it_parses_uri_string_from_an_anchor_tag(string $html, ?string $baseUri, string $expected): void
@@ -637,20 +622,15 @@ public static function provideAnchorTagMarkdown(): iterable
637622
}
638623

639624
#[Test]
640-
#[DataProvider('provideInvalidMarkdown')]
625+
#[TestWith(['html' => 'this is **markdown**'], 'missing markdown placeholder')]
626+
#[TestWith(['html' => '[this is an incomplete href] http://example.com markdown'], 'invalid markdown placeholder; missing URI part')]
627+
#[TestWith(['html' => 'this is an incomplete(http://example.com) markdown'], 'invalid markdown placeholder; missing content part')]
641628
public function it_fails_to_parse_an_invalid_markdown(string $html): void
642629
{
643630
$this->expectException(InvalidArgumentException::class);
644631
Uri::fromMarkdownAnchor($html);
645632
}
646633

647-
public static function provideInvalidMarkdown(): iterable
648-
{
649-
yield 'missing markdown placeholder' => ['html' => 'this is **markdown**'];
650-
yield 'invalid markdown placeholder; missing URI part' => ['html' => '[this is an imcomplete] http://example.com markdown'];
651-
yield 'invalid markdown placeholder; missing content part' => ['html' => 'this is an imcomplete(http://example.com) markdown'];
652-
}
653-
654634
#[Test]
655635
#[DataProvider('provideInvalidUri')]
656636
public function it_fails_to_parse_with_new(Stringable|string|null $uri): void
@@ -665,15 +645,10 @@ public static function provideInvalidUri(): iterable
665645
}
666646

667647
#[Test]
668-
#[DataProvider('provideInvalidUriForResolution')]
648+
#[TestWith(['uri' => ':', 'baseUri' => null], 'invalid URI')]
649+
#[TestWith(['uri' => '', 'baseUri' => '/absolute/path'], 'invalid resolution with a non absolute URI')]
669650
public function it_fails_to_parse_with_parse(Stringable|string $uri, Stringable|string|null $baseUri): void
670651
{
671652
self::assertNull(Uri::parse($uri, $baseUri));
672653
}
673-
674-
public static function provideInvalidUriForResolution(): iterable
675-
{
676-
yield 'invalid URI' => ['uri' => ':', 'baseUri' => null];
677-
yield 'invalid resolution with a non absolute URI' => ['uri' => '', 'baseUri' => '/absolute/path'];
678-
}
679654
}

FtpTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ public function testConstructorThrowInvalidArgumentException(string $uri): void
6969
public static function invalidUrlProvider(): array
7070
{
7171
return [
72-
//['http://example.com'],
7372
['ftp:/example.com'],
7473
['ftp:example.com'],
7574
['ftp://example.com?query#fragment'],

Http.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace League\Uri;
1515

1616
use Deprecated;
17+
use Exception;
1718
use JsonSerializable;
1819
use League\Uri\Contracts\Conditionable;
1920
use League\Uri\Contracts\UriException;
@@ -273,6 +274,26 @@ public function withFragment(string $fragment): self
273274
return $this->newInstance($this->uri->withFragment($this->filterInput($fragment)));
274275
}
275276

277+
/**
278+
* @return array{uri: string}
279+
*/
280+
public function __serialize(): array
281+
{
282+
return ['uri' => $this->uri->toString()];
283+
}
284+
285+
/**
286+
* @param array{uri: string} $data
287+
*
288+
* @throws Exception
289+
*/
290+
public function __unserialize(array $data): void
291+
{
292+
$uri = self::new($data['uri'] ?? throw new Exception('The `uri` property is missing from the serialized object.'));
293+
294+
$this->uri = $uri->uri;
295+
}
296+
276297
/**
277298
* DEPRECATION WARNING! This method will be removed in the next major point release.
278299
*

HttpTest.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616
use PHPUnit\Framework\Attributes\CoversClass;
1717
use PHPUnit\Framework\Attributes\DataProvider;
1818
use PHPUnit\Framework\Attributes\Group;
19+
use PHPUnit\Framework\Attributes\Test;
20+
use PHPUnit\Framework\Attributes\TestWith;
1921
use PHPUnit\Framework\TestCase;
2022
use Psr\Http\Message\UriInterface;
2123

24+
use function serialize;
25+
use function unserialize;
26+
2227
#[CoversClass(Http::class)]
2328
#[Group('http')]
2429
final class HttpTest extends TestCase
@@ -171,23 +176,16 @@ public static function portProvider(): array
171176
];
172177
}
173178

174-
#[DataProvider('invalidPathProvider')]
179+
#[TestWith(['data:go'])]
180+
#[TestWith(['//data'])]
181+
#[TestWith(['to://to'])]
175182
public function testPathIsInvalid(string $path): void
176183
{
177184
self::expectException(SyntaxError::class);
178185

179186
Http::new()->withPath($path);
180187
}
181188

182-
public static function invalidPathProvider(): array
183-
{
184-
return [
185-
['data:go'],
186-
['//data'],
187-
['to://to'],
188-
];
189-
}
190-
191189
#[DataProvider('invalidURI')]
192190
public function testCreateFromInvalidUrlKO(string $uri): void
193191
{
@@ -262,4 +260,14 @@ public function testICanBeInstantiateFromRFC6750(): void
262260
Http::fromTemplate($template, $params)->getPath()
263261
);
264262
}
263+
264+
#[Test]
265+
public function it_can_be_serialized_by_php(): void
266+
{
267+
$uri = Http::new('https://user:pass@example.com:81/path?query#fragment');
268+
/** @var Http $newUri */
269+
$newUri = unserialize(serialize($uri));
270+
271+
self::assertEquals($uri, $newUri);
272+
}
265273
}

Uri.php

Lines changed: 14 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -482,8 +482,6 @@ public static function new(Stringable|string $uri = ''): self
482482
* Returns a new instance from a URI and a Base URI.or null on failure.
483483
*
484484
* The returned URI must be absolute if a base URI is provided
485-
*
486-
* @see https://wiki.php.net/rfc/url_parsing_api
487485
*/
488486
public static function parse(Stringable|string $uri, Stringable|string|null $baseUri = null): ?self
489487
{
@@ -1470,16 +1468,7 @@ public function withScheme(Stringable|string|null $scheme): UriInterface
14701468

14711469
return match ($scheme) {
14721470
$this->scheme => $this,
1473-
default => new self(
1474-
$scheme,
1475-
$this->user,
1476-
$this->pass,
1477-
$this->host,
1478-
$this->port,
1479-
$this->path,
1480-
$this->query,
1481-
$this->fragment,
1482-
),
1471+
default => new self($scheme, $this->user, $this->pass, $this->host, $this->port, $this->path, $this->query, $this->fragment),
14831472
};
14841473
}
14851474

@@ -1513,16 +1502,7 @@ public function withUserInfo(
15131502

15141503
return match ($userInfo) {
15151504
$this->userInfo => $this,
1516-
default => new self(
1517-
$this->scheme,
1518-
$user,
1519-
$pass,
1520-
$this->host,
1521-
$this->port,
1522-
$this->path,
1523-
$this->query,
1524-
$this->fragment,
1525-
),
1505+
default => new self($this->scheme, $user, $pass, $this->host, $this->port, $this->path, $this->query, $this->fragment),
15261506
};
15271507
}
15281508

@@ -1545,16 +1525,7 @@ public function withHost(Stringable|string|null $host): UriInterface
15451525

15461526
return match ($host) {
15471527
$this->host => $this,
1548-
default => new self(
1549-
$this->scheme,
1550-
$this->user,
1551-
$this->pass,
1552-
$host,
1553-
$this->port,
1554-
$this->path,
1555-
$this->query,
1556-
$this->fragment,
1557-
),
1528+
default => new self($this->scheme, $this->user, $this->pass, $host, $this->port, $this->path, $this->query, $this->fragment),
15581529
};
15591530
}
15601531

@@ -1564,16 +1535,7 @@ public function withPort(int|null $port): UriInterface
15641535

15651536
return match ($port) {
15661537
$this->port => $this,
1567-
default => new self(
1568-
$this->scheme,
1569-
$this->user,
1570-
$this->pass,
1571-
$this->host,
1572-
$port,
1573-
$this->path,
1574-
$this->query,
1575-
$this->fragment,
1576-
),
1538+
default => new self($this->scheme, $this->user, $this->pass, $this->host, $port, $this->path, $this->query, $this->fragment),
15771539
};
15781540
}
15791541

@@ -1585,16 +1547,7 @@ public function withPath(Stringable|string $path): UriInterface
15851547

15861548
return match ($path) {
15871549
$this->path => $this,
1588-
default => new self(
1589-
$this->scheme,
1590-
$this->user,
1591-
$this->pass,
1592-
$this->host,
1593-
$this->port,
1594-
$path,
1595-
$this->query,
1596-
$this->fragment,
1597-
),
1550+
default => new self($this->scheme, $this->user, $this->pass, $this->host, $this->port, $path, $this->query, $this->fragment),
15981551
};
15991552
}
16001553

@@ -1604,16 +1557,7 @@ public function withQuery(Stringable|string|null $query): UriInterface
16041557

16051558
return match ($query) {
16061559
$this->query => $this,
1607-
default => new self(
1608-
$this->scheme,
1609-
$this->user,
1610-
$this->pass,
1611-
$this->host,
1612-
$this->port,
1613-
$this->path,
1614-
$query,
1615-
$this->fragment,
1616-
),
1560+
default => new self($this->scheme, $this->user, $this->pass, $this->host, $this->port, $this->path, $query, $this->fragment),
16171561
};
16181562
}
16191563

@@ -1623,16 +1567,7 @@ public function withFragment(Stringable|string|null $fragment): UriInterface
16231567

16241568
return match ($fragment) {
16251569
$this->fragment => $this,
1626-
default => new self(
1627-
$this->scheme,
1628-
$this->user,
1629-
$this->pass,
1630-
$this->host,
1631-
$this->port,
1632-
$this->path,
1633-
$this->query,
1634-
$fragment,
1635-
),
1570+
default => new self($this->scheme, $this->user, $this->pass, $this->host, $this->port, $this->path, $this->query, $fragment),
16361571
};
16371572
}
16381573

@@ -1747,10 +1682,8 @@ public function equals(UriInterface|Stringable|string $uri, bool $excludeFragmen
17471682
}
17481683

17491684
/**
1750-
* Normalize an URI by applying non-destructive and destructive normalization
1685+
* Normalize a URI by applying non-destructive and destructive normalization
17511686
* rules as defined in RFC3986 and RFC3987.
1752-
*
1753-
* @see https://wiki.php.net/rfc/url_parsing_api
17541687
*/
17551688
public function normalize(): UriInterface
17561689
{
@@ -1759,7 +1692,12 @@ public function normalize(): UriInterface
17591692
return $this;
17601693
}
17611694

1762-
return self::new(UriString::normalize($uriString));
1695+
$normalizedUriString = UriString::normalize($uriString);
1696+
if ($normalizedUriString === $uriString) {
1697+
return $this;
1698+
}
1699+
1700+
return self::new($normalizedUriString);
17631701
}
17641702

17651703
/**
@@ -1770,8 +1708,6 @@ public function normalize(): UriInterface
17701708
*
17711709
* This method MUST be transparent when dealing with error and exceptions.
17721710
* It MUST not alter or silence them apart from validating its own parameters.
1773-
*
1774-
* @see https://wiki.php.net/rfc/url_parsing_api
17751711
*/
17761712
public function resolve(Stringable|string $uri): UriInterface
17771713
{

0 commit comments

Comments
 (0)