Skip to content

Commit

Permalink
Improve URI test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Jun 23, 2023
1 parent c8e916a commit a73b0f5
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 139 deletions.
11 changes: 11 additions & 0 deletions FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,15 @@ public function testCreateFromComponentsWithNullPath(): void
{
self::assertSame('', Uri::fromComponents(['path' => null])->toString());
}

public function testICanBeInstantiateFromRFC6750(): void
{
$template = 'https://example.com/hotels/{hotel}/bookings/{booking}';
$params = ['booking' => '42', 'hotel' => 'Rest & Relax'];

self::assertSame(
'/hotels/Rest%20%26%20Relax/bookings/42',
Uri::fromTemplate($template, $params)->getPath()
);
}
}
11 changes: 11 additions & 0 deletions HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,15 @@ public function testItPreservesMultipleLeadingSlashesOnMutation(): void
self::assertSame('https://www.example.com///google.com', (string) $modifiedUri2);
self::assertSame('/google.com', $modifiedUri2->getPath());
}

public function testICanBeInstantiateFromRFC6750(): void
{
$template = 'https://example.com/hotels/{hotel}/bookings/{booking}';
$params = ['booking' => '42', 'hotel' => 'Rest & Relax'];

self::assertSame(
'/hotels/Rest%20%26%20Relax/bookings/42',
Http::fromTemplate($template, $params)->getPath()
);
}
}
85 changes: 47 additions & 38 deletions Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace League\Uri;

use finfo;
use League\Uri\Contracts\UriComponentInterface;
use League\Uri\Contracts\UriInterface;
use League\Uri\Exceptions\FileinfoSupportMissing;
use League\Uri\Exceptions\IdnaConversionFailed;
Expand Down Expand Up @@ -397,35 +398,6 @@ public static function new(Stringable|string $uri = ''): self
);
}

/**
* Create a new instance from a hash representation of the URI similar
* to PHP parse_url function result.
*
* @param InputComponentMap $components a hash representation of the URI similar to PHP parse_url function result
*/
public static function fromComponents(array $components = []): self
{
$components += [
'scheme' => null, 'user' => null, 'pass' => null, 'host' => null,
'port' => null, 'path' => '', 'query' => null, 'fragment' => null,
];

if (null === $components['path']) {
$components['path'] = '';
}

return new self(
$components['scheme'],
$components['user'],
$components['pass'],
$components['host'],
$components['port'],
$components['path'],
$components['query'],
$components['fragment']
);
}

/**
* Creates a new instance from a URI and a Base URI.
*
Expand Down Expand Up @@ -466,6 +438,45 @@ public static function fromBaseUri(Stringable|String $uri, Stringable|String|nul
return $uri;
}

/**
* Creates a new instance from a template.
*/
public static function fromTemplate(Stringable|string $template, iterable $variables = []): self
{
return self::new(
UriTemplate\Template::new($template)->expand($variables)
);
}

/**
* Create a new instance from a hash representation of the URI similar
* to PHP parse_url function result.
*
* @param InputComponentMap $components a hash representation of the URI similar to PHP parse_url function result
*/
public static function fromComponents(array $components = []): self
{
$components += [
'scheme' => null, 'user' => null, 'pass' => null, 'host' => null,
'port' => null, 'path' => '', 'query' => null, 'fragment' => null,
];

if (null === $components['path']) {
$components['path'] = '';
}

return new self(
$components['scheme'],
$components['user'],
$components['pass'],
$components['host'],
$components['port'],
$components['path'],
$components['query'],
$components['fragment']
);
}

/**
* Create a new instance from a data file path.
*
Expand Down Expand Up @@ -562,14 +573,6 @@ public static function fromServer(array $server): self
return Uri::fromComponents($components);
}

/**
* Creates a new instance from a template.
*/
public static function fromTemplate(Stringable|string $template, iterable $variables = []): self
{
return self::new(UriTemplate\Template::new($template)->expand($variables));
}

