Search code examples
phpcodeigniternamespacespropel

Using a namespace in an extended class


I'm using Propel together with CodeIgniter. I made a MY_Model class (which extends CI_Model) that uses its constructor to load Propel.

In case you're curious:

class MY_Model extends CI_Model{
    public function __construct(){
        parent::__construct();

        require_once '/propel/runtime/lib/Propel.php';
        Propel::init('/build/conf/project-conf.php');
        set_include_path('/build/classes'.PATH_SEPARATOR.get_include_path());
    }
}

So, now when I make a new CodeIgniter model, it will load up Propel for me. Thing is, I added namespaces to a few of the Propel-generated models. I figured I could add the use Reports; line inside the model's constructor, but nope.

class Reports_model extends MY_Model{
    function __construct(){
        parent::__construct();
        use Reports;
    }
}

This gives me

syntax error, unexpected T_USE

Ok, I thought, let's try putting it outside the constructor:

class Reports_model extends MY_Model{
    use Reports;

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

Now I get a longer error:

syntax error, unexpected T_USE, expecting T_FUNCTION

As a last resort, I added the use Reports; before the class declaration:

use Reports;

class Reports_model extends MY_Model{
    function __construct(){
        parent::__construct();
    }
}

Now I get even more errors!

The use statement with non-compound name 'Reports' has no effect
Class 'ReportsQuery' not found

In another function in the class, I have a line that does $report = ReportsQuery::create();.

So, how can I get the use Reports; line to work? I really don't feel like adding Reports\ everywhere.

How can I make it so I can do:

$report = ReportsQuery::create();

instead of:

$report = Reports\ReportsQuery::create();

Solution

  • Apparently, the use keyword doesn't do what I though it did. That just tells PHP where to look for a class.

    What I needed to do was use the namespace keyword to declare that my class was in the Reports namespace. I then had to tell it to use MY_Model from the global namespace.

    namespace Reports;
    use MY_Model;
    
    class Reports_model extends MY_Model{
        function __construct(){
            parent::__construct();
        }
    }
    

    I could also do class Reports_model extends \MY_Model{ instead of the use MY_Model; line.

    Problem now is that CodeIgniter can't find Reports_model because it's now inside the Reports namespace, and not the global namespace. I found the solution to that in another StackOverflow question (https://stackoverflow.com/a/14008411/206403).

    There is a function called class_alias that's basically magic.

    namespace Reports;
    use MY_Model;
    
    class_alias('Reports\Reports_model', 'Reports_model', FALSE);
    
    class Reports_model extends MY_Model{
        function __construct(){
            parent::__construct();
        }
    }
    

    And that works perfectly!