• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Turning MCV into MVCL: the solution to a mega project?

I'm looking at developing a very large project on CI, and in a nutshell I'm considering doing most of the classic 'controller' work within libraries, and using the controllers to access those libraries.

I'm looking for reasons why this is a bad idea, and how I might achieve the same effect in controllers.

Application Outline:

The goal accross the entire app is to make new versions, updates and tweaks fast, simple and able to be selectively applied.

The single CI app will serve requests made to any number of TLDs. Effectively, each country in Europe will have it's own tld - .fr, .co.uk, .es, .it etc - and visitors from each country will be directed to their version. This bit is done and worked out quite easily.

There will be 3 levels of user;

- me, able to access and edit everything
- country admins, able to edit the config and language for their country
- users, able to make use of the feature set on the site.

Here's the big thing. Each (and every) section needs to be available to different countries in different versions at the same time. This is because the countries have to do translation / localisation for each version, and coordinate marketing efforts.

So - while Ireland might be using public_site version 1.0, France might be using 2.0. Country admins will be able to change their version usage on-the-fly through their CPs.

Each section will include libraries, models and views and will not share these with previous versions (at least, not in a physical file sense - I may copy / paste if there are no changes).

Using controllers is out, because you can't have "controllers/public_site/1.0/public_site.php" and in any case, that would make URL routing a potential nightmare.

The solution that I have worked out is to use the same controller for each section, regardless of version. The controllers only function is to call the library that holds the logic for that section and that version. Version details are held in config files that can be updated by country admins. The controller determines which version to load, and calls a 'handler' function within the library with does everything else.

The library uses the $ci super-object to access all of CI's functions and vars, and reads both the HTTP_HOST and QUERY_STRING to understand what the user wants. Views, models etc are called directly from the helper using $ci.

This allows me to leave the controller (and therefore the URL) the same, regardless of the version a specific country is using. Simply adding a new file under "libraries/public_site/2.0/" will let me add a new version of a section, and updating the config file will allow a specific country to use the new version, while other countries continue with the old one.

Views and models will also be versioned in this way, but they, like libraries, do not suffer from the restrictions on subfolders that controllers do. Substantial bits will be held in databases - such as localised / translated language for the views. New versions will not ba available until the translation has been done by each country - some countries will need more than one language (e.g. Austria - French and German), and all counrties will have access to the English master version.

We are looking at around 30 sections immediatly, and new ones added regulaly.

The site will replace an existing one built on a _very_ different basis that currently suffers from major issues with developer involvement in updates and changes, which is one of the key goals of the rebuild. In terms of usage, the current sites (which will all become one) currently enjoy over 50k views / day, and this is expected to reach 250k by the end of the year (as new countries are added).

Does this make sense? I know it will work, but are there any issues you can see down the line?


The main problem is that you're abusing the system, but I can't deny it would work. I actually have a library myself that I can plug&play;into a controller-function and that will allow a user to upload a picture, lets the user crop it and ultimately resizes it. All of that from a single function that only loads & configures the library. But that's just one function that gets multiple uses.
But what you seem to want to do is to effectively cut out the Controllers and just use them to redirect to specific libraries - in fact to do the routing. While it would work fine, you'll lose the real MVC qualities.

I would look a bit more around if I were you, to find a way to do the same thing but keep using controllers and allow for neat seperation of libraries from controllers - instead of mixing them up.
Why not HMVC? Have you taken a look at Modular Seperation or Matchbox?

I did have a quick look at modules and didn't think they would do the job, but actually they may well solve the remaining issue (with the above method) of having a very messy folder tree with related files all other the place.

I will need to work a way around the module_name/controller_name issue - www.foo.co.uk/public_site_1_0/public_site won't really fly, and I have some questions about routing in general, but that should be do-able.

The biggest fear I have about the original method is that I can claim some semblance of MVC by extending the C into Libraries - but only if I then do not use libraries for anything else, which I may end up doing. Really don't want to mix and match..

Thanks for your thoughts Jelmer!

You can really do whatever works best for you. There are no rules per say, just best practices. That being said...

You should really let the controllers do what they were meant to do. That is separate your models from your views (or your business logic from your layout.) Your business logic (or model) should know nothing about your layout, and your layout (views) should know nothing about your business logic.

Quote:Controller<---Get data from Model (does not have to be database data...remember...business logic)
Controller--&gt;Send data from model to the view.
That's it! You can have very "thin" controllers. This is advisable under most circumstances even (makes your site that much more modular and that's a good thing.)

As for the versioning, it seems it would be VERY trivial to extend your Loader class to look at configuration variables (could be as simple as an associative array that maps URL segments to version folders.)

This way, the versioning is transparent to your Controllers (as it should be.) Just make sure that your views are the same (if not possible than you can further extend the Loader class to get view files from a different folder.)

For example, here is an extended Loader class that I wrote to get views from alternate folders.

class MY_Loader extends CI_Loader
     * Load View
     * @access    public
     * @param    string
     * @param    array
     * @param    bool
     * @return    void
    function view($view, $vars = array(), $return = FALSE)
            return $this->_ci_load(array('_ci_view' => $this->_get_prefix() . $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));

        function _get_prefix()
            // config should load before Loader since Loader is called form the controller.
            $CI =& get_instance();
            if ( $CI->config->item('mobile_base_url') !== FALSE && $CI->config->_get_host_header() == $CI->config->item('mobile_base_url') ) {
                return ( $CI->config->item('mobile_view_folder') !== FALSE ) ? $CI->config->slash_item('mobile_view_folder') : '';
            } else {
                return ( $CI->config->item('base_view_folder') !== FALSE ) ? $CI->config->slash_item('base_view_folder') : '';

EDIT: I suppose I should show my extended Config lib too:

class MY_Config extends CI_Config {

        // --------------------------------------------------------------------

     * Site URL
     * @access    public
     * @param    string    the URI string
     * @return    string
    function site_url($uri = '')
                   if (is_array($uri))
            $uri = implode('/', $uri);

        if ($uri == '')
            return $this->_get_host_header().$this->item('index_page');
            $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix');
            return $this->_get_host_header().$this->slash_item('index_page').preg_replace("|^/*(.+?)/*$|", "\\1", $uri).$suffix;

        * return URL for mobile base url if defined and matches hot header. otherwise, get base url.
        * @access       public
        * @return       string

        function _get_host_header()
            if ( $this->item('mobile_base_url') !== FALSE && strpos($this->item('mobile_base_url'), 'http://' . $_SERVER['HTTP_HOST']) !== FALSE ) {
                return $this->slash_item('mobile_base_url');
            } else {
                return $this->slash_item('base_url');


I'll definatly look into extending the loader and config classes bretticus - could be the way to go.

I think the biggest issue is that the section version mst be invisible to the user - version numbers will not appear in the url so the url for Irelands public_site v1.0 would be foo.ie/public_site and Frances version 2.0 would be foo.fr/public_site. The versions exist only for admins to manage what functionality the end user sees.

Modules will need hacking to achieve this; extending the load looks like it may do the job based purely on the tld and version lookup from a config file.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  

  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.