2

In my current implementation of the MVC design pattern (demonstrated using PHP and CodeIgniter):

Let's say I have a "page" located at "www.mysite.com/blue/page" that is ultimately generated by the following (greatly simplified) files:

/libraries
    session_lib.php
/controllers
    /red
    /white
    /blue
        page.php
/models
    /red
    /white
    /blue
        funky_class.php
        page_model.php
/views
    /red
    /white
    /blue
        page.php

And here's an easy to understand controller:

// FILE: /controllers/blue/page.php

// Get some paramaters from URL
$params = $this->input->get();

// Use a library to do some stuff with these params with a session
$this->load->library('session_lib');
$this->session_lib->store_in_session($params);

// Use a very page specific class to do some funky stuff with the params
$this->load->model('blue/funky_class');
$funkified_params = $this->funky_class->funkify($params);

// Pass params to a model
$this->load->model('blue/page_model');
$data['output_from_db'] = $this->page_model->get_some_output_from_db($funkified_params);

// Send to view
$this->load->view('blue/page', $data);

And now the question...

What is the best procedure for these "funky" little page specific classes that don't interact with the database? In this example I store the little class with the models, and in some cases might just add additional methods inside the model class to do the funky stuff. Is this good practice? Or should the library and funky class both go inside the model so the controller is even skinnier (however the model might be used in other places without the need for sessions and funkiness)?

tereško
  • 58,060
  • 25
  • 98
  • 150
prograhammer
  • 20,132
  • 13
  • 91
  • 118
  • What is the "funky stuff" doing? Is it mathematical transformations? Computing layouts? Associating past responses with potential future responses? – wallyk Jul 11 '13 at 20:15
  • Well, an example could be that "funky" is a class for creating a set of funky form inputs based on passed paramaters that are used to filter a datagrid (model). – prograhammer Jul 11 '13 at 20:17
  • Another line of concern: is sometimes a controller is calling so many libraries and models and passing stuff in between each that the controller itself seems like a model, handling a big amount of business logic. – prograhammer Jul 11 '13 at 20:20
  • 1
    Just a note, CodeIgniter does not promote MVC (it says it is, but it isn't). In MVC, you only have one *Model **layer***, which is actually the "space" of all of your heavy logic. A model is not a class or an object, and there aren't "many" models. – Madara's Ghost Jul 11 '13 at 20:34
  • Yeah, maybe I know what you mean, in that I've matured more to thinking that models should be more like "contracts" to interactions with the database. We can build and collect all these contracts for "services" to use when servicing the controllers. But there is no place for these "services" in any PHP framework that I know of. So maybe I need to create a folder called "services" that handles all the little classes and group them similar to the controller/routes/url structure, and the models are grouped by related queries/data. This would lighten the pressure on interaction tests. – prograhammer Jul 11 '13 at 21:22
  • 3
    @DavidGraham: See [How should a model be structured in MVC?](http://stackoverflow.com/q/5863870). Also, *Frameworks* do not implement MVC. *Your code does*. The framework can help you by providing the tools for you, but you decide how to code yourself. – Madara's Ghost Jul 12 '13 at 06:57

1 Answers1

2

I would use a helper.

  • When a helper is loaded, that function will be available in the global scope so you can call it anywhere.
  • They're great for small, stand-alone functions that do only one thing that is not necessarily related to code in a model or library
  • Helpers especially excel for me when converting things between one format or another (slugify, convert_timezone, change_query_string) or doing little tasks that you don't want to think about (force_ssl, is_image, uri_string)

funkify() seems like an appropriate helper function that may prevent a lot of repeated code.

Here's the codeigniter documentation page on them: http://ellislab.com/codeigniter/user-guide/general/helpers.html

If you're in a situation where the helper function is so specific it will be only used in one place, you can still use a helper. Name the helper after your controller, page_helper.php for example.

page_helper.php

function funkify($params) {
    // do funky stuff
    return $funky_params;
}

then in your controller:

class Page extends CI_Controller {
    public function __construct() {
        parent::__construct();
        $this->load->helper('page');
    }

    public function page() {
        // do stuff
        $funky_params = funkify($params);
        // do more stuff
        $this->load->view('blue/page', $data);
    }

I have no excuse for it, but sometimes if I am in a situation where I need a razor specific function that will only be used on one location (say, a controller) ever, I will put it right in the controller's file. You can paste a function outside of the class definition and it will act like a helper and be available globally (as long as that controller is loaded). You can also define functions inside of a view. Yucky, but possible. I don't like to do it often because it's unusual and not expected (by myself or other developers)

Lea
  • 602
  • 9
  • 20
  • Yeah, what I think I ended up deciding is just to add them as additional methods to the page specific model (I find I have models for each page almost, but I also have some "core" models that my page specific models may use). But if I change my mind later and think they are more reusable, then I convert them to helpers. Let me give you a vote up, it's helpful to know I'm not too far off from other's approach to MVC. – prograhammer Jul 23 '13 at 20:31
  • I think the real drawback, is frameworks do great at organizing things, but fall short at giving good real world examples of how to use that organization. All kinds of things happen that can be gray areas like: models that have heavy HTML outputting that tightly goes with the data being queried and couldn't possibly be put into a view for-loop, or lots of page specific helpers that don't need to be put in a generalized place, but should go with the model(s) used for building the page, or how best to keep those controllers skinny or what about all that javascript/jquery/ajax. – prograhammer Jul 23 '13 at 20:43
  • Darunada...if you expand your nice answer a bit to include what you do for very page specific "helper" situations that wouldn't be repeated much else where, I'll go ahead and accept it as the answer. – prograhammer Jul 23 '13 at 20:46
  • 1
    I agree with you, it's hard to find examples for a style that you like, and there are so many 'acceptable' ways to do things that finding the 'right' one is impossible. If you do what makes sense to you, you can't go wrong. I'll go ahead and add some to my answer... – Lea Jul 24 '13 at 00:01