Welcome Guest, Not a member yet? Register   Sign In
Calling method of other class
#1

[eluser]bapobap[/eluser]
Hi all,

I've coded an API which uses the following to route requests:

$controller_name::$controller_method();

This works fine in PHP 5.3+ but it doesn't in 5.2, which is unfortunately what my server is running (have no control over updating).

Is there anyway around this? I've found references to stuff like call_user_func but then the method I'm calling doesn't see the big $this singleton.

Thanks if you can help, just spent 3 days re-writing code, only to find the entire thing won't work because of this one line of code :-S
#2

[eluser]Filippo Toso[/eluser]
[quote author="bapobap" date="1277010846"]$controller_name::$controller_method();[/quote]

This seems a static method call (see http://www.php.net/manual/en/language.oo...otayim.php)

If you need to access $this within the called method, you have to call the object method, not the class method. This means you have to create the controller and then call the method:

Code:
$controller = new $controller_name();
$controller->$controller_method();

Hope it helps.
#3

[eluser]bapobap[/eluser]
Hi Filippo,

When I do this it seems to create a new instance of the super-object as all the preparation work I've done in the first controller gets lost.

Basically everything gets routed to controllers/dispatcher.php. It takes all GET, POST, PUT, DELETE variables, cleans them etc and adds them into the CI object, $this->request_data. It then determines what controller and method to call, includes that file and calls it. Helpers that use $CI =& get_instance(); work fine with the $ClassName::$method() but as I stated PHP 5.2 you can't use a variable ClassName.

Using the above seems to create a fresh object that doesn't have any of my data in it. Is there anyway around that?

Thanks if you can help
#4

[eluser]Filippo Toso[/eluser]
You can manually copy the data from the current controller and the new controller.

In alternative, try to identify the controller class before in your code and then add all the cleaned data to the instance of the destination controller instead of the dispatcher.
#5

[eluser]bapobap[/eluser]
Tried the first one but while the controller sees it, nothing else does.

For the second one, what do you mean by that? Would that be, have the dispatcher work out where to send the request, call that, then have that controller do all the cleaning work? Would my models/libraries/helpers then be able to see that?

Such a pain. One little line messing up so much work!

Thanks for your help
#6

[eluser]Filippo Toso[/eluser]
Can you attach the dispatcher controller or at least a sample / bare bone dispatcher controller that reproduces the behavior you are experiencing (<i>"the controller sees it, nothing else does."</i>)?
#7

[eluser]bapobap[/eluser]
Sure:

So every request gets sent to dispatcher.php. It's constructor does all the work of setting up the request stuff, like:

Code:
// Add GET
    $get = array();
    parse_str($_SERVER['QUERY_STRING'], $get);

    foreach ($get as $key => $value):

        if (!array_key_exists($key, $this->request)):

            $this->request[$key] = $this->input->xss_clean($value);

        endif;

    endforeach;

$this->request['resource'] = 'whatever class the user wants, like login, signup etc';
$this->request['method'] = 'the actual method to call so login_user, login_robot';
$this->request['request_method'] = 'either get, post etc';


Then a _remap method, sends the request on it's way if it can:

Code:
function _remap()
{
    $path = APPPATH.'controllers/';

    // Add resource required
    $path .= $this->request['resource'];

    // Check controller exists
    if (file_exists($path)):

        require($path);

    else:

        exit;

    endif;


    $controller_method = $this->request['method'].'_'.strtolower($this->request['request_method']);

    if (method_exists(ucwords($this->request['resource']), $controller_method)):

// So something like Login::login_get()

        $call = ucwords($this->request['resource']);
        // $call::$controller_method(); // Doesn't work in 5.2

        $instance = new $call();
        $instance->$controller_method();

    else:

        exit;

    endif;
}


When using $call::$controller_method(); everything sees the Disptacher object with my lovely request data added in. Anything that was autoloaded works fine, like database etc.

When using $instance = new $call(); $instance->$controller_method(); let's say to a Login controller, Login becomes the new $this instead of Dispatch. Anything autoloaded isn't there anymore, $this->request doesn't exist and any helpers that use the &= get_instance() only see the Login object not Dispatch.

Manually passing the data from Dispatch to Login, while it works, doesn't get around the problem of anything that is autoloaded or helpers etc that use get_instance because that seems to just refer to Login, not Dispatch.
#8

[eluser]Filippo Toso[/eluser]
Why are you using a dispatcher controller?
Have you think about extending the base Controller class instead?

It will be a cleaner way to add your own processing code in the Controlller constructor.

Something like:

Code:
&lt;?php

class MY_Controller extends Controller {

    function MY_Controller()
    {

        // Standard behavior
        parent::Controller();

        // Custom behavior
        $get = array();
        parse_str($_SERVER['QUERY_STRING'], $get);
        
        foreach ($get as $key => $value):
            if (!array_key_exists($key, $this->request)):
                $this->request[$key] = $this->input->xss_clean($value);
            endif;
        endforeach;
        
        $this->request['resource'] = 'whatever class the user wants, like login, signup etc';
        $this->request['method'] = 'the actual method to call so login_user, login_robot';
        $this->request['request_method'] = 'either get, post etc';            

    }

}

/* End of file MY_Controller.php */
/* Location: ./application/libraries/MY_Controller.php */

Then you can call the controllers/methods using the standard CI way (routes) and you get rid of the problems with get_instance().
#9

[eluser]bapobap[/eluser]
CI routes need to be defined for each resource I set up, the way I was doing it meant if the file someone was asking for didn't exist, the request was denied.

Also, CI doesn't seem to like GET vars, so something like http://api.website.com/login?username=blablabla had to be defined in routes as:

Code:
$route['login']                        = 'login';
$route['login:any']                    = 'login';
$route['login/:any']                    = 'login';

as I didn't want to enable querystrings or anything like that.

I guess you are right though, I should have just followed conventions instead of re-writing the rulebook.
#10

[eluser]bapobap[/eluser]
Sorry just remembered why I had done it that way now!

I need to call certain methods based on the request method. So let's imagine a class called Cupcake where you can bake or eat a cupcake.

REST means that to eat a cupcake I would GET, to bake one I would POST. Routes don't allow me to send things based on the request method whereas mine does. Mine would call Cupcake::cupcake_get() or Cupcake::cupcake_post(). I don't know how that can be achieved with routes.




Theme © iAndrew 2016 - Forum software by © MyBB