| 148 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
namespace Illuminate\Routing;
|
|
|
4 |
|
|
|
5 |
use Illuminate\Support\Arr;
|
|
|
6 |
use Illuminate\Support\Reflector;
|
|
|
7 |
use Illuminate\Support\Str;
|
|
|
8 |
use LogicException;
|
|
|
9 |
use UnexpectedValueException;
|
|
|
10 |
|
|
|
11 |
class RouteAction
|
|
|
12 |
{
|
|
|
13 |
/**
|
|
|
14 |
* Parse the given action into an array.
|
|
|
15 |
*
|
|
|
16 |
* @param string $uri
|
|
|
17 |
* @param mixed $action
|
|
|
18 |
* @return array
|
|
|
19 |
*/
|
|
|
20 |
public static function parse($uri, $action)
|
|
|
21 |
{
|
|
|
22 |
// If no action is passed in right away, we assume the user will make use of
|
|
|
23 |
// fluent routing. In that case, we set a default closure, to be executed
|
|
|
24 |
// if the user never explicitly sets an action to handle the given uri.
|
|
|
25 |
if (is_null($action)) {
|
|
|
26 |
return static::missingAction($uri);
|
|
|
27 |
}
|
|
|
28 |
|
|
|
29 |
// If the action is already a Closure instance, we will just set that instance
|
|
|
30 |
// as the "uses" property, because there is nothing else we need to do when
|
|
|
31 |
// it is available. Otherwise we will need to find it in the action list.
|
|
|
32 |
if (Reflector::isCallable($action, true)) {
|
|
|
33 |
return ! is_array($action) ? ['uses' => $action] : [
|
|
|
34 |
'uses' => $action[0].'@'.$action[1],
|
|
|
35 |
'controller' => $action[0].'@'.$action[1],
|
|
|
36 |
];
|
|
|
37 |
}
|
|
|
38 |
|
|
|
39 |
// If no "uses" property has been set, we will dig through the array to find a
|
|
|
40 |
// Closure instance within this list. We will set the first Closure we come
|
|
|
41 |
// across into the "uses" property that will get fired off by this route.
|
|
|
42 |
elseif (! isset($action['uses'])) {
|
|
|
43 |
$action['uses'] = static::findCallable($action);
|
|
|
44 |
}
|
|
|
45 |
|
|
|
46 |
if (! static::containsSerializedClosure($action) && is_string($action['uses']) && ! str_contains($action['uses'], '@')) {
|
|
|
47 |
$action['uses'] = static::makeInvokable($action['uses']);
|
|
|
48 |
}
|
|
|
49 |
|
|
|
50 |
return $action;
|
|
|
51 |
}
|
|
|
52 |
|
|
|
53 |
/**
|
|
|
54 |
* Get an action for a route that has no action.
|
|
|
55 |
*
|
|
|
56 |
* @param string $uri
|
|
|
57 |
* @return array
|
|
|
58 |
*
|
|
|
59 |
* @throws \LogicException
|
|
|
60 |
*/
|
|
|
61 |
protected static function missingAction($uri)
|
|
|
62 |
{
|
|
|
63 |
return ['uses' => function () use ($uri) {
|
|
|
64 |
throw new LogicException("Route for [{$uri}] has no action.");
|
|
|
65 |
}];
|
|
|
66 |
}
|
|
|
67 |
|
|
|
68 |
/**
|
|
|
69 |
* Find the callable in an action array.
|
|
|
70 |
*
|
|
|
71 |
* @param array $action
|
|
|
72 |
* @return callable
|
|
|
73 |
*/
|
|
|
74 |
protected static function findCallable(array $action)
|
|
|
75 |
{
|
|
|
76 |
return Arr::first($action, function ($value, $key) {
|
|
|
77 |
return Reflector::isCallable($value) && is_numeric($key);
|
|
|
78 |
});
|
|
|
79 |
}
|
|
|
80 |
|
|
|
81 |
/**
|
|
|
82 |
* Make an action for an invokable controller.
|
|
|
83 |
*
|
|
|
84 |
* @param string $action
|
|
|
85 |
* @return string
|
|
|
86 |
*
|
|
|
87 |
* @throws \UnexpectedValueException
|
|
|
88 |
*/
|
|
|
89 |
protected static function makeInvokable($action)
|
|
|
90 |
{
|
|
|
91 |
if (! method_exists($action, '__invoke')) {
|
|
|
92 |
throw new UnexpectedValueException("Invalid route action: [{$action}].");
|
|
|
93 |
}
|
|
|
94 |
|
|
|
95 |
return $action.'@__invoke';
|
|
|
96 |
}
|
|
|
97 |
|
|
|
98 |
/**
|
|
|
99 |
* Determine if the given array actions contain a serialized Closure.
|
|
|
100 |
*
|
|
|
101 |
* @param array $action
|
|
|
102 |
* @return bool
|
|
|
103 |
*/
|
|
|
104 |
public static function containsSerializedClosure(array $action)
|
|
|
105 |
{
|
|
|
106 |
return is_string($action['uses']) && Str::startsWith($action['uses'], [
|
|
|
107 |
'O:47:"Laravel\\SerializableClosure\\SerializableClosure',
|
|
|
108 |
]) !== false;
|
|
|
109 |
}
|
|
|
110 |
}
|