UriTemplate.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <?php
  2. /**
  3. * League.Uri (https://uri.thephpleague.com)
  4. *
  5. * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. declare(strict_types=1);
  11. namespace League\Uri;
  12. use League\Uri\Contracts\UriException;
  13. use League\Uri\Contracts\UriInterface;
  14. use League\Uri\Exceptions\SyntaxError;
  15. use League\Uri\UriTemplate\Template;
  16. use League\Uri\UriTemplate\TemplateCanNotBeExpanded;
  17. use League\Uri\UriTemplate\VariableBag;
  18. use Stringable;
  19. use function array_fill_keys;
  20. use function array_key_exists;
  21. /**
  22. * Defines the URI Template syntax and the process for expanding a URI Template into a URI reference.
  23. *
  24. * @link https://tools.ietf.org/html/rfc6570
  25. * @package League\Uri
  26. * @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
  27. * @since 6.1.0
  28. */
  29. final class UriTemplate
  30. {
  31. private readonly Template $template;
  32. private readonly VariableBag $defaultVariables;
  33. /**
  34. * @throws SyntaxError if the template syntax is invalid
  35. * @throws TemplateCanNotBeExpanded if the template or the variables are invalid
  36. */
  37. public function __construct(Stringable|string $template, iterable $defaultVariables = [])
  38. {
  39. $this->template = $template instanceof Template ? $template : Template::new($template);
  40. $this->defaultVariables = $this->filterVariables($defaultVariables);
  41. }
  42. private function filterVariables(iterable $variables): VariableBag
  43. {
  44. if (!$variables instanceof VariableBag) {
  45. $variables = new VariableBag($variables);
  46. }
  47. return $variables
  48. ->filter(fn ($value, string|int $name) => array_key_exists(
  49. $name,
  50. array_fill_keys($this->template->variableNames, 1)
  51. ));
  52. }
  53. public function getTemplate(): string
  54. {
  55. return $this->template->value;
  56. }
  57. /**
  58. * @return array<string>
  59. */
  60. public function getVariableNames(): array
  61. {
  62. return $this->template->variableNames;
  63. }
  64. public function getDefaultVariables(): array
  65. {
  66. return iterator_to_array($this->defaultVariables);
  67. }
  68. /**
  69. * Returns a new instance with the updated default variables.
  70. *
  71. * This method MUST retain the state of the current instance, and return
  72. * an instance that contains the modified default variables.
  73. *
  74. * If present, variables whose name is not part of the current template
  75. * possible variable names are removed.
  76. *
  77. * @throws TemplateCanNotBeExpanded if the variables are invalid
  78. */
  79. public function withDefaultVariables(iterable $defaultVariables): self
  80. {
  81. $defaultVariables = $this->filterVariables($defaultVariables);
  82. if ($defaultVariables == $this->defaultVariables) {
  83. return $this;
  84. }
  85. return new self($this->template, $defaultVariables);
  86. }
  87. /**
  88. * @throws TemplateCanNotBeExpanded if the variables are invalid
  89. * @throws UriException if the resulting expansion cannot be converted to a UriInterface instance
  90. */
  91. public function expand(iterable $variables = []): UriInterface
  92. {
  93. return Uri::new($this->template->expand(
  94. $this->filterVariables($variables)->replace($this->defaultVariables)
  95. ));
  96. }
  97. /**
  98. * @throws TemplateCanNotBeExpanded if the variables are invalid or missing
  99. * @throws UriException if the resulting expansion cannot be converted to a UriInterface instance
  100. */
  101. public function expandOrFail(iterable $variables = []): UriInterface
  102. {
  103. return Uri::new($this->template->expandOrFail(
  104. $this->filterVariables($variables)->replace($this->defaultVariables)
  105. ));
  106. }
  107. }