Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Routing;
4
 
5
use ArrayIterator;
6
use Countable;
7
use Illuminate\Http\Request;
8
use Illuminate\Http\Response;
9
use Illuminate\Support\Str;
10
use IteratorAggregate;
11
use LogicException;
12
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
13
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
14
use Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper;
15
use Symfony\Component\Routing\RouteCollection as SymfonyRouteCollection;
16
use Traversable;
17
 
18
abstract class AbstractRouteCollection implements Countable, IteratorAggregate, RouteCollectionInterface
19
{
20
    /**
21
     * Handle the matched route.
22
     *
23
     * @param  \Illuminate\Http\Request  $request
24
     * @param  \Illuminate\Routing\Route|null  $route
25
     * @return \Illuminate\Routing\Route
26
     *
27
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
28
     */
29
    protected function handleMatchedRoute(Request $request, $route)
30
    {
31
        if (! is_null($route)) {
32
            return $route->bind($request);
33
        }
34
 
35
        // If no route was found we will now check if a matching route is specified by
36
        // another HTTP verb. If it is we will need to throw a MethodNotAllowed and
37
        // inform the user agent of which HTTP verb it should use for this route.
38
        $others = $this->checkForAlternateVerbs($request);
39
 
40
        if (count($others) > 0) {
41
            return $this->getRouteForMethods($request, $others);
42
        }
43
 
44
        throw new NotFoundHttpException(sprintf(
45
            'The route %s could not be found.',
46
            $request->path()
47
        ));
48
    }
49
 
50
    /**
51
     * Determine if any routes match on another HTTP verb.
52
     *
53
     * @param  \Illuminate\Http\Request  $request
54
     * @return array
55
     */
56
    protected function checkForAlternateVerbs($request)
57
    {
58
        $methods = array_diff(Router::$verbs, [$request->getMethod()]);
59
 
60
        // Here we will spin through all verbs except for the current request verb and
61
        // check to see if any routes respond to them. If they do, we will return a
62
        // proper error response with the correct headers on the response string.
63
        return array_values(array_filter(
64
            $methods,
65
            function ($method) use ($request) {
66
                return ! is_null($this->matchAgainstRoutes($this->get($method), $request, false));
67
            }
68
        ));
69
    }
70
 
71
    /**
72
     * Determine if a route in the array matches the request.
73
     *
74
     * @param  \Illuminate\Routing\Route[]  $routes
75
     * @param  \Illuminate\Http\Request  $request
76
     * @param  bool  $includingMethod
77
     * @return \Illuminate\Routing\Route|null
78
     */
79
    protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true)
80
    {
81
        [$fallbacks, $routes] = collect($routes)->partition(function ($route) {
82
            return $route->isFallback;
83
        });
84
 
85
        return $routes->merge($fallbacks)->first(
86
            fn (Route $route) => $route->matches($request, $includingMethod)
87
        );
88
    }
89
 
90
    /**
91
     * Get a route (if necessary) that responds when other available methods are present.
92
     *
93
     * @param  \Illuminate\Http\Request  $request
94
     * @param  string[]  $methods
95
     * @return \Illuminate\Routing\Route
96
     *
97
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
98
     */
99
    protected function getRouteForMethods($request, array $methods)
100
    {
101
        if ($request->isMethod('OPTIONS')) {
102
            return (new Route('OPTIONS', $request->path(), function () use ($methods) {
103
                return new Response('', 200, ['Allow' => implode(',', $methods)]);
104
            }))->bind($request);
105
        }
106
 
107
        $this->requestMethodNotAllowed($request, $methods, $request->method());
108
    }
109
 
110
    /**
111
     * Throw a method not allowed HTTP exception.
112
     *
113
     * @param  \Illuminate\Http\Request  $request
114
     * @param  array  $others
115
     * @param  string  $method
116
     * @return void
117
     *
118
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
119
     */
120
    protected function requestMethodNotAllowed($request, array $others, $method)
121
    {
122
        throw new MethodNotAllowedHttpException(
123
            $others,
124
            sprintf(
125
                'The %s method is not supported for route %s. Supported methods: %s.',
126
                $method,
127
                $request->path(),
128
                implode(', ', $others)
129
            )
130
        );
131
    }
132
 
133
    /**
134
     * Throw a method not allowed HTTP exception.
135
     *
136
     * @param  array  $others
137
     * @param  string  $method
138
     * @return void
139
     *
140
     * @deprecated use requestMethodNotAllowed
141
     *
142
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
143
     */
