From 88f9dca7e9079da4e321ef3652a848750ba22526 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 01:07:41 +0530 Subject: [PATCH 01/44] Add support for writing bake templates using Twig syntax. --- .editorconfig | 3 + composer.json | 6 +- src/Shell/Task/BakeTemplateTask.php | 8 +- src/Template/Bake/Layout/default.twig | 16 +++ src/Template/Bake/tests/fixture.twig | 69 ++++++++++ src/Utility/CommonOptionsTrait.php | 5 + src/View/BakeTwigView.php | 128 ++++++++++++++++++ .../Shell/Task/BakeTemplateTaskTest.php | 3 + tests/bootstrap.php | 9 +- tests/test_app/App/Template/Bake/example.twig | 2 + .../src/Template/Bake/config/routes.twig | 9 ++ 11 files changed, 252 insertions(+), 6 deletions(-) create mode 100644 src/Template/Bake/Layout/default.twig create mode 100644 src/Template/Bake/tests/fixture.twig create mode 100644 src/View/BakeTwigView.php create mode 100644 tests/test_app/App/Template/Bake/example.twig create mode 100644 tests/test_app/Plugin/TestBakeTheme/src/Template/Bake/config/routes.twig diff --git a/.editorconfig b/.editorconfig index 8eb4b0795..f84f04779 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,3 +14,6 @@ trim_trailing_whitespace = true [*.yml] indent_style = space indent_size = 2 + +[*.twig] +insert_final_newline = false diff --git a/composer.json b/composer.json index 13104d9af..439519e1c 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ }, "require-dev": { "cakephp/cakephp-codesniffer": "^3.0", - "phpunit/phpunit": "~5.7 | ~6.0" + "phpunit/phpunit": "~5.7 | ~6.0", + "wyrihaximus/twig-view": "4.x-dev as 4.1" }, "autoload": { "psr-4": { @@ -39,6 +40,5 @@ "Bake\\Test\\App\\": "tests/test_app/App", "Cake\\Test\\": "./vendor/cakephp/cakephp/tests" } - }, - "minimum-stability": "beta" + } } diff --git a/src/Shell/Task/BakeTemplateTask.php b/src/Shell/Task/BakeTemplateTask.php index 6a6a53e74..3843e2c8e 100644 --- a/src/Shell/Task/BakeTemplateTask.php +++ b/src/Shell/Task/BakeTemplateTask.php @@ -14,8 +14,8 @@ */ namespace Bake\Shell\Task; -use Bake\View\BakeView; use Cake\Console\Shell; +use Cake\Core\App; use Cake\Core\ConventionsTrait; use Cake\Event\Event; use Cake\Event\EventManager; @@ -61,7 +61,11 @@ public function getView() ], 'theme' => $theme ]; - $view = new BakeView(new Request(), new Response(), null, $viewOptions); + + $viewClass = isset($this->params['view-class']) ? $this->params['view-class'] : 'Bake.Bake'; + $viewClass = App::className($viewClass, 'View', 'View'); + + $view = new $viewClass(new Request(), new Response(), null, $viewOptions); $event = new Event('Bake.initialize', $view); EventManager::instance()->dispatch($event); $this->View = $event->subject; diff --git a/src/Template/Bake/Layout/default.twig b/src/Template/Bake/Layout/default.twig new file mode 100644 index 000000000..5ffcffb57 --- /dev/null +++ b/src/Template/Bake/Layout/default.twig @@ -0,0 +1,16 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{{ _view.fetch('content')|raw }} \ No newline at end of file diff --git a/src/Template/Bake/tests/fixture.twig b/src/Template/Bake/tests/fixture.twig new file mode 100644 index 000000000..3e72753e3 --- /dev/null +++ b/src/Template/Bake/tests/fixture.twig @@ -0,0 +1,69 @@ +{# +/** + * Fixture Template file + * + * Fixture Template used when baking fixtures with bake + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + 'The theme to use when baking code.', 'default' => Configure::read('Bake.theme'), 'choices' => $bakeThemes + ])->addOption('view-class', [ + 'short' => 'v', + 'help' => 'The view class to use baking code.', + 'default' => Configure::read('Bake.viewClass') ?: 'Bake.Bake', + 'choices' => ['Bake.Bake', 'Bake.BakeTwig'], ]); return $parser; diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php new file mode 100644 index 000000000..555cfb82e --- /dev/null +++ b/src/View/BakeTwigView.php @@ -0,0 +1,128 @@ +loadHelper('Bake.Bake'); + $this->loadHelper('Bake.DocBlock'); + + $this->getEventManager()->on(ConstructEvent::EVENT, function ($event) { + $event->getTwig()->addExtension(new Inflector); + }); + + parent::initialize(); + } + + /** + * Renders view for given view file and layout. + * + * Render triggers helper callbacks, which are fired before and after the view are rendered, + * as well as before and after the layout. The helper callbacks are called: + * + * - `beforeRender` + * - `afterRender` + * + * View names can point to plugin views/layouts. Using the `Plugin.view` syntax + * a plugin view/layout can be used instead of the app ones. If the chosen plugin is not found + * the view will be located along the regular view path cascade. + * + * View can also be a template string, rather than the name of a view file + * + * @param string|null $view Name of view file to use, or a template string to render + * @param string|null $layout Layout to use. Not used, for consistency with other views only + * @return string|null Rendered content. + * @throws \Cake\Core\Exception\Exception If there is an error in the view. + */ + public function render($view = null, $layout = null) + { + $viewFileName = $this->_getViewFileName($view); + $templateEventName = str_replace( + ['.ctp', DS], + ['', '.'], + explode('Template' . DS . 'Bake' . DS, $viewFileName)[1] + ); + + $this->_currentType = static::TYPE_TEMPLATE; + $this->dispatchEvent('View.beforeRender', [$viewFileName]); + $this->dispatchEvent('View.beforeRender.' . $templateEventName, [$viewFileName]); + $this->Blocks->set('content', $this->_render($viewFileName)); + $this->dispatchEvent('View.afterRender', [$viewFileName]); + $this->dispatchEvent('View.afterRender.' . $templateEventName, [$viewFileName]); + + if ($layout === null) { + $layout = $this->layout; + } + if ($layout && $this->autoLayout) { + $this->Blocks->set('content', $this->renderLayout('', $layout)); + } + + return $this->Blocks->get('content'); + } + + /** + * Wrapper for creating and dispatching events. + * + * Use the Bake prefix for bake related view events + * + * @param string $name Name of the event. + * @param array|null $data Any value you wish to be transported with this event to + * it can be read by listeners. + * + * @param object|null $subject The object that this event applies to + * ($this by default). + * + * @return \Cake\Event\Event + */ + public function dispatchEvent($name, $data = null, $subject = null) + { + $name = preg_replace('/^View\./', 'Bake.', $name); + + return parent::dispatchEvent($name, $data, $subject); + } + + /** + * Return all possible paths to find view files in order + * + * @param string $plugin Optional plugin name to scan for view files. + * @param bool $cached Set to false to force a refresh of view paths. Default true. + * @return array paths + */ + protected function _paths($plugin = null, $cached = true) + { + $paths = parent::_paths($plugin, false); + foreach ($paths as &$path) { + $path .= 'Bake' . DS; + } + + return $paths; + } +} diff --git a/tests/TestCase/Shell/Task/BakeTemplateTaskTest.php b/tests/TestCase/Shell/Task/BakeTemplateTaskTest.php index 96a2e4511..efd3d5a6d 100644 --- a/tests/TestCase/Shell/Task/BakeTemplateTaskTest.php +++ b/tests/TestCase/Shell/Task/BakeTemplateTaskTest.php @@ -15,6 +15,7 @@ namespace Bake\Test\TestCase\Shell\Task; use Bake\Test\TestCase\TestCase; +use Cake\Core\Configure; use Cake\Core\Plugin; /** @@ -45,6 +46,8 @@ public function setUp() ->setConstructorArgs([$io]) ->getMock(); ; + + $this->Task->params['view-class'] = Configure::read('Bake.viewClass'); } /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0ae9852c1..ce786bde8 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -39,6 +39,7 @@ define('ROOT', $root . DS . 'tests' . DS . 'test_app' . DS); define('APP', ROOT . 'App' . DS); define('TMP', sys_get_temp_dir() . DS); +define('CACHE', TMP . 'cache' . DS); Configure::write('debug', true); Configure::write('App', [ @@ -46,14 +47,20 @@ 'paths' => [ 'plugins' => [ROOT . 'Plugin' . DS], 'templates' => [ROOT . 'App' . DS . 'Template' . DS] - ] + ], + 'encoding' => 'UTF-8' ]); +Configure::write('Bake.viewClass', getenv('bake_class') ?: 'Bake.Bake'); if (!getenv('db_dsn')) { putenv('db_dsn=sqlite:///:memory:'); } ConnectionManager::config('test', ['url' => getenv('db_dsn')]); +Plugin::load('WyriHaximus/TwigView', [ + 'bootstrap' => true, +]); + Plugin::load('Bake', [ 'path' => dirname(dirname(__FILE__)) . DS, ]); diff --git a/tests/test_app/App/Template/Bake/example.twig b/tests/test_app/App/Template/Bake/example.twig new file mode 100644 index 000000000..e3ca219ba --- /dev/null +++ b/tests/test_app/App/Template/Bake/example.twig @@ -0,0 +1,2 @@ +I got rendered +{{ test }} \ No newline at end of file diff --git a/tests/test_app/Plugin/TestBakeTheme/src/Template/Bake/config/routes.twig b/tests/test_app/Plugin/TestBakeTheme/src/Template/Bake/config/routes.twig new file mode 100644 index 000000000..4def19ad0 --- /dev/null +++ b/tests/test_app/Plugin/TestBakeTheme/src/Template/Bake/config/routes.twig @@ -0,0 +1,9 @@ +fallbacks(); +}); From 0c65148361fc1653e5ff14ef52c41049ea824557 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 01:10:27 +0530 Subject: [PATCH 02/44] Add twig templates for ControllerTask. --- src/Template/Bake/Controller/controller.twig | 47 +++++++++++++++++++ src/Template/Bake/Element/array_property.twig | 7 +++ .../Shell/Task/ControllerTaskTest.php | 2 + 3 files changed, 56 insertions(+) create mode 100644 src/Template/Bake/Controller/controller.twig create mode 100644 src/Template/Bake/Element/array_property.twig diff --git a/src/Template/Bake/Controller/controller.twig b/src/Template/Bake/Controller/controller.twig new file mode 100644 index 000000000..eabc0c95e --- /dev/null +++ b/src/Template/Bake/Controller/controller.twig @@ -0,0 +1,47 @@ +{# +/** + * Controller bake template file + * + * Allows templating of Controllers generated from bake. + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +Task->connection = 'test'; $this->Task->BakeTemplate = new BakeTemplateTask($io); + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->Task->Model = $this->getMockBuilder('Bake\Shell\Task\ModelTask') ->setMethods(['in', 'out', 'err', 'createFile', '_stop']) From c244431562f12b7276c5a922182730b002c7266d Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 01:12:24 +0530 Subject: [PATCH 03/44] Add travis job to run tests using BakeTwig class. --- .travis.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0368d061..159d90ceb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,7 @@ php: - 5.6 - 7.0 - 7.1 - -sudo: false + - 7.2 cache: directories: @@ -17,6 +16,7 @@ env: - DB=mysql db_dsn='mysql://root@127.0.0.1/cakephp_test' - DB=pgsql db_dsn='postgres://postgres@127.0.0.1/cakephp_test' - DB=sqlite db_dsn='sqlite:///:memory:' + - bake_class='Bake.BakeTwig' global: - RUN_TESTS=1 @@ -33,9 +33,8 @@ before_install: - if [[ $DB = 'mysql' ]]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi - if [[ $DB = 'pgsql' ]]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi - - phpenv rehash - - set +H - - composer update +before_script: + - composer install --prefer-dist --no-interaction script: - if [[ $RUN_TESTS = 1 && $TRAVIS_PHP_VERSION != 7.* ]]; then vendor/bin/phpunit; fi From 890523d81c88232b419e75ddc615e1dfdd482d86 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 03:54:02 +0530 Subject: [PATCH 04/44] Add twig templates for Cell, Fixture, Mailer, Middlware tasks. --- src/Template/Bake/Mailer/mailer.twig | 33 ++++++++++++++ src/Template/Bake/Middleware/middleware.twig | 40 +++++++++++++++++ src/Template/Bake/View/cell.twig | 43 +++++++++++++++++++ src/Template/Bake/tests/fixture.twig | 8 ++-- tests/TestCase/Shell/Task/CellTaskTest.php | 1 + tests/TestCase/Shell/Task/FixtureTaskTest.php | 2 + tests/TestCase/Shell/Task/MailerTaskTest.php | 1 + .../Shell/Task/MiddlewareTaskTest.php | 1 + 8 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 src/Template/Bake/Mailer/mailer.twig create mode 100644 src/Template/Bake/Middleware/middleware.twig create mode 100644 src/Template/Bake/View/cell.twig diff --git a/src/Template/Bake/Mailer/mailer.twig b/src/Template/Bake/Mailer/mailer.twig new file mode 100644 index 000000000..621e9d6fe --- /dev/null +++ b/src/Template/Bake/Mailer/mailer.twig @@ -0,0 +1,33 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->initialize(); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); } /** diff --git a/tests/TestCase/Shell/Task/FixtureTaskTest.php b/tests/TestCase/Shell/Task/FixtureTaskTest.php index c993cf809..19d251206 100644 --- a/tests/TestCase/Shell/Task/FixtureTaskTest.php +++ b/tests/TestCase/Shell/Task/FixtureTaskTest.php @@ -16,6 +16,7 @@ use Bake\Shell\Task\BakeTemplateTask; use Bake\Test\TestCase\TestCase; +use Cake\Core\Configure; use Cake\Core\Plugin; use Cake\ORM\TableRegistry; @@ -67,6 +68,7 @@ public function setUp() $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->interactive = false; $this->Task->BakeTemplate->initialize(); + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->_compareBasePath = Plugin::path('Bake') . 'tests' . DS . 'comparisons' . DS . 'Fixture' . DS; } diff --git a/tests/TestCase/Shell/Task/MailerTaskTest.php b/tests/TestCase/Shell/Task/MailerTaskTest.php index ad3aa9e5c..e9a52e9f1 100644 --- a/tests/TestCase/Shell/Task/MailerTaskTest.php +++ b/tests/TestCase/Shell/Task/MailerTaskTest.php @@ -54,6 +54,7 @@ public function setUp() $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->initialize(); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); } /** diff --git a/tests/TestCase/Shell/Task/MiddlewareTaskTest.php b/tests/TestCase/Shell/Task/MiddlewareTaskTest.php index 9972d2515..3180ac2bb 100644 --- a/tests/TestCase/Shell/Task/MiddlewareTaskTest.php +++ b/tests/TestCase/Shell/Task/MiddlewareTaskTest.php @@ -54,6 +54,7 @@ public function setUp() $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->initialize(); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); } /** From ba721d7cd8a0c328de37b1558c40d013292c4d25 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 03:57:37 +0530 Subject: [PATCH 05/44] Add docblock --- src/View/BakeTwigView.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index 555cfb82e..eafd0412d 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -14,7 +14,6 @@ */ namespace Bake\View; -use Bake\View\Listener\TwigLoaderListener; use Cake\Core\Configure; use WyriHaximus\TwigView\Event\ConstructEvent; use WyriHaximus\TwigView\Lib\Twig\Extension\Inflector; @@ -22,6 +21,11 @@ class BakeTwigView extends TwigView { + /** + * Initialize view + * + * @return void + */ public function initialize() { $bakeTemplates = dirname(dirname(__FILE__)) . DS . 'Template' . DS; From a871dbe9cefa2c75f39441bfd373671c34a9ba9e Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 12:29:32 +0530 Subject: [PATCH 06/44] Add more twig templates. --- src/Template/Bake/Controller/component.twig | 34 +++++++++++ src/Template/Bake/Form/form.twig | 60 +++++++++++++++++++ src/Template/Bake/Plugin/README.md.twig | 26 ++++++++ .../Bake/Plugin/config/routes.php.twig | 27 +++++++++ .../Bake/Plugin/phpunit.xml.dist.twig | 53 ++++++++++++++++ .../src/Controller/AppController.php.twig | 25 ++++++++ .../Bake/Plugin/tests/bootstrap.php.twig | 47 +++++++++++++++ src/Template/Bake/Plugin/webroot/empty.twig | 15 +++++ src/Template/Bake/Shell/helper.twig | 37 ++++++++++++ src/Template/Bake/Shell/shell.twig | 50 ++++++++++++++++ src/Template/Bake/Shell/task.twig | 34 +++++++++++ src/Template/Bake/Template/add.twig | 22 +++++++ src/Template/Bake/Template/edit.twig | 22 +++++++ src/Template/Bake/Template/login.twig | 31 ++++++++++ src/Template/Bake/View/helper.twig | 35 +++++++++++ .../ModelTaskAssociationDetectionTest.php | 1 + tests/TestCase/Shell/Task/ModelTaskTest.php | 1 + tests/TestCase/Shell/Task/PluginTaskTest.php | 1 + .../Shell/Task/SimpleBakeTaskTest.php | 1 + tests/TestCase/Shell/Task/TaskTaskTest.php | 1 + tests/TestCase/Shell/Task/TestTaskTest.php | 1 + 21 files changed, 524 insertions(+) create mode 100644 src/Template/Bake/Controller/component.twig create mode 100644 src/Template/Bake/Form/form.twig create mode 100644 src/Template/Bake/Plugin/README.md.twig create mode 100644 src/Template/Bake/Plugin/config/routes.php.twig create mode 100644 src/Template/Bake/Plugin/phpunit.xml.dist.twig create mode 100644 src/Template/Bake/Plugin/src/Controller/AppController.php.twig create mode 100644 src/Template/Bake/Plugin/tests/bootstrap.php.twig create mode 100644 src/Template/Bake/Plugin/webroot/empty.twig create mode 100644 src/Template/Bake/Shell/helper.twig create mode 100644 src/Template/Bake/Shell/shell.twig create mode 100644 src/Template/Bake/Shell/task.twig create mode 100644 src/Template/Bake/Template/add.twig create mode 100644 src/Template/Bake/Template/edit.twig create mode 100644 src/Template/Bake/Template/login.twig create mode 100644 src/Template/Bake/View/helper.twig diff --git a/src/Template/Bake/Controller/component.twig b/src/Template/Bake/Controller/component.twig new file mode 100644 index 000000000..65ba0b97f --- /dev/null +++ b/src/Template/Bake/Controller/component.twig @@ -0,0 +1,34 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + '/{{ routePath }}'], + function (RouteBuilder $routes) { + $routes->fallbacks(DashedRoute::class); + } +); diff --git a/src/Template/Bake/Plugin/phpunit.xml.dist.twig b/src/Template/Bake/Plugin/phpunit.xml.dist.twig new file mode 100644 index 000000000..bd3feb5a5 --- /dev/null +++ b/src/Template/Bake/Plugin/phpunit.xml.dist.twig @@ -0,0 +1,53 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + + + + + + + + + + + ./tests/TestCase + + + + + + + + + + + + + + + ./src/ + + + + diff --git a/src/Template/Bake/Plugin/src/Controller/AppController.php.twig b/src/Template/Bake/Plugin/src/Controller/AppController.php.twig new file mode 100644 index 000000000..d06ea6823 --- /dev/null +++ b/src/Template/Bake/Plugin/src/Controller/AppController.php.twig @@ -0,0 +1,25 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +out($this->OptionParser->help()); + } +} diff --git a/src/Template/Bake/Shell/task.twig b/src/Template/Bake/Shell/task.twig new file mode 100644 index 000000000..7e7804ce9 --- /dev/null +++ b/src/Template/Bake/Shell/task.twig @@ -0,0 +1,34 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + +{{ element 'form' }} diff --git a/src/Template/Bake/Template/edit.twig b/src/Template/Bake/Template/edit.twig new file mode 100644 index 000000000..eab98d3fa --- /dev/null +++ b/src/Template/Bake/Template/edit.twig @@ -0,0 +1,22 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 0.1.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + +{{ element 'form' }} diff --git a/src/Template/Bake/Template/login.twig b/src/Template/Bake/Template/login.twig new file mode 100644 index 000000000..7b03c8cff --- /dev/null +++ b/src/Template/Bake/Template/login.twig @@ -0,0 +1,31 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + +
+Flash->render('auth') ?> + Form->create() ?> +
+ + Form->control('username') ?> + Form->control('password') ?> +
+ Form->button(__('Login')); ?> + Form->end() ?> +
diff --git a/src/Template/Bake/View/helper.twig b/src/Template/Bake/View/helper.twig new file mode 100644 index 000000000..cddf60aac --- /dev/null +++ b/src/Template/Bake/View/helper.twig @@ -0,0 +1,35 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +getMock(); $this->Task->connection = 'default'; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->_setupOtherMocks(); TableRegistry::clear(); } diff --git a/tests/TestCase/Shell/Task/ModelTaskTest.php b/tests/TestCase/Shell/Task/ModelTaskTest.php index 1610cf535..06432e385 100644 --- a/tests/TestCase/Shell/Task/ModelTaskTest.php +++ b/tests/TestCase/Shell/Task/ModelTaskTest.php @@ -80,6 +80,7 @@ public function setUp() ->getMock(); $this->Task->connection = 'test'; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->_setupOtherMocks(); TableRegistry::clear(); } diff --git a/tests/TestCase/Shell/Task/PluginTaskTest.php b/tests/TestCase/Shell/Task/PluginTaskTest.php index c79d64f1c..9dd553b04 100644 --- a/tests/TestCase/Shell/Task/PluginTaskTest.php +++ b/tests/TestCase/Shell/Task/PluginTaskTest.php @@ -59,6 +59,7 @@ public function setUp() $this->Task->BakeTemplate = new BakeTemplateTask($this->io); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->Task->path = TMP . 'tests' . DS . 'BakedPlugins' . DS; new Folder($this->Task->path, true); diff --git a/tests/TestCase/Shell/Task/SimpleBakeTaskTest.php b/tests/TestCase/Shell/Task/SimpleBakeTaskTest.php index 229dbb963..bd3bbb311 100644 --- a/tests/TestCase/Shell/Task/SimpleBakeTaskTest.php +++ b/tests/TestCase/Shell/Task/SimpleBakeTaskTest.php @@ -54,6 +54,7 @@ public function setUp() $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->initialize(); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->Task->pathFragment = 'Model/Behavior/'; diff --git a/tests/TestCase/Shell/Task/TaskTaskTest.php b/tests/TestCase/Shell/Task/TaskTaskTest.php index ffbc587eb..25e10fc10 100644 --- a/tests/TestCase/Shell/Task/TaskTaskTest.php +++ b/tests/TestCase/Shell/Task/TaskTaskTest.php @@ -54,6 +54,7 @@ public function setUp() $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->initialize(); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); } /** diff --git a/tests/TestCase/Shell/Task/TestTaskTest.php b/tests/TestCase/Shell/Task/TestTaskTest.php index b08a71a4c..a0808fd69 100644 --- a/tests/TestCase/Shell/Task/TestTaskTest.php +++ b/tests/TestCase/Shell/Task/TestTaskTest.php @@ -75,6 +75,7 @@ public function setUp() $this->Task->name = 'Test'; $this->Task->BakeTemplate = new BakeTemplateTask($this->io); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); } /** From 4bcbc07cb0d1f88b6b745dc2054590990572e8ac Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 13:14:11 +0530 Subject: [PATCH 07/44] Fix tests. --- tests/TestCase/Shell/BakeShellTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/TestCase/Shell/BakeShellTest.php b/tests/TestCase/Shell/BakeShellTest.php index 9fe6febb6..7301e8cbc 100644 --- a/tests/TestCase/Shell/BakeShellTest.php +++ b/tests/TestCase/Shell/BakeShellTest.php @@ -149,6 +149,7 @@ public function testMain() '- task', '- template', '- test', + '- twig_template', '', 'By using `cake bake [name]` you can invoke a specific bake task.', ]; @@ -203,7 +204,8 @@ public function testLoadTasksCoreAndApp() 'Bake.Test', 'Bake.Template', 'Controller', - 'CustomController' + 'CustomController', + 'WyriHaximus/TwigView.TwigTemplate', ]; sort($this->Shell->tasks); sort($expected); From 7fd68de5e71be5c50185d11f350f3f781c087b07 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 18:01:39 +0530 Subject: [PATCH 08/44] Load all available twig extensions. --- src/View/BakeTwigView.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index eafd0412d..42c9bd860 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -16,6 +16,7 @@ use Cake\Core\Configure; use WyriHaximus\TwigView\Event\ConstructEvent; +use WyriHaximus\TwigView\Event\ExtensionsListener; use WyriHaximus\TwigView\Lib\Twig\Extension\Inflector; use WyriHaximus\TwigView\View\TwigView; @@ -39,9 +40,7 @@ public function initialize() $this->loadHelper('Bake.Bake'); $this->loadHelper('Bake.DocBlock'); - $this->getEventManager()->on(ConstructEvent::EVENT, function ($event) { - $event->getTwig()->addExtension(new Inflector); - }); + $this->getEventManager()->on(new ExtensionsListener()); parent::initialize(); } From e5672d63ae1a12621fe911343f057293fe8b4542 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 21:34:45 +0530 Subject: [PATCH 09/44] Fix test. --- tests/TestCase/Shell/Task/ModelTaskAssociationDetectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase/Shell/Task/ModelTaskAssociationDetectionTest.php b/tests/TestCase/Shell/Task/ModelTaskAssociationDetectionTest.php index 4a0f56bf0..ccced4ceb 100644 --- a/tests/TestCase/Shell/Task/ModelTaskAssociationDetectionTest.php +++ b/tests/TestCase/Shell/Task/ModelTaskAssociationDetectionTest.php @@ -66,7 +66,6 @@ public function setUp() ->getMock(); $this->Task->connection = 'default'; - $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->_setupOtherMocks(); TableRegistry::clear(); } @@ -109,6 +108,7 @@ protected function _setupOtherMocks() ->getMock(); $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->Task->name = 'Model'; } From 5145ee31cdc04f197e796bb70e60e9da63423e3a Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 21:38:25 +0530 Subject: [PATCH 10/44] Fix tests. --- tests/TestCase/Shell/Task/ModelTaskTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase/Shell/Task/ModelTaskTest.php b/tests/TestCase/Shell/Task/ModelTaskTest.php index 06432e385..f090f2e9b 100644 --- a/tests/TestCase/Shell/Task/ModelTaskTest.php +++ b/tests/TestCase/Shell/Task/ModelTaskTest.php @@ -80,7 +80,6 @@ public function setUp() ->getMock(); $this->Task->connection = 'test'; - $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->_setupOtherMocks(); TableRegistry::clear(); } @@ -123,6 +122,7 @@ protected function _setupOtherMocks() ->getMock(); $this->Task->BakeTemplate = new BakeTemplateTask($io); $this->Task->BakeTemplate->interactive = false; + $this->Task->BakeTemplate->params['view-class'] = Configure::read('Bake.viewClass'); $this->Task->name = 'Model'; } From 57ed3810e49497e2c7884b8b1c62fa64fa1f1dce Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 21 Oct 2017 22:49:28 +0530 Subject: [PATCH 11/44] Add more twig templates. --- src/Template/Bake/Element/form.twig | 72 ++++++++++++++++++ src/Template/Bake/Model/behavior.twig | 34 +++++++++ src/Template/Bake/Model/entity.twig | 72 ++++++++++++++++++ src/Template/Bake/Template/index.twig | 102 ++++++++++++++++++++++++++ src/View/Helper/BakeHelper.php | 32 ++++++++ 5 files changed, 312 insertions(+) create mode 100644 src/Template/Bake/Element/form.twig create mode 100644 src/Template/Bake/Model/behavior.twig create mode 100644 src/Template/Bake/Model/entity.twig create mode 100644 src/Template/Bake/Template/index.twig diff --git a/src/Template/Bake/Element/form.twig b/src/Template/Bake/Element/form.twig new file mode 100644 index 000000000..320072f35 --- /dev/null +++ b/src/Template/Bake/Element/form.twig @@ -0,0 +1,72 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set fields = Bake.filterFields(fields, schema) %} + +
+ Form->create(${{ singularVar }}) ?> +
+ + Form->control('{{ field }}', ['options' => ${{ keyFields.field }}, 'empty' => true]); +{% else %} + echo $this->Form->control('{{ field }}', ['options' => ${{ keyFields.field }}]); +{% endif %} +{% elseif field in ['created', 'modified', 'updated'] %} +{% set fieldData = Bake.fieldData(field, schema) %} +{% if fieldData.type|in_array(['date', 'datetime', 'time']) and fieldData.null %} + echo $this->Form->control('{{ field }}', ['empty' => true]); +{% else %} + echo $this->Form->control('{{ field }}'); +{% endif %} +{% endif %} +{% endfor %} +{% if associations.BelongsToMany %} +{% for assocName, assocData in associations.BelongsToMany %} + echo $this->Form->control('{{ assocData.property }}._ids', ['options' => ${{ assocData.variable }}]); +{% endfor %} +{% endif %} + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
diff --git a/src/Template/Bake/Model/behavior.twig b/src/Template/Bake/Model/behavior.twig new file mode 100644 index 000000000..3f42750ca --- /dev/null +++ b/src/Template/Bake/Model/behavior.twig @@ -0,0 +1,34 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + false])|raw }}]; +{% endif %} +{% if hidden %} + + /** + * Fields that are excluded from JSON versions of the entity. + * + * @var array + */ + protected $_hidden = [{{ Bake.stringifyList(hidden) }}]; +{% endif %} +{% if not accessible and not hidden %} + +{% endif %} +} diff --git a/src/Template/Bake/Template/index.twig b/src/Template/Bake/Template/index.twig new file mode 100644 index 000000000..b1edbc22d --- /dev/null +++ b/src/Template/Bake/Template/index.twig @@ -0,0 +1,102 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + +{% set fields = Bake.filterFields(fields, schema, indexColumns, ['binary', 'text']) %} + +
+

