How to list all controllers

Published on and tagged with cakephp  component

From time to time the question “how can I list all controllers?” pops up. I provided a (untested) solution in the german google group, but yesterday I had to see that it didn’t work (thanks to Kinesis77). So here is the improved code as a component:

// app/controllers/components/controller_list.php
class ControllerListComponent extends Object {
    public function get() {
        $controllerClasses = App::objects('controller');

        foreach($controllerClasses as $controller) { 
            if ($controller != 'App') { 
                App::import('Controller', $controller);
                $className = $controller . 'Controller';
                $actions = get_class_methods($className);
                foreach($actions as $k => $v) {
                    if ($v{0} == '_') {
                        unset($actions[$k]);
                    }
                }
                $parentActions = get_class_methods('AppController');
                $controllers[$controller] = array_diff($actions, $parentActions);
            }
        }
		     
        return $controllers;  
    }
}

The usage is simple. Just include the component in the $components array of your controller:

public $components = array('ControllerList');

and call it with:

$this->ControllerList->get()

It returns an array with the following format:

Array
(
    [Pages] => Array
        (
            [0] => display
        )
    [Tests] => Array
        (
            [0] => index
            [1] => groups
            [2] => cases
        )
)

You can find the component on Github: http://github.com/cakebaker/controller-list-component.

Update 2008-02-04: Applied Jej’s patch and adapted the component to work with Cake 1.2.
Update 2008-07-17: Applied Raymond’s fix.
Update 2008-11-21: Applied Maxim Tsyngaev’s patch.
Update 2010-05-19: Adapting the component to work with Cake 1.3
Update 2010-06-29: Applying Andrew’s fix plus adding the code to Github.

