Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a controller catch an exception thrown from a model?

Well, it is technically possible, but would this break the MVC architecture?

I'm not sure whether this type of communication is recommended between both controller and model. I will describe it using a simple example and two ways of doing it:

OPTION 1 (model throws exception and controller catches it):

class Controller {
  private $model;

  public function save($data) {
     try {
         $this->model->save($data); 
     } catch (Exception $e) {  
         // handle exception
     }
  }
}

class Model {
  public function save($data) {
     // Call to internal function to save data in BD
     if (! $this->_save($data)) throw new Exception('Error saving data');
  }
}

OPTION 2 (the controller handles the exception completely):

class Controller {
  private $model;

  public function save($data) {
     try {
         if (! $this->model->save($data)) throw new Exception('Error saving data'); 
     } catch (Exception $e) { 
         // handle exception
     }
  }
}

class Model {
  public function save($data) {
     // Call to internal function to save data in BD
     if (! $this->_save($data)) return false;
  }
}

**

EDIT after some responses:

**

These are other ways to solve it based on your suggestions. I hope not to get things too complicated.

OPTION 3 (model handles the exception completely, as Ray said. KingCrunch also suggested to better do it in the model)

class Controller {
  private $model;

  public function save($data) {

     if (! $this->model->save($data)) {
         // possible action: redirect to the form with an error message
     }

  }
}

class Model {
  public function save($data) {
     try {
         if (! $this->_save($data)) throw new Exception('Error saving data'); 
     } catch (Exception $e) { 
         // handle exception
         return false;
     }
     return true; 
  }
}

OPTION 4 (controller gets a custom child exception thrown by the model, as shiplu.mokadd.im said.)

class Controller {
  private $model;

  public function save($data) {
     try {
         $this->model->save($data); 
     } catch (Exception $e) {  
         if ($e instanceof ValidationException) {
            // handle validation error
         }
         elseif ($e instanceof DBStorageException) {
            // handle DB error
         }
     }
  }
}

class Model {
  public function save($data) {
     if (! $this->_validate($data)) {
        throw new ValidationException ('Validation error');
     }
     if (! $this->_save($data)) {
        throw new DBStorageException ('Storage error');
     }
  }
}
like image 465
Luis Martin Avatar asked Jan 08 '13 22:01

Luis Martin


People also ask

CAN controller throw exception?

Controller Based - We can define exception handler methods in our controller classes. All we need is to annotate these methods with @ExceptionHandler annotation. This annotation takes Exception class as argument.

Should error handling be in the controller?

The correct answer is "Both", but mostly in the Model. The appropriate thing for your controller to do is simply catch some exception that the model throws, and handle outputting a nice "whups" message. Depending on how you're structuring your models, it might be appropriate for the controller to do some logging.

Can exceptions be caught and thrown?

A thrown object may match several catch block but only the first catch block that matches the object will be executed. A catch-block will catch a thrown exception if and only if: the thrown exception object is the same as the exception object specified by the catch-block.

What happens when exception is thrown by method?

When a method declares that it throws an exception, it is not required to handle the exception. The caller of a method that throws exceptions is required to handle the exceptions (or throw them to its caller and so on) so that the flow of the program can be maintained.


2 Answers

Model can throw Exception and Controller or View should catch it. Otherwise you never know if everything is working properly down there. So use the first option. But make sure you are throwing properly abstracted Exception that is meaningful to the controller and View.

To illustrate the above bold line see these two throw statements which are used inside a model.

 throw new Exception('SQL Error: '.$mysqli->error()); // dont use it
 throw new DuplicateFieldException('Duplicate username'); // use this

The second example does not show internal error. Rather it hides it. Controller should never know whats happening inside.

In your code your tied a single model to a single controller. Controller does not represent a single model. It uses model. And it can use any number of model. So dont tie up a single model with a controller with variable like private $model.

like image 148
Shiplu Mokaddim Avatar answered Sep 21 '22 20:09

Shiplu Mokaddim


Definitely first option. Some words:

  • It's the job of a Controller to ... well, control. This means, that it should take care, that at least an useful error message appears. Other parts of the application may do it before, when they are able to handle the exceptional case. That includes the model itself: If it is able to handle it, it should do it.

  • save() means "save". Don't misuse the return value for status information. When the method is not able to save() it is an exception and when a method doesn't have to give you something, then it shouldn't give you something.

like image 30
KingCrunch Avatar answered Sep 20 '22 20:09

KingCrunch