ILIAS  release_8 Revision v8.24
URLBuilder.php
Go to the documentation of this file.
1<?php
2
18declare(strict_types=1);
19
20namespace ILIAS\UI;
21
23
40{
45 public const URL_MAX_LENGTH = 2048;
49 public const SEPARATOR = '_';
53 private URI $uri;
58 private ?string $fragment = null;
65 private array $params = [];
71 private array $tokens = [];
72
73 public function __construct(URI $uri)
74 {
75 $this->uri = $uri;
76 }
77
81 public function withURI(URI $uri): self
82 {
83 $clone = clone $this;
84 $clone->uri = $uri;
85 return $clone;
86 }
87
91 public function withFragment(?string $fragment): self
92 {
93 $clone = clone $this;
94 $clone->fragment = $fragment;
95 return $clone;
96 }
97
118 public function acquireParameter(array $namespace, string $name, ?string $initial_value = null): array
119 {
120 if ($name === '' || empty($namespace)) {
121 throw new \InvalidArgumentException("Parameter name or namespace not set");
122 }
123
124 $parameter = implode(self::SEPARATOR, $namespace) . self::SEPARATOR . $name;
125 if ($this->parameterExists($parameter)) {
126 throw new \ilException("Parameter '" . $parameter . "' already reserved in URL");
127 }
128
130 $clone = clone $this;
131 $clone->params[$parameter] = ($initial_value) ?? '';
132 $clone->tokens[$parameter] = $token;
133
134 return [$clone, $token];
135 }
136
137 public function acquireParameters(array $namespace, string ...$names): array
138 {
139 $tokens = [];
140 $builder = $this;
141 foreach ($names as $name) {
142 list($builder, $token) = $builder->acquireParameter($namespace, $name);
143 $tokens[] = $token;
144 }
145 array_unshift($tokens, $builder);
146 return $tokens;
147 }
148
153 {
154 $this->checkToken($token);
155 $clone = clone $this;
156 unset($clone->params[$token->getName()]);
157 unset($clone->tokens[$token->getName()]);
158
159 return $clone;
160 }
161
165 public function withParameter(URLBuilderToken $token, $value): self
166 {
167 if(! is_string($value) && ! is_array($value)) {
168 throw new \InvalidArgumentException('Parameter must be of type string or array');
169 }
170 $this->checkToken($token);
171 $clone = clone $this;
172 $clone->params[$token->getName()] = $value;
173
174 return $clone;
175 }
176
185 public function renderTokens(array $tokens): string
186 {
187 $token_render = [];
188 foreach ($tokens as $token) {
189 $token_render[] = '["' . $token->getName() . '",' . $token->render() . ']';
190 }
191 $output = 'new Map([' . implode(',', $token_render) . '])';
192 return $output;
193 }
194
205 public function renderObject(array $tokens): string
206 {
207 $output = 'new il.UI.core.URLBuilder(new URL("' . $this->buildURI() . '"), ' . $this->renderTokens($tokens) . ')';
208 return $output;
209 }
210
214 public function buildURI(): URI
215 {
216 $uri = new URI($this->uri->getBaseURI() . $this->buildQuery() . $this->buildFragment());
217 $this->checkLength($uri);
218 return $uri;
219 }
220
227 private function buildQuery(): string
228 {
229 $params = array_merge($this->uri->getParameters(), $this->params);
230 $query = (! empty($params)) ? '?' . http_build_query($params) : '';
231 $query = preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', $query);
232 return $query;
233 }
234
238 private function buildFragment(): string
239 {
240 if ($this->fragment !== null) {
241 return ($this->fragment !== '') ? '#' . $this->fragment : '';
242 }
243 $fragment = ($this->uri->getFragment()) ? '#' . $this->uri->getFragment() : '';
244 return $fragment;
245 }
246
250 private function parameterExists(string $name): bool
251 {
252 return array_key_exists($name, $this->params);
253 }
254
261 private function checkToken(URLBuilderToken $token): void
262 {
263 if (! in_array($token, $this->tokens)
264 || $this->tokens[$token->getName()]->getToken() !== $token->getToken()) {
265 throw new \DomainException("Token for '" . $token->getName() . "' is not valid");
266 }
267 if (! $this->parameterExists($token->getName())) {
268 throw new \ilException("Parameter '" . $token->getName() . "' does not exist in URL");
269 }
270 }
271
277 private function checkLength(URI $uri): void
278 {
279 if (! (strlen((string) $uri) <= self::URL_MAX_LENGTH)) {
280 throw new \LengthException("The final URL is longer than " . self::URL_MAX_LENGTH . " and will not be valid.");
281 }
282 }
283}
The scope of this class is split ilias-conform URI's into components.
Definition: URI.php:35
getName()
Get the full name of the token including its namespace.
__construct(URI $uri)
Definition: URLBuilder.php:73
withParameter(URLBuilderToken $token, $value)
Change an acquired parameter's value if the supplied token is valid.
Definition: URLBuilder.php:165
buildFragment()
Create the fragment/hash part of the URL.
Definition: URLBuilder.php:238
buildQuery()
Create the query part of the URL from all parameters Claimed parameters overwrite base parameters in ...
Definition: URLBuilder.php:227
renderTokens(array $tokens)
Renders a Javascript Map of all given tokens.
Definition: URLBuilder.php:185
withURI(URI $uri)
Changes the base URI of the Builder.
Definition: URLBuilder.php:81
parameterExists(string $name)
Check if parameter was already acquired.
Definition: URLBuilder.php:250
array $tokens
Stores all generated tokens for acquired parameters.
Definition: URLBuilder.php:71
acquireParameters(array $namespace, string ... $names)
Definition: URLBuilder.php:137
buildURI()
Get a URI representation of the full URL including query string and fragment/hash.
Definition: URLBuilder.php:214
withFragment(?string $fragment)
Change the fragment/hash part of the URL.
Definition: URLBuilder.php:91
array $params
Stores all acquired parameters These always take precedence over existing parameters in the base URI.
Definition: URLBuilder.php:65
checkToken(URLBuilderToken $token)
Check if a token is valid.
Definition: URLBuilder.php:261
deleteParameter(URLBuilderToken $token)
Delete an acquired parameter if the supplied token is valid.
Definition: URLBuilder.php:152
string $fragment
Stores the URL fragment/hash (#) (always changeable due to its usage)
Definition: URLBuilder.php:58
renderObject(array $tokens)
Renders a Javascript URLBuilder object with changeable parameters for all given tokens.
Definition: URLBuilder.php:205
const SEPARATOR
Separator for parts of a parameter's namespace.
Definition: URLBuilder.php:49
acquireParameter(array $namespace, string $name, ?string $initial_value=null)
Add a new parameter with a namespace and get its token for subsequent changes.
Definition: URLBuilder.php:118
URI $uri
Base URI for the URLBuilder.
Definition: URLBuilder.php:53
const URL_MAX_LENGTH
A maximum length of 2048 characters should be safe to use in most browsers, even though longer URLs w...
Definition: URLBuilder.php:45
checkLength(URI $uri)
Check the full length of the URI against URL_MAX_LENGTH.
Definition: URLBuilder.php:277
if($err=$client->getError()) $namespace
if($format !==null) $name
Definition: metadata.php:247
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$query
$token
Definition: xapitoken.php:70