36 comments baked

  • AD7six

    Like it.

    I have a sneaky suspicion that many users want to use this to generate a navigation menu whilst in development.

    You seem to be one blog ahead of me ;), here’s a snippet of code taken from something I was going to post in the coming days:

    $class_methods = get_class_methods($this->controller);
    $controller_methods = get_class_methods(“AppController”);
    $class_methods = array_diff($class_methods,$controller_methods);
    foreach ($class_methods as $method)
    {
    if ($method{0}”_”)
    {
    $admin = strpos($method, CAKE_ADMIN);
    if ($admin === false)
    {
    if (!stristr($method,”controller”)) // Without this, class names are appearing in the results (?) with PHP4.
    {
    $this->PublicUrls[] = Array(ucfirst($method),”/”.$this->controller->name.”/”.$method);
    }
    }
    }
    }

    That way, methods defined in app_controller or the plugin app controller are captured, and all the private methods are ignored (as well as the default methods, as is the case for your example.)

  • AD7six

    Ooops made a copy paste error… that should be:

    $controller_methods = get_class_methods(”Controller”);

  • Felix Geisendörfer

    Hi, one more thing to consider for any solution that is supposed to list controllers/models/etc., is that they can also be placed outside of app/controllers or app/models, and that those places can be defined in the bootstrap.php. For that reason, it is neccessary to loop through ldall those possible locations which you can get from the Configure singleton. Bear in mind that also plugins can have controllers in them.

    Just do something like this:
    uses(‘Folder’);
    $paths = Configure::getInstance();
    $folder =& new Folder();

    $controllers = array();

    foreach ($paths->controllerPaths as $path)
    {
    $folder->cd($path);
    $files = $folder->findRecursive(‘.*_controller\.php’);
    $controllers = array_merge($controllers, $files);
    }

    $folder->cd(APP.’plugins’);
    $files = $folder->findRecursive(‘.*_controller\.php’);
    $files = $folder->findRecursive(‘.*[^api]_controller\.php’);

    $controllers = array_merge($controllers, $files);

    Ok, this is not 100% perfect either, since it doesn’t go through each plugin folder and only checks the /controllers subdir in it, but you can add that.

    In SpliceIt! I sucessfully am using an automatically generated menu based on all _admin functions, the code can be found here:
    https://cakeforge.org/plugins/scmsvn/viewcvs.php/trunk/spliceit/app/plugins/admin/controllers/admin_api.php?rev=78&root=spliceit&view=markup

    Anyway, other then that thanks for publishing it, I think that’s really useful for a lot of people out there ; ).

  • cakebaker

    @AD7six, Felix: Thanks for your additions. I have completely missed plug-ins ;)

  • How to list all controllers

    […] How to list all controllers: ”From time to time the question ‘how can I list all controllers?’ pops up. I provided a (untested) solution in the german google group, but yesterday I had to see that it didn’t work (thanks to Kinesis77). So here is the improved code as a component: […]

  • My CakePHP User/Permission Management System part 1 « job’s cry

    […] The Permission Model is simplified by the fact that permission are either 1 or 0. There are no levels, it’s either can or can’t. Development was aided by a year old post from Daniel Hofstetter, the cakeBaker himself: How to list all controllers. […]

  • job’s cry » My CakePHP User/Permission Management System part 1

    […] The Permission Model is simplified by the fact that permission are either 1 or 0. There are no levels, it’s either can or can’t. Development was aided by a year old post from Daniel Hofstetter, the cakeBaker himself: How to list all controllers. […]

  • Jej

    Hi,

    Thanks for this hack, very useful for me.

    I noticed that the _private _functions() are returned as controller functions. That’s not correct I think. Here is a small patch for this :

    $actions = get_class_methods($className);
    + foreach($actions as $k => $v)
    + if ($v{0} == ‘_’) unset($actions[$k]);
    $parentActions = get_class_methods(‘AppController’);

    Bye,
    J.

  • Jej

    Hi again,

    Here is a modified version compatible with cake 1.2 :

    $v)
    if ($v{0} == ‘_’) unset($actions[$k]);
    $parentActions = get_class_methods(‘AppController’);
    $controllersList[$controller] = array_diff($actions, $parentActions);
    }

    return $controllersList;
    }
    }

    ?>

    Bye,
    J.

  • cakebaker

    @Jej: Thanks for your patch, I modified the article accordingly.

  • Jej

    Hi cakebaker,

    Thanks for the update. You can delete comment February 02, 2008 at 20:06, it was a mistake (the first submit didn’t appear)

    Cheers,
    Jej

  • cakebaker

    @Jej: Ok, comment is now deleted.

  • Chris Brinker

    After the $file = CONTROLLERS.$fileName; You may want to put a check for file existence, just in case a controller file is not there.

    $file = CONTROLLERS.$fileName;
    if(!file_exists($file)) continue; //Just in case
    require_once($file);

  • cakebaker

    @Chris: Thanks for your comment!

    I’m not sure, if that’s really necessary, as Configure::listObjects(‘controller’); gets the names of the controllers from the file system (at least if there is no caching).

  • Raymond

    I think you need to use
    $fileName = Inflector::underscore($controller).’_controller.php’;
    instead of
    $fileName = strtolower($controller).’_controller.php’;

    because controllers like WorkingHours have the filename working_hours_controller.php instead of workinghours_controller.php

  • cakebaker

    @Raymond: Yes, you are right. Thanks for the hint, it is now fixed in the article.

  • Recent URLs tagged Controllers - Urlrecorder

    […] Recent public urls tagged “controllers” → Comment on How to list all controllers by Raymond […]

  • Maxim Tsyngaev

    Hi cakebaker,

    If Pages controller not exist in APP/controllers path then i have a problem (error message “No such file or directory: cake/app/contollers/pages_controller.php”)

    Here is a small patch for this:

    ==    function get() {
    ++        $paths=array();
    ==        $controllerClasses = Configure::listObjects('controller', &$paths);
    
    ++        $inc_paths = explode(":",ini_get('include_path'));
    ++        ini_set('include_path', implode(":",array_merge(array_diff($paths, $inc_paths), $inc_paths)));
    ...
    ==             $fileName = Inflector::underscore($controller) .'_controller.php';
    --              $file = CONTROLLERS.$fileName;
    --              require_once($file);
    ++            require_once($fileName);
    ==            $className = $controller . 'Controller';

    P.S. Sorry, I speak English but very badly.

    Best regards,
    Maxim

  • Maxim Tsyngaev

    Oops! What is this? I don’t known.

    == function get() {
    ++ $paths=array();
    == $controllerClasses = Configure::listObjects(‘controller’, &$paths);

    ++ $inc_paths = explode(“:”,ini_get(‘include_path’));
    ++ ini_set(‘include_path’, implode(“:”,array_merge(array_diff($paths, $inc_paths), $inc_paths)));

    == $fileName = Inflector::underscore($controller) .’_controller.php’;
    — $file = CONTROLLERS.$fileName;
    — require_once($file);
    ++ require_once($fileName);
    == $className = $controller . ‘Controller’;

  • cakebaker

    @Maxim: Thanks for your comment and your patch, I applied it in the article.

    I’m sorry that your comment wasn’t shown correctly, somehow the plugin I use to format source code ran amok… Anyway, your comment is now fixed.

    PS: You do not have to apologize for your English skills, there is nothing wrong with being a learner ;-)

  • chrispie

    its better to use

    $Configure = &Configure::getInstance();
    	foreach($Configure->listObjects('controller') as $controller){ }

    for getting a list of all controller

  • cakebaker

    @chrispie: Hm, and what is the advantage of this approach?

  • Nath

    Thanks – perfect for what I need! However:

    $includePaths = explode(':', ini_get('include_path');
    

    is missing a parentheses:

    $includePaths = explode(':', ini_get('include_path'));
    

    Thanks

  • cakebaker

    @Nath: Thanks, it is fixed now.

  • cetver

    alternative:

    function get_cv() { //get_controllers_actions
    		$result = array();
    		$views  = array();
    		
    		$controllers_folder = new Folder( APP . 'controllers' );
    		$controllers = $controllers_folder->find('.*_controller\.php');
    		foreach( $controllers as $controller ) {
    			$controller_name = substr($controller, 0, strpos($controller, '_'));
    			if ( $controller_name !== 'app' ) {
    				$actions_folder = new Folder( APP . 'views' . DIRECTORY_SEPARATOR . $controller_name );
    				$actions = $actions_folder->find('.*\.ctp');
    				foreach( $actions as $action ) {
    					$action_name = substr($action, 0, strpos($action, '.'));					
    					array_push($views, $action_name);
    				}
    				$result[$controller_name] = $views;
    			}
    		}
    		return $result;
    	}
  • cetver

    small fix:
    $controller_name = substr($controller, 0, strpos($controller, '_controller'));

  • cetver
    //and final component :)
    <?php
    
    class ControllerListComponent extends Object {
    	function get() {
    		$result = array();
    		$controllers_folder = new Folder( APP . 'controllers' );
    		$controllers = $controllers_folder->find('.*_controller\.php');
    		foreach( $controllers as $controller ) {
    			$views  = array();
    			$controller_name = substr($controller, 0, strpos($controller, '_controller'));
    			if ( $controller_name !== 'app' ) {
    				$actions_folder = new Folder( APP . 'views' . DIRECTORY_SEPARATOR . $controller_name );
    				$actions = $actions_folder->find('.*\.ctp');
    				foreach( $actions as $action ) {
    					$action_name = substr($action, 0, strpos($action, '.'));					
    					array_push($views, $action_name);
    				}
    				$result[$controller_name] = $views;
    			}
    		}
    		return $result;
    	}
    }
    
    ?>
  • cakebaker

    @cetver: Thanks for your component!

    However, there is a problem with your approach to detect the action names. It will only find actions with views…

  • Andrew K

    Just wanted to point out that this code will not work for controllers that are not in the main controller directory (e.g. app/controllers/). I have some controllers in a sub-directory that are not getting picked up. I added that extra folder to my bootstrap config and this code errored out saying that the file could not be found, because it was looking only in the main controllers directory.

    I’d recommend changing:

    $fileName = Inflector::underscore($controller).'_controller.php';
                    require_once(CONTROLLERS.$fileName);

    to
    App::import('Controller', $controller);

    That way Cake will work it’s magic to find the file even if it’s in an secondary directory.

    P.S. I’ve only done this in version 1.2, but I have a feeling it should work in later versions.

  • cakebaker

    @Andrew: Thanks for your fix, I modified the code accordingly.

  • Come ottenere una lista di tutti i componenti e relative actions | Luizz

    […] http://cakebaker.42dh.com/2006/07/21/how-to-list-all-controllers/ Bookmark It Hide Sites $$('div.d380').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); […]

  • Controller List Component | CakePHP Desk

    […] http://cakebaker.42dh.com/2006/07/21/how-to-list-all-controllers/ Articoli ← Persistent Pagination Leave a comment0 […]

  • Finding all application Controllers in CakePHP (v1.3.x) - mysiteonline™

    […] Automatically load all controllers and actions into ACO tables for ACL with a CakePHP Task How to list all controllers Geschrieben von Brendon Kozlowski Comments (0) Trackbacks (0) Sie können einen Kommentar […]

  • Finding all application Controllers in CakePHP (v1.3.x) | Tech Info....

    […] Other useful links (check version compatibility in these resources): Quick dessert: List all controllers of a CakePHP application Automatically load all controllers and actions into ACO tables for ACL with a CakePHP Task How to list all controllers […]

  • List all controllers in Cakephp 2

    […] I needed to list all the Controllers of an Cakephp 2 application. I searched the webz and found an old article that got me started. The original article with code is here: http://cakebaker.42dh.com/2006/07/21/how-to-list-all-controllers/. […]

  • Richard@Home

    If you need this to work in CakePHP 2, I’ve blogged an alternative solution:

    http://richardathome.com/blog/cakephp-2-get-all-public-methods-controller

    Hope you find this useful :-)

  • URL

    … [Trackback]

    […] Read More: cakebaker.42dh.com/2006/07/21/how-to-list-all-controllers/ […]

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License