Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 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
 
16
/**
17
 * A RouteCollection represents a set of Route instances.
18
 *
19
 * When adding a route at the end of the collection, an existing route
20
 * with the same name is removed first. So there can only be one route
21
 * with a given name.
22
 *
23
 * @author Fabien Potencier <fabien@symfony.com>
24
 * @author Tobias Schultze <http://tobion.de>
25
 */
26
class RouteCollection implements \IteratorAggregate, \Countable
27
{
28
    /**
29
     * @var Route[]
30
     */
31
    private $routes = [];
32
 
33
    /**
34
     * @var array
35
     */
36
    private $resources = [];
37
 
38
    /**
39
     * @var int[]
40
     */
41
    private $priorities = [];
42
 
43
    public function __clone()
44
    {
45
        foreach ($this->routes as $name => $route) {
46
            $this->routes[$name] = clone $route;
47
        }
48
    }
49
 
50
    /**
51
     * Gets the current RouteCollection as an Iterator that includes all routes.
52
     *
53
     * It implements \IteratorAggregate.
54
     *
55
     * @see all()
56
     *
57
     * @return \ArrayIterator|Route[] An \ArrayIterator object for iterating over routes
58
     */
59
    public function getIterator()
60
    {
61
        return new \ArrayIterator($this->all());
62
    }
63
 
64
    /**
65
     * Gets the number of Routes in this collection.
66
     *
67
     * @return int The number of routes
68
     */
69
    public function count()
70
    {
71
        return \count($this->routes);
72
    }
73
 
74
    /**
75
     * @param int $priority
76
     */
77
    public function add(string $name, Route $route/*, int $priority = 0*/)
78
    {
79
        if (\func_num_args() < 3 && __CLASS__ !== static::class && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface && !$this instanceof \Mockery\MockInterface) {
80
            trigger_deprecation('symfony/routing', '5.1', 'The "%s()" method will have a new "int $priority = 0" argument in version 6.0, not defining it is deprecated.', __METHOD__);
81
        }
82
 
83
        unset($this->routes[$name], $this->priorities[$name]);
84
 
85
        $this->routes[$name] = $route;
86
 
87
        if ($priority = 3 <= \func_num_args() ? func_get_arg(2) : 0) {
88
            $this->priorities[$name] = $priority;
89
        }
90
    }
91
 
92
    /**
93
     * Returns all routes in this collection.
94
     *
95
     * @return Route[] An array of routes
96
     */
97
    public function all()
98
    {
99
        if ($this->priorities) {
100
            $priorities = $this->priorities;
101
            $keysOrder = array_flip(array_keys($this->routes));
102
            uksort($this->routes, static function ($n1, $n2) use ($priorities, $keysOrder) {
103
                return (($priorities[$n2] ?? 0) <=> ($priorities[$n1] ?? 0)) ?: ($keysOrder[$n1] <=> $keysOrder[$n2]);
104
            });
105
        }
106
 
107
        return $this->routes;
108
    }
109
 
110
    /**
111
     * Gets a route by name.
112
     *
113
     * @return Route|null A Route instance or null when not found
114
     */
115
    public function get(string $name)
116
    {
117
        return isset($this->routes[$name]) ? $this->routes[$name] : null;
118
    }
119
 
120
    /**
121
     * Removes a route or an array of routes by name from the collection.
122
     *
123
     * @param string|string[] $name The route name or an array of route names
124
     */
125
    public function remove($name)
126
    {
127
        foreach ((array) $name as $n) {
128
            unset($this->routes[$n], $this->priorities[$n]);
129
        }
130
    }
131
 
132
    /**
133
     * Adds a route collection at the end of the current set by appending all
134
     * routes of the added collection.
135
     */
136
    public function addCollection(self $collection)
137
    {
138
        // we need to remove all routes with the same names first because just replacing them
139
        // would not place the new route at the end of the merged array
140
        foreach ($collection->all() as $name => $route) {
141
            unset($this->routes[$name], $this->priorities[$name]);
142
            $this->routes[$name] = $route;
143
 
144
            if (isset($collection->priorities[$name])) {
145
                $this->priorities[$name] = $collection->priorities[$name];
146
            }
147
        }
148
 
149
        foreach ($collection->getResources() as $resource) {
150
            $this->addResource($resource);
151
        }
152
    }
153
 
154
    /**
155
     * Adds a prefix to the path of all child routes.
156
     */
157
    public function addPrefix(string $prefix, array $defaults = [], array $requirements = [])
158
    {
159
        $prefix = trim(trim($prefix), '/');
160
 
161
        if ('' === $prefix) {
162
            return;
163
        }
164
 
165
        foreach ($this->routes as $route) {
166
            $route->setPath('/'.$prefix.$route->getPath());
167
            $route->addDefaults($defaults);
168
            $route->addRequirements($requirements);
169
        }
170
    }
171
 
172
    /**
173
     * Adds a prefix to the name of all the routes within in the collection.
174
     */
175
    public function addNamePrefix(string $prefix)
176
    {
177
        $prefixedRoutes = [];
178
        $prefixedPriorities = [];
179
 
180
        foreach ($this->routes as $name => $route) {
181
            $prefixedRoutes[$prefix.$name] = $route;
182
            if (null !== $canonicalName = $route->getDefault('_canonical_route')) {
183
                $route->setDefault('_canonical_route', $prefix.$canonicalName);
184
            }
185
            if (isset($this->priorities[$name])) {
186
                $prefixedPriorities[$prefix.$name] = $this->priorities[$name];
187
            }
188
        }
189
 
190
        $this->routes = $prefixedRoutes;
191
        $this->priorities = $prefixedPriorities;
192
    }
193
 
194
    /**
195
     * Sets the host pattern on all routes.
196
     */
197
    public function setHost(?string $pattern, array $defaults = [], array $requirements = [])
198
    {
199
        foreach ($this->routes as $route) {
200
            $route->setHost($pattern);
201
            $route->addDefaults($defaults);
202
            $route->addRequirements($requirements);
203
        }
204
    }
205
 
206
    /**
207
     * Sets a condition on all routes.
208
     *
209
     * Existing conditions will be overridden.
210
     */
211
    public function setCondition(?string $condition)
212
    {
213
        foreach ($this->routes as $route) {
214
            $route->setCondition($condition);
215
        }
216
    }
217
 
218
    /**
219
     * Adds defaults to all routes.
220
     *
221
     * An existing default value under the same name in a route will be overridden.
222
     */
223
    public function addDefaults(array $defaults)
224
    {
225
        if ($defaults) {
226
            foreach ($this->routes as $route) {
227
                $route->addDefaults($defaults);
228
            }
229
        }
230
    }
231
 
232
    /**
233
     * Adds requirements to all routes.
234
     *
235
     * An existing requirement under the same name in a route will be overridden.
236
     */
237
    public function addRequirements(array $requirements)
238
    {
239
        if ($requirements) {
240
            foreach ($this->routes as $route) {
241
                $route->addRequirements($requirements);
242
            }
243
        }
244
    }
245
 
246
    /**
247
     * Adds options to all routes.
248
     *
249
     * An existing option value under the same name in a route will be overridden.
250
     */
251
    public function addOptions(array $options)
252
    {
253
        if ($options) {
254
            foreach ($this->routes as $route) {
255
                $route->addOptions($options);
256
            }
257
        }
258
    }
259
 
260
    /**
261
     * Sets the schemes (e.g. 'https') all child routes are restricted to.
262
     *
263
     * @param string|string[] $schemes The scheme or an array of schemes
264
     */
265
    public function setSchemes($schemes)
266
    {
267
        foreach ($this->routes as $route) {
268
            $route->setSchemes($schemes);
269
        }
270
    }
271
 
272
    /**
273
     * Sets the HTTP methods (e.g. 'POST') all child routes are restricted to.
274
     *
275
     * @param string|string[] $methods The method or an array of methods
276
     */
277
    public function setMethods($methods)
278
    {
279
        foreach ($this->routes as $route) {
280
            $route->setMethods($methods);
281
        }
282
    }
283
 
284
    /**
285
     * Returns an array of resources loaded to build this collection.
286
     *
287
     * @return ResourceInterface[] An array of resources
288
     */
289
    public function getResources()
290
    {
291
        return array_values($this->resources);
292
    }
293
 
294
    /**
295
     * Adds a resource for this collection. If the resource already exists
296
     * it is not added.
297
     */
298
    public function addResource(ResourceInterface $resource)
299
    {
300
        $key = (string) $resource;
301
 
302
        if (!isset($this->resources[$key])) {
303
            $this->resources[$key] = $resource;
304
        }
305
    }
306
}