10

The architecture of the Session component in Zend Framework 2 is yet undocumented and I'm having some trouble understanding it's practical use (compared to the very intuitive Symfony Session for example).

A short summary of the important pieces:

  • Zend\Session\Storage\SessionStorage maps and replaces the $_SESSION superglobal
  • Zend\Session\SessionManager is a facade to manage the storage, the session cookies, session configuration, session validation, etc.
  • Zend\Session\Container is a sort of replacement for the old Session_Namespace, different Containers share one Manager instance (via a static field).

There is no component that represents a collection of namespaces (containers) and therefore there is no way of using methods like 'issetNamespaceX', 'unsetNamespaceX', etc. Nobody (including the Manager as well as Storage) knows about the containers, whether there are any, and if, how many with what names.

Matthew Weier O'Phinney explained this circumstance as follows:

The Container is a special class for working with isolated segments of the current Storage instance. [...] If anything, a Storage adapter would contain Containers, not the Manager. However, we also want to allow more basic usage of storage, which makes the Container orthogonal to Storage, and which explains the difference in has-a relations.

I see a couple of practical problems with this solution with regard to proper dependency injection. Obviously the Manager can be seen as a service with a rather long lifetime and therefore qualifies for constructor injection. Unfortunately, the Manager has no clue about the Containers which forces me to either inject Containers as well (bad because rather short lived and takes slots away), write my own additional functionality to make the Storage or the Manager Container-aware (should be framework functionality) or create Containers in my Consuming classes (which I want to avoid obviously).

So the Zend solution doesn't seem practical to me. If I want to use the Manager, the FlashMessenger and an additional container, I need to inject 4 (four!) classes. If I do the same with the Symfony Session, I only need to inject 1 (one) class.

Furthermore Containers don't qualify for injection since they're potentially short lived run time objects, which may exist or may not at a given point during script execution. With Symfony Session this is not a problem since the Session is aware of it's bags (containers), with ZF2 this is a problem since the Manager is NOT aware of the Containers.


Main question: How am I supposed to use Zend\Session with Containers in practice?

Additional question: Is there a good reason not to provide real namespace functionality similar to ZF1 or for example similar to the Symfony SessionBag?

markus
  • 40,136
  • 23
  • 97
  • 142
  • Using containers is quite easy, just instantiate and use them: `$cnt = new Container('namespaceName'); $cnt['myData'] = 'someValue';` Do you need to do anything further? // Edit: As far as I understand this, a container represents a key of $_SESSION (if using the default storage). – Daniel M Dec 17 '12 at 11:23
  • Yes, using containers is easy, it's more the question on how to use them in a fully DI enabled environment. – markus Dec 17 '12 at 15:18
  • And, as I say, how to manage them! – markus Dec 17 '12 at 15:30
  • Currently, I'm using Symfony\Component\HttpFoundation\Session\Session to replace Zend Session in my ZF2 applications, because it's understandable, documented and does exactly what I expect it to do. I'll revisit the topic, when I hear from ZF or the docs are up. – markus Dec 18 '12 at 11:56
  • I might have some answers. Can you elaborate on "Obviously the Manager can be seen as a service with a rather long lifetime and **therefore qualifies for constructor injection**." and why you want to inject a manager and not a container? – Jurian Sluiman Jan 06 '13 at 10:13
  • Because containers are a) potentially short lived, and b) there might be any number of them. – markus Jan 06 '13 at 11:19
  • Containers are a bundle of parameters; you can see them as a single "namespace". If a controller needs to store some arbitrary data in a session, the controller is completely unaware of the manager and just expects a container to be injected. Your controller should focus around a single aspect, so 99% chance you have also a container for a single "namespace" of parameters too. "Any number" sounds therefore a bit odd. – Jurian Sluiman Jan 06 '13 at 12:49
  • A container shouldn't care about the manager and storage of a session, that's a completely different layer and the session (with the manager, or directly) should be configured out the scope of the controller. – Jurian Sluiman Jan 06 '13 at 12:50
  • Yeah, but since the container is orthogonal to the manager, I still need to inject several objects instead of one. With Symfony Session I can just inject the session and I'm sure I have everything, even a pre-configured flashbag. – markus Jan 06 '13 at 12:57
  • You know the "flashbag" is done in ZF2 with a controller plugin called `flashMessenger`? It is actually the perfect example why you only need a container and not a manager at all: the plugin expects some container to put the parameters in, the rest is up to you to configure (though the default config is already pretty OK): http://zf2.readthedocs.org/en/latest/modules/zend.mvc.plugins.html#the-flashmessenger – Jurian Sluiman Jan 06 '13 at 14:12
  • 2
    Which means I have to inject the flashMessenger too, one MORE dependency... I'm starting to think I didn't write my question very well. You don't seem to understand what I'm trying to say. – markus Jan 06 '13 at 14:28
  • @markus-tharkun truth be told, I read this question a couple of times. I'm surprised by the fact that you seem to have a firm grasp of DI and DP/OOP in general. Which makes it even more confusing that the question feels all over the place. Consider giving an example of what DI you're trying to do on what and why. – Khez Jan 09 '13 at 09:36
  • @Khez I rewrote my question. Does it make more sense to you now, what exactly confuses you? – markus Jan 09 '13 at 20:51
  • I'm glad for the upvotes, it seems that at least some people understand what I'm trying to ask. – markus Jan 11 '13 at 13:29
  • Weird that I keep getting upvotes for this question even though nobody understands it :D. – markus Sep 25 '13 at 22:17

1 Answers1

5

I'm not 100% certain I understand what issues you're getting at.

First, the constructor for a Container accepts both the namespace for the container, as well as optionally the Manager instance: $container = new Container('your container namespace here', $manager). You can specify a default manager instance to use as well: Container::setDefaultManager($manager).

Second, a Container represents simply a named array within the Storage instance used. As such, you can test for existence of a container by doing an isset($storage['your container namespace here']) call.

What exact issues are you running up against that the above do not solve? From your description, it sounds like (a) you were not aware that containers have a 1:1 relationship with the storage, and (b) that you can inject a manager into the container instances. If there are additional problems, I'd like to better understand them.

weierophinney
  • 1,790
  • 9
  • 17
  • Ok, so I gave this some more thought and understood more of it. I wrote a follow up question but decided it doesn't qualify as an SO question and made a gist instead, cloud you verify my thoughts, please? https://gist.github.com/4556064 – markus Jan 17 '13 at 14:01