【问题标题】:Symfony - how to call next service in chainSymfony - 如何调用链中的下一个服务
【发布时间】:2022-10-24 00:55:09
【问题描述】:

我想在我的应用程序中实现授权链模式。我创建了四种不同的授权链服务,它们取决于用户想要访问的路由。我有链接服务的问题。我想在不明确命名的情况下链接服务。例如:

class Authorization1:
public function auth($request){
    if (isThisRoute){
        $this->authorize($request);
     }
     $this->authorization2->authorize($request);  
 }

我想知道如何将最后一行: $this->authorization2->authorize($request); 替换为 $this->chain->authorize($request);,以便可以完全实现责任链模式。

【问题讨论】:

标签: php symfony design-patterns method-chaining


【解决方案1】:

你的代码看起来像 Laravel 中间件代码。

努力学习吧:https://refactoring.guru/design-patterns/chain-of-responsibility

如果你真的想为你的四种不同的服务使用责任链而不是策略,它可以看起来像下面的代码(PHP v8.0)。

链接口

interface AuthorizationRequestHandlerInterface
{
    public function auth(Request $request): bool;

   // Option 2
   public function setNext(AuthorizationRequestHandlerInterface $handler): void;
}

条件或状态的处理程序

class Authorization1 implements AuthorizationRequestHandlerInterface
{
    // Option 1
    public function __construct(private AuthorizationRequestHandlerInterface $handler)
    {
    }

    // Option 2
    public function setNext(AuthorizationRequestHandlerInterface $handler): void
    {
        $this->handler = $handler;
    } 

    public function auth(Request $request): bool
    {
        if (isThisRoute) {
            // Check permissions here or call your private or protected method
            return $this->authorize($request);
        }

        // Option 1: Call the next handler
        return $this->handler->auth($request);  

        // Option 2: Call the next handler if it exists
        return $this->handler ? $this->handler->auth($request) : false;
    }

    private function authorize(Request $request): bool
    {
        $result = false;

        // Your code

        return $result;
    }
}

其他处理程序看起来像以前的处理程序。

您可以对对象执行任何操作并返回任何类型的值,但此示例使用bool

您应该以services.yml 或您使用的其他方式准备服务配置。

最后 PHP 代码可能如下所示:

// Initialization: Option 1
$authNull = new AuthNull();
$auth1 = new Authorization1($authNull);
$auth2 = new Authorization2($auth1);
$auth3 = new Authorization3($auth2);

return $auth3;

// Initialization: Option 2
$auth1 = new Authorization1($authNull);
$auth2 = new Authorization2($auth1);
$auth3 = new Authorization3($auth2);
$auth1->setNext($auth2);
$auth2->setNext($auth3);
// In this way you must add the `setNext` method and use its value as `handler` instead of that constructor value.

return $auth1;

// ...

// A class that has the main handler, like AbstractGuardAuthenticator, Controller, ArgumentResolver, ParamConverter, Middleware, etc.

if ($auth->handle($request)) {
    // when it is authorizable, continues the request
} else {
    // when it isn't authorizable, throws Exception, for example
}

// Different handling order that depends on the options.
// Option 1: Auth3 -> Auth2 -> Auth1 -> AuthNull
// Option 2: Auth1 -> Auth2 -> Auth3

正如@alexcm 提到的,您应该阅读一些 Symfony 信息:

【讨论】:

    猜你喜欢
    • 2012-08-01
    • 2015-02-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多