/**
* Returns the environment scheme.
*/
Expand Down Expand Up @@ -1094,6 +1097,10 @@ public function withScheme(Stringable|string|null $scheme): UriInterface
*/
private function filterString(Stringable|string|null $str): ?string
{
if ($str instanceof UriComponentInterface) {
$str = $str->value();
}

if (null === $str) {
return null;
}
Expand Down Expand Up @@ -1164,8 +1171,10 @@ public function withPort(int|null $port): UriInterface

public function withPath(Stringable|string $path): UriInterface
{
/** @var string $path */
$path = $this->filterString($path);
if (null === $path) {
throw new SyntaxError('The path component can not be null.');
}
$path = $this->formatPath($path);
if ($path === $this->path) {
return $this;
Expand Down
11 changes: 4 additions & 7 deletions UriInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ public static function isSameDocument(Stringable|string $uri, Stringable|string
$uri = self::normalize(self::filterUri($uri));
$baseUri = self::normalize(self::filterUri($baseUri));

return (string) $uri->withFragment($uri instanceof Psr7UriInterface ? '' : null)
=== (string) $baseUri->withFragment($baseUri instanceof Psr7UriInterface ? '' : null);
return (string) $uri->withFragment(self::emptyComponentValue($uri))
=== (string) $baseUri->withFragment(self::emptyComponentValue($baseUri));
}

/**
Expand Down Expand Up @@ -179,11 +179,8 @@ public static function getOrigin(Stringable|string $uri): ?string
*/
public static function isCrossOrigin(Stringable|string $uri, Stringable|string $baseUri): bool
{
$uri = self::filterUri($uri);
$baseUri = self::filterUri($baseUri);

return null === ($uriString = self::getOrigin(Uri::new($uri)))
|| null === ($baseUriString = self::getOrigin(Uri::new($baseUri)))
return null === ($uriString = self::getOrigin(Uri::new(self::filterUri($uri))))
|| null === ($baseUriString = self::getOrigin(Uri::new(self::filterUri($baseUri))))
|| $uriString !== $baseUriString;
}
}
38 changes: 23 additions & 15 deletions UriTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use League\Uri\UriTemplate\Template;
use League\Uri\UriTemplate\VariableBag;
use Stringable;
use function array_fill_keys;
use function array_key_exists;

/**
* Defines the URI Template syntax and the process for expanding a URI Template into a URI reference.
Expand All @@ -28,9 +30,6 @@
* @package League\Uri
* @author Ignace Nyamagana Butera <[email protected]>
* @since 6.1.0
*
* Based on GuzzleHttp\UriTemplate class in Guzzle v6.5.
* @link https://github.com/guzzle/guzzle/blob/6.5/src/UriTemplate.php
*/
final class UriTemplate
{
Expand All @@ -39,12 +38,22 @@ final class UriTemplate

/**
* @throws SyntaxError if the template syntax is invalid
* @throws TemplateCanNotBeExpanded if the template variables are invalid
* @throws TemplateCanNotBeExpanded if the template or the variables are invalid
*/
public function __construct(Template|Stringable|string $template, iterable $defaultVariables = [])
{
$this->template = $template instanceof Template ? $template : Template::new($template);
$this->defaultVariables = VariableBag::fromTemplate($this->template, $defaultVariables);
$this->defaultVariables = $this->filterVariables($defaultVariables);
}

private function filterVariables(iterable $variables): VariableBag
{
if (!$variables instanceof VariableBag) {
$variables = new VariableBag($variables);
}
$variablesNames = array_fill_keys($this->template->variableNames, 1);

return $variables->filter(fn ($value, string|int $name) => array_key_exists($name, $variablesNames));
}

/**
Expand All @@ -55,42 +64,41 @@ public function __construct(Template|Stringable|string $template, iterable $defa
*
* If present, variables whose name is not part of the current template
* possible variable names are removed.
*
* @throws TemplateCanNotBeExpanded if the variables are invalid
*/
public function withDefaultVariables(iterable $defaultVariables): self
{
$variables = VariableBag::fromTemplate($this->template, $defaultVariables);
if ($variables == $this->defaultVariables) {
$defaultVariables = $this->filterVariables($defaultVariables);
if ($defaultVariables == $this->defaultVariables) {
return $this;
}

return new self($this->template, $defaultVariables);
}

/**
* @throws TemplateCanNotBeExpanded if the variable contains nested array values
* @throws TemplateCanNotBeExpanded if the variables are invalid
* @throws UriException if the resulting expansion can not be converted to a UriInterface instance
*/
public function expand(iterable $variables = []): UriInterface
{
return Uri::new(
$this->template->expand(
VariableBag::fromTemplate($this->template, $variables)
->replace($this->defaultVariables)
$this->filterVariables($variables)->replace($this->defaultVariables)
)
);
}

/**
* @throws TemplateCanNotBeExpanded if the expansion fails
* @throws TemplateCanNotBeExpanded if the variable contains nested array values
* @throws TemplateCanNotBeExpanded if the variables are invalid or missing
* @throws UriException if the resulting expansion can not be converted to a UriInterface instance
*/
public function expandOrFail(iterable $variables): UriInterface
public function expandOrFail(iterable $variables = []): UriInterface
{
return Uri::new(
$this->template->expandOrFail(
VariableBag::fromTemplate($this->template, $variables)
->replace($this->defaultVariables)
$this->filterVariables($variables)->replace($this->defaultVariables)
)
);
}
Expand Down
Loading

0 comments on commit a73b0f5

Please sign in to comment.