This commit is contained in:
Paolo A
2024-08-13 13:44:16 +00:00
parent 1bbb23088d
commit e796d76612
4001 changed files with 30101 additions and 40075 deletions

View File

@@ -146,6 +146,7 @@ abstract class AbstractRouteCollection implements Countable, IteratorAggregate,
'bindingFields' => $route->bindingFields(),
'lockSeconds' => $route->locksFor(),
'waitSeconds' => $route->waitsFor(),
'withTrashed' => $route->allowsTrashedBindings(),
];
}
@@ -194,13 +195,18 @@ abstract class AbstractRouteCollection implements Countable, IteratorAggregate,
* @param \Symfony\Component\Routing\RouteCollection $symfonyRoutes
* @param \Illuminate\Routing\Route $route
* @return \Symfony\Component\Routing\RouteCollection
*
* @throws \LogicException
*/
protected function addToSymfonyRoutesCollection(SymfonyRouteCollection $symfonyRoutes, Route $route)
{
$name = $route->getName();
if (Str::endsWith($name, '.') &&
! is_null($symfonyRoutes->get($name))) {
if (
! is_null($name)
&& Str::endsWith($name, '.')
&& ! is_null($symfonyRoutes->get($name))
) {
$name = null;
}
@@ -232,6 +238,7 @@ abstract class AbstractRouteCollection implements Countable, IteratorAggregate,
*
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->getRoutes());
@@ -242,6 +249,7 @@ abstract class AbstractRouteCollection implements Countable, IteratorAggregate,
*
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->getRoutes());

View File

@@ -152,7 +152,7 @@ class CompiledRouteCollection extends AbstractRouteCollection
*/
protected function requestWithoutTrailingSlash(Request $request)
{
$trimmedRequest = Request::createFromBase($request);
$trimmedRequest = $request->duplicate();
$parts = explode('?', $request->server->get('REQUEST_URI'), 2);
@@ -252,7 +252,7 @@ class CompiledRouteCollection extends AbstractRouteCollection
})
->map(function (Collection $routes) {
return $routes->mapWithKeys(function (Route $route) {
return [$route->uri => $route];
return [$route->getDomain().$route->uri => $route];
})->all();
})
->all();
@@ -293,12 +293,13 @@ class CompiledRouteCollection extends AbstractRouteCollection
), '/');
}
return $this->router->newRoute($attributes['methods'], $baseUri == '' ? '/' : $baseUri, $attributes['action'])
return $this->router->newRoute($attributes['methods'], $baseUri === '' ? '/' : $baseUri, $attributes['action'])
->setFallback($attributes['fallback'])
->setDefaults($attributes['defaults'])
->setWheres($attributes['wheres'])
->setBindingFields($attributes['bindingFields'])
->block($attributes['lockSeconds'] ?? null, $attributes['waitSeconds'] ?? null);
->block($attributes['lockSeconds'] ?? null, $attributes['waitSeconds'] ?? null)
->withTrashed($attributes['withTrashed'] ?? false);
}
/**

View File

@@ -2,13 +2,15 @@
namespace Illuminate\Routing\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Symfony\Component\Console\Input\InputOption;
class ControllerMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*
@@ -39,7 +41,9 @@ class ControllerMakeCommand extends GeneratorCommand
{
$stub = null;
if ($this->option('parent')) {
if ($type = $this->option('type')) {
$stub = "/stubs/controller.{$type}.stub";
} elseif ($this->option('parent')) {
$stub = '/stubs/controller.nested.stub';
} elseif ($this->option('model')) {
$stub = '/stubs/controller.model.stub';
@@ -87,7 +91,7 @@ class ControllerMakeCommand extends GeneratorCommand
/**
* Build the class with the given name.
*
* Remove the base controller import if we are already in base namespace.
* Remove the base controller import if we are already in the base namespace.
*
* @param string $name
* @return string
@@ -157,6 +161,8 @@ class ControllerMakeCommand extends GeneratorCommand
}
}
$replace = $this->buildFormRequestReplacements($replace, $modelClass);
return array_merge($replace, [
'DummyFullModelClass' => $modelClass,
'{{ namespacedModel }}' => $modelClass,
@@ -184,13 +190,73 @@ class ControllerMakeCommand extends GeneratorCommand
throw new InvalidArgumentException('Model name contains invalid characters.');
}
$model = trim(str_replace('/', '\\', $model), '\\');
return $this->qualifyModel($model);
}
if (! Str::startsWith($model, $rootNamespace = $this->laravel->getNamespace())) {
$model = $rootNamespace.$model;
/**
* Build the model replacement values.
*
* @param array $replace
* @param string $modelClass
* @return array
*/
protected function buildFormRequestReplacements(array $replace, $modelClass)
{
[$namespace, $storeRequestClass, $updateRequestClass] = [
'Illuminate\\Http', 'Request', 'Request',
];
if ($this->option('requests')) {
$namespace = 'App\\Http\\Requests';
[$storeRequestClass, $updateRequestClass] = $this->generateFormRequests(
$modelClass, $storeRequestClass, $updateRequestClass
);
}
return $model;
$namespacedRequests = $namespace.'\\'.$storeRequestClass.';';
if ($storeRequestClass !== $updateRequestClass) {
$namespacedRequests .= PHP_EOL.'use '.$namespace.'\\'.$updateRequestClass.';';
}
return array_merge($replace, [
'{{ storeRequest }}' => $storeRequestClass,
'{{storeRequest}}' => $storeRequestClass,
'{{ updateRequest }}' => $updateRequestClass,
'{{updateRequest}}' => $updateRequestClass,
'{{ namespacedStoreRequest }}' => $namespace.'\\'.$storeRequestClass,
'{{namespacedStoreRequest}}' => $namespace.'\\'.$storeRequestClass,
'{{ namespacedUpdateRequest }}' => $namespace.'\\'.$updateRequestClass,
'{{namespacedUpdateRequest}}' => $namespace.'\\'.$updateRequestClass,
'{{ namespacedRequests }}' => $namespacedRequests,
'{{namespacedRequests}}' => $namespacedRequests,
]);
}
/**
* Generate the form requests for the given model and classes.
*
* @param string $modelName
* @param string $storeRequestClass
* @param string $updateRequestClass
* @return array
*/
protected function generateFormRequests($modelClass, $storeRequestClass, $updateRequestClass)
{
$storeRequestClass = 'Store'.class_basename($modelClass).'Request';
$this->call('make:request', [
'name' => $storeRequestClass,
]);
$updateRequestClass = 'Update'.class_basename($modelClass).'Request';
$this->call('make:request', [
'name' => $updateRequestClass,
]);
return [$storeRequestClass, $updateRequestClass];
}
/**
@@ -202,11 +268,13 @@ class ControllerMakeCommand extends GeneratorCommand
{
return [
['api', null, InputOption::VALUE_NONE, 'Exclude the create and edit methods from the controller.'],
['type', null, InputOption::VALUE_REQUIRED, 'Manually specify the controller stub file to use.'],
['force', null, InputOption::VALUE_NONE, 'Create the class even if the controller already exists'],
['invokable', 'i', InputOption::VALUE_NONE, 'Generate a single method, invokable controller class.'],
['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a resource controller for the given model.'],
['parent', 'p', InputOption::VALUE_OPTIONAL, 'Generate a nested resource controller class.'],
['resource', 'r', InputOption::VALUE_NONE, 'Generate a resource controller class.'],
['requests', 'R', InputOption::VALUE_NONE, 'Generate FormRequest classes for store and update.'],
];
}
}

View File

@@ -2,10 +2,13 @@
namespace Illuminate\Routing\Console;
use Illuminate\Console\Concerns\CreatesMatchingTest;
use Illuminate\Console\GeneratorCommand;
class MiddlewareMakeCommand extends GeneratorCommand
{
use CreatesMatchingTest;
/**
* The console command name.
*

View File

@@ -4,7 +4,7 @@ namespace {{ namespace }};
use {{ namespacedModel }};
use {{ rootNamespace }}Http\Controllers\Controller;
use Illuminate\Http\Request;
use {{ namespacedRequests }}
class {{ class }} extends Controller
{
@@ -21,10 +21,10 @@ class {{ class }} extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \{{ namespacedStoreRequest }} $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store({{ storeRequest }} $request)
{
//
}
@@ -43,11 +43,11 @@ class {{ class }} extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \{{ namespacedUpdateRequest }} $request
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \Illuminate\Http\Response
*/
public function update(Request $request, {{ model }} ${{ modelVariable }})
public function update({{ updateRequest }} $request, {{ model }} ${{ modelVariable }})
{
//
}

