Skip to main content

INTRODUÇÃO

É possível usar no Accelero (v2.17.0 em diante) um sistema de "request validados", parecido com o sistema de validação de requests do Laravel.

Com isso é possível tirar do Controller a lógica de validação de requests e deixar apenas a lógica de negócio, separando as responsabilidades.

Você pode validar o que quiser fora do Controller, mas a sugestão é:

  • validar se todos os campos esperados no request estão presentes;
  • validar se o usuário tem permissão pra executar a ação.

Pra criar um sistema desse tipo, são três etapas:

VALIDATED REQUEST

Criar uma classe pra representar o "request validado". Ela deve ter uma estrutura parecida com:

<?php
namespace Accelero\Controllers\FormRequests;

use Iongrade\Exceptions\InvalidRequestException;
use Iongrade\Exceptions\NoPermissionException;
use Laminas\Diactoros\ServerRequest;

class ClasseXYZSaveFormRequest extends ServerRequest {
public readonly string $foo;
public readonly int $bar;
/**
* @throws NoPermissionException
* @throws InvalidRequestException
*/
public function __construct(array $serverParams = [], array $uploadedFiles = [], $uri = null, ?string $method = null, $body = 'php://input', array $headers = [], array $cookieParams = [], array $queryParams = [], $parsedBody = null, string $protocol = '1.1') {
parent::__construct($serverParams, $uploadedFiles, $uri, $method, $body, $headers, $cookieParams, $queryParams, $parsedBody, $protocol);
$this->validate();
}
/**
* @throws InvalidRequestException
* @throws NoPermissionException
*/
private function validate() : void {
$parsedBody = $this->getParsedBody();
if (!is_array($parsedBody)) throw new InvalidRequestException('Request body did not provide proper array');
if (null === ($parsedBody['foo'] ?? null)) throw new InvalidRequestException();
if (null === ($parsedBody['bar'] ?? null)) throw new InvalidRequestException();
if (false === ClasseXYZ::checkPermissionStatic('save')) throw new NoPermissionException();

$this->foo = $parsedBody['foo'];
$this->bar = $parsedBody['bar'];
}
}

Note que:

  • foi chamado o construtor do parent;
  • foram feitas validações de campos presentes;
  • foi feita checagem de permissão fazendo referência à ClasseXYZ;
  • foram criados alguns campos foo e bar pra facilitar o uso mais pra frente.

MIDDLEWARE

É necessário criar um middleware simples que vai ser responsável por criar o request validado. Estrutura básica:

<?php
namespace Accelero\Controllers\Middleware;

use Accelero\Controllers\FormRequests\ClasseXYZSaveFormRequest;
use Accelero\Controllers\FormRequests\FormRequestFactory;
use Exception;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class ClasseXYZSaveMiddleware implements MiddlewareInterface {
/**
* @throws Exception
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface {
$request = FormRequestFactory::createFromType(ClasseXYZSaveFormRequest::class);
return $handler->handle($request);
}
}

ROTA

É necessário especificar, na rota, que o Middleware que acabamos de criar deve ser utilizado:

<?php

use Accelero\Controllers\ClassexYZController;
use Accelero\Controllers\Middleware\ClasseXYZSaveMiddleware;
use Accelero\Controllers\Middleware\LoggedInMiddleware;
use Accelero\Router\Route;

return [
new Route('*', '/classeXYZ/save', [ClassexYZController::class, 'myAction'], middleware: [LoggedInMiddleware::class, ClasseXYZSaveMiddleware::class]),
];

CONTROLLER

Finalmente, devemos especificar no nosso Controller que receberemos um request específico validado (mas nem é obrigatório fazer isso, já que o request validade extende o ServerRequestInterface -- apenas pode ajudar porque você pode aproveitar campos específicos que foram setados).

<?php
namespace Accelero\Controllers;

use Accelero\Controllers\FormRequests\ClasseXYZSaveFormRequest;
use Psr\Http\Message\ResponseInterface;
use SinFramework\DataFlusher\DataFlusher;

class ClasseXYZController {
public function myAction(ClasseXYZSaveFormRequest $request) : ResponseInterface {
$message = $request->foo . ' >> ' . $request->bar;
return DataFlusher::flush($request, DataFlusher::HTTP_OK, $message);
}
}

PRECISA DISSO?

Não.

Se você usar o "modo padrão" do roteador Route (https://route.thephpleague.com/), tudo vai funcionar. Na verdade, o sistema praticamente inteiro funciona sem isso, e todos os requests são "genéricos e validados diretamente no Controller".

Mas pode ajudar, principalmente:

  1. pra separar as responsabilidades dos componentes;
  2. pra simplificar os controller;
  3. pra que o sistema tenha um pouco mais "cara de mercado/Laravel", onde esse paradigma é comum.