Skip to content

Loading…

Session service factories #4268

Merged
merged 11 commits into from

4 participants

@weierophinney
Zend Framework member

This pull request provides ServiceManager factories for the Zend\Session component. It includes the following:

  • A new Zend\Session\Storage\Factory class for creating instances of storage adapters. This is completely de-coupled from the ServiceManager.
  • Zend\Session\Service namespace with the following:

    • SessionConfigFactory, for instantiating a session configuration object. This utilizes the session_config key of the Config service. If a config_class subkey is available, the class name it defines will be used as the configuration class. The entire session_config array is passed to the configuration class's setOptions() method. This factory should be assigned to the service name Zend\Session\Config\ConfigInterface.
    • StorageFactory, for instantiating a storage instance. It utilizes the session_storage key of the Config service, and expects it to be in the format:

      array(
          'type' => 'ShortName Or FQCN of Storage Class',
          'options' => array(/* any valid options for the given storage class */),
      )

      The type and options are passed to Zend\Session\Storage\Factory to create and return an instance. This factory should be assigned to the service name Zend\Session\Storage\StorageInterface.

    • SessionManagerFactory, for instantiating a Zend\Session\SessionManager instance. If any of the services Zend\Session\Config\ConfigInterface, Zend\Session\Storage\StorageInterface, or Zend\Session\SaveHandler\SaveHandlerInterface are present, they will be used to instantiate the SessionManager instance. This service should be assigned to the service name Zend\Session\ManagerInterface.
    • ContainerAbstractFactory, for instantiating Zend\Session\Container instances. It uses the session_containers key of the Config service, and expects the value of that key to be an array of container names. If a Zend\Session\ManagerInterface service is present, it will be used to instantiate Container instances. Container service names MUST be prefixed with SessionContainer\ for the factory to match. This means that the following definition:

      'session_containers' => array(
        'foo',
        'Captcha',
      )

      defines the services SessionContainer\foo and SessionContainer\Captcha.

All factories are completely opt-in, and Zend\ServiceManager has been added as an optional dependency.

As a full example of configuration:

return array(
    'service_manager' => array(
        'factories' => array(
            'Zend\Session\Config\ConfigInterface' => 'Zend\Session\Service\SessionConfigFactory',
            'Zend\Session\Storage\StorageInterface' => 'Zend\Session\Service\SessionStorageFactory',
            'Zend\Session\ManagerInterface' => 'Zend\Session\Service\SessionManagerFactory',
        ),
        'abstract_factories' => array(
            'Zend\Session\Service\ContainerAbstractFactory',
        ),
    ),
    'session_config' => array(
        'remember_me_seconds' => 1800,
        'name' => 'my_app',
    ),
    'session_storage' => array(
        'type' => 'SessionArrayStorage',
        'options' => array(), // Likely don't want to seed it
    ),
    'session_containers' => array(
        'Captcha',
        'User',
        'FlashMessages',
    ),
);

You would then retrieve services within factories as follows:

$user = $services->get('SessionContainer\User');
$messages = $services->get('SessionContainer\FlashMessages');

$manager = $services->get('Zend\Session\ManagerInterface');
weierophinney added some commits
@weierophinney weierophinney Created SessionConfig factory
- Uses "session_config" key, assigned to an array of options, to create
  a Zend\Session\Config\ConfigInterface instance.
- By default, uses SessionConfig as ConfigInterface implementation.
- A "config_class" subkey can be used to specify a specific
  ConfigInterface implementation to use.
398e7d7
@weierophinney weierophinney Created SessionManager factory
- Consumes ConfigInterface, StorageInterface, and SaveHandlerInterface
  services in order to create a SessionManager instance. Services do not
  need to be present, as null values will be used by default if not
  found.
4eff646
@weierophinney weierophinney Created a factory for StorageInterface objects b4fb90e
@weierophinney weierophinney Implemented session storage service factory
- Marshals arguments from Config service
- Proxies to Zend\Session\Storage\Factory for actual creation
4fed884
@weierophinney weierophinney Added note about save handler service
- Save handler factory will not be provided by the framework at this
  time.
d19cfb4
@weierophinney weierophinney Created session Container abstract factory
- Provide an array of container names in "session_containers"
  configuration.
- Uses `Zend\Session\ManagerInterface` service, if available, when
  instantiating containers.
- Session container services must be prefixed with "SessionContainer\\"
500eda3
@weierophinney weierophinney Fixes typo in docblock
- s/SessionConfig/SessionContainer/
d26394b
@weierophinney
Zend Framework member

Ping @mwillbanks -- this is what we discussed on IRC yesterday.