144
    protected function methodNotAllowed(array $others, $method)
145
    {
146
        throw new MethodNotAllowedHttpException(
147
            $others,
148
            sprintf(
149
                'The %s method is not supported for this route. Supported methods: %s.',
150
                $method,
151
                implode(', ', $others)
152
            )
153
        );
154
    }
155
 
156
    /**
157
     * Compile the routes for caching.
158
     *
159
     * @return array
160
     */
161
    public function compile()
162
    {
163
        $compiled = $this->dumper()->getCompiledRoutes();
164
 
165
        $attributes = [];
166
 
167
        foreach ($this->getRoutes() as $route) {
168
            $attributes[$route->getName()] = [
169
                'methods' => $route->methods(),
170
                'uri' => $route->uri(),
171
                'action' => $route->getAction(),
172
                'fallback' => $route->isFallback,
173
                'defaults' => $route->defaults,
174
                'wheres' => $route->wheres,
175
                'bindingFields' => $route->bindingFields(),
176
                'lockSeconds' => $route->locksFor(),
177
                'waitSeconds' => $route->waitsFor(),
178
                'withTrashed' => $route->allowsTrashedBindings(),
179
            ];
180
        }
181
 
182
        return compact('compiled', 'attributes');
183
    }
184
 
185
    /**
186
     * Return the CompiledUrlMatcherDumper instance for the route collection.
187
     *
188
     * @return \Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper
189
     */
190
    public function dumper()
191
    {
192
        return new CompiledUrlMatcherDumper($this->toSymfonyRouteCollection());
193
    }
194
 
195
    /**
196
     * Convert the collection to a Symfony RouteCollection instance.
197
     *
198
     * @return \Symfony\Component\Routing\RouteCollection
199
     */
200
    public function toSymfonyRouteCollection()
201
    {
202
        $symfonyRoutes = new SymfonyRouteCollection;
203
 
204
        $routes = $this->getRoutes();
205
 
206
        foreach ($routes as $route) {
207
            if (! $route->isFallback) {
208
                $symfonyRoutes = $this->addToSymfonyRoutesCollection($symfonyRoutes, $route);
209
            }
210
        }
211
 
212
        foreach ($routes as $route) {
213
            if ($route->isFallback) {
214
                $symfonyRoutes = $this->addToSymfonyRoutesCollection($symfonyRoutes, $route);
215
            }
216
        }
217
 
218
        return $symfonyRoutes;
219
    }
220
 
221
    /**
222
     * Add a route to the SymfonyRouteCollection instance.
223
     *
224
     * @param  \Symfony\Component\Routing\RouteCollection  $symfonyRoutes
225
     * @param  \Illuminate\Routing\Route  $route
226
     * @return \Symfony\Component\Routing\RouteCollection
227
     *
228
     * @throws \LogicException
229
     */
230
    protected function addToSymfonyRoutesCollection(SymfonyRouteCollection $symfonyRoutes, Route $route)
231
    {
232
        $name = $route->getName();
233
 
234
        if (
235
            ! is_null($name)
236
            && str_ends_with($name, '.')
237
            && ! is_null($symfonyRoutes->get($name))
238
        ) {
239
            $name = null;
240
        }
241
 
242
        if (! $name) {
243
            $route->name($this->generateRouteName());
244
 
245
            $this->add($route);
246
        } elseif (! is_null($symfonyRoutes->get($name))) {
247
            throw new LogicException("Unable to prepare route [{$route->uri}] for serialization. Another route has already been assigned name [{$name}].");
248
        }
249
 
250
        $symfonyRoutes->add($route->getName(), $route->toSymfonyRoute());
251
 
252
        return $symfonyRoutes;
253
    }
254
 
255
    /**
256
     * Get a randomly generated route name.
257
     *
258
     * @return string
259
     */
260
    protected function generateRouteName()
261
    {
262
        return 'generated::'.Str::random();
263
    }
264
 
265
    /**
266
     * Get an iterator for the items.
267
     *
268
     * @return \ArrayIterator
269
     */
270
    public function getIterator(): Traversable
271
    {
272
        return new ArrayIterator($this->getRoutes());
273
    }
274
 
275
    /**
276
     * Count the number of items in the collection.
277
     *
278
     * @return int
279
     */
280
    public function count(): int
281
    {
282
        return count($this->getRoutes());
283
    }
284
}