1<?php 2 3/** 4 * League.Uri (https://uri.thephpleague.com) 5 * 6 * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12declare(strict_types=1); 13 14namespace League\Uri\UriTemplate; 15 16use League\Uri\Exceptions\TemplateCanNotBeExpanded; 17use function gettype; 18use function is_array; 19use function is_bool; 20use function is_object; 21use function is_scalar; 22use function method_exists; 23use function sprintf; 24 25final class VariableBag 26{ 27 /** 28 * @var array<string,string|array<string>> 29 */ 30 private $variables = []; 31 32 /** 33 * @param iterable<string,mixed> $variables 34 */ 35 public function __construct(iterable $variables = []) 36 { 37 foreach ($variables as $name => $value) { 38 $this->assign($name, $value); 39 } 40 } 41 42 public static function __set_state(array $properties): self 43 { 44 return new self($properties['variables']); 45 } 46 47 /** 48 * @return array<string,string|array<string>> 49 */ 50 public function all(): array 51 { 52 return $this->variables; 53 } 54 55 /** 56 * Fetches the variable value if none found returns null. 57 * 58 * @return null|string|array<string> 59 */ 60 public function fetch(string $name) 61 { 62 return $this->variables[$name] ?? null; 63 } 64 65 /** 66 * @param string|array<string> $value 67 */ 68 public function assign(string $name, $value): void 69 { 70 $this->variables[$name] = $this->normalizeValue($value, $name, true); 71 } 72 73 /** 74 * @param mixed $value the value to be expanded 75 * 76 * @throws TemplateCanNotBeExpanded if the value contains nested list 77 * 78 * @return string|array<string> 79 */ 80 private function normalizeValue($value, string $name, bool $isNestedListAllowed) 81 { 82 if (is_bool($value)) { 83 return true === $value ? '1' : '0'; 84 } 85 86 if (null === $value || is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) { 87 return (string) $value; 88 } 89 90 if (!is_array($value)) { 91 throw new \TypeError(sprintf('The variable '.$name.' must be NULL, a scalar or a stringable object `%s` given', gettype($value))); 92 } 93 94 if (!$isNestedListAllowed) { 95 throw TemplateCanNotBeExpanded::dueToNestedListOfValue($name); 96 } 97 98 foreach ($value as &$var) { 99 $var = self::normalizeValue($var, $name, false); 100 } 101 unset($var); 102 103 return $value; 104 } 105 106 /** 107 * Replaces elements from passed variables into the current instance. 108 */ 109 public function replace(VariableBag $variables): self 110 { 111 $instance = clone $this; 112 $instance->variables += $variables->variables; 113 114 return $instance; 115 } 116} 117