Imagine that I want to login a user. The user sends the validation data, and my controller gets the POST request so it calls a User Repository method in order to registered him.
I'd like to start the user Session with the user data. But how should I start the session? Should it start in the controller or the model? I think it should be the model, since it's my business logic who says that session have to be started. But how? Should I pass the session object to my Repository?
Im using Doctrine for the model layer, and my own framework for the rest. I use dependency injection but I don't see how to get access to the Session from the entities / repositories layer.
The only solution I've got right now is to call the repository method passing the session as a parameter, but it doesn't feel right.
I think session handling should be done in the controller, but just personal opinion. If you are trying to have a clean separation of concern, it should defiantly be done it the controller. It doesn't make a lot of sense to make Doctrine (which has a very strong focus on abstraction and independence) dependable on the session.
Make a controller which calls a method from model to register the user. The model method returns the user specific data, which you pass to the Session (from controller). You will probably use session in a lot of places, not relevant to model. Why make it stretch to two levels, if you can encapsulate it in one?
Related
I have used this tutorial for creating my user login in Laravel: Laravel Authentication Essentials. So I have a SessionController that contains the methods create, store and destroy, for showing the form, logging in and out respectively.
But there is no model in this tutorial, the validation and Auth::attempt is in the controller. And that doesn't feel right. I can not create a Session model, since the Session class already exists.
Should I put the login/out logic in the User model, or is there another way to do this that complies with the MVC architectural pattern?
First, remember (or know) that you can change everything in Laravel. If you need a Session model using a sessions table, go to app/config/session.php and change the Laravel sessions table to laravel_sessions:
'table' => 'laravel_sessions',
People are doing things differently these days, methods are improving on a daily basis and the way you do your code must be confortable to you. If you feel it is not right the way you are seeing people doing it, change it, Laravel give you the power to change and do things your way. And if you feel you just found a better way of doing it, share it.
This is a 2013 video and today Jeffrey is doing authentication in a completly different way. Sign up for a Laracasts account and take the full Build a Larabook video series to see how he's doing it now.
There's no Session model in this tutorial because he's not storing sessions (successful logins) in a sessions table.
In the tutorial he never touches the User model, so there is no login in the user model. The only thing he's using to do authentication is Auth::attempt(), a Laravel facade method which uses internally the user model (M), to find a user and check if the password matches. He's working with a Session controller (C) and everything related to login (or sign in) and showing login views (V) is done inside that particular controller.
If it is easier to you, you can rename SessionsController to LoginController, I, myself, don't really like the Sessions name for login, but that's a matter of taste not code correctness.
That being said I don't see an MVC (or whatever name people like to call it this week) problem in that video.
EDIT Answering the comment:
The purpose of the model is towards data, no data, no model. In the context of Laravel and a database management system, yes, no table, no model. In the context, for instance, of a client-server API, your server API (Laravel, Rails...) will provide data for your client model (Angular, EmberJS...), so, there will be no table directly related to the client model, but still a model.
But in that particular case you are accessing a model, the user model, via a service, the Authentication service.
I've build my own MVC framework, but I'm still getting my head around a few things.
I have a class to handle session methods such as refreshing sessions, verifying sessions, starting sessions, closing sessions.
My question is where should I declare it in my MVC architecture?
I have an abstract base class, which is extended by the controller.
This base class then declares the model and view.
Should it go in the base class? If so how can I refer to session object methods from the model? Or should I aim to only trigger it from the controller?
I'm new to Object Orientated php as well which makes this more hard. My mind is boggling!!
The request objects are best thought of, or at least written as, being part of the model layer, but because you're writing for the web, Request objects are part of the core of your Framework.
But to clarify:
Effectively, a Session class is a data model, and one could argue that it's part of a bigger subset of request models. Remember, MVC doesn't imply that each request requires a Controller, View and "A Model".
The Model bit, especially, is a layer. It can contain services, data models, an ORM, helpers and what have you...
That said, All things deal with the request should be at the ready in the controller. That's how most FW's work. Check the symfony workflow of a request, and note how far apart the controller and the request are.
This graph, though it deals with the ZendFW cycle, shows the special status of the request object(s) even more clearly:
The server receives the request, the framework kicks in and pours the request into the corresponding objects.
Then, in the code that resolves the request to a given controller, and controller action, I'd pass the required request objects to the controller's constructor.
A basic schematic would be:
Request ===> index.php (startup script)
||
|| some basic checks, create objects
||
|_==> create base controller
||
||
|_==> pass request to constructor, or starter method
Do more specific/targetted checks
||
||
\/
controller has access to request through base controller
and can pass this through to the model layer
So, in resuming, and because I believe repetition works: The request objects are best thought of, or at least written as, being part of the model layer, but because you're writing for the web, Request objects are part of the core of your Framework.
The best way to think of problems involving OO is to consider the following simple questions:
Is your object a representation of something?
Is it actually going to modify other representations?
Is it purely there for display?
Answering "yes" to 1 and "no" to 2 usually (99% of the time) points to the role of a model. "no" to 1 and "yes" to 2 identifies a controller, while "no" to 1, 2, and "yes" to 3 implies a view.
Answering the following highlights inconsistencies or lack of separation:
Yes - yes - no - your model is not clearly separated
Yes - yes - yes - you effectively have an object trying to do everything
Yes - no - yes - your view and models are not separated
In your case, a session is a representation of a state that is held for a client. It therefore can only modify itself, and does not act on anything else. It is a model and is best represented as one.
You should ideally create a session storage controller/object/helper (depending on framework) to insert, recover and update session models, by the way. This is akin to a data provider.
The controller should handle this.
When you will need to set variables, refresh thing inthe session, the controller will do it from the results of your backend functions. That way you do not have to import this session class in every service, backend or utils class and it will always be done in the same way at the same level of coding.
I am working with an MVC framework (specifically, PHP's CodeIgniter). I am trying to follow "best practices" as much as possible, but I don't have much experience with MVC. Is it bad practice for me to retrieve data from a session within the Controller? Should I "ask" the model if, say, a particular session value is 'foo' or 'bar', or should I do that directly inside the Controller? I'm thinking I should do it inside the Model since the session data is technically data, but I just want to make sure. To be clear, I don't store the session data in the database at all, so I'm not running a query.
Models typically handle all domain objects that are persisted to some sort of long-term storage. They may or may not have transient values in them that have to do with the particular application's use of them.
Controllers should be querying any data they need in order to correctly route and display information. It may help to create a 'Service' layer that operates directly on domain objects (your model) and provides an API for Controllers to use. The main thing to not include in Controllers is business logic.
It would be reasonable, for instance, for the Controller to grab the referring page and do something with that data in regards to the user flow. However, apart from validation, it probably shouldn't, say, examine the amount of money being transferred between accounts - it should just pass that on to a service object that instantiates and works with the correct domain objects.
Questions to ask about logic you're putting into a Controller:
Does this logic help figure out what Model objects I need? If not, it shouldn't be here.
Does this logic help figure out what View objects will be used to construct the response to the user? If not, it shouldn't be here.
I am working on this app that accesses session variables in the model layer. This just seems wrong but am willing to be proven wrong. Maybe not wrong but, in most places in app, session variables are handled in controller and passed in as arguments but, in other places, the session value is just accessed. Am I wrong that this seems like bad practice?
edit:
one reason I don't like sessions in models is that it seems to make it more complex to test. Keep it as just params passsed to functions and then recordset passed back.
thx
It depends.
The way I think about this is such:
A Model represents your data layer.
most of the time that data layer will be DB Table based
The Session is just another data storage medium.
Conclusion: If the data that your model represents is stored in the Session, than it is OK to access that data from within the model
An example is a Session based shopping cart. My cart's objects are models of my session data.
Controller shd do a check weather session exist or not before using the model which uses that session inside it .
No it shouldn't. The storage type, should be apart from your business logic. For example:
I have one simple plug-in that perform the access check and put the user object on the registry. So, instead of access session, the model have access to the registry, which is well defined.
$User = Zend_Registry::get('User'); // User model object
From the theoretical point of view, everything should be accessed through data mappers. In the future, if you change from session storage to something else, you'll need to update it just in one place. Your models do not need to know from where the data came from.
If you are taking more than one path to get your data, probably this will cause some problems when your application get large.
The OOP and layered systems approach suggestion is to created specialized objects and layers and keep things simple preventing specific actions to be spread all over the code.
But again, you do not need to change that unless you see advantages.
Keep in mind that sometimes refactoring is more efficient than try to predict everything.
What's stored in the session variables? If it's simply 'logged in? Y/N', then they probably don't need to be part of the model layer. If, however, it's more complex than that, they are probably inextricably linked to your business model and should be treated as such.
The examples at the bottom of the Zend Test documentation show how to test the full MVC using a login function. Presumably you could do the same when testing models?
I am coding my first CodeIgniter application (very familiar with PHP, but not CI) and have the following setup:
I have a controller, Signup, that controls a signup process. Every function of the controller is the next step in the process. I have an object, Did, that I am currently loading as a library. This object's properties/variables are updated as the signup process moves along.
The issue I'm having is that the properties from one function of the Signup controller do not carry over to the next function. It is as if the class is re-constructed with every function.
Is there a way to reuse the class throughout the controller without it having to be re-instantiated? I'd rather not have to serialize and store in a session, either.
Thanks in advance.
As always, there are many solutions to the same problem. Please disregard this if it doesn't fit well with your implementation.
Keeping the signup steps in an object is a good idea- however, every time you load a new page CI rebuilds all the objects. In order for data to persist it should be stored in the session, but that doesn't mean you have to be working with session variables in your controller.
How are you transferring data to your application? Is it via forms or ajax?
One way you can do it is by unserializing the object from the session and storing it as an object in your controller's constructor. That way you can still run $myObj->function() against it and use a $myObj->save() function to reserialize and store it.
Hope that helps!
The problem you are having is that you are depending on the in-memory state of your application to remain from request to request.
You're expecting your class to use the same instantiation of your Did object between requests.
This is not how PHP/HTTP works. Each request is handled individually and is it's own instance of your application. So each request creates a new Did object.
To persist the state you need to either use Sessions to carry information between requests, use a database to handle your persistent state, or a combination of both.
Codeigniter Sessions
Codeigniter Database Class