├── plugins └── empty ├── webroot ├── js │ └── empty ├── favicon.ico ├── img │ ├── cake.icon.png │ └── cake.power.gif ├── .htaccess ├── index.php └── css │ └── cake.css ├── src ├── View │ ├── Helper │ │ └── empty │ ├── AppView.php │ └── AjaxView.php ├── Model │ ├── Behavior │ │ └── empty │ ├── Entity │ │ ├── Post.php │ │ ├── Widget.php │ │ ├── Group.php │ │ └── User.php │ └── Table │ │ ├── WidgetsTable.php │ │ ├── GroupsTable.php │ │ ├── PostsTable.php │ │ └── UsersTable.php ├── Controller │ ├── Component │ │ └── empty │ ├── PagesController.php │ ├── AppController.php │ ├── WidgetsController.php │ ├── GroupsController.php │ ├── PostsController.php │ └── UsersController.php ├── Template │ ├── Element │ │ └── Flash │ │ │ ├── error.ctp │ │ │ ├── success.ctp │ │ │ └── default.ctp │ ├── Users │ │ ├── login.ctp │ │ ├── add.ctp │ │ ├── edit.ctp │ │ ├── index.ctp │ │ └── view.ctp │ ├── Layout │ │ ├── rss │ │ │ └── default.ctp │ │ ├── ajax.ctp │ │ ├── Email │ │ │ ├── text │ │ │ │ └── default.ctp │ │ │ └── html │ │ │ │ └── default.ctp │ │ ├── error.ctp │ │ └── default.ctp │ ├── Email │ │ ├── text │ │ │ └── default.ctp │ │ └── html │ │ │ └── default.ctp │ ├── Widgets │ │ ├── add.ctp │ │ ├── edit.ctp │ │ ├── view.ctp │ │ └── index.ctp │ ├── Groups │ │ ├── add.ctp │ │ ├── edit.ctp │ │ ├── index.ctp │ │ └── view.ctp │ ├── Posts │ │ ├── add.ctp │ │ ├── edit.ctp │ │ ├── view.ctp │ │ └── index.ctp │ ├── Error │ │ ├── error500.ctp │ │ └── error400.ctp │ └── Pages │ │ └── home.ctp ├── Shell │ └── ConsoleShell.php └── Console │ └── Installer.php ├── tests ├── TestCase │ ├── View │ │ └── Helper │ │ │ └── empty │ ├── Model │ │ ├── Behavior │ │ │ └── empty │ │ └── Table │ │ │ ├── WidgetsTableTest.php │ │ │ ├── GroupsTableTest.php │ │ │ ├── PostsTableTest.php │ │ │ └── UsersTableTest.php │ └── Controller │ │ ├── Component │ │ └── empty │ │ ├── WidgetsControllerTest.php │ │ ├── GroupsControllerTest.php │ │ ├── PostsControllerTest.php │ │ └── UsersControllerTest.php ├── bootstrap.php └── Fixture │ ├── GroupsFixture.php │ ├── WidgetsFixture.php │ ├── UsersFixture.php │ └── PostsFixture.php ├── .gitignore ├── .htaccess ├── .travis.yml ├── .editorconfig ├── config ├── schema │ ├── sessions.sql │ └── i18n.sql ├── bootstrap_cli.php ├── paths.php ├── routes.php ├── bootstrap.php └── app.default.php ├── index.php ├── .gitattributes ├── phpunit.xml.dist ├── bin ├── cake.bat ├── cake.php └── cake ├── composer.json ├── README.md └── composer.lock /plugins/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webroot/js/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/View/Helper/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Model/Behavior/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Controller/Component/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/TestCase/View/Helper/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/TestCase/Model/Behavior/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/TestCase/Controller/Component/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/* 2 | /config/app.php 3 | /tmp/* 4 | /logs/* 5 | -------------------------------------------------------------------------------- /src/Template/Element/Flash/error.ctp: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /src/Template/Element/Flash/success.ctp: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /webroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmemmesheimer/cakephp-3-acl-example/HEAD/webroot/favicon.ico -------------------------------------------------------------------------------- /webroot/img/cake.icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmemmesheimer/cakephp-3-acl-example/HEAD/webroot/img/cake.icon.png -------------------------------------------------------------------------------- /webroot/img/cake.power.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmemmesheimer/cakephp-3-acl-example/HEAD/webroot/img/cake.power.gif -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine on 3 | RewriteRule ^$ webroot/ [L] 4 | RewriteRule (.*) webroot/$1 [L] 5 | -------------------------------------------------------------------------------- /webroot/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteCond %{REQUEST_FILENAME} !-f 4 | RewriteRule ^ index.php [L] 5 | 6 | -------------------------------------------------------------------------------- /src/Template/Element/Flash/default.ctp: -------------------------------------------------------------------------------- 1 | 7 |
8 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | Form->create() ?> 2 |
3 | 4 | Form->input('username') ?> 5 | Form->input('password') ?> 6 | Form->submit(__('Login')) ?> 7 |
8 | Form->end() ?> -------------------------------------------------------------------------------- /src/Template/Layout/rss/default.ctp: -------------------------------------------------------------------------------- 1 | fetch('title'); 7 | endif; 8 | 9 | echo $this->Rss->document( 10 | $this->Rss->channel( 11 | array(), $channel, $this->fetch('content') 12 | ) 13 | ); 14 | ?> 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | php: 6 | - 7.0 7 | 8 | before_script: 9 | - sh -c "composer require 'cakephp/cakephp-codesniffer:dev-master'" 10 | - phpenv rehash 11 | 12 | script: 13 | - sh -c "vendor/bin/phpcs -p --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests ./config ./webroot" 14 | 15 | notifications: 16 | email: false 17 | -------------------------------------------------------------------------------- /.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 = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.bat] 14 | end_of_line = crlf 15 | 16 | [*.yml] 17 | indent_style = space 18 | indent_size = 2 19 | -------------------------------------------------------------------------------- /src/Model/Entity/Post.php: -------------------------------------------------------------------------------- 1 | true, 19 | 'id' => false, 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /src/Model/Entity/Widget.php: -------------------------------------------------------------------------------- 1 | true, 19 | 'id' => false, 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /src/Model/Entity/Group.php: -------------------------------------------------------------------------------- 1 | true, 19 | 'id' => false, 20 | ]; 21 | 22 | public function parentNode() 23 | { 24 | return null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /config/schema/sessions.sql: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | # 3 | # Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) 4 | # 1785 E. Sahara Avenue, Suite 490-204 5 | # Las Vegas, Nevada 89104 6 | # 7 | # Licensed under The MIT License 8 | # For full copyright and license information, please see the LICENSE.txt 9 | # Redistributions of files must retain the above copyright notice. 10 | # MIT License (http://www.opensource.org/licenses/mit-license.php) 11 | 12 | CREATE TABLE sessions ( 13 | id varchar(40) NOT NULL default '', 14 | data text, 15 | expires INT(11) NOT NULL, 16 | PRIMARY KEY (id) 17 | ); 18 | -------------------------------------------------------------------------------- /src/Template/Email/text/default.ctp: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 16 | fetch('content') ?> 17 | -------------------------------------------------------------------------------- /src/Template/Layout/Email/text/default.ctp: -------------------------------------------------------------------------------- 1 | 16 | fetch('content') ?> 17 | -------------------------------------------------------------------------------- /src/Template/Widgets/add.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 | 6 |
7 |
8 | Form->create($widget) ?> 9 |
10 | 11 | Form->input('name'); 13 | echo $this->Form->input('part_no'); 14 | echo $this->Form->input('quantity'); 15 | ?> 16 |
17 | Form->button(__('Submit')) ?> 18 | Form->end() ?> 19 |
20 | -------------------------------------------------------------------------------- /src/Template/Email/html/default.ctp: -------------------------------------------------------------------------------- 1 | 16 | ' . $line . "

\n"; 21 | endforeach; 22 | ?> 23 | -------------------------------------------------------------------------------- /src/Template/Groups/add.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 | 8 |
9 |
10 | Form->create($group) ?> 11 |
12 | 13 | Form->input('name'); 15 | ?> 16 |
17 | Form->button(__('Submit')) ?> 18 | Form->end() ?> 19 |
20 | -------------------------------------------------------------------------------- /src/Template/Layout/Email/html/default.ctp: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | <?= $this->fetch('title') ?> 20 | 21 | 22 | fetch('content') ?> 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Model/Entity/User.php: -------------------------------------------------------------------------------- 1 | true, 19 | 'id' => false, 20 | ]; 21 | 22 | public function parentNode() 23 | { 24 | if (!$this->id) { 25 | return null; 26 | } 27 | if (isset($this->group_id)) { 28 | $groupId = $this->group_id; 29 | } else { 30 | $Users = TableRegistry::get('Users'); 31 | $user = $Users->find('all', ['fields' => ['group_id']])->where(['id' => $this->id])->first(); 32 | $groupId = $user->group_id; 33 | } 34 | if (!$groupId) { 35 | return null; 36 | } 37 | return ['Groups' => ['id' => $groupId]]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Define the line ending behavior of the different file extensions 2 | # Set default behaviour, in case users don't have core.autocrlf set. 3 | * text=auto 4 | * text eol=lf 5 | 6 | # Explicitly declare text files we want to always be normalized and converted 7 | # to native line endings on checkout. 8 | *.php text 9 | *.default text 10 | *.ctp text 11 | *.sql text 12 | *.md text 13 | *.po text 14 | *.js text 15 | *.css text 16 | *.ini text 17 | *.properties text 18 | *.txt text 19 | *.xml text 20 | *.yml text 21 | .htaccess text 22 | 23 | # Declare files that will always have CRLF line endings on checkout. 24 | *.bat eol=crlf 25 | 26 | # Declare files that will always have LF line endings on checkout. 27 | *.pem eol=lf 28 | 29 | # Denote all files that are truly binary and should not be modified. 30 | *.png binary 31 | *.jpg binary 32 | *.gif binary 33 | *.ico binary 34 | *.mo binary 35 | *.pdf binary 36 | *.phar binary 37 | -------------------------------------------------------------------------------- /src/Template/Posts/add.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 | 8 |
9 |
10 | Form->create($post) ?> 11 |
12 | 13 | Form->input('user_id', ['options' => $users]); 15 | echo $this->Form->input('title'); 16 | echo $this->Form->input('body'); 17 | ?> 18 |
19 | Form->button(__('Submit')) ?> 20 | Form->end() ?> 21 |
22 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ./tests/TestCase 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/Template/Widgets/edit.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Form->postLink( 5 | __('Delete'), 6 | ['action' => 'delete', $widget->id], 7 | ['confirm' => __('Are you sure you want to delete # {0}?', $widget->id)] 8 | ) 9 | ?>
  • 10 |
  • Html->link(__('List Widgets'), ['action' => 'index']) ?>
  • 11 |
12 |
13 |
14 | Form->create($widget) ?> 15 |
16 | 17 | Form->input('name'); 19 | echo $this->Form->input('part_no'); 20 | echo $this->Form->input('quantity'); 21 | ?> 22 |
23 | Form->button(__('Submit')) ?> 24 | Form->end() ?> 25 |
26 | -------------------------------------------------------------------------------- /src/View/AppView.php: -------------------------------------------------------------------------------- 1 | loadHelper('Html');` 29 | * 30 | * @return void 31 | */ 32 | public function initialize() 33 | { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /config/schema/i18n.sql: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | # 3 | # Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) 4 | # 5 | # Licensed under The MIT License 6 | # For full copyright and license information, please see the LICENSE.txt 7 | # Redistributions of files must retain the above copyright notice. 8 | # MIT License (http://www.opensource.org/licenses/mit-license.php) 9 | 10 | CREATE TABLE i18n ( 11 | id int(10) NOT NULL auto_increment, 12 | locale varchar(6) NOT NULL, 13 | model varchar(255) NOT NULL, 14 | foreign_key int(10) NOT NULL, 15 | field varchar(255) NOT NULL, 16 | content mediumtext, 17 | PRIMARY KEY (id), 18 | # UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field), 19 | # INDEX I18N_LOCALE_ROW(locale, model, foreign_key), 20 | # INDEX I18N_LOCALE_MODEL(locale, model), 21 | # INDEX I18N_FIELD(model, foreign_key, field), 22 | # INDEX I18N_ROW(model, foreign_key), 23 | INDEX locale (locale), 24 | INDEX model (model), 25 | INDEX row_id (foreign_key), 26 | INDEX field (field) 27 | ); -------------------------------------------------------------------------------- /src/Template/Error/error500.ctp: -------------------------------------------------------------------------------- 1 | layout = 'dev_error'; 7 | 8 | $this->assign('title', $message); 9 | $this->assign('templateName', 'error500.ctp'); 10 | 11 | $this->start('file'); 12 | ?> 13 | queryString)) : ?> 14 |

15 | SQL Query: 16 | queryString) ?> 17 |

18 | 19 | params)) : ?> 20 | SQL Query Params: 21 | params) ?> 22 | 23 | element('auto_table_warning'); 25 | 26 | if (extension_loaded('xdebug')): 27 | xdebug_print_function_stack(); 28 | endif; 29 | 30 | $this->end(); 31 | endif; 32 | ?> 33 |

34 |

35 | : 36 | 37 |

38 | -------------------------------------------------------------------------------- /bin/cake.bat: -------------------------------------------------------------------------------- 1 | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 2 | :: 3 | :: Cake is a Windows batch script for invoking CakePHP shell commands 4 | :: 5 | :: CakePHP(tm) : Rapid Development Framework (http://cakephp.org) 6 | :: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) 7 | :: 8 | :: Licensed under The MIT License 9 | :: Redistributions of files must retain the above copyright notice. 10 | :: 11 | :: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) 12 | :: @link http://cakephp.org CakePHP(tm) Project 13 | :: @since 2.0.0 14 | :: @license http://www.opensource.org/licenses/mit-license.php MIT License 15 | :: 16 | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 17 | 18 | :: In order for this script to work as intended, the cake\console\ folder must be in your PATH 19 | 20 | @echo. 21 | @echo off 22 | 23 | SET app=%0 24 | SET lib=%~dp0 25 | 26 | php "%lib%cake.php" %* 27 | 28 | echo. 29 | 30 | exit /B %ERRORLEVEL% 31 | -------------------------------------------------------------------------------- /src/Template/Groups/edit.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Form->postLink( 5 | __('Delete'), 6 | ['action' => 'delete', $group->id], 7 | ['confirm' => __('Are you sure you want to delete # {0}?', $group->id)] 8 | ) 9 | ?>
  • 10 |
  • Html->link(__('List Groups'), ['action' => 'index']) ?>
  • 11 |
  • Html->link(__('List Users'), ['controller' => 'Users', 'action' => 'index']) ?>
  • 12 |
  • Html->link(__('New User'), ['controller' => 'Users', 'action' => 'add']) ?>
  • 13 |
14 |
15 |
16 | Form->create($group) ?> 17 |
18 | 19 | Form->input('name'); 21 | ?> 22 |
23 | Form->button(__('Submit')) ?> 24 | Form->end() ?> 25 |
26 | -------------------------------------------------------------------------------- /src/Template/Error/error400.ctp: -------------------------------------------------------------------------------- 1 | layout = 'dev_error'; 6 | 7 | $this->assign('title', $message); 8 | $this->assign('templateName', 'error400.ctp'); 9 | 10 | $this->start('file'); 11 | ?> 12 | queryString)) : ?> 13 |

14 | SQL Query: 15 | queryString) ?> 16 |

17 | 18 | params)) : ?> 19 | SQL Query Params: 20 | params) ?> 21 | 22 | element('auto_table_warning') ?> 23 | end(); 29 | endif; 30 | ?> 31 |

32 |

33 | : 34 | '{$url}'" 37 | ) ?> 38 |

39 | -------------------------------------------------------------------------------- /src/Template/Users/add.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('List Users'), ['action' => 'index']) ?>
  • 5 |
  • Html->link(__('List Groups'), ['controller' => 'Groups', 'action' => 'index']) ?>
  • 6 |
  • Html->link(__('New Group'), ['controller' => 'Groups', 'action' => 'add']) ?>
  • 7 |
  • Html->link(__('List Posts'), ['controller' => 'Posts', 'action' => 'index']) ?>
  • 8 |
  • Html->link(__('New Post'), ['controller' => 'Posts', 'action' => 'add']) ?>
  • 9 |
10 |
11 |
12 | Form->create($user) ?> 13 |
14 | 15 | Form->input('username'); 17 | echo $this->Form->input('password'); 18 | echo $this->Form->input('group_id', ['options' => $groups]); 19 | ?> 20 |
21 | Form->button(__('Submit')) ?> 22 | Form->end() ?> 23 |
24 | -------------------------------------------------------------------------------- /config/bootstrap_cli.php: -------------------------------------------------------------------------------- 1 | 2 |

3 |
    4 |
  • Form->postLink( 5 | __('Delete'), 6 | ['action' => 'delete', $post->id], 7 | ['confirm' => __('Are you sure you want to delete # {0}?', $post->id)] 8 | ) 9 | ?>
  • 10 |
  • Html->link(__('List Posts'), ['action' => 'index']) ?>
  • 11 |
  • Html->link(__('List Users'), ['controller' => 'Users', 'action' => 'index']) ?>
  • 12 |
  • Html->link(__('New User'), ['controller' => 'Users', 'action' => 'add']) ?>
  • 13 |
14 | 15 |
16 | Form->create($post) ?> 17 |
18 | 19 | Form->input('user_id', ['options' => $users]); 21 | echo $this->Form->input('title'); 22 | echo $this->Form->input('body'); 23 | ?> 24 |
25 | Form->button(__('Submit')) ?> 26 | Form->end() ?> 27 |
28 | -------------------------------------------------------------------------------- /bin/cake.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php -q 2 | require->php)) { 23 | $minVersion = preg_replace('/([^0-9\.])/', '', $composer->require->php); 24 | } 25 | } 26 | if (version_compare(phpversion(), $minVersion, '<')) { 27 | fwrite(STDERR, sprintf("Minimum PHP version: %s. You are using: %s.\n", $minVersion, phpversion())); 28 | exit(-1); 29 | } 30 | 31 | include dirname(__DIR__) . '/config/bootstrap.php'; 32 | 33 | exit(Cake\Console\ShellDispatcher::run($argv)); 34 | -------------------------------------------------------------------------------- /src/Template/Users/edit.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Form->postLink( 5 | __('Delete'), 6 | ['action' => 'delete', $user->id], 7 | ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)] 8 | ) 9 | ?>
  • 10 |
  • Html->link(__('List Users'), ['action' => 'index']) ?>
  • 11 |
  • Html->link(__('List Groups'), ['controller' => 'Groups', 'action' => 'index']) ?>
  • 12 |
  • Html->link(__('New Group'), ['controller' => 'Groups', 'action' => 'add']) ?>
  • 13 |
  • Html->link(__('List Posts'), ['controller' => 'Posts', 'action' => 'index']) ?>
  • 14 |
  • Html->link(__('New Post'), ['controller' => 'Posts', 'action' => 'add']) ?>
  • 15 |