+ + + +{% for field in fields %} + +{% endfor %} + + + + + + +{% for field in fields %} +{% set isKey = false %} +{% if associations.BelongsTo %} +{% for alias, details in associations.BelongsTo %} +<% + if ($field === $details['foreignKey']) { + $isKey = true; +%> + +<% + break; + } +%> +{% endfor %} +{% endif %} +{% if isKey is not true %} +<% + if (!in_array($schema->columnType($field), ['integer', 'float', 'decimal', 'biginteger', 'smallinteger', 'tinyinteger'])) { +%> + +<% + } else { +%> + +<% + } +%> +{% endif %} +{% endfor %} +{% set pk '$' ~ singularVar ~ '->' ~ primaryKey.0 %} + + + + +
Paginator->sort('{{ field }}') ?>
has('<%= $details['property'] %>') ? $this->Html->link(${{ singularVar }}-><%= $details['property'] %>->{{ details.displayField }}, ['controller' => '{{ details.controller }}', 'action' => 'view', ${{ singularVar }}-><%= $details['property'] %>-><%= $details['primaryKey'][0] %>]) : '' ?>{{ field }}) ?>Number->format(${{ singularVar }}->{{ field }}) ?> + Html->link(__('View'), ['action' => 'view', {{ pk }}]) ?> + Html->link(__('Edit'), ['action' => 'edit', {{ pk }}]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', {{ pk }}], ['confirm' => __('Are you sure you want to delete # {0}?', {{ pk }})]) ?> +
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(['format' => __('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')]) ?>

+
+
diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index b33e56709..053f4f6bd 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -162,6 +162,38 @@ public function classInfo($class, $type, $suffix) ]; } + /** + * Return list of fields to generate controls for. + * + * @param array $fields Fields list. + * @param \Cake\Datasource\SchemaInterface $schema Schema instance. + * @return \Cake\Collection\CollectionInterface + */ + public function filterFields($fields, $schema, $takeFields = [], $filterTypes = ['binary']) + { + $fields = collection($fields) + ->filter(function ($field) use ($schema) { + return !in_array($schema->columnType($field), ['binary', 'text']); + }); + + if (isset($modelObject) && $modelObject->hasBehavior('Tree')) { + $fields = $fields->reject(function ($field) { + return $field === 'lft' || $field === 'rght'; + }); + } + + if (!empty($takeFields)) { + $fields = $fields->take($takeFields); + } + + return $fields; + } + + public function fieldData($field, $schema) + { + return $schema->column($field); + } + /** * To be mocked elsewhere... * From a99a9b4ecac225f4f2fa3ea34ca38734a76dc97b Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Sat, 21 Oct 2017 21:52:10 +0200 Subject: [PATCH 12/44] Added missing TokenParsersListener listener for element --- src/View/BakeTwigView.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index 42c9bd860..8b8b023a3 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -17,6 +17,7 @@ use Cake\Core\Configure; use WyriHaximus\TwigView\Event\ConstructEvent; use WyriHaximus\TwigView\Event\ExtensionsListener; +use WyriHaximus\TwigView\Event\TokenParsersListener; use WyriHaximus\TwigView\Lib\Twig\Extension\Inflector; use WyriHaximus\TwigView\View\TwigView; @@ -41,6 +42,7 @@ public function initialize() $this->loadHelper('Bake.DocBlock'); $this->getEventManager()->on(new ExtensionsListener()); + $this->getEventManager()->on(new TokenParsersListener()); parent::initialize(); } From abfdc5b648ebcd884636b3c36028d3acb9225627 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 09:57:15 +0530 Subject: [PATCH 13/44] Load TwigView plugin in TestCase::setUp(). The global event manager instance is reset before each test hence the plugin has to be laoded later to ensure TwigView's listeners set in it's bootstrap are not lost. --- src/View/BakeTwigView.php | 7 ------- tests/TestCase/TestCase.php | 12 ++++++++++++ tests/bootstrap.php | 4 ---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index 8b8b023a3..f69e2fd65 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -15,10 +15,6 @@ namespace Bake\View; use Cake\Core\Configure; -use WyriHaximus\TwigView\Event\ConstructEvent; -use WyriHaximus\TwigView\Event\ExtensionsListener; -use WyriHaximus\TwigView\Event\TokenParsersListener; -use WyriHaximus\TwigView\Lib\Twig\Extension\Inflector; use WyriHaximus\TwigView\View\TwigView; class BakeTwigView extends TwigView @@ -41,9 +37,6 @@ public function initialize() $this->loadHelper('Bake.Bake'); $this->loadHelper('Bake.DocBlock'); - $this->getEventManager()->on(new ExtensionsListener()); - $this->getEventManager()->on(new TokenParsersListener()); - parent::initialize(); } diff --git a/tests/TestCase/TestCase.php b/tests/TestCase/TestCase.php index 8dd970885..1e94c5535 100644 --- a/tests/TestCase/TestCase.php +++ b/tests/TestCase/TestCase.php @@ -14,6 +14,7 @@ */ namespace Bake\Test\TestCase; +use Cake\Core\Configure; use Cake\Core\Plugin; use Cake\TestSuite\StringCompareTrait; use Cake\TestSuite\TestCase as ParentTestCase; @@ -22,6 +23,17 @@ abstract class TestCase extends ParentTestCase { use StringCompareTrait; + public function setUp() + { + parent::setUp(); + + if (Configure::read('Bake.viewClass') === 'Bake.BakeTwig') { + Plugin::load('WyriHaximus/TwigView', [ + 'bootstrap' => true, + ]); + } + } + /** * Load a plugin from the tests folder, and add to the autoloader * diff --git a/tests/bootstrap.php b/tests/bootstrap.php index ce786bde8..a29e0268c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -57,10 +57,6 @@ } ConnectionManager::config('test', ['url' => getenv('db_dsn')]); -Plugin::load('WyriHaximus/TwigView', [ - 'bootstrap' => true, -]); - Plugin::load('Bake', [ 'path' => dirname(dirname(__FILE__)) . DS, ]); From 860883fd1f5953a58edc4466a2ffeced895f73d2 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 11:46:28 +0530 Subject: [PATCH 14/44] Add templates for controller actions. --- src/Template/Bake/Controller/controller.twig | 12 +++-- src/Template/Bake/Element/Controller/add.twig | 45 +++++++++++++++++ .../Bake/Element/Controller/delete.twig | 35 +++++++++++++ .../Bake/Element/Controller/edit.twig | 49 +++++++++++++++++++ .../Bake/Element/Controller/index.twig | 34 +++++++++++++ .../Bake/Element/Controller/login.twig | 33 +++++++++++++ .../Bake/Element/Controller/logout.twig | 25 ++++++++++ .../Bake/Element/Controller/view.twig | 36 ++++++++++++++ src/View/BakeTwigView.php | 8 +++ src/View/Helper/BakeHelper.php | 14 ++++++ 10 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 src/Template/Bake/Element/Controller/add.twig create mode 100644 src/Template/Bake/Element/Controller/delete.twig create mode 100644 src/Template/Bake/Element/Controller/edit.twig create mode 100644 src/Template/Bake/Element/Controller/index.twig create mode 100644 src/Template/Bake/Element/Controller/login.twig create mode 100644 src/Template/Bake/Element/Controller/logout.twig create mode 100644 src/Template/Bake/Element/Controller/view.twig diff --git a/src/Template/Bake/Controller/controller.twig b/src/Template/Bake/Controller/controller.twig index eabc0c95e..e80459356 100644 --- a/src/Template/Bake/Controller/controller.twig +++ b/src/Template/Bake/Controller/controller.twig @@ -39,9 +39,15 @@ use {{ namespace }}\Controller\AppController; */ class {{ name }}Controller extends AppController { -{{ Bake.arrayProperty('helpers', helpers, {'indent': false})|raw }} -{{ Bake.arrayProperty('components', components, {'indent': false})|raw }} +{% set helpers = Bake.arrayProperty('helpers', helpers, {'indent': false})|raw %} +{% if helpers|trim %} +{{ helpers|raw }} +{% endif %} +{% set components = Bake.arrayProperty('components', components, {'indent': false})|raw %} +{% if components|trim %} +{{ components|raw }} +{% endif %} {% for action in actions %} - {% element 'Controller/' ~ action %} +{% element 'Controller/' ~ action %} {% endfor %} } diff --git a/src/Template/Bake/Element/Controller/add.twig b/src/Template/Bake/Element/Controller/add.twig new file mode 100644 index 000000000..ddceaa9b8 --- /dev/null +++ b/src/Template/Bake/Element/Controller/add.twig @@ -0,0 +1,45 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set compact = [("'" ~ singularName ~ "'")] %} + + /** + * Add method + * + * @return \Cake\Http\Response|null Redirects on successful add, renders view otherwise. + */ + public function add() + { + ${{ singularName }} = $this->{{ currentModelName }}->newEntity(); + if ($this->request->is('post')) { + ${{ singularName }} = $this->{{ currentModelName }}->patchEntity(${{ singularName }}, $this->request->getData()); + if ($this->{{ currentModelName }}->save(${{ singularName }})) { + $this->Flash->success(__('The {{ singularHumanName|lower }} has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The {{ singularHumanName|lower }} could not be saved. Please, try again.')); + } +{% set associations = Bake.aliasExtractor(modelObj, 'BelongsTo') %} +{% set associations = associations|merge(Bake.aliasExtractor(modelObj, 'BelongsToMany')) %} +{% for assoc in associations %} +{% set otherName = Bake.getAssociatedTableAlias(modelObj, assoc) %} +{% set otherPlural = _view.variableName(otherName) %} + ${{ otherPlural }} = $this->{{ currentModelName }}->{{ otherName }}->find('list', ['limit' => 200]); +{% set compact = compact|merge(["'" ~ otherPlural ~ "'"]) %} +{% endfor %} + $this->set(compact({{ compact|join(', ')|raw }})); + $this->set('_serialize', ['{{ singularName }}']); + } diff --git a/src/Template/Bake/Element/Controller/delete.twig b/src/Template/Bake/Element/Controller/delete.twig new file mode 100644 index 000000000..2fbbf6db1 --- /dev/null +++ b/src/Template/Bake/Element/Controller/delete.twig @@ -0,0 +1,35 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + + /** + * Delete method + * + * @param string|null $id {{ singularHumanName }} id. + * @return \Cake\Http\Response|null Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + ${{ singularName }} = $this->{{ currentModelName }}->get($id); + if ($this->{{ currentModelName }}->delete(${{ singularName }})) { + $this->Flash->success(__('The {{ singularHumanName|lower }} has been deleted.')); + } else { + $this->Flash->error(__('The {{ singularHumanName|lower }} could not be deleted. Please, try again.')); + } + + return $this->redirect(['action' => 'index']); + } diff --git a/src/Template/Bake/Element/Controller/edit.twig b/src/Template/Bake/Element/Controller/edit.twig new file mode 100644 index 000000000..4b0db617f --- /dev/null +++ b/src/Template/Bake/Element/Controller/edit.twig @@ -0,0 +1,49 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set belongsTo = Bake.aliasExtractor(modelObj, 'BelongsTo') %} +{% set belongsToMany = Bake.aliasExtractor(modelObj, 'belongsToMany') %} +{% set compact = ["'" ~ singularName ~ "'"] %} + + /** + * Edit method + * + * @param string|null $id {{ singularHumanName }} id. + * @return \Cake\Http\Response|null Redirects on successful edit, renders view otherwise. + * @throws \Cake\Network\Exception\NotFoundException When record not found. + */ + public function edit($id = null) + { + ${{ singularName }} = $this->{{ currentModelName }}->get($id, [ + 'contain' => [{{ Bake.stringifyList(belongsToMany, {'indent': false})|raw }}] + ]); + if ($this->request->is(['patch', 'post', 'put'])) { + ${{ singularName }} = $this->{{ currentModelName }}->patchEntity(${{ singularName }}, $this->request->getData()); + if ($this->{{ currentModelName }}->save(${{ singularName }})) { + $this->Flash->success(__('The {{ singularHumanName|lower }} has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The {{ singularHumanName|lower }} could not be saved. Please, try again.')); + } +{% for assoc in belongsTo|merge(belongsToMany) %} +{% set otherName = Bake.getAssociatedTableAlias(modelObj, assoc) %} +{% set otherPlural = _view.variableName(otherName) %} + ${{ otherPlural }} = $this->{{ currentModelName }}->{{ otherName }}->find('list', ['limit' => 200]); +{% set compact = compact|merge(["'" ~ otherPlural ~ "'"]) %} +{% endfor %} + $this->set(compact({{ compact|join(', ')|raw }})); + $this->set('_serialize', ['{{ singularName }}']); + } diff --git a/src/Template/Bake/Element/Controller/index.twig b/src/Template/Bake/Element/Controller/index.twig new file mode 100644 index 000000000..52ed9e15b --- /dev/null +++ b/src/Template/Bake/Element/Controller/index.twig @@ -0,0 +1,34 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + + /** + * Index method + * + * @return \Cake\Http\Response|void + */ + public function index() + { +{% set belongsTo = Bake.aliasExtractor(modelObj, 'BelongsTo') %} +{% if belongsTo %} + $this->paginate = [ + 'contain' => [{{ Bake.stringifyList(belongsTo, {'indent': false})|raw }}] + ]; +{% endif %} + ${{ pluralName }} = $this->paginate($this->{{ currentModelName }}); + + $this->set(compact('{{ pluralName }}')); + $this->set('_serialize', ['{{ pluralName }}']); + } diff --git a/src/Template/Bake/Element/Controller/login.twig b/src/Template/Bake/Element/Controller/login.twig new file mode 100644 index 000000000..ee473edad --- /dev/null +++ b/src/Template/Bake/Element/Controller/login.twig @@ -0,0 +1,33 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + + /** + * Login method + * + * @return \Cake\Http\Response|null + */ + public function login() + { + if ($this->request->is('post')) { + $user = $this->Auth->identify(); + if ($user) { + $this->Auth->setUser($user); + + return $this->redirect($this->Auth->redirectUrl()); + } + $this->Flash->error(__('Invalid credentials, try again')); + } + } diff --git a/src/Template/Bake/Element/Controller/logout.twig b/src/Template/Bake/Element/Controller/logout.twig new file mode 100644 index 000000000..dd75231ad --- /dev/null +++ b/src/Template/Bake/Element/Controller/logout.twig @@ -0,0 +1,25 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 0.1.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} + + /** + * Logout method + * + * @return \Cake\Http\Response + */ + public function logout() + { + return $this->redirect($this->Auth->logout()); + } diff --git a/src/Template/Bake/Element/Controller/view.twig b/src/Template/Bake/Element/Controller/view.twig new file mode 100644 index 000000000..5b48d8c3c --- /dev/null +++ b/src/Template/Bake/Element/Controller/view.twig @@ -0,0 +1,36 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 0.1.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set allAssociations = Bake.aliasExtractor(modelObj, 'BelongsTo') %} +{% set allAssociations = allAssociations|merge(Bake.aliasExtractor(modelObj, 'BelongsToMany')) %} +{% set allAssociations = allAssociations|merge(Bake.aliasExtractor(modelObj, 'HasOne')) %} +{% set allAssociations = allAssociations|merge(Bake.aliasExtractor(modelObj, 'HasMany')) %} + + /** + * View method + * + * @param string|null $id {{ singularHumanName }} id. + * @return \Cake\Http\Response|void + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + ${{ singularName }} = $this->{{ currentModelName }}->get($id, [ + 'contain' => [{{ Bake.stringifyList(allAssociations, {'indent': false})|raw }}] + ]); + + $this->set('{{ singularName }}', ${{ singularName }}); + $this->set('_serialize', ['{{ singularName }}']); + } diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index f69e2fd65..885d4afae 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -15,10 +15,13 @@ namespace Bake\View; use Cake\Core\Configure; +use Cake\Core\ConventionsTrait; use WyriHaximus\TwigView\View\TwigView; class BakeTwigView extends TwigView { + use ConventionsTrait; + /** * Initialize view * @@ -86,6 +89,11 @@ public function render($view = null, $layout = null) return $this->Blocks->get('content'); } + public function variableName($string) + { + return $this->_variableName($string); + } + /** * Wrapper for creating and dispatching events. * diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index 053f4f6bd..820fbd092 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -194,6 +194,20 @@ public function fieldData($field, $schema) return $schema->column($field); } + /** + * Get alias of associated table. + * + * @param \Cake\ORM\Table $modelObj Model object. + * @param string $assoc Association name. + * @return string + */ + public function getAssociatedTableAlias($modelObj, $assoc) + { + $association = $modelObj->association($assoc); + + return $association->getTarget()->getAlias(); + } + /** * To be mocked elsewhere... * From ead145b9eb4784b8396f9e71f29bac1310277a53 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 12:45:48 +0530 Subject: [PATCH 15/44] Add more templates. --- src/Template/Bake/Plugin/composer.json.twig | 39 +++++++ src/Template/Bake/tests/test_case.twig | 117 ++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/Template/Bake/Plugin/composer.json.twig create mode 100644 src/Template/Bake/tests/test_case.twig diff --git a/src/Template/Bake/Plugin/composer.json.twig b/src/Template/Bake/Plugin/composer.json.twig new file mode 100644 index 000000000..b243674d7 --- /dev/null +++ b/src/Template/Bake/Plugin/composer.json.twig @@ -0,0 +1,39 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set namespace = namespace|replace('\\', '\\\\') %} +{ + "name": "{{ package }}", + "description": "{{ plugin }} plugin for CakePHP", + "type": "cakephp-plugin", + "license": "MIT", + "require": { + "cakephp/cakephp": "^3.4" + }, + "require-dev": { + "phpunit/phpunit": "^5.7|^6.0" + }, + "autoload": { + "psr-4": { + "{{ namespace }}\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "{{ namespace }}\\Test\\": "tests", + "Cake\\Test\\": "./vendor/cakephp/cakephp/tests" + } + } +} diff --git a/src/Template/Bake/tests/test_case.twig b/src/Template/Bake/tests/test_case.twig new file mode 100644 index 000000000..8ba2d4fae --- /dev/null +++ b/src/Template/Bake/tests/test_case.twig @@ -0,0 +1,117 @@ +{# +/** + * Test Case bake template + * + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set isController = type|lower == 'controller' %} +{% if isController %} +{% set uses = uses|merge(['Cake\\TestSuite\\IntegrationTestCase']) %} +{% else %} +{% set uses = uses|merge(['Cake\\TestSuite\\TestCase']) %} +{% endif %} +{% set uses = uses|sort %} +{{ (subject ~ ' = ' ~ construction)|raw }} +{% if postConstruct %} + {{ postConstruct|raw }} +{% endif %} + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->{{ subject }}); + + parent::tearDown(); + } +{% endif %} +{% for method in methods %} + + /** + * Test {{ method }} method + * + * @return void + */ + public function test{{ method|camelize }}() + { + $this->markTestIncomplete('Not implemented yet.'); + } +{% endfor %} +{% if not methods %} + + /** + * Test initial setup + * + * @return void + */ + public function testInitialization() + { + $this->markTestIncomplete('Not implemented yet.'); + } +{% endif %} +} From 8a4ca967cdac220d26b282fc39cec9f1246e6e90 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 15:05:36 +0530 Subject: [PATCH 16/44] Add / update templates for baking models. --- src/Template/Bake/Model/entity.twig | 22 ++--- src/Template/Bake/Model/table.twig | 124 ++++++++++++++++++++++++++++ src/View/Helper/BakeHelper.php | 45 ++++++++++ src/View/Helper/DocBlockHelper.php | 35 ++++++++ 4 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 src/Template/Bake/Model/table.twig diff --git a/src/Template/Bake/Model/entity.twig b/src/Template/Bake/Model/entity.twig index 7bb8dc7ae..7ee23334b 100644 --- a/src/Template/Bake/Model/entity.twig +++ b/src/Template/Bake/Model/entity.twig @@ -17,23 +17,23 @@ {% set associationHintMap = DocBlock.buildEntityAssociationHintTypeMap(propertySchema ?: []) %} {% set annotations = DocBlock.propertyHints(propertyHintMap) %} -{% if associationHintMap %} -{% annotations|push('') %} +{%- if associationHintMap %} +{% set annotations = annotations|merge(['']) %} {% set annotations = annotations|merge(DocBlock.propertyHints(associationHintMap)) %} {% endif %} -{% set accessible = [] %} +{%- set accessible = [] %} -{% if fields %} +{% if fields is not defined or fields is not same as(false) %} {% for field in fields %} -{% set accessible.field = 'true' %} +{% set accessible = accessible|merge({field: 'true'}) %} {% endfor %} {% endif %} -{% if fields and primaryKey %} -{% set accessible['*'] = 'true' %} +{%- if fields and primaryKey %} +{% set accessible = accessible|merge({'*': 'true'}) %} {% for field in primaryKey %} -{% set accessible.field = 'false' %} +{% set accessible = accessible|merge({field: 'false'}) %} {% endfor %} {% endif %} false])|raw }}]; + protected $_accessible = [{{ Bake.stringifyList(accessible, {'quotes': false})|raw }}]; {% endif %} {% if hidden %} @@ -64,7 +64,7 @@ class {{ name }} extends Entity * * @var array */ - protected $_hidden = [{{ Bake.stringifyList(hidden) }}]; + protected $_hidden = [{{ Bake.stringifyList(hidden)|raw }}]; {% endif %} {% if not accessible and not hidden %} diff --git a/src/Template/Bake/Model/table.twig b/src/Template/Bake/Model/table.twig new file mode 100644 index 000000000..fa7ea24c6 --- /dev/null +++ b/src/Template/Bake/Model/table.twig @@ -0,0 +1,124 @@ +{# +/** + * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * For full copyright and license information, please see the LICENSE.txt + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://cakephp.org CakePHP(tm) Project + * @since 2.0.0 + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +#} +{% set annotations = DocBlock.buildTableAnnotations(associations, associationInfo, behaviors, entity, namespace) %} +setTable('{{ table }}'); +{% endif %} +{% if displayField %} + $this->setDisplayField('{{ displayField }}'); +{% endif %} +{% if primaryKey %} +{% if primaryKey|count > 1 %} + $this->setPrimaryKey([{{ Bake.stringifyList(primaryKey, {'indent': false})|raw }}]); +{% else %} + $this->setPrimaryKey('{{ primaryKey|as_array|first }}'); +{% endif %} +{% endif %} +{% if behaviors %} + +{% endif %} +{% for behavior, behaviorData in behaviors %} + $this->addBehavior('{{ behavior }}'{{ (behaviorData ? (", [" ~ behaviorData|join(', ') ~ ']') : '')|raw }}); +{% endfor %} +{% if associations.belongsTo or associations.hasMany or associations.belongsToMany %} + +{% endif %} +{% for type, assocs in associations %} +{% for assoc in assocs %} +{% set alias = assoc.alias %} +{# https://www.drupal.org/node/1696912 #} +{#{% set assoc = assoc|unset('alias') %}#} + $this->{{ type }}('{{ alias }}', [{{ Bake.stringifyList(assoc, {'indent': 3})|raw }}]); +{% endfor %} +{% endfor %} + } +{% if validation %} + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator) + { +{% for field, rules in validation %} +{% set validationMethods = Bake.getValidationMethods(field, rules) %} +{% if validationMethods %} + $validator +{% for validationMethod in validationMethods %} +{% if loop.last %} +{% set validationMethod = validationMethod ~ ';' %} +{% endif %} + $validator + {{ validationMethod|raw }} +{% endfor %} +{% endif %} +{% endfor %} + return $validator; + } +{% endif %} +{% if rulesChecker %} + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules) + { +{% for field, rule in rulesChecker %} + $rules->add($rules->{{ rule.name }}(['{{ field }}']{{ (rule.extra ? (", '" ~ rule.extra ~ "'") : '')|raw }})); +{% endfor %} + + return $rules; + } +{% endif %} +{% if connection is not same as('default') %} + + /** + * Returns the database connection name to use by default. + * + * @return string + */ + public static function defaultConnectionName() + { + return '{{ connection }}'; + } +{% endif %} +} diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index 820fbd092..4df7ee9d6 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -208,6 +208,51 @@ public function getAssociatedTableAlias($modelObj, $assoc) return $association->getTarget()->getAlias(); } + public function getValidationMethods($field, $rules) + { + $validationMethods = []; + + foreach ($rules as $ruleName => $rule) { + if ($rule['rule'] && !isset($rule['provider'])) { + $validationMethods[] = sprintf("->%s('%s')", $rule['rule'], $field); + } elseif ($rule['rule'] && isset($rule['provider'])) { + $validationMethods[] = sprintf( + "->add('%s', '%s', ['rule' => '%s', 'provider' => '%s'])", + $field, + $ruleName, + $rule['rule'], + $rule['provider'] + ); + } + + if (isset($rule['allowEmpty'])) { + if (is_string($rule['allowEmpty'])) { + $validationMethods[] = sprintf( + "->allowEmpty('%s', '%s')", + $field, + $rule['allowEmpty'] + ); + } elseif ($rule['allowEmpty']) { + $validationMethods[] = sprintf( + "->allowEmpty('%s')", + $field + ); + } else { + $validationMethods[] = sprintf( + "->requirePresence('%s', 'create')", + $field + ); + $validationMethods[] = sprintf( + "->notEmpty('%s')", + $field + ); + } + } + } + + return $validationMethods; + } + /** * To be mocked elsewhere... * diff --git a/src/View/Helper/DocBlockHelper.php b/src/View/Helper/DocBlockHelper.php index 901b5e323..bab245d96 100644 --- a/src/View/Helper/DocBlockHelper.php +++ b/src/View/Helper/DocBlockHelper.php @@ -4,6 +4,7 @@ use Cake\Collection\Collection; use Cake\Database\Type; use Cake\ORM\Association; +use Cake\Utility\Inflector; use Cake\View\Helper; /** @@ -213,6 +214,40 @@ public function propertyHints(array $properties) return $lines; } + /** + * Build property, method, mixing annotations for table class. + * + * @param array $associations Associations list. + * @param array $associationInfo Association info. + * @param array $behaviors Behaviors list. + * @param string $entity Entity name. + * @param string $namespace Namespace. + * @return array + */ + public function buildTableAnnotations($associations, $associationInfo, $behaviors, $entity, $namespace) + { + $annotations = []; + foreach ($associations as $type => $assocs) { + foreach ($assocs as $assoc) { + $typeStr = Inflector::camelize($type); + $tableFqn = $associationInfo[$assoc['alias']]['targetFqn']; + $annotations[] = "@property {$tableFqn}|\Cake\ORM\Association\\{$typeStr} \${$assoc['alias']}"; + } + } + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} get(\$primaryKey, \$options = [])"; + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} newEntity(\$data = null, array \$options = [])"; + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity}[] newEntities(array \$data, array \$options = [])"; + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity}|bool save(\\Cake\\Datasource\\EntityInterface \$entity, \$options = [])"; + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} patchEntity(\\Cake\\Datasource\\EntityInterface \$entity, array \$data, array \$options = [])"; + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity}[] patchEntities(\$entities, array \$data, array \$options = [])"; + $annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} findOrCreate(\$search, callable \$callback = null, \$options = [])"; + foreach ($behaviors as $behavior => $behaviorData) { + $annotations[] = "@mixin \Cake\ORM\Behavior\\{$behavior}Behavior"; + } + + return $annotations; + } + /** * Inserts a value after a specific key in an associative array. * From 8f6a379ad6680450eab8d39c21e1435cc56892e0 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 19:13:48 +0530 Subject: [PATCH 17/44] Fix template. --- src/Template/Bake/tests/test_case.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Template/Bake/tests/test_case.twig b/src/Template/Bake/tests/test_case.twig index 8ba2d4fae..e4aa40368 100644 --- a/src/Template/Bake/tests/test_case.twig +++ b/src/Template/Bake/tests/test_case.twig @@ -57,7 +57,7 @@ class {{ className }}Test extends TestCase * * @var array */ - public $fixtures = [{{ Bake.stringifyList(fixtures)|raw }}]; + public $fixtures = [{{ Bake.stringifyList(fixtures|values)|raw }}]; {% endif %} {% if construction %} From c78ba5cac3ba77310097f1152c786efc5fd18ff8 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 19:44:31 +0530 Subject: [PATCH 18/44] More template fixes. --- src/Template/Bake/Model/entity.twig | 15 +-------------- src/Template/Bake/Model/table.twig | 4 ++-- src/Template/Bake/Plugin/composer.json.twig | 4 ++-- src/View/Helper/BakeHelper.php | 20 ++++++++++++++++++++ 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Template/Bake/Model/entity.twig b/src/Template/Bake/Model/entity.twig index 7ee23334b..79589e4e6 100644 --- a/src/Template/Bake/Model/entity.twig +++ b/src/Template/Bake/Model/entity.twig @@ -22,20 +22,7 @@ {% set annotations = annotations|merge(DocBlock.propertyHints(associationHintMap)) %} {% endif %} -{%- set accessible = [] %} - -{% if fields is not defined or fields is not same as(false) %} -{% for field in fields %} -{% set accessible = accessible|merge({field: 'true'}) %} -{% endfor %} -{% endif %} - -{%- if fields and primaryKey %} -{% set accessible = accessible|merge({'*': 'true'}) %} -{% for field in primaryKey %} -{% set accessible = accessible|merge({field: 'false'}) %} -{% endfor %} -{% endif %} +{%- set accessible = Bake.getFieldAccessibility(fields, primaryKey) %} Date: Sun, 22 Oct 2017 20:00:34 +0530 Subject: [PATCH 19/44] Fix tests. --- tests/TestCase/Shell/BakeShellTest.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/TestCase/Shell/BakeShellTest.php b/tests/TestCase/Shell/BakeShellTest.php index 7301e8cbc..7fc6bffc0 100644 --- a/tests/TestCase/Shell/BakeShellTest.php +++ b/tests/TestCase/Shell/BakeShellTest.php @@ -149,10 +149,15 @@ public function testMain() '- task', '- template', '- test', - '- twig_template', - '', - 'By using `cake bake [name]` you can invoke a specific bake task.', ]; + + if (Plugin::loaded('WyriHaximus/TwigView')) { + $expected[] = '- twig_template'; + } + + $expected[] = ''; + $expected[] = 'By using `cake bake [name]` you can invoke a specific bake task.'; + $this->assertSame($expected, $output); } @@ -205,8 +210,10 @@ public function testLoadTasksCoreAndApp() 'Bake.Template', 'Controller', 'CustomController', - 'WyriHaximus/TwigView.TwigTemplate', ]; + if (Plugin::loaded('WyriHaximus/TwigView')) { + $expected[] = 'WyriHaximus/TwigView.TwigTemplate'; + } sort($this->Shell->tasks); sort($expected); $this->assertEquals($expected, $this->Shell->tasks); From b1d4e40036439bafc9dafa2ffd6856485f7fdb8c Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 20:21:10 +0530 Subject: [PATCH 20/44] Fix "since" tag. --- src/Template/Bake/Middleware/middleware.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Template/Bake/Middleware/middleware.twig b/src/Template/Bake/Middleware/middleware.twig index 7ef906852..d7e80c6a3 100644 --- a/src/Template/Bake/Middleware/middleware.twig +++ b/src/Template/Bake/Middleware/middleware.twig @@ -9,7 +9,7 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @since 1.3.6 + * @since 2.0.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} From 4757d90d7c5383c04402c459164212b04ec066ed Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 20:27:11 +0530 Subject: [PATCH 21/44] Add docblocks. --- src/View/Helper/BakeHelper.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index 77016c215..4658e1294 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -208,6 +208,13 @@ public function getAssociatedTableAlias($modelObj, $assoc) return $association->getTarget()->getAlias(); } + /** + * Get validation methods data. + * + * @param string $field Field name. + * @param array $rules Validation rules list. + * @return array + */ public function getValidationMethods($field, $rules) { $validationMethods = []; @@ -253,6 +260,13 @@ public function getValidationMethods($field, $rules) return $validationMethods; } + /** + * Get field accessibility data. + * + * @param mixed $fields Fields list. + * @param mixed $primaryKey Primary key. + * @return array + */ public function getFieldAccessibility($fields = null, $primaryKey = null) { $accessible = []; From d2c3b1b439d2755417c41c4445a0beaa39fb0f3c Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 23:16:49 +0530 Subject: [PATCH 22/44] Rename method. --- src/Template/Bake/Element/form.twig | 4 ++-- src/View/Helper/BakeHelper.php | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Template/Bake/Element/form.twig b/src/Template/Bake/Element/form.twig index 320072f35..bcc667a72 100644 --- a/src/Template/Bake/Element/form.twig +++ b/src/Template/Bake/Element/form.twig @@ -45,14 +45,14 @@ Form->control('{{ field }}', ['options' => ${{ keyFields.field }}, 'empty' => true]); {% else %} echo $this->Form->control('{{ field }}', ['options' => ${{ keyFields.field }}]); {% endif %} {% elseif field in ['created', 'modified', 'updated'] %} -{% set fieldData = Bake.fieldData(field, schema) %} +{% set fieldData = Bake.columnData(field, schema) %} {% if fieldData.type|in_array(['date', 'datetime', 'time']) and fieldData.null %} echo $this->Form->control('{{ field }}', ['empty' => true]); {% else %} diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index 4658e1294..d46b59472 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -189,7 +189,14 @@ public function filterFields($fields, $schema, $takeFields = [], $filterTypes = return $fields; } - public function fieldData($field, $schema) + /** + * Get column data from schema. + * + * @param string $field Field name. + * @param Cake\Database\Schema\TableSchemaAwareInterface $schema Schema. + * @return array + */ + public function columnData($field, $schema) { return $schema->column($field); } From 39d0717ee0eb6520ceddd037b5723f6fa7d90283 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 23:35:42 +0530 Subject: [PATCH 23/44] Fix templates. --- src/Template/Bake/Model/table.twig | 9 +++++---- src/Template/Bake/Plugin/composer.json.twig | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Template/Bake/Model/table.twig b/src/Template/Bake/Model/table.twig index e50355af0..ad365c561 100644 --- a/src/Template/Bake/Model/table.twig +++ b/src/Template/Bake/Model/table.twig @@ -58,10 +58,11 @@ class {{ name }}Table extends Table {% endif %} {% for type, assocs in associations %} {% for assoc in assocs %} -{% set alias = assoc.alias %} -{# https://www.drupal.org/node/1696912 #} -{#{% set assoc = assoc|unset('alias') %}#} - $this->{{ type }}('{{ alias }}', [{{ Bake.stringifyList(assoc, {'indent': 3})|raw }}]); +{% set assocData = [] %} +{% for key, val in assoc if key is not same as('alias') %} +{% set assocData = assocData|merge({(key): val}) %} +{% endfor %} + $this->{{ type }}('{{ assoc.alias }}', [{{ Bake.stringifyList(assocData, {'indent': 3})|raw }}]); {% endfor %} {% endfor %} } diff --git a/src/Template/Bake/Plugin/composer.json.twig b/src/Template/Bake/Plugin/composer.json.twig index b8980ae54..a573d8394 100644 --- a/src/Template/Bake/Plugin/composer.json.twig +++ b/src/Template/Bake/Plugin/composer.json.twig @@ -13,7 +13,7 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} -{% set namespace = namespace|replace('\\', '\\\\') %} +{% set namespace = namespace|replace({'\\': '\\\\'}) %} { "name": "{{ package }}", "description": "{{ plugin }} plugin for CakePHP", @@ -27,12 +27,12 @@ }, "autoload": { "psr-4": { - "{{ namespace|raw }}\\": "src" + "{{ namespace }}\\": "src" } }, "autoload-dev": { "psr-4": { - "{{ namespace|raw }}\\Test\\": "tests", + "{{ namespace }}\\Test\\": "tests", "Cake\\Test\\": "./vendor/cakephp/cakephp/tests" } } From d1d6bc834034d4e26eb83584ef28d0691409c0bd Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 23:38:00 +0530 Subject: [PATCH 24/44] Fix "since" tags. --- src/Template/Bake/Element/Controller/logout.twig | 2 +- src/Template/Bake/Element/Controller/view.twig | 2 +- src/Template/Bake/Plugin/webroot/empty.twig | 2 +- src/Template/Bake/Shell/shell.twig | 2 +- src/Template/Bake/Template/edit.twig | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Template/Bake/Element/Controller/logout.twig b/src/Template/Bake/Element/Controller/logout.twig index dd75231ad..facbd2fe6 100644 --- a/src/Template/Bake/Element/Controller/logout.twig +++ b/src/Template/Bake/Element/Controller/logout.twig @@ -9,7 +9,7 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @since 0.1.0 + * @since 2.0.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} diff --git a/src/Template/Bake/Element/Controller/view.twig b/src/Template/Bake/Element/Controller/view.twig index 5b48d8c3c..7374335b1 100644 --- a/src/Template/Bake/Element/Controller/view.twig +++ b/src/Template/Bake/Element/Controller/view.twig @@ -9,7 +9,7 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @since 0.1.0 + * @since 2.0.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} diff --git a/src/Template/Bake/Plugin/webroot/empty.twig b/src/Template/Bake/Plugin/webroot/empty.twig index 69fe6e5ba..e48dbb3c0 100644 --- a/src/Template/Bake/Plugin/webroot/empty.twig +++ b/src/Template/Bake/Plugin/webroot/empty.twig @@ -9,7 +9,7 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @since 0.1.0 + * @since 2.0.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} \ No newline at end of file diff --git a/src/Template/Bake/Shell/shell.twig b/src/Template/Bake/Shell/shell.twig index 037428876..c0c16b8e9 100644 --- a/src/Template/Bake/Shell/shell.twig +++ b/src/Template/Bake/Shell/shell.twig @@ -9,7 +9,7 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @since 0.1.0 + * @since 2.0.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} diff --git a/src/Template/Bake/Template/edit.twig b/src/Template/Bake/Template/edit.twig index eab98d3fa..de628d0e9 100644 --- a/src/Template/Bake/Template/edit.twig +++ b/src/Template/Bake/Template/edit.twig @@ -9,7 +9,7 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project - * @since 0.1.0 + * @since 2.0.0 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} From 753f7acb5c70a825002b642f3f08f48f4851ebaa Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 23:40:31 +0530 Subject: [PATCH 25/44] Add docblock. --- src/View/BakeTwigView.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index 885d4afae..0cbf57f9a 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -89,6 +89,12 @@ public function render($view = null, $layout = null) return $this->Blocks->get('content'); } + /** + * Inflect string to variable name form. + * + * @param string $string Input string + * @return string + */ public function variableName($string) { return $this->_variableName($string); From 8bdaabd6625ba92e17a3a31e50afc0fa8183896b Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 23:47:33 +0530 Subject: [PATCH 26/44] Remove unneeded method. --- src/Template/Bake/Element/Controller/add.twig | 2 +- src/Template/Bake/Element/Controller/edit.twig | 2 +- src/View/BakeTwigView.php | 13 ------------- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Template/Bake/Element/Controller/add.twig b/src/Template/Bake/Element/Controller/add.twig index ddceaa9b8..c5d858b94 100644 --- a/src/Template/Bake/Element/Controller/add.twig +++ b/src/Template/Bake/Element/Controller/add.twig @@ -36,7 +36,7 @@ {% set associations = associations|merge(Bake.aliasExtractor(modelObj, 'BelongsToMany')) %} {% for assoc in associations %} {% set otherName = Bake.getAssociatedTableAlias(modelObj, assoc) %} -{% set otherPlural = _view.variableName(otherName) %} +{% set otherPlural = otherName|variable %} ${{ otherPlural }} = $this->{{ currentModelName }}->{{ otherName }}->find('list', ['limit' => 200]); {% set compact = compact|merge(["'" ~ otherPlural ~ "'"]) %} {% endfor %} diff --git a/src/Template/Bake/Element/Controller/edit.twig b/src/Template/Bake/Element/Controller/edit.twig index 4b0db617f..9f60e1831 100644 --- a/src/Template/Bake/Element/Controller/edit.twig +++ b/src/Template/Bake/Element/Controller/edit.twig @@ -40,7 +40,7 @@ } {% for assoc in belongsTo|merge(belongsToMany) %} {% set otherName = Bake.getAssociatedTableAlias(modelObj, assoc) %} -{% set otherPlural = _view.variableName(otherName) %} +{% set otherPlural = otherName|variable %} ${{ otherPlural }} = $this->{{ currentModelName }}->{{ otherName }}->find('list', ['limit' => 200]); {% set compact = compact|merge(["'" ~ otherPlural ~ "'"]) %} {% endfor %} diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index 0cbf57f9a..f7d44c8fa 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -15,12 +15,10 @@ namespace Bake\View; use Cake\Core\Configure; -use Cake\Core\ConventionsTrait; use WyriHaximus\TwigView\View\TwigView; class BakeTwigView extends TwigView { - use ConventionsTrait; /** * Initialize view @@ -89,17 +87,6 @@ public function render($view = null, $layout = null) return $this->Blocks->get('content'); } - /** - * Inflect string to variable name form. - * - * @param string $string Input string - * @return string - */ - public function variableName($string) - { - return $this->_variableName($string); - } - /** * Wrapper for creating and dispatching events. * From e10eb28fc95b6682af6e7f973dd63329d5543ff9 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 22 Oct 2017 23:50:32 +0530 Subject: [PATCH 27/44] Use extension variable. --- src/View/BakeTwigView.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index f7d44c8fa..45a753245 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -65,7 +65,7 @@ public function render($view = null, $layout = null) { $viewFileName = $this->_getViewFileName($view); $templateEventName = str_replace( - ['.ctp', DS], + [$this->_ext, DS], ['', '.'], explode('Template' . DS . 'Bake' . DS, $viewFileName)[1] ); From 1ba9fe3810134c0caf95f653e43ee088ff32a040 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 23 Oct 2017 00:11:29 +0530 Subject: [PATCH 28/44] Fix error on PHP 7.2. --- src/Template/Bake/Model/table.ctp | 2 +- src/Template/Bake/Model/table.twig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Template/Bake/Model/table.ctp b/src/Template/Bake/Model/table.ctp index 2b1934ce8..8b73263e9 100644 --- a/src/Template/Bake/Model/table.ctp +++ b/src/Template/Bake/Model/table.ctp @@ -69,7 +69,7 @@ class <%= $name %>Table extends Table $this->setDisplayField('<%= $displayField %>'); <% endif %> <% if (!empty($primaryKey)): %> -<% if (count($primaryKey) > 1): %> +<% if (is_array($primaryKey) && count($primaryKey) > 1): %> $this->setPrimaryKey([<%= $this->Bake->stringifyList((array)$primaryKey, ['indent' => false]) %>]); <% else: %> $this->setPrimaryKey('<%= current((array)$primaryKey) %>'); diff --git a/src/Template/Bake/Model/table.twig b/src/Template/Bake/Model/table.twig index ad365c561..c0b3820a5 100644 --- a/src/Template/Bake/Model/table.twig +++ b/src/Template/Bake/Model/table.twig @@ -41,7 +41,7 @@ class {{ name }}Table extends Table $this->setDisplayField('{{ displayField }}'); {% endif %} {% if primaryKey %} -{% if primaryKey|count > 1 %} +{% if primaryKey is iterable and primaryKey|count > 1 %} $this->setPrimaryKey([{{ Bake.stringifyList(primaryKey, {'indent': false})|raw }}]); {% else %} $this->setPrimaryKey('{{ primaryKey|as_array|first }}'); From 72973f4841f9fabaa3dd7e8b0e1d8cc2c641c589 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 23 Oct 2017 00:41:18 +0530 Subject: [PATCH 29/44] Update docblock. --- src/View/Helper/BakeHelper.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/View/Helper/BakeHelper.php b/src/View/Helper/BakeHelper.php index d46b59472..87c613570 100644 --- a/src/View/Helper/BakeHelper.php +++ b/src/View/Helper/BakeHelper.php @@ -167,6 +167,8 @@ public function classInfo($class, $type, $suffix) * * @param array $fields Fields list. * @param \Cake\Datasource\SchemaInterface $schema Schema instance. + * @param array $takeFields Take fields. + * @param array $filterTypes Filter field types. * @return \Cake\Collection\CollectionInterface */ public function filterFields($fields, $schema, $takeFields = [], $filterTypes = ['binary']) From fc910c64d9d14f59a212d795d6d7a92556c385f1 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 23 Oct 2017 11:03:57 +0530 Subject: [PATCH 30/44] Use string interpolation. --- src/Template/Bake/Element/Controller/add.twig | 4 ++-- src/Template/Bake/Element/Controller/edit.twig | 4 ++-- src/Template/Bake/Model/table.twig | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Template/Bake/Element/Controller/add.twig b/src/Template/Bake/Element/Controller/add.twig index c5d858b94..969ada13c 100644 --- a/src/Template/Bake/Element/Controller/add.twig +++ b/src/Template/Bake/Element/Controller/add.twig @@ -13,7 +13,7 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} -{% set compact = [("'" ~ singularName ~ "'")] %} +{% set compact = ["'#{singularName}'"] %} /** * Add method @@ -38,7 +38,7 @@ {% set otherName = Bake.getAssociatedTableAlias(modelObj, assoc) %} {% set otherPlural = otherName|variable %} ${{ otherPlural }} = $this->{{ currentModelName }}->{{ otherName }}->find('list', ['limit' => 200]); -{% set compact = compact|merge(["'" ~ otherPlural ~ "'"]) %} +{% set compact = compact|merge(["'#{otherPlural}'"]) %} {% endfor %} $this->set(compact({{ compact|join(', ')|raw }})); $this->set('_serialize', ['{{ singularName }}']); diff --git a/src/Template/Bake/Element/Controller/edit.twig b/src/Template/Bake/Element/Controller/edit.twig index 9f60e1831..e64bb5bdd 100644 --- a/src/Template/Bake/Element/Controller/edit.twig +++ b/src/Template/Bake/Element/Controller/edit.twig @@ -15,7 +15,7 @@ #} {% set belongsTo = Bake.aliasExtractor(modelObj, 'BelongsTo') %} {% set belongsToMany = Bake.aliasExtractor(modelObj, 'belongsToMany') %} -{% set compact = ["'" ~ singularName ~ "'"] %} +{% set compact = ["'#{singularName}'"] %} /** * Edit method @@ -42,7 +42,7 @@ {% set otherName = Bake.getAssociatedTableAlias(modelObj, assoc) %} {% set otherPlural = otherName|variable %} ${{ otherPlural }} = $this->{{ currentModelName }}->{{ otherName }}->find('list', ['limit' => 200]); -{% set compact = compact|merge(["'" ~ otherPlural ~ "'"]) %} +{% set compact = compact|merge(["'#{otherPlural}'"]) %} {% endfor %} $this->set(compact({{ compact|join(', ')|raw }})); $this->set('_serialize', ['{{ singularName }}']); diff --git a/src/Template/Bake/Model/table.twig b/src/Template/Bake/Model/table.twig index c0b3820a5..a6879a5b7 100644 --- a/src/Template/Bake/Model/table.twig +++ b/src/Template/Bake/Model/table.twig @@ -104,7 +104,7 @@ class {{ name }}Table extends Table public function buildRules(RulesChecker $rules) { {% for field, rule in rulesChecker %} - $rules->add($rules->{{ rule.name }}(['{{ field }}']{{ (rule.extra ? (", '" ~ rule.extra ~ "'") : '')|raw }})); + $rules->add($rules->{{ rule.name }}(['{{ field }}']{{ (rule.extra ? (", '#{rule.extra}'") : '')|raw }})); {% endfor %} return $rules; From 9ece322d305fb7ce537a758c35b8a8c4392eff1c Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 23 Oct 2017 19:47:01 +0530 Subject: [PATCH 31/44] Remove duplicate helper loading. --- src/View/BakeTwigView.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/View/BakeTwigView.php b/src/View/BakeTwigView.php index 45a753245..502daa3e2 100644 --- a/src/View/BakeTwigView.php +++ b/src/View/BakeTwigView.php @@ -35,9 +35,6 @@ public function initialize() Configure::write('App.paths.templates', $paths); } - $this->loadHelper('Bake.Bake'); - $this->loadHelper('Bake.DocBlock'); - parent::initialize(); } From 830d36e06eae86ca98518e3716c777761b0b1afc Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 24 Oct 2017 19:11:59 +0530 Subject: [PATCH 32/44] Use "merge" instead of "push". --- src/Template/Bake/Element/form.twig | 2 +- src/Template/Bake/Template/index.twig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Template/Bake/Element/form.twig b/src/Template/Bake/Element/form.twig index bcc667a72..379646f6a 100644 --- a/src/Template/Bake/Element/form.twig +++ b/src/Template/Bake/Element/form.twig @@ -32,7 +32,7 @@ {% if details.controller != _view.name && done not in details.controller %}
  • Html->link(__('List {{ _view._pluralHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'index']) ?>
  • Html->link(__('New {{ _view._singularHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'add']) ?>
  • -{% done|push(details.controller) %} +{% set done = done|merge([details.controller]) %} {% endif %} {% endfor %} {% endfor %} diff --git a/src/Template/Bake/Template/index.twig b/src/Template/Bake/Template/index.twig index b1edbc22d..8b03dd13a 100644 --- a/src/Template/Bake/Template/index.twig +++ b/src/Template/Bake/Template/index.twig @@ -30,7 +30,7 @@ {% if details.navLink and details.controller != _view.name and details.controller not in done %}
  • Html->link(__('List {{ _view._pluralHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'index']) ?>
  • Html->link(__('New {{ _view._singularHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'add']) ?>
  • -{% done|push(details.controller) %} +{% set done = done|merge([details.controller]) %} {% endif %} {% endfor %} {% endfor %} From b21381518f633e8d4e7073cd76eb944a3ac57b49 Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 24 Oct 2017 19:20:02 +0530 Subject: [PATCH 33/44] Fix logic operators --- src/Template/Bake/Element/form.twig | 2 +- src/Template/Bake/Template/index.twig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Template/Bake/Element/form.twig b/src/Template/Bake/Element/form.twig index 379646f6a..27d6ed832 100644 --- a/src/Template/Bake/Element/form.twig +++ b/src/Template/Bake/Element/form.twig @@ -29,7 +29,7 @@ {% set done = [] %} {% for type, data in associations %} {% for alias, details in data %} -{% if details.controller != _view.name && done not in details.controller %} +{% if details.controller is not same as(_view.name) and details.controller not in done %}
  • Html->link(__('List {{ _view._pluralHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'index']) ?>
  • Html->link(__('New {{ _view._singularHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'add']) ?>
  • {% set done = done|merge([details.controller]) %} diff --git a/src/Template/Bake/Template/index.twig b/src/Template/Bake/Template/index.twig index 8b03dd13a..08cbbd439 100644 --- a/src/Template/Bake/Template/index.twig +++ b/src/Template/Bake/Template/index.twig @@ -27,7 +27,7 @@ {% set done = [] %} {% for type, data in associations %} {% for alias, details in data %} -{% if details.navLink and details.controller != _view.name and details.controller not in done %} +{% if details.navLink and details.controller is not same as(_view.name) and details.controller not in done %}
  • Html->link(__('List {{ _view._pluralHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'index']) ?>
  • Html->link(__('New {{ _view._singularHumanName(alias) }}'), ['controller' => '{{ details.controller }}', 'action' => 'add']) ?>
  • {% set done = done|merge([details.controller]) %} From b99c5b861d134afca93a69c18bde7a0914863464 Mon Sep 17 00:00:00 2001 From: ADmad Date: Tue, 24 Oct 2017 23:15:41 +0530 Subject: [PATCH 34/44] Add / fix templates for template generation. --- src/Template/Bake/Element/form.twig | 26 ++-- src/Template/Bake/Template/add.twig | 2 +- src/Template/Bake/Template/edit.twig | 2 +- src/Template/Bake/Template/index.twig | 44 ++---- src/Template/Bake/Template/view.twig | 137 ++++++++++++++++++ src/View/Helper/BakeHelper.php | 71 ++++++++- .../TestCase/Shell/Task/TemplateTaskTest.php | 1 + 7 files changed, 236 insertions(+), 47 deletions(-) create mode 100644 src/Template/Bake/Template/view.twig diff --git a/src/Template/Bake/Element/form.twig b/src/Template/Bake/Element/form.twig index 27d6ed832..a789362fb 100644 --- a/src/Template/Bake/Element/form.twig +++ b/src/Template/Bake/Element/form.twig @@ -13,25 +13,25 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} -{% set fields = Bake.filterFields(fields, schema) %} +{% set fields = Bake.filterFields(fields, schema, modelObject) %}