让事件在后台更改变量

时间:2014-02-19 10:39:45

标签: php zend-framework2

我有以下情景呈现给我:

  • 针对AD运行身份验证
  • AD Server返回标识字符串“foo \ bar”
  • 成功验证后,会以“身份字符串和适配器作为参数”触发“LOGIN_SUCCESS”事件

一旦触发此事件,就会附加几个触发器。

  1. First Listener检查数据库中具有匹配的“identity foo \ bar”的用户行是否已存在。如果没有,将创建用户行
  2. 在每次登录时,另一个侦听器将更新从适配器提供的用户元数据
  3. 我想让第三个侦听器将身份字符串“foo \ bar”从DB中的用户行更改为用户对象
  4. 目前我的AuthenticationService看起来像这样:

    if ($result->isValid()) {
        $currentIdentity = $result->getIdentity();
    
        $eventManager = new EventManager(__CLASS__);
        $eventResult = $eventManager->trigger(self::DUIT_USER_LOGIN_SUCCESSFUL, $this, [
            'identity' => $currentIdentity,
            'adapter' => $adapter
        ]);
    
        // This whole stuff sucks!
        if ($eventResult->last() instanceof EventInterface) {
            $identityObject = $eventResult->last()->getParam('identity');
    
            if ($identityObject instanceof User) {
                $this->getStorage()->write($identityObject);
    
                return $result;
            }
        }
    
        $this->getStorage()->write($result->getIdentity());
    }
    

    正如你所看到的,我在这里做的事情并不属于AuthenticationService。是否有Event能够修改给定的parameter(在这种情况下为identity),以便在后台更改参数的值?

    我真的不想在AuthenticationService中进行eventResult检查。这个假设不应该存在,但我真的没有看到任何不同的做事方式。

    //修改

    目前触发器在后台执行此操作:

    public function handleWorkflow(EventInterface $event)
    {
        $identityString = $event->getParam('identity');
    
        $userObject = $this->userService->findByActiveDirectoryId($identityString);
    
        if ($userObject instanceof User) {
            return $event->setParam('identity', $userObject);
        }
    
        return $event->setParam('identity', $identityString);
    }
    

1 个答案:

答案 0 :(得分:2)

正如在IRC上讨论的那样,这种应用于事件数据的“转换”是微妙的,会让你反感。

如果您希望从您的活动数据中获得string,那么请编写IdentityFinder或类似内容的代码并将其注入您的AuthenticationService

if ($result->isValid()) {
    $currentIdentity = $result->getIdentity();

    // we use some sort of locator to find the identity
    $identity = $this->identityLocator->find($currentIdentity);

    $this->getStorage()->write($identity);

    // triggering is still OK, but not to manipulate the data here.
    // it should also happen _AFTER_ successful authentication
    // I also assume you injected the EventManager here, instead of building it
    // result is also being ignored, it shouldn't contain data required to us
    $this->eventManager->trigger(
        self::DUIT_USER_LOGIN_SUCCESSFUL, 
        $this,
        [
            'identity' => $identity,
            'adapter' => $adapter
        ]
    );

}

如果结果仍然是传入的内容,那么只需实现一个虚拟的,就可以使这个查找器无操作:

class NoopIdentityFinder implements IdentityFinderInterface
{
    public function find($identity)
    {
        return $identity; // no real "find" going on
    }
}

通过这种方式,您可以通过允许事件侦听器“捕获”发生的事情来明确地编写逻辑并且易于理解。