This is proof-of-concept implementation of laravel’s like form requests.
Most of Symfony developers uses forms to map request data to some Data Transfer Object.This object then passes to validator and system start to work with validated data convertedto be compatible with application model.
Symfony/forms is great component which simplifies life alot when you are dealing with forms.But what if you don’t have any forms? For example you are developing HTTP API and you already havepretty much structured request data, which should be validated.
FosRest bundle provides ParamFetcher
, but it doesn’t allow to validate all request and will fail onfirst failed constraint.
Laravel has FormRequest, which encapsulates all validation stuff inside of custom user-defined request.This allows to DRY request validation and validation of input data can be done in middlewareat front-controller level.
Why not bring this idea to Symfony?
Basically anything, but for our implementation we suggest to pass:
This solutions is similar to Laravel’s FormRequests but it responsible only for data validationIf you need to restruct access to this particular request you should use symfony/security features.
For data validation this solution uses symfony/validation. All rules is just good old constraints provided by symfony. So if youneed to validate simple request for new book, all that you need is to define CreateBookRequest
extended from base class, and use in in your controller’s actions:
namespace AppHttpRequest;use SymfonyComponentValidatorConstraints as Assert;class CreateBookRequest extends Request{ public function rules() { return new AssertCollection([ 'name' => new AssertRequired(['message' => 'Book name required']), 'brief' => new AssertRequired(['message' => 'Book brief description required']), 'year' => new AssertRequired(['message' => 'Year of publishing is required']), 'cover' => new AssertImage(['message' => 'Book cover image is required']) ]); }}
public function createBookAction(CreateBookRequest $request){ $coverImage = $this->coverMaker->make($request->get('cover'); $book = new Book( $request->get('name'), $request->get('brief'), $request->get('year'), $coverImage ); // ...}
This request objects can be used just as DTO, but you may may want to use more strict approaches.For example in php7.1 there will be typed properties, and you may want to make use of it:
class CreateBookRequest extends Request{ /** @AssertRequired(message="Book name required") */ private string $name; /** @AssertRequired(message="Book brief description required") */ private string $brief; /** @AssertRequired(message="Year of publishing is required") */ private int $year; /** @AssertImage(message="Book cover image is required") */ private UploadedFile $cover; // this could be moved into // some trait for example protected function payload() { return $this; } /** * This method allows you to manipulate with data. * It called right after data is validated * * If you want to change data before validation * then override `__constructor`. */ protected function resolve(array $payload) { // other php 7.1 features // array destructuring assignment [ 'name' => $this->name, 'brief' => $this->brief, 'year' => $this->brief, 'cover' => $this->cover ] = $payload; } // getters stuff...}
If you for some reasone need to validate request data depending on context, you can use validation groupsto have different constraints to be applied depending on payload:
namespace AppHttpRequest;use SymfonyComponentValidatorConstraints as Assert;class CreateBookRequest extends Request{ protected function rules() { return new AssertCollection([ 'provider' => new AssertChoise(['basic', 'facebook', 'twitter']), 'identity' => new AssertRequired(['message' => 'Your resource user id is required', 'group' => 'oauth']), 'email' => new AssertEmail(['message' => 'Email is required', 'group' => 'basic']), 'secret' => new AssertRequired(['message' => 'Your app token is required', 'group' => 'oauth']), 'password' => new AssertRequired(['message' => 'Your password is required', 'group' => 'basic']), ]); } protected function validationGroups(array $payload) { return [ 'Default', ['basic' => 'basic'][$payload['provider'] ?? 'basic'] ?? 'oauth' ]; }}
Как менялся логотип Apple на протяжении многих лет. Логотип Apple — это не просто символ,…
Security Boot Fail при загрузке Acer — решение проблемы При загрузке ноутбука Acer с флешки,…
Ноутбук не включается — варианты решения Если при попытке включить ноутбук вы обнаруживаете, что он…
The AC power adapter wattage and type cannot be determined — причины и решение При…
Свистит или звенит блок питания компьютера — причины и решения Некоторые владельцы ПК могут обратить…
Мигает Caps Lock на ноутбуке HP — почему и что делать? При включении ноутбука HP…