Same tasks in each controller: controller inheritance?

#1
[eluser]sl3dg3hamm3r[/eluser]
Hey there

I just wanted to ask for some advice if I am on the right track. Supposed I need to build an administration area, each controller which handles this area would need to check if the user is really logged in as administrator before letting him do anything.

I thought I would write then first a general admin-controller who would check this in the constructor, and all other controllers would inherit from this one. This makes sure I won't forget this check anywhere. Similar to this example.

Does this make sense to you experienced code-igniters, or is there a more elegant, better way?

Glad for any hint :-)
Oliver

#2
[eluser]xwero[/eluser]
a hook is the most elegant solution in my book. You create/fetch an authentication library and you add a post_controller_constructor hook that uses the authentication library. It can be a function if you want
Code:
function access()
{
  $CI =& get_instance(); // this is the reason why it has to be a post_controller_constructor hook
  $CI->load->library('authentication'); // as a precaution if the library isn't defined in the autoload file
  if($CI->uri->segment(1) == 'admin' && /* I assume the admin has a own directory/controller */
     ! $CI->authentication->logged_in())
  {
     redirect(''); // url helper function
  }
}
I prefer the loose coupling of the hooks better than the extending of controllers.

#3
[eluser]sl3dg3hamm3r[/eluser]
I also thought about hooks. About loose coupling you are absolutely right, I might prefer this method, thx!

p.s.: what book?

#4
[eluser]xwero[/eluser]
in one's book : According to one's opinion or way of thinking Smile

#5
[eluser]sl3dg3hamm3r[/eluser]
ah... didn't know that one, took it for real :-))

#6
[eluser]Randy Casburn[/eluser]
I do it with inheritance....

You can provide a folder through which all contents are secure. If the controller is in there...it is secure simply by being in there. There is little code required (a simple path change) to make this work. Remove it from the folder (change on path) and it is no longer secure.

I agree with xwero that hooks are very elegant and I do like them.

The one thing I don't like about hooks that that they are so dreadfully obscure. If you decide to use hooks, please, I emplore you comment, comment, comment your code in triplicate. Then put a text file in the root of your System directory named HOOKS that describes what hooks you have in place.

The reason is that they work behind the scenes and will be doing things that you forget about.

Just a thought.

Randy

#7
[eluser]xwero[/eluser]
I agree with Randy that hooks can be a cause of bugs because they are not added in plain sight. But an easy way to know they are there is to add debug log messages to the hook function/methods you use.

#8
[eluser]Randy Casburn[/eluser]
Good point xwero...duh. I'll start doing that too.

I have a full IDE with complete debugging capability. I'm stepping through the code with the debugger. So I don't rely on the CI logs too much. Even after all this time...perhaps I should.

Thanks for the tip.

Randy

#9
[eluser]sl3dg3hamm3r[/eluser]
[quote author="Randy Casburn" date="1223670292"]You can provide a folder through which all contents are secure. If the controller is in there...it is secure simply by being in there. There is little code required (a simple path change) to make this work. Remove it from the folder (change on path) and it is no longer secure.[/quote]

I'm not sure if I understood that... can you provide a simple example?

#10
[eluser]gon[/eluser]
I also use inheritance from a base controller.

The base controller has a _remap method, so every action will call _remap first.

The _remap method checks the controller and the action, and checks if the user has permission to execute that controller / action.
If access control is successful, the controller action is executed.

Note that _remap only check ACL. Auth is checked in the base_controller constructor, and we get redirected out if not successful.

This is the _remap method in base_controller:

Code:
/////////////////////////////////////////////
    // catch-all function                        //
    //                                            //
    // dispatches to action after checking ACL //
    /////////////////////////////////////////////
    function _remap($action) {
        
        if (!method_exists($this, $action))
            show_404();
        
        $segments = $this->uri->segment_array();
        if (count($segments)<2)
            show_404();
        
        $controller = $segments[2];        
        $args = array_slice($segments, 3);
        
        if ($this->menu_section) {
            $menu_section = $this->menu_section;    
        } else {
            $menu_section = $controller;
        }
        $this->cl_navi_model->set_route($menu_section, $action, $args);
                    
        $authorization = $this->cl_acl->getAuthorization($controller, $action);                
        if (!$authorization) {            
            show_404();
        }
        
        if (method_exists($this, $controller."_init")) {
            call_user_func_array(array($this, $controller."_init"), array($action, $args));
        }    

        ob_start();
        call_user_func_array(array($this, $action), $args);
        $content = ob_get_contents();        
        ob_end_clean();
        
        echo $this->cl_layout->render($content);
    }

I also configure the menu, and call an optional XXX_init method which some controllers implement, but you can skip that.

The ob_start(), ob_end() is another part you can skip if you want. I use it for getting the content that the action renders, and injecting it into the common layout.

Regards.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


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