├── .editorconfig ├── .semver ├── .travis.yml ├── CONTRIBUTING.md ├── Console └── Command │ ├── AdminShell.php │ └── Task │ ├── AdminControllerTask.php │ ├── AdminModelTask.php │ ├── AdminTemplateTask.php │ └── AdminViewTask.php ├── LICENSE.txt ├── Lib ├── CakeAdmin.php ├── CakeAdminActionConfig.php └── Templates │ ├── Action │ ├── Add │ │ ├── AddCakeAdminConfig.php │ │ ├── Controller │ │ │ └── actions.ctp │ │ ├── Model │ │ │ └── methods.ctp │ │ └── View │ │ │ └── add.ctp │ ├── Changelog │ │ ├── ChangelogCakeAdminConfig.php │ │ ├── Controller │ │ │ └── actions.ctp │ │ ├── Model │ │ │ └── methods.ctp │ │ └── View │ │ │ └── changelog.ctp │ ├── Delete │ │ ├── Controller │ │ │ └── actions.ctp │ │ ├── DeleteCakeAdminConfig.php │ │ ├── Model │ │ │ └── methods.ctp │ │ └── View │ │ │ └── delete.ctp │ ├── Edit │ │ ├── Controller │ │ │ └── actions.ctp │ │ ├── EditCakeAdminConfig.php │ │ ├── Model │ │ │ └── methods.ctp │ │ └── View │ │ │ └── edit.ctp │ ├── History │ │ ├── Controller │ │ │ └── actions.ctp │ │ ├── HistoryCakeAdminConfig.php │ │ ├── Model │ │ │ └── methods.ctp │ │ └── View │ │ │ └── history.ctp │ ├── Index │ │ ├── Controller │ │ │ └── actions.ctp │ │ ├── IndexCakeAdminConfig.php │ │ ├── Model │ │ │ └── methods.ctp │ │ └── View │ │ │ └── index.ctp │ └── View │ │ ├── Controller │ │ └── actions.ctp │ │ ├── Model │ │ └── methods.ctp │ │ ├── View │ │ └── view.ctp │ │ └── ViewCakeAdminConfig.php │ ├── Class │ ├── AppController.ctp │ ├── AppModel.ctp │ ├── Controller.ctp │ └── Model.ctp │ └── Misc │ ├── Makefile │ ├── background-noise.gif │ ├── background.png │ ├── cake.admin.generic.ctp │ ├── cake.admin.generic.min.ctp │ ├── flash │ ├── error.ctp │ ├── info.ctp │ ├── notice.ctp │ └── success.ctp │ ├── layout.default.ctp │ └── less │ ├── 01_reset.less │ ├── 02_general.less │ ├── 03_layout.less │ ├── 04_scaffolding.less │ ├── 05_navigation.less │ ├── 06_tables.less │ ├── 07_paging.less │ ├── 08_definition.less │ ├── 09_forms.less │ ├── 10_notifications.less │ ├── 11_buttons.less │ ├── bootstrap.less │ └── preboot.less ├── README.markdown ├── Test ├── Case │ ├── AllCakeAdminTest.php │ └── Lib │ │ └── CakeAdminTest.php └── Fixture │ └── PostFixture.php └── composer.json /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = false 5 | 6 | [*] 7 | indent_style = tab 8 | indent_size = 2 9 | charset = "utf-8" 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.yml] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.semver: -------------------------------------------------------------------------------- 1 | --- 2 | :major: 1 3 | :minor: 0 4 | :patch: 0 5 | :special: '' 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | env: 9 | global: 10 | - REPO_NAME="cakephp-admin" 11 | - PLUGIN_NAME=CakeAdmin 12 | matrix: 13 | - DB=mysql CAKE_VERSION=master 14 | - DB=mysql CAKE_VERSION=2.5 15 | 16 | matrix: 17 | include: 18 | - php: 5.4 19 | env: 20 | - DB=mysql CAKE_VERSION=master COVERALLS=1 21 | - php: 5.4 22 | env: 23 | - DB=mysql CAKE_VERSION=master PHPCS=1 24 | 25 | before_script: 26 | - cd .. 27 | - git clone git://github.com/cakephp/cakephp.git --branch $CAKE_VERSION --depth 1 28 | - cd cakephp/app 29 | - git clone https://github.com/FriendsOfCake/travis.git 30 | - ./travis/before_script.sh 31 | 32 | script: 33 | - ./travis/script.sh 34 | 35 | after_success: 36 | - ./travis/after_success.sh 37 | 38 | notifications: 39 | email: false 40 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We'd love to welcome your contributions. There are several ways to help out: 4 | * Create a ticket in GitHub, if you have found a bug 5 | * Write testcases for open bug tickets 6 | * Write patches for open bug/feature tickets, preferably with testcases included 7 | * Contribute to the [documentation](https://github.com/josegonzalez/cakephp-admin/tree/gh-pages) 8 | 9 | There are a few guidelines that we need contributors to follow so that we have a 10 | chance of keeping on top of things. 11 | 12 | ## Getting Started 13 | 14 | * Make sure you have a [GitHub account](https://github.com/signup/free) 15 | * Submit a ticket for your issue, assuming one does not already exist. 16 | * Clearly describe the issue including steps to reproduce when it is a bug. 17 | * Make sure you fill in the earliest version that you know has the issue. 18 | * Fork the repository on GitHub. 19 | 20 | ## Making Changes 21 | 22 | * Create a topic branch from where you want to base your work. 23 | * This is usually the develop branch 24 | * To quickly create a topic branch based on master; `git branch 25 | master/my_contribution master` then checkout the new branch with `git 26 | checkout master/my_contribution`. Better avoid working directly on the 27 | `master` branch, to avoid conflicts if you pull in updates from origin. 28 | * Make commits of logical units. 29 | * Check for unnecessary whitespace with `git diff --check` before committing. 30 | * Use descriptive commit messages and reference the #ticket number 31 | * Core testcases should continue to pass. You can run tests locally or enable 32 | [travis-ci](https://travis-ci.org/) for your fork, so all tests and codesniffs 33 | will be executed. 34 | * Your work should apply the CakePHP coding standards. 35 | 36 | ## Which branch to base the work 37 | 38 | * Bugfix branches will be based on develop branch. 39 | * New features that are backwards compatible will be based on develop branch 40 | * New features or other non-BC changes will go in the next major release branch. 41 | 42 | ## Submitting Changes 43 | 44 | * Push your changes to a topic branch in your fork of the repository. 45 | * Submit a pull request to the repository with the correct target branch. 46 | 47 | ## Testcases and codesniffer 48 | 49 | Tests require [PHPUnit](http://www.phpunit.de/manual/current/en/installation.html) 50 | 3.5 or higher. To run the testcases locally use the following command: 51 | 52 | ./lib/Cake/Console/cake test CakeAdmin AllCakeAdmin 53 | 54 | To run the sniffs for CakePHP coding standards 55 | 56 | phpcs -p --extensions=php --standard=CakePHP ./app/Plugin/CakeAdmin 57 | 58 | Check the [cakephp-codesniffer](https://github.com/cakephp/cakephp-codesniffer) 59 | repository to setup the CakePHP standard. The README contains installation info 60 | for the sniff and phpcs. 61 | 62 | 63 | # Additional Resources 64 | 65 | * [CakePHP coding standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html) 66 | * [Bug tracker](https://github.com/josegonzalez/cakephp-admin/issues) 67 | * [General GitHub documentation](https://help.github.com/) 68 | * [GitHub pull request documentation](https://help.github.com/send-pull-requests/) 69 | * #cakephp IRC channel on freenode.org 70 | -------------------------------------------------------------------------------- /Console/Command/AdminShell.php: -------------------------------------------------------------------------------- 1 | templateDir = array(); 56 | $this->templateDir[] = dirname(__FILE__); 57 | $this->templateDir[] = '..'; 58 | $this->templateDir[] = '..'; 59 | $this->templateDir[] = 'Lib'; 60 | $this->templateDir[] = 'Templates'; 61 | $this->templateDir = implode(DS, $this->templateDir); 62 | } 63 | 64 | /** 65 | * Override main 66 | * 67 | */ 68 | public function generate() { 69 | if (!isset($this->params['interactive'])) { 70 | $this->params['interactive'] = false; 71 | } else { 72 | $this->params['interactive'] = true; 73 | } 74 | $this->interactive = $this->params['interactive']; 75 | foreach (array('AdminController', 'AdminModel', 'AdminView') as $task) { 76 | $this->{$task}->interactive = $this->params['interactive']; 77 | } 78 | 79 | // Create the admin object 80 | $files = $this->_find(); 81 | if (!$files) { 82 | $this->error(__('Admin files not found', true)); 83 | } 84 | 85 | $build = 0; 86 | $skipped = 0; 87 | $plugins = array(); 88 | $adminClasses = array(); 89 | foreach ($files as $file) { 90 | // Create an instance of the particular admin class 91 | $className = str_replace('.php', '', $file); 92 | App::uses($className, 'Lib/Admin'); 93 | $admin = new $className(); 94 | 95 | if (!$admin->enabled) { 96 | $skipped++; 97 | continue; 98 | } 99 | 100 | // Check that paths can be written 101 | if (($error = $this->_checkBuild($admin)) !== true) { 102 | $this->err(sprintf('%s for %s', $error, $className)); 103 | continue; 104 | } 105 | 106 | $adminClasses[$file] = $admin; 107 | $plugins[Inflector::underscore($admin->plugin)][] = array( 108 | 'title' => $this->_controllerName($admin->modelName), 109 | 'controller'=> $this->_pluralName($this->_controllerName($admin->modelName)), 110 | 'action' => $admin->redirectTo, 111 | 'adminClass'=> $admin, 112 | ); 113 | } 114 | 115 | $this->_generateApp($plugins); 116 | 117 | foreach ($adminClasses as $file => $admin) { 118 | if (!$this->_create($admin)) { 119 | $this->err(__('Error in creating admin for %s', $file)); 120 | continue; 121 | } 122 | 123 | $build++; 124 | } 125 | 126 | $this->_generateMisc($plugins); 127 | 128 | $fails = count($files) - $skipped - $build; 129 | if ($build == 0) { 130 | $this->out(__('Failed to build admin')); 131 | } 132 | 133 | $this->out(sprintf( 134 | __('Admin successfully built for %s models'), 135 | count($file) 136 | )); 137 | 138 | if ($fails !== 0) { 139 | $this->out(sprintf( 140 | __('Fix all %s errors before regenerating admin'), 141 | $fails 142 | )); 143 | } 144 | } 145 | 146 | /** 147 | * Finds all CakeAdmin files in app/libs/admin 148 | * 149 | * @return array 150 | * @todo test me 151 | */ 152 | public function _find() { 153 | $this->_handler(); 154 | $this->handler->cd(APPLIBS); 155 | $content = $this->handler->read(); 156 | 157 | if (empty($content[0])) { 158 | return false; 159 | } 160 | 161 | if (!in_array('Admin', $content[0])) { 162 | return false; 163 | } 164 | 165 | $this->handler->cd(APPLIBS . 'Admin'); 166 | $content = $this->handler->find('([\w_]+)(.php)'); 167 | 168 | return (empty($content)) ? false : $content; 169 | } 170 | 171 | /** 172 | * Checks that directories are writeable 173 | * 174 | * Checks the 'plugin' prefix class variable 175 | * to ensure that the plugin path, and all 176 | * subpaths, are writeable by the system. 177 | * 178 | * Also ensures that templates are available for 179 | * all actions, plugins, etc 180 | * 181 | * @param CakeAdmin $admin 182 | * @return mixed boolean true if successful, string error message otherwise 183 | * @todo test me 184 | */ 185 | public function _checkBuild($admin) { 186 | $this->_handler(); 187 | $this->handler->cd(APP); 188 | $contents = $this->handler->read(); 189 | 190 | if (!in_array('Plugin', $contents[0])) { 191 | return __("Missing Plugin directory"); 192 | } 193 | 194 | $this->handler->cd(APP . 'Plugin'); 195 | $contents = $this->handler->read(); 196 | $path = APP . 'Plugin' . DS . Inflector::camelize($admin->plugin); 197 | // Recover if the required plugin directory is missing 198 | if (!in_array($admin->plugin, $contents[0])) { 199 | $this->handler->create($path); 200 | } 201 | 202 | $contents = $this->handler->read(); 203 | if (!in_array(Inflector::camelize($admin->plugin), $contents[0])) { 204 | return __("Unable to create path: %s", $path); 205 | } 206 | 207 | // Check all the required MVC directories 208 | $required = array('Controller', 'Model', 'View'); 209 | $this->handler->cd($path); 210 | $content = $this->handler->read(); 211 | 212 | foreach ($required as $directory) { 213 | if (!in_array($directory, $content[0])) { 214 | $this->handler->create($path . DS . $directory); 215 | } 216 | $content = $this->handler->read(); 217 | 218 | if (!in_array($directory, $content[0])) { 219 | return __('Missing directory: %s', $directory); 220 | } 221 | } 222 | 223 | // Check that the directories and files are writeable by shell 224 | foreach ($required as $directory) { 225 | if (!$this->handler->chmod($path . DS .$directory)) { 226 | return __('Directory not writeable: %s', $directory); 227 | } 228 | } 229 | 230 | return true; 231 | } 232 | 233 | /** 234 | * Compiles the admin section for a particular model 235 | * 236 | * @param CakeAdmin $admin 237 | * @return boolean 238 | * @todo test me 239 | **/ 240 | public function _create($admin) { 241 | if (!$this->AdminModel->generate($admin)) { 242 | $this->out(); 243 | $this->out(__('Failed to generate %s Model', $admin->modelName)); 244 | $this->out(); 245 | return false; 246 | } 247 | if (!$this->AdminController->generate($admin)) { 248 | $this->out(); 249 | $this->out(__('Failed to generate %s Controller', 250 | $this->_controllerName($admin->modelName) 251 | )); 252 | $this->out(); 253 | return false; 254 | } 255 | if (!$this->AdminView->generate($admin)) { 256 | $this->out(); 257 | $this->out(__('Failed to generate %s Views', 258 | $this->_controllerName($admin->modelName) 259 | )); 260 | $this->out(); 261 | return false; 262 | } 263 | return true; 264 | } 265 | 266 | /** 267 | * Generates App classes for each plugin 268 | * 269 | * @return boolean 270 | * @author Jose Diaz-Gonzalez 271 | **/ 272 | public function _generateApp($plugins) { 273 | $generated = array(); 274 | 275 | foreach ($plugins as $plugin => $cakeAdmins) { 276 | if (in_array($plugin, $generated)) continue; 277 | $generated[] = $plugin; 278 | 279 | $admin = current($cakeAdmins); 280 | $admin = $admin['adminClass']; 281 | 282 | if (!$this->AdminController->generateAppController($admin)) { 283 | $this->out(); 284 | $this->out(__('Failed to generate %sAppController', Inflector::camelize($admin->plugin))); 285 | $this->out(); 286 | return false; 287 | } 288 | if (!$this->AdminModel->generateAppModel($admin)) { 289 | $this->out(); 290 | $this->out(__('Failed to generate %sAppModel', Inflector::camelize($admin->plugin))); 291 | $this->out(); 292 | return false; 293 | } 294 | } 295 | return true; 296 | } 297 | 298 | /** 299 | * Adds extra data for each generated plugin, such as 300 | * layouts, css, and elements 301 | * 302 | * @return void 303 | * @author Jose Diaz-Gonzalez 304 | **/ 305 | public function _generateMisc($plugins) { 306 | foreach ($plugins as $plugin => $cakeAdmins) { 307 | $pluginPath = APP . 'Plugin' . DS . $plugin; 308 | 309 | // Generate flash elements 310 | $elementPath = $pluginPath . DS . 'View' . DS . 'Elements' . DS . 'flash'; 311 | foreach (array('error', 'info', 'notice', 'success') as $file) { 312 | $contents = $this->AdminTemplate->generate( 313 | $this->templateDir . DS . 'Misc' . DS . 'flash' . DS, 314 | $file 315 | ); 316 | 317 | $this->createFile($elementPath . DS . $file . '.ctp', $contents); 318 | } 319 | 320 | // Generate CSS 321 | $contents = $this->AdminTemplate->generate( 322 | $this->templateDir . DS . 'Misc' . DS, 323 | 'cake.admin.generic.min' 324 | ); 325 | $path = $pluginPath . DS . 'webroot' . DS . 'css'; 326 | $this->createFile($path . DS . 'cake.admin.generic.min.css', $contents); 327 | 328 | // Generate Layout 329 | $this->AdminTemplate->set(compact( 330 | 'plugin', 331 | 'plugins' 332 | )); 333 | $contents = $this->AdminTemplate->generate( 334 | $this->templateDir . DS . 'Misc' . DS, 335 | 'layout.default' 336 | ); 337 | $path = $pluginPath . DS . 'View' . DS . 'Layouts'; 338 | $this->createFile($path . DS . 'default.ctp', $contents); 339 | } 340 | } 341 | 342 | /** 343 | * Sets up a folder handler 344 | * 345 | * Calls App::import('Core', 'Folder') if the handler has not 346 | * been created in order to create a new folder. 347 | * 348 | * @return boolean true if handler is setup, false otherwise 349 | * @todo test me 350 | */ 351 | public function _handler() { 352 | if (!$this->handler) { 353 | $this->handler = new Folder(APP); 354 | } 355 | return is_object($this->handler); 356 | } 357 | 358 | /** 359 | * get the option parser. 360 | * 361 | * @return void 362 | */ 363 | public function getOptionParser() { 364 | $parser = parent::getOptionParser(); 365 | return $parser->description(__d('cake_admin', 366 | 'The CakeAdmin shell generates a backend for your application.' 367 | ))->addSubcommand('generate', array( 368 | 'help' => __d('cake_admin', 'Auto-generates admin sections based on your app/Lib/Admin files'), 369 | ))->addSubcommand('help', array( 370 | 'help' => __d('cake_admin', 'Shows this help message'), 371 | )); 372 | } 373 | 374 | 375 | } 376 | -------------------------------------------------------------------------------- /Console/Command/Task/AdminControllerTask.php: -------------------------------------------------------------------------------- 1 | pluginDir = APP . 'Plugin' . DS; 35 | $this->templateDir = array(); 36 | $this->templateDir[] = dirname(__FILE__); 37 | $this->templateDir[] = '..'; 38 | $this->templateDir[] = '..'; 39 | $this->templateDir[] = '..'; 40 | $this->templateDir[] = 'Lib'; 41 | $this->templateDir[] = 'Templates'; 42 | $this->templateDir = implode(DS, $this->templateDir); 43 | } 44 | 45 | /** 46 | * undocumented function 47 | * 48 | * @return void 49 | **/ 50 | function generateAppController($admin) { 51 | $path = $this->templateDir . DS . 'Class'; 52 | 53 | $this->AdminTemplate->set(compact('admin')); 54 | $contents = $this->AdminTemplate->generate($path, 'AppController'); 55 | 56 | $path = $this->pluginDir . Inflector::camelize($admin->plugin) . DS . 'Controller' . DS; 57 | $filename = $path . Inflector::camelize($admin->plugin) . 'AppController.php'; 58 | if ($this->createFile($filename, $contents)) { 59 | return $contents; 60 | } 61 | return false; 62 | } 63 | 64 | /** 65 | * undocumented function 66 | * 67 | * @return void 68 | **/ 69 | function generate($admin) {; 70 | $actions = $this->generateContents($admin); 71 | if (!$actions) return false; 72 | 73 | $this->AdminTemplate->set(compact( 74 | 'admin', 75 | 'actions' 76 | )); 77 | 78 | $path = $this->templateDir . DS . 'Class'; 79 | $contents = $this->AdminTemplate->generate($path, 'Controller'); 80 | if ($this->createFile($admin->paths['controller'], $contents)) { 81 | return $contents; 82 | } 83 | return false; 84 | } 85 | 86 | /** 87 | * undocumented function 88 | * 89 | * @return void 90 | **/ 91 | function generateContents($admin) { 92 | $actions = ''; 93 | foreach ($admin->actions as $alias => $configuration) { 94 | if ($configuration['enabled'] !== true) continue; 95 | 96 | $actionContents = $this->getAction($admin, array( 97 | 'action' => $configuration['type'], 98 | 'plugin' => $configuration['plugin'], 99 | 'alias' => $alias, 100 | 'config' => $configuration, 101 | 'modelObj'=>$admin->modelObj, 102 | )); 103 | if (!$actionContents) return false; 104 | $actions .= "{$actionContents}\n\n"; 105 | } 106 | 107 | return $actions; 108 | } 109 | 110 | /** 111 | * Retrieves action contents 112 | * 113 | * @return void 114 | **/ 115 | function getAction($admin, $options = array()) { 116 | $endPath = 'Lib' . DS . 'Templates' . DS . 'Action' . DS; 117 | if (empty($options['plugin'])) { 118 | $path = APP . $endPath; 119 | } else { 120 | $path = $this->pluginDir . $options['plugin'] . DS . $endPath; 121 | } 122 | $path .= $options['action'] . DS . 'Controller'; 123 | 124 | $alias = $options['alias']; 125 | $configuration = $options['config']; 126 | 127 | $this->AdminTemplate->set(compact( 128 | 'admin', 129 | 'alias', 130 | 'configuration' 131 | )); 132 | return $this->AdminTemplate->generate($path, 'actions'); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /Console/Command/Task/AdminModelTask.php: -------------------------------------------------------------------------------- 1 | pluginDir = APP . 'Plugin' . DS; 28 | $this->templateDir = array(); 29 | $this->templateDir[] = dirname(__FILE__); 30 | $this->templateDir[] = '..'; 31 | $this->templateDir[] = '..'; 32 | $this->templateDir[] = '..'; 33 | $this->templateDir[] = 'Lib'; 34 | $this->templateDir[] = 'Templates'; 35 | $this->templateDir = implode(DS, $this->templateDir); 36 | } 37 | 38 | /** 39 | * undocumented function 40 | * 41 | * @return void 42 | **/ 43 | function generateAppModel($admin) { 44 | $path = $this->templateDir . DS . 'Class'; 45 | 46 | $this->AdminTemplate->set(compact('admin')); 47 | $contents = $this->AdminTemplate->generate($path, 'AppModel'); 48 | 49 | $path = APP . 'Plugin' . DS . Inflector::camelize($admin->plugin) . DS . 'Model' . DS; 50 | $filename = $path . Inflector::camelize($admin->plugin) . 'AppModel.php'; 51 | if ($this->createFile($filename, $contents)) { 52 | return $contents; 53 | } 54 | return false; 55 | } 56 | 57 | /** 58 | * undocumented function 59 | * 60 | * @return void 61 | **/ 62 | function generate($admin) { 63 | $path = $this->templateDir . DS . 'Class'; 64 | 65 | list($methods, $hasFinders, $hasRelated) = $this->generateContents($admin); 66 | 67 | $this->AdminTemplate->set(compact( 68 | 'admin', 69 | 'methods', 70 | 'hasFinders', 71 | 'hasRelated' 72 | )); 73 | $contents = $this->AdminTemplate->generate($path, 'Model'); 74 | 75 | if ($this->createFile($admin->paths['model'], $contents)) { 76 | return $contents; 77 | } 78 | return false; 79 | } 80 | 81 | /** 82 | * undocumented function 83 | * 84 | * @param object $admin 85 | * @param object $modelObj 86 | * @return void 87 | */ 88 | function generateContents($admin) { 89 | $methods = ''; 90 | $finders = false; 91 | $related = false; 92 | foreach ($admin->actions as $alias => $configuration) { 93 | if ($configuration['enabled'] !== true) continue; 94 | 95 | $contents = $this->getMethods($admin, array( 96 | 'action' => $configuration['type'], 97 | 'plugin' => $configuration['plugin'], 98 | 'alias' => $alias, 99 | )); 100 | 101 | if (!empty($contents)) { 102 | $methods .= "{$contents}\n\n"; 103 | if (in_array('find', (array) $configuration['methods'])) $finders = true; 104 | if (in_array('related', (array) $configuration['methods'])) $related = true; 105 | } 106 | } 107 | 108 | return array($methods, $finders, $related); 109 | } 110 | 111 | /** 112 | * undocumented function 113 | * 114 | * @param string $admin 115 | * @param string $options 116 | * @return void 117 | */ 118 | function getMethods($admin, $options) { 119 | $endPath = 'Lib' . DS . 'Templates' . DS . 'Action' . DS; 120 | if (empty($options['plugin'])) { 121 | $path = APP . $endPath; 122 | } else { 123 | $path = $this->pluginDir . $options['plugin'] . DS . $endPath; 124 | } 125 | $path .= $options['action'] . DS . 'Model'; 126 | 127 | $find = $options['alias']; 128 | $alias = $options['alias']; 129 | 130 | $this->AdminTemplate->set(compact( 131 | 'admin', 132 | 'alias', 133 | 'find' 134 | )); 135 | return $this->AdminTemplate->generate($path, "methods"); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /Console/Command/Task/AdminTemplateTask.php: -------------------------------------------------------------------------------- 1 | $two); 49 | } 50 | 51 | if ($data == null) { 52 | return false; 53 | } 54 | 55 | foreach ($data as $name => $value) { 56 | $this->templateVars[$name] = $value; 57 | } 58 | } 59 | 60 | /** 61 | * Runs the template 62 | * 63 | * @param string $directory directory / type of thing you want 64 | * @param string $filename template name 65 | * @param string $vars Additional vars to set to template scope. 66 | * @access public 67 | * @return contents of generated code template 68 | */ 69 | function generate($directory, $filename, $vars = null) { 70 | if ($vars !== null) { 71 | $this->set($vars); 72 | } 73 | 74 | $templateFile = $this->_findTemplate($directory, $filename); 75 | if ($templateFile) { 76 | extract($this->templateVars); 77 | ob_start(); 78 | ob_implicit_flush(0); 79 | include($templateFile); 80 | $content = ob_get_clean(); 81 | $this->templateVars = array(); 82 | return $content; 83 | } 84 | $this->templateVars = array(); 85 | return ''; 86 | } 87 | 88 | /** 89 | * Parses frontmatter from given content and returns the split data 90 | * as an array of [content, parsed frontmatter] 91 | * 92 | * Parsed frontmatter is always an array, whose contents are dependent 93 | * upon the template in use 94 | * 95 | * If frontmatter exists more than once, then this method will return 96 | * false. Frontmatter may only be specified once per template 97 | * 98 | * @param string $content 99 | * @return void 100 | */ 101 | function parseMetadata($contents) { 102 | $results = preg_match('/^(?:---\s*[\n\r]*)(.*)[\n\r]*(?:---\s*[\n\r]*)/ms', $contents, $matches); 103 | if ($results == 0) return array($contents, array()); 104 | if ($results > 1) return false; 105 | 106 | return array( 107 | str_replace($matches[0], "\t", $contents), 108 | $this->json_decode_nice("{{$matches[1]}}") 109 | ); 110 | } 111 | 112 | /** 113 | * Allows the Json frontmatter to be a bit more lenient and YAML like if necessary 114 | * 115 | * @param string $json 116 | * @param boolean $assoc 117 | * @return void 118 | */ 119 | function json_decode_nice($json, $assoc = false) { 120 | $json = str_replace(array("\n","\r"),"", $json); 121 | $json = preg_replace('/([{,])(\s*)([^"]+?)\s*:/','$1"$3":',$json); 122 | return json_decode($json, $assoc); 123 | } 124 | /** 125 | * Find a template inside a directory inside a path. 126 | * 127 | * @param string $directory Subdirectory to look for ie. 'views', 'objects' 128 | * @param string $filename lower_case_underscored filename you want. 129 | * @access public 130 | * @return string filename will exit program if template is not found. 131 | */ 132 | function _findTemplate($directory, $filename) { 133 | $themeFile = $directory . DS . $filename . '.ctp'; 134 | if (file_exists($themeFile)) { 135 | return $themeFile; 136 | } 137 | 138 | $this->err(sprintf(__('Could not find template for %s', true), $filename)); 139 | $this->err(sprintf(__('Error in path %s', true), $themeFile)); 140 | return false; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Console/Command/Task/AdminViewTask.php: -------------------------------------------------------------------------------- 1 | pluginDir = APP . 'Plugin' . DS; 28 | $this->templateDir = array(); 29 | $this->templateDir[] = dirname(__FILE__); 30 | $this->templateDir[] = '..'; 31 | $this->templateDir[] = '..'; 32 | $this->templateDir[] = '..'; 33 | $this->templateDir[] = 'Lib'; 34 | $this->templateDir[] = 'Templates'; 35 | $this->templateDir = implode(DS, $this->templateDir); 36 | } 37 | 38 | /** 39 | * undocumented function 40 | * 41 | * @return void 42 | **/ 43 | function generate($admin) { 44 | foreach ($admin->actions as $alias => $configuration) { 45 | if ($configuration['enabled'] !== true) continue; 46 | 47 | $content = $this->getContent($admin, $alias, $configuration); 48 | if (empty($content)) continue; 49 | if (!$this->createFile($admin->paths['views'][$alias], $content)) return false; 50 | } 51 | return true; 52 | } 53 | 54 | function getContent($admin, $action, $configuration) { 55 | $endPath = 'Lib' . DS . 'Templates' . DS . 'Action' . DS; 56 | if (empty($configuration['plugin'])) { 57 | $path = APP . $endPath; 58 | } else { 59 | $path = $this->pluginDir . $configuration['plugin'] . DS . $endPath; 60 | } 61 | $path .= $configuration['type'] . DS . 'View'; 62 | 63 | $this->AdminTemplate->set(compact( 64 | 'admin', 65 | 'action', 66 | 'configuration' 67 | )); 68 | 69 | $template = $configuration['type']; 70 | if (!$template) return false; 71 | return $this->AdminTemplate->generate($path, $template); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2010 Jose Diaz-Gonzalez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lib/CakeAdminActionConfig.php: -------------------------------------------------------------------------------- 1 | tags. 40 | * - (array) options: Array of HTML attributes 41 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 42 | * the following will be replaced within the confirmMessage 43 | * {{primaryKey}} : alias of the primaryKey 44 | * {{modelName}} : alias of the humanized application modelName 45 | * {{pluginModelName}} : alias of the humanized generated modelName 46 | * 47 | * @var mixed 48 | **/ 49 | var $linkable = false; 50 | 51 | /** 52 | * Model methods this action contains 53 | * 54 | * @var array 55 | **/ 56 | var $methods = array(); 57 | 58 | /** 59 | * Constructor. Throws exceptions on invalid class properties 60 | * 61 | * @author Jose Diaz-Gonzalez 62 | */ 63 | function __construct() { 64 | if (!$this->type) throw new Exception('undefined property "$type"'); 65 | if (!$this->plugin) throw new Exception('undefined property "$plugin"'); 66 | } 67 | 68 | /** 69 | * Merges instantiated configuration with the class defaults 70 | * 71 | * @param array $configuration action configuration 72 | * @return array 73 | * @author Jose Diaz-Gonzalez 74 | */ 75 | function mergeVars($admin, $configuration = array()) { 76 | return array_merge($this->defaults, $configuration); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Lib/Templates/Action/Add/AddCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | null, // Defaults to null 11 | 'classes' => null, // Wraps the section in these classes 12 | 'description' => null, // Used to describe this section 13 | 'fields' => array('*'), // These fields are editable. if associative, field => label 14 | 'readonly' => array(), // These fields are read-only 15 | 'hidden' => array(), // These fields are hidden 16 | 'default' => array(), // These fields are defaulted, field => default 17 | 'exclude' => array('created', 'modified', 'updated'),// These fields are excluded 18 | 'habtm' => false, // Allow editing of habtm data 19 | ); 20 | 21 | /** 22 | * Is this action enabled by default 23 | * 24 | * @var boolean 25 | **/ 26 | var $enabled = true; 27 | 28 | /** 29 | * Plugin where the templates for this action are located 30 | * 31 | * @var string 32 | **/ 33 | var $plugin = 'cake_admin'; 34 | 35 | /** 36 | * Type of action this is 37 | * Standard types are [index, add, edit, deleted, changelog, history] 38 | * 39 | * @var string 40 | **/ 41 | var $type = 'add'; 42 | 43 | /** 44 | * Whether this action is linkable 45 | * 46 | * False to produce no links anywhere (except when specified within a template) 47 | * True when linkable on a model-level 48 | * An array when linkable on the record-level. The mappings for the array are: 49 | * - (string) title: The content to be wrapped by tags. 50 | * - (array) options: Array of HTML attributes 51 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 52 | * the following will be replaced within the confirmMessage 53 | * {{primaryKey}} : alias of the primaryKey 54 | * {{modelName}} : alias of the humanized application modelName 55 | * {{pluginModelName}} : alias of the humanized generated modelName 56 | * 57 | * @var mixed 58 | **/ 59 | var $linkable = true; 60 | 61 | /** 62 | * Model methods this action contains 63 | * 64 | * @var array 65 | **/ 66 | var $methods = array('related'); 67 | 68 | function mergeVars($admin, $configuration) { 69 | if (empty($configuration)) $configuration = array($this->defaults); 70 | 71 | $formType = false; 72 | if (isset($configuration[0]['formType'])) { 73 | $formType = $configuration[0]['formType']; 74 | } 75 | 76 | $schema = $admin->modelObj->schema(); 77 | 78 | foreach ($configuration as $i => $config) { 79 | 80 | foreach ($this->defaults as $key => $value) { 81 | if (!isset($config[$key])) $configuration[$i][$key] = $value; 82 | } 83 | 84 | $fields = array(); 85 | if (empty($configuration[$i]['fields']) || (in_array('*', (array) $configuration[$i]['fields']))) { 86 | // $fields is all fields 87 | foreach (array_keys($schema) as $field) { 88 | if ($field == $admin->modelObj->primaryKey) continue; 89 | if (in_array($field, array('created', 'modified', 'updated'))) continue; 90 | if (in_array($field, array('created_by', 'modified_by', 'updated_by'))) continue; 91 | 92 | $fields[$field] = array( 93 | 'label' => Inflector::humanize($field), 94 | 'wrapper' => '%s', 95 | ); 96 | } 97 | } 98 | if (!empty($configuration[$i]['fields'])) { 99 | $configuration[$i]['fields'] = Set::normalize($configuration[$i]['fields']); 100 | foreach ((array) $configuration[$i]['fields'] as $field => $config) { 101 | if ($field == $admin->modelObj->primaryKey || $field === '*') continue; 102 | 103 | if (empty($configuration[$i])) { 104 | $config = array(); 105 | } else if (is_string($config)) { 106 | $config = array('label' => $config); 107 | } 108 | 109 | if (empty($config['label'])) $config['label'] = Inflector::humanize($field); 110 | if (empty($config['wrapper'])) $config['wrapper'] = '%s'; 111 | $fields[$field] = $config; 112 | } 113 | } 114 | 115 | if (!empty($configuration[$i]['exclude'])) { 116 | foreach ($configuration[$i]['exclude'] as $field) { 117 | if (in_array($field, array_keys($fields))) { 118 | $fields = array_diff_key($fields, array($field => $field)); 119 | } 120 | } 121 | } 122 | 123 | if (!empty($configuration[$i]['hidden'])) { 124 | foreach ((array) $configuration[$i]['hidden'] as $field) { 125 | if (in_array($field, array_keys($fields))) { 126 | $fields[$field]['type'] = 'hidden'; 127 | } 128 | } 129 | } 130 | 131 | if (!empty($configuration[$i]['default'])) { 132 | foreach ((array) $configuration[$i]['default'] as $field => $value) { 133 | if (in_array($field, array_keys($fields))) { 134 | $fields[$field]['value'] = $value; 135 | } 136 | } 137 | } 138 | 139 | $configuration[$i]['fields'] = $fields; 140 | $configuration[$i]['classes'] = (string) $configuration[$i]['classes']; 141 | $configuration[$i]['description'] = (string) $configuration[$i]['description']; 142 | } 143 | 144 | $configuration['formType'] = $formType; 145 | 146 | return $configuration; 147 | } 148 | 149 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Add/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function () { 2 | if (!$this->request->is('post')) { 3 | return; 4 | } 5 | 6 | if (empty($this->request->data)) { 7 | sessions): ?> 8 | $this->Session->setFlash(__d('plugin; ?>', 'No data was posted'), 'flash/success'); 9 | 10 | $this->flash(__d('plugin; ?>', 'No data was posted.'), array('action' => 'redirectTo?>')); 11 | 12 | return; 13 | } 14 | 15 | $this->modelName; ?>->create(); 16 | if ($this->modelName; ?>->save($this->request->data)) { 17 | sessions): ?> 18 | $this->Session->setFlash(__d('plugin; ?>', 'The singularHumanName)); ?> has been saved'), 'flash/success'); 19 | return $this->redirect(array('action' => 'redirectTo?>')); 20 | 21 | $this->flash(__d('plugin; ?>', 'modelName)); ?> saved.'), array('action' => 'redirectTo?>')); 22 | 23 | } else { 24 | sessions): ?> 25 | $this->Session->setFlash(__d('plugin; ?>', 'The singularHumanName)); ?> could not be saved.'), 'flash/error'); 26 | 27 | } 28 | associations['belongsTo']) || !empty($admin->associations['hasAndBelongsToMany'])) : ?> 29 | 30 | $this->set($this->modelName; ?>->related('')); 31 | 32 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Add/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | associations['belongsTo']) || !empty($admin->associations['hasAndBelongsToMany'])) : 4 | 5 | ?> 6 | public function _related() { 7 | associations[$assocType])): 12 | foreach ($admin->associations[$assocType] as $i => $relation): 13 | $otherModelName = Inflector::camelize(Inflector::singularize($relation['alias'])); 14 | $otherPluralName = Inflector::variable(Inflector::pluralize($relation['alias'])); 15 | echo "\t\t\${$otherPluralName} = \$this->{$otherModelName}->find('list');\n"; 16 | $compact[] = "'{$otherPluralName}'"; 17 | endforeach; 18 | endif; 19 | endforeach; 20 | if (!empty($compact)): 21 | echo "\t\treturn compact(".join(', ', $compact).");\n"; 22 | endif; 23 | 24 | ?> 25 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Add/View/add.ctp: -------------------------------------------------------------------------------- 1 | '" . $configuration['config']['formType'] . "'"; 5 | } 6 | unset($configuration['config']['formType']); 7 | ?> 8 |
9 |

