What is a session in a web application? It is a period of time with some kind of activity and data possibly associated with it. For example, a user opens an online store and starts adding goods into his cart. He isn’t a registered user, he is not authenticated. He may just as well close the page and forget about those goods he’s added. What is that thing the cart is associated to? The session. The session of them working with the site. When he’s gone - the session ends. It’s important that sessions are limited in time, they start and end. When a session ends (user decides not to buy anything from your store) all stuff associated with the session is gone along with it. That’s why sessions are convenient.
Implementing sessions for a DDD application
Even though frameworks and even programming languages often have things like Sessions built-in (also ACL, authentication etc), it is important to understand that all those things are actually part of Domain. How to use those built-in features in a DDD application?
My approach to this is to always implement Sessions for the purposes of a specific application instead of relying on built-in features. In my practice there have always been problems because of relying on PHP’s session either with performance or flexibility of the overall architecture.
Session for BasicCrm
I decided that we don’t really need sessions for not registered users (like in the online store example). That is, when a registered user logs in - only then a session starts. In other words, in response to the login action user gets new session started. I don’t remember in which book it was described so well about the ways of session implementation variations. There are three ways to go about it, but essentially two are important:
clients send the session data every request so the system uses it
clients only use a secure session id and all the session data is stored in the system
The one I used the most is the second one. When somebody logs in to the BasicCRM application we let them know the session identifier: a unique, secure id. Whenever they want to do anything within this session they started they need to provide this id. As as far as it is secure and associated with the user who started the session there’s no need to provide user credentials each request. Just session id.
Sessions are considered valid only for one day since they been used last time.
“Session” class of objects:
has a secure unique identifier, string of 32 random characters, used to refer it
there is a way to find out a session identifier
there is a way to find out whether a session is valid or not
has last used time, the time when it was created or used last time
there is a way to “use” a session therefore prolong it
is associated with the user who started the session
there is a way to find out the user who started the session
SessionsRepository
What would we do in every Service Layer function where we need to process a user-provided session id? It’s not enough to get it from the datastorage, we also need check whether it’s valid or not and mark it as “used” i.e. prolong it being valid. This is some kind of logic we’d like to avoid duplicating. Any logic being duplicated is a sign that you need to introduce a new domain term that would be responsible for that logic.
Here I put all that into the SessionRepository:
there is a way to retrieve a valid session by it’s id
finds session by its id
error if session isn’t found
error if session isn’t valid
refreshes session
persists changes
returns session
The code implementing this logic:
Here’s the list of Service Layer functions (the system’s public API) I’ve added for these new domain objects:
MVC
A few MVC additions here. I’ve added an action helper that attempts to view current session data and if it’s a registered user using the system now - it switches the layout:
This way if you log in you’ll see a different set of menus and current session data information (like the email):
It’s a de facto standard these days to save session ids in the browser’s cookies so it’s all transparent for the users. I decided to follow that best practice: when user logs in, the browser is requested to remember the id in the cookies, when they log out - the cookie is cleared: