refactor: 💡 重构 ValidationMiddleware

This commit is contained in:
wangyi 2019-09-10 18:38:28 +08:00
parent f2258295d0
commit 181bfa2ed0

View File

@ -12,14 +12,8 @@ declare(strict_types=1);
namespace Hyperf\Validation\Middleware;
use Closure;
use FastRoute\Dispatcher;
use Hyperf\Contract\NormalizerInterface;
use Hyperf\Di\MethodDefinitionCollectorInterface;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\HttpServer\Router\DispatcherFactory;
use Hyperf\Utils\Context;
use Hyperf\Utils\Contracts\Arrayable;
use Hyperf\Validation\Contracts\Validation\ValidatesWhenResolved;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
@ -41,8 +35,8 @@ class ValidationMiddleware implements MiddlewareInterface
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$factory = $this->container->get(DispatcherFactory::class);
$this->container = $container;
$factory = $this->container->get(DispatcherFactory::class);
$this->dispatcher = $factory->getDispatcher('http');
}
@ -52,107 +46,15 @@ class ValidationMiddleware implements MiddlewareInterface
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
/** @var ResponseInterface $response */
$uri = $request->getUri();
/**
* @var array
* Returns array with one of the following formats:
* [self::NOT_FOUND]
* [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']]
* [self::FOUND, $handler, ['varName' => 'value', ...]]
*/
$routes = $this->dispatcher->dispatch($request->getMethod(), $uri->getPath());
switch ($routes[0]) {
case Dispatcher::NOT_FOUND:
case Dispatcher::METHOD_NOT_ALLOWED:
break;
case Dispatcher::FOUND:
$this->handleFound($routes, $request);
break;
/** @var Dispatched $dispatched */
$dispatched = $request->getAttribute(Dispatched::class);
$params = $dispatched->params;
foreach ($params as $param) {
if ($param instanceof ValidatesWhenResolved) {
$param->validateResolved();
}
}
return $handler->handle($request);
}
/**
* @param array|string $handler
*/
protected function prepareHandler($handler): array
{
if (is_string($handler)) {
if (strpos($handler, '@') !== false) {
return explode('@', $handler);
}
return explode('::', $handler);
}
if (is_array($handler) && isset($handler[0], $handler[1])) {
return $handler;
}
throw new \RuntimeException('Handler not exist.');
}
/**
* Handle the response when found.
*
* @return array|Arrayable|mixed|ResponseInterface|string
*/
protected function handleFound(array $routes, ServerRequestInterface $request)
{
if ($routes[1] instanceof Closure) {
// Do nothing
} else {
[$controller, $action] = $this->prepareHandler($routes[1]);
if (! method_exists($controller, $action)) {
// Route found, but the handler does not exist.
return $this->response()->withStatus(500)->withBody(new SwooleStream('Method of class does not exist.'));
}
$params = $this->parseParameters($controller, $action, $routes[2]);
foreach ($params as $param) {
if ($param instanceof ValidatesWhenResolved) {
$param->validateResolved();
}
}
}
}
/**
* Get response instance from context.
*/
protected function response(): ResponseInterface
{
return Context::get(ResponseInterface::class);
}
/**
* Parse the parameters of method definitions, and then bind the specified arguments or
* get the value from DI container, combine to a argument array that should be injected
* and return the array.
*/
protected function parseParameters(string $controller, string $action, array $arguments): array
{
$injections = [];
$this->container->get(MethodDefinitionCollectorInterface::class);
$definitions = $this->container->get(MethodDefinitionCollectorInterface::class)->getParameters($controller, $action);
foreach ($definitions ?? [] as $pos => $definition) {
$value = $arguments[$pos] ?? $arguments[$definition->getMeta('name')] ?? null;
if ($value === null) {
if ($definition->getMeta('defaultValueAvailable')) {
$injections[] = $definition->getMeta('defaultValue');
} elseif ($definition->allowsNull()) {
$injections[] = null;
} elseif ($this->container->has($definition->getName())) {
$injections[] = $this->container->get($definition->getName());
} else {
throw new \InvalidArgumentException("Parameter '{$definition->getMeta('name')}' "
. "of {$controller}::{$action} should not be null");
}
} else {
$injections[] = $this->container->get(NormalizerInterface::class)->denormalize($value, $definition->getName());
}
}
return $injections;
}
}