pitch/symfony-adr

此包使得在编写Symfony应用程序时遵循ADR模式变得更加容易

安装: 264

依赖者: 1

建议者: 1

安全性: 0

星标: 2

关注者: 2

分支: 0

开放问题: 1

类型:symfony-bundle

v1.4.0 2022-06-20 14:16 UTC

README

此包使得在编写 Symfony 应用程序时遵循ADR模式变得更加容易。

用法

将控制器转换为动作

通过将响应者逻辑从动作逻辑中分离出来,将其移出控制器。只需返回有效载荷即可!

如果控制器返回的不是 Response 对象,Symfony将触发一个kernel.view事件。

现在,您不必注册大量事件监听器进行迭代,只需实现 ResponseHandlerInterface

namespace App\Responder;

use Pitch\AdrBundle\Responder\ResponseHandlerInterface;
use Pitch\AdrBundle\Responder\ResponsePayloadEvent;
use Symfony\Component\HttpFoundation\Response;

use App\Entity\MyPayload;

class MyPayloadHandler implements ResponseHandlerInterface
{
    public function getSupportedPayloadTypes(): array
    {
        return [
            MyPayload::class,
        ];
    }

    public function handleResponsePayload(
        ResponsePayloadEvent $payloadEvent
    ): void {
        $response = new Response();

        // prepare the response
        if ($payloadEvent->request->getAttribute('_foo') === 'bar') {
            // adjust the response according to the request
        }

        $payloadEvent->payload = $response;
    }
}

如果您的处理类根据您的 config/services.yaml 作为服务可用,它将在控制器返回 MyPayload 对象时被发现和使用。

默认配置下,只需将类放入 src/Responder/MyPayloadHandler.php 即可。

您可以在 getSupportedTypes 中报告您的响应处理器的优先级。

class MyPayloadHandler implements ResponseHandlerInterface
{
    public function getSupportedPayloadTypes(): array
    {
        return [
            MyPayload::class => 123,
            MyOtherPayload:class => 456,
        ];
    }
    //...
}

或者,您可以在 services.yml 中覆盖响应处理器的处理类型和优先级。

services:
  App\Responder\MyPayloadHandler:
    tags:
      - name: pitch_adr.responder
        for: [App\Entity\MyPayload]
        priority: 1000
      - name: pitch_adr.responder
        for: [App\Entity\MyOtherPayload]
        priority: 0

您可以通过控制台命令轻松调试响应器配置。

$ php bin/console debug:responder MyPayload

将一些异常作为响应有效载荷处理

一个健壮的领域将有严格的约束,并在发生任何意外或无效条件时抛出异常,并且对于所有通过控制器/动作传递的异常,Symfony都会触发一个kernel.exception事件。

您可以将此事件保留用于真正意外的行为,而无需在控制器中重复类似的try-catch块。

定义所有控制器应该捕获哪些异常并将其作为响应有效载荷处理

pitch_adr:
    graceful:
        - { value: RuntimeException, not: [BadRuntime, OtherBadRuntime] }
        - Foo
        - { not: GloballyBadException }
        - { value: Bar, not: BadBar }

如果已安装Doctrine Annotations,则可以为控制器方法定义额外的规则

namespace App\Controller;

use Pitch\AdrBundle\Configuration\Graceful;

class MyController
{
    /**
     * @Graceful(not=LocallyBadException::class)
     * @Graceful(LocallyGoodException::class, not={ButNotThisOne::class, OrThatOne::class})
     */
    public function __invoke(
        Request $request
    ) {
        /// ...
    }
}

使用PHP8,您可以按属性定义每个方法的额外规则

namespace App\Controller;

use Pitch\AdrBundle\Configuration\Graceful;

class MyController
{
    #[Graceful(not: LocallyBadException::class)]
    #[Graceful(LocallyGoodException::class, not: [ButNotThisOne::class, OrThatOne::class])]
    public function __invoke(
        Request $request
    ) {
        /// ...
    }
}

规则按出现顺序应用,方法规则在全局规则之后。

现在,您可以创建一个 App\Responder\MyGoodRuntimeExceptionHandler,如上所述。

默认响应处理器

该包自动为基本类型添加了一些响应处理器,具有负优先级,以便在您的响应处理器中未停止传播之前调用它们。如果您不想添加默认处理器,可以按包配置修改此行为。

pitch_adr:
    defaultResponseHandlers: false # defaults to true

优先级响应处理器

如果连续的响应处理器(按配置优先级顺序)实现了 PrioritisedResponseHandlerInterface,则该处理器块将在运行时根据它们在getResponseHandlerPriority中报告的特定请求优先级进行排序。

Given the following response handlers are configured to handle a `SomePayloadType`:

900: HandlerA
600: PrioritisedHandler1 with getResponseHandlerPriority(): 1
500: PrioritisedHandler2 with getResponseHandlerPriority(): 2
400: PrioritisedHandler3 with getResponseHandlerPriority(): 0
100: HandlerB

these will be executed in the following order:

HandlerA
PrioritisedHandler2
PrioritisedHandler1
PrioritisedHandler3
HandlerB

在响应处理器中协商内容类型

有关如何实现自己的优先级响应处理器,该处理器根据请求中的 Accept 头处理有效载荷,请参阅 JsonResponder

您可以为不包含Accept头的请求设置默认内容类型。这可以通过容器参数或控制器注释来完成。

parameters:
    pitch_adr.defaultContentType: 'application/json'
use Pitch\AdrBundle\Configuration\DefaultContentType;

class MyController
{
    #[DefaultContentType('application/json')]
    public function __invoke()
    {
        // ...
    }
}