https://github.com/tblindaruk/laravel-request-mapper
mapping laravel request to the DTO objects
https://github.com/tblindaruk/laravel-request-mapper
dto laravel laravel-package request-mapping
Last synced: about 1 year ago
JSON representation
mapping laravel request to the DTO objects
- Host: GitHub
- URL: https://github.com/tblindaruk/laravel-request-mapper
- Owner: TBlindaruk
- License: mit
- Created: 2018-12-15T08:54:57.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2021-12-22T01:37:04.000Z (over 4 years ago)
- Last Synced: 2025-04-02T06:12:17.274Z (about 1 year ago)
- Topics: dto, laravel, laravel-package, request-mapping
- Language: PHP
- Homepage:
- Size: 87.9 KB
- Stars: 33
- Watchers: 3
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# Request Mapper for Laravel
This component allow you to inject DTO object mapped from the Request to the action.
1. [Install](#install)
2. [Requirements](#requirements)
3. [Basic usage](#basic)
4. [Nested object](#nested)
5. [Mapped strategies](#mapped-strategies)
6. [Create custom mapped strategy](#custom-mapped-strategy)
7. [How to create an custom exception?](#change-exception)
8. [Project example](#example)
9. [Contributing](#contributing)
10. [Licence](#licence)
11. [TODO](#todo)
You can install this package via composer using this command:
```
composer require maksi/laravel-request-mapper
```
The package will automatically register itself.
PHP 7.1 or newer and Laravel 5.5 or newer
3.1 Create an DTO object
```PHP
name = $data['name'] ?? null;
}
public function getName(): string
{
return $this->name;
}
}
```
Your DTO object should extend one of RequestData classes:
- [AllRequestData](./src/Filling/RequestData/AllRequestData.php)
- [HeaderRequestData](./src/Filling/RequestData/HeaderRequestData.php)
- [JsonRequestData](./src/Filling/RequestData/JsonRequestData.php)
RequestData classes responsible for [mapped strategies](#mapped-strategies).
`$data` array in the `init` it is an `array` which return from the [mapped strategies](#mapped-strategies) classes. Basically `$data` it is some data from the `Request`.
3.2 Inject to the action
DTO object can be injected to any type of action.
```PHP
3.3 Validate DTO object
You can apply validation to the DTO object:
- before mapping data to the DTO (`laravel` validation)
- after mapping data to the DTO (`symfony annotation` validation)
3.3.1 Apply laravel validation
Laravel validation applied for the `RequestData` object before object filling.
1. You should create a class with validation rules. This class should implement `Maksi\LaravelRequestMapper\Validation\BeforeType\Laravel\ValidationRuleInterface` interface (in case, if you do no need change the validation `messages` and `customAttributes`, than you can extend `Maksi\LaravelRequestMapper\Validation\BeforeType\Laravel\AbstractValidationRule` class)
```PHP
'array|required',
'title' => 'string|required',
];
}
}
```
2. In the next you should apply this rules to the DTO object. This should be done via `annotation`.
```PHP
title = $data['title'] ?? null;
$this->nested = new NestedRequestDataStub($data['nested'] ?? []);
}
public function getTitle(): string
{
return $this->title;
}
public function getNested(): NestedRequestDataStub
{
return $this->nested;
}
}
```
string
```PHP
@ValidationClass(class="\Maksi\LaravelRequestMapper\Tests\Integration\LaravelNestedValidation\Stub\ValidatorRule")
```
indicates that before filling current DTO should be appied `\Maksi\LaravelRequestMapper\Tests\Integration\LaravelNestedValidation\Stub\ValidatorRule` rules for the `data` which will be injected to the dto.
3.3.2 Apply symfony annotation validation
Annotation symfony validation applied to the properties in the `RequestData` object (So this validation appied after the creating and DTO object).
At the first you should add the `@Type(type="annotation")` annotation to the RequestData object. After this you can apply the validation to the DTO object (for more information please see symfony [validation documentation](https://symfony.com/doc/current/validation.html))
```PHP
allAge = $data['age'] ?? null;
$this->allTitle = $data['title'] ?? null;
}
public function getAllTitle(): string
{
return $this->allTitle;
}
public function getAllAge(): int
{
return $this->allAge;
}
}
```
4.1. Symfony annotation validation
In the same way you can create an nested DTO object, for example:
Root class
```PHP
title = $data['title'] ?? null;
$this->nested = new NestedRequestDataStub($data['nested'] ?? []);
}
public function getTitle(): string
{
return $this->title;
}
public function getNested(): NestedRequestDataStub
{
return $this->nested;
}
}
```
Nested class
```PHP
nestedTitle = $data['title'] ?? null;
}
public function getTitle(): string
{
return $this->nestedTitle;
}
}
```
4.2. Laravel validation for nested
So, as a laravel validation applied before filling the `RequestData` object, than you should just create the same validation class as an for no nested validation.
```PHP
'array|required',
'title' => 'string|required',
'nested.title' => 'string|required', // nested object validation
];
}
}
```
By default package has 3 strategies:
- [AllStrategy](./src/Filling/Strategies/AllStrategy.php)
- [HeaderStrategy](./src/Filling/Strategies/HeaderStrategy.php)
- [JsonStrategy](./src/Filling/Strategies/JsonStrategy.php)
AllStrategy - responsible for filling data from the `$request->all()` array. If you want to use this strategy, than your `RequestData` object should extend `AllRequestData` class.
HeaderStrategy - responsible for filling data from the `$request->header->all()` array. If you want to use this strategy, than your `RequestData` object should extend `HeaderRequestData` class.
JsonStrategy - responsible for filling data from the `$request->json()->all()` array. If you want to use this strategy, than your `RequestData` object should extend `JsonRequestData` class.
6. Create custom mapped strategy
You can create a custom mapped strategies for our application.
6.1 Create custom strategy
You strategy should implement [StrategyInterface](./src/Filling/Strategies/StrategyInterface.php);
```PHP
all();
}
public function support(Request $request, RequestData $object): bool
{
return $object instanceof TeacherSearchRequestData
&& $request->routeIs('teacher-search');
}
}
```
Method `support` define is strategy available for `resolve` object. This method has 2 parameters `$request` and `$object`:
- `$request` as a `Request` instance
- `$object` - it is empty DTO instance, witch will be filled
Method `resolve` will return the array which will be injected to the DTO instance. This method accept `$request` object.
6.2 Create RequestData class for Strategy
You should extend [RequestData](./src/Filling/RequestData/RequestData.php) in case if you want to create your own strategy
```PHP
name = $data['name'] ?? null;
}
public function getName(): string
{
return $this->name;
}
}
```
6.3 Register your strategy in the `ServiceProvider`
You should add instance of your `strategy` to the `Maksi\LaravelRequestMapper\StrategiesHandler` via `addStrategy` method.
```PHP
addStrategy($this->app->make(TeacherSearchStrategy::class));
}
}
```
7. Change validation exception
1. Create Exception which will extend `\Maksi\LaravelRequestMapper\Validation\ResponseException\AbstractException` and implement toResponse method
For example:
```PHP
setStatusCode(\Illuminate\Http\Response::HTTP_UNPROCESSABLE_ENTITY);
}
}
```
2. Define in `config/laravel-request-mapper.php` `exception-class` key
```PHP
\Maksi\LaravelRequestMapper\Validation\ResponseException\DefaultException::class,
];
```
You can see example of usage part of this package in https://github.com/E-ZSTU/rozklad-rest-api project.
Please see [CONTRIBUTING](./CONTRIBUTING.md) for details.
The MIT License (MIT). Please see [License](./LICENSE) File for more information.
- [ ] think about https://www.reddit.com/r/laravel/comments/af843q/laravel_request_mapper/edx39cj
- [ ] think about https://www.reddit.com/r/laravel/comments/af843q/laravel_request_mapper/edx8mci
- [ ] delete symfony validation, since I`m not sure that is needed for the laravel community
- [ ] add integration tests for `change exception`
- [ ] add priority to the strategies
- [ ] how you can get this DTO from the middleware (just register `RequestData` as a singleton)