", $admin->plugin, Inflector::humanize($action), $admin->singularHumanName); ?>

10 | Form->create('%s', array('url' => array( 11 | 'plugin' => '%s', 'controller' => '%s', 'action' => '%s')%s));?>\n", $admin->modelName, $admin->plugin, $admin->controllerRoute, $action, $formType); ?> 12 | $config): ?> 13 | > 14 | 15 | ", $admin->plugin, $config['title']); ?> 16 | 17 | 18 |

", $admin->plugin, $config['description']); ?>


19 | 20 | $fieldConfig) { 23 | $options = array(); 24 | if (!empty($fieldConfig)) { 25 | foreach ($fieldConfig as $key => $value) { 26 | if (in_array($key, array('readonly', 'wrapper'))) continue; 27 | $option = sprintf("'%s' => '%s'", $key, $value); 28 | if ($key === 'label') { 29 | $option = sprintf("'%s' => __d('%s', '%s')", $key, $admin->plugin, $value); 30 | } 31 | $options[] = $option; 32 | } 33 | if (in_array($field, $config['readonly'])) { 34 | $options[] = "'disabled'"; 35 | } 36 | } 37 | $options = (empty($options)) ? '' : sprintf(", array(\n\t\t\t\t\t%s\n\t\t\t\t)", implode(",\n\t\t\t\t\t ", $options)); 38 | echo sprintf($fieldConfig['wrapper'], sprintf("\t\t\t\techo \$this->Form->input('%s'%s);\n", $field, $options)); 39 | } 40 | echo "\t\t\t?>\n"; 41 | ?> 42 | 43 | 44 | associations['hasAndBelongsToMany'])) { 46 | echo "\t
"; 47 | foreach ($admin->associations['hasAndBelongsToMany'] as $assocName => $assocData) { 48 | echo sprintf("\t\tForm->input('%s'); ?>\n", $assocName); 49 | } 50 | echo "\t 53 | Form->end(__d('%s', 'Submit'));?>\n", $admin->plugin); ?> 54 |
55 |
56 |

", $admin->plugin); ?>

57 | 68 |
-------------------------------------------------------------------------------- /Lib/Templates/Action/Changelog/ChangelogCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | false, 11 | ); 12 | 13 | /** 14 | * Is this action enabled by default 15 | * 16 | * @var boolean 17 | **/ 18 | var $enabled = false; 19 | 20 | /** 21 | * Plugin where the templates for this action are located 22 | * 23 | * @var string 24 | **/ 25 | var $plugin = 'cake_admin'; 26 | 27 | /** 28 | * Type of action this is 29 | * Standard types are [index, add, edit, deleted, changelog, history] 30 | * 31 | * @var string 32 | **/ 33 | var $type = 'changelog'; 34 | 35 | /** 36 | * Whether this action is linkable 37 | * 38 | * False to produce no links anywhere (except when specified within a template) 39 | * True when linkable on a model-level 40 | * An array when linkable on the record-level. The mappings for the array are: 41 | * - (string) title: The content to be wrapped by
tags. 42 | * - (array) options: Array of HTML attributes 43 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 44 | * the following will be replaced within the confirmMessage 45 | * {{primaryKey}} : alias of the primaryKey 46 | * {{modelName}} : alias of the humanized application modelName 47 | * {{pluginModelName}} : alias of the humanized generated modelName 48 | * 49 | * @var mixed 50 | **/ 51 | var $linkable = array('title' => 'Changelog'); 52 | 53 | /** 54 | * Model methods this action contains 55 | * 56 | * @var array 57 | **/ 58 | var $methods = array('find'); 59 | 60 | /** 61 | * Merges instantiated configuration with the class defaults 62 | * 63 | * @param array $configuration action configuration 64 | * @return array 65 | * @author Jose Diaz-Gonzalez 66 | */ 67 | function mergeVars($admin, $configuration = array()) { 68 | if (empty($configuration)) $configuration = $this->defaults; 69 | 70 | if (!$configuration['title']) { 71 | $configuration['title'] = 'Changelog for: '; 72 | } 73 | 74 | return $configuration; 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Changelog/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function ($primaryKey; ?> = null) { 2 | if (!$primaryKey; ?>) { 3 | if (empty($this->request->params['named']['primaryKey; ?>'])) { 4 | sessions): ?> 5 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 6 | return $this->redirect(array('action' => 'redirectTo; ?>')); 7 | 8 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 9 | 10 | } else { 11 | $id = $this->request->params['named']['primaryKey; ?>']; 12 | } 13 | } 14 | 15 | if (!$primaryKey; ?>) { 16 | sessions): ?> 17 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 18 | return $this->redirect(array('action' => 'redirectTo; ?>')); 19 | 20 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 21 | 22 | } 23 | 24 | $singularName; ?> = $this->modelName; ?>->find('', compact('primaryKey; ?>')); 25 | if (!$singularName; ?>) { 26 | sessions): ?> 27 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 28 | return $this->redirect(array('action' => 'redirectTo; ?>')); 29 | 30 | return $this->flash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 31 | 32 | } 33 | 34 | $this->helpers[] = 'Log.Log'; 35 | $this->set(compact('singularName; ?>')); 36 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Changelog/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | public function _find($state, $query, $results = array()) { 2 | if ($state === 'before') { 3 | $query['conditions']['modelName; ?>.primaryKey?>'] = $query['primaryKey; ?>']; 4 | $query['fields'] = array('primaryKey?>', 'displayField; ?>'); 5 | $query['limit'] = 1; 6 | 7 | return $query; 8 | } 9 | 10 | if (empty($results[0])) { 11 | return false; 12 | } 13 | 14 | $results[0]['Log'] = $this->Behaviors->Logable->Log->find('dashboard', array( 15 | 'conditions' => array( 16 | 'Log.model' => 'modelName; ?>', 17 | 'Log.model_id' => $query['primaryKey; ?>'], 18 | ) 19 | )); 20 | return $results[0]; 21 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Changelog/View/changelog.ctp: -------------------------------------------------------------------------------- 1 |
2 |

singularName}['{$admin->modelName}']['{$admin->displayField}']); ?>", $configuration['config']['title']); ?>

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | singularName}['Log'] as \${$admin->singularName}Log) : ?>\n"); ?> 13 | 14 | Log->checkIfChanged(date('Y-m-d', strtotime(\${$admin->singularName}Log['Log']['created'])))) : ?>\n"); ?> 15 | 18 | 19 | 20 | \n");?> 21 | 24 | 29 | 32 | 33 | \n"); ?> 34 | 35 |
16 | Log->logDate(\${$admin->singularName}Log['Log']['created']); ?>\n"); ?> 17 |
22 | Log->logType(\${$admin->singularName}Log['Log']); ?>\n"); ?> 23 | 25 | Html->link(\${$admin->singularName}Log['Log']['title'], array(", $admin->modelName, $admin->displayField); 26 | echo sprintf("'action' => '%s', \${$admin->singularName}Log['Log']['model_id'])); ?>\n", $admin->linkTo); 27 | ?> 28 | 30 | Log->logOwner(\${$admin->singularName}Log['Log']['action'], \${$admin->singularName}Log['User']); ?>\n"); ?> 31 |
36 |
37 |
38 |

