webmunkeez/adr-bundle
Composer 安装命令:
composer require webmunkeez/adr-bundle
包简介
Action-Domain-Responder pattern made for Symfony.
README 文档
README
This bundle unleashes the Action-Domain-Responder pattern on Symfony applications.
Installation
Use Composer to install this bundle:
$ composer require webmunkeez/adr-bundle
Add the bundle in your application kernel:
// config/bundles.php return [ // ... Webmunkeez\ADRBundle\WebmunkeezADRBundle::class => ['all' => true], // ... ];
Usage
Actions
An Action is just an invokable class that has to implement \Webmunkeez\ADRBundle\Action\ActionInterface:
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface { public function __invoke(): Response { return $this->render($data); } public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response { return new Response(...); } }
But, it can be a more classic Controller that implements the same interface:
final class StoryController implements \Webmunkeez\ADRBundle\Action\ActionInterface { public function detail(): Response { return $this->render($data); } public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response { return new Response(...); } }
(Each service that implements ActionInterface is automatically tagged controller.service_arguments)
Responders
Responders are services which take data (an object that implements \Webmunkeez\ADRBundle\Response\ResponseDataInterface) and return it in a Response.
It can be a response containing HTML or a JsonResponse, or whatever you want, as far as it is a Symfony\Component\HttpFoundation\Response instance.
In this bundle, there is a responder manager \Webmunkeez\ADRBundle\Response\Responder that you can inject into your actions (or controllers).
This responder manager takes all responders of your application (it uses a compiler pass to get all services tagged webmunkeez_adr.responder sorted by priority) and find the right one to render the response.
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface { private \Webmunkeez\ADRBundle\Response\Responder $responder; public function __construct(\Webmunkeez\ADRBundle\Response\Responder $responder) { $this->responder = $responder } public function __invoke(): Response { return $this->render($data); } public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response { return $this->responder->render($data); } }
You can use \Webmunkeez\ADRBundle\Response\ResponderAwareInterface and \Webmunkeez\ADRBundle\Response\ResponderAwareTrait to automatically inject Responder:
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface, \Webmunkeez\ADRBundle\Response\ResponderAwareInterface { use \Webmunkeez\ADRBundle\Response\ResponderAwareTrait; public function __invoke(): Response { return $this->render($data); } public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response { return $this->responder->render($data); } }
And you can use \Webmunkeez\ADRBundle\Action\ActionTrait to clean code:
final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface, \Webmunkeez\ADRBundle\Response\ResponderAwareInterface { use \Webmunkeez\ADRBundle\Response\ResponderAwareTrait; use \Webmunkeez\ADRBundle\Action\ActionTrait; public function __invoke(): Response { return $this->render($data); } }
Or directly extend \Webmunkeez\ADRBundle\Action\AbstractAction:
final class StoryDetailAction extends \Webmunkeez\ADRBundle\Action\AbstractAction { public function __invoke(): Response { return $this->render($data); } }
Responders are classes that implement \Webmunkeez\ADRBundle\Response\ResponderInterface (and so, they are automatically tagged webmunkeez_adr.responder):
final class XmlResponder implements \Webmunkeez\ADRBundle\Response\ResponderInterface { private RequestStack $requestStack; private SerializerInterface $serializer; public function __construct(RequestStack $requestStack, SerializerInterface $serializer) { $this->requestStack = $requestStack; $this->serializer = $serializer; } public function supports(): bool { return 'xml' === $this->requestStack->getCurrentRequest()->getPreferredFormat(); } public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response { $xml = $this->serializer->serialize($data, 'xml'); $response = new Response($xml); $response->headers->set('Content-Type', 'text/xml'); return $response; } }
As you can see, there are two methods: supports that defines conditions to "activate" the responder and render to make the response.
Core responders
There are two core responders provided:
HtmlResponder
\Webmunkeez\ADRBundle\Response\HtmlResponder that uses Twig for render html with a twig template. To indicate template, you have to use \Webmunkeez\ADRBundle\Attribute\Template:
use Webmunkeez\ADRBundle\Attribute\Template; #[Template('story/detail.html.twig')] final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface { ... }
This responder is active if the request contains HTTP_ACCEPT text/html header (warning: a twig template is needed for this responder, otherwise it will throw an \Webmunkeez\ADRBundle\Exception\RenderingException exception).
It has a priority: -20.
JsonResponder
\Webmunkeez\ADRBundle\Response\JsonResponder that uses Serializer for render json (you can indicate serialization context with \Webmunkeez\ADRBundle\Attribute\SerializationContext):
use Webmunkeez\ADRBundle\Attribute\SerializationContext; #[SerializationContext(['groups' => 'group_one'])] final class StoryDetailAction implements \Webmunkeez\ADRBundle\Action\ActionInterface { ... }
This responder is active if the request contains HTTP_ACCEPT application/json header.
It has a priority: -10.
Custom responders
You can write your own reponders like in my previous XmlResponder example, by implementing \Webmunkeez\ADRBundle\Response\ResponderInterface.
Services implementing this interface are automatically tagged webmunkeez_adr.responder with priority: 0, and you can change it (in your service.yaml or by static getDefaultPriority method ; see https://symfony.com/doc/current/service_container/tags.html#tagged-services-with-priority).
You can define "generic" responders like html, json, xml and so on. But you can also define more specifics, by checking $request->attributes->get('_controller') to make a responder only for a specific action:
final class CustomResponder implements \Webmunkeez\ADRBundle\Response\ResponderInterface { private RequestStack $requestStack; private Environment $twig; public function __construct(RequestStack $requestStack, Environment $twig) { $this->requestStack = $requestStack; $this->twig = $twig; } public function supports(): bool { $controller = $this->requestStack->getCurrentRequest()->attributes->get('_controller'); $actionClass = false !== strpos($controller, '::') ? substr($controller, 0, strpos($controller, '::')) : $controller; return CustomResponderAction::class === $actionClass; } public function render(?\Webmunkeez\ADRBundle\Response\ResponseDataInterface $data = null): Response { $data = array_merge($data, ['customResponder' => true]); $html = $this->twig->render($this->requestStack->getCurrentRequest()->attributes->get('_template_path'), $data); return new Response($html); } }
Render Exception Listener
If there is an uncaught \Webmunkeez\ADRBundle\Exception\RenderingException, it will be catch by this listener which will throw an \Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException that will embed the original exception.
Exception Listener
If there is an uncaught \Throwable, it will be catch by this listener which will throw an \Symfony\Component\HttpKernel\Exception\BadRequestHttpException that will embed the original exception.
Http Exception Listener
If you request an Action with HTTP_ACCEPT application/json header and if this Action throws an Exception that implements \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface, its content will automatically be serialized in a JSON reading format to the Response body content.
webmunkeez/adr-bundle 适用场景与选型建议
webmunkeez/adr-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 117 次下载、GitHub Stars 达 1, 最近一次更新时间为 2021 年 10 月 14 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「symfony」 「controllers」 「templates」 「action」 「Autowiring」 「responder」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 webmunkeez/adr-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 webmunkeez/adr-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 webmunkeez/adr-bundle 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Shoot aims to make providing data to your templates more manageable
CakePHP 4.x AdminLTE Theme.
Opinionated Laravel Controllers extension
Bookdown.io With Bootswatch Styles And Prism Syntax Highlighting
The bundle for easy using json-rpc api on your project
A package for generating annotations and drawing SwUi when working with Bitrix controllers.
统计信息
- 总下载量: 117
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2021-10-14