16 |
17 |
18 | Form->create($user) ?> 19 |
20 | 21 | Form->input('username'); 23 | echo $this->Form->input('group_id', ['options' => $groups]); 24 | ?> 25 |
26 | Form->button(__('Submit')) ?> 27 | Form->end() ?> 28 |
29 | -------------------------------------------------------------------------------- /src/Template/Widgets/view.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('Edit Widget'), ['action' => 'edit', $widget->id]) ?>
  • 5 |
  • Form->postLink(__('Delete Widget'), ['action' => 'delete', $widget->id], ['confirm' => __('Are you sure you want to delete # {0}?', $widget->id)]) ?>
  • 6 |
  • Html->link(__('List Widgets'), ['action' => 'index']) ?>
  • 7 |
  • Html->link(__('New Widget'), ['action' => 'add']) ?>
  • 8 |
9 |
10 |
11 |

name) ?>

12 |
13 |
14 |
15 |

name) ?>

16 |
17 |

part_no) ?>

18 |
19 |
20 |
21 |

Number->format($widget->id) ?>

22 |
23 |

Number->format($widget->quantity) ?>

24 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cakephp/app", 3 | "description": "CakePHP skeleton app", 4 | "homepage": "http://cakephp.org", 5 | "type": "project", 6 | "license": "MIT", 7 | "require": { 8 | "php": ">=5.4.16", 9 | "cakephp/cakephp": "~3.0", 10 | "cakephp/acl": "dev-master", 11 | "mobiledetect/mobiledetectlib": "2.*", 12 | "cakephp/migrations": "~1.0", 13 | "cakephp/plugin-installer": "*" 14 | }, 15 | "require-dev": { 16 | "psy/psysh": "@stable", 17 | "cakephp/debug_kit": "~3.0", 18 | "cakephp/bake": "~1.0" 19 | }, 20 | "suggest": { 21 | "phpunit/phpunit": "Allows automated tests to be run without system-wide install.", 22 | "cakephp/cakephp-codesniffer": "Allows to check the code against the coding standards used in CakePHP." 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "App\\": "src" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "App\\Test\\": "tests", 32 | "Cake\\Test\\": "./vendor/cakephp/cakephp/tests" 33 | } 34 | }, 35 | "scripts": { 36 | "post-install-cmd": "App\\Console\\Installer::postInstall", 37 | "post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump" 38 | }, 39 | "minimum-stability": "dev", 40 | "prefer-stable": true 41 | } 42 | -------------------------------------------------------------------------------- /webroot/index.php: -------------------------------------------------------------------------------- 1 | dispatch( 35 | Request::createFromGlobals(), 36 | new Response() 37 | ); 38 | -------------------------------------------------------------------------------- /src/Model/Table/WidgetsTable.php: -------------------------------------------------------------------------------- 1 | table('widgets'); 28 | $this->displayField('name'); 29 | $this->primaryKey('id'); 30 | } 31 | 32 | /** 33 | * Default validation rules. 34 | * 35 | * @param \Cake\Validation\Validator $validator Validator instance. 36 | * @return \Cake\Validation\Validator 37 | */ 38 | public function validationDefault(Validator $validator) 39 | { 40 | $validator 41 | ->add('id', 'valid', ['rule' => 'numeric']) 42 | ->allowEmpty('id', 'create'); 43 | 44 | $validator 45 | ->requirePresence('name', 'create') 46 | ->notEmpty('name'); 47 | 48 | $validator 49 | ->allowEmpty('part_no'); 50 | 51 | $validator 52 | ->add('quantity', 'valid', ['rule' => 'numeric']) 53 | ->allowEmpty('quantity'); 54 | 55 | return $validator; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /bin/cake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | ################################################################################ 3 | # 4 | # Cake is a shell script for invoking CakePHP shell commands 5 | # 6 | # CakePHP(tm) : Rapid Development Framework (http://cakephp.org) 7 | # Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) 8 | # 9 | # Licensed under The MIT License 10 | # For full copyright and license information, please see the LICENSE.txt 11 | # Redistributions of files must retain the above copyright notice. 12 | # 13 | # @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) 14 | # @link http://cakephp.org CakePHP(tm) Project 15 | # @since 1.2.0 16 | # @license http://www.opensource.org/licenses/mit-license.php MIT License 17 | # 18 | ################################################################################ 19 | 20 | # Canonicalize by following every symlink of the given name recursively 21 | canonicalize() { 22 | NAME="$1" 23 | if [ -f "$NAME" ] 24 | then 25 | DIR=$(dirname -- "$NAME") 26 | NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") 27 | fi 28 | while [ -h "$NAME" ]; do 29 | DIR=$(dirname -- "$NAME") 30 | SYM=$(readlink "$NAME") 31 | NAME=$(cd "$DIR" > /dev/null && cd $(dirname -- "$SYM") > /dev/null && pwd)/$(basename -- "$SYM") 32 | done 33 | echo "$NAME" 34 | } 35 | 36 | CONSOLE=$(dirname -- "$(canonicalize "$0")") 37 | APP=$(dirname "$CONSOLE") 38 | 39 | exec php "$CONSOLE"/cake.php "$@" 40 | exit 41 | -------------------------------------------------------------------------------- /tests/TestCase/Model/Table/WidgetsTableTest.php: -------------------------------------------------------------------------------- 1 | 'App\Model\Table\WidgetsTable']; 32 | $this->Widgets = TableRegistry::get('Widgets', $config); 33 | } 34 | 35 | /** 36 | * tearDown method 37 | * 38 | * @return void 39 | */ 40 | public function tearDown() 41 | { 42 | unset($this->Widgets); 43 | 44 | parent::tearDown(); 45 | } 46 | 47 | /** 48 | * Test initialize method 49 | * 50 | * @return void 51 | */ 52 | public function testInitialize() 53 | { 54 | $this->markTestIncomplete('Not implemented yet.'); 55 | } 56 | 57 | /** 58 | * Test validationDefault method 59 | * 60 | * @return void 61 | */ 62 | public function testValidationDefault() 63 | { 64 | $this->markTestIncomplete('Not implemented yet.'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Model/Table/GroupsTable.php: -------------------------------------------------------------------------------- 1 | table('groups'); 29 | $this->displayField('name'); 30 | $this->primaryKey('id'); 31 | $this->addBehavior('Timestamp'); 32 | $this->addBehavior('Acl.Acl', ['type' => 'requester']); 33 | $this->hasMany('Users', [ 34 | 'foreignKey' => 'group_id' 35 | ]); 36 | } 37 | 38 | /** 39 | * Default validation rules. 40 | * 41 | * @param \Cake\Validation\Validator $validator Validator instance. 42 | * @return \Cake\Validation\Validator 43 | */ 44 | public function validationDefault(Validator $validator) 45 | { 46 | $validator 47 | ->add('id', 'valid', ['rule' => 'numeric']) 48 | ->allowEmpty('id', 'create'); 49 | 50 | $validator 51 | ->requirePresence('name', 'create') 52 | ->notEmpty('name'); 53 | 54 | return $validator; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/TestCase/Model/Table/GroupsTableTest.php: -------------------------------------------------------------------------------- 1 | 'App\Model\Table\GroupsTable']; 33 | $this->Groups = TableRegistry::get('Groups', $config); 34 | } 35 | 36 | /** 37 | * tearDown method 38 | * 39 | * @return void 40 | */ 41 | public function tearDown() 42 | { 43 | unset($this->Groups); 44 | 45 | parent::tearDown(); 46 | } 47 | 48 | /** 49 | * Test initialize method 50 | * 51 | * @return void 52 | */ 53 | public function testInitialize() 54 | { 55 | $this->markTestIncomplete('Not implemented yet.'); 56 | } 57 | 58 | /** 59 | * Test validationDefault method 60 | * 61 | * @return void 62 | */ 63 | public function testValidationDefault() 64 | { 65 | $this->markTestIncomplete('Not implemented yet.'); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/TestCase/Controller/WidgetsControllerTest.php: -------------------------------------------------------------------------------- 1 | markTestIncomplete('Not implemented yet.'); 30 | } 31 | 32 | /** 33 | * Test view method 34 | * 35 | * @return void 36 | */ 37 | public function testView() 38 | { 39 | $this->markTestIncomplete('Not implemented yet.'); 40 | } 41 | 42 | /** 43 | * Test add method 44 | * 45 | * @return void 46 | */ 47 | public function testAdd() 48 | { 49 | $this->markTestIncomplete('Not implemented yet.'); 50 | } 51 | 52 | /** 53 | * Test edit method 54 | * 55 | * @return void 56 | */ 57 | public function testEdit() 58 | { 59 | $this->markTestIncomplete('Not implemented yet.'); 60 | } 61 | 62 | /** 63 | * Test delete method 64 | * 65 | * @return void 66 | */ 67 | public function testDelete() 68 | { 69 | $this->markTestIncomplete('Not implemented yet.'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/View/AjaxView.php: -------------------------------------------------------------------------------- 1 | response->type('ajax'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/TestCase/Controller/GroupsControllerTest.php: -------------------------------------------------------------------------------- 1 | markTestIncomplete('Not implemented yet.'); 31 | } 32 | 33 | /** 34 | * Test view method 35 | * 36 | * @return void 37 | */ 38 | public function testView() 39 | { 40 | $this->markTestIncomplete('Not implemented yet.'); 41 | } 42 | 43 | /** 44 | * Test add method 45 | * 46 | * @return void 47 | */ 48 | public function testAdd() 49 | { 50 | $this->markTestIncomplete('Not implemented yet.'); 51 | } 52 | 53 | /** 54 | * Test edit method 55 | * 56 | * @return void 57 | */ 58 | public function testEdit() 59 | { 60 | $this->markTestIncomplete('Not implemented yet.'); 61 | } 62 | 63 | /** 64 | * Test delete method 65 | * 66 | * @return void 67 | */ 68 | public function testDelete() 69 | { 70 | $this->markTestIncomplete('Not implemented yet.'); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/TestCase/Controller/PostsControllerTest.php: -------------------------------------------------------------------------------- 1 | markTestIncomplete('Not implemented yet.'); 32 | } 33 | 34 | /** 35 | * Test view method 36 | * 37 | * @return void 38 | */ 39 | public function testView() 40 | { 41 | $this->markTestIncomplete('Not implemented yet.'); 42 | } 43 | 44 | /** 45 | * Test add method 46 | * 47 | * @return void 48 | */ 49 | public function testAdd() 50 | { 51 | $this->markTestIncomplete('Not implemented yet.'); 52 | } 53 | 54 | /** 55 | * Test edit method 56 | * 57 | * @return void 58 | */ 59 | public function testEdit() 60 | { 61 | $this->markTestIncomplete('Not implemented yet.'); 62 | } 63 | 64 | /** 65 | * Test delete method 66 | * 67 | * @return void 68 | */ 69 | public function testDelete() 70 | { 71 | $this->markTestIncomplete('Not implemented yet.'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/TestCase/Controller/UsersControllerTest.php: -------------------------------------------------------------------------------- 1 | markTestIncomplete('Not implemented yet.'); 32 | } 33 | 34 | /** 35 | * Test view method 36 | * 37 | * @return void 38 | */ 39 | public function testView() 40 | { 41 | $this->markTestIncomplete('Not implemented yet.'); 42 | } 43 | 44 | /** 45 | * Test add method 46 | * 47 | * @return void 48 | */ 49 | public function testAdd() 50 | { 51 | $this->markTestIncomplete('Not implemented yet.'); 52 | } 53 | 54 | /** 55 | * Test edit method 56 | * 57 | * @return void 58 | */ 59 | public function testEdit() 60 | { 61 | $this->markTestIncomplete('Not implemented yet.'); 62 | } 63 | 64 | /** 65 | * Test delete method 66 | * 67 | * @return void 68 | */ 69 | public function testDelete() 70 | { 71 | $this->markTestIncomplete('Not implemented yet.'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/Fixture/GroupsFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 21 | 'name' => ['type' => 'string', 'length' => 100, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 22 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 23 | 'modified' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 24 | '_constraints' => [ 25 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 26 | ], 27 | '_options' => [ 28 | 'engine' => 'InnoDB', 29 | 'collation' => 'latin1_swedish_ci' 30 | ], 31 | ]; 32 | // @codingStandardsIgnoreEnd 33 | 34 | /** 35 | * Records 36 | * 37 | * @var array 38 | */ 39 | public $records = [ 40 | [ 41 | 'id' => 1, 42 | 'name' => 'Lorem ipsum dolor sit amet', 43 | 'created' => '2015-08-14 23:27:38', 44 | 'modified' => '2015-08-14 23:27:38' 45 | ], 46 | ]; 47 | } 48 | -------------------------------------------------------------------------------- /tests/Fixture/WidgetsFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 21 | 'name' => ['type' => 'string', 'length' => 100, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 22 | 'part_no' => ['type' => 'string', 'length' => 12, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 23 | 'quantity' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], 24 | '_constraints' => [ 25 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 26 | ], 27 | '_options' => [ 28 | 'engine' => 'InnoDB', 29 | 'collation' => 'latin1_swedish_ci' 30 | ], 31 | ]; 32 | // @codingStandardsIgnoreEnd 33 | 34 | /** 35 | * Records 36 | * 37 | * @var array 38 | */ 39 | public $records = [ 40 | [ 41 | 'id' => 1, 42 | 'name' => 'Lorem ipsum dolor sit amet', 43 | 'part_no' => 'Lorem ipsu', 44 | 'quantity' => 1 45 | ], 46 | ]; 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestCase/Model/Table/PostsTableTest.php: -------------------------------------------------------------------------------- 1 | 'App\Model\Table\PostsTable']; 34 | $this->Posts = TableRegistry::get('Posts', $config); 35 | } 36 | 37 | /** 38 | * tearDown method 39 | * 40 | * @return void 41 | */ 42 | public function tearDown() 43 | { 44 | unset($this->Posts); 45 | 46 | parent::tearDown(); 47 | } 48 | 49 | /** 50 | * Test initialize method 51 | * 52 | * @return void 53 | */ 54 | public function testInitialize() 55 | { 56 | $this->markTestIncomplete('Not implemented yet.'); 57 | } 58 | 59 | /** 60 | * Test validationDefault method 61 | * 62 | * @return void 63 | */ 64 | public function testValidationDefault() 65 | { 66 | $this->markTestIncomplete('Not implemented yet.'); 67 | } 68 | 69 | /** 70 | * Test buildRules method 71 | * 72 | * @return void 73 | */ 74 | public function testBuildRules() 75 | { 76 | $this->markTestIncomplete('Not implemented yet.'); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/TestCase/Model/Table/UsersTableTest.php: -------------------------------------------------------------------------------- 1 | 'App\Model\Table\UsersTable']; 34 | $this->Users = TableRegistry::get('Users', $config); 35 | } 36 | 37 | /** 38 | * tearDown method 39 | * 40 | * @return void 41 | */ 42 | public function tearDown() 43 | { 44 | unset($this->Users); 45 | 46 | parent::tearDown(); 47 | } 48 | 49 | /** 50 | * Test initialize method 51 | * 52 | * @return void 53 | */ 54 | public function testInitialize() 55 | { 56 | $this->markTestIncomplete('Not implemented yet.'); 57 | } 58 | 59 | /** 60 | * Test validationDefault method 61 | * 62 | * @return void 63 | */ 64 | public function testValidationDefault() 65 | { 66 | $this->markTestIncomplete('Not implemented yet.'); 67 | } 68 | 69 | /** 70 | * Test buildRules method 71 | * 72 | * @return void 73 | */ 74 | public function testBuildRules() 75 | { 76 | $this->markTestIncomplete('Not implemented yet.'); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Template/Widgets/index.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('New Widget'), ['action' => 'add']) ?>
  • 5 |
6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 |
Paginator->sort('id') ?>Paginator->sort('name') ?>Paginator->sort('part_no') ?>Paginator->sort('quantity') ?>
Number->format($widget->id) ?>name) ?>part_no) ?>Number->format($widget->quantity) ?> 26 | Html->link(__('View'), ['action' => 'view', $widget->id]) ?> 27 | Html->link(__('Edit'), ['action' => 'edit', $widget->id]) ?> 28 | Form->postLink(__('Delete'), ['action' => 'delete', $widget->id], ['confirm' => __('Are you sure you want to delete # {0}?', $widget->id)]) ?> 29 |
35 |
36 |
    37 | Paginator->prev('< ' . __('previous')) ?> 38 | Paginator->numbers() ?> 39 | Paginator->next(__('next') . ' >') ?> 40 |
41 |

Paginator->counter() ?>

42 |
43 |
44 | -------------------------------------------------------------------------------- /src/Template/Layout/error.ctp: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | Html->charset() ?> 22 | 23 | <?= $cakeDescription ?>: 24 | <?= $this->fetch('title') ?> 25 | 26 | Html->meta('icon') ?> 27 | 28 | Html->css('base.css') ?> 29 | Html->css('cake.css') ?> 30 | 31 | fetch('meta') ?> 32 | fetch('css') ?> 33 | fetch('script') ?> 34 | 35 | 36 |
37 | 40 |
41 | Flash->render() ?> 42 | 43 | fetch('content') ?> 44 |
45 | 53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /src/Model/Table/PostsTable.php: -------------------------------------------------------------------------------- 1 | table('posts'); 29 | $this->displayField('title'); 30 | $this->primaryKey('id'); 31 | $this->addBehavior('Timestamp'); 32 | $this->belongsTo('Users', [ 33 | 'foreignKey' => 'user_id', 34 | 'joinType' => 'INNER' 35 | ]); 36 | } 37 | 38 | /** 39 | * Default validation rules. 40 | * 41 | * @param \Cake\Validation\Validator $validator Validator instance. 42 | * @return \Cake\Validation\Validator 43 | */ 44 | public function validationDefault(Validator $validator) 45 | { 46 | $validator 47 | ->add('id', 'valid', ['rule' => 'numeric']) 48 | ->allowEmpty('id', 'create'); 49 | 50 | $validator 51 | ->requirePresence('title', 'create') 52 | ->notEmpty('title'); 53 | 54 | $validator 55 | ->allowEmpty('body'); 56 | 57 | return $validator; 58 | } 59 | 60 | /** 61 | * Returns a rules checker object that will be used for validating 62 | * application integrity. 63 | * 64 | * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. 65 | * @return \Cake\ORM\RulesChecker 66 | */ 67 | public function buildRules(RulesChecker $rules) 68 | { 69 | $rules->add($rules->existsIn(['user_id'], 'Users')); 70 | return $rules; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Template/Layout/default.ctp: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | Html->charset() ?> 22 | 23 | 24 | <?= $cakeDescription ?>: 25 | <?= $this->fetch('title') ?> 26 | 27 | Html->meta('icon') ?> 28 | 29 | Html->css('base.css') ?> 30 | Html->css('cake.css') ?> 31 | 32 | fetch('meta') ?> 33 | fetch('css') ?> 34 | fetch('script') ?> 35 | 36 | 37 |
38 |
39 | fetch('title') ?> 40 |
41 |
42 | Documentation 43 | API 44 |
45 |
46 |
47 | 48 |
49 | Flash->render() ?> 50 | 51 |
52 | fetch('content') ?> 53 |
54 |
55 |
56 |
57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /src/Template/Posts/view.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('Edit Post'), ['action' => 'edit', $post->id]) ?>
  • 5 |
  • Form->postLink(__('Delete Post'), ['action' => 'delete', $post->id], ['confirm' => __('Are you sure you want to delete # {0}?', $post->id)]) ?>
  • 6 |
  • Html->link(__('List Posts'), ['action' => 'index']) ?>
  • 7 |
  • Html->link(__('New Post'), ['action' => 'add']) ?>
  • 8 |
  • Html->link(__('List Users'), ['controller' => 'Users', 'action' => 'index']) ?>
  • 9 |
  • Html->link(__('New User'), ['controller' => 'Users', 'action' => 'add']) ?>
  • 10 |
