Skip to content

Instantly share code, notes, and snippets.

@kmuenkel
Last active May 7, 2021 14:51
Show Gist options
  • Save kmuenkel/522cdf786cdd3258f0f8c3fba84cbb2e to your computer and use it in GitHub Desktop.
Save kmuenkel/522cdf786cdd3258f0f8c3fba84cbb2e to your computer and use it in GitHub Desktop.
Make sure any custom values applied to the request object past into this class get transposed onto any Controller type-hinted Request objects as well
<?php
namespace App\Http\Middleware;
use Closure;
use Exception;
use RuntimeException;
use ReflectionMethod;
use ReflectionFunction;
use Illuminate\Http\{Request, Response};
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Container\Container;
use Illuminate\Routing\{Controller, Route, Router, Redirector};
/**
* Make sure any custom values applied to the request object past into this class get transposed onto any Controller
* type-hinted Request objects as well
*
* Class SoftRedirect
* @package Lti\Http\Middleware
*/
class SoftRedirect
{
const LIMIT = 10;
/**
* @var int
*/
protected static $redirects = 0;
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$route = $request->route();
$parameters = $this->getTargetParameters($route);
foreach ($parameters as $name => $parameter) {
$parameter instanceof Request && $this->rebindRequests($request, $parameter);
}
return $next($request);
}
/**
* @param Request $currentRequest
* @param Request $newRequest
*/
protected function rebindRequests(Request $currentRequest, Request $newRequest)
{
$newRequest->query->add($currentRequest->query->all());
app()->resolving(FormRequest::class, function (Request $originalRequest, Container $app) use ($currentRequest) {
$formRequest = FormRequest::createFrom($app['request'], $originalRequest);
$formRequest->setContainer($app)->setRedirector($app->make(Redirector::class));
$formRequest->query->add($currentRequest->query->all());
});
app()->bind(get_class($newRequest), function () use ($newRequest) {
return $newRequest;
});
}
/**
* @param Route $route
* @return array
*/
protected function getTargetParameters(Route $route): array
{
['controller' => $controller, 'method' => $method] = $this->getTarget($route);
$parameters = $route->parametersWithoutNulls();
$reflector = $controller instanceof Closure ? app(ReflectionFunction::class, ['name' => $controller])
: app(ReflectionMethod::class, ['class_or_method' => $controller, 'name' => $method]);
return $route->resolveMethodDependencies($parameters, $reflector);
}
/**
* @param Route $route
* @return array
*/
protected function getTarget(Route $route): array
{
$controller = static::getController($route);
$method = $route->getActionMethod();
return compact('controller', 'method');
}
/**
* @param string $uri
* @param string $method
* @param array $parameters
* @return Response
* @throws Exception
*/
public static function response(string $uri, $method = 'GET', array $parameters = []): Response
{
if (static::$redirects++ >= self::LIMIT) {
throw new RuntimeException('Too many redirects.');
}
$request = Request::create($uri, $method, $parameters);
$request = static::applyMiddleware($request);
$response = app(Router::class)->dispatch($request);
return response($response->getContent(), $response->getStatusCode(), $response->headers->all());
}
/**
* @param Request $request
* @return Request
* @throws Exception
*/
protected static function applyMiddleware(Request $request): Request
{
$route = app(Router::class)->getRoutes()->match($request);
$controller = static::getController($route);
if ($controller instanceof Controller) {
$controller->middleware(static::class);
} else {
$request->setRouteResolver(function () use ($route) {
return $route;
});
$request = app(static::class)->handle($request, function (Request $request) {
return $request;
});
}
return $request;
}
/**
* @param Route $route
* @return callable|Controller
*/
protected static function getController(Route $route)
{
$action = $route->getAction('uses');
return is_callable($action) ? $action : $route->getController();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment