I have a MVC application that receives an input from a form.
This is a login form so the only validation that is necessary is to check whether the input is non-empty.
Right now before I pass it to the model I validate it in the controller.
Is this a best practice or not? Does it belong to the model?
I don't think there's an official best practice limiting validation to any single part of the MVC pattern. For example, your view can (and should) do some up-front validation using Javascript. Your controller should also offer the same types of validation, as well as more business-logic related validation. The model can also offer forms of validation, i.e., setters not allowing null values.
There's an interesting discussion of this at joelonsoftware.
I have been thinking about this for a LONG time and after trying putting validation in both controllers and models.... finally I have come to the conclusion that for many of my applications... validation belongs in the model and not in the controller. Why? Because the same model could in the future be used by various other controller calls or APIs... and then I would have to repeat the validation process over and over again. That would violate DRY and lead to many errors. Plus philosophically its the model which interacts with the database ( or other persistent storage ) and thus is sort of a 'last call for alcohol' place to do this anyway.
So I do my get/post translation in the controller and then send raw data to the model for validation and processing. Of course I am often doing php/mysql web applications and if you are doing other things results may vary. I hope this helps someone.
Validation must be in the Model
Only the model knows the "details" of the business. only the model knows which data is acceptable and which data is not. the controller just knows how to "use" the model.
for example: let's say we need the functionality of registering new users to our system.
The Model:
public function registerUser(User $user){
//pseudo code
//primitive validation
if(!isInt($user->age)){
//log the invalid input error
return "age";
}
if(!isString($user->name)){
//log the invalid input error
return "name";
}
//business logic validation
//our buisnees only accept grown peoples
if($user->age < 18){
//log the error
return "age";
}
//our buisness accepts only users with good physique
if($user->weight > 100){
//log the error
return "weight";
}
//ervery thing is ok ? then insert the user
//data base query (insert into user (,,,) valeues (?,?,?,?))
return true;
}
Now the controller/s job is to "use" the model registerUser() function without the knowledge of how the model is going to do the validation, or even what is considered "valid" or not!
the Controller:
$user = new User();
$user->age = isset($_POST['age']) ? $_POST['age'] : null;
$user->name = isset($_POST['name']) ? $_POST['name'] : null;
$user->age = isset($_POST['weight']) ? $_POST['weight'] : null;
$result = $theModel->registerUser($user);// <- the controller uses the model
if($result === true){
//build the view(page/template) with success message and die
}
$msg = "";
//use the return value from the function or you can check the error logs
switch ($result){
case"age" :
$msg = "Sorry, you must be over 18";
break;
case "name":
$msg = "name field is not correct";
break;
case "weight":
$msg = "Sorry, you must have a good physique";
break;
}
//build the view(page/template) with error messages and die
The class user
class User {
public $age;
public $name;
public $weight;
}
having an architecture like that will "free" the controllers completely from the details of the business logic -which is a good thing-.
Suppose we want to make another form of user registration somewhere else in the website (and we will have another controller allocated for it). now the other controller will use the same method of the model registerUser().
But if we distributed the validation logic between the controller and the model they will not be separated -which is bad and against MVC- meaning that every time you need to make new view and controller to register new user you must use the same old controller AND the model together. Moreover if the business logic is changed (we now accept teenagers in our sports club) you are going only to change the code in the model registerUser() function. the controllers code is still the same.
Its business logic, so no, it doesn't belong in the model.
Within the controller you have the ModelState property to which you can add validation errors to.
See this example on the MSDN.
Assuming your application is structured like:
Model-View-Controller
Service
Persistence
Model
The user input would come to your controller, and you would use services in the service layer to validate it.
Business Logic -> Controller
Data Validation -> Model
Related
I have such function in the controller
public function actionNext(){
$category = $this->getCategory();
$not_finished = $this->getQuestionFromCategory($category);
if(!empty($not_finished)){
$next_question_id = getNextQuestionId();
$this->updateNextQuestion();
}
else{
addNextCategory();
}
}
My question is: all fuctions
getCategory
getQuestionFromCategory
getNextQuestionId
updateNextQuestion
addNextCategory
from the example should be in model or controller too (all functions is the requests to the db).
Normally the function related to the db are in model, tipically the model extend the active record and for this contain also the related sql/schema/model related function. in your case is think the function getCategory and probably getQuestionFormCategory
The function related to service for support controller action are place in controller. in your case genNextQuestionId, updateNewQuestion, addNextQuestion.
The main rules is: what's regarding the structural knwoledge of an entity is in model, what's regarding tactical behaviuor is in controller.
Obviously the part related to sort and find are placed in ...search class.
After reading a lot of posts and Stack Overflow resources, I've still got some problems about the famous question about "where to put business logic?" Reading StackOverflow Question and A Blog Post, I believe I've understood the issue of code separation well.
Suppose I have a web form where you can add a user that will be added to a db. This example involves these concepts:
Form
Controller
Entity
Service
Repository
If I didn't miss something, you have to create an entity with some properties, getters, setters and so on in order to make it persist into a db. If you want to fetch or write that entity, you'll use entityManager and, for "non-canonical" query, entityRepository (that is where you can fit your "query language" query).
Now you have to define a service (that is a PHP class with a "lazy" instance) for all business logic; this is the place to put "heavy" code. Once you've recorded the service into your application, you can use it almost everywhere and that involves code reuse and so on.
When you render and post a form, you bind it with your entity (and with constraints of course) and use all the concepts defined above to put all together.
So, "old-me" would write a controller's action in this way:
public function indexAction(Request $request)
{
$modified = False;
if($request->getMethod() == 'POST'){ // submit, so have to modify data
$em = $this->getDoctrine()->getEntityManager();
$parameters = $request->request->get('User'); //form retriving
$id = $parameters['id'];
$user = $em->getRepository('SestanteUserBundle:User')->find($id);
$form = $this->createForm(new UserType(), $user);
$form->bindRequest($request);
$em->flush();
$modified = True;
}
$users = $this->getDoctrine()->getEntityManager()->getRepository('SestanteUserBundle:User')->findAll();
return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
}
"New-me" has refactored code in this way:
public function indexAction(Request $request)
{
$um = $this->get('user_manager');
$modified = False;
if($request->getMethod() == 'POST'){ // submit, so have to modify data
$user = $um->getUserById($request,False);
$form = $this->createForm(new UserType(), $user);
$form->bindRequest($request);
$um->flushAll();
$modified = True;
}
$users = $um->showAllUser();
return $this->render('SestanteUserBundle:Default:index.html.twig',array('users'=>$users));
}
Where $um is a custom service where all code that you can't see from #1 code piece to #2 code piece is stored.
So, here are my questions:
Did I, finally, get the essence of symfony2 and {M}VC in general?
Is the refactor a good one? If not, what would be a better way?
Post Scriptum: I know that I can use the FOSUserBundle for User store and authentication, but this is a basic example for teach myself how to work with Symfony.
Moreover, my service was injected with ORM.Doctrine.* in order to work (just a note for who read this question with my same confusion)
There are two main approaches regarding on where to put the business logic: the SOA architecture and the domain-driven architecture. If your business objects (entities) are anemic, I mean, if they don’t have business logic, just getters and setters, then you will prefer SOA. However, if you build the business logic inside your business objects, then you will prefer the other. Adam Bien discusses these approaches:
Domain-driven design with Java EE 6: http://www.javaworld.com/javaworld/jw-05-2009/jw-05-domain-driven-design.html
Lean service architectures with Java EE 6: http://www.javaworld.com/javaworld/jw-04-2009/jw-04-lean-soa-with-javaee6.html
It’s Java, but you can get the idea.
Is the refactor a good one? If not, what would be a better way?
One of the best framework practices is using param converters to directly invoke an entity from user request.
Example from Symfony documentation:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
/**
* #Route("/blog/{id}")
* #ParamConverter("post", class="SensioBlogBundle:Post")
*/
public function showAction(Post $post)
{
}
More on param converters:
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
Robert C. Martin (the clean code guy) says in his new book clean architecture, that you should put your business logic independently from your framerwork, because the framework will change with time.
So you can put your business logic in a seperate folder like App/Core or App/Manager and avoid inheretence from symfony classes here:
<?php
namespace App\Core;
class UserManager extends BaseManager implements ManagerInterface
{
}
I realize this is an old question, but since I had a similar problem I wanted to share my experience, hoping that it might be of help for somebody.
My suggestion would be to introduce a command bus and start using the command pattern. The workflow is pretty much like this:
Controller receives request and translates it to a command (a form might be used to do that, and you might need some DTO to move data cleanly from one layer to the other)
Controller sends that command to the command bus
The command bus looks up a handler and handles the command
The controller can then generate the response based on what it needs.
Some code based on your example:
public function indexAction(Request $request)
{
$command = new CreateUser();
$form = $this->createForm(new CreateUserFormType(), $command);
$form->submit($request);
if ($form->isValid()) {
$this->get('command_bus')->handle();
}
return $this->render(
'SestanteUserBundle:Default:index.html.twig',
['users' => $this->get('user_manager')->showAllUser()]
);
}
Then your command handler (which is really part of the service layer) would be responsible of creating the user. This has several advantages:
Your controllers are much less likely to become bloated, because they have little to no logic
Your business logic is separated from the application (HTTP) logic
Your code becomes more testable
You can reuse the same command handler but with data coming from a different port (e.g. CLI)
There are also a couple downsides:
the number of classes you need in order to apply this pattern is higher and it usually scales linearly with the number of features your application exposes
there are more moving pieces and it's a bit harder to reason about, so the learning curve for a team might be a little steeper.
A couple command buses worth noting:
https://github.com/thephpleague/tactician
https://github.com/SimpleBus/MessageBus
currently i am doing a project in zend the way i am doing is working perfectly but i am sure its not the way i am suppose to do i mean i am not following MVC and i want to apply MVC in my zend app.
i am pasting code of one simple module which will describe what i am doing .kindly correct me where i am making faults.
my controller
class ContactsController extends Zend_Controller_Action{
public function contactsAction(){
if(!Zend_Auth::getInstance()->hasIdentity()){
$this->_redirect('login/login');
}
else{
$request = $this->getRequest();
$user = new Zend_Session_Namespace('user');
$phone_service_id = $user->p_id;
$instance = new Contacts();
$select = $instance->Get_Contacts($p_id);
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
$paginator = new Zend_Paginator($adapter);
.
.
//more code
}
plz note this 2 line in my controller
$instance = new Contacts();
$select = $instance->Get_Contacts($pid);
this is my contacts class in models
class Contacts extends Zend_Db_Table{
function Get_Contacts($p_id){
$DB = Zend_Db_Table_Abstract::getDefaultAdapter();
$select = $DB->select()
->from('contact', array('contact_id','contact_first_name','contact_mobile_no','contact_home_no','contact_email','contact_office_no'))
->where('pid = ?', $p_id)
->order('date_created DESC');
return $select;
}
}
after this i simple assign my result to my view.
note please
as its working but there is not private data members in my class,my class is not a blue print.there are no SETTERS AND GETTERS .how can i make my code that best suits MVC and OOP??
The most simple answer: you are already almost MVC. You use a Zend_Controller_Action to grab some data and pass this on to a view layer where you render the html. The only missing part is your model, which is mixed up between the controller and your data gateway (where you implemented a table data gateway pattern, that Zend_Db_Table thing).
I gave a pretty thorough explanation in an answer to another question how I'd properly set up the relations between Controller and Model. I also combined this with a Form, to handle data input, filtering and validation. Then to bundle some common functions, I introduced a Service layer between the Model and Controller.
With the controller, you perform some actions (list all my contacts, create a new contact, modify a contact) and the model is purely containing the data (id, name, phone, address). The service helps to group some functions (findContactByName, findContactById, updateContactWithForm).
If you know how to split Controller, Mode, Form and Service, your controller can become something like this:
class ContactsController extends Zend_Controller_Action
{
public function indexAction ()
{
if (!$this->hasIdentity()) {
$this->_redirect('login/login');
}
$service = new Application_Service_Contacts;
$contacts = $service->getContacts();
$paginator = $service->getPaginator($contacts);
$this->view->paginator = $paginator;
}
protected function hasIdentity ()
{
return Zend_Auth::getInstance->hasIdentity();
}
}
It is your personal taste what you want to do in your controller: I'd say you put as less as possible in your controllers, but you need to keep the control. So: a call to get data happens in the controller, retrieving this data happens somewhere else. Also: a call to convert a dataset into something else happens in the controller, the conversion happens somewhere else.
This way you can change the outcome in controllers extremely fast if you provided enough methods to your service classes to fetch the data. (Note I took the Zend_Auth to another function: if you have other actions, you can use this same function. Also, if you want to change something in your authentication, you have one place where this is located instead of every action in the controller)
keep one thing in mind when u learn new technology so first read thier own documentation. No one can explain better than them. Its hard to understand firstly but when you study it you will usedto and than u will love it like me Zend Offical Site
Where to clean up/ validate/ verify the user input data? In the controller or the model?
In controller.
Look at it this way: Your form will post to a controller function with the form data in $_POST variable. You validate the data in that function of the controller and do some DB inserts or updates. Then you show the success message as a view or in case of error a fail message.
See the form validation tutorial in CodeIgniter's user guide here.
I'd go with the model so your validation can be reused. Models should handle the data and the controller should direct it to where it needs to go.
The code that make the validation must be in the model, but the call to this code must be in the controller.
Something like this:
class MyAwesomeUserModel {
public function isValid()
{
//some code to validate the user
}
}
class MyUserController {
public function myUserAction()
{
//some code to insert the input of the user in the model
if($userModel->isValid()){
//do nice things with the data and send some message/data to the view
} else {
//send 'nice' error messages to the view
}
}
}
This is just the way I use, may not be the best way, but it's the best fit in my application. And that's what matters, you should look for what best suits your application.
I'm using the MVC PHP framework Codeigniter and I have a straight forward question about where to call redirect() from: Controller or Model?
Scenario:
A user navigates to www.example.com/item/555. In my Model I search the item database for an item with the ID of 555. If I find the item, I'll return the result to my controller. However, if an item is not found, I want to redirect the user somewhere. Should this call to redirect() come from inside the model or the controller? Why?
No your model should return false and you should check in your controller like so:
class SampleModel extends Model
{
//Construct
public function FetchItem($id)
{
$result = $this->db->select("*")->from("table")->where("item_id",$id)->get();
if($result->num_rows() == 0)
{
return false;
}
//return result
}
}
and within your controller do:
function item($id)
{
$Item = $this->SampleModel->FetchItem($id);
if(!$Item)
{
redirect("class/error/no_item");
}
}
Models are for data only either return a standard result such as an key/value object or a boolean.
all logic should be handled / controlled by the Controller.
Models are not page specific, and are used globally throughout the whole application, so if another class / method uses the model, it might get redirect to the incorrect location as its a different part of your site.
It seems like the controller would be the best place to invoke your redirect because the controller typically delegates calls to the model, view, or in your case, another controller.
However, you should use whatever makes the most sense for your application and for what will be easier to maintain in the future, but also consider that rules do exist for a reason.
In short, if a coworker were to try to fix a bug in your code, what would the "reasonable person" standard say? Where would most of them be most likely to look for your redirect?
Plus, you said you're returning the result to your controller already... perhaps that's where you should make your redirect...