CakePHP: best way to call an action of another controller with array as parameter?
Asked Answered
G

5

27

In a controller, what is the most appropriate way to call the action of another controller and also pass an array as parameter?

I know that you can use requestAction to call actions within other controllers. But is it possible to pass arrays as parameters using request action?

And no, I do not want to put the action in the App Controller. So that is not a solution for me.

The only other way I know is to load the other controller as explained in: http://book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/Configuration.html#importing-controllers-models-components-behaviors-views-and-helpers

But is there an easier way to just call the other controllers action while passing an array as parameter?

I am new to cakePHP so any suggestion is appreciated. Thanks.

Gonsalve answered 2/10, 2009 at 2:56 Comment(1)
Which cakephp version? could you add it?Gulgee
B
25

Would it be appropriate for you to move the logic from the second controller into its model, then do something like this in your first controller's action?

$var = ClassRegistry::init('SecondModel')->myMethod($array);
$this->set(compact('var'));

Then, in the view for the first controller's action, you can use that data.

I always try to keep controller methods to actions you can hit through the browser, put as much logic in my models, call foreign model methods from controllers actions that need data from models that aren't the model for that controller, then use that data in my views, and if it's data that is viewed frequently, I create an element for it.

Bawdyhouse answered 2/10, 2009 at 2:56 Comment(7)
good suggestion. I have heard somethings about separating logic from controller to model before. but still not clear about that concept. maybe as I gain more experience with cake, I will get a clearer picture. Thanks for your help.Gonsalve
Neil has the right idea. Controllers are intended to handle and delegate incoming requests. Business logic, or code that does stuff should primarily be in your models.Sun
I don't believe this is correct, models are for database access rules, the controllers handle everything else, the bulk of an application would be in the controller, in most cases.. I don't know what you mean by "code that does stuff".. anyways, the best practice IMO is to make code re-use a priority, so ideally a lot of stuff should be placed in controller componenets, the model is only used for stuff like data validation, etc, and in these cases should usually also be made into components (within the model folder) for re-use of these as wellAlmoner
I disagree. Models should be fat, controllers skinny. As much logic should be put in models as possible. All your controller should do is process the request, deal with sessions, call model methods, set data for the view and handle userflow etc. If you find you are doing these things the same in lots of controllers, then create a component for it. BTW, did you know the comment you commented on, was written by the one of the lead developers of CakePHP?Bawdyhouse
@Bawdyhouse +1 for the good advice in the answer and comments. It's easy to forget about best practise and go for the 'easy' solution.Dentilabial
The "fat models" mantra is not a justification for throwing anything and everything in them. Models are concerned with data retrieval and storage, and any methods that make those jobs easier belong in the model... but that's it. Business logic should technically not even be coupled to the CakePHP framework at all in either the controller or the model. It should exist in your own PHP "library" classes that the controller pulls into scope and uses as necessary, but this is a far more advanced approach than you typically see in Cake apps.Ess
@Almoner +1 the models are for data definition and access rules. Controllers do all the logic in the app.Lederhosen
C
30

I would not advice to use the method requestAction but rather import, and instantiate the needed controller.

CakePHP doc says about requestAction that:

"It is rarely appropriate to use in a controller or model"

http://book.cakephp.org/view/434/requestAction

Once you imported and loaded the controller you can call any method of this controller with its parameters.

<?php
  //Import controller
  App::import('Controller', 'Posts');

  class CommentsController extends AppController {
    //Instantiation
    $Posts = new PostsController;
    //Load model, components...
    $Posts->constructClasses();

    function index($passArray = array(1,2,3)) {
      //Call a method from PostsController with parameter
      $Posts->doSomething($passArray);
    }
  }
?>
Corded answered 2/10, 2009 at 2:56 Comment(7)
thanks for your reply. yes I have heard that rumor about requestAction. wonder why it's not encouraged. Anyway, 'Import' is an alternate solution, thanks.Gonsalve
I agree, this is best, I had been using requestaction but it quickly shows why its not good, if you need to pass in a string that contains anything but basic text it won't work right, since its using the url method so it can't have special characters and if you use "/" in a string htis will break it into separate variablesAlmoner
Using one controller action in another is quite common in a large app. Is there any news on if Cake will implement a standard single command to do so other than requestAction that even the documentation states has poor performance.Enrollee
sorry for being that old the post to ask, but after loading the model and using it, is it necessary to unload it?Brownfield
@hephestos: As far as I understand, you don't have to worry about unloading them. The loaded models will be used by your Controller functions each time they are called.Gonsalve
The code example will not run as currently written. $Posts = new PostsController; and $Posts->constructClasses(); are not inside of a CommentsController method.Ess
The variables defined need to go in a method, or perhaps this class constructor. But apart from that, I consider this a much cleaner solution than the other answer. Thanks!Soriano
B
25

