Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.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
 
12
namespace Symfony\Component\Routing;
13
 
14
use Symfony\Component\Config\Resource\ResourceInterface;
15
use Symfony\Component\Routing\Exception\InvalidArgumentException;
16
use Symfony\Component\Routing\Exception\RouteCircularReferenceException;
17
 
18
/**
19
 * A RouteCollection represents a set of Route instances.
20
 *
21
 * When adding a route at the end of the collection, an existing route
22
 * with the same name is removed first. So there can only be one route
23
 * with a given name.
24
 *
25
 * @author Fabien Potencier <fabien@symfony.com>
26
 * @author Tobias Schultze <http://tobion.de>
27
 *
28
 * @implements \IteratorAggregate<string, Route>
29
 */
30
class RouteCollection implements \IteratorAggregate, \Countable
31
{
32
    /**
33
     * @var array<string, Route>
34
     */
35
    private array $routes = [];
36
 
37
    /**
38
     * @var array<string, Alias>
39
     */
40
    private $aliases = [];
41
 
42
    /**
43
     * @var array<string, ResourceInterface>
44
     */
45
    private array $resources = [];
46
 
47
    /**
48
     * @var array<string, int>
49
     */
50
    private array $priorities = [];
51
 
52
    public function __clone()
53
    {
54
        foreach ($this->routes as $name => $route) {
55
            $this->routes[$name] = clone $route;
56
        }
57
 
58
        foreach ($this->aliases as $name => $alias) {
59
            $this->aliases[$name] = clone $alias;
60
        }
61
    }
62
 
63
    /**
64
     * Gets the current RouteCollection as an Iterator that includes all routes.
65
     *
66
     * It implements \IteratorAggregate.
67
     *
68
     * @see all()
69
     *
70
     * @return \ArrayIterator<string, Route>
71
     */
72
    public function getIterator(): \ArrayIterator
73
    {
74
        return new \ArrayIterator($this->all());
75
    }
76
 
77
    /**
78
     * Gets the number of Routes in this collection.
79
     */
80
    public function count(): int
81
    {
82
        return \count($this->routes);
83
    }
84
 
85
    public function add(string $name, Route $route, int $priority = 0)
86
    {
87
        unset($this->routes[$name], $this->priorities[$name], $this->aliases[$name]);
88
 
89
        $this->routes[$name] = $route;
90
 
91
        if ($priority) {
92
            $this->priorities[$name] = $priority;
93
        }
94
    }
95
 
96
    /**
97
     * Returns all routes in this collection.
98
     *
99
     * @return array<string, Route>
100
     */
101
    public function all(): array
102
    {
103
        if ($this->priorities) {
104
            $priorities = $this->priorities;
105
            $keysOrder = array_flip(array_keys($this->routes));
106
            uksort($this->routes, static function ($n1, $n2) use ($priorities, $keysOrder) {
107
                return (($priorities[$n2] ?? 0) <=> ($priorities[$n1] ?? 0)) ?: ($keysOrder[$n1] <=> $keysOrder[$n2]);
108
            });
109
        }
110
 
111
        return $this->routes;
112
    }
113
 
114
    /**
115
     * Gets a route by name.
116
     */
117
    public function get(string $name): ?Route
118
    {
119
        $visited = [];
120
        while (null !== $alias = $this->aliases[$name] ?? null) {
121
            if (false !== $searchKey = array_search($name, $visited)) {
122
                $visited[] = $name;
123
 
124
                throw new RouteCircularReferenceException($name, \array_slice($visited, $searchKey));
125
            }
126
 
127
            if ($alias->isDeprecated()) {
128
                $deprecation = $alias->getDeprecation($name);
129
 
130
                trigger_deprecation($deprecation['package'], $deprecation['version'], $deprecation['message']);
131
            }
132
 
133
            $visited[] = $name;
134
            $name = $alias->getId();
135
        }
136
 
137
        return $this->routes[$name] ?? null;
138
    }
139
 
140
    /**
141
     * Removes a route or an array of routes by name from the collection.
142
     *
143
     * @param string|string[] $name The route name or an array of route names
144
     */
145
    public function remove(string|array $name)
146
    {
147
        foreach ((array) $name as $n) {
148
            unset($this->routes[$n], $this->priorities[$n], $this->aliases[$n]);
149
        }
150
    }
151
 
152
    /**
153
     * Adds a route collection at the end of the current set by appending all
154
     * routes of the added collection.
155
     */
156
    public function addCollection(self $collection)
157
    {
158
        // we need to remove all routes with the same names first because just replacing them
159
        // would not place the new route at the end of the merged array
160
        foreach ($collection->all() as $name => $route) {
161
            unset($this->routes[$name], $this->priorities[$name], $this->aliases[$name]);
162
            $this->routes[$name] = $route;
163
 
164
            if (isset($collection->priorities[$name])) {
165
                $this->priorities[$name] = $collection->priorities[$name];
166
            }
167
        }
168
 
169
        foreach ($collection->getAliases() as $name => $alias) {
170
            unset($this->routes[$name], $this->priorities[$name], $this->aliases[$name]);
171
 
172
            $this->aliases[$name] = $alias;
173
        }
174
 
175
        foreach ($collection->getResources() as $resource) {
176
            $this->addResource($resource);
177
        }
178
    }
179
 
180
    /**
181
     * Adds a prefix to the path of all child routes.
182
     */
183
    public function addPrefix(string $prefix, array $defaults = [], array $requirements = [])
184
    {
185
        $prefix = trim(trim($prefix), '/');
186
 
187
        if ('' === $prefix) {
188
            return;
189
        }
190
 
191
        foreach ($this->routes as $route) {
192
            $route->setPath('/'.$prefix.$route->getPath());
193
            $route->addDefaults($defaults);
194
            $route->addRequirements($requirements);
195
        }
196
    }
197
 
198
    /**
199
     * Adds a prefix to the name of all the routes within in the collection.
200
     */
201
    public function addNamePrefix(string $prefix)
202
    {
203
        $prefixedRoutes = [];
204
        $prefixedPriorities = [];
205
        $prefixedAliases = [];
206
 
207
        foreach ($this->routes as $name => $route) {
208
            $prefixedRoutes[$prefix.$name] = $route;
209
            if (null !== $canonicalName = $route->getDefault('_canonical_route')) {
210
                $route->setDefault('_canonical_route', $prefix.$canonicalName);
211
            }
212
            if (isset($this->priorities[$name])) {
213
                $prefixedPriorities[$prefix.$name] = $this->priorities[$name];
214
            }
215
        }
216
 
217
        foreach ($this->aliases as $name => $alias) {
218
            $prefixedAliases[$prefix.$name] = $alias->withId($prefix.$alias->getId());
219
        }
220
 
221
        $this->routes = $prefixedRoutes;
222
        $this->priorities = $prefixedPriorities;
223
        $this->aliases = $prefixedAliases;
224
    }
225
 
226
    /**
227
     * Sets the host pattern on all routes.
228
     */
229
    public function setHost(?string $pattern, array $defaults = [], array $requirements = [])
230
    {
231
        foreach ($this->routes as $route) {
232
            $route->setHost($pattern);
233
            $route->addDefaults($defaults);
234
            $route->addRequirements($requirements);
235
        }
236
    }
237
 
238
    /**
239
     * Sets a condition on all routes.
240
     *
241
     * Existing conditions will be overridden.
242
     */
243
    public function setCondition(?string $condition)
244
    {
245
        foreach ($this->routes as $route) {
246
            $route->setCondition($condition);
247
        }
248
    }
249
 
250
    /**
251
     * Adds defaults to all routes.
252
     *
253
     * An existing default value under the same name in a route will be overridden.
254
     */
255
    public function addDefaults(array $defaults)
256
    {
257
        if ($defaults) {
258
            foreach ($this->routes as $route) {
259
                $route->addDefaults($defaults);
260
            }
261
        }
262
    }
263
 
264
    /**
265
     * Adds requirements to all routes.
266
     *
267
     * An existing requirement under the same name in a route will be overridden.
268
     */
269
    public function addRequirements(array $requirements)
270
    {
271
        if ($requirements) {
272
            foreach ($this->routes as $route) {
273
                $route->addRequirements($requirements);
274
            }
275
        }
276
    }
277
 
278
    /**
279
     * Adds options to all routes.
280
     *
281
     * An existing option value under the same name in a route will be overridden.
282
     */
283
    public function addOptions(array $options)
284
    {
285
        if ($options) {
286
            foreach ($this->routes as $route) {
287
                $route->addOptions($options);
288
            }
289
        }
290
    }
291
 
292
    /**
293
     * Sets the schemes (e.g. 'https') all child routes are restricted to.
294
     *
295
     * @param string|string[] $schemes The scheme or an array of schemes
296
     */
297
    public function setSchemes(string|array $schemes)
298
    {
299
        foreach ($this->routes as $route) {
300
            $route->setSchemes($schemes);
301
        }
302
    }
303
 
304
    /**
305
     * Sets the HTTP methods (e.g. 'POST') all child routes are restricted to.
306
     *
307
     * @param string|string[] $methods The method or an array of methods
308
     */
309
    public function setMethods(string|array $methods)
310
    {
311
        foreach ($this->routes as $route) {
312
            $route->setMethods($methods);
313
        }
314
    }
315
 
316
    /**
317
     * Returns an array of resources loaded to build this collection.
318
     *
319
     * @return ResourceInterface[]
320
     */
321
    public function getResources(): array
322
    {
323
        return array_values($this->resources);
324
    }
325
 
326
    /**
327
     * Adds a resource for this collection. If the resource already exists
328
     * it is not added.
329
     */
330
    public function addResource(ResourceInterface $resource)
331
    {
332
        $key = (string) $resource;
333
 
334
        if (!isset($this->resources[$key])) {
335
            $this->resources[$key] = $resource;
336
        }
337
    }
338
 
339
    /**
340
     * Sets an alias for an existing route.
341
     *
342
     * @param string $name  The alias to create
343
     * @param string $alias The route to alias
344
     *
345
     * @throws InvalidArgumentException if the alias is for itself
346
     */
347
    public function addAlias(string $name, string $alias): Alias
348
    {
349
        if ($name === $alias) {
350
            throw new InvalidArgumentException(sprintf('Route alias "%s" can not reference itself.', $name));
351
        }
352
 
353
        unset($this->routes[$name], $this->priorities[$name]);
354
 
355
        return $this->aliases[$name] = new Alias($alias);
356
    }
357
 
358
    /**
359
     * @return array<string, Alias>
360
     */
361
    public function getAliases(): array
362
    {
363
        return $this->aliases;
364
    }
365
 
366
    public function getAlias(string $name): ?Alias
367
    {
368
        return $this->aliases[$name] ?? null;
369
    }
370
}