Welcome Guest, Not a member yet? Register   Sign In
Yet another "what goes where" question
#1

(This post was last modified: 08-11-2015, 08:54 PM by kwonghow.)

Suppose I am starting a simple CodeIgniter project that ranks photographers in a photography competition.

A database table contains various Contestants, each with his/her own attributes such as "time taken to submit finished work", "years of experience", "money spent in executing the shoot", etc. (I'm making these criteria up as I go along, lol)

Our CodeIgniter application will apply a scoring function across all Contestants (e.g. people who submit their works within 5 hours get 10 points, but people who take 24 hours get 0 points) and calculate their final scores. Next, it reverse-sorts the Contestants to produce a list of Contestants from the highest-scoring to the lowest-scoring.

How would such an application be designed?

Here's my suggestion:

Model: Contestant with corresponding attributes (mapped to the database table)
Controller: Calls upon the Model to retrieve data from the database table, aggregates these (perhaps into an array) then applies the scoring function logic and sorting logic. Send the finalised output to the View.
View: Output of photographers and their details

However, I have read that Models should contain all the business logic, and Controllers simply act as traffic controllers to direct information between Models and Views.

In this case, the scoring function would be considered a business logic, hence this design does not conform to the MVC pattern. Should everything be refactored into the Model?
Reply
#2

Different people will choose to put things in different places, but as a general rule the aggregate/score/sort logic should be in the model. The most common example for why this would be a good idea would be what happens if you need to get the same information from a second controller? Then you have to duplicate the logic and maintain two instances of it, or either move it into the model or create another model or library to hold it.

Your example brings up a better reason for moving this logic into the model: what happens if you decide to move that logic into the database? This would require some more overhead for certain transactions, but would usually be much faster when reading and sorting the aggregate data. If that logic is in the controller, you have to change the controller, the model, and the database, and you might be making some very significant changes to the way the model and controller work at that point. If the logic was in the model, the model could be updated to let the database handle it (and maybe manage some of that overhead on updates) and the controller wouldn't have to be changed at all.

The basic idea behind most design patterns is limiting the impact of change. MVC is no different in this sense, but, like many design patterns, it was created for a completely different environment, so we don't always use it the way it was originally designed to work. If you keep in mind the basic idea of limiting the impact of change and think about the ways in which you might decide (under relatively normal circumstances) to change your application, you can usually start to see where you might have diverged from the underlying idea of the pattern.
Reply
#3

Thanks for your reply, mwhitney. Smile

I have a noob question after reading your reply. While I can see how the scoring logic can be refactored into the Model, I'm not too sure how to do that for the aggregating/sorting behaviour.

Suppose my Model is implemented as such:

PHP Code:
class ContestantModel extends CI_Model {
 
 private $first_name;
 
 private $last_name;
 
 private $time_taken_hours;
 
 private $experience_years;
 
 private $money_spent;
 
 private $score;

 
 /* Setters and getters */
 
 .
 
 .
 
 .

 
 public function findContestantBy($field$value) {
 
   $query $this->db->get_where('contestants', array($field => $value));
 
   // Populate table row data into object properties
 
   .
 
   .
 
   .
 
 }

 
 public function calculateScore() {
 
   // Logic to calculate score
 
   .
 
   .
 
   .
 
   $this->score $result;
 
 }


Each ContestantModel object would correspond to one Contestant and is unaware of other ContestantModel objects. How would I be able to implement the aggregating/sorting logic into the Model itself?

This was the original reason why I had thought to place the logic in the Controller: since it was a "layer" above the Model, it could have an overview of all the ContestantModels objects and hence be able to loop through these objects.
Reply
#4

In that case, I would make a second model to represent the collection of models and return ContestantModels from the new model, using $query->result('ContestantModel') (or $query->custom_result_object('ContestantModel'), which is the same thing, minus the check in result() to determine whether you want to call result_array(), result_object(), or custom_result_object()). You may have to modify the ContestantModel slightly to allow the DB_result method to populate the object with the data, but, in the long run, this will probably be the easiest way to handle this.

The documentation for custom result objects has been improved in GitHub by Lonnie and Narf:
https://github.com/bcit-ci/CodeIgniter/b...lt-objects
Reply
#5

I have enough information to proceed with the refactoring of my code now. Thanks for the very detailed reply, mwhitney. You've been a great help!
Reply




Theme © iAndrew 2016 - Forum software by © MyBB