Would it be appropriate for you to move the logic from the second controller into its model, then do something like this in your first controller's action?

$var = ClassRegistry::init('SecondModel')->myMethod($array);
$this->set(compact('var'));

Then, in the view for the first controller's action, you can use that data.

I always try to keep controller methods to actions you can hit through the browser, put as much logic in my models, call foreign model methods from controllers actions that need data from models that aren't the model for that controller, then use that data in my views, and if it's data that is viewed frequently, I create an element for it.

Bawdyhouse answered 2/10, 2009 at 2:56 Comment(7)
good suggestion. I have heard somethings about separating logic from controller to model before. but still not clear about that concept. maybe as I gain more experience with cake, I will get a clearer picture. Thanks for your help.Gonsalve
Neil has the right idea. Controllers are intended to handle and delegate incoming requests. Business logic, or code that does stuff should primarily be in your models.Sun
I don't believe this is correct, models are for database access rules, the controllers handle everything else, the bulk of an application would be in the controller, in most cases.. I don't know what you mean by "code that does stuff".. anyways, the best practice IMO is to make code re-use a priority, so ideally a lot of stuff should be placed in controller componenets, the model is only used for stuff like data validation, etc, and in these cases should usually also be made into components (within the model folder) for re-use of these as wellAlmoner
I disagree. Models should be fat, controllers skinny. As much logic should be put in models as possible. All your controller should do is process the request, deal with sessions, call model methods, set data for the view and handle userflow etc. If you find you are doing these things the same in lots of controllers, then create a component for it. BTW, did you know the comment you commented on, was written by the one of the lead developers of CakePHP?Bawdyhouse
@Bawdyhouse +1 for the good advice in the answer and comments. It's easy to forget about best practise and go for the 'easy' solution.Dentilabial
The "fat models" mantra is not a justification for throwing anything and everything in them. Models are concerned with data retrieval and storage, and any methods that make those jobs easier belong in the model... but that's it. Business logic should technically not even be coupled to the CakePHP framework at all in either the controller or the model. It should exist in your own PHP "library" classes that the controller pulls into scope and uses as necessary, but this is a far more advanced approach than you typically see in Cake apps.Ess
@Almoner +1 the models are for data definition and access rules. Controllers do all the logic in the app.Lederhosen
M
3

CakePHP 2.X:

<?php
App::uses('AppController', 'Controller');
App::uses('PostsController', 'Controller');

class CommentsController extends AppController {

    public function index($parameter = null){
        //Instantiate
        $Posts = new PostsController();
        //Load model, components...
        $Posts->constructClasses();

        //Call a method of Posts passing a parameter
        $Posts->aMethod($parameter);
    }
}
Mokas answered 2/10, 2009 at 2:56 Comment(0)
I
3

As of CakePHP 1.2.5, you should be able to pass various parameter types through the second parameter in requestAction(). e.g.:

$this->requestAction('/users/view', array('pass' => array('123')));

Then in the UsersController:

function view($id) {
    echo $id; // should echo 123 I believe, otherwise try $this->params['pass'].
}

Instead of using 'pass' above, you can alternatively try 'form' and 'named' to pass form/named parameters respectively.

Incus answered 2/10, 2009 at 2:56 Comment(1)
Great! wasn't sure whether I can do that. Will try it. Thank you.Gonsalve
G
-1

I put into my AppController class the following method and variable so it is caches in case of multiple calls

var $controllersArray = array();

function _getController( $pControllerName ){
    if ( ! isset($this->controllersArray[$pControllerName]) ){
        $importRes = App::import('Controller', $pControllerName);// The same as require('controllers/users_controller.php');
        $strToEval = "\$controller = new ".$pControllerName."Controller;";
        $evalRes = eval($strToEval);
        if ( $evalRes === false ){
            throw new AppException("Error during eval of given getController '$pControllerName'");
        }
        $controller->constructClasses();// If we want the model associations, components, etc to be loaded
        $this->controllersArray[$pControllerName] = $controller;
    }
    $result = $this->controllersArray[$pControllerName];

    return $result;
}
Gulgee answered 2/10, 2009 at 2:56 Comment(1)
It's impossible that you have tested this code. It does throw syntax errors.. Eval..:? Sure?Traitor

© 2022 - 2024 — McMap. All rights reserved.