Last active
November 27, 2022 15:52
-
-
Save zabaala/2e7e766c4ae5b0a97d2b71e1179e5fc3 to your computer and use it in GitHub Desktop.
How to validate domain DTOs using Laravel Framework avoiding use of FormRequest approaches.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* A Simple way to use a DTO and your validations instead of a Laravel FormRequest approach. | |
*/ | |
Route::post('/test', function (\Core\Comparison\Application\DTOs\SampleInput $input) { | |
// After a validation, should be possible retrieve a | |
// instance of input with all your properties filled. | |
return dd($input); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"id": 1, | |
"firstname": "Mauricio", | |
"lastname": "Rodrigues", | |
"age": 37 // property/value will be ignored. Continue reading the codes to understand why. | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Core\SomeDomain\Application\DTOs; | |
use Exception; | |
use Illuminate\Contracts\Validation\ValidatesWhenResolved; | |
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; | |
class SampleInput implements ValidatesWhenResolved | |
{ | |
/** | |
* Notes: | |
* Properties should be nullables, can be promoted, but can't be readonly, | |
* because all there will be filled after the call of __constructor method. | |
* Considering that we don't want to create a package to solve this issue, these considerations | |
* are acceptable. But we need to check the clean architecture principles to know if some one of these criteria | |
* represent a pattern violation. | |
* | |
* | |
* @param string|null $id | |
* @param string|null $firstname | |
* @param string|null $lastname | |
*/ | |
public function __construct( | |
public ?string $id = null, | |
public ?string $firstname = null, | |
public ?string $lastname = null | |
) {} | |
/** | |
* This method will be called by kernel on the request live cycle. | |
* I believe that just with it is possible to validate a DTO using annotations or attributes validations, | |
* without need to change anything in some low level of the framework, without create, by example, a package | |
* to do that. | |
* | |
* As I said, I believe, but I don't have a confirmation of that. | |
* | |
* I'll continue to trying implements a solutions for that. | |
* | |
* @return void | |
* @throws Exception | |
*/ | |
public function validateResolved(): void | |
{ | |
$properties = get_object_vars($this); | |
foreach ($properties as $property => $value) { | |
$this->{$property} = request($property); | |
} | |
// validate this DTO... | |
// $validator = app()->get(ValidatorInterface::class); // implement as you want... | |
// $validator->validate($this); if invalid, throw an Exception to the request. | |
// Since here, to continue, comment code bellow or, to see an error, leave the codes uncommented. | |
// create an error list... | |
$errors = [ | |
'id' => 'Invalid ID for some reason...', | |
'firstname' => 'Firstname cannot be blank.', | |
'lastname' => 'Lastname must have at least 3 characters.', | |
]; | |
/** | |
* ...and throws some HttpException interface. | |
* For the moment, we don't have a full control about the response structure. | |
* But we need to investigate how to change the response body to send back our errors properly. | |
* | |
* I've an idea that we can intercept here the request and apply change to him. | |
*/ | |
throw new class(json_encode($errors)) extends \Exception implements HttpExceptionInterface | |
{ | |
public function getStatusCode(): int | |
{ | |
return 403; | |
} | |
public function getHeaders(): array | |
{ | |
return ['Content-type' => 'application/problem+json']; | |
} | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment