├── .gitignore ├── .travis.yml ├── Console └── Command │ └── AclExtrasShell.php ├── Lib └── AclExtras.php ├── README.md ├── Test ├── Case │ ├── AllTestsTest.php │ └── Lib │ │ └── AclExtrasTest.php └── test_controllers.php └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - 7.0 8 | 9 | env: 10 | - CAKE_VERSION=2.x 11 | 12 | install: 13 | - git clone git://github.com/cakephp/cakephp ../cakephp && cd ../cakephp && git checkout $CAKE_VERSION 14 | - cp -R ../acl_extras plugins/AclExtras 15 | - chmod -R 777 ../cakephp/app/tmp 16 | - sh -c "composer require 'phpunit/phpunit=3.7.33'" 17 | - sh -c "ln -s ./vendor/phpunit/phpunit/PHPUnit ../cakephp/vendors/PHPUnit" 18 | 19 | before_script: 20 | - sh -c "mysql -e 'CREATE DATABASE cakephp_test;'" 21 | - echo " 'Database/Mysql', 25 | 'database' => 'cakephp_test', 26 | 'host' => '0.0.0.0', 27 | 'login' => 'travis', 28 | 'persistent' => false, 29 | ); 30 | }" > ../cakephp/app/Config/database.php 31 | 32 | script: 33 | - ./lib/Cake/Console/cake test AclExtras AllTests --stderr 34 | 35 | notifications: 36 | email: false 37 | -------------------------------------------------------------------------------- /Console/Command/AclExtrasShell.php: -------------------------------------------------------------------------------- 1 | 13 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 14 | */ 15 | App::uses('AppShell', 'Console/Command'); 16 | App::uses('AclExtras', 'AclExtras.Lib'); 17 | 18 | /** 19 | * Shell for ACO extras 20 | * 21 | * @package acl_extras 22 | * @subpackage acl_extras.Console.Command 23 | */ 24 | class AclExtrasShell extends AppShell { 25 | 26 | /** 27 | * Contains arguments parsed from the command line. 28 | * 29 | * @var array 30 | * @access public 31 | */ 32 | public $args; 33 | 34 | /** 35 | * AclExtras instance 36 | */ 37 | public $AclExtras; 38 | 39 | /** 40 | * Constructor 41 | */ 42 | public function __construct($stdout = null, $stderr = null, $stdin = null) { 43 | parent::__construct($stdout, $stderr, $stdin); 44 | $this->AclExtras = new AclExtras(); 45 | } 46 | 47 | /** 48 | * Start up And load Acl Component / Aco model 49 | * 50 | * @return void 51 | **/ 52 | public function startup() { 53 | parent::startup(); 54 | $this->AclExtras->startup(); 55 | $this->AclExtras->Shell = $this; 56 | } 57 | 58 | /** 59 | * Sync the ACO table 60 | * 61 | * @return void 62 | **/ 63 | public function aco_sync() { 64 | $this->AclExtras->aco_sync($this->params); 65 | } 66 | 67 | /** 68 | * Updates the Aco Tree with new controller actions. 69 | * 70 | * @return void 71 | **/ 72 | public function aco_update() { 73 | $this->AclExtras->aco_update($this->params); 74 | return true; 75 | } 76 | 77 | public function getOptionParser() { 78 | $plugin = array( 79 | 'short' => 'p', 80 | 'help' => __('Plugin to process'), 81 | ); 82 | return parent::getOptionParser() 83 | ->description(__("Better manage, and easily synchronize you application's ACO tree")) 84 | ->addSubcommand('aco_update', array( 85 | 'parser' => array( 86 | 'options' => compact('plugin'), 87 | ), 88 | 'help' => __('Add new ACOs for new controllers and actions. Does not remove nodes from the ACO table.') 89 | ))->addSubcommand('aco_sync', array( 90 | 'parser' => array( 91 | 'options' => compact('plugin'), 92 | ), 93 | 'help' => __('Perform a full sync on the ACO table.' . 94 | 'Will create new ACOs or missing controllers and actions.' . 95 | 'Will also remove orphaned entries that no longer have a matching controller/action') 96 | ))->addSubcommand('verify', array( 97 | 'help' => __('Verify the tree structure of either your Aco or Aro Trees'), 98 | 'parser' => array( 99 | 'arguments' => array( 100 | 'type' => array( 101 | 'required' => true, 102 | 'help' => __('The type of tree to verify'), 103 | 'choices' => array('aco', 'aro') 104 | ) 105 | ) 106 | ) 107 | ))->addSubcommand('recover', array( 108 | 'help' => __('Recover a corrupted Tree'), 109 | 'parser' => array( 110 | 'arguments' => array( 111 | 'type' => array( 112 | 'required' => true, 113 | 'help' => __('The type of tree to recover'), 114 | 'choices' => array('aco', 'aro') 115 | ) 116 | ) 117 | ) 118 | )); 119 | } 120 | 121 | /** 122 | * Verify a Acl Tree 123 | * 124 | * @param string $type The type of Acl Node to verify 125 | * @access public 126 | * @return void 127 | */ 128 | public function verify() { 129 | $this->AclExtras->args = $this->args; 130 | return $this->AclExtras->verify(); 131 | } 132 | /** 133 | * Recover an Acl Tree 134 | * 135 | * @param string $type The Type of Acl Node to recover 136 | * @access public 137 | * @return void 138 | */ 139 | public function recover() { 140 | $this->AclExtras->args = $this->args; 141 | $this->AclExtras->recover(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Lib/AclExtras.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 12 | */ 13 | 14 | App::uses('Controller', 'Controller'); 15 | App::uses('ComponentCollection', 'Controller'); 16 | App::uses('AclComponent', 'Controller/Component'); 17 | App::uses('DbAcl', 'Model'); 18 | App::uses('Shell', 'Console'); 19 | App::uses('CakeObject', 'Core'); 20 | 21 | /** 22 | * Shell for ACO extras 23 | * 24 | * @package acl_extras 25 | * @subpackage acl_extras.Console.Command 26 | */ 27 | class AclExtras extends CakeObject { 28 | 29 | /** 30 | * Contains instance of AclComponent 31 | * 32 | * @var AclComponent 33 | * @access public 34 | */ 35 | public $Acl; 36 | 37 | /** 38 | * Contains arguments parsed from the command line. 39 | * 40 | * @var array 41 | * @access public 42 | */ 43 | public $args; 44 | 45 | /** 46 | * Contains database source to use 47 | * 48 | * @var string 49 | * @access public 50 | */ 51 | public $dataSource = 'default'; 52 | 53 | /** 54 | * Root node name. 55 | * 56 | * @var string 57 | **/ 58 | public $rootNode = 'controllers'; 59 | 60 | /** 61 | * Internal Clean Actions switch 62 | * 63 | * @var boolean 64 | **/ 65 | protected $_clean = false; 66 | 67 | /** 68 | * Start up And load Acl Component / Aco model 69 | * 70 | * @return void 71 | **/ 72 | public function startup($controller = null) { 73 | if (!$controller) { 74 | $controller = new Controller(new CakeRequest()); 75 | } 76 | $collection = new ComponentCollection(); 77 | $this->Acl = new AclComponent($collection); 78 | $this->Acl->startup($controller); 79 | $this->Aco = $this->Acl->Aco; 80 | $this->controller = $controller; 81 | } 82 | 83 | public function out($msg) { 84 | if (!empty($this->controller->Session)) { 85 | $this->controller->Flash->set($msg); 86 | } else { 87 | return $this->Shell->out($msg); 88 | } 89 | } 90 | 91 | public function err($msg) { 92 | if (!empty($this->controller->Session)) { 93 | $this->controller->Flash->set($msg);; 94 | } else { 95 | return $this->Shell->err($msg); 96 | } 97 | } 98 | 99 | /** 100 | * Sync the ACO table 101 | * 102 | * @return void 103 | **/ 104 | public function aco_sync($params = array()) { 105 | $this->_clean = true; 106 | $this->aco_update($params); 107 | } 108 | 109 | /** 110 | * Updates the Aco Tree with new controller actions. 111 | * 112 | * @return void 113 | **/ 114 | public function aco_update($params = array()) { 115 | $root = $this->_checkNode($this->rootNode, $this->rootNode, null); 116 | 117 | if (empty($params['plugin'])) { 118 | $controllers = $this->getControllerList(); 119 | $this->_updateControllers($root, $controllers); 120 | $plugins = CakePlugin::loaded(); 121 | } else { 122 | $plugin = $params['plugin']; 123 | if (!in_array($plugin, App::objects('plugin')) || !CakePlugin::loaded($plugin)) { 124 | $this->err(__('Plugin %s not found or not activated', $plugin)); 125 | return false; 126 | } 127 | $plugins = array($params['plugin']); 128 | } 129 | 130 | foreach ($plugins as $plugin) { 131 | $controllers = $this->getControllerList($plugin); 132 | 133 | $path = $this->rootNode . '/' . $plugin; 134 | $pluginRoot = $this->_checkNode($path, $plugin, $root['Aco']['id']); 135 | $this->_updateControllers($pluginRoot, $controllers, $plugin); 136 | } 137 | $this->out(__('Aco Update Complete')); 138 | return true; 139 | } 140 | 141 | /** 142 | * Updates a collection of controllers. 143 | * 144 | * @param array $root Array or ACO information for root node. 145 | * @param array $controllers Array of Controllers 146 | * @param string $plugin Name of the plugin you are making controllers for. 147 | * @return void 148 | */ 149 | protected function _updateControllers($root, $controllers, $plugin = null) { 150 | $dotPlugin = $pluginPath = $plugin; 151 | if ($plugin) { 152 | $dotPlugin .= '.'; 153 | $pluginPath .= '/'; 154 | } 155 | $appIndex = array_search($plugin . 'AppController', $controllers); 156 | if ($appIndex !== false) { 157 | App::uses($plugin . 'AppController', $dotPlugin . 'Controller'); 158 | unset($controllers[$appIndex]); 159 | } 160 | // look at each controller 161 | foreach ($controllers as $controller) { 162 | App::uses($controller, $dotPlugin . 'Controller'); 163 | $controllerName = preg_replace('/Controller$/', '', $controller); 164 | 165 | $path = $this->rootNode . '/' . $pluginPath . $controllerName; 166 | $controllerNode = $this->_checkNode($path, $controllerName, $root['Aco']['id']); 167 | $this->_checkMethods($controller, $controllerName, $controllerNode, $pluginPath); 168 | } 169 | if ($this->_clean) { 170 | if (!$plugin) { 171 | $controllers = array_merge($controllers, App::objects('plugin', null, false)); 172 | } 173 | $controllerFlip = array_flip($controllers); 174 | 175 | $this->Aco->id = $root['Aco']['id']; 176 | $controllerNodes = $this->Aco->children(null, true); 177 | foreach ($controllerNodes as $ctrlNode) { 178 | $alias = $ctrlNode['Aco']['alias']; 179 | $name = $alias . 'Controller'; 180 | if (!isset($controllerFlip[$name]) && !isset($controllerFlip[$alias])) { 181 | if ($this->Aco->delete($ctrlNode['Aco']['id'])) { 182 | $this->out(__( 183 | 'Deleted %s and all children', 184 | $this->rootNode . '/' . $ctrlNode['Aco']['alias'] 185 | ), 1, Shell::VERBOSE); 186 | } 187 | } 188 | } 189 | } 190 | } 191 | 192 | /** 193 | * Get a list of controllers in the app and plugins. 194 | * 195 | * Returns an array of path => import notation. 196 | * 197 | * @param string $plugin Name of plugin to get controllers for 198 | * @return array 199 | **/ 200 | public function getControllerList($plugin = null) { 201 | if (!$plugin) { 202 | $controllers = App::objects('Controller', null, false); 203 | } else { 204 | $controllers = App::objects($plugin . '.Controller', null, false); 205 | } 206 | return $controllers; 207 | } 208 | 209 | /** 210 | * Check a node for existance, create it if it doesn't exist. 211 | * 212 | * @param string $path 213 | * @param string $alias 214 | * @param int $parentId 215 | * @return array Aco Node array 216 | */ 217 | protected function _checkNode($path, $alias, $parentId = null) { 218 | $node = $this->Aco->node($path); 219 | if (!$node) { 220 | $this->Aco->create(array('parent_id' => $parentId, 'model' => null, 'alias' => $alias)); 221 | $node = $this->Aco->save(); 222 | $node['Aco']['id'] = $this->Aco->id; 223 | $this->out(__('Created Aco node: %s', $path), 1, Shell::VERBOSE); 224 | } else { 225 | $node = $node[0]; 226 | } 227 | return $node; 228 | } 229 | 230 | /** 231 | * Get a list of registered callback methods 232 | */ 233 | protected function _getCallbacks($className) { 234 | $callbacks = array(); 235 | $reflection = new ReflectionClass($className); 236 | if ($reflection->isAbstract()) { 237 | return $callbacks; 238 | } 239 | try { 240 | $method = $reflection->getMethod('implementedEvents'); 241 | } catch (ReflectionException $e) { 242 | return $callbacks; 243 | } 244 | if (version_compare(phpversion(), '5.4', '>=')) { 245 | $object = $reflection->newInstanceWithoutConstructor(); 246 | } else { 247 | $object = unserialize( 248 | sprintf('O:%d:"%s":0:{}', strlen($className), $className) 249 | ); 250 | } 251 | $implementedEvents = $method->invoke($object); 252 | foreach ($implementedEvents as $event => $callable) { 253 | if (is_string($callable)) { 254 | $callbacks[] = $callable; 255 | } 256 | if (is_array($callable) && isset($callable['callable'])) { 257 | $callbacks[] = $callable['callable']; 258 | } 259 | } 260 | return $callbacks; 261 | } 262 | 263 | /** 264 | * Check and Add/delete controller Methods 265 | * 266 | * @param string $controller 267 | * @param array $node 268 | * @param string $plugin Name of plugin 269 | * @return void 270 | */ 271 | protected function _checkMethods($className, $controllerName, $node, $pluginPath = false) { 272 | $excludes = $this->_getCallbacks($className); 273 | $baseMethods = get_class_methods('Controller'); 274 | $actions = get_class_methods($className); 275 | if ($actions == null) { 276 | $this->err(__('Unable to get methods for "%s"', $className)); 277 | return false; 278 | } 279 | $methods = array_diff($actions, $baseMethods); 280 | $methods = array_diff($methods, $excludes); 281 | foreach ($methods as $action) { 282 | if (strpos($action, '_', 0) === 0) { 283 | continue; 284 | } 285 | $path = $this->rootNode . '/' . $pluginPath . $controllerName . '/' . $action; 286 | $this->_checkNode($path, $action, $node['Aco']['id']); 287 | } 288 | 289 | if ($this->_clean) { 290 | $actionNodes = $this->Aco->children($node['Aco']['id']); 291 | $methodFlip = array_flip($methods); 292 | foreach ($actionNodes as $action) { 293 | if (!isset($methodFlip[$action['Aco']['alias']])) { 294 | $this->Aco->id = $action['Aco']['id']; 295 | if ($this->Aco->delete()) { 296 | $path = $this->rootNode . '/' . $controllerName . '/' . $action['Aco']['alias']; 297 | $this->out(__('Deleted Aco node: %s', $path), 1, Shell::VERBOSE); 298 | } 299 | } 300 | } 301 | } 302 | return true; 303 | } 304 | 305 | /** 306 | * Verify a Acl Tree 307 | * 308 | * @param string $type The type of Acl Node to verify 309 | * @access public 310 | * @return void 311 | */ 312 | public function verify() { 313 | $type = Inflector::camelize($this->args[0]); 314 | $return = $this->Acl->{$type}->verify(); 315 | if ($return === true) { 316 | $this->out(__('Tree is valid and strong')); 317 | } else { 318 | $this->err(print_r($return, true)); 319 | return false; 320 | } 321 | } 322 | 323 | /** 324 | * Recover an Acl Tree 325 | * 326 | * @param string $type The Type of Acl Node to recover 327 | * @access public 328 | * @return void 329 | */ 330 | public function recover() { 331 | $type = Inflector::camelize($this->args[0]); 332 | $return = $this->Acl->{$type}->recover(); 333 | if ($return === true) { 334 | $this->out(__('Tree has been recovered, or tree did not need recovery.')); 335 | } else { 336 | $this->err(__('Tree recovery failed.')); 337 | return false; 338 | } 339 | } 340 | 341 | } 342 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Acl Extras 2 | 3 | Acl Extras provides a console app that helps you manage DbAcl records more easily. Its main feature and purpose is to make generating Aco nodes for all your controllers and actions easier. It also includes some helper methods for verifying and recovering corrupted trees. 4 | 5 | ## Installation 6 | 7 | Clone the repo or download a tarball and install it into `app/Plugin/AclExtras` or in any of your pluginPaths. 8 | 9 | Then activate the plugin in your app/Config/bootstrap.php file as shown below: 10 | 11 | CakePlugin::load('AclExtras'); 12 | 13 | ## Usage 14 | 15 | You can find a list of commands by running `Console/cake AclExtras.AclExtras -h` from your command line. 16 | 17 | ### Setting up the contorller 18 | 19 | You'll need to configure AuthComponent to use the Actions authorization method. 20 | In your `beforeFilter` add the following: 21 | 22 | $this->Auth->authorize = 'actions'; 23 | $this->Auth->actionPath = 'controllers/'; 24 | 25 | ## Issues 26 | 27 | If you find an issue in the code or want to suggest something, please use the tickets at http://github.com/markstory/acl_extras/issues 28 | 29 | ## License 30 | 31 | Acl Extras is licensed under the MIT license. 32 | -------------------------------------------------------------------------------- /Test/Case/AllTestsTest.php: -------------------------------------------------------------------------------- 1 | addTestDirectoryRecursive(App::pluginPath('AclExtras') . 'Test' . DS . 'Case' . DS); 15 | 16 | return $suite; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Test/Case/Lib/AclExtrasTest.php: -------------------------------------------------------------------------------- 1 | 17 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 18 | */ 19 | App::uses('Shell', 'Console'); 20 | App::uses('Aco', 'Model'); 21 | App::uses('AclComponent', 'Controller/Component'); 22 | App::uses('Controller', 'Controller'); 23 | App::uses('AclExtras', 'AclExtras.Lib'); 24 | 25 | 26 | //Mock::generate('Aco', 'MockAco', array('children', 'verify', 'recover')); 27 | 28 | //import test controller class names. 29 | include dirname(dirname(dirname(__FILE__))) . DS . 'test_controllers.php'; 30 | 31 | /** 32 | * AclExtras Shell Test case 33 | * 34 | * @package acl_extras.tests.cases 35 | */ 36 | class AclExtrasShellTestCase extends CakeTestCase { 37 | 38 | public $fixtures = array('core.aco', 'core.aro', 'core.aros_aco'); 39 | 40 | /** 41 | * startTest 42 | * 43 | * @return void 44 | * @access public 45 | */ 46 | public function setUp() { 47 | parent::setUp(); 48 | Configure::write('Acl.classname', 'DbAcl'); 49 | Configure::write('Acl.database', 'test'); 50 | 51 | $this->Task = $this->getMock( 52 | 'AclExtras', 53 | array('in', 'out', 'hr', 'createFile', 'error', 'err', 'clear', 'getControllerList') 54 | ); 55 | } 56 | 57 | /** 58 | * end the test 59 | * 60 | * @return void 61 | **/ 62 | public function tearDown() { 63 | parent::tearDown(); 64 | unset($this->Task); 65 | } 66 | 67 | /** 68 | * test recover 69 | * 70 | * @return void 71 | **/ 72 | public function testRecover() { 73 | $this->Task->startup(); 74 | $this->Task->args = array('Aco'); 75 | $this->Task->Acl->Aco = $this->getMock('Aco', array('recover')); 76 | $this->Task->Acl->Aco->expects($this->once()) 77 | ->method('recover') 78 | ->will($this->returnValue(true)); 79 | 80 | $this->Task->expects($this->once()) 81 | ->method('out') 82 | ->with($this->matchesRegularExpression('/recovered/')); 83 | 84 | $this->Task->recover(); 85 | } 86 | 87 | /** 88 | * test verify 89 | * 90 | * @return void 91 | **/ 92 | public function testVerify() { 93 | $this->Task->startup(); 94 | $this->Task->args = array('Aco'); 95 | $this->Task->Acl->Aco = $this->getMock('Aco', array('verify')); 96 | $this->Task->Acl->Aco->expects($this->once()) 97 | ->method('verify') 98 | ->will($this->returnValue(true)); 99 | 100 | $this->Task->expects($this->once()) 101 | ->method('out') 102 | ->with($this->matchesRegularExpression('/valid/')); 103 | 104 | $this->Task->verify(); 105 | } 106 | 107 | /** 108 | * test startup 109 | * 110 | * @return void 111 | **/ 112 | public function testStartup() { 113 | $this->assertEqual($this->Task->Acl, null); 114 | $this->Task->startup(); 115 | $this->assertInstanceOf('AclComponent', $this->Task->Acl); 116 | } 117 | 118 | /** 119 | * clean fixtures and setup mock 120 | * 121 | * @return void 122 | **/ 123 | protected function _cleanAndSetup() { 124 | $tableName = $this->db->fullTableName('acos'); 125 | $this->db->execute('DELETE FROM ' . $tableName); 126 | $this->Task->expects($this->any()) 127 | ->method('getControllerList') 128 | ->will($this->returnValue(array('CommentsController', 'PostsController', 'BigLongNamesController'))); 129 | 130 | $this->Task->startup(); 131 | } 132 | /** 133 | * Test aco_update method. 134 | * 135 | * @return void 136 | **/ 137 | public function testAcoUpdate() { 138 | $this->_cleanAndSetup(); 139 | $this->Task->aco_update(); 140 | 141 | $Aco = $this->Task->Acl->Aco; 142 | 143 | $result = $Aco->node('controllers/Comments'); 144 | $this->assertEqual($result[0]['Aco']['alias'], 'Comments'); 145 | 146 | $result = $Aco->children($result[0]['Aco']['id']); 147 | $this->assertEqual(count($result), 3); 148 | $this->assertEqual($result[0]['Aco']['alias'], 'add'); 149 | $this->assertEqual($result[1]['Aco']['alias'], 'index'); 150 | $this->assertEqual($result[2]['Aco']['alias'], 'delete'); 151 | 152 | $result = $Aco->node('controllers/Posts'); 153 | $this->assertEqual($result[0]['Aco']['alias'], 'Posts'); 154 | $result = $Aco->children($result[0]['Aco']['id']); 155 | $this->assertEqual(count($result), 3); 156 | 157 | $result = $Aco->node('controllers/BigLongNames'); 158 | $this->assertEqual($result[0]['Aco']['alias'], 'BigLongNames'); 159 | $result = $Aco->children($result[0]['Aco']['id']); 160 | $this->assertEqual(count($result), 4); 161 | } 162 | 163 | /** 164 | * test syncing of Aco records 165 | * 166 | * @return void 167 | **/ 168 | public function testAcoSyncRemoveMethods() { 169 | $this->_cleanAndSetup(); 170 | $this->Task->aco_update(); 171 | 172 | $Aco = $this->Task->Acl->Aco; 173 | $Aco->cacheQueries = false; 174 | 175 | $result = $Aco->node('controllers/Comments'); 176 | $new = array( 177 | 'parent_id' => $result[0]['Aco']['id'], 178 | 'alias' => 'some_method' 179 | ); 180 | $Aco->create($new); 181 | $Aco->save(); 182 | $children = $Aco->children($result[0]['Aco']['id']); 183 | $this->assertEqual(count($children), 4); 184 | 185 | $this->Task->aco_sync(); 186 | $children = $Aco->children($result[0]['Aco']['id']); 187 | $this->assertEqual(count($children), 3); 188 | 189 | $method = $Aco->node('controllers/Commments/some_method'); 190 | $this->assertFalse($method); 191 | } 192 | 193 | /** 194 | * test adding methods with aco_update 195 | * 196 | * @return void 197 | **/ 198 | public function testAcoUpdateAddingMethods() { 199 | $this->_cleanAndSetup(); 200 | $this->Task->aco_update(); 201 | 202 | $Aco = $this->Task->Acl->Aco; 203 | $Aco->cacheQueries = false; 204 | 205 | $result = $Aco->node('controllers/Comments'); 206 | $children = $Aco->children($result[0]['Aco']['id']); 207 | $this->assertEqual(count($children), 3); 208 | 209 | $Aco->delete($children[0]['Aco']['id']); 210 | $Aco->delete($children[1]['Aco']['id']); 211 | $this->Task->aco_update(); 212 | 213 | $children = $Aco->children($result[0]['Aco']['id']); 214 | $this->assertEqual(count($children), 3); 215 | } 216 | 217 | /** 218 | * test adding controllers on sync 219 | * 220 | * @return void 221 | **/ 222 | public function testAddingControllers() { 223 | $this->_cleanAndSetup(); 224 | $this->Task->aco_update(); 225 | 226 | $Aco = $this->Task->Acl->Aco; 227 | $Aco->cacheQueries = false; 228 | 229 | $result = $Aco->node('controllers/Comments'); 230 | $Aco->delete($result[0]['Aco']['id']); 231 | 232 | $this->Task->aco_update(); 233 | $newResult = $Aco->node('controllers/Comments'); 234 | $this->assertNotEqual($newResult[0]['Aco']['id'], $result[0]['Aco']['id']); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /Test/test_controllers.php: -------------------------------------------------------------------------------- 1 | =5.2.17", 21 | "cakephp/cakephp": ">=2.4 <3.0", 22 | "composer/installers": "*" 23 | } 24 | } 25 | --------------------------------------------------------------------------------