", $admin->plugin); ?>

39 | 91 |
-------------------------------------------------------------------------------- /Lib/Templates/Action/Delete/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function ($primaryKey; ?> = null) { 2 | if (!$primaryKey; ?>) { 3 | if (empty($this->request->params['named']['primaryKey; ?>'])) { 4 | sessions): ?> 5 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 6 | return $this->redirect(array('action' => 'redirectTo; ?>')); 7 | 8 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 9 | 10 | } else { 11 | $id = $this->request->params['named']['primaryKey; ?>']; 12 | } 13 | } 14 | 15 | if (!$primaryKey; ?>) { 16 | sessions): ?> 17 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 18 | return $this->redirect(array('action' => 'redirectTo; ?>')); 19 | 20 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 21 | 22 | } 23 | 24 | if (empty($this->request->data['modelName; ?>']['primaryKey; ?>'])) { 25 | $this->request->data = $this->modelName; ?>->find('', compact('primaryKey; ?>')); 26 | } 27 | 28 | if (empty($this->request->data)) { 29 | sessions): ?> 30 | $this->Session->setFlash(__d('plugin; ?>', 'singularHumanName)); ?> unspecified'), 'flash/error'); 31 | $this->redirect(array('action' => 'redirectTo; ?>')); 32 | 33 | $this->flash(__d('plugin; ?>', 'singularHumanName)); ?> unspecified'), array('action' => 'redirectTo; ?>')); 34 | 35 | } 36 | 37 | if ($primaryKey; ?> != $this->request->data['modelName; ?>']['primaryKey; ?>']) { 38 | sessions): ?> 39 | $this->Session->setFlash(__d('plugin; ?>', 'The posted primaryKey; ?> did not match the url'), 'flash/error'); 40 | return $this->redirect(array('action' => 'redirectTo; ?>')); 41 | 42 | return $this->flash(__('The posted primaryKey; ?> did not match the url'), array('action' => 'redirectTo; ?>')); 43 | 44 | } 45 | 46 | if ($this->request->is('post')) { 47 | if ($this->modelName; ?>->delete($this->request->data['modelName; ?>']['primaryKey; ?>'])) { 48 | sessions): ?> 49 | $this->Session->setFlash(__d('plugin; ?>', 'singularHumanName)); ?> deleted'), 'flash/success'); 50 | return $this->redirect(array('action' => 'redirectTo; ?>')); 51 | 52 | $this->flash(__d('plugin; ?>', 'singularHumanName)); ?> deleted'), array('action' => 'redirectTo; ?>')); 53 | 54 | } 55 | sessions): ?> 56 | $this->Session->setFlash(__d('plugin; ?>', 'singularHumanName)); ?> was not deleted'), 'flash/error'); 57 | 58 | return $this->flash(__d('plugin; ?>', 'singularHumanName)); ?> was not deleted'), array('action' => '', $primaryKey; ?>)); 59 | 60 | $primaryKey; ?> = $this->request->data['modelName; ?>']['primaryKey; ?>']; 61 | } 62 | $this->set(compact('primaryKey; ?>')); 63 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Delete/DeleteCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | true, // Display the primary key of the record being deleted 11 | 'displayName' => true, // Display the name of the record being deleted 12 | 'cascade' => true, // Cascade delete queries 13 | ); 14 | 15 | /** 16 | * Is this action enabled by default 17 | * 18 | * @var boolean 19 | **/ 20 | var $enabled = true; 21 | 22 | /** 23 | * Plugin where the templates for this action are located 24 | * 25 | * @var string 26 | **/ 27 | var $plugin = 'cake_admin'; 28 | 29 | /** 30 | * Type of action this is 31 | * Standard types are [index, add, edit, deleted, changelog, history] 32 | * 33 | * @var string 34 | **/ 35 | var $type = 'delete'; 36 | 37 | /** 38 | * Whether this action is linkable 39 | * 40 | * False to produce no links anywhere (except when specified within a template) 41 | * True when linkable on a model-level 42 | * An array when linkable on the record-level. The mappings for the array are: 43 | * - (string) title: The content to be wrapped by
tags. 44 | * - (array) options: Array of HTML attributes 45 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 46 | * the following will be replaced within the confirmMessage 47 | * {{primaryKey}} : alias of the primaryKey 48 | * {{displayField}} : alias of the displayField 49 | * {{modelName}} : alias of the humanized application modelName 50 | * {{modelNameVar}} : alias of the variablized application modelName 51 | * {{pluginModelName}} : alias of the humanized generated modelName 52 | * {{pluginModelNameVar}} : alias of the variablized generated modelName 53 | * 54 | * @var mixed 55 | **/ 56 | var $linkable = array('title' => 'Delete'); 57 | 58 | /** 59 | * Model methods this action contains 60 | * 61 | * @var array 62 | **/ 63 | var $methods = array('find'); 64 | 65 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Delete/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | public function _find($state, $query, $results = array()) { 2 | if ($state === 'before') { 3 | $query['conditions']['modelName; ?>.primaryKey?>'] = $query['primaryKey; ?>']; 4 | $query['limit'] = 1; 5 | unset($query['primaryKey; ?>']); 6 | 7 | return $query; 8 | } 9 | if (empty($results[0])) { 10 | return false; 11 | } 12 | return $results[0]; 13 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Delete/View/delete.ctp: -------------------------------------------------------------------------------- 1 | 2 |
3 |

", $admin->plugin, Inflector::humanize($action), $admin->singularHumanName); ?>

4 | Form->create('{$admin->modelName}', array('url' => array( 6 | 'plugin' => '{$admin->plugin}', 'controller' => '{$admin->controllerRoute}', 'action' => '{$action}')));?>\n"; 7 | if ($configuration['config']['displayPrimaryKey']) { 8 | if ($configuration['config']['displayName']) { 9 | echo sprintf("\t\tForm->value('%s.%s'), \$this->Form->value('%s.%s')); ?>\n", $admin->plugin, $admin->modelName, $admin->primaryKey, $admin->modelName, $admin->displayField); 10 | } else { 11 | echo sprintf("\t\tForm->value('%s.%s')); ?>\n", $admin->plugin, $admin->modelName, $admin->primaryKey); 12 | } 13 | } else { 14 | echo sprintf("\t\t\n", $admin->plugin); 15 | } 16 | echo sprintf("\t\tForm->input('%s.%s', array('type' => 'hidden')); ?>\n", $admin->modelName, $admin->primaryKey); 17 | echo sprintf("\tForm->end(__d('%s', 'Confirm Deletion'));?>\n", $admin->plugin); 18 | ?> 19 |
20 |
21 |

", $admin->plugin); ?>

22 | 74 |
-------------------------------------------------------------------------------- /Lib/Templates/Action/Edit/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function ($primaryKey; ?> = null) { 2 | if (!$primaryKey; ?>) { 3 | if (empty($this->request->params['named']['primaryKey; ?>'])) { 4 | sessions): ?> 5 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 6 | return $this->redirect(array('action' => 'redirectTo; ?>')); 7 | 8 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 9 | 10 | } else { 11 | $id = $this->request->params['named']['primaryKey; ?>']; 12 | } 13 | } 14 | 15 | if (!$primaryKey; ?> && empty($this->request->data)) { 16 | sessions): ?> 17 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 18 | return $this->redirect(array('action' => 'redirectTo; ?>')); 19 | 20 | return $this->flash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 21 | 22 | } 23 | 24 | if ($this->request->is('patch') || $this->request->is('put') || $this->request->is('patch')) { 25 | if ($this->modelName; ?>->save($this->request->data)) { 26 | sessions): ?> 27 | $this->Session->setFlash(__d('plugin; ?>', 'The singularHumanName)); ?> has been saved'), 'flash/success'); 28 | return $this->redirect(array('action' => 'redirectTo; ?>')); 29 | 30 | return $this->flash(__d('plugin; ?>', 'The singularHumanName)); ?> has been saved.'), array('action' => 'redirectTo; ?>')); 31 | 32 | } else { 33 | sessions): ?> 34 | $this->Session->setFlash(__d('plugin; ?>', 'The singularHumanName)); ?> could not be saved.'), 'flash/error'); 35 | 36 | } 37 | } 38 | 39 | if (empty($this->request->data)) { 40 | $this->request->data = $this->modelName; ?>->find('', compact('primaryKey; ?>')); 41 | } 42 | 43 | if (empty($this->request->data)) { 44 | sessions): ?> 45 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 46 | return $this->redirect(array('action' => 'redirectTo; ?>')); 47 | 48 | return $this->flash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 49 | 50 | } 51 | associations['belongsTo']) || !empty($admin->associations['hasAndBelongsToMany'])) : ?> 52 | 53 | $this->set($this->modelName; ?>->related('')); 54 | 55 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Edit/EditCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | null, // Defaults to null 11 | 'classes' => null, // Wraps the section in these classes 12 | 'description' => null, // Used to describe this section 13 | 'fields' => array('*'), // These fields are editable. if associative, field => label 14 | 'readonly' => array(), // These fields are read-only 15 | 'hidden' => array(), // These fields are hidden 16 | 'exclude' => array('created', 'modified', 'updated'),// These fields are excluded 17 | 'habtm' => false, // Allow editing of habtm data 18 | ); 19 | 20 | /** 21 | * Is this action enabled by default 22 | * 23 | * @var boolean 24 | **/ 25 | var $enabled = true; 26 | 27 | /** 28 | * Plugin where the templates for this action are located 29 | * 30 | * @var string 31 | **/ 32 | var $plugin = 'cake_admin'; 33 | 34 | /** 35 | * Type of action this is 36 | * Standard types are [index, add, edit, deleted, changelog, history] 37 | * 38 | * @var string 39 | **/ 40 | var $type = 'edit'; 41 | 42 | /** 43 | * Whether this action is linkable 44 | * 45 | * False to produce no links anywhere (except when specified within a template) 46 | * True when linkable on a model-level 47 | * An array when linkable on the record-level. The mappings for the array are: 48 | * - (string) title: The content to be wrapped by
tags. 49 | * - (array) options: Array of HTML attributes 50 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 51 | * the following will be replaced within the confirmMessage 52 | * {{primaryKey}} : alias of the primaryKey 53 | * {{modelName}} : alias of the humanized application modelName 54 | * {{pluginModelName}} : alias of the humanized generated modelName 55 | * 56 | * @var mixed 57 | **/ 58 | var $linkable = array('title' => 'Edit'); 59 | 60 | /** 61 | * Model methods this action contains 62 | * 63 | * @var array 64 | **/ 65 | var $methods = array('find', 'related'); 66 | 67 | function mergeVars($admin, $configuration) { 68 | if (empty($configuration)) $configuration = array($this->defaults); 69 | 70 | $formType = false; 71 | if (isset($configuration[0]['formType'])) { 72 | $formType = $configuration[0]['formType']; 73 | } 74 | 75 | $schema = $admin->modelObj->schema(); 76 | 77 | foreach ($configuration as $i => $config) { 78 | 79 | foreach ($this->defaults as $key => $value) { 80 | if (!isset($config[$key])) $configuration[$i][$key] = $value; 81 | } 82 | 83 | $fields = array(); 84 | if (empty($configuration[$i]['fields']) || (in_array('*', (array) $configuration[$i]['fields']))) { 85 | // $fields is all fields 86 | foreach (array_keys($schema) as $field) { 87 | if (in_array($field, array('created', 'modified', 'updated'))) continue; 88 | if (in_array($field, array('created_by', 'modified_by', 'updated_by'))) continue; 89 | 90 | $fields[$field] = array( 91 | 'label' => Inflector::humanize($field), 92 | 'wrapper' => '%s', 93 | ); 94 | } 95 | } 96 | if (!empty($configuration[$i]['fields'])) { 97 | $configuration[$i]['fields'] = Set::normalize($configuration[$i]['fields']); 98 | foreach ((array) $configuration[$i]['fields'] as $field => $config) { 99 | if ($field === '*') continue; 100 | if (empty($configuration[$i])) { 101 | $config = array(); 102 | } else if (is_string($config)) { 103 | $config = array('label' => $config); 104 | } 105 | 106 | if (empty($config['label'])) $config['label'] = Inflector::humanize($field); 107 | if (empty($config['wrapper'])) $config['wrapper'] = '%s'; 108 | $fields[$field] = $config; 109 | } 110 | } 111 | 112 | if (!empty($configuration[$i]['exclude'])) { 113 | foreach ($configuration[$i]['exclude'] as $field) { 114 | if (in_array($field, array_keys($fields))) { 115 | $fields = array_diff_key($fields, array($field => $field)); 116 | } 117 | } 118 | } 119 | 120 | if (!empty($configuration[$i]['hidden'])) { 121 | foreach ((array) $configuration[$i]['hidden'] as $field) { 122 | if (in_array($field, array_keys($fields))) { 123 | $fields[$field]['type'] = 'hidden'; 124 | } 125 | } 126 | } 127 | 128 | $configuration[$i]['fields'] = $fields; 129 | $configuration[$i]['classes'] = (string) $configuration[$i]['classes']; 130 | $configuration[$i]['description'] = (string) $configuration[$i]['description']; 131 | } 132 | 133 | $configuration['formType'] = $formType; 134 | 135 | return $configuration; 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Edit/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | public function _find($state, $query, $results = array()) { 2 | if ($state === 'before') { 3 | $query['conditions']['modelName; ?>.primaryKey?>'] = $query['primaryKey; ?>']; 4 | $query['limit'] = 1; 5 | unset($query['primaryKey; ?>']); 6 | 7 | return $query; 8 | } 9 | if (empty($results[0])) { 10 | return false; 11 | } 12 | return $results[0]; 13 | }associations['belongsTo']) || !empty($admin->associations['hasAndBelongsToMany'])) : 16 | 17 | ?> 18 | 19 | 20 | function _related() { 21 | associations[$assocType])): 26 | foreach ($admin->associations[$assocType] as $i => $relation): 27 | $otherModelName = Inflector::camelize(Inflector::singularize($relation['alias'])); 28 | $otherPluralName = Inflector::variable(Inflector::pluralize($relation['alias'])); 29 | echo "\t\t\${$otherPluralName} = \$this->{$otherModelName}->find('list');\n"; 30 | $compact[] = "'{$otherPluralName}'"; 31 | endforeach; 32 | endif; 33 | endforeach; 34 | if (!empty($compact)): 35 | echo "\t\treturn compact(".join(', ', $compact).");\n"; 36 | endif; 37 | 38 | ?> 39 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Edit/View/edit.ctp: -------------------------------------------------------------------------------- 1 | '" . $configuration['config']['formType'] . "'"; 6 | } 7 | unset($configuration['config']['formType']); 8 | ?> 9 |
10 |

", $admin->plugin, Inflector::humanize($action), $admin->singularHumanName); ?>

11 | Form->create('{$admin->modelName}', array('url' => array( 12 | 'plugin' => '{$admin->plugin}', 'controller' => '{$admin->controllerRoute}', 'action' => '{$action}'){$formType}));?>\n";?> 13 | $config): ?> 14 | > 15 | 16 | ", $admin->plugin, $config['title']); ?> 17 | 18 | 19 |

", $admin->plugin, $config['description']); ?>


20 | 21 | $fieldConfig) { 24 | if (in_array($field, array("{$admin->primaryKey}", "{$admin->modelName}.{$admin->primaryKey}"))) $id = true; 25 | $options = array(); 26 | if (!empty($fieldConfig)) { 27 | foreach ($fieldConfig as $key => $value) { 28 | if (in_array($key, array('readonly', 'wrapper'))) continue; 29 | $option = sprintf("'%s' => '%s'", $key, $value); 30 | if ($key === 'label') { 31 | $option = sprintf("'%s' => __d('%s', '%s')", $key, $admin->plugin, $value); 32 | } 33 | $options[] = $option; 34 | } 35 | if (in_array($field, $config['readonly'])) { 36 | $options[] = "'disabled'"; 37 | } 38 | } 39 | $options = (empty($options)) ? '' : sprintf(", array(\n\t\t\t\t\t%s\n\t\t\t\t)", implode(",\n\t\t\t\t\t ", $options)); 40 | echo sprintf($fieldConfig['wrapper'], sprintf("\t\t\t\techo \$this->Form->input('%s'%s);\n", $field, $options)); 41 | } 42 | echo "\t\t\t?>\n"; 43 | ?> 44 | 45 | 46 | associations['hasAndBelongsToMany'])) { 48 | echo "\t\t
"; 49 | foreach ($admin->associations['hasAndBelongsToMany'] as $assocName => $assocData) { 50 | echo sprintf("\t\t\tForm->input('%s'); ?>\n", $assocName); 51 | } 52 | echo "\t\t 55 | 56 | Form->input('%s');?>\n", $admin->primaryKey); ?> 57 | 58 | Form->end(__d('%s', 'Submit'));?>\n", $admin->plugin); ?> 59 |
60 |
61 |

", $admin->plugin); ?>

62 | 114 |
-------------------------------------------------------------------------------- /Lib/Templates/Action/History/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function () { 2 | $logs = $this->modelName; ?>->related(''); 3 | $this->helpers[] = 'Log.Log'; 4 | $this->set(compact('logs')); 5 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/History/HistoryCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | false, 11 | ); 12 | 13 | /** 14 | * Is this action enabled by default 15 | * 16 | * @var boolean 17 | **/ 18 | var $enabled = false; 19 | 20 | /** 21 | * Plugin where the templates for this action are located 22 | * 23 | * @var string 24 | **/ 25 | var $plugin = 'cake_admin'; 26 | 27 | /** 28 | * Type of action this is 29 | * Standard types are [index, add, edit, deleted, changelog, history] 30 | * 31 | * @var string 32 | **/ 33 | var $type = 'history'; 34 | 35 | /** 36 | * Whether this action is linkable 37 | * 38 | * False to produce no links anywhere (except when specified within a template) 39 | * True when linkable on a model-level 40 | * An array when linkable on the record-level. The mappings for the array are: 41 | * - (string) title: The content to be wrapped by
tags. 42 | * - (array) options: Array of HTML attributes 43 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 44 | * the following will be replaced within the confirmMessage 45 | * {{primaryKey}} : alias of the primaryKey 46 | * {{modelName}} : alias of the humanized application modelName 47 | * {{pluginModelName}} : alias of the humanized generated modelName 48 | * 49 | * @var mixed 50 | **/ 51 | var $linkable = 'History'; 52 | 53 | /** 54 | * Model methods this action contains 55 | * 56 | * @var array 57 | **/ 58 | var $methods = array('related'); 59 | 60 | /** 61 | * Merges instantiated configuration with the class defaults 62 | * 63 | * @param array $configuration action configuration 64 | * @return array 65 | * @author Jose Diaz-Gonzalez 66 | */ 67 | function mergeVars($admin, $configuration = array()) { 68 | if (empty($configuration)) $configuration = $this->defaults; 69 | 70 | if (!$configuration['title']) { 71 | $configuration['title'] = $admin->singularHumanName . ' History'; 72 | } 73 | 74 | return $configuration; 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/History/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | public function _related() { 2 | return $this->Behaviors->Logable->Log->find('dashboard', array( 3 | 'conditions' => array('Log.model' => 'modelName; ?>') 4 | )); 5 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/History/View/history.ctp: -------------------------------------------------------------------------------- 1 |
2 |

", $configuration['config']['title']); ?>

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | singularName}L) : ?>\n"); ?> 13 | 14 | Log->checkIfChanged(date('Y-m-d', strtotime(\${$admin->singularName}L['Log']['created'])))) : ?>\n"); ?> 15 | 18 | 19 | 20 | \n");?> 21 | 24 | 29 | 32 | 33 | \n"); ?> 34 | 35 |
16 | Log->logDate(\${$admin->singularName}L['Log']['created']); ?>\n"); ?> 17 |
22 | Log->logType(\${$admin->singularName}L['Log']); ?>\n"); ?> 23 | 25 | Html->link(\${$admin->singularName}L['Log']['title'], array(", $admin->modelName, $admin->displayField); 26 | echo sprintf("'action' => '%s', \${$admin->singularName}L['Log']['model_id'])); ?>\n", $admin->linkTo); 27 | ?> 28 | 30 | Log->logOwner(\${$admin->singularName}L['Log']['action'], \${$admin->singularName}L['User']); ?>\n"); ?> 31 |
36 |
37 |
38 |

