User Group-specific Controllers in CodeIgniter
I’ve been building out an application that has 2 types of users, corporate and operations. Each user type has access to a lot of the same methods, but operations has access to a little more than corporate. I’ve been struggling with how to break up the code for these two types of users since a lot of it is shared. At first, I thought I had a couple options:
1. Separate the logic into different directories
This would mean that I have completely separate controllers and I would be duplicating methods that are shared for each type of user. I started building this out as an HMVC application with a module for operations that provided the extra methods available to that type of user. This gave me regular URLs like products/edit/48
and operations users would get operations/products/edit/48
.
Issues:
I found myself duplicating a lot of code for methods that were shared for each user type and I didn’t really want 2 URLs to access the same method.
2. Create user-specific methods in the same controller
I thought about prefixing methods with “operations_” or “corporate_” so I would have methods like “operations_edit”. Doing things this way I would have had to:
- See what type of user is trying to access the method
- See if a method with a prefix of their user type exists
- Route them accordingly
Issues:
I didn’t like this approach because my controllers would be huge and I’d have to manage 2 of the same method for each type of user, even though I’d try to share private methods with each user type to limit code duplication.
My Current Solution
I thought about it a little more and I decided the way I would like it to work is if I could have a single controller that both user types share, and then be able to provide a controller with user-specific methods if there is anything that I want to override or add only for one user type. I ended up with a file structure like this:
- modules/products/controllers/products.php – The default
- modules/products/controllers/operations.php – Operations only
- modules/products/controllers/corporate.php – Corporate only
Then I use CodeIgniter’s _remap()
method to route the user accordingly. This method will:
- Check if there is a controller that has methods specific to that user type (corporate.php or operations.php)
- Check to see if the requested method exists in that controller
- If the method exists, execute it, otherwise try to execute it from the default controller
public function _remap($method, $arguments)
{
$controller = strtolower($this->router->class);
if ($controller === $this->uri->segment(1))
{
if ($this->acl->is_admin())
{
$user_type = 'operations';
}
else
{
$user_type = 'corporate';
}
if ($module = $this->load->module($controller .'/'. $user_type))
{
if ( ! method_exists($module, $method))
{
$module = $this->load->module($controller);
}
}
}
else
{
$module = $this->load->module($this->uri->segment(1) .'/'. $controller);
}
call_user_func_array(array($module, $method), $arguments);
}
Break It Down Now Ya’ll
We start out with CodeIgniter’s _remap()
method and setup the $controller
variable to be the requested class name lowercased.
public function _remap($method, $arguments)
{
$controller = strtolower($this->router->class);
}
Then we add a check to see if the requested controller is the default controller for the module. I do this because I don’t want to always override the requested controller, I still want to be able to have controllers for things like product images and categories in the same module. If it’s not the default controller for the module, I just load the requested controller.
if ($controller === $this->uri->segment(1))
{
}
else
{
$module = $this->load->module($this->uri->segment(1) .'/'. $controller);
}
If they are requesting the default controller, I check to see what type of user they are and assign to to a variable. This could, and probably should, be setup dynamically in most cases.
if ($this->acl->is_admin())
{
$user_type = 'operations';
}
else
{
$user_type = 'corporate';
}
Next, I attempt to load the module and their respective controller. If the controller exists, I check to see if the requested method exists. If the method doesn’t exist, that means that I haven’t created a group-specific method for that type of user so I load the default controller.
if ($module = $this->load->module($controller .'/'. $user_type))
{
if ( ! method_exists($module, $method))
{
$module = $this->load->module($controller);
}
}
And finally, we call the actual method.
call_user_func_array(array($module, $method), $arguments);
Source: