How to use Zend 2 save handler DbTableGateway?

2019-02-28 07:00发布

问题:

The Zend\Session Save Handler tutorial gives an example for DbTableGateway in which they create a TableGateway with an undefined $adapter variable. I want to use the handler to tie the Session Manager (from the previous page of the tutorial) to my session storage table in my database. How can I do this?

I guess the code should look something like this?

class Module implements AutoloaderProviderInterface, ConfigProviderInterface
{
    public function onBootstrap(MvcEvent $e) {
        $eventManager        = $e->getApplication()->getEventManager();

        // create the session manager
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);
        $this->bootstrapSession($e);
    }

    public function bootstrapSession($e)
    {
        $session = $e->getApplication()
            ->getServiceManager()
            ->get('Zend\Session\SessionManager');
        $tableGateway = new TableGateway('session', $adapter); // somehow define this somewhere?
        $saveHandler  = new DbTableGateway($tableGateway, new DbTableGatewayOptions());
        $session->setSaveHandler($saveHandler);
        $session->start();

        $container = new Container('initialized');
        if (!isset($container->init)) {
            $serviceManager = $e->getApplication()->getServiceManager();
            $request        = $serviceManager->get('Request');

            $session->regenerateId(true);
            $container->init          = 1;
            $container->remoteAddr    = $request->getServer()->get('REMOTE_ADDR');
            $container->httpUserAgent = $request->getServer()->get('HTTP_USER_AGENT');

            $config = $serviceManager->get('Config');
            if (!isset($config['session'])) {
                return;
            }

            $sessionConfig = $config['session'];
            if (isset($sessionConfig['validators'])) {
                $chain   = $session->getValidatorChain();

                foreach ($sessionConfig['validators'] as $validator) {
                    switch ($validator) {
                        case 'Zend\Session\Validator\HttpUserAgent':
                            $validator = new $validator($container->httpUserAgent);
                            break;
                        case 'Zend\Session\Validator\RemoteAddr':
                            $validator  = new $validator($container->remoteAddr);
                            break;
                        default:
                            $validator = new $validator();
                    }

                    $chain->attach('session.validate', array($validator, 'isValid'));
                }
            }
        }
    }

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Zend\Session\SessionManager' => function ($sm) {
                    $config = $sm->get('config');
                    if (isset($config['session'])) {
                        $session = $config['session'];

                        $sessionConfig = null;
                        if (isset($session['config'])) {
                            $class = isset($session['config']['class'])  ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
                            $options = isset($session['config']['options']) ? $session['config']['options'] : array();
                            $sessionConfig = new $class();
                            $sessionConfig->setOptions($options);
                        }

                        $sessionStorage = null;
                        if (isset($session['storage'])) {
                            $class = $session['storage'];
                            $sessionStorage = new $class();
                        }

                        $sessionSaveHandler = null;
                        if (isset($session['save_handler'])) {
                            // class should be fetched from service manager since it will require constructor arguments
                            $sessionSaveHandler = $sm->get($session['save_handler']);
                        }

                        $sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
                    } else {
                        $sessionManager = new SessionManager();
                    }
                    Container::setDefaultManager($sessionManager);
                    return $sessionManager;
                },
            ),
        );
    }

    /***************************************************************************************************
     * Returns the location of the module.config.php file. This function is used by the Zend Framework
     * underneath the hood.
     ***************************************************************************************************/
    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }

    /***************************************************************************************************
     * Returns the Zend StandardAutoLoader which contains the directory structure of the module source
     * folder.
     ***************************************************************************************************/
    public function getAutoloaderConfig()
    {
        return array(
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }
}

回答1:

I have this code for save a session to a db table.

'service_manager' => array(
    'factories' => array(
        'Zend\Session\SessionManager' => function (\Zend\ServiceManager\ServiceManager $sm) {
            $sessionConfig = new \Zend\Session\Config\SessionConfig();
            $sessionConfig->setOptions(
                array(
                    'use_cookies' => true,
                    'name' => 'ed2',
                    'gc_maxlifetime' => 1728000
                )
            );

            /* @var $adapter \Zend\Db\Adapter\Adapter */
            $adapter = $sm->get('Zend\Db\Adapter\Adapter');
            $tableGateway = new \Zend\Db\TableGateway\TableGateway('session', $adapter);
            $saveHandler  = new \Common\Session\SaveHandler\DbTableGateway(
                $tableGateway,
                new \Zend\Session\SaveHandler\DbTableGatewayOptions()
            );

            $sessionManager = new \Zend\Session\SessionManager($sessionConfig);
            $sessionManager->setSaveHandler($saveHandler);
            $sessionManager->start();
            return $sessionManager;
        },
    )
)

Config for db

'db' => array(
    'driver'    => 'Pdo_Mysql',
    'database'  => 'release',
    'username'  => 'username',
    'password'  => 'password',
    'hostname'  => '127.0.0.1',
    'driver_options' => array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
    )
),
'service_manager' => array(
    'factories' => array(
        'Zend\Db\Adapter\Adapter' => function (\Zend\ServiceManager\ServiceManager $serviceManager) {
            $adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
            $adapter = $adapterFactory->createService($serviceManager);

            Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);

            return $adapter;
        }
    )
)


回答2:

The answer turned out to be like newage's answer:

Since newage edited his answer to include the db adapter, I've accepted it as the right answer. The rest of this is just my implementation:

You can remove all the TableGateway and savehandler logic from the bootstrapSession method and put it in the getServiceConfig method.

Add the definition for Adapter to the 'factories' array in getServiceConfig, then modify the 'Zend\Session\SessionManager' function to include the Adapter, TableGateway, and save handler. This is what the new getServiceConfig would look like:

public function getServiceConfig()
{
    return array(
        'factories' => array(

            // New code here
            'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
            // New code here

            'Zend\Session\SessionManager' => function ($sm) {
                $config = $sm->get('config');
                if (isset($config['session'])) {
                    $session = $config['session'];

                    $sessionConfig = null;
                    if (isset($session['config'])) {
                        $class = isset($session['config']['class'])  ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
                        $options = isset($session['config']['options']) ? $session['config']['options'] : array();
                        $sessionConfig = new $class();
                        $sessionConfig->setOptions($options);
                    }

                    $sessionStorage = null;
                    if (isset($session['storage'])) {
                        $class = $session['storage'];
                        $sessionStorage = new $class();
                    }

                    $sessionSaveHandler = null;
                    if (isset($session['save_handler'])) {
                        // class should be fetched from service manager since it will require constructor arguments
                        $sessionSaveHandler = $sm->get($session['save_handler']);
                    }
                    $sessionManager = new SessionManager();
                }

                // New code here
                /* @var $adapter \Zend\Db\Adapter\Adapter */
                $adapter = $sm->get('Zend\Db\Adapter\Adapter');
                $tableGateway = new TableGateway('mytablename', $adapter);
                $saveHandler  = new DbTableGateway($tableGateway, new DbTableGatewayOptions());
                $sessionManager->setSaveHandler($saveHandler);
                // New code here

                Container::setDefaultManager($sessionManager);
                return $sessionManager;
            },
        ),
    );
}

Then add the database connection info to the module's config file:

return array(
    // ...
    'db' => array(
        'driver'         => 'Pdo',
        'dsn'            => 'mysql:dbname=mydbname;host=mydbhost;port=xxxx',
        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ),
        'username'       => 'dbusername',
        'password'       => 'dbpassword',
    ),
);