diff --git a/src/Factory/UriFactory.php b/src/Factory/UriFactory.php index 74ab377..077fec9 100644 --- a/src/Factory/UriFactory.php +++ b/src/Factory/UriFactory.php @@ -27,6 +27,8 @@ class UriFactory implements UriFactoryInterface { + public const URI_CLASS = Uri::class; + /** * {@inheritdoc} */ @@ -47,7 +49,7 @@ public function createUri(string $uri = ''): UriInterface $query = $parts['query'] ?? ''; $fragment = $parts['fragment'] ?? ''; - return new Uri($scheme, $host, $port, $path, $query, $fragment, $user, $pass); + return $this->makeUriObject($scheme, $host, $port, $path, $query, $fragment, $user, $pass); } /** @@ -108,6 +110,19 @@ public function createFromGlobals(array $globals): Uri } // Build Uri and return - return new Uri($scheme, $host, $port, $requestUri, $queryString, '', $username, $password); + return $this->makeUriObject($scheme, $host, $port, $requestUri, $queryString, '', $username, $password); + } + + protected function makeUriObject( + string $scheme, + string $host, + ?int $port = null, + string $path = '/', + string $query = '', + string $fragment = '', + string $user = '', + string $password = '' + ): Uri { + return new (static::URI_CLASS)($scheme, $host, $port, $path, $query, $fragment, $user, $password); } } diff --git a/src/Uri.php b/src/Uri.php index 6f51d7f..ba83ef7 100644 --- a/src/Uri.php +++ b/src/Uri.php @@ -129,6 +129,11 @@ protected function filterScheme($scheme): string throw new InvalidArgumentException('Uri scheme must be a string.'); } + // In case the supported schemes list is null, do no filtering. + if (null === static::SUPPORTED_SCHEMES) { + return $scheme; + } + $scheme = str_replace('://', '', strtolower($scheme)); if (!key_exists($scheme, static::SUPPORTED_SCHEMES)) { throw new InvalidArgumentException( @@ -286,6 +291,9 @@ public function withPort($port): UriInterface */ protected function hasStandardPort(): bool { + if (!isset(static::SUPPORTED_SCHEMES[$this->scheme])) { + return null === $this->port; + } return static::SUPPORTED_SCHEMES[$this->scheme] === $this->port; } diff --git a/tests/Factory/UriFactoryTest.php b/tests/Factory/UriFactoryTest.php index 1927569..1f8114e 100644 --- a/tests/Factory/UriFactoryTest.php +++ b/tests/Factory/UriFactoryTest.php @@ -13,6 +13,7 @@ use Interop\Http\Factory\UriFactoryTestCase; use Slim\Psr7\Environment; use Slim\Psr7\Factory\UriFactory; +use Slim\Psr7\Uri; class UriFactoryTest extends UriFactoryTestCase { @@ -240,4 +241,84 @@ public function testUriDistinguishZeroFromEmptyString() $expected = 'https://0:0@0:1/0?0#0'; $this->assertSame($expected, (string) $this->createUriFactory()->createUri($expected)); } + + public function testEnableInheritedUriObjectUsingInheritanceOfFactory() + { + $factory = new class () extends UriFactory { + protected function makeUriObject( + string $scheme, + string $host, + ?int $port = null, + string $path = '/', + string $query = '', + string $fragment = '', + string $user = '', + string $password = '' + ): Uri { + return new class ( + $scheme, + $host, + $port, + $path, + $query, + $fragment, + $user, + $password, + ) extends Uri { + }; + } + }; + + $uri = $factory->createUri(''); + $this->assertInstanceOf(Uri::class, $uri); + $this->assertNotSame(Uri::class, get_class($uri)); + } + + public function testEnableNoUriSchemeFilteringThroughInheritance() + { + $factory = new class () extends UriFactory { + protected function makeUriObject( + string $scheme, + string $host, + ?int $port = null, + string $path = '/', + string $query = '', + string $fragment = '', + string $user = '', + string $password = '' + ): Uri { + return new class ( + $scheme, + $host, + $port, + $path, + $query, + $fragment, + $user, + $password, + ) extends Uri { + public const SUPPORTED_SCHEMES = null; + }; + } + }; + + // The following are all valid URIs + (function () use ($factory) { + $uri = $factory->createUri('smtp://smtp.dakujem.dev:25'); + $this->assertEquals('smtp', $uri->getScheme()); + })(); + (function () use ($factory) { + $uri = $factory->createUri('tel:+1-816-555-1212'); + $this->assertEquals('tel', $uri->getScheme()); + $this->assertEquals('+1-816-555-1212', $uri->getPath()); + })(); + (function () use ($factory) { + $uri = $factory->createUri('ftp://ftp.is.co.za/rfc/rfc1808.txt'); + $this->assertEquals('ftp', $uri->getScheme()); + })(); + (function () use ($factory) { + $uri = $factory->createUri('ldap://[2001:db8::7]/c=GB?objectClass?one'); + $this->assertEquals('ldap', $uri->getScheme()); + })(); + } } diff --git a/tests/UriTest.php b/tests/UriTest.php index aeb3a85..fb84d8b 100644 --- a/tests/UriTest.php +++ b/tests/UriTest.php @@ -43,6 +43,14 @@ public function testSupportOtherSchemes() $this->assertEquals('ws', $wsUri->getScheme()); } + public function testSupportNoSchemeFilteringUsingInheritance() + { + $uri = new class ('whatever', 'example.com') extends Uri { + public const SUPPORTED_SCHEMES = null; + }; + $this->assertEquals('whatever', $uri->getScheme()); + } + public function testGetScheme() { $this->assertEquals('https', $this->uriFactory()->getScheme()); @@ -170,6 +178,35 @@ public function testGetPortWithSchemeAndDefaultPort() $this->assertNull($uriHttps->getPort()); } + public function testGetPortWithoutSchemeOrStandardPort() + { + $uri = new Uri('', 'www.example.com', 80); + + $this->assertEquals(80, $uri->getPort()); + } + + public function testSupportNoSchemeWithStandardPort() + { + $uri = new class ('', 'example.com', 80) extends Uri { + public const SUPPORTED_SCHEMES = [ + '' => 80, + ]; + }; + + $this->assertNull($uri->getPort()); + } + + public function testSupportNoSchemeWithoutStandardPort() + { + $uri = new class ('', 'example.com', 1234) extends Uri { + public const SUPPORTED_SCHEMES = [ + '' => 80, + ]; + }; + + $this->assertEquals(1234, $uri->getPort()); + } + public function testGetPortWithoutSchemeAndPort() { $uri = new Uri('', 'www.example.com');