fesor/request-objects
Composer 安装命令:
composer require fesor/request-objects
包简介
Custom request objects for Symfony made to make life less painful
README 文档
README
Note: This library should not be considered as production ready until 1.0 release. Please provide your feedback to make it happen!
Why?
Symfony Forms component is a very powerful tool for handling forms. But nowadays things have changed.
Complex forms are handled mostly on the client side. As for simple forms symfony/forms has very large overhead.
And in some cases you just don't have forms. For example, if you are developing an HTTP API, you probably just need to interact with request payload. So why not just wrap request payload in some user defined object and validate just it? This also encourages separation of concerns and will help you in case of API versioning.
Usage
First of all, we need to install this package via composer:
composer require fesor/request-objects
And register the bundle:
public function registerBundles()
{
$bundles = [
// ...
new \Fesor\RequestObject\Bundle\RequestObjectBundle(),
];
}
Bundle doesn't require any additional configuration, but you could also specify an error response provider service in bundle config. We will come back to this in "Handle validation errors" section.
Define your request objects
All user defined requests should extend Fesor\RequestObject\RequestObject. Let's create a simple
request object for user registration action:
use Fesor\RequestObject\RequestObject; use Symfony\Component\Validator\Constraints as Assert; class RegisterUserRequest extends RequestObject { public function rules() { return new Assert\Collection([ 'email' => new Assert\Email(['message' => 'Please fill in valid email']), 'password' => new Assert\Length(['min' => 4, 'minMessage' => 'Password is to short']), 'first_name' => new Assert\NotNull(['message' => 'Please provide your first name']), 'last_name' => new Assert\NotNull(['message' => 'Please provide your last name']) ]); } }
After that we can just use it in our action:
public function registerUserAction(RegisterUserRequest $request) { // Do Stuff! Data is already validated! }
This bundle will bind validated request object to the $request argument. Request object has very simple interface
for data interaction. It is very similar to Symfony's request object but is considered immutable by default (although you
can add some setters if you wish so)
// returns value from payload by specific key or default value if provided $request->get('key', 'default value'); // returns whole payload $request->all();
Where payload comes from?
This library has default implementation of PayloadResolver interface, which acts this way:
-
If a request can have a body (i.e. it is POST, PUT, PATCH or whatever request with body) it uses union of
$request->request->all()and$request->files->all()arrays as payload. -
If request can't have a body (i.e. GET, HEAD verbs), then it uses
$request->query->all().
If you wish to apply custom logic for payload extraction, you could implement PayloadResolver interface within
your request object:
class CustomizedPayloadRequest extends RequestObject implements PayloadResolver { public function resolvePayload(Request $request) { $query = $request->query->all(); // turn string to array of relations if (isset($query['includes'])) { $query['includes'] = explode(',', $query['includes']); } return $query; } }
This will allow you to do some crazy stuff with your requests and DRY a lot of stuff.
Validating payload
As you can see from previous example, the rules method should return validation rules for symfony validator.
Your request payload will be validated against it and you will get valid data in your action.
If you have some validation rules which depend on payload data, then you can handle it via validation groups.
Please note: due to limitations in Collection constraint validator it is not so handy to use groups.
So instead it is recommended to use Callback validator in tricky cases with dependencies on payload data.
See example for details about problem.
You may provide validation group by implementing validationGroup method:
public function validationGroup(array $payload) { return isset($payload['context']) ? ['Default', $payload['context']] : null; }
Handling validation errors
If validated data is invalid, library will throw exception which will contain validation errors and request object.
But if you don't want to handle it via kernel.exception listener, you have several options.
First is to use your controller action to handle errors:
public function registerUserAction(RegisterUserRequest $request, ConstraintViolationList $errors) { if (0 !== count($errors)) { // handle errors } }
But this not so handy and will break DRY if you just need to return common error response. Thats why
library provides you ErrorResponseProvider interface. You can implement it in your request object and move this
code to getErrorResponse method:
public function getErrorResponse(ConstraintViolationListInterface $errors) { return new JsonResponse([ 'message' => 'Please check your data', 'errors' => array_map(function (ConstraintViolation $violation) { return [ 'path' => $violation->getPropertyPath(), 'message' => $violation->getMessage() ]; }, iterator_to_array($errors)) ], 400); }
More examples
If you're still not sure is it useful for you, please see the examples directory for more use cases.
Didn't find your case? Then share your use case in issues!
Contribution
Feel free to give feedback and feature requests or post issues. PR's are welcomed!
fesor/request-objects 适用场景与选型建议
fesor/request-objects 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 55.96k 次下载、GitHub Stars 达 89, 最近一次更新时间为 2016 年 05 月 29 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 fesor/request-objects 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 fesor/request-objects 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 55.96k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 90
- 点击次数: 9
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2016-05-29