11 |
12 |
13 |

title) ?>

14 |
15 |
16 |
17 |

has('user') ? $this->Html->link($post->user->id, ['controller' => 'Users', 'action' => 'view', $post->user->id]) : '' ?>

18 |
19 |

title) ?>

20 |
21 |
22 |
23 |

Number->format($post->id) ?>

24 |
25 |
26 |
27 |

created) ?>

28 |
29 |

modified) ?>

30 |
31 |
32 |
33 |
34 |
35 | Text->autoParagraph(h($post->body)) ?> 36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /src/Template/Groups/index.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('New Group'), ['action' => 'add']) ?>
  • 5 |
  • Html->link(__('List Users'), ['controller' => 'Users', 'action' => 'index']) ?>
  • 6 |
  • Html->link(__('New User'), ['controller' => 'Users', 'action' => 'add']) ?>
  • 7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 32 | 33 | 34 | 35 | 36 |
Paginator->sort('id') ?>Paginator->sort('name') ?>Paginator->sort('created') ?>Paginator->sort('modified') ?>
Number->format($group->id) ?>name) ?>created) ?>modified) ?> 28 | Html->link(__('View'), ['action' => 'view', $group->id]) ?> 29 | Html->link(__('Edit'), ['action' => 'edit', $group->id]) ?> 30 | Form->postLink(__('Delete'), ['action' => 'delete', $group->id], ['confirm' => __('Are you sure you want to delete # {0}?', $group->id)]) ?> 31 |
37 |
38 |
    39 | Paginator->prev('< ' . __('previous')) ?> 40 | Paginator->numbers() ?> 41 | Paginator->next(__('next') . ' >') ?> 42 |
43 |

Paginator->counter() ?>

44 |
45 |
46 | -------------------------------------------------------------------------------- /src/Controller/PagesController.php: -------------------------------------------------------------------------------- 1 | redirect('/'); 45 | } 46 | $page = $subpage = null; 47 | 48 | if (!empty($path[0])) { 49 | $page = $path[0]; 50 | } 51 | if (!empty($path[1])) { 52 | $subpage = $path[1]; 53 | } 54 | $this->set(compact('page', 'subpage')); 55 | 56 | try { 57 | $this->render(implode('/', $path)); 58 | } catch (MissingTemplateException $e) { 59 | if (Configure::read('debug')) { 60 | throw $e; 61 | } 62 | throw new NotFoundException(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/Fixture/UsersFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 21 | 'username' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 22 | 'password' => ['type' => 'string', 'fixed' => true, 'length' => 60, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], 23 | 'group_id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], 24 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 25 | 'modified' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 26 | '_constraints' => [ 27 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 28 | 'username' => ['type' => 'unique', 'columns' => ['username'], 'length' => []], 29 | ], 30 | '_options' => [ 31 | 'engine' => 'InnoDB', 32 | 'collation' => 'latin1_swedish_ci' 33 | ], 34 | ]; 35 | // @codingStandardsIgnoreEnd 36 | 37 | /** 38 | * Records 39 | * 40 | * @var array 41 | */ 42 | public $records = [ 43 | [ 44 | 'id' => 1, 45 | 'username' => 'Lorem ipsum dolor sit amet', 46 | 'password' => 'Lorem ipsum dolor sit amet', 47 | 'group_id' => 1, 48 | 'created' => '2015-08-14 23:27:44', 49 | 'modified' => '2015-08-14 23:27:44' 50 | ], 51 | ]; 52 | } 53 | -------------------------------------------------------------------------------- /src/Controller/AppController.php: -------------------------------------------------------------------------------- 1 | [ 31 | 'className' => 'Acl.Acl' 32 | ] 33 | ]; 34 | 35 | /** 36 | * Initialization hook method. 37 | * 38 | * Use this method to add common initialization code like loading components. 39 | * 40 | * @return void 41 | */ 42 | public function initialize() 43 | { 44 | parent::initialize(); 45 | $this->loadComponent('Flash'); 46 | $this->loadComponent('Auth', [ 47 | 'authorize' => [ 48 | 'Acl.Actions' => ['actionPath' => 'controllers/'] 49 | ], 50 | 'loginAction' => [ 51 | 'plugin' => false, 52 | 'controller' => 'Users', 53 | 'action' => 'login' 54 | ], 55 | 'loginRedirect' => [ 56 | 'plugin' => false, 57 | 'controller' => 'Posts', 58 | 'action' => 'index' 59 | ], 60 | 'logoutRedirect' => [ 61 | 'plugin' => false, 62 | 'controller' => 'Users', 63 | 'action' => 'login' 64 | ], 65 | 'unauthorizedRedirect' => [ 66 | 'controller' => 'Users', 67 | 'action' => 'login', 68 | 'prefix' => false 69 | ], 70 | 'authError' => 'You are not authorized to access that location.', 71 | 'flash' => [ 72 | 'element' => 'error' 73 | ] 74 | ]); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Template/Posts/index.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('New Post'), ['action' => 'add']) ?>
  • 5 |
  • Html->link(__('List Users'), ['controller' => 'Users', 'action' => 'index']) ?>
  • 6 |
  • Html->link(__('New User'), ['controller' => 'Users', 'action' => 'add']) ?>
  • 7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 |
Paginator->sort('id') ?>Paginator->sort('user_id') ?>Paginator->sort('title') ?>Paginator->sort('created') ?>Paginator->sort('modified') ?>
Number->format($post->id) ?> 26 | has('user') ? $this->Html->link($post->user->id, ['controller' => 'Users', 'action' => 'view', $post->user->id]) : '' ?> 27 | title) ?>created) ?>modified) ?> 32 | Html->link(__('View'), ['action' => 'view', $post->id]) ?> 33 | Html->link(__('Edit'), ['action' => 'edit', $post->id]) ?> 34 | Form->postLink(__('Delete'), ['action' => 'delete', $post->id], ['confirm' => __('Are you sure you want to delete # {0}?', $post->id)]) ?> 35 |
41 |
42 |
    43 | Paginator->prev('< ' . __('previous')) ?> 44 | Paginator->numbers() ?> 45 | Paginator->next(__('next') . ' >') ?> 46 |
47 |

Paginator->counter() ?>

48 |
49 |
50 | -------------------------------------------------------------------------------- /tests/Fixture/PostsFixture.php: -------------------------------------------------------------------------------- 1 | ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 21 | 'user_id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], 22 | 'title' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 23 | 'body' => ['type' => 'text', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 24 | 'created' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 25 | 'modified' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 26 | '_constraints' => [ 27 | 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], 28 | ], 29 | '_options' => [ 30 | 'engine' => 'InnoDB', 31 | 'collation' => 'latin1_swedish_ci' 32 | ], 33 | ]; 34 | // @codingStandardsIgnoreEnd 35 | 36 | /** 37 | * Records 38 | * 39 | * @var array 40 | */ 41 | public $records = [ 42 | [ 43 | 'id' => 1, 44 | 'user_id' => 1, 45 | 'title' => 'Lorem ipsum dolor sit amet', 46 | 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida, phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit, feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.', 47 | 'created' => '2015-08-14 23:27:50', 48 | 'modified' => '2015-08-14 23:27:50' 49 | ], 50 | ]; 51 | } 52 | -------------------------------------------------------------------------------- /config/paths.php: -------------------------------------------------------------------------------- 1 | 2 |

3 |
    4 |
  • Html->link(__('New User'), ['action' => 'add']) ?>
  • 5 |
  • Html->link(__('List Groups'), ['controller' => 'Groups', 'action' => 'index']) ?>
  • 6 |
  • Html->link(__('New Group'), ['controller' => 'Groups', 'action' => 'add']) ?>
  • 7 |
  • Html->link(__('List Posts'), ['controller' => 'Posts', 'action' => 'index']) ?>
  • 8 |
  • Html->link(__('New Post'), ['controller' => 'Posts', 'action' => 'add']) ?>
  • 9 |
10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 38 | 39 | 40 | 41 | 42 |
Paginator->sort('id') ?>Paginator->sort('username') ?>Paginator->sort('group_id') ?>Paginator->sort('created') ?>Paginator->sort('modified') ?>
Number->format($user->id) ?>username) ?> 29 | has('group') ? $this->Html->link($user->group->name, ['controller' => 'Groups', 'action' => 'view', $user->group->id]) : '' ?> 30 | created) ?>modified) ?> 34 | Html->link(__('View'), ['action' => 'view', $user->id]) ?> 35 | Html->link(__('Edit'), ['action' => 'edit', $user->id]) ?> 36 | Form->postLink(__('Delete'), ['action' => 'delete', $user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]) ?> 37 |
43 |
44 |
    45 | Paginator->prev('< ' . __('previous')) ?> 46 | Paginator->numbers() ?> 47 | Paginator->next(__('next') . ' >') ?> 48 |
49 |

Paginator->counter() ?>

50 |
51 |
52 | -------------------------------------------------------------------------------- /src/Model/Table/UsersTable.php: -------------------------------------------------------------------------------- 1 | table('users'); 31 | $this->displayField('id'); 32 | $this->primaryKey('id'); 33 | $this->addBehavior('Timestamp'); 34 | $this->addBehavior('Acl.Acl', ['type' => 'requester']); 35 | $this->belongsTo('Groups', [ 36 | 'foreignKey' => 'group_id', 37 | 'joinType' => 'INNER' 38 | ]); 39 | $this->hasMany('Posts', [ 40 | 'foreignKey' => 'user_id' 41 | ]); 42 | } 43 | 44 | /** 45 | * Default validation rules. 46 | * 47 | * @param \Cake\Validation\Validator $validator Validator instance. 48 | * @return \Cake\Validation\Validator 49 | */ 50 | public function validationDefault(Validator $validator) 51 | { 52 | $validator 53 | ->add('id', 'valid', ['rule' => 'numeric']) 54 | ->allowEmpty('id', 'create'); 55 | 56 | $validator 57 | ->requirePresence('username', 'create') 58 | ->notEmpty('username') 59 | ->add('username', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); 60 | 61 | $validator 62 | ->requirePresence('password', 'create') 63 | ->notEmpty('password'); 64 | 65 | return $validator; 66 | } 67 | 68 | /** 69 | * Returns a rules checker object that will be used for validating 70 | * application integrity. 71 | * 72 | * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. 73 | * @return \Cake\ORM\RulesChecker 74 | */ 75 | public function buildRules(RulesChecker $rules) 76 | { 77 | $rules->add($rules->isUnique(['username'])); 78 | $rules->add($rules->existsIn(['group_id'], 'Groups')); 79 | return $rules; 80 | } 81 | 82 | public function beforeSave(\Cake\Event\Event $event, \Cake\ORM\Entity $entity, 83 | \ArrayObject $options) 84 | { 85 | $hasher = new DefaultPasswordHasher; 86 | $entity->password = $hasher->hash($entity->password); 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Shell/ConsoleShell.php: -------------------------------------------------------------------------------- 1 | err('Unable to load Psy\Shell.'); 37 | $this->err(''); 38 | $this->err('Make sure you have installed psysh as a dependency,'); 39 | $this->err('and that Psy\Shell is registered in your autoloader.'); 40 | $this->err(''); 41 | $this->err('If you are using composer run'); 42 | $this->err(''); 43 | $this->err('$ php composer.phar require --dev psy/psysh'); 44 | $this->err(''); 45 | return 1; 46 | } 47 | 48 | $this->out("You can exit with `CTRL-C` or `exit`"); 49 | $this->out(''); 50 | 51 | Log::drop('debug'); 52 | Log::drop('error'); 53 | $this->_io->setLoggers(false); 54 | restore_error_handler(); 55 | restore_exception_handler(); 56 | 57 | $psy = new PsyShell(); 58 | $psy->run(); 59 | } 60 | 61 | /** 62 | * Display help for this console. 63 | * 64 | * @return ConsoleOptionParser 65 | */ 66 | public function getOptionParser() 67 | { 68 | $parser = new ConsoleOptionParser('console'); 69 | $parser->description( 70 | 'This shell provides a REPL that you can use to interact ' . 71 | 'with your application in an interactive fashion. You can use ' . 72 | 'it to run adhoc queries with your models, or experiment ' . 73 | 'and explore the features of CakePHP and your application.' . 74 | "\n\n" . 75 | 'You will need to have psysh installed for this Shell to work.' 76 | ); 77 | return $parser; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /config/routes.php: -------------------------------------------------------------------------------- 1 | connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']); 51 | 52 | /** 53 | * ...and connect the rest of 'Pages' controller's URLs. 54 | */ 55 | $routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']); 56 | 57 | /** 58 | * Connect catchall routes for all controllers. 59 | * 60 | * Using the argument `InflectedRoute`, the `fallbacks` method is a shortcut for 61 | * `$routes->connect('/:controller', ['action' => 'index'], ['routeClass' => 'InflectedRoute']);` 62 | * `$routes->connect('/:controller/:action/*', [], ['routeClass' => 'InflectedRoute']);` 63 | * 64 | * Any route class can be used with this method, such as: 65 | * - DashedRoute 66 | * - InflectedRoute 67 | * - Route 68 | * - Or your own route class 69 | * 70 | * You can remove these routes once you've connected the 71 | * routes you want in your application. 72 | */ 73 | $routes->fallbacks('InflectedRoute'); 74 | }); 75 | 76 | /** 77 | * Load all plugin routes. See the Plugin documentation on 78 | * how to customize the loading of plugin routes. 79 | */ 80 | Plugin::routes(); 81 | -------------------------------------------------------------------------------- /src/Template/Groups/view.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('Edit Group'), ['action' => 'edit', $group->id]) ?>
  • 5 |
  • Form->postLink(__('Delete Group'), ['action' => 'delete', $group->id], ['confirm' => __('Are you sure you want to delete # {0}?', $group->id)]) ?>
  • 6 |
  • Html->link(__('List Groups'), ['action' => 'index']) ?>
  • 7 |
  • Html->link(__('New Group'), ['action' => 'add']) ?>
  • 8 |
  • Html->link(__('List Users'), ['controller' => 'Users', 'action' => 'index']) ?>
  • 9 |
  • Html->link(__('New User'), ['controller' => 'Users', 'action' => 'add']) ?>
  • 10 |
11 |
12 |
13 |

name) ?>

14 |
15 |
16 |
17 |

name) ?>

18 |
19 |
20 |
21 |

Number->format($group->id) ?>

22 |
23 |
24 |
25 |

created) ?>

26 |
27 |

modified) ?>

28 |
29 |
30 |
31 | 69 | -------------------------------------------------------------------------------- /src/Template/Users/view.ctp: -------------------------------------------------------------------------------- 1 |
2 |

3 |
    4 |
  • Html->link(__('Edit User'), ['action' => 'edit', $user->id]) ?>
  • 5 |
  • Form->postLink(__('Delete User'), ['action' => 'delete', $user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]) ?>
  • 6 |
  • Html->link(__('List Users'), ['action' => 'index']) ?>
  • 7 |
  • Html->link(__('New User'), ['action' => 'add']) ?>
  • 8 |
  • Html->link(__('List Groups'), ['controller' => 'Groups', 'action' => 'index']) ?>
  • 9 |
  • Html->link(__('New Group'), ['controller' => 'Groups', 'action' => 'add']) ?>
  • 10 |
  • Html->link(__('List Posts'), ['controller' => 'Posts', 'action' => 'index']) ?>
  • 11 |
  • Html->link(__('New Post'), ['controller' => 'Posts', 'action' => 'add']) ?>
  • 12 |
13 |
14 |
15 |

id) ?>

16 |
17 |
18 |
19 |

username) ?>

20 |
21 |

has('group') ? $this->Html->link($user->group->name, ['controller' => 'Groups', 'action' => 'view', $user->group->id]) : '' ?>

22 |
23 |
24 |
25 |

Number->format($user->id) ?>

26 |
27 |
28 |
29 |

created) ?>

30 |
31 |

modified) ?>

