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.

icc97
  • 11,395
  • 8
  • 76
  • 90
Vicer
  • 1,034
  • 5
  • 15
  • 22

5 Answers5

29

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);
    }
  }
?>
Sadikhasan
  • 18,365
  • 21
  • 80
  • 122
Schaoulli
  • 26
  • 1
  • 2
  • 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. – Vicer Oct 07 '09 at 04:21
  • 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 variables – Rick Aug 16 '10 at 23:14
  • 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. – Ryan Sep 26 '11 at 10:08
  • sorry for being that old the post to ask, but after loading the model and using it, is it necessary to unload it? – hephestos Jul 18 '12 at 19:49
  • @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. – Vicer Sep 27 '12 at 01:17
  • The code example will not run as currently written. `$Posts = new PostsController;` and `$Posts->constructClasses();` are not inside of a CommentsController method. – beporter Jan 30 '14 at 17:23
  • 2
    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! – Josh Feb 07 '14 at 18:03
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.

Brad Koch
  • 19,267
  • 19
  • 110
  • 137
neilcrookes
  • 4,203
  • 2
  • 21
  • 27
  • 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. – Vicer Oct 07 '09 at 04:25
  • 4
    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. – Mark Story Oct 22 '09 at 05:33
  • 1
    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 well – Rick Aug 16 '10 at 23:15
  • 13
    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? – neilcrookes Aug 17 '10 at 22:39
  • @neilcrookes +1 for the good advice in the answer and comments. It's easy to forget about best practise and go for the 'easy' solution. – camden_kid Apr 03 '14 at 14:16
  • 1
    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. – beporter May 28 '14 at 15:01
  • @Rick +1 the models are for data definition and access rules. Controllers do all the logic in the app. – marcoslhc Jun 23 '14 at 14:05
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.

Matt Huggins
  • 81,398
  • 36
  • 149
  • 218
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);
    }
}
Jocari
  • 43
  • 7
-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;
}
Pipo
  • 4,653
  • 38
  • 47