0

My Codeigniter project has a long list of identical categories, each with many identical methods.

To make it dynamic and cleaner, I have used _remap functions to load the identical methods within the controller. Now I am trying to replicate the controllers

e.g. My controllers Antelope.php Bat.php Cuckoo.php Dog.php Elephant.php... Zebra.php all have this format below (I used _remap to condense all the similar methods into one).

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Antelope extends CI_Controller {

    function __construct() {
        parent::__construct();
    }

    private function _remap($method, $params=array()){
       $this->animal = ucwords($this->router->fetch_class());
       $allowed_methods = array("Tame", "Buy", "Sell", "Gift");
       if (in_array($method, $allowed_methods)):
           // Model zoo has been autoloaded      
           data["foobar"] = $this->zoo->get_data($this->animal, $method);
           // Stuff goes here
       else:
          $this->index();
       endif;
    }

    public function index(){
       // Stuff goes here
    }
}

/** End of file Antelope.php **/

The remapping works fine for Antelope and all its remapped methods, but is there a way for me to apply this same method to all the other files so I can just have a single Animal.php Controller file instead?

I guess I may use routes.php, but the list of Controllers is too long; I'd have hundreds of lines in the routes file if I explicitly list each "animal" routing.

Any way around this?

EDIT: The "animal types" are listed in a database, and will keep increasing over time. I don't want to keep revisiting the project to create new controllers or add new classes for the new elements in the database! This is why I want to use a dynamic routing method. Also, the project is a site redesign, so the URLs like http://www.website.com/antelope/buy/3 need to remain the same.

Cogicero
  • 1,514
  • 2
  • 17
  • 36
  • Having a controller for each animal type seems a bit overkill. Are you sure you can't do it with a single controllers (seems to me you can). – Styxxy Sep 29 '12 at 12:15
  • Actually, no I can't. This is an oversimplified description of what I am trying to achieve. Thanks! – Cogicero Sep 29 '12 at 13:23
  • Oops. I meant, yes I'll like to use a single controller. But no, I don't think the problem is a trivial one. – Cogicero Sep 29 '12 at 13:40

3 Answers3

4

The trick is to realize that the animal type is variable and you're trying to map it to static files. Don't do this. Just pass the animal as the first argument to the index function. That's what arguments are for: variables.

class Animal extends CI_Controller{
    function __construct(){
        parent::__construct();
    }

    function index($animal){
        echo "I'm the {$animal}!";
    }
}

And set up the single route:

$route['animal/(:any)'] = "animal/index/$1";

Now, if you head to http://localhost/yourapp/animal/antelope

CodeIgniter will echo "I'm the antelope!"

Edit after your comment:

CodeIgniter goes from top to bottom in your routes file and breaks when it finds a valid one. You can place this at the bottom of your config/routes.php file:

$route['(:any)/buy/(:id)'] = "animal/$1/buy/$2";
$route[':any'] = "animal/index/$1";
//etc

You'll need to re-route all other controllers above this.

Jordan Arsenault
  • 7,100
  • 8
  • 53
  • 96
  • Thanks for your answer. But as I said, the project is a site redesign, so the URLs like http://www.website.com/antelope/buy/3 need to remain the same and NOT change to http://www.website.com/animal/antelope/buy/3 (this is a constraint from my superior). – Cogicero Sep 30 '12 at 08:39
  • Thanks a lot! I'm going to accept this answer because it gets me closest to what I want. However, it doesn't really solve my problem. As I said in the comment to Re0sless, '2) there are other "non-animal-related" controllers on the site.' Your method means I need to list all non-animal related controllers in the routes file before the above. Sigh. Just concerned about sustainability and low-maintenance cos I'm handing it over. Thanks again. – Cogicero Sep 30 '12 at 19:56
  • P.S. I used "animals" just to explain the problem. There are many other categories on the site, and not just "animals". The other categories have a different structure but the /buy/id URL is similar for them too. – Cogicero Sep 30 '12 at 19:57
1

A couple of options you could try are:

  1. Have a Animals.php base class and inherit all other categories from that like so

Animal.php

class Animal extends CI_Controller {
    //Your _remap() and other methods
}

Antelope.php Bat.php Cuckoo.php Dog.php Elephant.php... Zebra.php

require_once 'animal.php';

class Antelope extends Animal {
    //Antelope inherits its methods from Animal, so this is blank 
} 

This method would require you to have 100s of almost blank controller files (one per animal/ category) so is and not very dynamic, but would allow you to implement a __init() method in the Animal base class and override it in the sub-classes, allowing you to set-up any deviations in the categories (i.e. number of legs etc)


  1. Use one route for all animals

routes.php

//default index route http://www.sample.com/animal/type
$route['animal/(:any)']  = 'animal/reroute/$1/index';

//method route http://www.sample.com/animal/type/method
$route['animal/(:any)/(:any)']  = 'animal/reroute/$1/$2';

animal.php

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Animal extends CI_Controller {

    function __construct() {
        parent::__construct();
    }


    public function index(){
       // Stuff goes here
    }

    public function reroute($animal, $method) {
       //Check the $animal is valid
       //Check the $method is valid
       //Do stuff   
    }


}

/** End of file animal.php **/

This is a little more dynamic, as you can then load a list of valid animals from a database, but the URLs will not be as clean http://www.sample.com/bat/sell vs http://www.sample.com/animal/bat/sell

Re0sless
  • 10,678
  • 6
  • 51
  • 66
  • Thank you, Re0sless. The first option came to mind, but I discarded it because indeed it will require many almost-empty controller files. I like the second solution you gave, especially since I can load the list of animals from a database, but two issues are that: (1) the URL needs to be clean as in http://www.site.com/bat/sell because this is a site redesign, too many broken links will show up. (2) there are other "non-animal-related" controllers on the site. P.S. Do you think I can use the solution 2 above and then use Apache htaccess to clean up the URL? And will this impact performance? – Cogicero Sep 29 '12 at 13:30
  • 1
    You could use .htaccess to re-route to the animal controller, but this would just be shifting the problem, as htaccess would have to have either a list of animals to look for, or a list of controls not to re-route. I don't know how much it would effect performance, but anything you do (including codeigniters routing) will have some negative impact as its extra work the server will need to preform. – Re0sless Sep 29 '12 at 14:41
1

Just create a class to inherit from

class Animal extends CI_Controller {
   function __construct() {
        parent::__construct();
    }

    public function _remap($method, $params=array()){
       $this->animal = ucwords($this->router->fetch_class());
       $allowed_methods = array("Tame", "Buy", "Sell", "Gift");
       if (in_array($method, $allowed_methods)):
           // Model zoo has been autoloaded      
           data["foobar"] = $this->zoo->get_data($this->animal, $method);
           // Stuff goes here
       else:
          $this->index();
       endif;
    }
}

class Antelope extends Animal {
    public function index(){
       // Stuff goes here
    }
}
Laurence
  • 58,936
  • 21
  • 171
  • 212
  • Thanks for your answer, but the real problem is that the "animal types" are loaded from a database, and will keep increasing over time. I don't want to keep revisiting the project to add new classes for the new elements in the database! – Cogicero Sep 29 '12 at 13:25
  • ...but you have a file for each of the animals? you said so yourself?? i.e. bat.php, antelope.php – Laurence Sep 29 '12 at 13:39
  • Yes, I was manually copying and pasting code from the Antelope.php so as to meet my deadline, using names from the database. Then I realized that this is not a sustainable way of doing it. As the project grows, I will need to keep revisiting this to create new controllers or classes! – Cogicero Sep 29 '12 at 13:41