SaidbakR
SaidbakR

Reputation: 13534

How does this callback works for a cakePHP component?

In CakeDC comments plugin for CakePHP documentation states that:

Component callbacks

It is possible to override or extend the most comments component methods in the controller. To do this we need to create method with prefix callback_comments Examples:

callback_add will named as callback_commentsAdd in controller, callback_fetchData will named as callback_commentsFetchData in controller. ...

It works from the controller perfectly!:

public function callback_commentsInitType() {

    return 'flat'; // threaded, tree and flat supported
}

I wonder, what is the new feature of that allows you to do that? I need to understand how it was achieved to be able to implement such methodology in the future on my components.

Upvotes: 0

Views: 224

Answers (1)

Vishal
Vishal

Reputation: 2060

In the code of the component, if you look at the following function in this file (starting from line number 622):

/**
 * Call action from commponent or overriden action from controller.
 *
 * @param string $method
 * @param array $args
 * @return mixed
 */
    protected function _call($method, $args = array()) {
        $methodName = 'callback_comments' .  Inflector::camelize(Inflector::underscore($method));
        $localMethodName = 'callback_' .  $method;
        if (method_exists($this->Controller, $methodName)) {
            return call_user_func_array(array(&$this->Controller, $methodName), $args);
        } elseif (method_exists($this, $localMethodName)) {
            return call_user_func_array(array(&$this, $localMethodName), $args);
        } else {
            throw new BadMethodCallException();
        }
    }

You can see that the variable $methodName is being defined with prefix callback_comments and then the passed $method is appended to it after being treated by the Inflector::underscore and then Inflector::camelize method. The working of these is as follows:

  1. Inflector::underscore will convert initType to init_type. Check doc here.
  2. Inflector::camelize will further convert init_type to InitType. Check doc here.

Now, if initType was passed in the argument, then the $methodName will be:

callback_comments + InitType = callback_commentsInitType

After this, a $localMethodName is also being generated. In our initType example, it will be:

callback_ + initType = callback_initType

After the names have been generated, it will simply search if the method exists in the attached controller and will execute it using call_user_func_array function by passing it and array with the object (in our case, the controller object (&$this->Controller) or the component object itself (&$this)) containing the method and the $methodName as first argument and then $args as second argument.

If the function was not found in the controller, then it will instead search in the component with $localMethodName. If it's found, then it is executed the same way.

Now how all this works is that the _call function is the single function used to call all the internal functions of the component, so that it will first check if the function has been overwritten in the controller, otherwise it will execute the function in the component itself.

You can check the component's beforeRender function here and you'll see how the initType function is called. In this case, if the controller contains a function named callback_commentsInitType, then it will be executed. Otherwise, the components callback_initType will be executed.

Hope this helps..

Upvotes: 2

Related Questions