", $admin->plugin); ?>

39 | 50 | 51 | 52 |

", $admin->plugin); ?>

53 | request->params['named'], Set::normalize(array('direction', 'sort', 'order', 'page'))); ?>\n"; ?> 54 | $filter) : ?> 55 |

", $admin->plugin, Inflector::humanize(preg_replace('/_id$/', '', $field))); ?>

56 | 61 | 62 | 63 | 64 | 65 |

", $admin->plugin); ?>

66 | Form->create('%s', array('url' => array( 67 | 'plugin' => '%s', 'controller' => '%s', 'action' => '%s'))); ?>\n", $admin->modelName, $admin->plugin, $admin->controllerRoute, $action); ?> 68 | 73 | Form->submit(); ?>\n"; ?> 74 | Form->end(); ?>\n"; ?> 75 | 76 |
-------------------------------------------------------------------------------- /Lib/Templates/Action/Index/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function () { 2 | actions[$alias]['config']['search'])) { 5 | foreach ($admin->actions[$alias]['config']['search'] as $field => $config) { 6 | $mappings[] = $field; 7 | } 8 | } 9 | 10 | $mappings = (!empty($mappings)) ? "'" . implode("', '", $mappings) . "'" : ''; 11 | ?> 12 | $pluralName; ?> = $this->_customPaginate('', ); 13 | $this->set(compact('pluralName; ?>')); 14 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Index/IndexCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | array('*'), // array or string of fields to enable 11 | 'list_filter' => array(), // Allow these to be filterable 12 | 'link' => array('id'), // Link to object here. Must be in fields 13 | 'search' => array(), // Allow searching of these fields 14 | 'sort' => true, // Allow sorting. True or array of sortable fields 15 | ); 16 | 17 | /** 18 | * Is this action enabled by default 19 | * 20 | * @var boolean 21 | **/ 22 | var $enabled = true; 23 | 24 | /** 25 | * Plugin where the templates for this action are located 26 | * 27 | * @var string 28 | **/ 29 | var $plugin = 'cake_admin'; 30 | 31 | /** 32 | * Type of action this is 33 | * Standard types are [index, add, edit, deleted, changelog, history] 34 | * 35 | * @var string 36 | **/ 37 | var $type = 'index'; 38 | 39 | /** 40 | * Whether this action is linkable 41 | * 42 | * False to produce no links anywhere (except when specified within a template) 43 | * True when linkable on a model-level. Link prefix defaults to humanized action alias 44 | * String when linkable on a model-level. Link prefix is then the string 45 | * An array when linkable on the record-level. The mappings for the array are: 46 | * - (string) title: The content to be wrapped by
tags. 47 | * - (array) options: Array of HTML attributes 48 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 49 | * the following will be replaced within the confirmMessage 50 | * {{primaryKey}} : alias of the primaryKey 51 | * {{modelName}} : alias of the humanized application modelName 52 | * {{pluginModelName}} : alias of the humanized generated modelName 53 | * 54 | * @var mixed 55 | **/ 56 | var $linkable = 'List {{modelname}}'; 57 | 58 | /** 59 | * Model methods this action contains 60 | * 61 | * @var array 62 | **/ 63 | var $methods = array('find'); 64 | 65 | /** 66 | * Merges instantiated configuration with the class defaults 67 | * 68 | * @param array $configuration action configuration 69 | * @return array 70 | * @author Jose Diaz-Gonzalez 71 | */ 72 | function mergeVars($admin, $configuration = array()) { 73 | if (empty($configuration)) $configuration = $this->defaults; 74 | 75 | $filters = array(); 76 | $search = array(); 77 | $fields = array(); 78 | $schema = $admin->modelObj->schema(); 79 | 80 | if (empty($configuration['fields']) || (in_array('*', (array) $configuration['fields']))) { 81 | // $fields is all fields 82 | foreach (array_keys($schema) as $field) { 83 | $fields[] = $field; 84 | } 85 | } else { 86 | foreach ((array) $configuration['fields'] as $field) { 87 | if ($field !== '*') $fields[] = $field; 88 | } 89 | } 90 | 91 | if (!empty($configuration['list_filter'])) { 92 | foreach ($configuration['list_filter'] as $field => $config) { 93 | $filters[$field] = (array) $config; 94 | } 95 | } 96 | 97 | $configuration['search'] = Set::normalize($configuration['search']); 98 | if (!empty($configuration['search'])) { 99 | foreach ($configuration['search'] as $field => $alias) { 100 | if (!in_array($field, array_keys($filters))) { 101 | $type = ($schema[$field]['type'] == 'text') ? 'text' : $schema[$field]['type']; 102 | if ($type == 'string') $type = 'text'; 103 | 104 | if (is_array($alias)) { 105 | if (isset($alias['type'])) { 106 | $type = $alias['type']; 107 | } 108 | 109 | if (isset($alias['label'])) { 110 | $label = $alias['label']; 111 | } else { 112 | $label = Inflector::humanize((preg_replace('/_id$/', '', $field))); 113 | } 114 | 115 | if (isset($alias['alias'])) { 116 | $alias = $alias['alias']; 117 | } else { 118 | $alias = $field; 119 | } 120 | } else { 121 | $alias = empty($alias) ? $field : $alias; 122 | $label = Inflector::humanize((preg_replace('/_id$/', '', $field))); 123 | } 124 | 125 | $type = ($field === 'id') ? 'text' : $type; 126 | 127 | $search[$field] = array( 128 | 'type' => $type, 129 | 'alias' => $alias, 130 | 'label' => $label, 131 | ); 132 | } 133 | } 134 | } 135 | 136 | $sort = $fields; 137 | if (empty($configuration['sort']) || $configuration['sort'] === false) { 138 | $sort = array(); 139 | } else if (is_array($configuration['sort'])) { 140 | $sort = $configuration['sort']; 141 | } 142 | 143 | if (empty($configuration['link'])) { 144 | $configuration['link'] = array($admin->primaryKey); 145 | } 146 | 147 | $configuration = array_merge($this->defaults, $configuration); 148 | $configuration['list_filter'] = $filters; 149 | $configuration['search'] = $search; 150 | $configuration['fields'] = $fields; 151 | $configuration['sort'] = $sort; 152 | 153 | return $configuration; 154 | } 155 | 156 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Index/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | actions[$find]['config']['fields']; 4 | $searches = $admin->actions[$find]['config']['search']; 5 | $list_filter = $admin->actions[$find]['config']['list_filter']; 6 | 7 | // Available variables: [modelObj, list_filter, searches, fields] 8 | 9 | ?> 10 | public function _find($state, $query, $results = array()) { 11 | if ($state === 'before') { 12 | 13 | $config) : ?> 14 | if (isset($query['named'][''])) { 15 | $query['conditions']['modelName}.{$field}"; ?>'] = $query['named']['']; 16 | } 17 | 18 | 19 | 20 | $config) : ?> 21 | modelName}.{$field}'] . '%';\n"; 24 | } else { 25 | $modifier = ''; 26 | $query = "\$query['named']['{$admin->modelName}.{$field}'];\n"; 27 | } 28 | ?> 29 | if (isset($query['named']['modelName}.{$field}"; ?>'])) { 30 | $query['conditions']['modelName}.{$field}{$modifier}"; ?>'] = 31 | } 32 | 33 | 34 | 35 | 36 | $config) : ?> 37 | modelName}']['{$field}'] . '%';\n"; 40 | } else { 41 | $modifier = ''; 42 | $query = "\$query['data']['{$admin->modelName}']['{$field}'];\n"; 43 | } 44 | ?> 45 | if (!empty($query['data']['modelName}"; ?>'][''])) { 46 | $query['conditions']['modelName}.{$field}{$modifier}"; ?>'] = 47 | } 48 | 49 | 50 | 51 | 52 | $query['fields'] = array(''); 53 | 54 | 55 | 56 | modelObj->schema()) as $field) : ?> 57 | 58 | associations['belongsTo'])) : ?> 59 | associations['belongsTo'] as $alias => $details) : ?> 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | $query['contain'] = array(''); 70 | 71 | $query['contain'] = false; 72 | 73 | unset($query['data'], $query['named']); 74 | 75 | if (!empty($query['operation'])) { 76 | return $this->_findCount($state, $query, $results); 77 | } 78 | return $query; 79 | } 80 | if (!empty($query['operation'])) { 81 | return $this->_findCount($state, $query, $results); 82 | } 83 | return $results; 84 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/Index/View/index.ctp: -------------------------------------------------------------------------------- 1 |
2 |

", $admin->plugin, Inflector::pluralize(Inflector::humanize($admin->modelName))) ;?>

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | pluralVar} as \${$admin->singularVar}) : ?>\n"; 18 | echo "\t\t>\n"; 19 | foreach ($configuration['config']['fields'] as $field) { 20 | $isKey = false; 21 | if (!empty($admin->associations['belongsTo'])) { 22 | foreach ($admin->associations['belongsTo'] as $alias => $details) { 23 | if ($field === $details['foreignKey']) { 24 | $isKey = true; 25 | echo sprintf("\t\t\t\n", $admin->singularVar, $alias, $details['displayField'], $details['controller'], $admin->singularVar, $alias, $details['primaryKey']); 26 | break; 27 | } 28 | } 29 | } 30 | if ($isKey !== true) { 31 | if ($field == $admin->primaryKey || in_array($field, $configuration['config']['link'])) { 32 | echo sprintf("\t\t\t\n", $admin->linkTo, $admin->singularVar, $admin->modelName, $admin->primaryKey); 34 | } else { 35 | echo sprintf("\t\t\t\n", $admin->singularVar, $admin->modelName, $field); 36 | } 37 | } 38 | } 39 | 40 | echo "\t\t\t\n"; 87 | echo "\t\t\n"; 88 | 89 | echo "\t\t\n"; 90 | ?> 91 |
Paginator->sort('%s');?>", $field); ?>", $admin->plugin); ?>
\n\t\t\t\tHtml->link(\$%s['%s']['%s'], array('controller' => '%s', 'action' => 'view', \$%s['%s']['%s'])); ?>\n\t\t\tHtml->link(\$%s['%s']['%s'], array(", $admin->singularVar, $admin->modelName, $field); 33 | echo sprintf("'action' => '%s', \$%s['%s']['%s'])); ?> \n"; 41 | foreach ($admin->links as $alias => $config) { 42 | if ($alias == $action) continue; 43 | if (is_array($config)) { 44 | $url = array(); 45 | $options = array(); 46 | $confirmMessage = $config['confirmMessage']; 47 | if (is_array($config['url'])) { 48 | foreach ($config['url'] as $key => $value) { 49 | if (!empty($value)) { 50 | $url[] = sprintf("'%s' => '%s'", $key, $value); 51 | } else { 52 | $url[] = sprintf("'%s'", $key); 53 | } 54 | } 55 | $url[] = sprintf("\$%s['%s']['%s']", $admin->singularVar, $admin->modelName, $admin->primaryKey); 56 | $url = sprintf('array(%s)', implode(', ', $url)); 57 | } else { 58 | $url = sprintf("'%s'", $config['url']); 59 | } 60 | if (is_array($config['options'])) { 61 | foreach ($config['options'] as $key => $value) { 62 | if (!empty($value)) { 63 | $url[] = sprintf("'%s' => '%s'", $key, $value); 64 | } else { 65 | $url[] = sprintf("'%s'", $key); 66 | } 67 | } 68 | $options = sprintf('array(%s)', implode(', ', $options)); 69 | } else { 70 | $options = $config['options']; 71 | } 72 | $end = ''; 73 | if (empty($options)) { 74 | if (!empty($confirmMessage)) { 75 | $end = sprintf(", null, %s", $confirmMessage); 76 | } 77 | } else { 78 | $end .= sprintf(", '%s'", $options); 79 | if (!empty($confirmMessage)) { 80 | $end .= sprintf(", %s", $confirmMessage); 81 | } 82 | } 83 | echo sprintf("\t\t\t\tHtml->link(__d('%s', '%s'), %s); ?>\n", $admin->plugin, $config['title'], $url.$end); 84 | } 85 | } 86 | echo "\t\t\t
92 |

93 | Paginator->counter(array( 95 | 'format' => __d('%s', 'Page %%page%% of %%pages%%, showing %%current%% records out of %%count%% total, starting on record %%start%%, ending on %%end%%') 96 | )); 97 | ?>\n", $admin->plugin); ?> 98 |

99 |
100 | Paginator->prev(__d('%s', '« Previous'), array(), null, array('class'=>'disabled')); ?>\n", $admin->plugin); ?> 101 | Paginator->numbers(array('separator' => false)); ?>\n"?> 102 | Paginator->next(__d('%s', 'Next »'), array(), null, array('class' => 'disabled')); ?>\n", $admin->plugin); ?> 103 |
104 |
105 |
106 |

", $admin->plugin); ?>

107 | 118 | 119 | 120 |

", $admin->plugin); ?>

121 | request->params['named'], Set::normalize(array('direction', 'sort', 'order', 'page'))); ?>\n"; ?> 122 | $filter) : ?> 123 |

", $admin->plugin, Inflector::humanize(preg_replace('/_id$/', '', $field))); ?>

124 | 129 | 130 | 131 | 132 | 133 |

", $admin->plugin); ?>

134 | Form->create('%s', array('url' => array( 135 | 'plugin' => '%s', 'controller' => '%s', 'action' => '%s'))); ?>\n", $admin->modelName, $admin->plugin, $admin->controllerRoute, $action); ?> 136 | 141 | Form->submit(); ?>\n"; ?> 142 | Form->end(); ?>\n"; ?> 143 | 144 |
-------------------------------------------------------------------------------- /Lib/Templates/Action/View/Controller/actions.ctp: -------------------------------------------------------------------------------- 1 | public function ($primaryKey; ?> = null) { 2 | if (!$primaryKey; ?>) { 3 | if (empty($this->request->params['named']['primaryKey; ?>'])) { 4 | sessions): ?> 5 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 6 | return $this->redirect(array('action' => 'redirectTo; ?>')); 7 | 8 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 9 | 10 | } else { 11 | $id = $this->request->params['named']['primaryKey; ?>']; 12 | } 13 | } 14 | 15 | if (!$primaryKey; ?>) { 16 | sessions): ?> 17 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 18 | return $this->redirect(array('action' => 'redirectTo; ?>')); 19 | 20 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 21 | 22 | } 23 | 24 | $singularName; ?> = $this->modelName; ?>->find('', compact('primaryKey; ?>')); 25 | if (!$singularName; ?>) { 26 | sessions): ?> 27 | $this->Session->setFlash(__d('plugin; ?>', 'Invalid singularHumanName)); ?>'), 'flash/error'); 28 | return $this->redirect(array('action' => 'redirectTo; ?>')); 29 | 30 | return $this->flash(__('Invalid singularHumanName)); ?>'), array('action' => 'redirectTo; ?>')); 31 | 32 | } 33 | $this->set(compact('singularName ?>')); 34 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/View/Model/methods.ctp: -------------------------------------------------------------------------------- 1 | public function _find($state, $query, $results = array()) { 2 | if ($state === 'before') { 3 | $query['conditions']['modelName; ?>.primaryKey?>'] = $query['primaryKey; ?>']; 4 | actions[$find]['config']['contain'])) : ?> 5 | $query['contain'] = array( 6 | formatted($admin->actions[$find]['config']['contain'], 4); ?> 7 | ); 8 | 9 | $query['fields'] = array( 10 | formatted(array_keys($admin->actions[$find]['config']['fields']), 4); ?> 11 | ); 12 | $query['limit'] = 1; 13 | unset($query['primaryKey; ?>']); 14 | 15 | return $query; 16 | } 17 | if (empty($results[0])) { 18 | return false; 19 | } 20 | return $results[0]; 21 | } -------------------------------------------------------------------------------- /Lib/Templates/Action/View/View/view.ctp: -------------------------------------------------------------------------------- 1 |
2 |

", $admin->plugin, Inflector::humanize($action), $admin->singularHumanName); ?>

3 |
\n";?> 4 | $fieldConfig) { 6 | $isKey = false; 7 | if ($fieldConfig['link'] && !empty($admin->associations['belongsTo'])) { 8 | foreach ($admin->associations['belongsTo'] as $alias => $details) { 9 | if ($field === $details['foreignKey']) { 10 | $isKey = true; 11 | echo sprintf("\t\t>\n", $admin->plugin, $fieldConfig['label']); 12 | echo sprintf("\t\t>\n\t\t\tHtml->link(\$%s['%s']['%s'], array('controller' => '%s', 'action' => 'view', \$%s['%s']['%s'])); ?>\n\t\t\t \n\t\t\n", $admin->singularVar, $alias, $details['displayField'], $details['controller'], $admin->singularVar, $alias, $details['primaryKey']); 13 | break; 14 | } 15 | } 16 | } 17 | if ($isKey !== true) { 18 | echo sprintf("\t\t>\n", $admin->plugin, $fieldConfig['label']); 19 | echo sprintf("\t\t>\n\t\t\t\n\t\t\t \n\t\t\n", $admin->singularVar, $admin->modelName, $field); 20 | } 21 | } 22 | ?> 23 |
24 |
25 |
26 |

", $admin->plugin); ?>

