Свежайшие Пирожки от CakePHP по-русски

Полнейшее руководство CakePHP 1.2 на русском языке, горячие новости и полезные статьи

An Automated tool for creating ACOs

As mentioned before, there is no pre-built way to input all of our controllers and actions into the Acl. However, we all hate doing repetitive things like typing in what could be hundreds of actions in a large application. I've whipped up an automated function to build my Aco table. This function will look at every controller in your application. It will add any non-private, non Controller methods to the Acl table, nicely nested underneath the the owning controller. You can add and run this in your AppController or any controller for that matter, just be sure to remove it before putting your application into production.

Простой текст
  1. /**
  2. * Rebuild the Acl based on the current controllers in the application
  3. *
  4. * @return void
  5. */
  6. function buildAcl() {
  7. $log = array();
  8. $aco =& $this->Acl->Aco;
  9. $root = $aco->node('controllers');
  10. if (!$root) {
  11. $aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers'));
  12. $root = $aco->save();
  13. $root['Aco']['id'] = $aco->id;
  14. $log[] = 'Created Aco node for controllers';
  15. } else {
  16. $root = $root[0];
  17. }
  18. App::import('Core', 'File');
  19. $Controllers = Configure::listObjects('controller');
  20. $appIndex = array_search('App', $Controllers);
  21. if ($appIndex !== false ) {
  22. unset($Controllers[$appIndex]);
  23. }
  24. $baseMethods = get_class_methods('Controller');
  25. $baseMethods[] = 'buildAcl';
  26. // look at each controller in app/controllers
  27. foreach ($Controllers as $ctrlName) {
  28. App::import('Controller', $ctrlName);
  29. $ctrlclass = $ctrlName . 'Controller';
  30. $methods = get_class_methods($ctrlclass);
  31. // find / make controller node
  32. $controllerNode = $aco->node('controllers/'.$ctrlName);
  33. if (!$controllerNode) {
  34. $aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $ctrlName));
  35. $controllerNode = $aco->save();
  36. $controllerNode['Aco']['id'] = $aco->id;
  37. $log[] = 'Created Aco node for '.$ctrlName;
  38. } else {
  39. $controllerNode = $controllerNode[0];
  40. }
  41. //clean the methods. to remove those in Controller and private actions.
  42. foreach ($methods as $k => $method) {
  43. if (strpos($method, '_', 0) === 0) {
  44. unset($methods[$k]);
  45. continue;
  46. }
  47. if (in_array($method, $baseMethods)) {
  48. unset($methods[$k]);
  49. continue;
  50. }
  51. $methodNode = $aco->node('controllers/'.$ctrlName.'/'.$method);
  52. if (!$methodNode) {
  53. $aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method));
  54. $methodNode = $aco->save();
  55. $log[] = 'Created Aco node for '. $method;
  56. }
  57. }
  58. }
  59. debug($log);
  60. }

You might want to keep this function around as it will add new ACO's for all of the controllers & actions that are in your application any time you run it. It does not remove nodes for actions that no longer exist though. Now that all the heavy lifting is done, we need to set up some permissions, and remove the code that disabled AuthComponent earlier.

Now, once you get this working, you may notice that you have trouble accessing any plugins that you may be using. The trick to automating the controller ACOs for plugins, is that the App::import needs to follow the plugin naming convention of PluginName.PluginControllerName.

So what we need is a function that will give us a list of plugin controller names, and import them in the same way we did in the code above for the regular controllers. The function below will do just that:

Простой текст
  1. /**
  2. * Get the names of the plugin controllers ...
  3. *
  4. * This function will get an array of the plugin controller names, and
  5. * also makes sure the controllers are available for us to get the
  6. * method names by doing an App::import for each plugin controller.
  7. *
  8. * @return array of plugin names.
  9. *
  10. */
  11. function _get_plugin_controller_names(){
  12. App::import('Core', 'File', 'Folder');
  13. $paths = Configure::getInstance();
  14. $folder =& new Folder();
  15. // Change directory to the plugins
  16. $folder->cd(APP.'plugins');
  17. // Get a list of the files that have a file name that ends
  18. // with controller.php
  19. $files = $folder->findRecursive('.*_controller\.php');
  20. // Get the list of plugins
  21. $Plugins = Configure::listObjects('plugin');
  22. // Loop through the controllers we found int the plugins directory
  23. foreach($files as $f => $fileName)
  24. {
  25. // Get the base file name
  26. $file = basename($fileName);
  27. // Get the controller name
  28. $file = Inflector::camelize(substr($file, 0, strlen($file)-strlen('_controller.php')));
  29. // Loop through the plugins
  30. foreach($Plugins as $pluginName){
  31. if (preg_match('/^'.$pluginName.'/', $file)){
  32. // First get rid of the App controller for the plugin
  33. // We do this because the app controller is never called
  34. // directly ...
  35. if (preg_match('/^'.$pluginName.'App/', $file)){
  36. unset($files[$f]);
  37. } else {
  38. if (!App::import('Controller', $pluginName.'.'.$file))
  39. {
  40. debug('Error importing '.$file.' for plugin '.$pluginName);
  41. }
  42. /// Now prepend the Plugin name ...
  43. // This is required to allow us to fetch the method names.
  44. $files[$f] = $file;
  45. }
  46. break;
  47. }
  48. }
  49. }
  50. return $files;
  51. }

You can then either modify the original code to include the plugin controllers by merging them with the list you got (place this before the foreach loop):

Простой текст
  1. $Plugins = $this->_get_plugin_controller_names();
  2. $Controllers = array_merge($Controllers, $Plugins);