doupu3635 2014-04-09 13:35
浏览 48
已采纳

Zend 2:如何在Module.php中获取闭包接受参数?

edit: I should explain this is for an app that must use\authenticate to multiple dbs. I have all the DB adapters defined in my autoload config like this:

return array(
    'db' => array(
        //Default adapter retrieved with $sm->get('Zend\Db\Adapter\Adapter')
        'driver' => 'Pdo_Mysql',
        'dsn' => 'mysql:dbname=db1;host=myserver',
        'username' => $DBuser,
        'password' => $DBpass,
        //'driver_options' => array(
        //  PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        //),
        'adapters' => array(
            'someDB' => array(
                'driver' => 'Pdo_Mysql',
                'dsn' => 'mysql:dbname=someDB;host=myserver',
                'username' => $DBuser,
                'password' => $DBpass,
            ),
            'someOtherDB' => array(
                'driver' => 'Pdo_Mysql',
                'dsn' => 'mysql:dbname=someOtherDB;host=myserver',
                'username' => $DBuser,
                'password' => $DBpass,
                'AppType' => 'myCustomProperty',
...

I have the following function I'm trying to move to the service manager:

public function getAuthService($db) {
    if (! $this->authService) {
        //All DBs using authentication must have a view_users view
        $dbAdapter = $this->getServiceLocator()->get($db);
        $authAdapter = new AuthAdapter($dbAdapter);
        $authAdapter
            ->setTableName('view_users')
            ->setIdentityColumn('username')
            ->setCredentialColumn('password')
            ->setCredentialTreatment('MD5(?)');
        ;
        $authService = new AuthenticationService();
        $authService->setAdapter($authAdapter);
        $this->authService = $authService;
    }
    return $this->authService;
}

I have this in the service manager, but how do I modify it so $myParam can to passed when it is retrieved?

public function getServiceConfig() {
    return array(
        'factories' => array(
            'AuthService' => function($sm) {
                $dbAdapter = $this->getServiceLocator()->get($myParam);
                $authAdapter = new AuthAdapter($dbAdapter);
                $authAdapter
                    ->setTableName('view_users')
                    ->setIdentityColumn('username')
                    ->setCredentialColumn('password')
                    ->setCredentialTreatment('MD5(?)');
                ;
                $authService = new AuthenticationService();
                $authService->setAdapter($authAdapter);

                return $authService;
            }
        )
    );
}

The problem is that I want to be able to pass the factory the $db param when retrieving it from the service manager.

To be clear this question isn't specifically about how to authenticate to multiple DBs because this already works fine for me I just want to move my function into the service manager.

edit: crisp answered my actual question, but I found my real issue was a misunderstanding with how to use the Authentication class.

Long story short, I have a login controller that prompts for user creds then checks the user's access against all DBs and stores this info in Zend\Authentication\Storage\Session. Then from various other modules and can just call read() on Session and retrieve authorization info for the user.

  • 写回答

1条回答 默认 最新

  • douke6857 2014-04-09 17:27
    关注

    What you're looking for is an AbstractFactory, which itself is capable of determining from a service name exactly which service to return.

    There must be a pattern to the naming of services coming from your abstract factory, I'd suggest for your use case a pattern of AuthService\DbAdapterName.

    With that in mind you can then write a factory for it such as this one ...

    <?php
    namespace Application\Service;
    
    use Zend\Authentication\AuthenticationService;
    use Zend\Authentication\Adapter\DbTable as AuthAdapter;
    use Zend\ServiceManager\AbstractFactoryInterface;
    use Zend\ServiceManager\ServiceLocatorInterface;
    
    class AbstractAuthenticationServiceFactory implements AbstractFactoryInterface
    {
    
        public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) 
        {
            // the name must begin with authservice ($name is the lowercase canonical name)
            if (0 !== strpos($name, 'authservice')) {
                return false;
            }
            // remove authservice from the name, leaving just the db name
            $dbName = str_replace('authservice', '', $name);
    
            // we can create the service only if the service manager has the db
            return $serviceLocator->has($dbName);
        }
    
        public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) 
        {
            $dbName = str_replace('authservice', '', $name);
    
            $dbAdapter = $serviceLocator->get($dbName);
            $authAdapter = new AuthAdapter($dbAdapter);
            $authAdapter
                ->setTableName('view_users')
                ->setIdentityColumn('username')
                ->setCredentialColumn('password')
                ->setCredentialTreatment('MD5(?)');
    
            $authService = new AuthenticationService();
            $authService->setAdapter($authAdapter);
    
            return $authService;
        }
    }
    

    Once you have your factory, you need to add it to the service_manager config under the abstract_factories key ...

    // module.config.php
    return array(
        'service_manager' => array(
             'abstract_factories' => array(
                 'authservice' => 'Application\Service\AbstractAuthenticationServiceFactory',
             ),
         ),
    );
    

    You can then use the servicelocator to get your AuthService instances by using the pattern described earlier

    $someDbAuth = $this->getServiceLocator()->get('AuthService\someDB');
    
    $otherDbAuth = $this->getServiceLocator()->get('AuthService\someOtherDB');
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么