27 | 79 |
80 | associations['hasOne'])) : 82 | foreach ($admin->associations['hasOne'] as $alias => $details): ?> 83 | 101 | associations['hasMany'])) { 105 | $admin->associations['hasMany'] = array(); 106 | } 107 | if (empty($admin->associations['hasAndBelongsToMany'])) { 108 | $admin->associations['hasAndBelongsToMany'] = array(); 109 | } 110 | $relations = array_merge($admin->associations['hasMany'], $admin->associations['hasAndBelongsToMany']); 111 | $i = 0; 112 | foreach ($relations as $alias => $details): 113 | $otherSingularVar = Inflector::variable($alias); 114 | $otherPluralHumanName = Inflector::humanize($details['controller']); 115 | ?> 116 | 160 | -------------------------------------------------------------------------------- /Lib/Templates/Action/View/ViewCakeAdminConfig.php: -------------------------------------------------------------------------------- 1 | array('*'), // These fields are editable. if associative, field => label 11 | // May also indicate whether to link to the belongsTo model, 12 | // 'contain' => true 13 | 'contain' => array('*'), // Array or string of models to contain 14 | ); 15 | 16 | /** 17 | * Is this action enabled by default 18 | * 19 | * @var boolean 20 | **/ 21 | var $enabled = false; 22 | 23 | /** 24 | * Plugin where the templates for this action are located 25 | * 26 | * @var string 27 | **/ 28 | var $plugin = 'cake_admin'; 29 | 30 | /** 31 | * Type of action this is 32 | * Standard types are [index, add, edit, deleted, changelog, history] 33 | * 34 | * @var string 35 | **/ 36 | var $type = 'view'; 37 | 38 | /** 39 | * Whether this action is linkable 40 | * 41 | * False to produce no links anywhere (except when specified within a template) 42 | * True when linkable on a model-level 43 | * An array when linkable on the record-level. The mappings for the array are: 44 | * - (string) title: The content to be wrapped by
tags. 45 | * - (array) options: Array of HTML attributes 46 | * - (string) confirmMessage: JavaScript confirmation message. Literal string will be output 47 | * the following will be replaced within the confirmMessage 48 | * {{primaryKey}} : alias of the primaryKey 49 | * {{modelName}} : alias of the humanized application modelName 50 | * {{pluginModelName}} : alias of the humanized generated modelName 51 | * 52 | * @var mixed 53 | **/ 54 | var $linkable = array('title' => 'View'); 55 | 56 | /** 57 | * Model methods this action contains 58 | * 59 | * @var array 60 | **/ 61 | var $methods = array('find'); 62 | 63 | /** 64 | * Merges instantiated configuration with the class defaults 65 | * 66 | * @param array $configuration action configuration 67 | * @return array 68 | * @author Jose Diaz-Gonzalez 69 | */ 70 | function mergeVars($admin, $configuration = array()) { 71 | if (empty($configuration)) $configuration = $this->defaults; 72 | if (empty($configuration['link'])) $configuration['link'] = array(); 73 | if (empty($configuration['contain'])) $configuration['contain'] = array(); 74 | 75 | $fields = array(); 76 | $contains = array(); 77 | $schema = $admin->modelObj->schema(); 78 | 79 | if (empty($configuration['fields']) || (in_array('*', (array) $configuration['fields']))) { 80 | // $fields is all fields 81 | foreach (array_keys($schema) as $field) { 82 | $fields[$field] = array('label' => Inflector::humanize($field), 'link' => false); 83 | } 84 | } 85 | if (!empty($configuration['fields'])) { 86 | $configuration['fields'] = Set::normalize($configuration['fields']); 87 | foreach ((array) $configuration['fields'] as $field => $config) { 88 | if ($field === '*') continue; 89 | if (is_string($config)) { 90 | $config = array('label' => $config); 91 | } 92 | 93 | if (empty($config['label'])) $config['label'] = Inflector::humanize($field); 94 | if (empty($config['link'])) $config['link'] = false; 95 | if (in_array($field, $configuration['link'])) $config['link'] = true; 96 | $fields[$field] = $config; 97 | } 98 | } 99 | 100 | $linkAssociations = array(); 101 | // $fields is all fields 102 | foreach ($admin->associations as $type => $associations) { 103 | foreach ($associations as $assoc => $assocData) { 104 | if (in_array('*', (array) $configuration['contain'])) { 105 | $contains[$assoc] = array('fields' => $assocData['fields']); 106 | } 107 | $linkAssociations[$assocData['foreignKey']] = array( 108 | 'model' => $assoc, 109 | 'fields' => array($assocData['primaryKey'], $assocData['displayField']), 110 | ); 111 | } 112 | } 113 | if (!empty($configuration['contain'])) { 114 | foreach (Set::normalize((array) $configuration['contain']) as $assoc => $assocData) { 115 | if ($assoc !== '*') $contains[$assoc] = $assocData; 116 | } 117 | } 118 | 119 | foreach ($configuration['link'] as $field) { 120 | $fields[$field]['link'] = true; 121 | } 122 | 123 | foreach ($fields as $field => $config) { 124 | if ($config['link']) { 125 | if (!isset($linkAssociations[$field])) continue; 126 | $link = $linkAssociations[$field]; 127 | if (!isset($contains[$link['model']]) || !isset($contains[$link['model']]['fields'])) { 128 | $contains[$link['model']]['fields'] = array(); 129 | } 130 | foreach ($link['fields'] as $field) { 131 | if (!in_array($field, $contains[$link['model']]['fields'])) { 132 | $contains[$link['model']]['fields'][] = $field; 133 | } 134 | } 135 | } 136 | } 137 | 138 | $configuration = array_merge($this->defaults, $configuration); 139 | $configuration['fields'] = $fields; 140 | $configuration['contain'] = $contains; 141 | return $configuration; 142 | } 143 | 144 | } -------------------------------------------------------------------------------- /Lib/Templates/Class/AppController.ctp: -------------------------------------------------------------------------------- 1 | 2 | class plugin) ?>AppController extends AppController { 3 | } 4 | 5 | App::uses('ErrorHandler', 'Error'); 6 | class AppError extends ErrorHandler { 7 | public function _outputMessage($template) { 8 | $this->controller->plugin = 'plugin); ?>'; 9 | return parent::_outputMessage($template); 10 | } 11 | } -------------------------------------------------------------------------------- /Lib/Templates/Class/AppModel.ctp: -------------------------------------------------------------------------------- 1 | 4 | class plugin); ?>AppModel extends AppModel { 5 | 6 | var $actsAs = array('Containable'); 7 | var $recursive = -1; 8 | 9 | function related($type) { 10 | if (isset($this->relatedMethods[$type]) && $this->relatedMethods[$type] === true) { 11 | return $this->{'_related' . Inflector::camelize($type)}(); 12 | } 13 | 14 | trigger_error( 15 | __('(Model::related(%s)) Invalid related find for %s', $type, $this->alias), 16 | E_USER_WARNING 17 | ); 18 | } 19 | 20 | function paginateCount($conditions = array(), $recursive = 0, $extra = array()) { 21 | $parameters = compact('conditions'); 22 | $find = '_findCount'; 23 | if (isset($extra['type'])) { 24 | $extra['operation'] = 'count'; 25 | $find = '_find' . Inflector::camelize($extra['type']); 26 | $params = $this->$find('before', array_merge($parameters, $extra)); 27 | unset($params['fields']); 28 | unset($params['limit']); 29 | return $this->find('count', $params); 30 | } 31 | return $this->find('count', array_merge($parameters, $extra)); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /Lib/Templates/Class/Controller.ctp: -------------------------------------------------------------------------------- 1 | 25 | App::uses('plugin) ?>AppController', 'plugin) ?>.Controller'); 26 | class controllerName; ?>Controller extends plugin) ?>AppController { 27 | 28 | public $uses = array('plugin); ?>.modelName; ?>'); 29 | public $layout = 'default'; 30 | components)) { 33 | echo "\tpublic \$components = array(\n"; 34 | echo $admin->formatted('components', 2); 35 | echo "\t);\n"; 36 | } 37 | if (!empty($admin->helpers)) { 38 | echo "\tpublic \$helpers = array(\n"; 39 | echo $admin->formatted('helpers', 2); 40 | echo "\t);\n"; 41 | } 42 | 43 | echo "\n{$actions}"; ?> 44 | 45 | public function _customPaginate($findMethod, $mapping = array()) { 46 | $query = array(); 47 | foreach ($mapping as $field) { 48 | if (!empty($this->request->data['modelName}"; ?>'][$field])) { 49 | $query["modelName; ?>.{$field}"] = $this->request->data['modelName}"; ?>'][$field]; 50 | } 51 | } 52 | if (!empty($query)) $this->redirect($query); 53 | 54 | $this->paginate = array($findMethod) + array( 55 | 'data' => $this->request->data, 56 | 'named' => $this->request->params['named'], 57 | ); 58 | $results = $this->paginate(); 59 | 60 | foreach ($mapping as $field) { 61 | if (!isset($this->request->params['named']["modelName}"; ?>.{$field}"])) { 62 | continue; 63 | } 64 | if (is_string($this->request->params['named']["modelName}"; ?>.{$field}"]) && strlen($this->request->params['named']["modelName}"; ?>.{$field}"])) { 65 | $this->request->data['modelName}"; ?>'][$field] = $this->request->params['named']["modelName}"; ?>.{$field}"]; 66 | } elseif (!empty($this->request->params['named']["modelName}"; ?>.{$field}"])) { 67 | $this->request->data['modelName}"; ?>'][$field] = $this->request->params['named']["modelName}"; ?>.{$field}"]; 68 | } 69 | } 70 | return $results; 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /Lib/Templates/Class/Model.ctp: -------------------------------------------------------------------------------- 1 | 24 | class modelName ?> extends plugin) ?>AppModel { 25 | 26 | public $displayField = 'displayField; ?>'; 27 | public $useDbConfig = 'useDbConfig; ?>'; 28 | public $useTable = 'useTable; ?>'; 29 | public $primaryKey = 'primaryKey; ?>'; 30 | actsAs)) : ?> 32 | public $actsAs = array( 33 | formatted('actsAs', 2, false); ?> 34 | ); 35 | 36 | finders)) : ?> 37 | public $findMethods = array( 38 | finders as $findMethod) : ?> 39 | '' => true, 40 | 41 | ); 42 | 43 | relatedFinders)) : ?> 44 | public $relatedMethods = array( 45 | relatedFinders as $relatedMethod) : ?> 46 | '' => true, 47 | 48 | ); 49 | 50 | validate)): ?> 51 | 52 | public function __construct($id = false, $table = null, $ds = null) { 53 | parent::__construct($id, $table, $ds); 54 | $this->validate = array( 55 | formatted('validate', 3, false) ?> 56 | ); 57 | } 58 | 59 | relations as $assocType => $values) { 61 | echo "\n\public \$$assocType = array(\n"; 62 | echo $admin->formatted($values, 2); 63 | echo "\t);\n"; 64 | } 65 | 66 | echo "\n{$methods}"; 67 | ?> 68 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/Makefile: -------------------------------------------------------------------------------- 1 | DATE=$(shell DATE) 2 | BOOTSTRAP = ./cake.admin.generic.ctp 3 | BOOTSTRAP_MIN = ./cake.admin.generic.min.ctp 4 | BOOTSTRAP_LESS = ./less/bootstrap.less 5 | LESS_COMPRESSOR ?= `which lessc` 6 | WATCHR ?= `which watchr` 7 | 8 | build: 9 | @@if test ! -z ${LESS_COMPRESSOR}; then \ 10 | sed 's/@DATE/'"${DATE}"'/' ${BOOTSTRAP_LESS} >${BOOTSTRAP_LESS}.tmp; \ 11 | lessc ${BOOTSTRAP_LESS}.tmp > ${BOOTSTRAP}; \ 12 | lessc ${BOOTSTRAP_LESS}.tmp > ${BOOTSTRAP_MIN} --compress; \ 13 | rm -f ${BOOTSTRAP_LESS}.tmp; \ 14 | echo "Bootstrap successfully built! - `date`"; \ 15 | else \ 16 | echo "You must have the LESS compiler installed in order to build Bootstrap."; \ 17 | echo "You can install it by running: npm install less -g"; \ 18 | fi 19 | 20 | watch: 21 | @@if test ! -z ${WATCHR}; then \ 22 | echo "Watching less files..."; \ 23 | watchr -e "watch('lib/.*\.less') { system 'make' }"; \ 24 | else \ 25 | echo "You must have the watchr installed in order to watch Bootstrap less files."; \ 26 | echo "You can install it by running: gem install watchr"; \ 27 | fi 28 | 29 | .PHONY: build watch -------------------------------------------------------------------------------- /Lib/Templates/Misc/background-noise.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josegonzalez/cakephp-admin/1c010e57bd4d55889748b9979c83f3581cac4599/Lib/Templates/Misc/background-noise.gif -------------------------------------------------------------------------------- /Lib/Templates/Misc/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josegonzalez/cakephp-admin/1c010e57bd4d55889748b9979c83f3581cac4599/Lib/Templates/Misc/background.png -------------------------------------------------------------------------------- /Lib/Templates/Misc/cake.admin.generic.min.ctp: -------------------------------------------------------------------------------- 1 | 2 | html,body{margin:0;padding:0;} 3 | h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;font-weight:normal;font-style:normal;font-size:100%;line-height:1;font-family:inherit;} 4 | table{border-collapse:collapse;border-spacing:0;} 5 | ol,ul{list-style:none;} 6 | q:before,q:after,blockquote:before,blockquote:after{content:"";} 7 | header,section,footer,article,aside{display:block;} 8 | body{background:#000000 url('../img/background.png');color:#fff;font-family:"Helvetica Neue",Helvetica,Arial,Verdana,sans-serif;font-size:90%;margin:0;} 9 | a{color:#0686C8;text-decoration:underline;font-weight:bold;} 10 | a:hover{color:#056596;text-decoration:none;} 11 | a img{border:none;} 12 | h1,h2,h3,h4{font-family:"Helvetica Neue",Helvetica,Arial,Verdana,sans-serif;font-weight:normal;margin-bottom:0.5em;text-shadow:0 1px 0 white;} 13 | h1{color:#003d4c;font-size:140%;} 14 | h2{color:#000;border-bottom:1px solid #ccc;font-family:"Helvetica Neue",Helvetica,Arial,Verdana,sans-serif;font-size:180%;padding-bottom:5px;} 15 | h3{color:#495961;font-family:"Helvetica Neue",Helvetica,Arial,Verdana,sans-serif;font-size:155%;} 16 | h4{color:#111;font-size:12px;font-weight:bold;} 17 | ul,li{margin:0 12px;} 18 | #container{text-align:left;} 19 | #header{padding:16px 16px 0 16px;} 20 | #header h1{color:#fff;float:left;height:32px;line-height:32px;padding:0;text-shadow:2px 2px 2px #000;} 21 | #header h1 a{color:#fff;background:#003d4c;font-weight:normal;text-decoration:none;} 22 | #header h1 a:hover{color:#fff;background:#003d4c;text-decoration:underline;} 23 | #content{background:#f9f9f9 url('../img/background-noise.gif');clear:both;color:#333;margin:16px;overflow:auto;-opera-border-radius:5px;-o-border-radius:5px;-khtml-border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;-opera-border-radius:0 2px 16px black;-o-border-radius:0 2px 16px black;-khtml-border-radius:0 2px 16px black;-moz-border-radius:0 2px 16px black;-webkit-border-radius:0 2px 16px black;border-radius:0 2px 16px black;} 24 | #footer{clear:both;margin:0 16px 16px 16px;text-align:right;} 25 | div.form,div.index,div.view{float:right;width:76%;border-left:1px solid #666;padding:16px;} 26 | div.actions{float:left;width:16%;padding:16px;} 27 | div.actions h3{color:#777;margin-bottom:0.2em;margin-top:1em;text-shadow:0 1px 0 white;} 28 | div.actions h3:first-child{margin-top:0;} 29 | div.actions ul{margin:0;padding:0;} 30 | div.actions li{margin:0 0 0.5em 0;list-style-type:none;white-space:nowrap;padding:0;} 31 | div.actions ul li a{font-weight:normal;display:block;clear:both;} 32 | div.actions ul li a:hover{text-decoration:underline;} 33 | div.related{clear:both;display:block;} 34 | pre{background:#FEFBF3;border:1px solid rgba(0, 0, 0, 0.15);color:#000;display:block;font-family:Monaco, Andale Mono, Courier New, monospace;font-size:12px;line-height:16px;margin:16px;padding:16px;white-space:pre-wrap;-opera-border-radius:3px;-o-border-radius:3px;-khtml-border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:0 1px 2px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:0 1px 2px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:0 1px 2px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:0 1px 2px rgba(0, 0, 0, 0.1) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;} 35 | pre.cake-debug{background:#ffcc00;font-size:120%;line-height:140%;margin-top:1em;overflow:auto;position:relative;} 36 | div.cake-stack-trace{background:#fff;color:#333;margin:0px;padding:6px;font-size:120%;line-height:140%;overflow:auto;position:relative;} 37 | div.cake-code-dump pre{position:relative;overflow:auto;} 38 | div.cake-stack-trace pre,div.cake-code-dump pre{color:#000;background-color:#F0F0F0;margin:0px;padding:1em;overflow:auto;} 39 | div.cake-code-dump pre,div.cake-code-dump pre code{clear:both;font-size:12px;line-height:15px;margin:4px 2px;padding:4px;overflow:auto;} 40 | div.cake-code-dump span.code-highlight{background-color:#ff0;padding:4px;} 41 | div.code-coverage-results div.code-line{padding-left:5px;display:block;margin-left:10px;} 42 | div.code-coverage-results div.uncovered span.content{background:#ecc;} 43 | div.code-coverage-results div.covered span.content{background:#cec;} 44 | div.code-coverage-results div.ignored span.content{color:#aaa;} 45 | div.code-coverage-results span.line-num{color:#666;display:block;float:left;width:20px;text-align:right;margin-right:5px;} 46 | div.code-coverage-results span.line-num strong{color:#666;} 47 | div.code-coverage-results div.start{border:1px solid #aaa;border-width:1px 1px 0px 1px;margin-top:30px;padding-top:5px;} 48 | div.code-coverage-results div.end{border:1px solid #aaa;border-width:0px 1px 1px 1px;margin-bottom:30px;padding-bottom:5px;} 49 | div.code-coverage-results div.realstart{margin-top:0px;} 50 | div.code-coverage-results p.note{color:#bbb;padding:5px;margin:5px 0 10px;font-size:10px;} 51 | div.code-coverage-results span.result-bad{color:#a00;} 52 | div.code-coverage-results span.result-ok{color:#fa0;} 53 | div.code-coverage-results span.result-good{color:#0a0;} 54 | .navigation{background-color:rgba(200, 200, 200, 0.1);border:1px solid #444;float:right;height:28px;margin:0;padding:0;-opera-border-radius:2px;-o-border-radius:2px;-khtml-border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 2px 16px black,0 0 1px black,0 0 1px black,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:0 2px 16px black,0 0 1px black,0 0 1px black,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:0 2px 16px black,0 0 1px black,0 0 1px black,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:0 2px 16px black,0 0 1px black,0 0 1px black,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:0 2px 16px black,0 0 1px black,0 0 1px black,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:0 2px 16px black,0 0 1px black,0 0 1px black,transparent 0 0 0,transparent 0 0 0;box-shadow:0 2px 16px black;box-shadow:0 2px 16px black 0 0 1px black 0 0 1px black transparent 0 0 0 transparent 0 0 0;} 55 | .navigation li{color:#fff;list-style:none;float:left;margin:0 2px;} 56 | .navigation li a{color:#fff;display:block;font-size:12px;font-weight:normal;line-height:16px;padding:6px 1em;text-decoration:none;text-shadow:2px 2px 2px black;} 57 | .navigation li a:hover{text-decoration:underline;} 58 | .navigation li.first{margin-left:0;} 59 | table{background:#fff;clear:both;color:#333;font-size:11.2px;margin-bottom:11.2px;width:100%;} 60 | table a{color:#1B252C;text-decoration:none;} 61 | table a:hover{color:#1B252C;text-decoration:underline;} 62 | thead tr th:first-child{border-left:1px solid #ddd;-opera-border-top-left-radius:5px;-o-border-top-left-radius:5px;-khtml-border-top-left-radius:5px;-moz-border-radius-topleft:5px;-webkit-border-top-left-radius:5px;border-top-left-radius:5px;} 63 | thead tr th:last-child{-opera-border-top-right-radius:5px;-o-border-top-right-radius:5px;-khtml-border-top-right-radius:5px;-moz-border-radius-topright:5px;-webkit-border-top-right-radius:5px;border-top-right-radius:5px;} 64 | th{background-color:#f5f5f5;border:0;border-bottom:1px solid #ddd;border-top:1px solid #fdfdfd;text-align:left;padding:4px;} 65 | th.actions{text-align:center;} 66 | th a{display:block;font-size:11.2px;font-weight:normal;padding:2px 4px;} 67 | th a.asc:after{content:' ⇣';} 68 | th a.desc:after{content:' ⇡';} 69 | table tr td{background:#fafafa;border-bottom:1px solid #f0f0f0;line-height:11.2px;padding:6px;text-align:left;vertical-align:top;} 70 | table tr.altrow td{background:#fff;} 71 | table tr td a{height:11.2px;line-height:11.2px;padding:2px 0;} 72 | table tr td:first-child{border-left:1px solid #f0f0f0;} 73 | table tr td:last-child{border-right:1px solid #f0f0f0;} 74 | table tr:last-child td:first-child{-opera-border-bottom-left-radius:5px;-o-border-bottom-left-radius:5px;-khtml-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;-webkit-border-bottom-left-radius:5px;border-bottom-left-radius:5px;} 75 | table tr:last-child td:last-child{-opera-border-top-right-radius:5px;-o-border-top-right-radius:5px;-khtml-border-top-right-radius:5px;-moz-border-radius-topright:5px;-webkit-border-top-right-radius:5px;border-top-right-radius:5px;} 76 | td.actions{text-align:center;white-space:nowrap;} 77 | table td.actions a{margin:0px 6px;padding:2px 5px;} 78 | .cake-sql-log table{background:#f4f4f4;} 79 | .cake-sql-log td{padding:4px 8px;text-align:left;font-family:Monaco,Consolas,"Courier New",monospaced;} 80 | .cake-sql-log caption{color:#fff;} 81 | p.paging-details{color:#666;font-size:11.2px;padding-bottom:11.2px;text-align:center;} 82 | div.paging{background:#F1F1F1;border:1px solid #E5E5E5;clear:both;font-size:11.2px;margin:0 0 1em 0;padding:11.2px;text-align:center;-opera-border-radius:5px;-o-border-radius:5px;-khtml-border-radius:5px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;} 83 | div.paging span{padding:.2em .3em;} 84 | div.paging span.disabled{color:#ddd;display:inline;} 85 | div.paging span.current{color:#D1485E;font-weight:bold;} 86 | div.paging span a{color:#111;font-weight:normal;text-decoration:none;} 87 | div.paging span a:hover{text-decoration:underline;} 88 | dl{line-height:2em;margin:0em 0em;width:60%;} 89 | dt{line-height:2em;font-weight:bold;padding-left:4px;vertical-align:top;} 90 | dd{line-height:2em;margin-left:10em;margin-top:-2em;vertical-align:top;} 91 | form{margin-bottom:16px;}form fieldset{margin-bottom:16px;padding-top:16px;}form fieldset legend{display:block;margin-left:150px;font-size:20px;line-height:1;color:#404040;} 92 | form fieldset p{color:#bfbfbf;display:block;font-size:12px;line-height:16px;margin-left:150px;max-width:600px;} 93 | form div.input{margin-bottom:16px;} 94 | form .input.error{background-color:#FAE5E3;padding:20px 0;-opera-border-radius:4px;-o-border-radius:4px;-khtml-border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}form .input.error .error-message{color:#9D261D;padding-left:150px;padding-top:20px;} 95 | form .input.error input[type=text],form .input.error input[type=password],form .input.error textarea{border-color:#C87872;-webkit-box-shadow:0 0 3px rgba(171, 41, 32, 0.25),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:0 0 3px rgba(171, 41, 32, 0.25),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:0 0 3px rgba(171, 41, 32, 0.25),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:0 0 3px rgba(171, 41, 32, 0.25),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:0 0 3px rgba(171, 41, 32, 0.25),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:0 0 3px rgba(171, 41, 32, 0.25),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:0 0 3px rgba(171, 41, 32, 0.25);box-shadow:0 0 3px rgba(171, 41, 32, 0.25) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;}form .input.error input[type=text]:focus,form .input.error input[type=password]:focus,form .input.error textarea:focus{border-color:#ba554d;-webkit-box-shadow:0 0 6px rgba(171, 41, 32, 0.5),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:0 0 6px rgba(171, 41, 32, 0.5),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:0 0 6px rgba(171, 41, 32, 0.5),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:0 0 6px rgba(171, 41, 32, 0.5),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:0 0 6px rgba(171, 41, 32, 0.5),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:0 0 6px rgba(171, 41, 32, 0.5),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:0 0 6px rgba(171, 41, 32, 0.5);box-shadow:0 0 6px rgba(171, 41, 32, 0.5) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;} 96 | form label,form input,form select,form textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:normal;} 97 | form label{padding-top:4px;margin-right:20px;font-size:13px;line-height:18px;float:left;width:130px;text-align:right;color:#404040;} 98 | form .checkbox label{padding-top:0;} 99 | form input[type=checkbox],form input[type=radio]{cursor:pointer;} 100 | form input[type=text],form input[type=password],form textarea,form select,form .uneditable-input{display:inline-block;width:530px;margin:0;padding:4px;font-size:13px;line-height:16px;height:16px;color:#808080;border:1px solid #ccc;-opera-border-radius:3px;-o-border-radius:3px;-khtml-border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;} 101 | form select,form input[type=file]{height:24px;line-height:24px;} 102 | form textarea{height:auto;} 103 | form :-moz-placeholder{color:#bfbfbf;} 104 | form ::-webkit-input-placeholder{color:#bfbfbf;} 105 | form input[type=text],form input[type=password],form select,form textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;} 106 | form input[type=text]:focus,form input[type=password]:focus,form textarea:focus{outline:none;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;} 107 | form textarea{overflow-y:scroll;} 108 | form input[readonly]:focus,form textarea[readonly]:focus,form input.disabled{background:#f5f5f5;border-color:#ddd;-webkit-box-shadow:none,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:none,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:none,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:none,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:none,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:none,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:none;box-shadow:none transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;} 109 | input[type=submit]{width:auto;} 110 | .form .submit{margin-left:150px;} 111 | .actions form fieldset{padding-top:8px;} 112 | .actions form legend{margin-left:0;} 113 | .actions form label{display:block;float:none;width:auto;font-weight:bold;text-align:left;line-height:20px;padding-top:0;} 114 | .actions form div.clearfix{margin-bottom:8px;}.actions form div.clearfix div.input{margin-left:0;} 115 | .actions form ul.inputs-list{margin-bottom:0;}.actions form ul.inputs-list li{padding-top:0;}.actions form ul.inputs-list li label{font-weight:normal;padding-top:0;} 116 | .actions form input[type=text],.actions form input[type=password],.actions form textarea,.actions form select,.actions form .uneditable-input{width:auto;} 117 | .error-page #content{padding:16px;} 118 | .error-page h2{margin:0 16px 16px 16px;} 119 | .error-page p,.flash{background-color:rgba(0, 0, 0, 0.15);background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(transparent), to(rgba(0, 0, 0, 0.15)));background-image:-moz-linear-gradient(transparent, rgba(0, 0, 0, 0.15));background-image:-ms-linear-gradient(transparent, rgba(0, 0, 0, 0.15));background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, transparent), color-stop(100%, rgba(0, 0, 0, 0.15)));background-image:-webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.15));background-image:-o-linear-gradient(transparent, rgba(0, 0, 0, 0.15));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='transparent', endColorstr='rgba(0, 0, 0, 0.15)', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='transparent', endColorstr='rgba(0, 0, 0, 0.15)', GradientType=0);background-image:linear-gradient(transparent, rgba(0, 0, 0, 0.15));background-color:#e6e6e6;margin:16px;padding:8px 15px;color:#fff;text-shadow:none;border:1px solid rgba(0, 0, 0, 0.25);-opera-border-radius:4px;-o-border-radius:4px;-khtml-border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.25);}.error-page p em,.flash em{color:#000;} 120 | .error-page p p,.flash p{color:#fff;margin-bottom:0;}.error-page p p+p,.flash p+p{margin-top:5px;} 121 | .error-page p p.notice,.flash p.notice{color:#000;}.error-page p p.notice em,.flash p.notice em{color:#333;} 122 | .error-page p.error,.flash.error{background-color:#c43c35;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));background-image:-moz-linear-gradient(#ee5f5b, #c43c35);background-image:-ms-linear-gradient(#ee5f5b, #c43c35);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));background-image:-webkit-linear-gradient(#ee5f5b, #c43c35);background-image:-o-linear-gradient(#ee5f5b, #c43c35);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);background-image:linear-gradient(#ee5f5b, #c43c35);border-color:#c43c35 #c43c35 #882a25;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 123 | .error-page p.notice,.flash.notice{background-color:#eedc94;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));background-image:-moz-linear-gradient(#fceec1, #eedc94);background-image:-ms-linear-gradient(#fceec1, #eedc94);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));background-image:-webkit-linear-gradient(#fceec1, #eedc94);background-image:-o-linear-gradient(#fceec1, #eedc94);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0);background-image:linear-gradient(#fceec1, #eedc94);border-color:#eedc94 #eedc94 #e4c652;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);color:#000;} 124 | .error-page p.success,.flash.success{background-color:#57a957;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));background-image:-moz-linear-gradient(#62c462, #57a957);background-image:-ms-linear-gradient(#62c462, #57a957);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));background-image:-webkit-linear-gradient(#62c462, #57a957);background-image:-o-linear-gradient(#62c462, #57a957);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);background-image:linear-gradient(#62c462, #57a957);border-color:#57a957 #57a957 #3d773d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 125 | .error-page p.information,.flash.information{background-color:#339bb9;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));background-image:-moz-linear-gradient(#5bc0de, #339bb9);background-image:-ms-linear-gradient(#5bc0de, #339bb9);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));background-image:-webkit-linear-gradient(#5bc0de, #339bb9);background-image:-o-linear-gradient(#5bc0de, #339bb9);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);background-image:linear-gradient(#5bc0de, #339bb9);border-color:#339bb9 #339bb9 #22697d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} 126 | .error-page p a.close,.flash a.close{float:right;margin-top:-2px;color:#fff;font-size:20px;font-weight:bold;text-shadow:0 1px 0 rgba(0, 0, 0, 0.5);filter:alpha(opacity=50);-khtml-opacity:0.5;-moz-opacity:0.5;opacity:0.5;-opera-border-radius:3px;-o-border-radius:3px;-khtml-border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}.error-page p a.close:hover,.flash a.close:hover{text-decoration:none;filter:alpha(opacity=50);-khtml-opacity:0.5;-moz-opacity:0.5;opacity:0.5;} 127 | .destructive-form form{background:#f8dcda;border:1px solid #f4c8c5;color:#404040;color:rgba(0, 0, 0, 0.8);margin-bottom:16px;padding:14px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.25);-opera-border-radius:6px;-o-border-radius:6px;-khtml-border-radius:6px;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;}.destructive-form form p{color:#404040;color:rgba(0, 0, 0, 0.8);margin-right:30px;margin-bottom:0;} 128 | .destructive-form form ul{margin-bottom:0;} 129 | .destructive-form form strong{display:block;} 130 | .destructive-form form a.close{display:block;color:#404040;color:rgba(0, 0, 0, 0.5);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);} 131 | .destructive-form form .submit{margin-top:16px;margin-left:0;}.destructive-form form .submit input[type="submit"]{font-size:11px;margin-left:0;padding:0 9px;} 132 | input[type="submit"],div.actions ul li a,td.actions a{color:#333333;display:inline-block;background-color:#e6e6e6;background-repeat:no-repeat;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(0.25, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, color-stop(0.25, #ffffff), #e6e6e6);background-image:-moz-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, color-stop(#ffffff, 0.25), #e6e6e6);background-image:-o-linear-gradient(#ffffff, color-stop(#ffffff, 0.25), #e6e6e6);background-image:linear-gradient(#ffffff, color-stop(#ffffff, 0.25), #e6e6e6);font-size:12px;font-weight:normal;line-height:13px;padding:4px 14px;text-decoration:none;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);border:1px solid rgba(0, 0, 0, 0.1);border-bottom-color:rgba(0, 0, 0, 0.25);-opera-border-radius:4px;-o-border-radius:4px;-khtml-border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;-webkit-transition:0.1s linear all;-moz-transition:0.1s linear all;transition:0.1s linear all;}input[type="submit"]:hover,div.actions ul li a:hover,td.actions a:hover{background-position:0 -15px;color:#333333;text-decoration:none;} 133 | input[type="submit"].primary,div.actions ul li a.primary,td.actions a.primary{background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(#049cdb, #0064cd);background-image:-ms-linear-gradient(#049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(#049cdb, #0064cd);background-image:-o-linear-gradient(#049cdb, #0064cd);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);background-image:linear-gradient(#049cdb, #0064cd);color:#fff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}input[type="submit"].primary:hover,div.actions ul li a.primary:hover,td.actions a.primary:hover{color:#fff;} 134 | input[type="submit"].large,div.actions ul li a.large,td.actions a.large{font-size:16px;line-height:28px;-opera-border-radius:6px;-o-border-radius:6px;-khtml-border-radius:6px;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;} 135 | input[type="submit"].small,div.actions ul li a.small,td.actions a.small{padding-right:9px;padding-left:9px;font-size:11px;} 136 | input[type="submit"]:disabled,div.actions ul li a:disabled,td.actions a:disabled,input[type="submit"].disabled,div.actions ul li a.disabled,td.actions a.disabled{background-image:none;filter:alpha(opacity=65);-khtml-opacity:0.65;-moz-opacity:0.65;opacity:0.65;cursor:default;} 137 | input[type="submit"]:active,div.actions ul li a:active,td.actions a:active{-webkit-box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-opera-box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-o-box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-khtml-box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-moz-box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;-webkit-box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05),transparent 0 0 0,transparent 0 0 0,transparent 0 0 0,transparent 0 0 0;box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 3px 7px rgba(0, 0, 0, 0.1),0 1px 2px rgba(0, 0, 0, 0.05) transparent 0 0 0 transparent 0 0 0 transparent 0 0 0 transparent 0 0 0;} 138 | input[type="submit"]::-moz-focus-inner,div.actions ul li a::-moz-focus-inner,td.actions a::-moz-focus-inner{padding:0;border:0;} 139 | td.actions a{font-size:10px;} 140 | div.actions ul li a{text-align:center;width:90%;} 141 | div.submit input[type="submit"]{background-color:#0064cd;background-repeat:repeat-x;background-image:-khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));background-image:-moz-linear-gradient(#049cdb, #0064cd);background-image:-ms-linear-gradient(#049cdb, #0064cd);background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));background-image:-webkit-linear-gradient(#049cdb, #0064cd);background-image:-o-linear-gradient(#049cdb, #0064cd);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);background-image:linear-gradient(#049cdb, #0064cd);color:#fff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);font-size:16px;line-height:28px;-opera-border-radius:6px;-o-border-radius:6px;-khtml-border-radius:6px;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px;}div.submit input[type="submit"]:hover{color:#fff;} 142 | div.actions div.submit input[type="submit"]{padding:0 9px;font-size:11px;} 143 | -------------------------------------------------------------------------------- /Lib/Templates/Misc/flash/error.ctp: -------------------------------------------------------------------------------- 1 | "; ?> -------------------------------------------------------------------------------- /Lib/Templates/Misc/flash/info.ctp: -------------------------------------------------------------------------------- 1 | "; ?> -------------------------------------------------------------------------------- /Lib/Templates/Misc/flash/notice.ctp: -------------------------------------------------------------------------------- 1 | "; ?> -------------------------------------------------------------------------------- /Lib/Templates/Misc/flash/success.ctp: -------------------------------------------------------------------------------- 1 | "; ?> -------------------------------------------------------------------------------- /Lib/Templates/Misc/layout.default.ctp: -------------------------------------------------------------------------------- 1 | $cakeAdmins) { 4 | foreach ($cakeAdmins as $cakeAdmin) { 5 | $links[] = array( 6 | 'title' => $cakeAdmin['title'], 7 | 'plugin' => $pluginName, 8 | 'controller' => $cakeAdmin['controller'], 9 | 'action' => $cakeAdmin['action'], 10 | 'link' => "\$this->Html->link('{$cakeAdmin['title']}', array('plugin' => '{$pluginName}', 'controller' => '{$cakeAdmin['controller']}', 'action' => '{$cakeAdmin['action']}'));" 11 | ); 12 | } 13 | } 14 | echo" 15 | 34 | 35 | 36 | 37 | Html->charset(); ?> 38 | <?php echo __('%s - Dashboard', \$title_for_layout); ?> 39 | Html->meta('icon'); 41 | 42 | echo \$this->Html->css('/{$plugin}/css/cake.admin.generic.min'); 43 | 44 | echo \$scripts_for_layout; 45 | ?> 46 | 47 | name == 'CakeError') echo 'error-page'; ?>\"> 48 |
49 |
50 |

request->params['controller'])); ?>