@samsonasik samsonasik commented on an outdated diff
...Test/Session/Service/ContainerAbstractFactoryTest.php
((5 lines not shown))
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Session
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Storage\ArrayStorage;
+
+/**
+ * @category Zend
+ * @package Zend_Session
+ * @subpackage UnitTests
+ * @group Zend_Session

only @group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@samsonasik samsonasik commented on an outdated diff
...ZendTest/Session/Service/SessionConfigFactoryTest.php
((5 lines not shown))
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Session
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Service\SessionConfigFactory;
+
+/**
+ * @category Zend
+ * @package Zend_Session
+ * @subpackage UnitTests
+ * @group Zend_Session

only @group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@samsonasik samsonasik commented on an outdated diff
...endTest/Session/Service/SessionManagerFactoryTest.php
((7 lines not shown))
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Session
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Config\StandardConfig;
+use Zend\Session\Service\SessionManagerFactory;
+use Zend\Session\Storage\ArrayStorage;
+
+/**
+ * @category Zend
+ * @package Zend_Session
+ * @subpackage UnitTests
+ * @group Zend_Session

only @group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@samsonasik samsonasik commented on an outdated diff
tests/ZendTest/Session/Service/StorageFactoryTest.php
((5 lines not shown))
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Session
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Service\StorageFactory;
+
+/**
+ * @category Zend
+ * @package Zend_Session
+ * @subpackage UnitTests
+ * @group Zend_Session

only @group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@samsonasik samsonasik commented on an outdated diff
...Test/Session/Service/ContainerAbstractFactoryTest.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Session

remove @package

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@samsonasik samsonasik commented on an outdated diff
...ZendTest/Session/Service/SessionConfigFactoryTest.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Session

remove @package

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mwillbanks

@weierophinney Here is the feedback that I have on this now that I've had some time to look into it all.

  • Session Container Factories: I'm slightly curious on the use case for the containers to be honest. It seems like it may save a line or two of code. Do we plan to incorporate this into the framework where sessions are already leveraged?
    • Container itself: One area that I think is missing is the ability within the implementation is that there is no option to be able to setDefaultManager on the Container. Setting a default manager to Container is semi-important due to incorporation with several other tools. Sure it can be done manually but this provides far more convenience.
weierophinney added some commits
@weierophinney weierophinney Remove unnecessary annotations dde0426
@weierophinney weierophinney Set created manager as default manager for Containers
- Passes created `SessionManager` instance to
  `Container::setDefaultManager()`
8a72aab
@weierophinney weierophinney Make ability to inject manager as Container default mutable
- New Config service key, "session_manager"
  - single key for now: "enable_default_container_manager". Defaults to
    true, meaning "inject the Container". Set to false to disable this
    behavior.
16d642c
@weierophinney
Zend Framework member

@mwillbanks I've incorporated your feedback. At this ime:

  • The SessionManagerFactory now injects itself as the default manager for Container instances. You can disable this, if desired, by setting 'session_manager' => array('enable_default_container_manager' => false) via configuration.

As for the Container factories, the primary use case goes away when the default settings are used. However, if you disable the default manager functionality, this abstract factory would simplify usage of containers associated with the SessionManager service, as you would no longer need to retrieve the SessionManager prior to creating your Container instances.

The secondary use case is still present, however: IoC. Basically, you can then treat the Container instances as services, which ensures that injection of the SessionManager is appropriately done, and breaks you of the habit of instantiating the Containers directly.

I'm unsure if we should modify existing code to use these services. A quick check shows that the following components use Containers:

  • ProgressBar
  • CSRF validator
  • Authentication (session storage)
  • Captcha
  • Cache (session storage adapter)
  • FlashMessenger
  • PRG and File PRG plugins

The latter three could easily be updated to pull named containers, as they are managed by a plugin manager already. The Cache session storage adapter could be as well, as we have a proposed abstract factory for storage adapters. The CSRF validator falls under this as well, since we have a Validator plugin manager and factory. That leaves Authentication, CAPTCHA, and ProgressBar as outliers, however.

Question: should I update those components that we can with this PR, or wait until this one is merged?

Ideally, I'd like to get this into 2.2.0, as this, and the Log and Cache factories, have been much requested since 2.0.

@mwillbanks

@weierophinney i think we can update those components at a later time and get this in first. Looks like travis had some issues with it on 5.4.

@weierophinney
Zend Framework member

@mwillbanks The failures on 5.4 are due to issues with Travis-CI properly resolving the path to the downloaded php-cs-fixer.phar file; since it cannot resolve, it reports an error.

@mwillbanks mwillbanks added a commit that referenced this pull request
@mwillbanks mwillbanks Merge branch 'feature/4268' into develop
Close #4268
f1220c2
@mwillbanks mwillbanks merged commit 16d642c into zendframework:develop

1 check failed

Details default The Travis build failed
@rumeau

Im using thies factories to intitiate my Session Manager, the problem is that when i initialize the Session Manager onBoostrap, the Session Upload Progress var is removed from the $_SESSION var.

Im using the SessionArrayStorage the upload progress key is always removed. I also tried disabling the initialization but then my session object gets invalid as the upload progress key is not processed by the SessionArrayStorage so my session is lost after the upload.

Is the Session Manager compatible with session upload progress?.

@ghost Unknown pushed a commit that referenced this pull request
@weierophinney weierophinney [#4268] CS fixes
- per php-cs-fixer
6fec674
@ghost Unknown pushed a commit that referenced this pull request
@mwillbanks mwillbanks Merge branch 'feature/4268' into develop
Close #4268
16f2257
@weierophinney
Zend Framework member

@rumeau Can you please open a new issue instead of a comment thread inside a closed PR? :) This will allow us to track it separately.

Thanks in advance!

@weierophinney weierophinney added a commit to zendframework/zend-session that referenced this pull request
@weierophinney weierophinney [zendframework/zf2#4268] CS fixes
- per php-cs-fixer
6a0b7d7
@gianarb gianarb pushed a commit to zendframework/zend-session that referenced this pull request
@mwillbanks mwillbanks Merge branch 'feature/4268' into develop 747fe20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 18, 2013
  1. @weierophinney

    Created SessionConfig factory

    weierophinney committed
    - Uses "session_config" key, assigned to an array of options, to create
      a Zend\Session\Config\ConfigInterface instance.
    - By default, uses SessionConfig as ConfigInterface implementation.
    - A "config_class" subkey can be used to specify a specific
      ConfigInterface implementation to use.
  2. @weierophinney

    Created SessionManager factory

    weierophinney committed
    - Consumes ConfigInterface, StorageInterface, and SaveHandlerInterface
      services in order to create a SessionManager instance. Services do not
      need to be present, as null values will be used by default if not
      found.
  3. @weierophinney
  4. @weierophinney

    Implemented session storage service factory

    weierophinney committed
    - Marshals arguments from Config service
    - Proxies to Zend\Session\Storage\Factory for actual creation
  5. @weierophinney

    Added note about save handler service

    weierophinney committed
    - Save handler factory will not be provided by the framework at this
      time.
  6. @weierophinney

    Created session Container abstract factory

    weierophinney committed
    - Provide an array of container names in "session_containers"
      configuration.
    - Uses `Zend\Session\ManagerInterface` service, if available, when
      instantiating containers.
    - Session container services must be prefixed with "SessionContainer\\"
  7. @weierophinney

    Fixes typo in docblock

    weierophinney committed
    - s/SessionConfig/SessionContainer/
  8. @weierophinney

    [#4268] CS fixes

    weierophinney committed
    - per php-cs-fixer
Commits on Apr 21, 2013
  1. @weierophinney
  2. @weierophinney

    Set created manager as default manager for Containers

    weierophinney committed
    - Passes created `SessionManager` instance to
      `Container::setDefaultManager()`
  3. @weierophinney

    Make ability to inject manager as Container default mutable

    weierophinney committed
    - New Config service key, "session_manager"
      - single key for now: "enable_default_container_manager". Defaults to
        true, meaning "inject the Container". Set to false to disable this
        behavior.
View
136 library/Zend/Session/Service/ContainerAbstractFactory.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Session\Service;
+
+use Zend\ServiceManager\AbstractFactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\Session\Container;
+
+/**
+ * Session container abstract service factory.
+ *
+ * Allows creating Container instances, using the Zend\Service\ManagerInterface
+ * if present. Containers are named in a "session_containers" array in the
+ * Config service:
+ *
+ * <code>
+ * return array(
+ * 'session_containers' => array(
+ * 'auth',
+ * 'user',
+ * 'captcha',
+ * ),
+ * );
+ * </code>
+ *
+ * Services use the prefix "SessionContainer\\":
+ *
+ * <code>
+ * $container = $services->get('SessionContainer\captcha');
+ * </code>
+ */
+class ContainerAbstractFactory implements AbstractFactoryInterface
+{
+ /**
+ * Cached container configuration
+ *
+ * @var array
+ */
+ protected $config;
+
+ /**
+ * @param ServiceLocatorInterface $serviceLocator
+ * @param string $name
+ * @param string $requestedName
+ * @return bool
+ */
+ public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
+ {
+ $config = $this->getConfig($serviceLocator);
+ if (!$config) {
+ return false;
+ }
+
+ $containerName = $this->normalizeContainerName($requestedName);
+ if (!$containerName) {
+ return false;
+ }
+
+ return array_key_exists($containerName, $config);
+ }
+
+ /**
+ * @param ServiceLocatorInterface $serviceLocator
+ * @param string $name
+ * @param string $requestedName
+ * @return Container
+ */
+ public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
+ {
+ $containerName = substr($requestedName, 17);
+ $manager = null;
+
+ if ($serviceLocator->has('Zend\Session\ManagerInterface')) {
+ $manager = $serviceLocator->get('Zend\Session\ManagerInterface');
+ }
+
+ return new Container($containerName, $manager);
+ }
+
+ /**
+ * Retrieve config from service locator, and cache for later
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return false|array
+ */
+ protected function getConfig(ServiceLocatorInterface $serviceLocator)
+ {
+ if (null !== $this->config) {
+ return $this->config;
+ }
+
+ if (!$serviceLocator->has('Config')) {
+ $this->config = array();
+ return false;
+ }
+
+ $config = $serviceLocator->get('Config');
+ if (!isset($config['session_containers']) || !is_array($config['session_containers'])) {
+ $this->config = array();
+ return false;
+ }
+
+ $config = $config['session_containers'];
+ $config = array_flip($config);
+
+ $this->config = array_change_key_case($config);
+ return $this->config;
+ }
+
+ /**
+ * Normalize the container name in order to perform a lookup
+ *
+ * Strips off the "SessionContainer\" prefix, and lowercases the name.
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function normalizeContainerName($name)
+ {
+ $containerName = strtolower($name);
+ if (18 > strlen($containerName)
+ || ('sessioncontainer\\' !== substr($containerName, 0, 17))
+ ) {
+ return false;
+ }
+
+ return substr($containerName, 17);
+ }
+}
View
63 library/Zend/Session/Service/SessionConfigFactory.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Session\Service;
+
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\Session\Config\ConfigInterface;
+
+class SessionConfigFactory implements FactoryInterface
+{
+ /**
+ * Create session configuration object
+ *
+ * Uses "session_config" section of configuration to seed a ConfigInterface
+ * instance. By default, Zend\Session\Config\SessionConfig will be used, but
+ * you may also specify a specific implementation variant using the
+ * "config_class" subkey.
+ *
+ * @param ServiceLocatorInterface $services
+ * @return ConfigInterface
+ * @throws ServiceNotCreatedException if session_config is missing, or an
+ * invalid config_class is used
+ */
+ public function createService(ServiceLocatorInterface $services)
+ {
+ $config = $services->get('Config');
+ if (!isset($config['session_config']) || !is_array($config['session_config'])) {
+ throw new ServiceNotCreatedException(
+ 'Configuration is missing a "session_config" key, or the value of that key is not an array'
+ );
+ }
+ $class = 'Zend\Session\Config\SessionConfig';
+ $config = $config['session_config'];
+ if (isset($config['config_class'])) {
+ if (!class_exists($config['config_class'])) {
+ throw new ServiceNotCreatedException(sprintf(
+ 'Invalid configuration class "%s" specified in "config_class" session configuration; must be a valid class',
+ $class
+ ));
+ }
+ $class = $config['config_class'];
+ unset($config['config_class']);
+ }
+
+ $sessionConfig = new $class();
+ if (!$sessionConfig instanceof ConfigInterface) {
+ throw new ServiceNotCreatedException(sprintf(
+ 'Invalid configuration class "%s" specified in "config_class" session configuration; must implement Zend\Session\Config\ConfigInterface',
+ $class
+ ));
+ }
+ $sessionConfig->setOptions($config);
+ return $sessionConfig;
+ }
+}
View
127 library/Zend/Session/Service/SessionManagerFactory.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Session\Service;
+
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\Session\Config\ConfigInterface;
+use Zend\Session\Container;
+use Zend\Session\SaveHandler\SaveHandlerInterface;
+use Zend\Session\SessionManager;
+use Zend\Session\Storage\StorageInterface;
+
+class SessionManagerFactory implements FactoryInterface
+{
+ /**
+ * Default configuration for manager behavior
+ *
+ * @var array
+ */
+ protected $defaultManagerConfig = array(
+ 'enable_default_container_manager' => true,
+ );
+
+ /**
+ * Create session manager object
+ *
+ * Will consume any combination (or zero) of the following services, when
+ * present, to construct the SessionManager instance:
+ *
+ * - Zend\Session\Config\ConfigInterface
+ * - Zend\Session\Storage\StorageInterface
+ * - Zend\Session\SaveHandler\SaveHandlerInterface
+ *
+ * The first two have corresponding factories inside this namespace. The
+ * last, however, does not, due to the differences in implementations, and
+ * the fact that save handlers will often be written in userland. As such
+ * if you wish to attach a save handler to the manager, you will need to
+ * write your own factory, and assign it to the service name
+ * "Zend\Session\SaveHandler\SaveHandlerInterface", (or alias that name
+ * to your own service).
+ *
+ * You can configure limited behaviors via the "session_manager" key of the
+ * Config service. Currently, these include:
+ *
+ * - enable_default_container_manager: whether to inject the created instance
+ * as the default manager for Container instances. The default value for
+ * this is true; set it to false to disable.
+ *
+ * @param ServiceLocatorInterface $services
+ * @return SessionManager
+ * @throws ServiceNotCreatedException if any collaborators are not of the
+ * correct type
+ */
+ public function createService(ServiceLocatorInterface $services)
+ {
+ $config = null;
+ $storage = null;
+ $saveHandler = null;
+ $managerConfig = $this->defaultManagerConfig;
+
+ if ($services->has('Zend\Session\Config\ConfigInterface')) {
+ $config = $services->get('Zend\Session\Config\ConfigInterface');
+ if (!$config instanceof ConfigInterface) {
+ throw new ServiceNotCreatedException(sprintf(
+ 'SessionManager requires that the %s service implement %s; received "%s"',
+ 'Zend\Session\Config\ConfigInterface',
+ 'Zend\Session\Config\ConfigInterface',
+ (is_object($config) ? get_class($config) : gettype($config))
+ ));
+ }
+ }
+
+ if ($services->has('Zend\Session\Storage\StorageInterface')) {
+ $storage = $services->get('Zend\Session\Storage\StorageInterface');
+ if (!$storage instanceof StorageInterface) {
+ throw new ServiceNotCreatedException(sprintf(
+ 'SessionManager requires that the %s service implement %s; received "%s"',
+ 'Zend\Session\Storage\StorageInterface',
+ 'Zend\Session\Storage\StorageInterface',
+ (is_object($storage) ? get_class($storage) : gettype($storage))
+ ));
+ }
+ }
+
+ if ($services->has('Zend\Session\SaveHandler\SaveHandlerInterface')) {
+ $saveHandler = $services->get('Zend\Session\SaveHandler\SaveHandlerInterface');
+ if (!$saveHandler instanceof SaveHandlerInterface) {
+ throw new ServiceNotCreatedException(sprintf(
+ 'SessionManager requires that the %s service implement %s; received "%s"',
+ 'Zend\Session\SaveHandler\SaveHandlerInterface',
+ 'Zend\Session\SaveHandler\SaveHandlerInterface',
+ (is_object($saveHandler) ? get_class($saveHandler) : gettype($saveHandler))
+ ));
+ }
+ }
+
+ $manager = new SessionManager($config, $storage, $saveHandler);
+
+ // Get session manager configuration, if any, and merge with default configuration
+ if ($services->has('Config')) {
+ $configService = $services->get('Config');
+ if (isset($configService['session_manager'])
+ && is_array($configService['session_manager'])
+ ) {
+ $managerConfig = array_merge($managerConfig, $configService['session_manager']);
+ }
+ }
+
+ // If configuration enables the session manager as the default manager for container
+ // instances, do so.
+ if (isset($managerConfig['enable_default_container_manager'])
+ && $managerConfig['enable_default_container_manager']
+ ) {
+ Container::setDefaultManager($manager);
+ }
+
+ return $manager;
+ }
+}
View
63 library/Zend/Session/Service/StorageFactory.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Session\Service;
+
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\Session\Storage\Exception as SessionException;
+use Zend\Session\Storage\Factory;
+use Zend\Session\Storage\StorageInterface;
+
+class StorageFactory implements FactoryInterface
+{
+ /**
+ * Create session storage object
+ *
+ * Uses "session_storage" section of configuration to seed a StorageInterface
+ * instance. That array should contain the key "type", specifying the storage
+ * type to use, and optionally "options", containing any options to be used in
+ * creating the StorageInterface instance.
+ *
+ * @param ServiceLocatorInterface $services
+ * @return StorageInterface
+ * @throws ServiceNotCreatedException if session_storage is missing, or the
+ * factory cannot create the storage instance.
+ */
+ public function createService(ServiceLocatorInterface $services)
+ {
+ $config = $services->get('Config');
+ if (!isset($config['session_storage']) || !is_array($config['session_storage'])) {
+ throw new ServiceNotCreatedException(
+ 'Configuration is missing a "session_storage" key, or the value of that key is not an array'
+ );
+ }
+
+ $config = $config['session_storage'];
+ if (!isset($config['type'])) {
+ throw new ServiceNotCreatedException(
+ '"session_storage" configuration is missing a "type" key'
+ );
+ }
+ $type = $config['type'];
+ $options = isset($config['options']) ? $config['options'] : array();
+
+ try {
+ $storage = Factory::factory($type, $options);
+ } catch (SessionException $e) {
+ throw new ServiceNotCreatedException(sprintf(
+ 'Factory is unable to create StorageInterface instance: %s',
+ $e->getMessage()
+ ), $e->getCode(), $e);
+ }
+
+ return $storage;
+ }
+}
View
148 library/Zend/Session/Storage/Factory.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Session\Storage;
+
+use ArrayAccess;
+use Traversable;
+use Zend\Session\Exception;
+use Zend\Stdlib\ArrayObject;
+use Zend\Stdlib\ArrayUtils;
+
+abstract class Factory
+{
+ /**
+ * Create and return a StorageInterface instance
+ *
+ * @param string $type
+ * @param array|Traversable $options
+ * @return StorageInterface
+ * @throws Exception\InvalidArgumentException for unrecognized $type or individual options
+ */
+ public static function factory($type, $options = array())
+ {
+ if (!is_string($type)) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects the $type argument to be a string class name; received "%s"',
+ __METHOD__,
+ (is_object($type) ? get_class($type) : gettype($type))
+ ));
+ }
+ if (!class_exists($type)) {
+ $class = __NAMESPACE__ . '\\' . $type;
+ if (!class_exists($class)) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects the $type argument to be a valid class name; received "%s"',
+ __METHOD__,
+ $type
+ ));
+ }
+ $type = $class;
+ }
+
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ }
+ if (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects the $options argument to be an array or Traversable; received "%s"',
+ __METHOD__,
+ (is_object($options) ? get_class($options) : gettype($options))
+ ));
+ }
+
+ switch (true) {
+ case (in_array('Zend\Session\Storage\AbstractSessionArrayStorage', class_parents($type))):
+ return static::createSessionArrayStorage($type, $options);
+ break;
+ case ($type === 'Zend\Session\Storage\ArrayStorage'):
+ case (in_array('Zend\Session\Storage\ArrayStorage', class_parents($type))):
+ return static::createArrayStorage($type, $options);
+ break;
+ case (in_array('Zend\Session\Storage\StorageInterface', class_implements($type))):
+ return new $type($options);
+ break;
+ default:
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Unrecognized type "%s" provided; expects a class implementing %s\StorageInterface',
+ $type,
+ __NAMESPACE__
+ ));
+ }
+ }
+
+ /**
+ * Create a storage object from an ArrayStorage class (or a descendent)
+ *
+ * @param string $type
+ * @param array $options
+ * @return ArrayStorage
+ */
+ protected static function createArrayStorage($type, $options)
+ {
+ $input = array();
+ $flags = ArrayObject::ARRAY_AS_PROPS;
+ $iteratorClass = 'ArrayIterator';
+
+ if (isset($options['input']) && null !== $options['input']) {
+ if (!is_array($options['input'])) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects the "input" option to be an array; received "%s"',
+ $type,
+ (is_object($options['input']) ? get_class($options['input']) : gettype($options['input']))
+ ));
+ }
+ $input = $options['input'];
+ }
+
+ if (isset($options['flags'])) {
+ $flags = $options['flags'];
+ }
+
+ if (isset($options['iterator_class'])) {
+ if (!class_exists($options['iterator_class'])) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects the "iterator_class" option to be a valid class; received "%s"',
+ $type,
+ (is_object($options['iterator_class']) ? get_class($options['iterator_class']) : gettype($options['iterator_class']))
+ ));
+ }
+ $iteratorClass = $options['iterator_class'];
+ }
+
+ return new $type($input, $flags, $iteratorClass);
+ }
+
+ /**
+ * Create a storage object from a class extending AbstractSessionArrayStorage
+ *
+ * @param string $type
+ * @param array $options
+ * @return AbstractSessionArrayStorage
+ * @throws Exception\InvalidArgumentException if the input option is invalid
+ */
+ protected static function createSessionArrayStorage($type, array $options)
+ {
+ $input = null;
+ if (isset($options['input'])) {
+ if (null !== $options['input']
+ && !is_array($options['input'])
+ && !$input instanceof ArrayAccess
+ ) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects the "input" option to be null, an array, or to implement ArrayAccess; received "%s"',
+ $type,
+ (is_object($options['input']) ? get_class($options['input']) : gettype($options['input']))
+ ));
+ }
+ $input = $options['input'];
+ }
+ return new $type($input);
+ }
+}
View
5 library/Zend/Session/composer.json
@@ -17,8 +17,9 @@
"zendframework/zend-stdlib": "self.version"
},
"suggest": {
- "zendframework/zend-validator": "Zend\\Validator component",
- "zendframework/zend-eventmanager": "Zend\\EventManager component"
+ "zendframework/zend-eventmanager": "Zend\\EventManager component",
+ "zendframework/zend-servicemanager": "Zend\\ServiceManager component",
+ "zendframework/zend-validator": "Zend\\Validator component"
},
"extra": {
"branch-alias": {
View
90 tests/ZendTest/Session/Service/ContainerAbstractFactoryTest.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Storage\ArrayStorage;
+
+/**
+ * @group Zend_Session
+ */
+class ContainerAbstractFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ public $config = array(
+ 'session_containers' => array(
+ 'foo',
+ 'bar',
+ 'Baz\Bat',
+ 'Underscore_Separated',
+ 'With\Digits_0123',
+ ),
+ );
+
+ public function setUp()
+ {
+ $this->services = new ServiceManager();
+
+ $this->services->setService('Zend\Session\Storage\StorageInterface', new ArrayStorage());
+ $this->services->setFactory('Zend\Session\ManagerInterface', 'Zend\Session\Service\SessionManagerFactory');
+ $this->services->addAbstractFactory('Zend\Session\Service\ContainerAbstractFactory');
+
+ $this->services->setService('Config', $this->config);
+ }
+
+ public function validContainers()
+ {
+ $containers = array();
+ $config = $this->config;
+ foreach ($config['session_containers'] as $name) {
+ $containers[] = array('SessionContainer\\' . $name, $name);
+ }
+ return $containers;
+ }
+
+ /**
+ * @dataProvider validContainers
+ */
+ public function testCanRetrieveNamedContainers($serviceName, $containerName)
+ {
+ $this->assertTrue($this->services->has($serviceName), "Container does not have service by name '$serviceName'");
+ $container = $this->services->get($serviceName);
+ $this->assertInstanceOf('Zend\Session\Container', $container);
+ $this->assertEquals($containerName, $container->getName());
+ }
+
+ /**
+ * @dataProvider validContainers
+ */
+ public function testContainersAreInjectedWithSessionManagerService($serviceName, $containerName)
+ {
+ $this->assertTrue($this->services->has($serviceName), "Container does not have service by name '$serviceName'");
+ $container = $this->services->get($serviceName);
+ $this->assertSame($this->services->get('Zend\Session\ManagerInterface'), $container->getManager());
+ }
+
+ public function invalidContainers()
+ {
+ $containers = array();
+ $config = $this->config;
+ foreach ($config['session_containers'] as $name) {
+ $containers[] = array($name);
+ }
+ $containers[] = array('DOES_NOT_EXIST');
+ return $containers;
+ }
+
+ /**
+ * @dataProvider invalidContainers
+ */
+ public function testInvalidContainerNamesAreNotMatchedByAbstractFactory($name)
+ {
+ $this->assertFalse($this->services->has($name));
+ }
+}
View
59 tests/ZendTest/Session/Service/SessionConfigFactoryTest.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Service\SessionConfigFactory;
+
+/**
+ * @group Zend_Session
+ */
+class SessionConfigFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ $this->services = new ServiceManager();
+ $this->services->setFactory('Zend\Session\Config\ConfigInterface', 'Zend\Session\Service\SessionConfigFactory');
+ }
+
+ public function testCreatesSessionConfigByDefault()
+ {
+ $this->services->setService('Config', array(
+ 'session_config' => array(),
+ ));
+ $config = $this->services->get('Zend\Session\Config\ConfigInterface');
+ $this->assertInstanceOf('Zend\Session\Config\SessionConfig', $config);
+ }
+
+ public function testCanCreateAlternateSessionConfigTypeViaConfigClassKey()
+ {
+ $this->services->setService('Config', array(
+ 'session_config' => array(
+ 'config_class' => 'Zend\Session\Config\StandardConfig',
+ ),
+ ));
+ $config = $this->services->get('Zend\Session\Config\ConfigInterface');
+ $this->assertInstanceOf('Zend\Session\Config\StandardConfig', $config);
+ // Since SessionConfig extends StandardConfig, need to test that it's not that
+ $this->assertNotInstanceOf('Zend\Session\Config\SessionConfig', $config);
+ }
+
+ public function testServiceReceivesConfiguration()
+ {
+ $this->services->setService('Config', array(
+ 'session_config' => array(
+ 'config_class' => 'Zend\Session\Config\StandardConfig',
+ 'name' => 'zf2',
+ ),
+ ));
+ $config = $this->services->get('Zend\Session\Config\ConfigInterface');
+ $this->assertEquals('zf2', $config->getName());
+ }
+}
View
78 tests/ZendTest/Session/Service/SessionManagerFactoryTest.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Config\StandardConfig;
+use Zend\Session\Container;
+use Zend\Session\Service\SessionManagerFactory;
+use Zend\Session\Storage\ArrayStorage;
+
+/**
+ * @group Zend_Session
+ */
+class SessionManagerFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ $this->services = new ServiceManager();
+ $this->services->setFactory('Zend\Session\ManagerInterface', 'Zend\Session\Service\SessionManagerFactory');
+ }
+
+ public function testCreatesSessionManager()
+ {
+ $manager = $this->services->get('Zend\Session\ManagerInterface');
+ $this->assertInstanceOf('Zend\Session\SessionManager', $manager);
+ }
+
+ public function testConfigObjectIsInjectedIfPresentInServices()
+ {
+ $config = $this->getMock('Zend\Session\Config\ConfigInterface');
+ $this->services->setService('Zend\Session\Config\ConfigInterface', $config);
+ $manager = $this->services->get('Zend\Session\ManagerInterface');
+ $test = $manager->getConfig();
+ $this->assertSame($config, $test);
+ }
+
+ public function testFactoryWillInjectStorageIfPresentInServices()
+ {
+ // Using concrete version here as mocking was too complex
+ $storage = new ArrayStorage();
+ $this->services->setService('Zend\Session\Storage\StorageInterface', $storage);
+ $manager = $this->services->get('Zend\Session\ManagerInterface');
+ $test = $manager->getStorage();
+ $this->assertSame($storage, $test);
+ }
+
+ public function testFactoryWillInjectSaveHandlerIfPresentInServices()
+ {
+ $saveHandler = $this->getMock('Zend\Session\SaveHandler\SaveHandlerInterface');
+ $this->services->setService('Zend\Session\SaveHandler\SaveHandlerInterface', $saveHandler);
+ $manager = $this->services->get('Zend\Session\ManagerInterface');
+ $test = $manager->getSaveHandler();
+ $this->assertSame($saveHandler, $test);
+ }
+
+ public function testFactoryWillMarkManagerAsContainerDefaultByDefault()
+ {
+ $manager = $this->services->get('Zend\Session\ManagerInterface');
+ $this->assertSame($manager, Container::getDefaultManager());
+ }
+
+ public function testCanDisableContainerDefaultManagerInjectionViaConfiguration()
+ {
+ $config = array('session_manager' => array(
+ 'enable_default_container_manager' => false,
+ ));
+ $this->services->setService('Config', $config);
+ $manager = $this->services->get('Zend\Session\ManagerInterface');
+ $this->assertNotSame($manager, Container::getDefaultManager());
+ }
+}
View
125 tests/ZendTest/Session/Service/StorageFactoryTest.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace ZendTest\Session\Service;
+
+use Zend\ServiceManager\ServiceManager;
+use Zend\Session\Service\StorageFactory;
+
+/**
+ * @group Zend_Session
+ */
+class StorageFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ $this->services = new ServiceManager();
+ $this->services->setFactory('Zend\Session\Storage\StorageInterface', 'Zend\Session\Service\StorageFactory');
+ }
+
+ public function sessionStorageConfig()
+ {
+ return array(
+ 'array-storage-short' => array(array(
+ 'session_storage' => array(
+ 'type' => 'ArrayStorage',
+ 'options' => array(
+ 'input' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ ), 'Zend\Session\Storage\ArrayStorage'),
+ 'array-storage-fqcn' => array(array(
+ 'session_storage' => array(
+ 'type' => 'Zend\Session\Storage\ArrayStorage',
+ 'options' => array(
+ 'input' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ ), 'Zend\Session\Storage\ArrayStorage'),
+ 'session-array-storage-short' => array(array(
+ 'session_storage' => array(
+ 'type' => 'SessionArrayStorage',
+ 'options' => array(
+ 'input' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ ), 'Zend\Session\Storage\SessionArrayStorage'),
+ 'session-array-storage-fqcn' => array(array(
+ 'session_storage' => array(
+ 'type' => 'Zend\Session\Storage\SessionArrayStorage',
+ 'options' => array(
+ 'input' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ ), 'Zend\Session\Storage\SessionArrayStorage'),
+ );
+ }
+
+ /**
+ * @dataProvider sessionStorageConfig
+ */
+ public function testUsesConfigurationToCreateStorage($config, $class)
+ {
+ $this->services->setService('Config', $config);
+ $storage = $this->services->get('Zend\Session\Storage\StorageInterface');
+ $this->assertInstanceOf($class, $storage);
+ $test = $storage->toArray();
+ $this->assertEquals($config['session_storage']['options']['input'], $test);
+ }
+
+ public function invalidSessionStorageConfig()
+ {
+ return array(
+ 'unknown-class-short' => array(array(
+ 'session_storage' => array(
+ 'type' => 'FooStorage',
+ 'options' => array(),
+ ),
+ )),
+ 'unknown-class-fqcn' => array(array(
+ 'session_storage' => array(
+ 'type' => 'Foo\Bar\Baz\Bat',
+ 'options' => array(),
+ ),
+ )),
+ 'bad-class' => array(array(
+ 'session_storage' => array(
+ 'type' => 'Zend\Session\Config\StandardConfig',
+ 'options' => array(),
+ ),
+ )),
+ 'good-class-invalid-options' => array(array(
+ 'session_storage' => array(
+ 'type' => 'ArrayStorage',
+ 'options' => array(
+ 'input' => 'this is invalid',
+ ),
+ ),
+ )),
+ );
+ }
+
+ /**
+ * @dataProvider invalidSessionStorageConfig
+ */
+ public function testInvalidConfigurationRaisesServiceNotCreatedException($config)
+ {
+ $this->services->setService('Config', $config);
+ $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotCreatedException');
+ $storage = $this->services->get('Zend\Session\Storage\StorageInterface');
+ }
+}
Something went wrong with that request. Please try again.