1
votes

I'm this is my first CI Project and I am trying to build a login system (3 user groups = admin, member, public). I'm using Ion Auth.

If you want to skip the details..

..my problem is that I am somehow not doing my "require_once" correctly in my home controller, or I am not understanding something about extending classes. Or I am just not as clever as my mom tells me I am. I get this error:

Fatal error: require_once() [function.require]: Failed opening required 'application/Application/Core/public_controller.php' (include_path='.:/Applications/MAMP/bin/php/php5.3.6/lib/php') in /Applications/MAMP/htdocs/NOIR_FINAL/application/controllers/public/home.php on line 4

I referenced this article, as it looks like good practice. Specifically, I extended CI_Controller with MY_Controller (containing an Admin, Member, and Public controllers that all extended CI_Controller).

http://jondavidjohn.com/blog/2011/01/scalable-login-system-for-codeigniter-ion_auth

Then I saw some criticism of "packing" all these 3 admin, member, and public controllers into one "MY_Controller" .. so as per Phil Sturgeon I have tried to separate them into individual classes and use __autoload() to pull them in.

http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-Base-Classes-Keeping-it-DRY

But somehow I get the feeling that I am now just making things unnecessarily complicated.

I want to go through the login, and then depending on the user group send them to one of 3 "home" controllers in dedicated folders. Those home controllers extend Admin_controller, Member_controller, or Public_controller ... and each one of those extends MY_Controller, which in turn extends CI_Controller. So I would have group specific methods in their respective controllers, and some general stuff in MY_Controller ( checking to see if site is live/"open" .. checking user agent .. etc). This, to me, seems to be a pretty nice way of separating user roles.

I also have this in my config, as per Sturgeon's article ..

function __autoload($class)
{
    if(strpos($class, 'CI_') !== 0)
    {
        @include_once( APPPATH . 'core/'. $class . EXT );
    }
}

So am I going about this right way at all? Since its my first try at this and I am starting to think this is becoming a bit too "Frankenstein". Here is 'auth/login'...

function login() {

    if($_POST) {   //clean public facing app input
        $this->form_validation->set_rules('email', 'Email', 'required|valid_email');
        $this->form_validation->set_rules('password', 'Password', 'required');

        if ($this->form_validation->run() == true)
        {
            $identity = $this->input->post('email', true);
            $password = $this->input->post('password', true);
            $remember = $this->input->post('remember');
            if($this->ion_auth->login($identity,$password, $remember)) 
            {
                if($this->ion_auth->in_group('1'))
                {
                    $this->session->set_flashdata('message','Welcome');
                    redirect('admin/home','refresh'); // this might have to change @todo
                }
                elseif($this->ion_auth->in_group('2'))
                {
                    $this->session->set_flashdata('message','Welcome');
                    redirect('member/home','refresh');
                }
                else
                {
                    redirect('public/home','refresh');
                }   
            }
        }
        else 
        {
            // set error flashdata
            $this->session->set_flashdata('message','Your login attempt failed.');
            redirect('/');
        }
    }

    redirect('/');
}

.. and here is home.php in "controllers/member/" .. basically just setting up the view and translating the flashdata message (if any) into $data{'message']

class Home extends Member_Controller{
    require_once(APPPATH.'Application/Core/member_controller.php');
    public function __construct()
    {
        parent::__construct;
    }
    public function index()
    {
        // remember that $this->the_user is available in this controller
        // as is $the_user available in any view I load
        $this->load->model('Member_model');
        $this->data['message'] = $this->session->flashdata('message');
        $this->data['query'] = $this->Member_model->get_members();
        $this->data['title'] = 'Home';
        $this->load->view('member_view', $this->data);
    }
}

Here is my member controller with some member methods

class Member_Controller extends MY_Controller{
    public function __construct()
    {
        parent::__construct();
    }
    public function index()
    {
        $this->load->view('member_view');
    }
    public function edit_profile(){}
    public function delete_profile(){}

}

.. and MY_Controller with some common methods

class MY_Controller extends CI_Controller {
    protected $the_user;
    public function __construct()
    {
        parent::__construct();
        if( $this->config->item('site_open' ) === FALSE)
        {
            show_error("Sorry the site is shut right now.");
        }

        if( $this->ion_auth->logged_in() )
        {
            $this->the_user = $this->ion_auth->user()->row();
            $data->the_user = $this->the_user;
            $this->load->vars($data);
        }
        else
        {
            redirect('/','refresh');
        }

        //if the user is using a mobile, use a mobile theme
        $this->load->library('user_agent');
        if( $this->agent->is_mobile() )
        {
            $this->template->set_theme('mobile'); // what about admin @todo
        }
    }

    public function index()
    {
        redirect('/','refresh');
    }
} 

So am I approaching this correctly? As a bonus question, is it correct to put index methods on classes that are only ever going to be extended? For ex, nobody is going to "land" on MY_Controller. It will always be extended. So do I need to put an index method? Is it just good form? Should I make this an abstract class?

2
i think everyone has his own logic doing things, what is better to know is that there are multiple auth libraries out there for ci, and i think you could take less time and not re-invent the weel ;) - itsme
thx.. but I am using Ion_Auth, and referencing jondavidjohns srticle that seemed to add a bit of useful organization to Ion Auths (admittedly "barebones") basic system - K.K. Smith

2 Answers

1
votes

When it comes to working with require/include, you need to specify the PATH and it has to be either absolute or relative.

Absolute:

/my/cool/folder/file.php //which means from the root ("/") of the server

relative:

./file.php //which means look in the current directory for file.php

or

../file.php //which means go up one directory and look for file.php

if a PATH is not defined in the require or include, the system will use the include path which is defined in php.ini

What you have set: require_once('application/Application/Core/public_controller.php') will not work because you aren't setting a relative nor an absolute PATH therefore the system is looking for public_controller.php in the include_path which is set in php.ini.

All this and we haven't even started in to why you'd be including your public controller in the first place.

When you extend a class, you are making it available as an adjunct to existing classes. As such, when you extend CI_Controller, since CI_Controller is already available in the application, the extended functionality will be available as well without needing to include the file.

No, you don't need to create an index method in MY_Controller.

Lastly, I don't know that you need to be doing all this... Extending the core classes is usually reserved for adding some functionality that you may need or is missing to the core or for overriding existing functionality. What you are doing is moving code that would live just fine in controllers into the core application. I supposed it will work, but I don't think it's best practice nor very practical.

1
votes

Your include is failing because of the path you've given it, look at the error message. Application is unnecessary since that is what CI considers the apppath.

require_once(APPPATH.'core/member_controller.php');

That should fix it, but after rereading that code I realized... you shouldn't even need this. Extending it should be including it anyway? I know I don't do any includes like that in my extended controllers.

As to overcomplicating things. I personally don't feel you're overcomplicating except possibly in one regard. Our application has Admin_Controller, User_Controller and MY_Controller. The place you may just be overcomplicating it is having the Public_Controller. As I see it admin and user will have all the functionality of MY which is the base functionality of the application itself. So that in essence IS my public controller.

Being able to restrict access to certain parts of the site in one place makes a lot of sense and it does make the overall flow of the application make more sense too. In my opinion it also means less overhead as well since you aren't loading a controller that has all the functionality needed for all the different scenarios every time you load a page.