51 |
    \n"; 52 | foreach ($links as $i => $link) { 53 | if ($i === 0) { 54 | echo "\t\t\t
  • request->params['plugin'] === '{$link['plugin']}' && \$this->request->params['controller'] === '{$link['controller']}') echo ' on'?>\">\n\t\t\t\t\n\t\t\t
  • \n"; 55 | } else { 56 | echo "\t\t\t
  • request->params['plugin'] === '{$link['plugin']}' && \$this->request->params['controller'] === '{$link['controller']}') echo 'on'?>\">\n\t\t\t\t\n\t\t\t
  • \n"; 57 | } 58 | } 59 | echo "
60 |
61 |
62 |
63 | 64 | Session->flash(); ?> 65 | 66 | 67 | 68 |
69 |
70 | Html->link( 71 | \$this->Html->image('cake.power.gif', array('alt'=> __('CakePHP: the rapid development php framework'), 'border' => '0')), 72 | 'http://www.cakephp.org/', 73 | array('target' => '_blank', 'escape' => false) 74 | ); 75 | ?> 76 |
77 |
78 | 79 | 80 | "; 81 | ?> -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/01_reset.less: -------------------------------------------------------------------------------- 1 | /* Reset.less 2 | * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset 3 | * HTML elements we will never need here (i.e., dfn, samp, etc). 4 | * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ 5 | 6 | 7 | // ERIC MEYER RESET 8 | // ---------------- 9 | 10 | html, body { margin: 0; padding: 0; } 11 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, cite, code, del, dfn, em, img, q, s, samp, small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; font-weight: normal; font-style: normal; font-size: 100%; line-height: 1; font-family: inherit; } 12 | table { border-collapse: collapse; border-spacing: 0; } 13 | ol, ul { list-style: none; } 14 | q:before, q:after, blockquote:before, blockquote:after { content: ""; } 15 | 16 | 17 | // HTML5 18 | // ----- 19 | 20 | header, section, footer, article, aside { 21 | display: block; 22 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/02_general.less: -------------------------------------------------------------------------------- 1 | /** General Style Info **/ 2 | body { 3 | background: #000 url('../img/background.png'); 4 | color: #fff; 5 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif; 6 | font-size:90%; 7 | margin: 0; 8 | } 9 | a { 10 | color: #0686C8; 11 | text-decoration: underline; 12 | font-weight: bold; 13 | } 14 | a:hover { 15 | color: #056596; 16 | text-decoration:none; 17 | } 18 | a img { 19 | border:none; 20 | } 21 | h1, h2, h3, h4 { 22 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif; 23 | font-weight: normal; 24 | margin-bottom:0.5em; 25 | text-shadow: 0 1px 0 white; 26 | } 27 | h1 { 28 | color: #003d4c; 29 | font-size: 140%; 30 | } 31 | h2 { 32 | color: #000; 33 | border-bottom: 1px solid #ccc; 34 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif; 35 | font-size: 180%; 36 | padding-bottom: 5px; 37 | } 38 | h3 { 39 | color: #495961; 40 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif; 41 | font-size: 155%; 42 | } 43 | h4 { 44 | color: #111; 45 | font-size: 12px; 46 | font-weight: bold; 47 | } 48 | ul, li { 49 | margin: 0 12px; 50 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/03_layout.less: -------------------------------------------------------------------------------- 1 | /** Layout **/ 2 | #container { 3 | text-align: left; 4 | } 5 | 6 | #header{ 7 | padding: @baseline @baseline 0 @baseline; 8 | } 9 | #header h1 { 10 | color: #fff; 11 | float: left; 12 | height: @baseline * 2; 13 | line-height: @baseline * 2; 14 | padding: 0; 15 | text-shadow: 2px 2px 2px #000; 16 | } 17 | #header h1 a { 18 | color: #fff; 19 | background: #003d4c; 20 | font-weight: normal; 21 | text-decoration: none; 22 | } 23 | #header h1 a:hover { 24 | color: #fff; 25 | background: #003d4c; 26 | text-decoration: underline; 27 | } 28 | #content { 29 | background: #f9f9f9 url('../img/background-noise.gif'); 30 | clear: both; 31 | color: #333; 32 | margin: @baseline; 33 | overflow: auto; 34 | .border-radius(5px); 35 | .border-radius(0 2px 16px black, 0 0 1px black, 0 0 1px black); 36 | } 37 | #footer { 38 | clear: both; 39 | margin: 0 @baseline @baseline @baseline; 40 | text-align: right; 41 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/04_scaffolding.less: -------------------------------------------------------------------------------- 1 | /** Containers **/ 2 | div.form, 3 | div.index, 4 | div.view { 5 | float:right; 6 | width:76%; 7 | border-left:1px solid #666; 8 | padding: @baseline; 9 | } 10 | div.actions { 11 | float:left; 12 | width:16%; 13 | padding: @baseline; 14 | } 15 | div.actions h3 { 16 | color:#777; 17 | margin-bottom: 0.2em; 18 | margin-top: 1em; 19 | text-shadow: 0 1px 0 white; 20 | } 21 | div.actions h3:first-child { 22 | margin-top: 0; 23 | } 24 | /** Actions **/ 25 | div.actions ul { 26 | margin: 0; 27 | padding: 0; 28 | } 29 | div.actions li { 30 | margin:0 0 0.5em 0; 31 | list-style-type: none; 32 | white-space: nowrap; 33 | padding: 0; 34 | } 35 | div.actions ul li a { 36 | font-weight: normal; 37 | display: block; 38 | clear: both; 39 | } 40 | div.actions ul li a:hover { 41 | text-decoration: underline; 42 | } 43 | 44 | /** Related **/ 45 | div.related { 46 | clear: both; 47 | display: block; 48 | } 49 | 50 | /** Debugging **/ 51 | pre { 52 | background: #FEFBF3; 53 | border: 1px solid rgba(0, 0, 0, 0.15); 54 | color: #000; 55 | display: block; 56 | font-family: Monaco, Andale Mono, Courier New, monospace; 57 | font-size: @baseline - 4; 58 | line-height: @baseline; 59 | margin: @baseline; 60 | padding: @baseline; 61 | white-space: pre-wrap; 62 | .border-radius(3px); 63 | .box-shadow(0 1px 2px rgba(0,0,0,.1)); 64 | } 65 | pre.cake-debug { 66 | background: #ffcc00; 67 | font-size: 120%; 68 | line-height: 140%; 69 | margin-top: 1em; 70 | overflow: auto; 71 | position: relative; 72 | } 73 | div.cake-stack-trace { 74 | background: #fff; 75 | color: #333; 76 | margin: 0px; 77 | padding: 6px; 78 | font-size: 120%; 79 | line-height: 140%; 80 | overflow: auto; 81 | position: relative; 82 | } 83 | div.cake-code-dump pre { 84 | position: relative; 85 | overflow: auto; 86 | } 87 | div.cake-stack-trace pre, div.cake-code-dump pre { 88 | color: #000; 89 | background-color: #F0F0F0; 90 | margin: 0px; 91 | padding: 1em; 92 | overflow: auto; 93 | } 94 | div.cake-code-dump pre, div.cake-code-dump pre code { 95 | clear: both; 96 | font-size: 12px; 97 | line-height: 15px; 98 | margin: 4px 2px; 99 | padding: 4px; 100 | overflow: auto; 101 | } 102 | div.cake-code-dump span.code-highlight { 103 | background-color: #ff0; 104 | padding: 4px; 105 | } 106 | div.code-coverage-results div.code-line { 107 | padding-left:5px; 108 | display:block; 109 | margin-left:10px; 110 | } 111 | div.code-coverage-results div.uncovered span.content { 112 | background:#ecc; 113 | } 114 | div.code-coverage-results div.covered span.content { 115 | background:#cec; 116 | } 117 | div.code-coverage-results div.ignored span.content { 118 | color:#aaa; 119 | } 120 | div.code-coverage-results span.line-num { 121 | color:#666; 122 | display:block; 123 | float:left; 124 | width:20px; 125 | text-align:right; 126 | margin-right:5px; 127 | } 128 | div.code-coverage-results span.line-num strong { 129 | color:#666; 130 | } 131 | div.code-coverage-results div.start { 132 | border:1px solid #aaa; 133 | border-width:1px 1px 0px 1px; 134 | margin-top:30px; 135 | padding-top:5px; 136 | } 137 | div.code-coverage-results div.end { 138 | border:1px solid #aaa; 139 | border-width:0px 1px 1px 1px; 140 | margin-bottom:30px; 141 | padding-bottom:5px; 142 | } 143 | div.code-coverage-results div.realstart { 144 | margin-top:0px; 145 | } 146 | div.code-coverage-results p.note { 147 | color:#bbb; 148 | padding:5px; 149 | margin:5px 0 10px; 150 | font-size:10px; 151 | } 152 | div.code-coverage-results span.result-bad { 153 | color: #a00; 154 | } 155 | div.code-coverage-results span.result-ok { 156 | color: #fa0; 157 | } 158 | div.code-coverage-results span.result-good { 159 | color: #0a0; 160 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/05_navigation.less: -------------------------------------------------------------------------------- 1 | /** Navigation **/ 2 | .navigation { 3 | background-color: rgba(200, 200, 200, 0.1); 4 | border: 1px solid #444; 5 | float: right; 6 | height: @baseline * 2 - 4; 7 | margin: 0; 8 | padding: 0; 9 | .border-radius(2px); 10 | .box-shadow(0 2px 16px black, 0 0 1px black, 0 0 1px black); 11 | } 12 | .navigation li { 13 | color: #fff; 14 | list-style: none; 15 | float: left; 16 | margin: 0 2px; 17 | } 18 | .navigation li a { 19 | color: #fff; 20 | display: block; 21 | font-size: @baseline - 4; 22 | font-weight: normal; 23 | line-height: @baseline; 24 | padding: 6px 1em; 25 | text-decoration: none; 26 | text-shadow: 2px 2px 2px black; 27 | } 28 | .navigation li a:hover { 29 | text-decoration:underline; 30 | } 31 | .navigation li.first { 32 | margin-left: 0; 33 | } 34 | -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/06_tables.less: -------------------------------------------------------------------------------- 1 | /** Tables **/ 2 | table { 3 | background: #fff; 4 | clear: both; 5 | color: #333; 6 | font-size: @baseline * .7; 7 | margin-bottom: @baseline * .7; 8 | width: 100%; 9 | } 10 | table a { 11 | color: #1B252C; 12 | text-decoration: none; 13 | } 14 | table a:hover { 15 | color: #1B252C; 16 | text-decoration: underline; 17 | } 18 | thead tr th:first-child { 19 | border-left: 1px solid #ddd; 20 | .border-radius-top-left(5px); 21 | } 22 | thead tr th:last-child { 23 | .border-radius-top-right(5px); 24 | } 25 | th { 26 | background-color: #f5f5f5; 27 | border:0; 28 | border-bottom: 1px solid #ddd; 29 | border-top: 1px solid #fdfdfd; 30 | text-align: left; 31 | padding: 4px; 32 | } 33 | th.actions { 34 | text-align: center; 35 | } 36 | th a { 37 | display: block; 38 | font-size: @baseline * .7; 39 | font-weight: normal; 40 | padding: 2px 4px; 41 | } 42 | th a.asc:after { 43 | content: ' ⇣'; 44 | } 45 | th a.desc:after { 46 | content: ' ⇡'; 47 | } 48 | table tr td { 49 | background: #fafafa; 50 | border-bottom: 1px solid #f0f0f0; 51 | line-height: @baseline * .7; 52 | padding: 6px; 53 | text-align: left; 54 | vertical-align: top; 55 | } 56 | table tr.altrow td { 57 | background: #fff; 58 | } 59 | table tr td a { 60 | height: @baseline * .7; 61 | line-height: @baseline * .7; 62 | padding: 2px 0; 63 | } 64 | table tr td:first-child { 65 | border-left: 1px solid #f0f0f0; 66 | } 67 | table tr td:last-child { 68 | border-right: 1px solid #f0f0f0; 69 | } 70 | table tr:last-child td:first-child { 71 | .border-radius-bottom-left(5px); 72 | } 73 | table tr:last-child td:last-child { 74 | .border-radius-top-right(5px); 75 | } 76 | td.actions { 77 | text-align: center; 78 | white-space: nowrap; 79 | } 80 | table td.actions a { 81 | margin: 0px 6px; 82 | padding:2px 5px; 83 | } 84 | .cake-sql-log table { 85 | background: #f4f4f4; 86 | } 87 | .cake-sql-log td { 88 | padding: 4px 8px; 89 | text-align: left; 90 | font-family: Monaco, Consolas, "Courier New", monospaced; 91 | } 92 | .cake-sql-log caption { 93 | color:#fff; 94 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/07_paging.less: -------------------------------------------------------------------------------- 1 | /** Paging **/ 2 | p.paging-details { 3 | color: #666; 4 | font-size: @baseline * .7; 5 | padding-bottom: @baseline * .7; 6 | text-align: center; 7 | } 8 | div.paging { 9 | background: #F1F1F1; 10 | border: 1px solid #E5E5E5; 11 | clear:both; 12 | font-size: @baseline * .7; 13 | margin: 0 0 1em 0; 14 | padding: @baseline * .7; 15 | text-align: center; 16 | .border-radius(5px); 17 | } 18 | div.paging span { 19 | padding: .2em .3em; 20 | } 21 | div.paging span.disabled { 22 | color: #ddd; 23 | display: inline; 24 | } 25 | div.paging span.current { 26 | color: #D1485E; 27 | font-weight: bold; 28 | } 29 | div.paging span a { 30 | color: #111; 31 | font-weight: normal; 32 | text-decoration: none; 33 | } 34 | div.paging span a:hover { 35 | text-decoration: underline; 36 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/08_definition.less: -------------------------------------------------------------------------------- 1 | /** Scaffold View **/ 2 | dl { 3 | line-height: 2em; 4 | margin: 0em 0em; 5 | width: 60%; 6 | } 7 | dt { 8 | line-height: 2em; 9 | font-weight: bold; 10 | padding-left: 4px; 11 | vertical-align: top; 12 | } 13 | dd { 14 | line-height: 2em; 15 | margin-left: 10em; 16 | margin-top: -2em; 17 | vertical-align: top; 18 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/09_forms.less: -------------------------------------------------------------------------------- 1 | form { 2 | margin-bottom: @baseline; 3 | 4 | // Groups of fields with labels on top (legends) 5 | fieldset { 6 | margin-bottom: @baseline; 7 | padding-top: @baseline; 8 | legend { 9 | display: block; 10 | margin-left: 150px; 11 | font-size: 20px; 12 | line-height: 1; 13 | color: @grayDark; 14 | } 15 | // Big blocks of help text 16 | p { 17 | color: @grayLight; 18 | display: block; 19 | font-size: 12px; 20 | line-height: @baseline; 21 | margin-left: 150px; 22 | max-width: 600px; 23 | } 24 | } 25 | // Parent element that clears floats and wraps labels and fields together 26 | div.input { 27 | margin-bottom: @baseline; 28 | } 29 | .input.error { 30 | background-color: #FAE5E3; 31 | padding: 20px 0; 32 | .border-radius(4px); 33 | .error-message { 34 | color: #9D261D; 35 | padding-left: 150px; 36 | padding-top: 20px; 37 | } 38 | input[type=text], 39 | input[type=password], 40 | textarea { 41 | border-color: #C87872; 42 | .box-shadow(0 0 3px rgba(171,41,32,.25)); 43 | &:focus { 44 | border-color: darken(#C87872, 10%); 45 | .box-shadow(0 0 6px rgba(171,41,32,.5)); 46 | } 47 | } 48 | } 49 | // Set font for forms 50 | label, input, select, textarea { 51 | #font > .sans-serif(normal,13px,normal); 52 | } 53 | // Float labels left 54 | label { 55 | padding-top: 4px; 56 | margin-right: 20px; 57 | font-size: 13px; 58 | line-height: 18px; 59 | float: left; 60 | width: 130px; 61 | text-align: right; 62 | color: @grayDark; 63 | } 64 | .checkbox label { 65 | padding-top: 0; 66 | } 67 | // Checkboxs and radio buttons 68 | input[type=checkbox], 69 | input[type=radio] { 70 | cursor: pointer; 71 | } 72 | 73 | // Inputs, Textareas, Selects 74 | input[type=text], 75 | input[type=password], 76 | textarea, 77 | select, 78 | .uneditable-input { 79 | display: inline-block; 80 | width: 530px; 81 | margin: 0; 82 | padding: 4px; 83 | font-size: 13px; 84 | line-height: @baseline; 85 | height: @baseline; 86 | color: @gray; 87 | border: 1px solid #ccc; 88 | .border-radius(3px); 89 | } 90 | select, 91 | input[type=file] { 92 | height: @baseline * 1.5; 93 | line-height: @baseline * 1.5; 94 | } 95 | textarea { 96 | height: auto; 97 | } 98 | 99 | // Placeholder text gets special styles; can't be bundled together though for some reason 100 | :-moz-placeholder { 101 | color: @grayLight; 102 | } 103 | ::-webkit-input-placeholder { 104 | color: @grayLight; 105 | } 106 | 107 | // Focus states 108 | input[type=text], 109 | input[type=password], 110 | select, textarea { 111 | @transition: border linear .2s, box-shadow linear .2s; 112 | .transition(@transition); 113 | .box-shadow(inset 0 1px 3px rgba(0,0,0,.1)); 114 | } 115 | input[type=text]:focus, 116 | input[type=password]:focus, 117 | textarea:focus { 118 | outline: none; 119 | border-color: rgba(82,168,236,.8); 120 | @shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 121 | .box-shadow(@shadow); 122 | } 123 | textarea { 124 | overflow-y: scroll; 125 | } 126 | 127 | // Turn off focus for disabled (read-only) form elements 128 | input[readonly]:focus, 129 | textarea[readonly]:focus, 130 | input.disabled { 131 | background: #f5f5f5; 132 | border-color: #ddd; 133 | .box-shadow(none); 134 | } 135 | 136 | } 137 | input[type=submit] { 138 | width: auto; 139 | } 140 | .form .submit { 141 | margin-left: 150px; 142 | } 143 | // Stacked forms 144 | .actions form { 145 | fieldset { 146 | padding-top: @baseline / 2; 147 | } 148 | legend { 149 | margin-left: 0; 150 | } 151 | label { 152 | display: block; 153 | float: none; 154 | width: auto; 155 | font-weight: bold; 156 | text-align: left; 157 | line-height: 20px; 158 | padding-top: 0; 159 | } 160 | div.clearfix { 161 | margin-bottom: @baseline / 2; 162 | div.input { 163 | margin-left: 0; 164 | } 165 | } 166 | ul.inputs-list { 167 | margin-bottom: 0; 168 | li { 169 | padding-top: 0; 170 | label { 171 | font-weight: normal; 172 | padding-top: 0; 173 | } 174 | } 175 | } 176 | input[type=text], 177 | input[type=password], 178 | textarea, 179 | select, 180 | .uneditable-input { 181 | width: auto; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/10_notifications.less: -------------------------------------------------------------------------------- 1 | /** Notices and Errors **/ 2 | .error-page #content { 3 | padding: @baseline; 4 | } 5 | .error-page h2 { 6 | margin: 0 @baseline @baseline @baseline; 7 | } 8 | 9 | // One-liner alert bars 10 | .error-page p, .flash { 11 | #gradient > .vertical(transparent, rgba(0,0,0,0.15)); 12 | background-color: @grayLighter; 13 | margin: @baseline; 14 | padding: 8px 15px; 15 | color: #fff; 16 | text-shadow: none; 17 | border: 1px solid rgba(0,0,0,.25); 18 | .border-radius(4px); 19 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); 20 | em { 21 | color: #000; 22 | } 23 | p { 24 | color: #fff; 25 | margin-bottom: 0; 26 | + p { 27 | margin-top: 5px; 28 | } 29 | &.notice { 30 | color: #000; 31 | em { 32 | color: #333; 33 | } 34 | } 35 | } 36 | &.error { 37 | .gradientBar(#ee5f5b, #c43c35); 38 | } 39 | &.notice { 40 | .gradientBar(#fceec1, #eedc94); 41 | color: #000; 42 | } 43 | &.success { 44 | .gradientBar(#62c462, #57a957); 45 | } 46 | &.information { 47 | .gradientBar(#5bc0de, #339bb9); 48 | } 49 | a.close { 50 | float: right; 51 | margin-top: -2px; 52 | color: #fff; 53 | font-size: 20px; 54 | font-weight: bold; 55 | text-shadow: 0 1px 0 rgba(0,0,0,.5); 56 | .opacity(50); 57 | .border-radius(3px); 58 | &:hover { 59 | text-decoration: none; 60 | .opacity(50); 61 | } 62 | } 63 | } 64 | 65 | // Block-level Alerts 66 | .destructive-form form { 67 | background: lighten(@red, 55%); 68 | border: 1px solid lighten(@red, 50%); 69 | color: @grayDark; 70 | color: rgba(0,0,0,.8); 71 | margin-bottom: @baseline; 72 | padding: 14px; 73 | text-shadow: 0 1px 0 rgba(255,255,255,.25); 74 | .border-radius(6px); 75 | p { 76 | color: @grayDark; 77 | color: rgba(0,0,0,.8); 78 | margin-right: 30px; 79 | margin-bottom: 0; 80 | } 81 | ul { 82 | margin-bottom: 0; 83 | } 84 | strong { 85 | display: block; 86 | } 87 | a.close { 88 | display: block; 89 | color: @grayDark; 90 | color: rgba(0,0,0,.5); 91 | text-shadow: 0 1px 1px rgba(255,255,255,.75); 92 | } 93 | .submit { 94 | margin-top: @baseline; 95 | margin-left: 0; 96 | 97 | input[type="submit"] { 98 | font-size: 11px; 99 | margin-left: 0; 100 | padding: 0 9px; 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/11_buttons.less: -------------------------------------------------------------------------------- 1 | // Buttons 2 | input[type="submit"], div.actions ul li a, td.actions a { 3 | .button(); 4 | .transition(.1s linear all); 5 | &.primary { 6 | #gradient > .vertical(@blue, @blueDark); 7 | color: #fff; 8 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 9 | &:hover { 10 | color: #fff; 11 | } 12 | } 13 | &.large { 14 | font-size: 16px; 15 | line-height: 28px; 16 | .border-radius(6px); 17 | } 18 | &.small { 19 | padding-right: 9px; 20 | padding-left: 9px; 21 | font-size: 11px; 22 | } 23 | &:disabled, 24 | &.disabled { 25 | background-image: none; 26 | .opacity(65); 27 | cursor: default; 28 | } 29 | &:active { 30 | @shadow: inset 0 3px 7px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.05); 31 | .box-shadow(@shadow); 32 | } 33 | } 34 | 35 | // Help Firefox not be a jerk about adding extra padding to buttons 36 | input[type="submit"], div.actions ul li a, td.actions a { 37 | &::-moz-focus-inner { 38 | padding: 0; 39 | border: 0; 40 | } 41 | } 42 | td.actions a { 43 | font-size: 10px; 44 | } 45 | div.actions ul li a { 46 | text-align: center; 47 | width: 90%; 48 | } 49 | div.submit input[type="submit"] { 50 | #gradient > .vertical(@blue, @blueDark); 51 | color: #fff; 52 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 53 | font-size: 16px; 54 | line-height: 28px; 55 | .border-radius(6px); 56 | &:hover { 57 | color: #fff; 58 | } 59 | } 60 | div.actions div.submit input[type="submit"] { 61 | padding: 0 9px; 62 | font-size: 11px; 63 | } -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap version 1 3 | * 4 | * Copyright 2011 Jose Diaz-Gonzalez 5 | * Licensed under the MIT License 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | // Mixins 10 | @import "preboot.less"; 11 | 12 | // CSS Reset 13 | @import "01_reset.less"; 14 | 15 | // General stuff 16 | @import "02_general.less"; 17 | @import "03_layout.less"; 18 | @import "04_scaffolding.less"; 19 | 20 | // Styled patterns and elements 21 | @import "05_navigation.less"; 22 | @import "06_tables.less"; 23 | @import "07_paging.less"; 24 | @import "08_definition.less"; 25 | @import "09_forms.less"; 26 | @import "10_notifications.less"; 27 | @import "11_buttons.less"; -------------------------------------------------------------------------------- /Lib/Templates/Misc/less/preboot.less: -------------------------------------------------------------------------------- 1 | // Grays 2 | @black: #000; 3 | @grayDark: lighten(@black, 25%); 4 | @gray: lighten(@black, 50%); 5 | @grayLight: lighten(@black, 75%); 6 | @grayLighter: lighten(@black, 90%); 7 | @white: #fff; 8 | 9 | // Baseline grid 10 | @basefont: 13px; 11 | @baseline: 16px; 12 | 13 | // Accent Colors 14 | @blue: #049CDB; 15 | @blueDark: #0064CD; 16 | @green: #46a546; 17 | @red: #9d261d; 18 | @yellow: #ffc40d; 19 | @orange: #f89406; 20 | @pink: #c3325f; 21 | @purple: #7a43b6; 22 | 23 | .border-radius(@radius: 2px) { 24 | -opera-border-radius: @radius; 25 | -o-border-radius: @radius; 26 | -khtml-border-radius: @radius; 27 | -moz-border-radius: @radius; 28 | -webkit-border-radius: @radius; 29 | border-radius: @radius; 30 | } 31 | .border-radius-top-left(@radius: 2px) { 32 | -opera-border-top-left-radius: @radius; 33 | -o-border-top-left-radius: @radius; 34 | -khtml-border-top-left-radius: @radius; 35 | -moz-border-radius-topleft: @radius; 36 | -webkit-border-top-left-radius: @radius; 37 | border-top-left-radius: @radius; 38 | } 39 | .border-radius-top-right(@radius: 2px) { 40 | -opera-border-top-right-radius: @radius; 41 | -o-border-top-right-radius: @radius; 42 | -khtml-border-top-right-radius: @radius; 43 | -moz-border-radius-topright: @radius; 44 | -webkit-border-top-right-radius: @radius; 45 | border-top-right-radius: @radius; 46 | } 47 | .border-radius-bottom-right(@radius: 2px) { 48 | -opera-border-bottom-right-radius: @radius; 49 | -o-border-bottom-right-radius: @radius; 50 | -khtml-border-bottom-right-radius: @radius; 51 | -moz-border-radius-bottomright: @radius; 52 | -webkit-border-bottom-right-radius: @radius; 53 | border-bottom-right-radius: @radius; 54 | } 55 | .border-radius-bottom-left(@radius: 2px) { 56 | -opera-border-bottom-left-radius: @radius; 57 | -o-border-bottom-left-radius: @radius; 58 | -khtml-border-bottom-left-radius: @radius; 59 | -moz-border-radius-bottomleft: @radius; 60 | -webkit-border-bottom-left-radius: @radius; 61 | border-bottom-left-radius: @radius; 62 | } 63 | .box-shadow(@shadow1, @shadow2: transparent 0 0 0, @shadow3: transparent 0 0 0, @shadow4: transparent 0 0 0, @shadow5: transparent 0 0 0) { 64 | -webkit-box-shadow: @shadow1, @shadow2, @shadow3, @shadow4, @shadow5; 65 | -opera-box-shadow: @shadow1, @shadow2, @shadow3, @shadow4, @shadow5; 66 | -o-box-shadow: @shadow1, @shadow2, @shadow3, @shadow4, @shadow5; 67 | -khtml-box-shadow: @shadow1, @shadow2, @shadow3, @shadow4, @shadow5; 68 | -moz-box-shadow: @shadow1, @shadow2, @shadow3, @shadow4, @shadow5; 69 | -webkit-box-shadow: @shadow1, @shadow2, @shadow3, @shadow4, @shadow5; 70 | box-shadow: @shadow1; 71 | box-shadow: @arguments; 72 | } 73 | .background-gradient(@from:#00adee, @to:#0078a5) { 74 | background: @from; 75 | background-image: -webkit-gradient(linear, left top, left bottom, from(@from), to(@to)); 76 | background-image: -moz-linear-gradient(top, @from, @to); 77 | filter: formatstring("progid:DXImageTransform.Microsoft.gradient(startColorstr='{0}', endColorstr='{1}')", @from, @to); /* IE6,IE7 */ 78 | -ms-filter: formatstring("\"progid:DXImageTransform.Microsoft.gradient(startColorStr='{0}', EndColorStr='{1}')\"", @from, @to); /* IE8 */ 79 | } 80 | // Transitions 81 | .transition(@transition) { 82 | -webkit-transition: @transition; 83 | -moz-transition: @transition; 84 | transition: @transition; 85 | } 86 | // Opacity 87 | .opacity(@opacity: 100) { 88 | filter: e(%("alpha(opacity=%d)", @opacity)); 89 | -khtml-opacity: @opacity / 100; 90 | -moz-opacity: @opacity / 100; 91 | opacity: @opacity / 100; 92 | } 93 | // Buttons 94 | .button(@color: #fff, @padding: 4px 14px, @textColor: #333, @textShadow: 0 1px 1px rgba(255,255,255,.75), @fontSize: 13px, @borderColor: rgba(0,0,0,.1), @borderRadius: 4px) { 95 | color: @textColor; 96 | display: inline-block; 97 | #gradient > .vertical-three-colors(@color, @color, 0.25, darken(@color, 10%)); 98 | font-size: @fontSize - 1; 99 | font-weight: normal; 100 | line-height: @fontSize; 101 | padding: @padding; 102 | text-decoration: none; 103 | text-shadow: @textShadow; 104 | border: 1px solid @borderColor; 105 | border-bottom-color: fadein(@borderColor, 15%); 106 | .border-radius(@borderRadius); 107 | @shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); 108 | .box-shadow(@shadow); 109 | &:hover { 110 | background-position: 0 -15px; 111 | color: @textColor; 112 | text-decoration: none; 113 | } 114 | } 115 | 116 | // Font Stacks 117 | #font { 118 | .shorthand(@weight: normal, @size: 14px, @lineHeight: 20px) { 119 | font-size: @size; 120 | font-weight: @weight; 121 | line-height: @lineHeight; 122 | } 123 | .sans-serif(@weight: normal, @size: 14px, @lineHeight: 20px) { 124 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 125 | font-size: @size; 126 | font-weight: @weight; 127 | line-height: @lineHeight; 128 | } 129 | .serif(@weight: normal, @size: 14px, @lineHeight: 20px) { 130 | font-family: "Georgia", Times New Roman, Times, serif; 131 | font-size: @size; 132 | font-weight: @weight; 133 | line-height: @lineHeight; 134 | } 135 | .monospace(@weight: normal, @size: 12px, @lineHeight: 20px) { 136 | font-family: "Monaco", Courier New, monospace; 137 | font-size: @size; 138 | font-weight: @weight; 139 | line-height: @lineHeight; 140 | } 141 | } 142 | 143 | // Gradients 144 | #gradient { 145 | .horizontal (@startColor: #555, @endColor: #333) { 146 | background-color: @endColor; 147 | background-repeat: repeat-x; 148 | background-image: -khtml-gradient(linear, left top, right top, from(@startColor), to(@endColor)); // Konqueror 149 | background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+ 150 | background-image: -ms-linear-gradient(left, @startColor, @endColor); // IE10 151 | background-image: -webkit-gradient(linear, left top, right top, color-stop(0%, @startColor), color-stop(100%, @endColor)); // Safari 4+, Chrome 2+ 152 | background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+ 153 | background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10 154 | -ms-filter: %("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",@startColor,@endColor); // IE8+ 155 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",@startColor,@endColor)); // IE6 & IE7 156 | background-image: linear-gradient(left, @startColor, @endColor); // Le standard 157 | } 158 | .vertical (@startColor: #555, @endColor: #333) { 159 | background-color: @endColor; 160 | background-repeat: repeat-x; 161 | background-image: -khtml-gradient(linear, left top, left bottom, from(@startColor), to(@endColor)); // Konqueror 162 | background-image: -moz-linear-gradient(@startColor, @endColor); // FF 3.6+ 163 | background-image: -ms-linear-gradient(@startColor, @endColor); // IE10 164 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, @startColor), color-stop(100%, @endColor)); // Safari 4+, Chrome 2+ 165 | background-image: -webkit-linear-gradient(@startColor, @endColor); // Safari 5.1+, Chrome 10+ 166 | background-image: -o-linear-gradient(@startColor, @endColor); // Opera 11.10 167 | -ms-filter: %("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@startColor,@endColor); // IE8+ 168 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",@startColor,@endColor)); // IE6 & IE7 169 | background-image: linear-gradient(@startColor, @endColor); // The standard 170 | } 171 | .directional (@startColor: #555, @endColor: #333, @deg: 45deg) { 172 | background-color: @endColor; 173 | background-repeat: repeat-x; 174 | background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+ 175 | background-image: -ms-linear-gradient(@deg, @startColor, @endColor); // IE10 176 | background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+ 177 | background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10 178 | background-image: linear-gradient(@deg, @startColor, @endColor); // The standard 179 | } 180 | .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 0.5, @endColor: #c3325f) { 181 | background-color: @endColor; 182 | background-repeat: no-repeat; 183 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); 184 | background-image: -webkit-linear-gradient(@startColor, color-stop(@colorStop, @midColor), @endColor); 185 | background-image: -moz-linear-gradient(@startColor, @midColor @colorStop*100%, @endColor); 186 | background-image: -ms-linear-gradient(@startColor, color-stop(@midColor, @colorStop), @endColor); 187 | background-image: -o-linear-gradient(@startColor, color-stop(@midColor, @colorStop), @endColor); 188 | background-image: linear-gradient(@startColor, color-stop(@midColor, @colorStop), @endColor); 189 | } 190 | } 191 | // Gradient Bar Colors for buttons and allerts 192 | .gradientBar(@primaryColor, @secondaryColor) { 193 | #gradient > .vertical(@primaryColor, @secondaryColor); 194 | border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%); 195 | border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%); 196 | } -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/josegonzalez/cakephp-admin.png?branch=master)](https://travis-ci.org/josegonzalez/cakephp-admin) [![Coverage Status](https://coveralls.io/repos/josegonzalez/cakephp-admin/badge.png?branch=master)](https://coveralls.io/r/josegonzalez/cakephp-admin?branch=master) [![Total Downloads](https://poser.pugx.org/josegonzalez/cakephp-admin/d/total.png)](https://packagist.org/packages/josegonzalez/cakephp-admin) [![Latest Stable Version](https://poser.pugx.org/josegonzalez/cakephp-admin/v/stable.png)](https://packagist.org/packages/josegonzalez/cakephp-admin) 2 | # CakeAdmin Plugin 3 | 4 | Generate an awesome backend for your CakePHP application. Under **EXTREMELY** heavy development. 5 | 6 | ## Background 7 | 8 | I'm jealous of Django admin and think `cake bake` is not the greatest to work with. So I started toying with my own [app skeleton](http://github.com/josegonzalez/app_skellington). I realized halfway through that it sucks to base everything on the DB. What if I want to include behaviors other than those included in app_skellington? Impossible. 9 | 10 | So I started work on a Django admin for CakePHP. Here is the beginning of that. And it will rule. And you will love me. And you'll make oodles of cash from this likely. I'm hoping some of this goes to me, but I can dream, can't I? 11 | 12 | ## Requirements 13 | 14 | * CakePHP 2.x 15 | * Patience 16 | * PHP 5.2.8 17 | 18 | ## Installation 19 | 20 | _[Using [Composer](http://getcomposer.org/)]_ 21 | 22 | Add the plugin to your project's `composer.json` - something like this: 23 | 24 | { 25 | "require": { 26 | "josegonzalez/cakephp-admin": "dev-master" 27 | } 28 | } 29 | 30 | Because this plugin has the type `cakephp-plugin` set in it's own `composer.json`, composer knows to install it inside your `/Plugins` directory, rather than in the usual vendors file. It is recommended that you add `/Plugins/Upload` to your .gitignore file. (Why? [read this](http://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md).) 31 | 32 | _[Manual]_ 33 | 34 | * Download this: [http://github.com/josegonzalez/cakephp-admin/zipball/master](http://github.com/josegonzalez/cakephp-admin/zipball/master) 35 | * Unzip that download. 36 | * Copy the resulting folder to `app/Plugin` 37 | * Rename the folder you just copied to `CakeAdmin` 38 | 39 | _[GIT Submodule]_ 40 | 41 | In your app directory type: 42 | 43 | git submodule add -b master git://github.com/josegonzalez/cakephp-admin.git Plugin/CakeAdmin 44 | git submodule init 45 | git submodule update 46 | 47 | _[GIT Clone]_ 48 | 49 | In your `Plugin` directory type: 50 | 51 | git clone -b master git://github.com/josegonzalez/cakephp-admin.git CakeAdmin 52 | 53 | ### Enable plugin 54 | 55 | In 2.0 you need to enable the plugin your `app/Config/bootstrap.php` file: 56 | 57 | CakePlugin::load('CakeAdmin'); 58 | 59 | If you are already using `CakePlugin::loadAll();`, then this is not necessary. 60 | 61 | ## Usage 62 | 63 | Create a folder in your `app/Lib` folder called `Admin`. This folder will contain all of your `CakeAdmin` classes. We'll use a `Post` model for our example admin section. 64 | 65 | Create a @PostCakeAdmin.php@ file in your `app/Lib/Admin` folder. This will contain your `PostCakeAdmin` class. [This gist](http://gist.github.com/583603) is an example of such a class. 66 | 67 | Once your `PostCakeAdmin.php` file has been created, run `cake CakeAdmin.admin` from the shell. This will create the respective plugin if not already (in our case, an `Admin` plugin), as well as all the models, views, and controllers for ALL available `*CakeAdmin.php` files. In our case, you can then access the admin section at `example.com/admin/posts`. 68 | 69 | ## Parsing 70 | 71 | ## Model Validation Rules 72 | 73 | Validation rules are parsed in two steps. The `CakeAdmin` `__construct()` method parses each validation rule for a message and a rule. If the message is not found, then a generic message is attached. This avoids the need to edit the model file at a later date. 74 | 75 | The default validation rules can be overridden easily. They are defined within the @CakeAdmin@ class. The following is default set: 76 | 77 | ``` 78 | /** 79 | * Default Validation Messages 80 | * 81 | * Messages may contain the string `{{field}}` in order to support 82 | * inclusion of fieldnames via str_replace 83 | * 84 | * Rules that have parameters may include those parameters as {{parameter}} 85 | * 86 | * When overriding these in sub-classes, remember to either override 87 | * in the __construct() method to array_merge with the defaults, or 88 | * specify all the messages that may be used 89 | * 90 | * @var string 91 | */ 92 | var $_validationMessages = array( 93 | 'alphanumeric' => '{{field}} must only contain letters and numbers', 94 | 'between' => '{{field}} must be between {{min}} and {{max}} characters long', 95 | 'blank' => '{{field}} must be blank or contain only whitespace characters', 96 | 'boolean' => 'Incorrect value for {{field}}', 97 | 'cc' => 'The credit card number you supplied was invalid', 98 | 'comparison' => '{{field}} must be {{comparison}} to {{value}}', 99 | 'date' => 'Enter a valid date in {{format}} format', 100 | 'decimal' => '{{field}} must be a valid decimal number with at least {{length}} decimal points', 101 | 'email' => '{{field}} must be a valid email address', 102 | 'equalTo' => '{{field}} must be equal to {{number}}', 103 | 'extension' => '{{field}} must have a valid extension', 104 | 'file' => '{{field}} must be a valid file name', 105 | 'ip' => '{{field}} must be a valid IP address', 106 | 'inlist' => 'Your selection for {{field}} must be in the given list', 107 | 'isunique' => 'This {{field}} has already been taken', 108 | 'maxlength' => '{{field}} must have less than {{length}} characters', 109 | 'minlength' => '{{field}} must have at least {{length}} characters', 110 | 'money' => '{{field}} must be a valid monetary amount', 111 | 'multiple' => 'You must select at least {{min}} and no more than {{max}} options for {{field}}', 112 | 'numeric' => '{{field}} must be numeric', 113 | 'notempty' => '{{field}} cannot be empty', 114 | 'phone' => '{{field}} must be a valid phone number', 115 | 'postal' => '{{field}} must be a valid postal code', 116 | 'range' => '{{field}} must be between {{min}} and {{max}}', 117 | 'ssn' => '{{field}} must be a valid social security number', 118 | 'url' => '{{field}} must be a valid url', 119 | ); 120 | ``` 121 | 122 | If you would like to override them within your own admin classes, either include the above in your variable declaration, or override in the `__construct()` method: 123 | 124 | ``` 125 | function __construct() { 126 | $this->_validationMessages = array_merge(array( 127 | 'custom' => 'Custom message for {{field}}'), 128 | $this->_validationMessages 129 | ); 130 | parent::__construct(); 131 | } 132 | ``` 133 | 134 | All the default validation rules work as normal, with option parsing and everything. For example, given: 135 | 136 | ``` 137 | var $validate = array( 138 | 'content' => array( 139 | 'required' => 'notempty', 140 | 'maxLength' => array('maxLength', 255), 141 | 'inList' => array( 142 | 'rule' => array('inList', array(true, 'b', null)), 143 | 'allowEmpty' => true, 144 | 'on' => 'create', 145 | 'message' => 'Please be in the good list' 146 | ) 147 | ) 148 | ); 149 | ``` 150 | 151 | `CakeAdmin` will generate the following @__construct()@ method: 152 | 153 | ``` 154 | function __construct($id = false, $table = null, $ds = null) { 155 | parent::__construct($id, $table, $ds); 156 | $this->validate = array( 157 | 'content' => array( 158 | 'required' => array( 159 | 'rule' => array('notempty'), 160 | 'message' => __d('admin', 'Content cannot be empty', true), 161 | ), 162 | 'maxLength' => array( 163 | 'rule' => array('maxLength', 255), 164 | 'message' => __d('admin', 'Content must have less than 255 characters', true), 165 | ), 166 | 'inList' => array( 167 | 'rule' => array('inList', array(true, 'b', null)), 168 | 'allowEmpty' => true, 169 | 'on' => 'create', 170 | 'message' => __d('admin', 'Please be in the good list', true), 171 | ), 172 | ), 173 | ); 174 | } 175 | ``` 176 | 177 | All validation rules are wrapped in domain-specific internationalization calls - `__d()` - meaning it is possible to further internationalize your generated admin section without mucking with the included classes. 178 | 179 | ### Action Configuration 180 | 181 | When defining custom actions, there may be certain defaults that need to be set. All the included actions in CakeAdmin come with `CakeAdminActionConfig` classes. These define various properties, such as the action type, the plugin that the action is included in, whether it is enabled by default, and configuration defaults. Because the process of merging default configurations and your personal configuration is not standard, each `CakeAdminActionConfig` class can define it's own `mergeVars($configuration)` method. It can then proceed to merge the configuration as it wants, and returns the merged configuration. If omitted from the class implementation, an `array_merge` will be performed upon the configuration and the defaults. 182 | 183 | The following is an example implementation of `mergeVars($configuration)`: 184 | 185 | ``` 186 | function mergeVars($admin, $configuration = array()) { 187 | if (empty($configuration)) return $this->defaults; 188 | 189 | $modelObj = ClassRegistry::init(array( 190 | 'class' => $admin->modelName, 191 | 'table' => $admin->useTable, 192 | 'ds' => $admin->useDbConfig 193 | )); 194 | 195 | $filters = array(); 196 | $search = array(); 197 | $fields = array(); 198 | $schema = $modelObj->schema(); 199 | 200 | if (empty($configuration['fields']) || (in_array('*', (array) $configuration['fields']))) { 201 | // $fields is all fields 202 | foreach (array_keys($modelObj->schema()) as $field) { 203 | $fields[] = $field; 204 | } 205 | } else { 206 | foreach ((array) $configuration['fields'] as $field) { 207 | if ($field !== '*') $fields[] = $field; 208 | } 209 | } 210 | 211 | if (!empty($configuration['list_filter'])) { 212 | foreach ($configuration['list_filter'] as $field => $config) { 213 | $filters[$field] = (array) $config; 214 | } 215 | } 216 | 217 | $configuration['search'] = Set::normalize($configuration['search']); 218 | if (!empty($configuration['search'])) { 219 | foreach ($configuration['search'] as $field => $alias) { 220 | if (!in_array($field, array_keys($filters))) { 221 | $type = ($schema[$field]['type'] == 'text') ? 'text' : $schema[$field]['type']; 222 | $search[$field] = array( 223 | 'type' => ($field === 'id') ? 'text' : $type, 224 | 'alias' => empty($alias) ? $field : $alias, 225 | ); 226 | } 227 | } 228 | } 229 | 230 | $sort = $fields; 231 | if ($configuration['sort'] == false) { 232 | $sort = array(); 233 | } else if (is_array($configuration['sort'])) { 234 | $sort = $configuration['sort']; 235 | } 236 | 237 | $configuration = array_merge($this->defaults, $configuration); 238 | $configuration['list_filter'] = $filters; 239 | $configuration['search'] = $search; 240 | $configuration['fields'] = $fields; 241 | $configuration['sort'] = $sort; 242 | 243 | return $configuration; 244 | } 245 | ``` 246 | 247 | ## TODO 248 | 249 | The following is a list of things I am planning to implement, in order of most likely to be implemented first. 250 | 251 | * Refactor template paths 252 | * Implement mergeVars 253 | * Deprecate Frontmatter 254 | * View Templates, partials, and layouts 255 | * Allow installation of cake_admin generator in base plugins dir 256 | * Formatting wrappers for fields in built-in actions 257 | * Little box for logged-in user in top-left corner of built-in dashboard 258 | * Tree Behavior Support 259 | * Support for CakeAdmin class files in plugins 260 | * Ajax Form-handling and Pagination 261 | * Screencast 262 | * Building into regular application as opposed to plugin 263 | * Security Component Integration 264 | * Controller/Model/View base class enhancements 265 | * Behavior/Helper/Component option parsing 266 | * Authentication Implementations 267 | * Webservice Implementation 268 | * Inline model editing on built-in index action 269 | * Cache integration 270 | * Automagic CakeAdmin file-generation based solely upon DB 271 | * Unit Tests!!! 272 | * Theme support 273 | * Translate Behavior support 274 | * RSS Feeds 275 | * Internationalization 276 | * Bake-like console and web tool 277 | 278 | ## License 279 | 280 | The MIT License (MIT) 281 | 282 | Copyright (c) 2010 Jose Diaz-Gonzalez 283 | 284 | Permission is hereby granted, free of charge, to any person obtaining a copy 285 | of this software and associated documentation files (the "Software"), to deal 286 | in the Software without restriction, including without limitation the rights 287 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 288 | copies of the Software, and to permit persons to whom the Software is 289 | furnished to do so, subject to the following conditions: 290 | 291 | The above copyright notice and this permission notice shall be included in 292 | all copies or substantial portions of the Software. 293 | 294 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 295 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 296 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 297 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 298 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 299 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 300 | THE SOFTWARE. 301 | -------------------------------------------------------------------------------- /Test/Case/AllCakeAdminTest.php: -------------------------------------------------------------------------------- 1 | addTestDirectoryRecursive($path); 17 | 18 | return $suite; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Test/Case/Lib/CakeAdminTest.php: -------------------------------------------------------------------------------- 1 | loadFixtures('Post'); 30 | $this->PostCakeAdmin =& new PostCakeAdmin; 31 | $this->PostTwoCakeAdmin =& new PostTwoCakeAdmin; 32 | $this->PostThreeCakeAdmin =& new PostTwoCakeAdmin; 33 | } 34 | 35 | /** 36 | * end a test 37 | * 38 | * @return void 39 | */ 40 | function endTest($method) { 41 | unset($this->PostCakeAdmin); 42 | ClassRegistry::flush(); 43 | } 44 | 45 | function testEnabled() { 46 | $this->assertFalse($this->PostCakeAdmin->enabled); 47 | $this->assertTrue($this->PostTwoCakeAdmin->enabled); 48 | 49 | $this->assertNull($this->PostCakeAdmin->modelName); 50 | $this->assertNotNull($this->PostTwoCakeAdmin->modelName); 51 | } 52 | 53 | function testSetup() { 54 | $this->assertEqual($this->PostTwoCakeAdmin->modelName, 'Post'); 55 | $this->assertEqual($this->PostTwoCakeAdmin->controllerName, 'Posts'); 56 | $this->assertEqual($this->PostTwoCakeAdmin->useTable, 'test_suite_posts'); 57 | $this->assertEqual($this->PostTwoCakeAdmin->useDbConfig, 'default'); 58 | $this->assertEqual($this->PostTwoCakeAdmin->primaryKey, 'id'); 59 | $this->assertEqual($this->PostTwoCakeAdmin->displayField, 'title'); 60 | $this->assertEqual($this->PostCakeAdmin->plugin, 'admin'); 61 | $this->assertEqual($this->PostTwoCakeAdmin->plugin, 'dashboard'); 62 | 63 | $this->assertIsA($this->PostTwoCakeAdmin->modelObj, 'Model'); 64 | 65 | $this->assertEqual(count($this->PostTwoCakeAdmin->components), 1); 66 | $this->assertEqual(count($this->PostTwoCakeAdmin->helpers), 0); 67 | $this->assertEqual(count($this->PostTwoCakeAdmin->finders), 3); 68 | $this->assertEqual(count($this->PostTwoCakeAdmin->relatedFinders), 2); 69 | $this->assertEqual(count($this->PostTwoCakeAdmin->validate), 0); 70 | $this->assertEqual(count($this->PostTwoCakeAdmin->relations), 0); 71 | $this->assertEqual(count($this->PostTwoCakeAdmin->links), 4); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Test/Fixture/PostFixture.php: -------------------------------------------------------------------------------- 1 | 8 | * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) 9 | * 10 | * Licensed under The Open Group Test Suite License 11 | * Redistributions of files must retain the above copyright notice. 12 | * 13 | * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) 14 | * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests 15 | * @package cake 16 | * @subpackage cake.tests.fixtures 17 | * @since CakePHP(tm) v 1.2.0.4667 18 | * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License 19 | */ 20 | 21 | /** 22 | * Short description for class. 23 | * 24 | * @package cake 25 | * @subpackage cake.tests.fixtures 26 | */ 27 | class PostFixture extends CakeTestFixture { 28 | 29 | /** 30 | * name property 31 | * 32 | * @var string 'Post' 33 | * @access public 34 | */ 35 | var $name = 'Post'; 36 | 37 | /** 38 | * fields property 39 | * 40 | * @var array 41 | * @access public 42 | */ 43 | var $fields = array( 44 | 'id' => array('type' => 'integer', 'key' => 'primary'), 45 | 'author_id' => array('type' => 'integer', 'null' => false), 46 | 'title' => array('type' => 'string', 'null' => false), 47 | 'body' => 'text', 48 | 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'), 49 | 'created' => 'datetime', 50 | 'updated' => 'datetime' 51 | ); 52 | 53 | /** 54 | * records property 55 | * 56 | * @var array 57 | * @access public 58 | */ 59 | var $records = array( 60 | array('author_id' => 1, 'title' => 'First Post', 'body' => 'First Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'), 61 | array('author_id' => 3, 'title' => 'Second Post', 'body' => 'Second Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'), 62 | array('author_id' => 1, 'title' => 'Third Post', 'body' => 'Third Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31') 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "josegonzalez/cakephp-admin", 3 | "version": "1.0.0", 4 | "description": "An admin generator for CakePHP 2.x", 5 | "type": "cakephp-plugin", 6 | "keywords": [ 7 | "cakephp", 8 | "admin", 9 | "bake" 10 | ], 11 | "homepage": "http://github.com/josegonzalez/cakephp-admin", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Jose Diaz-Gonzalez", 16 | "email": "email@josediazgonzalez.com", 17 | "homepage": "http://josediazgonzalez.com", 18 | "role": "Maintainer" 19 | } 20 | ], 21 | "require": { 22 | "composer/installers": "*" 23 | }, 24 | "support": { 25 | "email": "cakephp+admin@josediazgonzalez.com", 26 | "issues": "https://github.com/josegonzalez/cakephp-admin/issues", 27 | "source": "https://github.com/josegonzalez/cakephp-admin" 28 | }, 29 | "extra": { 30 | "installer-name": "CakeAdmin" 31 | } 32 | } 33 | --------------------------------------------------------------------------------