32 |
33 |
34 |
35 | 73 | -------------------------------------------------------------------------------- /src/Controller/WidgetsController.php: -------------------------------------------------------------------------------- 1 | set('widgets', $this->paginate($this->Widgets)); 22 | $this->set('_serialize', ['widgets']); 23 | } 24 | 25 | /** 26 | * View method 27 | * 28 | * @param string|null $id Widget id. 29 | * @return void 30 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 31 | */ 32 | public function view($id = null) 33 | { 34 | $widget = $this->Widgets->get($id, [ 35 | 'contain' => [] 36 | ]); 37 | $this->set('widget', $widget); 38 | $this->set('_serialize', ['widget']); 39 | } 40 | 41 | /** 42 | * Add method 43 | * 44 | * @return void Redirects on successful add, renders view otherwise. 45 | */ 46 | public function add() 47 | { 48 | $widget = $this->Widgets->newEntity(); 49 | if ($this->request->is('post')) { 50 | $widget = $this->Widgets->patchEntity($widget, $this->request->data); 51 | if ($this->Widgets->save($widget)) { 52 | $this->Flash->success(__('The widget has been saved.')); 53 | return $this->redirect(['action' => 'index']); 54 | } else { 55 | $this->Flash->error(__('The widget could not be saved. Please, try again.')); 56 | } 57 | } 58 | $this->set(compact('widget')); 59 | $this->set('_serialize', ['widget']); 60 | } 61 | 62 | /** 63 | * Edit method 64 | * 65 | * @param string|null $id Widget id. 66 | * @return void Redirects on successful edit, renders view otherwise. 67 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 68 | */ 69 | public function edit($id = null) 70 | { 71 | $widget = $this->Widgets->get($id, [ 72 | 'contain' => [] 73 | ]); 74 | if ($this->request->is(['patch', 'post', 'put'])) { 75 | $widget = $this->Widgets->patchEntity($widget, $this->request->data); 76 | if ($this->Widgets->save($widget)) { 77 | $this->Flash->success(__('The widget has been saved.')); 78 | return $this->redirect(['action' => 'index']); 79 | } else { 80 | $this->Flash->error(__('The widget could not be saved. Please, try again.')); 81 | } 82 | } 83 | $this->set(compact('widget')); 84 | $this->set('_serialize', ['widget']); 85 | } 86 | 87 | /** 88 | * Delete method 89 | * 90 | * @param string|null $id Widget id. 91 | * @return void Redirects to index. 92 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 93 | */ 94 | public function delete($id = null) 95 | { 96 | $this->request->allowMethod(['post', 'delete']); 97 | $widget = $this->Widgets->get($id); 98 | if ($this->Widgets->delete($widget)) { 99 | $this->Flash->success(__('The widget has been deleted.')); 100 | } else { 101 | $this->Flash->error(__('The widget could not be deleted. Please, try again.')); 102 | } 103 | return $this->redirect(['action' => 'index']); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Controller/GroupsController.php: -------------------------------------------------------------------------------- 1 | Auth->allow(); 19 | } 20 | 21 | /** 22 | * Index method 23 | * 24 | * @return void 25 | */ 26 | public function index() 27 | { 28 | $this->set('groups', $this->paginate($this->Groups)); 29 | $this->set('_serialize', ['groups']); 30 | } 31 | 32 | /** 33 | * View method 34 | * 35 | * @param string|null $id Group id. 36 | * @return void 37 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 38 | */ 39 | public function view($id = null) 40 | { 41 | $group = $this->Groups->get($id, [ 42 | 'contain' => ['Users'] 43 | ]); 44 | $this->set('group', $group); 45 | $this->set('_serialize', ['group']); 46 | } 47 | 48 | /** 49 | * Add method 50 | * 51 | * @return void Redirects on successful add, renders view otherwise. 52 | */ 53 | public function add() 54 | { 55 | $group = $this->Groups->newEntity(); 56 | if ($this->request->is('post')) { 57 | $group = $this->Groups->patchEntity($group, $this->request->data); 58 | if ($this->Groups->save($group)) { 59 | $this->Flash->success(__('The group has been saved.')); 60 | return $this->redirect(['action' => 'index']); 61 | } else { 62 | $this->Flash->error(__('The group could not be saved. Please, try again.')); 63 | } 64 | } 65 | $this->set(compact('group')); 66 | $this->set('_serialize', ['group']); 67 | } 68 | 69 | /** 70 | * Edit method 71 | * 72 | * @param string|null $id Group id. 73 | * @return void Redirects on successful edit, renders view otherwise. 74 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 75 | */ 76 | public function edit($id = null) 77 | { 78 | $group = $this->Groups->get($id, [ 79 | 'contain' => [] 80 | ]); 81 | if ($this->request->is(['patch', 'post', 'put'])) { 82 | $group = $this->Groups->patchEntity($group, $this->request->data); 83 | if ($this->Groups->save($group)) { 84 | $this->Flash->success(__('The group has been saved.')); 85 | return $this->redirect(['action' => 'index']); 86 | } else { 87 | $this->Flash->error(__('The group could not be saved. Please, try again.')); 88 | } 89 | } 90 | $this->set(compact('group')); 91 | $this->set('_serialize', ['group']); 92 | } 93 | 94 | /** 95 | * Delete method 96 | * 97 | * @param string|null $id Group id. 98 | * @return void Redirects to index. 99 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 100 | */ 101 | public function delete($id = null) 102 | { 103 | $this->request->allowMethod(['post', 'delete']); 104 | $group = $this->Groups->get($id); 105 | if ($this->Groups->delete($group)) { 106 | $this->Flash->success(__('The group has been deleted.')); 107 | } else { 108 | $this->Flash->error(__('The group could not be deleted. Please, try again.')); 109 | } 110 | return $this->redirect(['action' => 'index']); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Controller/PostsController.php: -------------------------------------------------------------------------------- 1 | paginate = [ 22 | 'contain' => ['Users'] 23 | ]; 24 | $this->set('posts', $this->paginate($this->Posts)); 25 | $this->set('_serialize', ['posts']); 26 | } 27 | 28 | /** 29 | * View method 30 | * 31 | * @param string|null $id Post id. 32 | * @return void 33 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 34 | */ 35 | public function view($id = null) 36 | { 37 | $post = $this->Posts->get($id, [ 38 | 'contain' => ['Users'] 39 | ]); 40 | $this->set('post', $post); 41 | $this->set('_serialize', ['post']); 42 | } 43 | 44 | /** 45 | * Add method 46 | * 47 | * @return void Redirects on successful add, renders view otherwise. 48 | */ 49 | public function add() 50 | { 51 | $post = $this->Posts->newEntity(); 52 | if ($this->request->is('post')) { 53 | $post = $this->Posts->patchEntity($post, $this->request->data); 54 | if ($this->Posts->save($post)) { 55 | $this->Flash->success(__('The post has been saved.')); 56 | return $this->redirect(['action' => 'index']); 57 | } else { 58 | $this->Flash->error(__('The post could not be saved. Please, try again.')); 59 | } 60 | } 61 | $users = $this->Posts->Users->find('list', ['limit' => 200]); 62 | $this->set(compact('post', 'users')); 63 | $this->set('_serialize', ['post']); 64 | } 65 | 66 | /** 67 | * Edit method 68 | * 69 | * @param string|null $id Post id. 70 | * @return void Redirects on successful edit, renders view otherwise. 71 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 72 | */ 73 | public function edit($id = null) 74 | { 75 | $post = $this->Posts->get($id, [ 76 | 'contain' => [] 77 | ]); 78 | if ($this->request->is(['patch', 'post', 'put'])) { 79 | $post = $this->Posts->patchEntity($post, $this->request->data); 80 | if ($this->Posts->save($post)) { 81 | $this->Flash->success(__('The post has been saved.')); 82 | return $this->redirect(['action' => 'index']); 83 | } else { 84 | $this->Flash->error(__('The post could not be saved. Please, try again.')); 85 | } 86 | } 87 | $users = $this->Posts->Users->find('list', ['limit' => 200]); 88 | $this->set(compact('post', 'users')); 89 | $this->set('_serialize', ['post']); 90 | } 91 | 92 | /** 93 | * Delete method 94 | * 95 | * @param string|null $id Post id. 96 | * @return void Redirects to index. 97 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 98 | */ 99 | public function delete($id = null) 100 | { 101 | $this->request->allowMethod(['post', 'delete']); 102 | $post = $this->Posts->get($id); 103 | if ($this->Posts->delete($post)) { 104 | $this->Flash->success(__('The post has been deleted.')); 105 | } else { 106 | $this->Flash->error(__('The post could not be deleted. Please, try again.')); 107 | } 108 | return $this->redirect(['action' => 'index']); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Controller/UsersController.php: -------------------------------------------------------------------------------- 1 | Auth->allow(); 19 | } 20 | 21 | /** 22 | * Index method 23 | * 24 | * @return void 25 | */ 26 | public function index() 27 | { 28 | $this->paginate = [ 29 | 'contain' => ['Groups'] 30 | ]; 31 | $this->set('users', $this->paginate($this->Users)); 32 | $this->set('_serialize', ['users']); 33 | } 34 | 35 | /** 36 | * View method 37 | * 38 | * @param string|null $id User id. 39 | * @return void 40 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 41 | */ 42 | public function view($id = null) 43 | { 44 | $user = $this->Users->get($id, [ 45 | 'contain' => ['Groups', 'Posts'] 46 | ]); 47 | $this->set('user', $user); 48 | $this->set('_serialize', ['user']); 49 | } 50 | 51 | /** 52 | * Add method 53 | * 54 | * @return void Redirects on successful add, renders view otherwise. 55 | */ 56 | public function add() 57 | { 58 | $user = $this->Users->newEntity(); 59 | if ($this->request->is('post')) { 60 | $user = $this->Users->patchEntity($user, $this->request->data); 61 | if ($this->Users->save($user)) { 62 | $this->Flash->success(__('The user has been saved.')); 63 | return $this->redirect(['action' => 'index']); 64 | } else { 65 | $this->Flash->error(__('The user could not be saved. Please, try again.')); 66 | } 67 | } 68 | $groups = $this->Users->Groups->find('list', ['limit' => 200]); 69 | $this->set(compact('user', 'groups')); 70 | $this->set('_serialize', ['user']); 71 | } 72 | 73 | /** 74 | * Edit method 75 | * 76 | * @param string|null $id User id. 77 | * @return void Redirects on successful edit, renders view otherwise. 78 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 79 | */ 80 | public function edit($id = null) 81 | { 82 | $user = $this->Users->get($id, [ 83 | 'contain' => [] 84 | ]); 85 | if ($this->request->is(['patch', 'post', 'put'])) { 86 | $user = $this->Users->patchEntity($user, $this->request->data); 87 | if ($this->Users->save($user)) { 88 | $this->Flash->success(__('The user has been saved.')); 89 | return $this->redirect(['action' => 'index']); 90 | } else { 91 | $this->Flash->error(__('The user could not be saved. Please, try again.')); 92 | } 93 | } 94 | $groups = $this->Users->Groups->find('list', ['limit' => 200]); 95 | $this->set(compact('user', 'groups')); 96 | $this->set('_serialize', ['user']); 97 | } 98 | 99 | /** 100 | * Delete method 101 | * 102 | * @param string|null $id User id. 103 | * @return void Redirects to index. 104 | * @throws \Cake\Network\Exception\NotFoundException When record not found. 105 | */ 106 | public function delete($id = null) 107 | { 108 | $this->request->allowMethod(['post', 'delete']); 109 | $user = $this->Users->get($id); 110 | if ($this->Users->delete($user)) { 111 | $this->Flash->success(__('The user has been deleted.')); 112 | } else { 113 | $this->Flash->error(__('The user could not be deleted. Please, try again.')); 114 | } 115 | return $this->redirect(['action' => 'index']); 116 | } 117 | 118 | /** 119 | * Login method 120 | * 121 | * @return void Redirects on successful login, renders view otherwise. 122 | */ 123 | public function login() { 124 | if ($this->request->is('post')) { 125 | $user = $this->Auth->identify(); 126 | if ($user) { 127 | $this->Auth->setUser($user); 128 | return $this->redirect($this->Auth->redirectUrl()); 129 | } 130 | $this->Flash->error(__('Your username or password was incorrect.')); 131 | } 132 | } 133 | 134 | /** 135 | * Logout method 136 | * 137 | * @return void Redirects to the logout redirect location defined in the AuthComponent 138 | */ 139 | public function logout() { 140 | $this->Flash->success(__('Good-Bye')); 141 | $this->redirect($this->Auth->logout()); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Console/Installer.php: -------------------------------------------------------------------------------- 1 | getIO(); 37 | 38 | $rootDir = dirname(dirname(__DIR__)); 39 | 40 | static::createAppConfig($rootDir, $io); 41 | static::createWritableDirectories($rootDir, $io); 42 | 43 | // ask if the permissions should be changed 44 | if ($io->isInteractive()) { 45 | $validator = function ($arg) { 46 | if (in_array($arg, ['Y', 'y', 'N', 'n'])) { 47 | return $arg; 48 | } 49 | throw new Exception('This is not a valid answer. Please choose Y or n.'); 50 | }; 51 | $setFolderPermissions = $io->askAndValidate( 52 | 'Set Folder Permissions ? (Default to Y) [Y,n]? ', 53 | $validator, 54 | 10, 55 | 'Y' 56 | ); 57 | 58 | if (in_array($setFolderPermissions, ['Y', 'y'])) { 59 | static::setFolderPermissions($rootDir, $io); 60 | } 61 | } else { 62 | static::setFolderPermissions($rootDir, $io); 63 | } 64 | 65 | static::setSecuritySalt($rootDir, $io); 66 | 67 | if (class_exists('\Cake\Codeception\Console\Installer')) { 68 | \Cake\Codeception\Console\Installer::customizeCodeceptionBinary($event); 69 | } 70 | } 71 | 72 | /** 73 | * Create the config/app.php file if it does not exist. 74 | * 75 | * @param string $dir The application's root directory. 76 | * @param \Composer\IO\IOInterface $io IO interface to write to console. 77 | * @return void 78 | */ 79 | public static function createAppConfig($dir, $io) 80 | { 81 | $appConfig = $dir . '/config/app.php'; 82 | $defaultConfig = $dir . '/config/app.default.php'; 83 | if (!file_exists($appConfig)) { 84 | copy($defaultConfig, $appConfig); 85 | $io->write('Created `config/app.php` file'); 86 | } 87 | } 88 | 89 | /** 90 | * Create the `logs` and `tmp` directories. 91 | * 92 | * @param string $dir The application's root directory. 93 | * @param \Composer\IO\IOInterface $io IO interface to write to console. 94 | * @return void 95 | */ 96 | public static function createWritableDirectories($dir, $io) 97 | { 98 | $paths = [ 99 | 'logs', 100 | 'tmp', 101 | 'tmp/cache', 102 | 'tmp/cache/models', 103 | 'tmp/cache/persistent', 104 | 'tmp/cache/views', 105 | 'tmp/sessions', 106 | 'tmp/tests' 107 | ]; 108 | 109 | foreach ($paths as $path) { 110 | $path = $dir . '/' . $path; 111 | if (!file_exists($path)) { 112 | mkdir($path); 113 | $io->write('Created `' . $path . '` directory'); 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * Set globally writable permissions on the "tmp" and "logs" directory. 120 | * 121 | * This is not the most secure default, but it gets people up and running quickly. 122 | * 123 | * @param string $dir The application's root directory. 124 | * @param \Composer\IO\IOInterface $io IO interface to write to console. 125 | * @return void 126 | */ 127 | public static function setFolderPermissions($dir, $io) 128 | { 129 | // Change the permissions on a path and output the results. 130 | $changePerms = function ($path, $perms, $io) { 131 | // Get current permissions in decimal format so we can bitmask it. 132 | $currentPerms = octdec(substr(sprintf('%o', fileperms($path)), -4)); 133 | if (($currentPerms & $perms) == $perms) { 134 | return; 135 | } 136 | 137 | $res = chmod($path, $currentPerms | $perms); 138 | if ($res) { 139 | $io->write('Permissions set on ' . $path); 140 | } else { 141 | $io->write('Failed to set permissions on ' . $path); 142 | } 143 | }; 144 | 145 | $walker = function ($dir, $perms, $io) use (&$walker, $changePerms) { 146 | $files = array_diff(scandir($dir), ['.', '..']); 147 | foreach ($files as $file) { 148 | $path = $dir . '/' . $file; 149 | 150 | if (!is_dir($path)) { 151 | continue; 152 | } 153 | 154 | $changePerms($path, $perms, $io); 155 | $walker($path, $perms, $io); 156 | } 157 | }; 158 | 159 | $worldWritable = bindec('0000000111'); 160 | $walker($dir . '/tmp', $worldWritable, $io); 161 | $changePerms($dir . '/tmp', $worldWritable, $io); 162 | $changePerms($dir . '/logs', $worldWritable, $io); 163 | } 164 | 165 | /** 166 | * Set the security.salt value in the application's config file. 167 | * 168 | * @param string $dir The application's root directory. 169 | * @param \Composer\IO\IOInterface $io IO interface to write to console. 170 | * @return void 171 | */ 172 | public static function setSecuritySalt($dir, $io) 173 | { 174 | $config = $dir . '/config/app.php'; 175 | $content = file_get_contents($config); 176 | 177 | $newKey = hash('sha256', $dir . php_uname() . microtime(true)); 178 | $content = str_replace('__SALT__', $newKey, $content, $count); 179 | 180 | if ($count == 0) { 181 | $io->write('No Security.salt placeholder to replace.'); 182 | return; 183 | } 184 | 185 | $result = file_put_contents($config, $content); 186 | if ($result) { 187 | $io->write('Updated Security.salt value in config/app.php'); 188 | return; 189 | } 190 | $io->write('Unable to update Security.salt value.'); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /config/bootstrap.php: -------------------------------------------------------------------------------- 1 | getMessage() . "\n"); 70 | } 71 | 72 | // Load an environment local configuration file. 73 | // You can use a file like app_local.php to provide local overrides to your 74 | // shared configuration. 75 | //Configure::load('app_local', 'default'); 76 | 77 | // When debug = false the metadata cache should last 78 | // for a very very long time, as we don't want 79 | // to refresh the cache while users are doing requests. 80 | if (!Configure::read('debug')) { 81 | Configure::write('Cache._cake_model_.duration', '+1 years'); 82 | Configure::write('Cache._cake_core_.duration', '+1 years'); 83 | } 84 | 85 | /** 86 | * Set server timezone to UTC. You can change it to another timezone of your 87 | * choice but using UTC makes time calculations / conversions easier. 88 | */ 89 | date_default_timezone_set('UTC'); 90 | 91 | /** 92 | * Configure the mbstring extension to use the correct encoding. 93 | */ 94 | mb_internal_encoding(Configure::read('App.encoding')); 95 | 96 | /** 97 | * Set the default locale. This controls how dates, number and currency is 98 | * formatted and sets the default language to use for translations. 99 | */ 100 | ini_set('intl.default_locale', 'en_US'); 101 | 102 | /** 103 | * Register application error and exception handlers. 104 | */ 105 | $isCli = php_sapi_name() === 'cli'; 106 | if ($isCli) { 107 | (new ConsoleErrorHandler(Configure::read('Error')))->register(); 108 | } else { 109 | (new ErrorHandler(Configure::read('Error')))->register(); 110 | } 111 | 112 | // Include the CLI bootstrap overrides. 113 | if ($isCli) { 114 | require __DIR__ . '/bootstrap_cli.php'; 115 | } 116 | 117 | /** 118 | * Set the full base URL. 119 | * This URL is used as the base of all absolute links. 120 | * 121 | * If you define fullBaseUrl in your config file you can remove this. 122 | */ 123 | if (!Configure::read('App.fullBaseUrl')) { 124 | $s = null; 125 | if (env('HTTPS')) { 126 | $s = 's'; 127 | } 128 | 129 | $httpHost = env('HTTP_HOST'); 130 | if (isset($httpHost)) { 131 | Configure::write('App.fullBaseUrl', 'http' . $s . '://' . $httpHost); 132 | } 133 | unset($httpHost, $s); 134 | } 135 | 136 | Cache::config(Configure::consume('Cache')); 137 | ConnectionManager::config(Configure::consume('Datasources')); 138 | Email::configTransport(Configure::consume('EmailTransport')); 139 | Email::config(Configure::consume('Email')); 140 | Log::config(Configure::consume('Log')); 141 | Security::salt(Configure::consume('Security.salt')); 142 | 143 | /** 144 | * The default crypto extension in 3.0 is OpenSSL. 145 | * If you are migrating from 2.x uncomment this code to 146 | * use a more compatible Mcrypt based implementation 147 | */ 148 | // Security::engine(new \Cake\Utility\Crypto\Mcrypt()); 149 | 150 | /** 151 | * Setup detectors for mobile and tablet. 152 | */ 153 | Request::addDetector('mobile', function ($request) { 154 | $detector = new \Detection\MobileDetect(); 155 | return $detector->isMobile(); 156 | }); 157 | Request::addDetector('tablet', function ($request) { 158 | $detector = new \Detection\MobileDetect(); 159 | return $detector->isTablet(); 160 | }); 161 | 162 | /** 163 | * Custom Inflector rules, can be set to correctly pluralize or singularize 164 | * table, model, controller names or whatever other string is passed to the 165 | * inflection functions. 166 | * 167 | * Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']); 168 | * Inflector::rules('irregular', ['red' => 'redlings']); 169 | * Inflector::rules('uninflected', ['dontinflectme']); 170 | * Inflector::rules('transliteration', ['/å/' => 'aa']); 171 | */ 172 | 173 | /** 174 | * Plugins need to be loaded manually, you can either load them one by one or all of them in a single call 175 | * Uncomment one of the lines below, as you need. make sure you read the documentation on Plugin to use more 176 | * advanced ways of loading plugins 177 | * 178 | * Plugin::loadAll(); // Loads all plugins at once 179 | * Plugin::load('Migrations'); //Loads a single plugin named Migrations 180 | * 181 | */ 182 | 183 | Plugin::load('Migrations'); 184 | Plugin::load('Acl', ['bootstrap' => true]); 185 | 186 | // Only try to load DebugKit in development mode 187 | // Debug Kit should not be installed on a production system 188 | if (Configure::read('debug')) { 189 | Plugin::load('DebugKit', ['bootstrap' => true]); 190 | } 191 | 192 | /** 193 | * Connect middleware/dispatcher filters. 194 | */ 195 | DispatcherFactory::add('Asset'); 196 | DispatcherFactory::add('Routing'); 197 | DispatcherFactory::add('ControllerFactory'); 198 | 199 | /** 200 | * Enable default locale format parsing. 201 | * This is needed for matching the auto-localized string output of Time() class when parsing dates. 202 | */ 203 | Type::build('datetime')->useLocaleParser(); 204 | -------------------------------------------------------------------------------- /webroot/css/cake.css: -------------------------------------------------------------------------------- 1 | a.disabled { 2 | pointer-events: none; 3 | } 4 | 5 | a:hover { 6 | color: #15848F; 7 | } 8 | 9 | a { 10 | color: #1798A5; 11 | } 12 | 13 | .side-nav li a:not(.button) { 14 | color: #15848F; 15 | } 16 | 17 | .side-nav li a:not(.button):hover { 18 | color: #15848F; 19 | } 20 | 21 | header { 22 | background-color: #15848F; 23 | color: #ffffff; 24 | font-size: 30px; 25 | height: 84px; 26 | line-height: 64px; 27 | padding: 16px 0px; 28 | box-shadow: 0px 1px rgba(0, 0, 0, 0.24); 29 | } 30 | 31 | header .header-title { 32 | padding-left:80px 33 | } 34 | 35 | 36 | legend { 37 | color:#15848F; 38 | } 39 | 40 | .row { 41 | max-width: 80rem; 42 | } 43 | 44 | .actions.columns { 45 | margin-top:1rem; 46 | border-left: 5px solid #15848F; 47 | padding-left: 15px; 48 | padding: 32px 20px; 49 | } 50 | 51 | .actions.columns h3 { 52 | color:#15848F; 53 | } 54 | 55 | .index table { 56 | margin-top: 2rem; 57 | border: 0; 58 | } 59 | 60 | .index table thead { 61 | height: 3.5rem; 62 | } 63 | 64 | .header-help { 65 | float: right; 66 | margin-right:2rem; 67 | margin-top: -80px; 68 | font-size:16px; 69 | } 70 | 71 | .header-help span { 72 | font-weight: normal; 73 | text-align: center; 74 | text-decoration: none; 75 | line-height: 1; 76 | white-space: nowrap; 77 | display: inline-block; 78 | padding: 0.25rem 0.5rem 0.375rem; 79 | font-size: 0.8rem; 80 | background-color: #0097a7; 81 | color: #FFF; 82 | border-radius: 1000px; 83 | } 84 | 85 | .header-help a { 86 | color: #fff; 87 | } 88 | 89 | ul.pagination li a { 90 | color: rgba(0, 0 ,0 , 0.54); 91 | } 92 | 93 | ul.pagination li.active a { 94 | background: none repeat scroll 0% 0% #DCE47E; 95 | color: #FFF; 96 | font-weight: bold; 97 | cursor: default; 98 | } 99 | 100 | .paginator { 101 | text-align: center; 102 | } 103 | 104 | .paginator ul.pagination li { 105 | float: none; 106 | display: inline-block; 107 | } 108 | 109 | .paginator p { 110 | text-align: right; 111 | color: rgba(0, 0 ,0 , 0.54); 112 | } 113 | 114 | button { 115 | background: #8D6E65; 116 | } 117 | 118 | .form button:hover, .form button:focus { 119 | background: #7A6058; 120 | box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.26) !important; 121 | } 122 | 123 | .form button[type="submit"] { 124 | float: right; 125 | text-transform: uppercase; 126 | box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.26); 127 | } 128 | 129 | .form .error-message { 130 | display: block; 131 | padding: 0.375rem 0.5625rem 0.5625rem; 132 | margin-top: -1px; 133 | margin-bottom: 1rem; 134 | font-size: 0.75rem; 135 | font-weight: normal; 136 | font-style: italic; 137 | color: rgba(0, 0, 0, 0.54); 138 | } 139 | 140 | .required > label { 141 | font-weight: bold; 142 | } 143 | .required > label:after { 144 | content: ' *'; 145 | color: #C3232D; 146 | } 147 | 148 | select[multiple] { 149 | min-height:150px; 150 | background: none; 151 | } 152 | input[type=checkbox], 153 | input[type=radio] { 154 | margin-right: 0.5em; 155 | } 156 | 157 | .date select, 158 | .time select, 159 | .datetime select { 160 | display: inline; 161 | width: auto; 162 | margin-right: 10px; 163 | } 164 | 165 | .error label, 166 | .error label.error { 167 | color: #C3232D; 168 | } 169 | 170 | div.message { 171 | border-style: solid; 172 | border-width: 1px; 173 | display: block; 174 | font-weight: normal; 175 | position: relative; 176 | padding: 0.875rem 1.5rem 0.875rem 20%; 177 | transition: opacity 300ms ease-out 0s; 178 | background-color: #DCE47E; 179 | border-color: #DCE47E; 180 | color: #626262; 181 | } 182 | 183 | div.message.error { 184 | background-color: #C3232D; 185 | border-color: #C3232D; 186 | color: #FFF; 187 | } 188 | 189 | div.message:before { 190 | line-height: 0px; 191 | font-size: 20px; 192 | height: 12px; 193 | width: 12px; 194 | border-radius: 15px; 195 | text-align: center; 196 | vertical-align: middle; 197 | display: inline-block; 198 | position: relative; 199 | left: -11px; 200 | background-color: #FFF; 201 | padding: 12px 14px 12px 10px; 202 | content: "i"; 203 | color: #DCE47E; 204 | } 205 | 206 | div.message.error:before { 207 | padding: 11px 16px 14px 7px; 208 | color: #C3232D; 209 | content: "x"; 210 | } 211 | 212 | .view h2 { 213 | color: #6F6F6F; 214 | } 215 | 216 | .view .columns.strings { 217 | border-radius: 3px; 218 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 219 | margin-right:0.7rem; 220 | } 221 | 222 | .view .numbers { 223 | background-color: #B7E3EC; 224 | color: #FFF; 225 | border-radius: 3px; 226 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 227 | margin-right: 0.7rem; 228 | } 229 | 230 | .view .columns.dates { 231 | border-radius: 3px; 232 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 233 | margin-right:0.7rem; 234 | background-color:#DCE47E; 235 | color: #fff; 236 | } 237 | 238 | .view .columns.booleans { 239 | border-radius: 3px; 240 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 241 | margin-right:0.7rem; 242 | background-color: #8D6E65; 243 | color: #fff; 244 | } 245 | 246 | .view .strings p { 247 | border-bottom: 1px solid #eee; 248 | } 249 | .view .numbers .subheader, .view .dates .subheader { 250 | color:#747474; 251 | } 252 | .view .booleans .subheader { 253 | color: #E9E9E9 254 | } 255 | 256 | .view .texts .columns { 257 | margin-top:1.2rem; 258 | border-bottom: 1px solid #eee; 259 | } 260 | 261 | 262 | /** Notices and Errors **/ 263 | .cake-error, 264 | .cake-debug, 265 | .notice, 266 | p.error, 267 | p.notice { 268 | display: block; 269 | clear: both; 270 | background-repeat: repeat-x; 271 | margin-bottom: 18px; 272 | padding: 7px 14px; 273 | border-radius: 3px; 274 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 275 | } 276 | 277 | .cake-debug, 278 | .notice, 279 | p.notice { 280 | color: #000000; 281 | background: #ffcc00; 282 | } 283 | 284 | .cake-error, 285 | p.error { 286 | color: #fff; 287 | background: #C3232D; 288 | } 289 | 290 | pre { 291 | background: none repeat scroll 0% 0% #FFF; 292 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 293 | margin: 15px 0px; 294 | color: rgba(0, 0 ,0 , 0.74); 295 | padding:5px; 296 | } 297 | 298 | .cake-error .cake-stack-trace { 299 | margin-top:10px; 300 | } 301 | 302 | .cake-stack-trace code { 303 | background: inherit; 304 | border:0; 305 | } 306 | 307 | .cake-code-dump .code-highlight { 308 | display: block; 309 | background-color: #FFC600; 310 | } 311 | 312 | .cake-error a, 313 | .cake-error a:hover { 314 | color:#fff; 315 | text-decoration: underline; 316 | } 317 | 318 | .home header { 319 | width: 100%; 320 | height: 85%; 321 | position: relative; 322 | display: table; 323 | } 324 | 325 | .home h1 { 326 | font-family: "Gill Sans MT", Calibri, sans-serif; 327 | } 328 | 329 | .home header .header-image { 330 | display: table-cell; 331 | vertical-align: middle; 332 | text-align: center; 333 | } 334 | 335 | .home header h1 { 336 | color: #fff; 337 | } 338 | 339 | .home .checks { 340 | padding:30px; 341 | color: #626262; 342 | border-radius: 3px; 343 | box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); 344 | margin-top:50px; 345 | } 346 | 347 | .checks.platform { 348 | background-color: #B7E3EC; 349 | } 350 | 351 | .checks.filesystem { 352 | background: #DCE47E; 353 | } 354 | 355 | .checks.database { 356 | background-color: #DFF0D8; 357 | padding-bottom: 10px; 358 | margin-bottom: 30px; 359 | } 360 | 361 | .home .checks .success:before, .home .checks .problem:before { 362 | line-height: 0px; 363 | font-size: 28px; 364 | height: 12px; 365 | width: 12px; 366 | border-radius: 15px; 367 | text-align: center; 368 | vertical-align: middle; 369 | display: inline-block; 370 | position: relative; 371 | left: -11px; 372 | } 373 | 374 | .home .checks .success:before { 375 | content: "✓"; 376 | color: green; 377 | margin-right: 9px; 378 | } 379 | 380 | .home .checks .problem:before { 381 | content: "✘"; 382 | color: red; 383 | margin-right: 9px; 384 | } 385 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cakephp-3-acl-example 2 | A very simple CakePHP 3 ACL plugin usage example. This example is based on [Simple Acl controlled Application](http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html) for CakePHP 2. The differences are described in this document. The files in this repository contain the changes and implementations of functions discuessed below. 3 | 4 | ### Getting started 5 | - Assuming you are using [composer](https://getcomposer.org/), get a copy of the latest cakephp release by running `composer create-project --prefer-dist cakephp/app acl-example`. This will create an empty CakePHP project in the `acl-example` directory. Answer YES when asked if folder permissions should be set. 6 | - Navigate to the CakePHP project directory (`acl-example` in this case) `cd acl-example` 7 | - Install the [CakePHP ACL plugin](https://github.com/cakephp/acl) by running `composer require cakephp/acl` 8 | - Include the ACL plugin in `app/config/bootstrap.php` 9 | 10 | ```php 11 | Plugin::load('Acl', ['bootstrap' => true]); 12 | ``` 13 | 14 | ###Example schema 15 | An example schema taken from the CakePHP 2 ACL tutorial: 16 | ```sql 17 | CREATE TABLE users ( 18 | id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 19 | username VARCHAR(255) NOT NULL UNIQUE, 20 | password CHAR(60) NOT NULL, 21 | group_id INT(11) NOT NULL, 22 | created DATETIME, 23 | modified DATETIME 24 | ); 25 | 26 | CREATE TABLE groups ( 27 | id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 28 | name VARCHAR(100) NOT NULL, 29 | created DATETIME, 30 | modified DATETIME 31 | ); 32 | 33 | CREATE TABLE posts ( 34 | id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 35 | user_id INT(11) NOT NULL, 36 | title VARCHAR(255) NOT NULL, 37 | body TEXT, 38 | created DATETIME, 39 | modified DATETIME 40 | ); 41 | 42 | CREATE TABLE widgets ( 43 | id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 44 | name VARCHAR(100) NOT NULL, 45 | part_no VARCHAR(12), 46 | quantity INT(11) 47 | ); 48 | ``` 49 | After the schema is created, proceed to "bake" the application. 50 | 51 | ```bash 52 | bin/cake bake all groups 53 | bin/cake bake all users 54 | bin/cake bake all posts 55 | bin/cake bake all widgets 56 | ``` 57 | 58 | ### Preparing to Add Auth 59 | Add `UsersController::login` function 60 | ```php 61 | public function login() { 62 | if ($this->request->is('post')) { 63 | $user = $this->Auth->identify(); 64 | if ($user) { 65 | $this->Auth->setUser($user); 66 | return $this->redirect($this->Auth->redirectUrl()); 67 | } 68 | $this->Flash->error(__('Your username or password was incorrect.')); 69 | } 70 | } 71 | ``` 72 | Add `UsersController::logout` function 73 | ```php 74 | public function logout() { 75 | $this->Flash->success(__('Good-Bye')); 76 | $this->redirect($this->Auth->logout()); 77 | } 78 | ``` 79 | Add `src/Templates/Users/login.ctp` 80 | ```php 81 | Form->create() ?> 82 |
83 | 84 | Form->input('username') ?> 85 | Form->input('password') ?> 86 | Form->submit(__('Login')) ?> 87 |
88 | Form->end() ?> 89 | ``` 90 | Modify `UsersTable::beforeSave` to hash the password before saving 91 | ```php 92 | use Cake\Auth\DefaultPasswordHasher; 93 | ... 94 | public function beforeSave(\Cake\Event\Event $event, \Cake\ORM\Entity $entity, 95 | \ArrayObject $options) 96 | { 97 | $hasher = new DefaultPasswordHasher; 98 | $entity->password = $hasher->hash($entity->password); 99 | return true; 100 | } 101 | ``` 102 | Include and configure the `AuthComponent` and the `AclComponent` in the `AppController` 103 | ```php 104 | public $components = [ 105 | 'Acl' => [ 106 | 'className' => 'Acl.Acl' 107 | ] 108 | ]; 109 | ... 110 | $this->loadComponent('Auth', [ 111 | 'authorize' => [ 112 | 'Acl.Actions' => ['actionPath' => 'controllers/'] 113 | ], 114 | 'loginAction' => [ 115 | 'plugin' => false, 116 | 'controller' => 'Users', 117 | 'action' => 'login' 118 | ], 119 | 'loginRedirect' => [ 120 | 'plugin' => false, 121 | 'controller' => 'Posts', 122 | 'action' => 'index' 123 | ], 124 | 'logoutRedirect' => [ 125 | 'plugin' => false, 126 | 'controller' => 'Users', 127 | 'action' => 'login' 128 | ], 129 | 'unauthorizedRedirect' => [ 130 | 'controller' => 'Users', 131 | 'action' => 'login', 132 | 'prefix' => false 133 | ], 134 | 'authError' => 'You are not authorized to access that location.', 135 | 'flash' => [ 136 | 'element' => 'error' 137 | ] 138 | ]); 139 | ``` 140 | 141 | ### Add Temporary Auth Overrides 142 | Temporarily allow access to `UsersController` and `GroupsController` so groups and users can be added. Add the following implementation of `beforeFilter` to `src/Controllers/UsersController.php` and `src/Controllers/GroupsController.php`: 143 | ```php 144 | public function initialize() 145 | { 146 | parent::initialize(); 147 | 148 | $this->Auth->allow(); 149 | } 150 | ``` 151 | 152 | ### Initialize the Db Acl tables 153 | - Create the ACL related tables by running `bin/cake Migrations.migrations migrate -p Acl` 154 | 155 | ### Model Setup 156 | #### Acting as a requester 157 | - Add the requester behavior to `GroupsTable` and `UsersTable` 158 | - Add `$this->addBehavior('Acl.Acl', ['type' => 'requester']);` to the `initialize` function in the files `src/Model/Table/UsersTable.php` and `src/Model/Table/GroupsTable.php` 159 | 160 | 161 | #### Implement `parentNode` function in `Group` entity 162 | Add the following implementation of `parentNode` to the file `src/Model/Entity/Group.php`: 163 | ```php 164 | public function parentNode() 165 | { 166 | return null; 167 | } 168 | ``` 169 | 170 | #### Implement `parentNode` function in `User` entity 171 | Add the following implementation of `parentNode` to the file `src/Model/Entity/User.php`: 172 | ```php 173 | public function parentNode() 174 | { 175 | if (!$this->id) { 176 | return null; 177 | } 178 | if (isset($this->group_id)) { 179 | $groupId = $this->group_id; 180 | } else { 181 | $Users = TableRegistry::get('Users'); 182 | $user = $Users->find('all', ['fields' => ['group_id']])->where(['id' => $this->id])->first(); 183 | $groupId = $user->group_id; 184 | } 185 | if (!$groupId) { 186 | return null; 187 | } 188 | return ['Groups' => ['id' => $groupId]]; 189 | } 190 | ``` 191 | 192 | ### Creating ACOs 193 | The [ACL Extras](https://github.com/markstory/acl_extras/) plugin referred to in the CakePHP 2 ACL tutorial is now integrated into the [CakePHP ACL plugin](https://github.com/cakephp/acl) for CakePHP 3. 194 | - Run `bin/cake acl_extras aco_sync` to automatically create ACOs. 195 | - ACOs and AROs can be managed manually using the ACL shell. Run `bin/cake acl` for more information. 196 | 197 | ### Creating Users and Groups 198 | #### Create Groups 199 | - Navigate to `/groups/add` and add the groups 200 | - For this example, we will create `Administrator`, `Manager`, and `User` 201 | 202 | #### Create Users 203 | - Navigate to `/users/add` and add the users 204 | - For this example, we will create one user in each group 205 | - `test-administrator` is an `Administrator` 206 | - `test-manager` is a `Manager` 207 | - `test-user` is a `User` 208 | 209 | ### Remove Temporary Auth Overrides 210 | Remove the temporary auth overrides by removing the `beforeFilter` function or the call to `$this->Auth->allow();` in `src/Controllers/UsersController.php` and `src/Controllers/GroupsController.php`. 211 | 212 | ### Configuring Permissions 213 | #### Configuring permissions using the ACL shell 214 | First, find the IDs of each group you want to grant permissions on. There are several ways of doing this. Since we will be at the console anyway, the quickest way is probably to run `bin/cake acl view aro` to view the ARO tree. In this example, we will assume the `Administrator`, `Manager`, and `User` groups have IDs 1, 2, and 3 respectively. 215 | - Grant members of the `Administrator` group permission to everything 216 | - Run `bin/cake acl grant Groups.1 controllers` 217 | - Grant members of the `Manager` group permission to all actions in `Posts` and `Widgets` 218 | - Run `bin/cake acl deny Groups.2 controllers` 219 | - Run `bin/cake acl grant Groups.2 controllers/Posts` 220 | - Run `bin/cake acl grant Groups.2 controllers/Widgets` 221 | - Grant members of the `User` group permission to view `Posts` and `Widgets` 222 | - Run `bin/cake acl deny Groups.3 controllers` 223 | - Run `bin/cake acl grant Groups.3 controllers/Posts/index` 224 | - Run `bin/cake acl grant Groups.3 controllers/Posts/view` 225 | - Run `bin/cake acl grant Groups.3 controllers/Widgets/index` 226 | - Run `bin/cake acl grant Groups.3 controllers/Widgets/view` 227 | - Allow all groups to logout 228 | - Run `bin/cake acl grant Groups.2 controllers/Users/logout` 229 | - Run `bin/cake acl grant Groups.3 controllers/Users/logout` 230 | -------------------------------------------------------------------------------- /src/Template/Pages/home.ctp: -------------------------------------------------------------------------------- 1 | layout = false; 22 | 23 | if (!Configure::read('debug')): 24 | throw new NotFoundException(); 25 | endif; 26 | 27 | $cakeDescription = 'CakePHP: the rapid development php framework'; 28 | ?> 29 | 30 | 31 | 32 | Html->charset() ?> 33 | 34 | 35 | <?= $cakeDescription ?> 36 | 37 | Html->meta('icon') ?> 38 | Html->css('base.css') ?> 39 | Html->css('cake.css') ?> 40 | 41 | 42 |
43 |
44 | Html->image('http://cakephp.org/img/cake-logo.png') ?> 45 |

Get the Ovens Ready

46 |
47 |
48 |
49 | 50 | 55 | 56 |
57 |
58 | =')): ?> 59 |

Your version of PHP is 5.4.16 or higher.

60 | 61 |

Your version of PHP is too low. You need PHP 5.4.16 or higher to use CakePHP.

62 | 63 | 64 | 65 |

Your version of PHP has the mbstring extension loaded.

66 | 67 |

Your version of PHP does NOT have the mbstring extension loaded.

; 68 | 69 | 70 | 71 |

Your version of PHP has the openssl extension loaded.

72 | 73 |

Your version of PHP has the mcrypt extension loaded.

74 | 75 |

Your version of PHP does NOT have the openssl or mcrypt extension loaded.

76 | 77 | 78 | 79 |

Your version of PHP has the intl extension loaded.

80 | 81 |

Your version of PHP does NOT have the intl extension loaded.

82 | 83 |
84 |
85 | 86 |

Your tmp directory is writable.

87 | 88 |

Your tmp directory is NOT writable.

89 | 90 | 91 | 92 |

Your logs directory is writable.

93 | 94 |

Your logs directory is NOT writable.

95 | 96 | 97 | 98 | 99 |

The Engine is being used for core caching. To change the config edit config/app.php

100 | 101 |

Your cache is NOT working. Please check the settings in config/app.php

102 | 103 |
104 |
105 |
106 |
107 | connect(); 111 | } catch (Exception $connectionError) { 112 | $connected = false; 113 | $errorMsg = $connectionError->getMessage(); 114 | if (method_exists($connectionError, 'getAttributes')): 115 | $attributes = $connectionError->getAttributes(); 116 | if (isset($errorMsg['message'])): 117 | $errorMsg .= '
' . $attributes['message']; 118 | endif; 119 | endif; 120 | } 121 | ?> 122 | 123 |

CakePHP is able to connect to the database.

124 | 125 |

CakePHP is NOT able to connect to the database.

126 | 127 |
128 |
129 |
130 |
131 |

Editing this Page

132 |
    133 |
  • To change the content of this page, edit: src/Template/Pages/home.ctp.
  • 134 |
  • You can also add some CSS styles for your pages at: webroot/css/.
  • 135 |
136 |
137 |
138 |

Getting Started

139 | 144 |

145 |

146 |
147 | 148 |
149 |
150 |
151 |

More about Cake

152 |

153 | CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Front Controller and MVC. 154 |

155 |

156 | Our primary goal is to provide a structured framework that enables PHP users at all levels to rapidly develop robust web applications, without any loss to flexibility. 157 |

158 | 159 | 181 |
182 |
183 |
184 |
185 |
186 | 187 | 188 | -------------------------------------------------------------------------------- /config/app.default.php: -------------------------------------------------------------------------------- 1 | true, 13 | 14 | /** 15 | * Configure basic information about the application. 16 | * 17 | * - namespace - The namespace to find app classes under. 18 | * - encoding - The encoding used for HTML + database connections. 19 | * - base - The base directory the app resides in. If false this 20 | * will be auto detected. 21 | * - dir - Name of app directory. 22 | * - webroot - The webroot directory. 23 | * - wwwRoot - The file path to webroot. 24 | * - baseUrl - To configure CakePHP to *not* use mod_rewrite and to 25 | * use CakePHP pretty URLs, remove these .htaccess 26 | * files: 27 | * /.htaccess 28 | * /webroot/.htaccess 29 | * And uncomment the baseUrl key below. 30 | * - fullBaseUrl - A base URL to use for absolute links. 31 | * - imageBaseUrl - Web path to the public images directory under webroot. 32 | * - cssBaseUrl - Web path to the public css directory under webroot. 33 | * - jsBaseUrl - Web path to the public js directory under webroot. 34 | * - paths - Configure paths for non class based resources. Supports the 35 | * `plugins`, `templates`, `locales` subkeys, which allow the definition of 36 | * paths for plugins, view templates and locale files respectively. 37 | */ 38 | 'App' => [ 39 | 'namespace' => 'App', 40 | 'encoding' => 'UTF-8', 41 | 'base' => false, 42 | 'dir' => 'src', 43 | 'webroot' => 'webroot', 44 | 'wwwRoot' => WWW_ROOT, 45 | // 'baseUrl' => env('SCRIPT_NAME'), 46 | 'fullBaseUrl' => false, 47 | 'imageBaseUrl' => 'img/', 48 | 'cssBaseUrl' => 'css/', 49 | 'jsBaseUrl' => 'js/', 50 | 'paths' => [ 51 | 'plugins' => [ROOT . DS . 'plugins' . DS], 52 | 'templates' => [APP . 'Template' . DS], 53 | 'locales' => [APP . 'Locale' . DS], 54 | ], 55 | ], 56 | 57 | /** 58 | * Security and encryption configuration 59 | * 60 | * - salt - A random string used in security hashing methods. 61 | * The salt value is also used as the encryption key. 62 | * You should treat it as extremely sensitive data. 63 | */ 64 | 'Security' => [ 65 | 'salt' => '__SALT__', 66 | ], 67 | 68 | /** 69 | * Apply timestamps with the last modified time to static assets (js, css, images). 70 | * Will append a querystring parameter containing the time the file was modified. 71 | * This is useful for busting browser caches. 72 | * 73 | * Set to true to apply timestamps when debug is true. Set to 'force' to always 74 | * enable timestamping regardless of debug value. 75 | */ 76 | 'Asset' => [ 77 | // 'timestamp' => true, 78 | ], 79 | 80 | /** 81 | * Configure the cache adapters. 82 | */ 83 | 'Cache' => [ 84 | 'default' => [ 85 | 'className' => 'File', 86 | 'path' => CACHE, 87 | ], 88 | 89 | /** 90 | * Configure the cache used for general framework caching. Path information, 91 | * object listings, and translation cache files are stored with this 92 | * configuration. 93 | */ 94 | '_cake_core_' => [ 95 | 'className' => 'File', 96 | 'prefix' => 'myapp_cake_core_', 97 | 'path' => CACHE . 'persistent/', 98 | 'serialize' => true, 99 | 'duration' => '+2 minutes', 100 | ], 101 | 102 | /** 103 | * Configure the cache for model and datasource caches. This cache 104 | * configuration is used to store schema descriptions, and table listings 105 | * in connections. 106 | */ 107 | '_cake_model_' => [ 108 | 'className' => 'File', 109 | 'prefix' => 'myapp_cake_model_', 110 | 'path' => CACHE . 'models/', 111 | 'serialize' => true, 112 | 'duration' => '+2 minutes', 113 | ], 114 | ], 115 | 116 | /** 117 | * Configure the Error and Exception handlers used by your application. 118 | * 119 | * By default errors are displayed using Debugger, when debug is true and logged 120 | * by Cake\Log\Log when debug is false. 121 | * 122 | * In CLI environments exceptions will be printed to stderr with a backtrace. 123 | * In web environments an HTML page will be displayed for the exception. 124 | * With debug true, framework errors like Missing Controller will be displayed. 125 | * When debug is false, framework errors will be coerced into generic HTTP errors. 126 | * 127 | * Options: 128 | * 129 | * - `errorLevel` - int - The level of errors you are interested in capturing. 130 | * - `trace` - boolean - Whether or not backtraces should be included in 131 | * logged errors/exceptions. 132 | * - `log` - boolean - Whether or not you want exceptions logged. 133 | * - `exceptionRenderer` - string - The class responsible for rendering 134 | * uncaught exceptions. If you choose a custom class you should place 135 | * the file for that class in src/Error. This class needs to implement a 136 | * render method. 137 | * - `skipLog` - array - List of exceptions to skip for logging. Exceptions that 138 | * extend one of the listed exceptions will also be skipped for logging. 139 | * E.g.: 140 | * `'skipLog' => ['Cake\Network\Exception\NotFoundException', 'Cake\Network\Exception\UnauthorizedException']` 141 | */ 142 | 'Error' => [ 143 | 'errorLevel' => E_ALL & ~E_DEPRECATED, 144 | 'exceptionRenderer' => 'Cake\Error\ExceptionRenderer', 145 | 'skipLog' => [], 146 | 'log' => true, 147 | 'trace' => true, 148 | ], 149 | 150 | /** 151 | * Email configuration. 152 | * 153 | * By defining transports separately from delivery profiles you can easily 154 | * re-use transport configuration across multiple profiles. 155 | * 156 | * You can specify multiple configurations for production, development and 157 | * testing. 158 | * 159 | * Each transport needs a `className`. Valid options are as follows: 160 | * 161 | * Mail - Send using PHP mail function 162 | * Smtp - Send using SMTP 163 | * Debug - Do not send the email, just return the result 164 | * 165 | * You can add custom transports (or override existing transports) by adding the 166 | * appropriate file to src/Network/Email. Transports should be named 167 | * 'YourTransport.php', where 'Your' is the name of the transport. 168 | */ 169 | 'EmailTransport' => [ 170 | 'default' => [ 171 | 'className' => 'Mail', 172 | // The following keys are used in SMTP transports 173 | 'host' => 'localhost', 174 | 'port' => 25, 175 | 'timeout' => 30, 176 | 'username' => 'user', 177 | 'password' => 'secret', 178 | 'client' => null, 179 | 'tls' => null, 180 | ], 181 | ], 182 | 183 | /** 184 | * Email delivery profiles 185 | * 186 | * Delivery profiles allow you to predefine various properties about email 187 | * messages from your application and give the settings a name. This saves 188 | * duplication across your application and makes maintenance and development 189 | * easier. Each profile accepts a number of keys. See `Cake\Network\Email\Email` 190 | * for more information. 191 | */ 192 | 'Email' => [ 193 | 'default' => [ 194 | 'transport' => 'default', 195 | 'from' => 'you@localhost', 196 | //'charset' => 'utf-8', 197 | //'headerCharset' => 'utf-8', 198 | ], 199 | ], 200 | 201 | /** 202 | * Connection information used by the ORM to connect 203 | * to your application's datastores. 204 | * Drivers include Mysql Postgres Sqlite Sqlserver 205 | * See vendor\cakephp\cakephp\src\Database\Driver for complete list 206 | */ 207 | 'Datasources' => [ 208 | 'default' => [ 209 | 'className' => 'Cake\Database\Connection', 210 | 'driver' => 'Cake\Database\Driver\Mysql', 211 | 'persistent' => false, 212 | 'host' => 'localhost', 213 | /** 214 | * CakePHP will use the default DB port based on the driver selected 215 | * MySQL on MAMP uses port 8889, MAMP users will want to uncomment 216 | * the following line and set the port accordingly 217 | */ 218 | //'port' => 'nonstandard_port_number', 219 | 'username' => 'my_app', 220 | 'password' => 'secret', 221 | 'database' => 'my_app', 222 | 'encoding' => 'utf8', 223 | 'timezone' => 'UTC', 224 | 'cacheMetadata' => true, 225 | 226 | /** 227 | * Set identifier quoting to true if you are using reserved words or 228 | * special characters in your table or column names. Enabling this 229 | * setting will result in queries built using the Query Builder having 230 | * identifiers quoted when creating SQL. It should be noted that this 231 | * decreases performance because each query needs to be traversed and 232 | * manipulated before being executed. 233 | */ 234 | 'quoteIdentifiers' => false, 235 | 236 | /** 237 | * During development, if using MySQL < 5.6, uncommenting the 238 | * following line could boost the speed at which schema metadata is 239 | * fetched from the database. It can also be set directly with the 240 | * mysql configuration directive 'innodb_stats_on_metadata = 0' 241 | * which is the recommended value in production environments 242 | */ 243 | //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], 244 | ], 245 | 246 | /** 247 | * The test connection is used during the test suite. 248 | */ 249 | 'test' => [ 250 | 'className' => 'Cake\Database\Connection', 251 | 'driver' => 'Cake\Database\Driver\Mysql', 252 | 'persistent' => false, 253 | 'host' => 'localhost', 254 | //'port' => 'nonstandard_port_number', 255 | 'username' => 'my_app', 256 | 'password' => 'secret', 257 | 'database' => 'test_myapp', 258 | 'encoding' => 'utf8', 259 | 'timezone' => 'UTC', 260 | 'cacheMetadata' => true, 261 | 'quoteIdentifiers' => false, 262 | //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], 263 | ], 264 | ], 265 | 266 | /** 267 | * Configures logging options 268 | */ 269 | 'Log' => [ 270 | 'debug' => [ 271 | 'className' => 'Cake\Log\Engine\FileLog', 272 | 'path' => LOGS, 273 | 'file' => 'debug', 274 | 'levels' => ['notice', 'info', 'debug'], 275 | ], 276 | 'error' => [ 277 | 'className' => 'Cake\Log\Engine\FileLog', 278 | 'path' => LOGS, 279 | 'file' => 'error', 280 | 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], 281 | ], 282 | ], 283 | 284 | /** 285 | * Session configuration. 286 | * 287 | * Contains an array of settings to use for session configuration. The 288 | * `defaults` key is used to define a default preset to use for sessions, any 289 | * settings declared here will override the settings of the default config. 290 | * 291 | * ## Options 292 | * 293 | * - `cookie` - The name of the cookie to use. Defaults to 'CAKEPHP'. 294 | * - `cookiePath` - The url path for which session cookie is set. Maps to the 295 | * `session.cookie_path` php.ini config. Defaults to base path of app. 296 | * - `timeout` - The time in minutes the session should be valid for. 297 | * Pass 0 to disable checking timeout. 298 | * Please note that php.ini's session.gc_maxlifetime must be equal to or greater 299 | * than the largest Session['timeout'] in all served websites for it to have the 300 | * desired effect. 301 | * - `defaults` - The default configuration set to use as a basis for your session. 302 | * There are four built-in options: php, cake, cache, database. 303 | * - `handler` - Can be used to enable a custom session handler. Expects an 304 | * array with at least the `engine` key, being the name of the Session engine 305 | * class to use for managing the session. CakePHP bundles the `CacheSession` 306 | * and `DatabaseSession` engines. 307 | * - `ini` - An associative array of additional ini values to set. 308 | * 309 | * The built-in `defaults` options are: 310 | * 311 | * - 'php' - Uses settings defined in your php.ini. 312 | * - 'cake' - Saves session files in CakePHP's /tmp directory. 313 | * - 'database' - Uses CakePHP's database sessions. 314 | * - 'cache' - Use the Cache class to save sessions. 315 | * 316 | * To define a custom session handler, save it at src/Network/Session/.php. 317 | * Make sure the class implements PHP's `SessionHandlerInterface` and set 318 | * Session.handler to 319 | * 320 | * To use database sessions, load the SQL file located at config/Schema/sessions.sql 321 | */ 322 | 'Session' => [ 323 | 'defaults' => 'php', 324 | ], 325 | ]; 326 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "f3f3edc148d3456315dc6ef7b5ab3a76", 8 | "content-hash": "57453b94b1978121b769f119a370b9d3", 9 | "packages": [ 10 | { 11 | "name": "aura/installer-default", 12 | "version": "1.0.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/auraphp/installer-default.git", 16 | "reference": "52f8de3670cc1ef45a916f40f732937436d028c8" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/auraphp/installer-default/zipball/52f8de3670cc1ef45a916f40f732937436d028c8", 21 | "reference": "52f8de3670cc1ef45a916f40f732937436d028c8", 22 | "shasum": "" 23 | }, 24 | "type": "composer-installer", 25 | "extra": { 26 | "class": "Aura\\Composer\\DefaultInstaller" 27 | }, 28 | "autoload": { 29 | "psr-0": { 30 | "Aura\\Composer\\": "src/" 31 | } 32 | }, 33 | "notification-url": "https://packagist.org/downloads/", 34 | "license": [ 35 | "BSD-2-Clause" 36 | ], 37 | "authors": [ 38 | { 39 | "name": "Paul M. Jones", 40 | "email": "pmjones88@gmail.com", 41 | "homepage": "http://paul-m-jones.com" 42 | } 43 | ], 44 | "description": "Installs Aura packages using the Composer defaults.", 45 | "keywords": [ 46 | "aura", 47 | "installer" 48 | ], 49 | "time": "2012-11-26 21:35:57" 50 | }, 51 | { 52 | "name": "aura/intl", 53 | "version": "1.1.1", 54 | "source": { 55 | "type": "git", 56 | "url": "https://github.com/auraphp/Aura.Intl.git", 57 | "reference": "c5fe620167550ad6fa77dd3570fba2efc77a2a21" 58 | }, 59 | "dist": { 60 | "type": "zip", 61 | "url": "https://api.github.com/repos/auraphp/Aura.Intl/zipball/c5fe620167550ad6fa77dd3570fba2efc77a2a21", 62 | "reference": "c5fe620167550ad6fa77dd3570fba2efc77a2a21", 63 | "shasum": "" 64 | }, 65 | "require": { 66 | "aura/installer-default": "1.0.*", 67 | "php": ">=5.4.0" 68 | }, 69 | "type": "aura-package", 70 | "extra": { 71 | "aura": { 72 | "type": "library", 73 | "config": { 74 | "common": "Aura\\Intl\\_Config\\Common" 75 | } 76 | }, 77 | "branch-alias": { 78 | "dev-develop": "1.1.x-dev" 79 | } 80 | }, 81 | "autoload": { 82 | "psr-0": { 83 | "Aura\\Intl": "src/" 84 | }, 85 | "psr-4": { 86 | "Aura\\Intl\\_Config\\": "config/" 87 | } 88 | }, 89 | "notification-url": "https://packagist.org/downloads/", 90 | "license": [ 91 | "BSD-2-Clause" 92 | ], 93 | "authors": [ 94 | { 95 | "name": "Paul M. Jones", 96 | "email": "pmjones88@gmail.com", 97 | "homepage": "http://paul-m-jones.com" 98 | }, 99 | { 100 | "name": "Aura.Intl Contributors", 101 | "homepage": "https://github.com/auraphp/Aura.Intl/contributors" 102 | }, 103 | { 104 | "name": "Pascal Borreli", 105 | "email": "pascal@borreli.com" 106 | }, 107 | { 108 | "name": "Mapthegod", 109 | "email": "mapthegod@gmail.com" 110 | }, 111 | { 112 | "name": "Jose Lorenzo Rodriguez", 113 | "email": "jose.zap@gmail.com" 114 | } 115 | ], 116 | "description": "The Aura.Intl package provides internationalization (I18N) tools, specifically\npackage-oriented per-locale message translation.", 117 | "homepage": "http://auraphp.com/Aura.Intl", 118 | "keywords": [ 119 | "g11n", 120 | "globalization", 121 | "i18n", 122 | "internationalization", 123 | "intl", 124 | "l10n", 125 | "localization" 126 | ], 127 | "time": "2014-08-24 00:00:00" 128 | }, 129 | { 130 | "name": "cakephp/acl", 131 | "version": "dev-master", 132 | "source": { 133 | "type": "git", 134 | "url": "https://github.com/cakephp/acl.git", 135 | "reference": "9b9808e14cb07ac45b40cf957c7eec177813c567" 136 | }, 137 | "dist": { 138 | "type": "zip", 139 | "url": "https://api.github.com/repos/cakephp/acl/zipball/9b9808e14cb07ac45b40cf957c7eec177813c567", 140 | "reference": "9b9808e14cb07ac45b40cf957c7eec177813c567", 141 | "shasum": "" 142 | }, 143 | "require": { 144 | "cakephp/cakephp": "^3.1.0" 145 | }, 146 | "require-dev": { 147 | "cakephp/cakephp-codesniffer": "^2.0", 148 | "phpunit/phpunit": ">= 4.2" 149 | }, 150 | "type": "cakephp-plugin", 151 | "autoload": { 152 | "psr-4": { 153 | "Acl\\": "src" 154 | } 155 | }, 156 | "notification-url": "https://packagist.org/downloads/", 157 | "license": [ 158 | "MIT" 159 | ], 160 | "authors": [ 161 | { 162 | "name": "CakePHP Community", 163 | "homepage": "https://github.com/cakephp/acl/graphs/contributors" 164 | } 165 | ], 166 | "description": "Acl Plugin for CakePHP 3.x framework", 167 | "homepage": "http://cakephp.org", 168 | "keywords": [ 169 | "acl", 170 | "cakephp" 171 | ], 172 | "time": "2016-05-24 00:02:18" 173 | }, 174 | { 175 | "name": "cakephp/cakephp", 176 | "version": "3.2.11", 177 | "source": { 178 | "type": "git", 179 | "url": "https://github.com/cakephp/cakephp.git", 180 | "reference": "2c1463f4f80ec138f65a87a9c7d95d466a051e6f" 181 | }, 182 | "dist": { 183 | "type": "zip", 184 | "url": "https://api.github.com/repos/cakephp/cakephp/zipball/2c1463f4f80ec138f65a87a9c7d95d466a051e6f", 185 | "reference": "2c1463f4f80ec138f65a87a9c7d95d466a051e6f", 186 | "shasum": "" 187 | }, 188 | "require": { 189 | "aura/intl": "1.1.*", 190 | "cakephp/chronos": "*", 191 | "ext-intl": "*", 192 | "ext-mbstring": "*", 193 | "php": ">=5.5.9", 194 | "psr/log": "1.0" 195 | }, 196 | "replace": { 197 | "cakephp/cache": "self.version", 198 | "cakephp/collection": "self.version", 199 | "cakephp/core": "self.version", 200 | "cakephp/database": "self.version", 201 | "cakephp/datasource": "self.version", 202 | "cakephp/event": "self.version", 203 | "cakephp/filesystem": "self.version", 204 | "cakephp/i18n": "self.version", 205 | "cakephp/log": "self.version", 206 | "cakephp/orm": "self.version", 207 | "cakephp/utility": "self.version", 208 | "cakephp/validation": "self.version" 209 | }, 210 | "require-dev": { 211 | "cakephp/cakephp-codesniffer": "dev-master", 212 | "phpunit/phpunit": "*" 213 | }, 214 | "suggest": { 215 | "ext-openssl": "To use Security::encrypt() or have secure CSRF token generation." 216 | }, 217 | "type": "library", 218 | "autoload": { 219 | "psr-4": { 220 | "Cake\\": "src" 221 | }, 222 | "files": [ 223 | "src/Core/functions.php", 224 | "src/Collection/functions.php", 225 | "src/I18n/functions.php", 226 | "src/Utility/bootstrap.php" 227 | ] 228 | }, 229 | "notification-url": "https://packagist.org/downloads/", 230 | "license": [ 231 | "MIT" 232 | ], 233 | "authors": [ 234 | { 235 | "name": "CakePHP Community", 236 | "homepage": "https://github.com/cakephp/cakephp/graphs/contributors" 237 | } 238 | ], 239 | "description": "The CakePHP framework", 240 | "homepage": "http://cakephp.org", 241 | "keywords": [ 242 | "framework" 243 | ], 244 | "time": "2016-06-21 03:01:37" 245 | }, 246 | { 247 | "name": "cakephp/chronos", 248 | "version": "0.4.11", 249 | "source": { 250 | "type": "git", 251 | "url": "https://github.com/cakephp/chronos.git", 252 | "reference": "39db65d38488d6edd88bab5f33e19b1205ceeeda" 253 | }, 254 | "dist": { 255 | "type": "zip", 256 | "url": "https://api.github.com/repos/cakephp/chronos/zipball/39db65d38488d6edd88bab5f33e19b1205ceeeda", 257 | "reference": "39db65d38488d6edd88bab5f33e19b1205ceeeda", 258 | "shasum": "" 259 | }, 260 | "require": { 261 | "php": ">=5.5.9" 262 | }, 263 | "require-dev": { 264 | "athletic/athletic": "~0.1", 265 | "cakephp/cakephp-codesniffer": "dev-master", 266 | "phpunit/phpunit": "*" 267 | }, 268 | "type": "library", 269 | "autoload": { 270 | "psr-4": { 271 | "Cake\\Chronos\\": "src" 272 | }, 273 | "files": [ 274 | "src/carbon_compat.php" 275 | ] 276 | }, 277 | "notification-url": "https://packagist.org/downloads/", 278 | "license": [ 279 | "MIT" 280 | ], 281 | "authors": [ 282 | { 283 | "name": "Brian Nesbitt", 284 | "email": "brian@nesbot.com", 285 | "homepage": "http://nesbot.com" 286 | }, 287 | { 288 | "name": "The CakePHP Team", 289 | "homepage": "http://cakephp.org" 290 | } 291 | ], 292 | "description": "A simple API extension for DateTime.", 293 | "homepage": "http://cakephp.org", 294 | "keywords": [ 295 | "date", 296 | "datetime", 297 | "time" 298 | ], 299 | "time": "2016-06-15 06:26:37" 300 | }, 301 | { 302 | "name": "cakephp/migrations", 303 | "version": "1.6.3", 304 | "source": { 305 | "type": "git", 306 | "url": "https://github.com/cakephp/migrations.git", 307 | "reference": "b683daebb6d0f0ea41546b14f8a9ea591cebedfd" 308 | }, 309 | "dist": { 310 | "type": "zip", 311 | "url": "https://api.github.com/repos/cakephp/migrations/zipball/b683daebb6d0f0ea41546b14f8a9ea591cebedfd", 312 | "reference": "b683daebb6d0f0ea41546b14f8a9ea591cebedfd", 313 | "shasum": "" 314 | }, 315 | "require": { 316 | "cakephp/cakephp": "~3.1", 317 | "php": ">=5.4", 318 | "robmorgan/phinx": "0.5.3" 319 | }, 320 | "require-dev": { 321 | "cakephp/bake": "@stable", 322 | "phpunit/phpunit": "*" 323 | }, 324 | "suggest": { 325 | "cakephp/bake": "Required if you want to generate migrations." 326 | }, 327 | "type": "cakephp-plugin", 328 | "autoload": { 329 | "psr-4": { 330 | "Migrations\\": "src" 331 | } 332 | }, 333 | "notification-url": "https://packagist.org/downloads/", 334 | "license": [ 335 | "MIT" 336 | ], 337 | "authors": [ 338 | { 339 | "name": "CakePHP Community", 340 | "homepage": "https://github.com/cakephp/migrations/graphs/contributors" 341 | } 342 | ], 343 | "description": "Database Migration plugin for CakePHP 3.0 based on Phinx", 344 | "homepage": "https://github.com/cakephp/migrations", 345 | "keywords": [ 346 | "cakephp", 347 | "migrations" 348 | ], 349 | "time": "2016-06-23 17:18:29" 350 | }, 351 | { 352 | "name": "cakephp/plugin-installer", 353 | "version": "0.0.15", 354 | "source": { 355 | "type": "git", 356 | "url": "https://github.com/cakephp/plugin-installer.git", 357 | "reference": "8e84898b44df50e88b5109bb7d4d28de845e9bf8" 358 | }, 359 | "dist": { 360 | "type": "zip", 361 | "url": "https://api.github.com/repos/cakephp/plugin-installer/zipball/8e84898b44df50e88b5109bb7d4d28de845e9bf8", 362 | "reference": "8e84898b44df50e88b5109bb7d4d28de845e9bf8", 363 | "shasum": "" 364 | }, 365 | "require-dev": { 366 | "cakephp/cakephp-codesniffer": "dev-master", 367 | "composer/composer": "1.0.*@dev" 368 | }, 369 | "type": "composer-installer", 370 | "extra": { 371 | "class": "Cake\\Composer\\Installer\\PluginInstaller" 372 | }, 373 | "autoload": { 374 | "psr-4": { 375 | "Cake\\Composer\\": "src" 376 | } 377 | }, 378 | "notification-url": "https://packagist.org/downloads/", 379 | "license": [ 380 | "MIT" 381 | ], 382 | "authors": [ 383 | { 384 | "name": "CakePHP Community", 385 | "homepage": "http://cakephp.org" 386 | } 387 | ], 388 | "description": "A composer installer for CakePHP 3.0+ plugins.", 389 | "time": "2016-04-28 03:01:34" 390 | }, 391 | { 392 | "name": "mobiledetect/mobiledetectlib", 393 | "version": "2.8.22", 394 | "source": { 395 | "type": "git", 396 | "url": "https://github.com/serbanghita/Mobile-Detect.git", 397 | "reference": "53cddae0c272a478b24a4b5fb60d0f838caf70b6" 398 | }, 399 | "dist": { 400 | "type": "zip", 401 | "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/53cddae0c272a478b24a4b5fb60d0f838caf70b6", 402 | "reference": "53cddae0c272a478b24a4b5fb60d0f838caf70b6", 403 | "shasum": "" 404 | }, 405 | "require": { 406 | "php": ">=5.0.0" 407 | }, 408 | "require-dev": { 409 | "codeclimate/php-test-reporter": "dev-master", 410 | "johnkary/phpunit-speedtrap": "~1.0@dev", 411 | "phpunit/phpunit": "*" 412 | }, 413 | "type": "library", 414 | "autoload": { 415 | "classmap": [ 416 | "Mobile_Detect.php" 417 | ], 418 | "psr-0": { 419 | "Detection": "namespaced/" 420 | } 421 | }, 422 | "notification-url": "https://packagist.org/downloads/", 423 | "license": [ 424 | "MIT" 425 | ], 426 | "authors": [ 427 | { 428 | "name": "Serban Ghita", 429 | "email": "serbanghita@gmail.com", 430 | "homepage": "http://mobiledetect.net", 431 | "role": "Developer" 432 | } 433 | ], 434 | "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", 435 | "homepage": "https://github.com/serbanghita/Mobile-Detect", 436 | "keywords": [ 437 | "detect mobile devices", 438 | "mobile", 439 | "mobile detect", 440 | "mobile detector", 441 | "php mobile detect" 442 | ], 443 | "time": "2016-04-24 09:47:16" 444 | }, 445 | { 446 | "name": "psr/log", 447 | "version": "1.0.0", 448 | "source": { 449 | "type": "git", 450 | "url": "https://github.com/php-fig/log.git", 451 | "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" 452 | }, 453 | "dist": { 454 | "type": "zip", 455 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", 456 | "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", 457 | "shasum": "" 458 | }, 459 | "type": "library", 460 | "autoload": { 461 | "psr-0": { 462 | "Psr\\Log\\": "" 463 | } 464 | }, 465 | "notification-url": "https://packagist.org/downloads/", 466 | "license": [ 467 | "MIT" 468 | ], 469 | "authors": [ 470 | { 471 | "name": "PHP-FIG", 472 | "homepage": "http://www.php-fig.org/" 473 | } 474 | ], 475 | "description": "Common interface for logging libraries", 476 | "keywords": [ 477 | "log", 478 | "psr", 479 | "psr-3" 480 | ], 481 | "time": "2012-12-21 11:40:51" 482 | }, 483 | { 484 | "name": "robmorgan/phinx", 485 | "version": "v0.5.3", 486 | "source": { 487 | "type": "git", 488 | "url": "https://github.com/robmorgan/phinx.git", 489 | "reference": "4e7fee7792f4bf3dbf55ee29001850ba26c86a88" 490 | }, 491 | "dist": { 492 | "type": "zip", 493 | "url": "https://api.github.com/repos/robmorgan/phinx/zipball/4e7fee7792f4bf3dbf55ee29001850ba26c86a88", 494 | "reference": "4e7fee7792f4bf3dbf55ee29001850ba26c86a88", 495 | "shasum": "" 496 | }, 497 | "require": { 498 | "php": ">=5.4", 499 | "symfony/config": "~2.8|~3.0", 500 | "symfony/console": "~2.8|~3.0", 501 | "symfony/yaml": "~2.8|~3.0" 502 | }, 503 | "require-dev": { 504 | "phpunit/phpunit": "^3.7|^4.0|^5.0" 505 | }, 506 | "bin": [ 507 | "bin/phinx" 508 | ], 509 | "type": "library", 510 | "autoload": { 511 | "psr-4": { 512 | "Phinx\\": "src/Phinx" 513 | } 514 | }, 515 | "notification-url": "https://packagist.org/downloads/", 516 | "license": [ 517 | "MIT" 518 | ], 519 | "authors": [ 520 | { 521 | "name": "Rob Morgan", 522 | "email": "robbym@gmail.com", 523 | "homepage": "http://robmorgan.id.au", 524 | "role": "Lead Developer" 525 | }, 526 | { 527 | "name": "Woody Gilk", 528 | "email": "woody.gilk@gmail.com", 529 | "homepage": "http://shadowhand.me", 530 | "role": "Developer" 531 | } 532 | ], 533 | "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", 534 | "homepage": "https://phinx.org", 535 | "keywords": [ 536 | "database", 537 | "database migrations", 538 | "db", 539 | "migrations", 540 | "phinx" 541 | ], 542 | "time": "2016-03-07 14:09:22" 543 | }, 544 | { 545 | "name": "symfony/config", 546 | "version": "v3.1.2", 547 | "source": { 548 | "type": "git", 549 | "url": "https://github.com/symfony/config.git", 550 | "reference": "bcf5aebabc95b56e370e13d78565f74c7d8726dc" 551 | }, 552 | "dist": { 553 | "type": "zip", 554 | "url": "https://api.github.com/repos/symfony/config/zipball/bcf5aebabc95b56e370e13d78565f74c7d8726dc", 555 | "reference": "bcf5aebabc95b56e370e13d78565f74c7d8726dc", 556 | "shasum": "" 557 | }, 558 | "require": { 559 | "php": ">=5.5.9", 560 | "symfony/filesystem": "~2.8|~3.0" 561 | }, 562 | "suggest": { 563 | "symfony/yaml": "To use the yaml reference dumper" 564 | }, 565 | "type": "library", 566 | "extra": { 567 | "branch-alias": { 568 | "dev-master": "3.1-dev" 569 | } 570 | }, 571 | "autoload": { 572 | "psr-4": { 573 | "Symfony\\Component\\Config\\": "" 574 | }, 575 | "exclude-from-classmap": [ 576 | "/Tests/" 577 | ] 578 | }, 579 | "notification-url": "https://packagist.org/downloads/", 580 | "license": [ 581 | "MIT" 582 | ], 583 | "authors": [ 584 | { 585 | "name": "Fabien Potencier", 586 | "email": "fabien@symfony.com" 587 | }, 588 | { 589 | "name": "Symfony Community", 590 | "homepage": "https://symfony.com/contributors" 591 | } 592 | ], 593 | "description": "Symfony Config Component", 594 | "homepage": "https://symfony.com", 595 | "time": "2016-06-29 05:41:56" 596 | }, 597 | { 598 | "name": "symfony/console", 599 | "version": "v3.1.2", 600 | "source": { 601 | "type": "git", 602 | "url": "https://github.com/symfony/console.git", 603 | "reference": "747154aa69b0f83cd02fc9aa554836dee417631a" 604 | }, 605 | "dist": { 606 | "type": "zip", 607 | "url": "https://api.github.com/repos/symfony/console/zipball/747154aa69b0f83cd02fc9aa554836dee417631a", 608 | "reference": "747154aa69b0f83cd02fc9aa554836dee417631a", 609 | "shasum": "" 610 | }, 611 | "require": { 612 | "php": ">=5.5.9", 613 | "symfony/polyfill-mbstring": "~1.0" 614 | }, 615 | "require-dev": { 616 | "psr/log": "~1.0", 617 | "symfony/event-dispatcher": "~2.8|~3.0", 618 | "symfony/process": "~2.8|~3.0" 619 | }, 620 | "suggest": { 621 | "psr/log": "For using the console logger", 622 | "symfony/event-dispatcher": "", 623 | "symfony/process": "" 624 | }, 625 | "type": "library", 626 | "extra": { 627 | "branch-alias": { 628 | "dev-master": "3.1-dev" 629 | } 630 | }, 631 | "autoload": { 632 | "psr-4": { 633 | "Symfony\\Component\\Console\\": "" 634 | }, 635 | "exclude-from-classmap": [ 636 | "/Tests/" 637 | ] 638 | }, 639 | "notification-url": "https://packagist.org/downloads/", 640 | "license": [ 641 | "MIT" 642 | ], 643 | "authors": [ 644 | { 645 | "name": "Fabien Potencier", 646 | "email": "fabien@symfony.com" 647 | }, 648 | { 649 | "name": "Symfony Community", 650 | "homepage": "https://symfony.com/contributors" 651 | } 652 | ], 653 | "description": "Symfony Console Component", 654 | "homepage": "https://symfony.com", 655 | "time": "2016-06-29 07:02:31" 656 | }, 657 | { 658 | "name": "symfony/filesystem", 659 | "version": "v3.1.2", 660 | "source": { 661 | "type": "git", 662 | "url": "https://github.com/symfony/filesystem.git", 663 | "reference": "322da5f0910d8aa0b25fa65ffccaba68dbddb890" 664 | }, 665 | "dist": { 666 | "type": "zip", 667 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/322da5f0910d8aa0b25fa65ffccaba68dbddb890", 668 | "reference": "322da5f0910d8aa0b25fa65ffccaba68dbddb890", 669 | "shasum": "" 670 | }, 671 | "require": { 672 | "php": ">=5.5.9" 673 | }, 674 | "type": "library", 675 | "extra": { 676 | "branch-alias": { 677 | "dev-master": "3.1-dev" 678 | } 679 | }, 680 | "autoload": { 681 | "psr-4": { 682 | "Symfony\\Component\\Filesystem\\": "" 683 | }, 684 | "exclude-from-classmap": [ 685 | "/Tests/" 686 | ] 687 | }, 688 | "notification-url": "https://packagist.org/downloads/", 689 | "license": [ 690 | "MIT" 691 | ], 692 | "authors": [ 693 | { 694 | "name": "Fabien Potencier", 695 | "email": "fabien@symfony.com" 696 | }, 697 | { 698 | "name": "Symfony Community", 699 | "homepage": "https://symfony.com/contributors" 700 | } 701 | ], 702 | "description": "Symfony Filesystem Component", 703 | "homepage": "https://symfony.com", 704 | "time": "2016-06-29 05:41:56" 705 | }, 706 | { 707 | "name": "symfony/polyfill-mbstring", 708 | "version": "v1.2.0", 709 | "source": { 710 | "type": "git", 711 | "url": "https://github.com/symfony/polyfill-mbstring.git", 712 | "reference": "dff51f72b0706335131b00a7f49606168c582594" 713 | }, 714 | "dist": { 715 | "type": "zip", 716 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", 717 | "reference": "dff51f72b0706335131b00a7f49606168c582594", 718 | "shasum": "" 719 | }, 720 | "require": { 721 | "php": ">=5.3.3" 722 | }, 723 | "suggest": { 724 | "ext-mbstring": "For best performance" 725 | }, 726 | "type": "library", 727 | "extra": { 728 | "branch-alias": { 729 | "dev-master": "1.2-dev" 730 | } 731 | }, 732 | "autoload": { 733 | "psr-4": { 734 | "Symfony\\Polyfill\\Mbstring\\": "" 735 | }, 736 | "files": [ 737 | "bootstrap.php" 738 | ] 739 | }, 740 | "notification-url": "https://packagist.org/downloads/", 741 | "license": [ 742 | "MIT" 743 | ], 744 | "authors": [ 745 | { 746 | "name": "Nicolas Grekas", 747 | "email": "p@tchwork.com" 748 | }, 749 | { 750 | "name": "Symfony Community", 751 | "homepage": "https://symfony.com/contributors" 752 | } 753 | ], 754 | "description": "Symfony polyfill for the Mbstring extension", 755 | "homepage": "https://symfony.com", 756 | "keywords": [ 757 | "compatibility", 758 | "mbstring", 759 | "polyfill", 760 | "portable", 761 | "shim" 762 | ], 763 | "time": "2016-05-18 14:26:46" 764 | }, 765 | { 766 | "name": "symfony/yaml", 767 | "version": "v3.1.2", 768 | "source": { 769 | "type": "git", 770 | "url": "https://github.com/symfony/yaml.git", 771 | "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de" 772 | }, 773 | "dist": { 774 | "type": "zip", 775 | "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de", 776 | "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de", 777 | "shasum": "" 778 | }, 779 | "require": { 780 | "php": ">=5.5.9" 781 | }, 782 | "type": "library", 783 | "extra": { 784 | "branch-alias": { 785 | "dev-master": "3.1-dev" 786 | } 787 | }, 788 | "autoload": { 789 | "psr-4": { 790 | "Symfony\\Component\\Yaml\\": "" 791 | }, 792 | "exclude-from-classmap": [ 793 | "/Tests/" 794 | ] 795 | }, 796 | "notification-url": "https://packagist.org/downloads/", 797 | "license": [ 798 | "MIT" 799 | ], 800 | "authors": [ 801 | { 802 | "name": "Fabien Potencier", 803 | "email": "fabien@symfony.com" 804 | }, 805 | { 806 | "name": "Symfony Community", 807 | "homepage": "https://symfony.com/contributors" 808 | } 809 | ], 810 | "description": "Symfony Yaml Component", 811 | "homepage": "https://symfony.com", 812 | "time": "2016-06-29 05:41:56" 813 | } 814 | ], 815 | "packages-dev": [ 816 | { 817 | "name": "cakephp/bake", 818 | "version": "1.2.5", 819 | "source": { 820 | "type": "git", 821 | "url": "https://github.com/cakephp/bake.git", 822 | "reference": "876e074d2a936b0a2c825db06d81f3ea1d4b2af3" 823 | }, 824 | "dist": { 825 | "type": "zip", 826 | "url": "https://api.github.com/repos/cakephp/bake/zipball/876e074d2a936b0a2c825db06d81f3ea1d4b2af3", 827 | "reference": "876e074d2a936b0a2c825db06d81f3ea1d4b2af3", 828 | "shasum": "" 829 | }, 830 | "require": { 831 | "cakephp/cakephp": ">=3.2.0", 832 | "php": ">=5.5.9" 833 | }, 834 | "require-dev": { 835 | "cakephp/cakephp-codesniffer": "dev-master", 836 | "phpunit/phpunit": "*" 837 | }, 838 | "type": "cakephp-plugin", 839 | "autoload": { 840 | "psr-4": { 841 | "Bake\\": "src" 842 | } 843 | }, 844 | "notification-url": "https://packagist.org/downloads/", 845 | "license": [ 846 | "MIT" 847 | ], 848 | "authors": [ 849 | { 850 | "name": "CakePHP Community", 851 | "homepage": "https://github.com/cakephp/bake/graphs/contributors" 852 | } 853 | ], 854 | "description": "Bake plugin for CakePHP 3.0", 855 | "homepage": "https://github.com/cakephp/bake", 856 | "keywords": [ 857 | "bake", 858 | "cakephp" 859 | ], 860 | "time": "2016-06-28 01:58:30" 861 | }, 862 | { 863 | "name": "cakephp/debug_kit", 864 | "version": "3.2.9", 865 | "source": { 866 | "type": "git", 867 | "url": "https://github.com/cakephp/debug_kit.git", 868 | "reference": "5c351136576b05a386eb2bbb02267529123edf7b" 869 | }, 870 | "dist": { 871 | "type": "zip", 872 | "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/5c351136576b05a386eb2bbb02267529123edf7b", 873 | "reference": "5c351136576b05a386eb2bbb02267529123edf7b", 874 | "shasum": "" 875 | }, 876 | "require": { 877 | "cakephp/cakephp": ">=3.1.0 <4.0", 878 | "jdorn/sql-formatter": "~1.2" 879 | }, 880 | "require-dev": { 881 | "cakephp/cakephp-codesniffer": "dev-master", 882 | "phpunit/phpunit": "4.1.*" 883 | }, 884 | "suggest": { 885 | "ext-sqlite": "DebugKit needs to store panel data in a database. SQLite is simple and easy to use." 886 | }, 887 | "type": "cakephp-plugin", 888 | "autoload": { 889 | "psr-4": { 890 | "DebugKit\\": "src", 891 | "DebugKit\\Test\\Fixture\\": "tests\\Fixture" 892 | } 893 | }, 894 | "notification-url": "https://packagist.org/downloads/", 895 | "license": [ 896 | "MIT" 897 | ], 898 | "authors": [ 899 | { 900 | "name": "Mark Story", 901 | "homepage": "http://mark-story.com", 902 | "role": "Author" 903 | }, 904 | { 905 | "name": "CakePHP Community", 906 | "homepage": "https://github.com/cakephp/debug_kit/graphs/contributors" 907 | } 908 | ], 909 | "description": "CakePHP Debug Kit", 910 | "homepage": "https://github.com/cakephp/debug_kit", 911 | "keywords": [ 912 | "cakephp", 913 | "debug", 914 | "kit" 915 | ], 916 | "time": "2016-05-28 15:47:46" 917 | }, 918 | { 919 | "name": "dnoegel/php-xdg-base-dir", 920 | "version": "0.1", 921 | "source": { 922 | "type": "git", 923 | "url": "https://github.com/dnoegel/php-xdg-base-dir.git", 924 | "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" 925 | }, 926 | "dist": { 927 | "type": "zip", 928 | "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", 929 | "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", 930 | "shasum": "" 931 | }, 932 | "require": { 933 | "php": ">=5.3.2" 934 | }, 935 | "require-dev": { 936 | "phpunit/phpunit": "@stable" 937 | }, 938 | "type": "project", 939 | "autoload": { 940 | "psr-4": { 941 | "XdgBaseDir\\": "src/" 942 | } 943 | }, 944 | "notification-url": "https://packagist.org/downloads/", 945 | "license": [ 946 | "MIT" 947 | ], 948 | "description": "implementation of xdg base directory specification for php", 949 | "time": "2014-10-24 07:27:01" 950 | }, 951 | { 952 | "name": "jakub-onderka/php-console-color", 953 | "version": "0.1", 954 | "source": { 955 | "type": "git", 956 | "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", 957 | "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" 958 | }, 959 | "dist": { 960 | "type": "zip", 961 | "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", 962 | "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", 963 | "shasum": "" 964 | }, 965 | "require": { 966 | "php": ">=5.3.2" 967 | }, 968 | "require-dev": { 969 | "jakub-onderka/php-code-style": "1.0", 970 | "jakub-onderka/php-parallel-lint": "0.*", 971 | "jakub-onderka/php-var-dump-check": "0.*", 972 | "phpunit/phpunit": "3.7.*", 973 | "squizlabs/php_codesniffer": "1.*" 974 | }, 975 | "type": "library", 976 | "autoload": { 977 | "psr-0": { 978 | "JakubOnderka\\PhpConsoleColor": "src/" 979 | } 980 | }, 981 | "notification-url": "https://packagist.org/downloads/", 982 | "license": [ 983 | "BSD-2-Clause" 984 | ], 985 | "authors": [ 986 | { 987 | "name": "Jakub Onderka", 988 | "email": "jakub.onderka@gmail.com", 989 | "homepage": "http://www.acci.cz" 990 | } 991 | ], 992 | "time": "2014-04-08 15:00:19" 993 | }, 994 | { 995 | "name": "jakub-onderka/php-console-highlighter", 996 | "version": "v0.3.2", 997 | "source": { 998 | "type": "git", 999 | "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", 1000 | "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" 1001 | }, 1002 | "dist": { 1003 | "type": "zip", 1004 | "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", 1005 | "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", 1006 | "shasum": "" 1007 | }, 1008 | "require": { 1009 | "jakub-onderka/php-console-color": "~0.1", 1010 | "php": ">=5.3.0" 1011 | }, 1012 | "require-dev": { 1013 | "jakub-onderka/php-code-style": "~1.0", 1014 | "jakub-onderka/php-parallel-lint": "~0.5", 1015 | "jakub-onderka/php-var-dump-check": "~0.1", 1016 | "phpunit/phpunit": "~4.0", 1017 | "squizlabs/php_codesniffer": "~1.5" 1018 | }, 1019 | "type": "library", 1020 | "autoload": { 1021 | "psr-0": { 1022 | "JakubOnderka\\PhpConsoleHighlighter": "src/" 1023 | } 1024 | }, 1025 | "notification-url": "https://packagist.org/downloads/", 1026 | "license": [ 1027 | "MIT" 1028 | ], 1029 | "authors": [ 1030 | { 1031 | "name": "Jakub Onderka", 1032 | "email": "acci@acci.cz", 1033 | "homepage": "http://www.acci.cz/" 1034 | } 1035 | ], 1036 | "time": "2015-04-20 18:58:01" 1037 | }, 1038 | { 1039 | "name": "jdorn/sql-formatter", 1040 | "version": "v1.2.17", 1041 | "source": { 1042 | "type": "git", 1043 | "url": "https://github.com/jdorn/sql-formatter.git", 1044 | "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc" 1045 | }, 1046 | "dist": { 1047 | "type": "zip", 1048 | "url": "https://api.github.com/repos/jdorn/sql-formatter/zipball/64990d96e0959dff8e059dfcdc1af130728d92bc", 1049 | "reference": "64990d96e0959dff8e059dfcdc1af130728d92bc", 1050 | "shasum": "" 1051 | }, 1052 | "require": { 1053 | "php": ">=5.2.4" 1054 | }, 1055 | "require-dev": { 1056 | "phpunit/phpunit": "3.7.*" 1057 | }, 1058 | "type": "library", 1059 | "extra": { 1060 | "branch-alias": { 1061 | "dev-master": "1.3.x-dev" 1062 | } 1063 | }, 1064 | "autoload": { 1065 | "classmap": [ 1066 | "lib" 1067 | ] 1068 | }, 1069 | "notification-url": "https://packagist.org/downloads/", 1070 | "license": [ 1071 | "MIT" 1072 | ], 1073 | "authors": [ 1074 | { 1075 | "name": "Jeremy Dorn", 1076 | "email": "jeremy@jeremydorn.com", 1077 | "homepage": "http://jeremydorn.com/" 1078 | } 1079 | ], 1080 | "description": "a PHP SQL highlighting library", 1081 | "homepage": "https://github.com/jdorn/sql-formatter/", 1082 | "keywords": [ 1083 | "highlight", 1084 | "sql" 1085 | ], 1086 | "time": "2014-01-12 16:20:24" 1087 | }, 1088 | { 1089 | "name": "nikic/php-parser", 1090 | "version": "v2.1.0", 1091 | "source": { 1092 | "type": "git", 1093 | "url": "https://github.com/nikic/PHP-Parser.git", 1094 | "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3" 1095 | }, 1096 | "dist": { 1097 | "type": "zip", 1098 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/47b254ea51f1d6d5dc04b9b299e88346bf2369e3", 1099 | "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3", 1100 | "shasum": "" 1101 | }, 1102 | "require": { 1103 | "ext-tokenizer": "*", 1104 | "php": ">=5.4" 1105 | }, 1106 | "require-dev": { 1107 | "phpunit/phpunit": "~4.0" 1108 | }, 1109 | "bin": [ 1110 | "bin/php-parse" 1111 | ], 1112 | "type": "library", 1113 | "extra": { 1114 | "branch-alias": { 1115 | "dev-master": "2.1-dev" 1116 | } 1117 | }, 1118 | "autoload": { 1119 | "psr-4": { 1120 | "PhpParser\\": "lib/PhpParser" 1121 | } 1122 | }, 1123 | "notification-url": "https://packagist.org/downloads/", 1124 | "license": [ 1125 | "BSD-3-Clause" 1126 | ], 1127 | "authors": [ 1128 | { 1129 | "name": "Nikita Popov" 1130 | } 1131 | ], 1132 | "description": "A PHP parser written in PHP", 1133 | "keywords": [ 1134 | "parser", 1135 | "php" 1136 | ], 1137 | "time": "2016-04-19 13:41:41" 1138 | }, 1139 | { 1140 | "name": "psy/psysh", 1141 | "version": "v0.7.2", 1142 | "source": { 1143 | "type": "git", 1144 | "url": "https://github.com/bobthecow/psysh.git", 1145 | "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280" 1146 | }, 1147 | "dist": { 1148 | "type": "zip", 1149 | "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280", 1150 | "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280", 1151 | "shasum": "" 1152 | }, 1153 | "require": { 1154 | "dnoegel/php-xdg-base-dir": "0.1", 1155 | "jakub-onderka/php-console-highlighter": "0.3.*", 1156 | "nikic/php-parser": "^1.2.1|~2.0", 1157 | "php": ">=5.3.9", 1158 | "symfony/console": "~2.3.10|^2.4.2|~3.0", 1159 | "symfony/var-dumper": "~2.7|~3.0" 1160 | }, 1161 | "require-dev": { 1162 | "fabpot/php-cs-fixer": "~1.5", 1163 | "phpunit/phpunit": "~3.7|~4.0|~5.0", 1164 | "squizlabs/php_codesniffer": "~2.0", 1165 | "symfony/finder": "~2.1|~3.0" 1166 | }, 1167 | "suggest": { 1168 | "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", 1169 | "ext-pdo-sqlite": "The doc command requires SQLite to work.", 1170 | "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", 1171 | "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." 1172 | }, 1173 | "bin": [ 1174 | "bin/psysh" 1175 | ], 1176 | "type": "library", 1177 | "extra": { 1178 | "branch-alias": { 1179 | "dev-develop": "0.8.x-dev" 1180 | } 1181 | }, 1182 | "autoload": { 1183 | "files": [ 1184 | "src/Psy/functions.php" 1185 | ], 1186 | "psr-4": { 1187 | "Psy\\": "src/Psy/" 1188 | } 1189 | }, 1190 | "notification-url": "https://packagist.org/downloads/", 1191 | "license": [ 1192 | "MIT" 1193 | ], 1194 | "authors": [ 1195 | { 1196 | "name": "Justin Hileman", 1197 | "email": "justin@justinhileman.info", 1198 | "homepage": "http://justinhileman.com" 1199 | } 1200 | ], 1201 | "description": "An interactive shell for modern PHP.", 1202 | "homepage": "http://psysh.org", 1203 | "keywords": [ 1204 | "REPL", 1205 | "console", 1206 | "interactive", 1207 | "shell" 1208 | ], 1209 | "time": "2016-03-09 05:03:14" 1210 | }, 1211 | { 1212 | "name": "symfony/var-dumper", 1213 | "version": "v3.1.2", 1214 | "source": { 1215 | "type": "git", 1216 | "url": "https://github.com/symfony/var-dumper.git", 1217 | "reference": "39492b8b8fe514163e677bf154fd80f6cc995759" 1218 | }, 1219 | "dist": { 1220 | "type": "zip", 1221 | "url": "https://api.github.com/repos/symfony/var-dumper/zipball/39492b8b8fe514163e677bf154fd80f6cc995759", 1222 | "reference": "39492b8b8fe514163e677bf154fd80f6cc995759", 1223 | "shasum": "" 1224 | }, 1225 | "require": { 1226 | "php": ">=5.5.9", 1227 | "symfony/polyfill-mbstring": "~1.0" 1228 | }, 1229 | "require-dev": { 1230 | "twig/twig": "~1.20|~2.0" 1231 | }, 1232 | "suggest": { 1233 | "ext-symfony_debug": "" 1234 | }, 1235 | "type": "library", 1236 | "extra": { 1237 | "branch-alias": { 1238 | "dev-master": "3.1-dev" 1239 | } 1240 | }, 1241 | "autoload": { 1242 | "files": [ 1243 | "Resources/functions/dump.php" 1244 | ], 1245 | "psr-4": { 1246 | "Symfony\\Component\\VarDumper\\": "" 1247 | }, 1248 | "exclude-from-classmap": [ 1249 | "/Tests/" 1250 | ] 1251 | }, 1252 | "notification-url": "https://packagist.org/downloads/", 1253 | "license": [ 1254 | "MIT" 1255 | ], 1256 | "authors": [ 1257 | { 1258 | "name": "Nicolas Grekas", 1259 | "email": "p@tchwork.com" 1260 | }, 1261 | { 1262 | "name": "Symfony Community", 1263 | "homepage": "https://symfony.com/contributors" 1264 | } 1265 | ], 1266 | "description": "Symfony mechanism for exploring and dumping PHP variables", 1267 | "homepage": "https://symfony.com", 1268 | "keywords": [ 1269 | "debug", 1270 | "dump" 1271 | ], 1272 | "time": "2016-06-29 05:41:56" 1273 | } 1274 | ], 1275 | "aliases": [], 1276 | "minimum-stability": "dev", 1277 | "stability-flags": { 1278 | "cakephp/acl": 20, 1279 | "psy/psysh": 0 1280 | }, 1281 | "prefer-stable": true, 1282 | "prefer-lowest": false, 1283 | "platform": { 1284 | "php": ">=5.4.16" 1285 | }, 1286 | "platform-dev": [] 1287 | } 1288 | --------------------------------------------------------------------------------