View File

@@ -4,7 +4,7 @@ namespace {{ namespace }};
use {{ namespacedModel }};
use {{ rootNamespace }}Http\Controllers\Controller;
use Illuminate\Http\Request;
use {{ namespacedRequests }}
class {{ class }} extends Controller
{
@@ -31,10 +31,10 @@ class {{ class }} extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \{{ namespacedStoreRequest }} $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store({{ storeRequest }} $request)
{
//
}
@@ -64,11 +64,11 @@ class {{ class }} extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \{{ namespacedUpdateRequest }} $request
* @param \{{ namespacedModel }} ${{ modelVariable }}
* @return \Illuminate\Http\Response
*/
public function update(Request $request, {{ model }} ${{ modelVariable }})
public function update({{ updateRequest }} $request, {{ model }} ${{ modelVariable }})
{
//
}

View File

@@ -3,6 +3,7 @@
namespace {{ namespace }};
use Closure;
use Illuminate\Http\Request;
class {{ class }}
{
@@ -10,10 +11,10 @@ class {{ class }}
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle($request, Closure $next)
public function handle(Request $request, Closure $next)
{
return $next($request);
}

View File

@@ -3,6 +3,8 @@
namespace Illuminate\Routing\Exceptions;
use Exception;
use Illuminate\Routing\Route;
use Illuminate\Support\Str;
class UrlGenerationException extends Exception
{
@@ -10,10 +12,26 @@ class UrlGenerationException extends Exception
* Create a new exception for missing route parameters.
*
* @param \Illuminate\Routing\Route $route
* @param array $parameters
* @return static
*/
public static function forMissingParameters($route)
public static function forMissingParameters(Route $route, array $parameters = [])
{
return new static("Missing required parameters for [Route: {$route->getName()}] [URI: {$route->uri()}].");
$parameterLabel = Str::plural('parameter', count($parameters));
$message = sprintf(
'Missing required %s for [Route: %s] [URI: %s]',
$parameterLabel,
$route->getName(),
$route->uri()
);
if (count($parameters) > 0) {
$message .= sprintf(' [Missing %s: %s]', $parameterLabel, implode(', ', $parameters));
}
$message .= '.';
return new static($message);
}
}

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Routing;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Reflector;
use Illuminate\Support\Str;
@@ -37,13 +38,21 @@ class ImplicitRouteBinding
$parent = $route->parentOfParameter($parameterName);
if ($parent instanceof UrlRoutable && in_array($parameterName, array_keys($route->bindingFields()))) {
if (! $model = $parent->resolveChildRouteBinding(
$routeBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
? 'resolveSoftDeletableRouteBinding'
: 'resolveRouteBinding';
if ($parent instanceof UrlRoutable && ($route->enforcesScopedBindings() || array_key_exists($parameterName, $route->bindingFields()))) {
$childRouteBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
? 'resolveSoftDeletableChildRouteBinding'
: 'resolveChildRouteBinding';
if (! $model = $parent->{$childRouteBindingMethod}(
$parameterName, $parameterValue, $route->bindingFieldFor($parameterName)
)) {
throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue]);
}
} elseif (! $model = $instance->resolveRouteBinding($parameterValue, $route->bindingFieldFor($parameterName))) {
} elseif (! $model = $instance->{$routeBindingMethod}($parameterValue, $route->bindingFieldFor($parameterName))) {
throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue]);
}

View File

@@ -4,6 +4,7 @@ namespace Illuminate\Routing\Middleware;
use Closure;
use Illuminate\Contracts\Routing\Registrar;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class SubstituteBindings
{
@@ -34,9 +35,17 @@ class SubstituteBindings
*/
public function handle($request, Closure $next)
{
$this->router->substituteBindings($route = $request->route());
try {
$this->router->substituteBindings($route = $request->route());
$this->router->substituteImplicitBindings($route);
$this->router->substituteImplicitBindings($route);
} catch (ModelNotFoundException $exception) {
if ($route->getMissing()) {
return $route->getMissing()($request, $exception);
}
throw $exception;
}
return $next($request);
}

View File

@@ -4,7 +4,10 @@ namespace Illuminate\Routing\Middleware;
use Closure;
use Illuminate\Cache\RateLimiter;
use Illuminate\Cache\RateLimiting\Unlimited;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Support\Arr;
use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Str;
use RuntimeException;
@@ -46,22 +49,92 @@ class ThrottleRequests
*/
public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')
{
$key = $prefix.$this->resolveRequestSignature($request);
$maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);
if ($this->limiter->tooManyAttempts($key, $maxAttempts)) {
throw $this->buildException($key, $maxAttempts);
if (is_string($maxAttempts)
&& func_num_args() === 3
&& ! is_null($limiter = $this->limiter->limiter($maxAttempts))) {
return $this->handleRequestUsingNamedLimiter($request, $next, $maxAttempts, $limiter);
}
$this->limiter->hit($key, $decayMinutes * 60);
return $this->handleRequest(
$request,
$next,
[
(object) [
'key' => $prefix.$this->resolveRequestSignature($request),
'maxAttempts' => $this->resolveMaxAttempts($request, $maxAttempts),
'decayMinutes' => $decayMinutes,
'responseCallback' => null,
],
]
);
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $limiterName
* @param \Closure $limiter
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
*/
protected function handleRequestUsingNamedLimiter($request, Closure $next, $limiterName, Closure $limiter)
{
$limiterResponse = call_user_func($limiter, $request);
if ($limiterResponse instanceof Response) {
return $limiterResponse;
} elseif ($limiterResponse instanceof Unlimited) {
return $next($request);
}
return $this->handleRequest(
$request,
$next,
collect(Arr::wrap($limiterResponse))->map(function ($limit) use ($limiterName) {
return (object) [
'key' => md5($limiterName.$limit->key),
'maxAttempts' => $limit->maxAttempts,
'decayMinutes' => $limit->decayMinutes,
'responseCallback' => $limit->responseCallback,
];
})->all()
);
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param array $limits
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
*/
protected function handleRequest($request, Closure $next, array $limits)
{
foreach ($limits as $limit) {
if ($this->limiter->tooManyAttempts($limit->key, $limit->maxAttempts)) {
throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
}
$this->limiter->hit($limit->key, $limit->decayMinutes * 60);
}
$response = $next($request);
return $this->addHeaders(
$response, $maxAttempts,
$this->calculateRemainingAttempts($key, $maxAttempts)
);
foreach ($limits as $limit) {
$response = $this->addHeaders(
$response,
$limit->maxAttempts,
$this->calculateRemainingAttempts($limit->key, $limit->maxAttempts)
);
}
return $response;
}
/**
@@ -96,9 +169,7 @@ class ThrottleRequests
{
if ($user = $request->user()) {
return sha1($user->getAuthIdentifier());
}
if ($route = $request->route()) {
} elseif ($route = $request->route()) {
return sha1($route->getDomain().'|'.$request->ip());
}
@@ -108,11 +179,13 @@ class ThrottleRequests
/**
* Create a 'too many attempts' exception.
*
* @param \Illuminate\Http\Request $request
* @param string $key
* @param int $maxAttempts
* @param callable|null $responseCallback
* @return \Illuminate\Http\Exceptions\ThrottleRequestsException
*/
protected function buildException($key, $maxAttempts)
protected function buildException($request, $key, $maxAttempts, $responseCallback = null)
{
$retryAfter = $this->getTimeUntilNextRetry($key);
@@ -122,9 +195,9 @@ class ThrottleRequests
$retryAfter
);
return new ThrottleRequestsException(
'Too Many Attempts.', null, $headers
);
return is_callable($responseCallback)
? new HttpResponseException($responseCallback($request, $headers))
: new ThrottleRequestsException('Too Many Attempts.', null, $headers);
}
/**
@@ -150,7 +223,7 @@ class ThrottleRequests
protected function addHeaders(Response $response, $maxAttempts, $remainingAttempts, $retryAfter = null)
{
$response->headers->add(
$this->getHeaders($maxAttempts, $remainingAttempts, $retryAfter)
$this->getHeaders($maxAttempts, $remainingAttempts, $retryAfter, $response)
);
return $response;
@@ -162,10 +235,20 @@ class ThrottleRequests
* @param int $maxAttempts
* @param int $remainingAttempts
* @param int|null $retryAfter
* @param \Symfony\Component\HttpFoundation\Response|null $response
* @return array
*/
protected function getHeaders($maxAttempts, $remainingAttempts, $retryAfter = null)
protected function getHeaders($maxAttempts,
$remainingAttempts,
$retryAfter = null,
?Response $response = null)
{
if ($response &&
! is_null($response->headers->get('X-RateLimit-Remaining')) &&
(int) $response->headers->get('X-RateLimit-Remaining') <= (int) $remainingAttempts) {
return [];
}
$headers = [
'X-RateLimit-Limit' => $maxAttempts,
'X-RateLimit-Remaining' => $remainingAttempts,
@@ -189,10 +272,6 @@ class ThrottleRequests
*/
protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null)
{
if (is_null($retryAfter)) {
return $this->limiter->retriesLeft($key, $maxAttempts);
}
return 0;
return is_null($retryAfter) ? $this->limiter->retriesLeft($key, $maxAttempts) : 0;
}
}

View File

@@ -3,6 +3,7 @@
namespace Illuminate\Routing\Middleware;
use Closure;
use Illuminate\Cache\RateLimiter;
use Illuminate\Contracts\Redis\Factory as Redis;
use Illuminate\Redis\Limiters\DurationLimiter;
@@ -16,27 +17,30 @@ class ThrottleRequestsWithRedis extends ThrottleRequests
protected $redis;
/**
* The timestamp of the end of the current duration.
* The timestamp of the end of the current duration by key.
*
* @var int
* @var array
*/
public $decaysAt;
public $decaysAt = [];
/**
* The number of remaining slots.
* The number of remaining slots by key.
*
* @var int
* @var array
*/
public $remaining;
public $remaining = [];
/**
* Create a new request throttler.
*
* @param \Illuminate\Cache\RateLimiter $limiter
* @param \Illuminate\Contracts\Redis\Factory $redis
* @return void
*/
public function __construct(Redis $redis)
public function __construct(RateLimiter $limiter, Redis $redis)
{
parent::__construct($limiter);
$this->redis = $redis;
}
@@ -45,29 +49,30 @@ class ThrottleRequestsWithRedis extends ThrottleRequests
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param int|string $maxAttempts
* @param float|int $decayMinutes
* @param string $prefix
* @return mixed
* @param array $limits
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
*/
public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')
protected function handleRequest($request, Closure $next, array $limits)
{
$key = $prefix.$this->resolveRequestSignature($request);
$maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);
if ($this->tooManyAttempts($key, $maxAttempts, $decayMinutes)) {
throw $this->buildException($key, $maxAttempts);
foreach ($limits as $limit) {
if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decayMinutes)) {
throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
}
}
$response = $next($request);
return $this->addHeaders(
$response, $maxAttempts,
$this->calculateRemainingAttempts($key, $maxAttempts)
);
foreach ($limits as $limit) {
$response = $this->addHeaders(
$response,
$limit->maxAttempts,
$this->calculateRemainingAttempts($limit->key, $limit->maxAttempts)
);
}
return $response;
}
/**
@@ -84,8 +89,8 @@ class ThrottleRequestsWithRedis extends ThrottleRequests
$this->redis, $key, $maxAttempts, $decayMinutes * 60
);
return tap(! $limiter->acquire(), function () use ($limiter) {
[$this->decaysAt, $this->remaining] = [
return tap(! $limiter->acquire(), function () use ($key, $limiter) {
[$this->decaysAt[$key], $this->remaining[$key]] = [
$limiter->decaysAt, $limiter->remaining,
];
});
@@ -101,11 +106,7 @@ class ThrottleRequestsWithRedis extends ThrottleRequests
*/
protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null)
{
if (is_null($retryAfter)) {
return $this->remaining;
}
return 0;
return is_null($retryAfter) ? $this->remaining[$key] : 0;
}
/**
@@ -116,6 +117,6 @@ class ThrottleRequestsWithRedis extends ThrottleRequests
*/
protected function getTimeUntilNextRetry($key)
{
return $this->decaysAt - $this->currentTime();
return $this->decaysAt[$key] - $this->currentTime();
}
}

