RouteAction.php
TLDR
The RouteAction
class in the Illuminate\Routing
namespace provides methods for parsing route actions and finding callables within them.
Methods
parse
This method takes a URI and an action and parses the action into an array. If the action is null
, it returns a default closure to handle the URI. If the action is already a closure or callable, it sets the action as the "uses" property. Otherwise, it searches for the first closure in the action array and sets it as the "uses" property. It also handles invokable controllers by making the action an invokable callable.
missingAction
This protected method takes a URI and returns an array with a closure that throws a LogicException
indicating that the route has no action. This method is used when no action is provided for a route.
findCallable
This protected method takes an action array and finds the first callable in it. It returns the callable.
makeInvokable
This protected method takes an action string and checks if it is an invokable controller. If not, it throws an UnexpectedValueException
. If it is, it returns the action string appended with @__invoke
.
containsSerializedClosure
This public static method takes an action array and checks if it contains a serialized closure. It returns true
if it does, otherwise false
.
<?php
namespace Illuminate\Routing;
use Illuminate\Support\Arr;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
use LogicException;
use UnexpectedValueException;
class RouteAction
{
/**
* Parse the given action into an array.
*
* @param string $uri
* @param mixed $action
* @return array
*/
public static function parse($uri, $action)
{
// If no action is passed in right away, we assume the user will make use of
// fluent routing. In that case, we set a default closure, to be executed
// if the user never explicitly sets an action to handle the given uri.
if (is_null($action)) {
return static::missingAction($uri);
}
// If the action is already a Closure instance, we will just set that instance
// as the "uses" property, because there is nothing else we need to do when
// it is available. Otherwise we will need to find it in the action list.
if (Reflector::isCallable($action, true)) {
return ! is_array($action) ? ['uses' => $action] : [
'uses' => $action[0].'@'.$action[1],
'controller' => $action[0].'@'.$action[1],
];
}
// If no "uses" property has been set, we will dig through the array to find a
// Closure instance within this list. We will set the first Closure we come
// across into the "uses" property that will get fired off by this route.
elseif (! isset($action['uses'])) {
$action['uses'] = static::findCallable($action);
}
if (! static::containsSerializedClosure($action) && is_string($action['uses']) && ! str_contains($action['uses'], '@')) {
$action['uses'] = static::makeInvokable($action['uses']);
}
return $action;
}
/**
* Get an action for a route that has no action.
*
* @param string $uri
* @return array
*
* @throws \LogicException
*/
protected static function missingAction($uri)
{
return ['uses' => function () use ($uri) {
throw new LogicException("Route for [{$uri}] has no action.");
}];
}
/**
* Find the callable in an action array.
*
* @param array $action
* @return callable
*/
protected static function findCallable(array $action)
{
return Arr::first($action, function ($value, $key) {
return Reflector::isCallable($value) && is_numeric($key);
});
}
/**
* Make an action for an invokable controller.
*
* @param string $action
* @return string
*
* @throws \UnexpectedValueException
*/
protected static function makeInvokable($action)
{
if (! method_exists($action, '__invoke')) {
throw new UnexpectedValueException("Invalid route action: [{$action}].");
}
return $action.'@__invoke';
}
/**
* Determine if the given array actions contain a serialized Closure.
*
* @param array $action
* @return bool
*/
public static function containsSerializedClosure(array $action)
{
return is_string($action['uses']) && Str::startsWith($action['uses'], [
'O:47:"Laravel\\SerializableClosure\\SerializableClosure',
'O:55:"Laravel\\SerializableClosure\\UnsignedSerializableClosure',
]) !== false;
}
}