View File

@@ -12,13 +12,14 @@ class ValidateSignature
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $relative
* @return \Illuminate\Http\Response
*
* @throws \Illuminate\Routing\Exceptions\InvalidSignatureException
*/
public function handle($request, Closure $next)
public function handle($request, Closure $next, $relative = null)
{
if ($request->hasValidSignature()) {
if ($request->hasValidSignature($relative !== 'relative')) {
return $next($request);
}

View File

@@ -7,7 +7,7 @@ use Illuminate\Support\Traits\Macroable;
class PendingResourceRegistration
{
use Macroable;
use CreatesRegularExpressionRouteConstraints, Macroable;
/**
* The resource registrar.
@@ -149,6 +149,12 @@ class PendingResourceRegistration
*/
public function middleware($middleware)
{
$middleware = Arr::wrap($middleware);
foreach ($middleware as $key => $value) {
$middleware[$key] = (string) $value;
}
$this->options['middleware'] = $middleware;
return $this;
@@ -195,6 +201,19 @@ class PendingResourceRegistration
return $this;
}
/**
* Define the callable that should be invoked on a missing model exception.
*
* @param callable $callback
* @return $this
*/
public function missing($callback)
{
$this->options['missing'] = $callback;
return $this;
}
/**
* Indicate that the resource routes should be scoped using the given binding fields.
*

0
vendor/laravel/framework/src/Illuminate/Routing/Redirector.php vendored Normal file → Executable file
View File

View File

@@ -16,7 +16,7 @@ class ResourceRegistrar
/**
* The default actions for a resourceful controller.
*
* @var array
* @var string[]
*/
protected $resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy'];
@@ -184,6 +184,8 @@ class ResourceRegistrar
{
$uri = $this->getResourceUri($name);
unset($options['missing']);
$action = $this->getResourceAction($name, $controller, 'index', $options);
return $this->router->get($uri, $action);
@@ -202,6 +204,8 @@ class ResourceRegistrar
{
$uri = $this->getResourceUri($name).'/'.static::$verbs['create'];
unset($options['missing']);
$action = $this->getResourceAction($name, $controller, 'create', $options);
return $this->router->get($uri, $action);
@@ -220,6 +224,8 @@ class ResourceRegistrar
{
$uri = $this->getResourceUri($name);
unset($options['missing']);
$action = $this->getResourceAction($name, $controller, 'store', $options);
return $this->router->post($uri, $action);
@@ -421,6 +427,10 @@ class ResourceRegistrar
$action['where'] = $options['wheres'];
}
if (isset($options['missing'])) {
$action['missing'] = $options['missing'];
}
return $action;
}

View File

@@ -45,7 +45,7 @@ class ResponseFactory implements FactoryContract
/**
* Create a new response instance.
*
* @param string $content
* @param mixed $content
* @param int $status
* @param array $headers
* @return \Illuminate\Http\Response

156
vendor/laravel/framework/src/Illuminate/Routing/Route.php vendored Normal file → Executable file
View File

@@ -14,13 +14,15 @@ use Illuminate\Routing\Matching\UriValidator;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
use Laravel\SerializableClosure\SerializableClosure;
use LogicException;
use Opis\Closure\SerializableClosure as OpisSerializableClosure;
use ReflectionFunction;
use Symfony\Component\Routing\Route as SymfonyRoute;
class Route
{
use Macroable, RouteDependencyResolverTrait;
use CreatesRegularExpressionRouteConstraints, Macroable, RouteDependencyResolverTrait;
/**
* The URI pattern the route responds to.
@@ -92,6 +94,13 @@ class Route
*/
protected $originalParameters;
/**
* Indicates "trashed" models can be retrieved when resolving implicit model bindings for this route.
*
* @var bool
*/
protected $withTrashedBindings = false;
/**
* Indicates the maximum number of seconds the route should acquire a session lock for.
*
@@ -209,7 +218,7 @@ class Route
*/
protected function isControllerAction()
{
return is_string($this->action['uses']);
return is_string($this->action['uses']) && ! $this->isSerializedClosure();
}
/**
@@ -221,11 +230,25 @@ class Route
{
$callable = $this->action['uses'];
if ($this->isSerializedClosure()) {
$callable = unserialize($this->action['uses'])->getClosure();
}
return $callable(...array_values($this->resolveMethodDependencies(
$this->parametersWithoutNulls(), new ReflectionFunction($this->action['uses'])
$this->parametersWithoutNulls(), new ReflectionFunction($callable)
)));
}
/**
* Determine if the route action is a serialized Closure.
*
* @return bool
*/
protected function isSerializedClosure()
{
return RouteAction::containsSerializedClosure($this->action);
}
/**
* Run the route action and return the response.
*
@@ -276,6 +299,17 @@ class Route
return Str::parseCallback($this->action['uses']);
}
/**
* Flush the cached container instance on the route.
*
* @return void
*/
public function flushController()
{
$this->computedMiddleware = null;
$this->controller = null;
}
/**
* Determine if the route matches a given request.
*
@@ -287,7 +321,7 @@ class Route
{
$this->compileRoute();
foreach ($this->getValidators() as $validator) {
foreach (self::getValidators() as $validator) {
if (! $includingMethod && $validator instanceof MethodValidator) {
continue;
}
@@ -544,6 +578,29 @@ class Route
return array_values($this->parameters)[$key - 1];
}
/**
* Allow "trashed" models to be retrieved when resolving implicit model bindings for this route.
*
* @param bool $withTrashed
* @return $this
*/
public function withTrashed($withTrashed = true)
{
$this->withTrashedBindings = $withTrashed;
return $this;
}
/**
* Determines if the route allows "trashed" models to be retrieved when resolving implicit model bindings.
*
* @return bool
*/
public function allowsTrashedBindings()
{
return $this->withTrashedBindings;
}
/**
* Set a default value for the route.
*
@@ -731,6 +788,8 @@ class Route
*/
public function prefix($prefix)
{
$prefix = $prefix ?? '';
$this->updatePrefixOnAction($prefix);
$uri = rtrim($prefix, '/').'/'.ltrim($this->uri, '/');
@@ -836,11 +895,15 @@ class Route
/**
* Set the handler for the route.
*
* @param \Closure|string $action
* @param \Closure|array|string $action
* @return $this
*/
public function uses($action)
{
if (is_array($action)) {
$action = $action[0].'@'.$action[1];
}
$action = is_string($action) ? $this->addGroupNamespaceToStringUses($action) : $action;
return $this->setAction(array_merge($this->action, $this->parseAction([
@@ -914,6 +977,35 @@ class Route
return $this;
}
/**
* Get the value of the action that should be taken on a missing model exception.
*
* @return \Closure|null
*/
public function getMissing()
{
$missing = $this->action['missing'] ?? null;
return is_string($missing) &&
Str::startsWith($missing, [
'C:32:"Opis\\Closure\\SerializableClosure',
'O:47:"Laravel\\SerializableClosure\\SerializableClosure',
]) ? unserialize($missing) : $missing;
}
/**
* Define the callable that should be invoked on a missing model exception.
*
* @param \Closure $missing
* @return $this
*/
public function missing($missing)
{
$this->action['missing'] = $missing;
return $this;
}
/**
* Get all middleware, including the ones from the controller.
*
@@ -944,10 +1036,14 @@ class Route
return (array) ($this->action['middleware'] ?? []);
}
if (is_string($middleware)) {
if (! is_array($middleware)) {
$middleware = func_get_args();
}
foreach ($middleware as $index => $value) {
$middleware[$index] = (string) $value;
}
$this->action['middleware'] = array_merge(
(array) ($this->action['middleware'] ?? []), $middleware
);
@@ -955,6 +1051,20 @@ class Route
return $this;
}
/**
* Specify that the "Authorize" / "can" middleware should be applied to the route with the given options.
*
* @param string $ability
* @param array|string $models
* @return $this
*/
public function can($ability, $models = [])
{
return empty($models)
? $this->middleware(['can:'.$ability])
: $this->middleware(['can:'.$ability.','.implode(',', Arr::wrap($models))]);
}
/**
* Get the middleware for the route's controller.
*
@@ -996,6 +1106,28 @@ class Route
return (array) ($this->action['excluded_middleware'] ?? []);
}
/**
* Indicate that the route should enforce scoping of multiple implicit Eloquent bindings.
*
* @return bool
*/
public function scopeBindings()
{
$this->action['scope_bindings'] = true;
return $this;
}
/**
* Determine if the route should enforce scoping of multiple implicit Eloquent bindings.
*
* @return bool
*/
public function enforcesScopedBindings()
{
return (bool) ($this->action['scope_bindings'] ?? false);
}
/**
* Specify that the route should not allow concurrent requests from the same session.
*
@@ -1147,7 +1279,17 @@ class Route
public function prepareForSerialization()
{
if ($this->action['uses'] instanceof Closure) {
throw new LogicException("Unable to prepare route [{$this->uri}] for serialization. Uses Closure.");
$this->action['uses'] = serialize(\PHP_VERSION_ID < 70400
? new OpisSerializableClosure($this->action['uses'])
: new SerializableClosure($this->action['uses'])
);
}
if (isset($this->action['missing']) && $this->action['missing'] instanceof Closure) {
$this->action['missing'] = serialize(\PHP_VERSION_ID < 70400
? new OpisSerializableClosure($this->action['missing'])
: new SerializableClosure($this->action['missing'])
);
}
$this->compileRoute();

View File

@@ -43,7 +43,7 @@ class RouteAction
$action['uses'] = static::findCallable($action);
}
if (is_string($action['uses']) && ! Str::contains($action['uses'], '@')) {
if (! static::containsSerializedClosure($action) && is_string($action['uses']) && ! Str::contains($action['uses'], '@')) {
$action['uses'] = static::makeInvokable($action['uses']);
}
@@ -94,4 +94,18 @@ class RouteAction
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'], [
'C:32:"Opis\\Closure\\SerializableClosure',
'O:47:"Laravel\\SerializableClosure\\SerializableClosure',
]) !== false;
}
}

View File

@@ -20,6 +20,10 @@ class RouteGroup
unset($old['domain']);
}
if (isset($new['controller'])) {
unset($old['controller']);
}
$new = array_merge(static::formatAs($new, $old), [
'namespace' => static::formatNamespace($new, $old),
'prefix' => static::formatPrefix($new, $old, $prependExistingPrefix),
@@ -59,7 +63,7 @@ class RouteGroup
*/
protected static function formatPrefix($new, $old, $prependExistingPrefix = true)
{
$old = $old['prefix'] ?? null;
$old = $old['prefix'] ?? '';
if ($prependExistingPrefix) {
return isset($new['prefix']) ? trim($old, '/').'/'.trim($new['prefix'], '/') : $old;

View File

@@ -17,12 +17,15 @@ use InvalidArgumentException;
* @method \Illuminate\Routing\Route options(string $uri, \Closure|array|string|null $action = null)
* @method \Illuminate\Routing\Route any(string $uri, \Closure|array|string|null $action = null)
* @method \Illuminate\Routing\RouteRegistrar as(string $value)
* @method \Illuminate\Routing\RouteRegistrar controller(string $controller)
* @method \Illuminate\Routing\RouteRegistrar domain(string $value)
* @method \Illuminate\Routing\RouteRegistrar middleware(array|string|null $middleware)
* @method \Illuminate\Routing\RouteRegistrar name(string $value)
* @method \Illuminate\Routing\RouteRegistrar namespace(string $value)
* @method \Illuminate\Routing\RouteRegistrar namespace(string|null $value)
* @method \Illuminate\Routing\RouteRegistrar prefix(string $prefix)
* @method \Illuminate\Routing\RouteRegistrar scopeBindings()
* @method \Illuminate\Routing\RouteRegistrar where(array $where)
* @method \Illuminate\Routing\RouteRegistrar withoutMiddleware(array|string $middleware)
*/
class RouteRegistrar
{
@@ -43,7 +46,7 @@ class RouteRegistrar
/**
* The methods to dynamically pass through to the router.
*
* @var array
* @var string[]
*/
protected $passthru = [
'get', 'post', 'put', 'patch', 'delete', 'options', 'any',
@@ -52,10 +55,19 @@ class RouteRegistrar
/**
* The attributes that can be set through this class.
*
* @var array
* @var string[]
*/
protected $allowedAttributes = [
'as', 'domain', 'middleware', 'name', 'namespace', 'prefix', 'where',
'as',
'controller',
'domain',
'middleware',
'name',
'namespace',
'prefix',
'scopeBindings',
'where',
'withoutMiddleware',
];
/**
@@ -65,6 +77,8 @@ class RouteRegistrar
*/
protected $aliases = [
'name' => 'as',
'scopeBindings' => 'scope_bindings',
'withoutMiddleware' => 'excluded_middleware',
];
/**
@@ -93,7 +107,21 @@ class RouteRegistrar
throw new InvalidArgumentException("Attribute [{$key}] does not exist.");
}
$this->attributes[Arr::get($this->aliases, $key, $key)] = $value;
if ($key === 'middleware') {
foreach ($value as $index => $middleware) {
$value[$index] = (string) $middleware;
}
}
$attributeKey = Arr::get($this->aliases, $key, $key);
if ($key === 'withoutMiddleware') {
$value = array_merge(
(array) ($this->attributes[$attributeKey] ?? []), Arr::wrap($value)
);
}
$this->attributes[$attributeKey] = $value;
return $this;
}
@@ -184,6 +212,9 @@ class RouteRegistrar
if (is_array($action) &&
! Arr::isAssoc($action) &&
Reflector::isCallable($action)) {
if (strncmp($action[0], '\\', 1)) {
$action[0] = '\\'.$action[0];
}
$action = [
'uses' => $action[0].'@'.$action[1],
'controller' => $action[0].'@'.$action[1],
@@ -213,7 +244,7 @@ class RouteRegistrar
return $this->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters);
}
return $this->attribute($method, $parameters[0]);
return $this->attribute($method, array_key_exists(0, $parameters) ? $parameters[0] : true);
}
throw new BadMethodCallException(sprintf(

View File

@@ -18,9 +18,13 @@ class RouteSignatureParameters
*/
public static function fromAction(array $action, $subClass = null)
{
$parameters = is_string($action['uses'])
? static::fromClassMethodString($action['uses'])
: (new ReflectionFunction($action['uses']))->getParameters();
$callback = RouteAction::containsSerializedClosure($action)
? unserialize($action['uses'])->getClosure()
: $action['uses'];
$parameters = is_string($callback)
? static::fromClassMethodString($callback)
: (new ReflectionFunction($callback))->getParameters();
return is_null($subClass) ? $parameters : array_filter($parameters, function ($p) use ($subClass) {
return Reflector::isParameterSubclassOf($p, $subClass);

View File

@@ -87,8 +87,8 @@ class RouteUrlGenerator
$route
), $parameters);
if (preg_match('/\{.*?\}/', $uri)) {
throw UrlGenerationException::forMissingParameters($route);
if (preg_match_all('/{(.*?)}/', $uri, $matchedMissingParameters)) {
throw UrlGenerationException::forMissingParameters($route, $matchedMissingParameters[1]);
}
// Once we have ensured that there are no missing parameters in the URI we will encode

View File

@@ -18,9 +18,11 @@ use Illuminate\Http\Response;
use Illuminate\Routing\Events\RouteMatched;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Illuminate\Support\Stringable;
use Illuminate\Support\Traits\Macroable;
use JsonSerializable;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
use ReflectionClass;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
@@ -115,7 +117,7 @@ class Router implements BindingRegistrar, RegistrarContract
/**
* All of the verbs supported by the router.
*
* @var array
* @var string[]
*/
public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
@@ -265,13 +267,19 @@ class Router implements BindingRegistrar, RegistrarContract
* @param string $uri
* @param string $view
* @param array $data
* @param int|array $status
* @param array $headers
* @return \Illuminate\Routing\Route
*/
public function view($uri, $view, $data = [])
public function view($uri, $view, $data = [], $status = 200, array $headers = [])
{
return $this->match(['GET', 'HEAD'], $uri, '\Illuminate\Routing\ViewController')
->defaults('view', $view)
->defaults('data', $data);
->setDefaults([
'view' => $view,
'data' => $data,
'status' => is_array($status) ? 200 : $status,
'headers' => is_array($status) ? $status : $headers,
]);
}
/**
@@ -507,10 +515,11 @@ class Router implements BindingRegistrar, RegistrarContract
$action = ['uses' => $action];
}
// Here we'll merge any group "uses" statement if necessary so that the action
// has the proper clause for this property. Then we can simply set the name
// of the controller on the action and return the action array for usage.
// Here we'll merge any group "controller" and "uses" statements if necessary so that
// the action has the proper clause for this property. Then, we can simply set the
// name of this controller on the action plus return the action array for usage.
if ($this->hasGroupStack()) {
$action['uses'] = $this->prependGroupController($action['uses']);
$action['uses'] = $this->prependGroupNamespace($action['uses']);
}
@@ -536,6 +545,31 @@ class Router implements BindingRegistrar, RegistrarContract
? $group['namespace'].'\\'.$class : $class;
}
/**
* Prepend the last group controller onto the use clause.
*
* @param string $class
* @return string
*/
protected function prependGroupController($class)
{
$group = end($this->groupStack);
if (! isset($group['controller'])) {
return $class;
}
if (class_exists($class)) {
return $class;
}
if (strpos($class, '@') !== false) {
return $class;
}
return $group['controller'].'@'.$class;
}
/**
* Create a new Route object.
*
@@ -638,6 +672,8 @@ class Router implements BindingRegistrar, RegistrarContract
{
$this->current = $route = $this->routes->match($request);
$route->setContainer($this->container);
$this->container->instance(Route::class, $route);
return $route;
@@ -695,14 +731,36 @@ class Router implements BindingRegistrar, RegistrarContract
*/
public function gatherRouteMiddleware(Route $route)
{
$computedMiddleware = $route->gatherMiddleware();
$excluded = collect($route->excludedMiddleware())->map(function ($name) {
return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups);
})->flatten()->values()->all();
$middleware = collect($route->gatherMiddleware())->map(function ($name) {
$middleware = collect($computedMiddleware)->map(function ($name) {
return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups);
})->flatten()->reject(function ($name) use ($excluded) {
return in_array($name, $excluded, true);
if (empty($excluded)) {
return false;
}
if ($name instanceof Closure) {
return false;
}
if (in_array($name, $excluded, true)) {
return true;
}
if (! class_exists($name)) {
return false;
}
$reflection = new ReflectionClass($name);
return collect($excluded)->contains(function ($exclude) use ($reflection) {
return class_exists($exclude) && $reflection->isSubclassOf($exclude);
});
})->values();
return $this->sortMiddleware($middleware);
@@ -748,11 +806,14 @@ class Router implements BindingRegistrar, RegistrarContract
$response = (new HttpFoundationFactory)->createResponse($response);
} elseif ($response instanceof Model && $response->wasRecentlyCreated) {
$response = new JsonResponse($response, 201);
} elseif ($response instanceof Stringable) {
$response = new Response($response->__toString(), 200, ['Content-Type' => 'text/html']);
} elseif (! $response instanceof SymfonyResponse &&
($response instanceof Arrayable ||
$response instanceof Jsonable ||
$response instanceof ArrayObject ||
$response instanceof JsonSerializable ||
$response instanceof \stdClass ||
is_array($response))) {
$response = new JsonResponse($response);
} elseif (! $response instanceof SymfonyResponse) {
@@ -923,6 +984,18 @@ class Router implements BindingRegistrar, RegistrarContract
return $this;
}
/**
* Flush the router's middleware groups.
*
* @return $this
*/
public function flushMiddlewareGroups()
{
$this->middlewareGroups = [];
return $this;
}
/**
* Add a new route parameter binder.
*
@@ -1043,7 +1116,7 @@ class Router implements BindingRegistrar, RegistrarContract
/**
* Get the currently dispatched route instance.
*
* @return \Illuminate\Routing\Route
* @return \Illuminate\Routing\Route|null
*/
public function getCurrentRoute()
{
@@ -1249,6 +1322,19 @@ class Router implements BindingRegistrar, RegistrarContract
return $result;
}
/**
* Set the container instance used by the router.
*
* @param \Illuminate\Container\Container $container
* @return $this
*/
public function setContainer(Container $container)
{
$this->container = $container;
return $this;
}
/**
* Dynamically handle calls into the router instance.
*
@@ -1266,6 +1352,6 @@ class Router implements BindingRegistrar, RegistrarContract
return (new RouteRegistrar($this))->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters);
}
return (new RouteRegistrar($this))->attribute($method, $parameters[0]);
return (new RouteRegistrar($this))->attribute($method, array_key_exists(0, $parameters) ? $parameters[0] : true);
}
}

View File

@@ -126,6 +126,8 @@ class RoutingServiceProvider extends ServiceProvider
* Register a binding for the PSR-7 request implementation.
*
* @return void
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function registerPsrRequest()
{
@@ -145,6 +147,8 @@ class RoutingServiceProvider extends ServiceProvider
* Register a binding for the PSR-7 response implementation.
*
* @return void
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function registerPsrResponse()
{

52
vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php vendored Normal file → Executable file
View File

@@ -239,9 +239,7 @@ class UrlGenerator implements UrlGeneratorContract
// Once we get the root URL, we will check to see if it contains an index.php
// file in the paths. If it does, we will remove it since it is not needed
// for asset paths, but only for routes to endpoints in the application.
$root = $this->assetRoot
? $this->assetRoot
: $this->formatRoot($this->formatScheme($secure));
$root = $this->assetRoot ?: $this->formatRoot($this->formatScheme($secure));
return $this->removeIndex($root).'/'.trim($path, '/');
}
@@ -320,13 +318,9 @@ class UrlGenerator implements UrlGeneratorContract
*/
public function signedRoute($name, $parameters = [], $expiration = null, $absolute = true)
{
$parameters = Arr::wrap($parameters);
if (array_key_exists('signature', $parameters)) {
throw new InvalidArgumentException(
'"Signature" is a reserved parameter when generating signed routes. Please rename your route parameter.'
);
}
$this->ensureSignedRouteParametersAreNotReserved(
$parameters = Arr::wrap($parameters)
);
if ($expiration) {
$parameters = $parameters + ['expires' => $this->availableAt($expiration)];
@@ -341,6 +335,27 @@ class UrlGenerator implements UrlGeneratorContract
], $absolute);
}
/**
* Ensure the given signed route parameters are not reserved.
*
* @param mixed $parameters
* @return void
*/
protected function ensureSignedRouteParametersAreNotReserved($parameters)
{
if (array_key_exists('signature', $parameters)) {
throw new InvalidArgumentException(
'"Signature" is a reserved parameter when generating signed routes. Please rename your route parameter.'
);
}
if (array_key_exists('expires', $parameters)) {
throw new InvalidArgumentException(
'"Expires" is a reserved parameter when generating signed routes. Please rename your route parameter.'
);
}
}
/**
* Create a temporary signed route URL for a named route.
*
@@ -368,6 +383,17 @@ class UrlGenerator implements UrlGeneratorContract
&& $this->signatureHasNotExpired($request);
}
/**
* Determine if the given request has a valid signature for a relative URL.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
public function hasValidRelativeSignature(Request $request)
{
return $this->hasValidSignature($request, false);
}
/**
* Determine if the signature from the given request matches the URL.
*
@@ -379,11 +405,9 @@ class UrlGenerator implements UrlGeneratorContract
{
$url = $absolute ? $request->url() : '/'.$request->path();
$original = rtrim($url.'?'.Arr::query(
Arr::except($request->query(), 'signature')
), '?');
$queryString = ltrim(preg_replace('/(^|&)signature=[^&]+/', '', $request->server->get('QUERY_STRING')), '&');
$signature = hash_hmac('sha256', $original, call_user_func($this->keyResolver));
$signature = hash_hmac('sha256', rtrim($url.'?'.$queryString, '?'), call_user_func($this->keyResolver));
return hash_equals($signature, (string) $request->query('signature', ''));
}

View File

@@ -2,38 +2,38 @@
namespace Illuminate\Routing;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Contracts\Routing\ResponseFactory;
class ViewController extends Controller
{
/**
* The view factory implementation.
* The response factory implementation.
*
* @var \Illuminate\Contracts\View\Factory
* @var \Illuminate\Contracts\Routing\ResponseFactory
*/
protected $view;
protected $response;
/**
* Create a new controller instance.
*
* @param \Illuminate\Contracts\View\Factory $view
* @param \Illuminate\Contracts\Routing\ResponseFactory $response
* @return void
*/
public function __construct(ViewFactory $view)
public function __construct(ResponseFactory $response)
{
$this->view = $view;
$this->response = $response;
}
/**
* Invoke the controller method.
*
* @param array $args
* @return \Illuminate\Contracts\View\View
* @return \Illuminate\Http\Response
*/
public function __invoke(...$args)
{
[$view, $data] = array_slice($args, -2);
[$view, $data, $status, $headers] = array_slice($args, -4);
return $this->view->make($view, $data);
return $this->response->view($view, $data, $status, $headers);
}
}

View File

@@ -14,17 +14,19 @@
}
],
"require": {
"php": "^7.2.5|^8.0",
"php": "^7.3|^8.0",
"ext-json": "*",
"illuminate/container": "^7.0",
"illuminate/contracts": "^7.0",
"illuminate/http": "^7.0",
"illuminate/pipeline": "^7.0",
"illuminate/session": "^7.0",
"illuminate/support": "^7.0",
"symfony/http-foundation": "^5.0",
"symfony/http-kernel": "^5.0",
"symfony/routing": "^5.0"
"illuminate/collections": "^8.0",
"illuminate/container": "^8.0",
"illuminate/contracts": "^8.0",
"illuminate/http": "^8.0",
"illuminate/macroable": "^8.0",
"illuminate/pipeline": "^8.0",
"illuminate/session": "^8.0",
"illuminate/support": "^8.0",
"symfony/http-foundation": "^5.4",
"symfony/http-kernel": "^5.4",
"symfony/routing": "^5.4"
},
"autoload": {
"psr-4": {
@@ -33,11 +35,11 @@
},
"extra": {
"branch-alias": {
"dev-master": "7.x-dev"
"dev-master": "8.x-dev"
}
},
"suggest": {
"illuminate/console": "Required to use the make commands (^7.0).",
"illuminate/console": "Required to use the make commands (^8.0).",
"nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).",
"symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0)."
},