diff --git a/CHANGELOG.md b/CHANGELOG.md index 78a5fc09..8aaa7c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). In order to read more about upgrading and BC breaks have a look at the [UPGRADE Document](UPGRADE.md). -## 2.0.1 +## 2.1.0 + +### Added + ++ [#210](https://github.com/luyadev/luya-module-cms/pull/210) Added new Active Query Select Injector class. ### Fixed diff --git a/composer.json b/composer.json index b0379927..1a3c2414 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "issues" : "https://github.com/luyadev/luya-module-cms/issues" }, "require-dev" : { - "luyadev/luya-testsuite" : "^1.0@dev", + "luyadev/luya-testsuite" : "^1.0", "twbs/bootstrap": "~4.3.0", "unglue/client": "^1.3" }, diff --git a/composer.lock b/composer.lock index 465f47e6..b167eaaa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8732765d38b3e8f73427cd66371eb57f", + "content-hash": "8b1755a4ec83a020a40f25556f6a0779", "packages": [], "packages-dev": [ { @@ -595,16 +595,16 @@ }, { "name": "luyadev/luya-testsuite", - "version": "dev-master", + "version": "1.0.17.2", "source": { "type": "git", "url": "https://github.com/luyadev/luya-testsuite.git", - "reference": "08a5c0cfc5480d8765720f1fa9005c08502a44b5" + "reference": "828c9b6de876fd60ec81ad105b1dc5b45eb24ee2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/luyadev/luya-testsuite/zipball/08a5c0cfc5480d8765720f1fa9005c08502a44b5", - "reference": "08a5c0cfc5480d8765720f1fa9005c08502a44b5", + "url": "https://api.github.com/repos/luyadev/luya-testsuite/zipball/828c9b6de876fd60ec81ad105b1dc5b45eb24ee2", + "reference": "828c9b6de876fd60ec81ad105b1dc5b45eb24ee2", "shasum": "" }, "require": { @@ -644,7 +644,7 @@ "module", "php" ], - "time": "2019-06-19T15:58:38+00:00" + "time": "2019-06-26T13:55:17+00:00" }, { "name": "myclabs/deep-copy", @@ -2071,7 +2071,7 @@ }, { "name": "Gert de Pagter", - "email": "backendtea@gmail.com" + "email": "BackEndTea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", @@ -2390,16 +2390,16 @@ }, { "name": "yiisoft/yii2", - "version": "2.0.21", + "version": "2.0.22", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-framework.git", - "reference": "7e4622252c5f272373e1339a47d331e4a55e9591" + "reference": "417299927ed14adcd51c69a9d75311c5fc33d227" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/7e4622252c5f272373e1339a47d331e4a55e9591", - "reference": "7e4622252c5f272373e1339a47d331e4a55e9591", + "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/417299927ed14adcd51c69a9d75311c5fc33d227", + "reference": "417299927ed14adcd51c69a9d75311c5fc33d227", "shasum": "" }, "require": { @@ -2486,7 +2486,7 @@ "framework", "yii2" ], - "time": "2019-06-18T14:25:08+00:00" + "time": "2019-07-02T20:28:40+00:00" }, { "name": "yiisoft/yii2-composer", @@ -2673,9 +2673,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "luyadev/luya-testsuite": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": [], diff --git a/src/admin/apis/AdminController.php b/src/admin/apis/AdminController.php index 1713e3f9..6f5204c9 100644 --- a/src/admin/apis/AdminController.php +++ b/src/admin/apis/AdminController.php @@ -203,7 +203,7 @@ public function actionControllerActions($module, $controller) /** * Get actions for a given controller. - * + * * @param object $controller * @since 2.0.0 * @see Replace with luya core object helper diff --git a/src/admin/apis/NavController.php b/src/admin/apis/NavController.php index e71ffb68..362f0764 100644 --- a/src/admin/apis/NavController.php +++ b/src/admin/apis/NavController.php @@ -343,16 +343,16 @@ public function actionCreateModule() } $create = $model->createModule( - $parentNavId, - $navContainerId, - $this->postArg('lang_id'), - $this->postArg('title'), - $this->postArg('alias'), - $this->postArg('module_name'), + $parentNavId, + $navContainerId, + $this->postArg('lang_id'), + $this->postArg('title'), + $this->postArg('alias'), + $this->postArg('module_name'), $this->postArg('description'), - $this->postArg('controller_name'), - $this->postArg('action_name'), - $this->postArg('action_params', []) + $this->postArg('controller_name'), + $this->postArg('action_name'), + $this->postArg('action_params', []) ); if (is_array($create)) { Yii::$app->response->statusCode = 422; @@ -368,12 +368,12 @@ public function actionCreateModuleItem() $create = $model->createModuleItem( $this->postArg('nav_id'), $this->postArg('lang_id'), - $this->postArg('title'), - $this->postArg('alias'), + $this->postArg('title'), + $this->postArg('alias'), $this->postArg('module_name'), $this->postArg('description'), - $this->postArg('controller_name'), - $this->postArg('action_name'), + $this->postArg('controller_name'), + $this->postArg('action_name'), $this->postArg('action_params', []) ); if (is_array($create)) { diff --git a/src/admin/apis/RedirectController.php b/src/admin/apis/RedirectController.php index 1a8999ed..3fe707ad 100644 --- a/src/admin/apis/RedirectController.php +++ b/src/admin/apis/RedirectController.php @@ -19,9 +19,9 @@ class RedirectController extends \luya\admin\ngrest\base\Api /** * Find a redirect object for a given path info. - * + * * An example using path would be: Yii::$app->request->pathInfo - * + * * url: https://example.com/hello/world * path: hello/world * diff --git a/src/admin/importers/BlockImporter.php b/src/admin/importers/BlockImporter.php index 5595dfd1..cd7d8b52 100644 --- a/src/admin/importers/BlockImporter.php +++ b/src/admin/importers/BlockImporter.php @@ -119,7 +119,6 @@ protected function handleBlockDefintionInDirectories(array $directories, $blockD { $results = []; foreach ($directories as $directoryPath) { - $path = rtrim($directoryPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ltrim($blockDefinition, DIRECTORY_SEPARATOR); $path = $this->replaceDsSeparator($path); diff --git a/src/admin/importers/CmslayoutImporter.php b/src/admin/importers/CmslayoutImporter.php index b5ce940b..51d9fa69 100644 --- a/src/admin/importers/CmslayoutImporter.php +++ b/src/admin/importers/CmslayoutImporter.php @@ -169,7 +169,7 @@ protected function importLayoutFile($file, $aliased) } return $layoutItem->id; - } + } // add item into the database table $data = new Layout(); diff --git a/src/admin/messages/ru/cmsadmin.php b/src/admin/messages/ru/cmsadmin.php index d0b016dc..800f5e37 100644 --- a/src/admin/messages/ru/cmsadmin.php +++ b/src/admin/messages/ru/cmsadmin.php @@ -50,7 +50,7 @@ 'menu_group_item_env_container' => 'Контейнеры', 'menu_group_item_env_layouts' => 'Макеты', 'menu_group_elements' => 'Элементы контента', - 'menu_group_item_elements_blocks' => 'Блоки', + 'menu_group_item_elements_blocks' => 'Блоки', 'menu_group_item_elements_group' => 'Группы блоков', 'btn_abort' => 'Отмена', 'btn_refresh' => 'Обновить', diff --git a/src/base/BlockInterface.php b/src/base/BlockInterface.php index f0d3ed91..fb990c5a 100644 --- a/src/base/BlockInterface.php +++ b/src/base/BlockInterface.php @@ -212,17 +212,17 @@ public function getIsDirtyDialogEnabled(); /** * This method is called whenever a block inside a placeholder is rendered. - * + * * This allows you to change the render behavior of every block inside a placeholder. An example of * adding a wrapper div to the iteration: - * + * * ```php * public function placeholderRenderIteration(BlockInterface $block) * { * return '
'.$block->renderFrontend().'
'; * } * ``` - * + * * This also allows you to determined whether the block should be rendered or not as the response is the content * of the block inside the placholder. * diff --git a/src/base/InternalBaseBlock.php b/src/base/InternalBaseBlock.php index 3aff7917..c0bedf35 100644 --- a/src/base/InternalBaseBlock.php +++ b/src/base/InternalBaseBlock.php @@ -433,7 +433,8 @@ public function getExtraValue($key, $default = false) $this->getExtraVarValues(); $this->_assignExtraVars = true; } - return (isset($this->_extraVars[$key])) ? $this->_extraVars[$key] : $default; + + return isset($this->_extraVars[$key]) ? $this->_extraVars[$key] : $default; } /** @@ -483,7 +484,7 @@ public function addVar(array $varConfig, $append = false) */ public function getConfigPlaceholdersExport() { - $array = (array_key_exists('placeholders', $this->config())) ? $this->config()['placeholders'] : []; + $array = array_key_exists('placeholders', $this->config()) ? $this->config()['placeholders'] : []; $holders = []; @@ -505,7 +506,7 @@ public function getConfigPlaceholdersExport() */ public function getConfigPlaceholdersByRowsExport() { - $array = (array_key_exists('placeholders', $this->config())) ? $this->config()['placeholders'] : []; + $array = array_key_exists('placeholders', $this->config()) ? $this->config()['placeholders'] : []; $rows = []; diff --git a/src/frontend/Bootstrap.php b/src/frontend/Bootstrap.php index 0c655bd9..f1b697e0 100644 --- a/src/frontend/Bootstrap.php +++ b/src/frontend/Bootstrap.php @@ -46,7 +46,6 @@ public function bootstrap($app) // handle not found exceptions $app->errorHandler->on(ErrorHandler::EVENT_BEFORE_EXCEPTION_RENDER, function (ErrorHandlerExceptionRenderEvent $event) use ($app) { if ($event->exception instanceof NotFoundHttpException) { - $errorPageNavId = Config::get(Config::HTTP_EXCEPTION_NAV_ID, 0); /** @var $item Item */ $item = $app->menu->find()->with(['hidden'])->where(['nav_id' => $errorPageNavId])->one(); diff --git a/src/frontend/controllers/DefaultController.php b/src/frontend/controllers/DefaultController.php index 59460100..36bdac3a 100644 --- a/src/frontend/controllers/DefaultController.php +++ b/src/frontend/controllers/DefaultController.php @@ -112,6 +112,4 @@ protected function findInternalRedirect() return false; } - - } diff --git a/src/injectors/ActiveQueryRadioInjector.php b/src/injectors/ActiveQueryRadioInjector.php index bcd19e6a..2af39aab 100644 --- a/src/injectors/ActiveQueryRadioInjector.php +++ b/src/injectors/ActiveQueryRadioInjector.php @@ -2,32 +2,30 @@ namespace luya\cms\injectors; -use yii\db\ActiveQueryInterface; -use yii\data\ActiveDataProvider; use luya\admin\base\TypesInterface; /** - * Checkboxes from an ActiveQuery. + * Radio List from an ActiveQuery. * - * Generates a checkbox selection from an active query interface and returns the + * Generates a radio selection from an active query interface and returns the * models via the ActiveDataProvider. * * An example for the injector config: * * ```php - * new ActiveQueryCheckboxInjector([ + * new ActiveQueryRadioInjector([ * 'query' => \newsadmin\models\Article::find()->where(['cat_id' => 1]), * 'label' => 'title', // This attribute from the model is used to render the admin block dropdown selection. * ]); * ``` * - * In order to configure the ActiveQueryCheckboxInjector used the {{\luya\cms\base\InternalBaseBlock::injectors}} method: + * In order to configure the ActiveQueryRadioInjector used the {{\luya\cms\base\InternalBaseBlock::injectors}} method: * * ```php * public function injectors() * { * return [ - * 'theData' => new ActiveQueryCheckboxInjector([ + * 'theData' => new ActiveQueryRadioInjector([ * 'query' => News::find()->where(['is_deleted' => 0]), * 'label' => function($model) { * return $model->title . " - " . $model->description; diff --git a/src/injectors/ActiveQuerySelectInjector.php b/src/injectors/ActiveQuerySelectInjector.php new file mode 100644 index 00000000..a031e185 --- /dev/null +++ b/src/injectors/ActiveQuerySelectInjector.php @@ -0,0 +1,61 @@ + \newsadmin\models\Article::find()->where(['cat_id' => 1]), + * 'label' => 'title', // This attribute from the model is used to render the admin block dropdown selection. + * ]); + * ``` + * + * In order to configure the ActiveQuerySelectInjector used the {{\luya\cms\base\InternalBaseBlock::injectors}} method: + * + * ```php + * public function injectors() + * { + * return [ + * 'theData' => new ActiveQuerySelectInjector([ + * 'query' => News::find()->where(['is_deleted' => 0]), + * 'label' => function($model) { + * return $model->title . " - " . $model->description; + * }, + * ]); + * ]; + * } + * ``` + * + * @property \yii\db\ActiveQueryInterface $query The ActiveQuery object + * + * @author Basil Suter + * @since 2.1.0 + */ +class ActiveQuerySelectInjector extends BaseActiveQueryInjector +{ + /** + * @inheritdoc + */ + public function setup() + { + // injecto the config + $this->setContextConfig([ + 'var' => $this->varName, + 'type' => TypesInterface::TYPE_SELECT, + 'label' => $this->varLabel, + 'options' => $this->getQueryData(), + ]); + + // provide the extra data + $this->context->addExtraVar($this->varName, $this->getExtraAssignSingleData()); + } +} diff --git a/src/injectors/BaseActiveQueryInjector.php b/src/injectors/BaseActiveQueryInjector.php index d3c911db..b8a9d8fb 100644 --- a/src/injectors/BaseActiveQueryInjector.php +++ b/src/injectors/BaseActiveQueryInjector.php @@ -41,13 +41,29 @@ abstract class BaseActiveQueryInjector extends BaseBlockInjector * * Define the active query which will be used to retrieve data must be an instance of {{\yii\db\ActiveQueryInterface}}. * - * @param \yii\db\ActiveQueryInterface $query The query provider for the {{yii\data\ActiveDataProvider}}. + * @param ActiveQueryInterface $query The query provider for the {{yii\data\ActiveDataProvider}}. */ public function setQuery(ActiveQueryInterface $query) { $this->_query = $query; } + + /** + * Get the Active Query Object. + * + * @return ActiveQueryInterface + * @since 2.1.0 + */ + protected function getQuery() + { + return $this->_query; + } + /** + * Get an array with options + * + * @return array + */ protected function getQueryData() { $provider = new ActiveDataProvider([ @@ -65,9 +81,15 @@ protected function getQueryData() } $data[] = ['value' => $model->primaryKey, 'label' => $label]; } + return $data; } + /** + * Get the Active Record models from the stored block values + * + * @return \yii\db\ActiveRecord[] + */ protected function getExtraAssignArrayData() { $ids = ArrayHelper::getColumn($this->getContextConfigValue($this->varName, []), 'value'); @@ -80,12 +102,19 @@ protected function getExtraAssignArrayData() return $provider->getModels(); } + /** + * Get a single active record based on the stored block value. + * + * @return \yii\db\ActiveRecord + */ protected function getExtraAssignSingleData() { $value = $this->getContextConfigValue($this->varName); - if ($value) { - return $this->_query->where(['id' => $value])->one(); + if (!$value) { + return false; } + + return $this->getQuery()->where(['id' => $value])->one(); } } diff --git a/src/menu/Item.php b/src/menu/Item.php index 8ec5d642..3b606199 100644 --- a/src/menu/Item.php +++ b/src/menu/Item.php @@ -532,9 +532,9 @@ public function getParents() /** * Go down to a given element which is evalutaed trough a callable. - * + * * Iterate trough parent elements until the last. - * + * * ```php * $item = Yii::$app->menu->current->down(function(Item $item) { * if ($item->depth == 1) { diff --git a/src/models/Nav.php b/src/models/Nav.php index 08bad26e..6da39cf5 100644 --- a/src/models/Nav.php +++ b/src/models/Nav.php @@ -257,7 +257,7 @@ public function reindex($e) * * This method is mainly to find all recursive children of a nav item when moving a page into a container * all childrens requires to update its container id as well, so this method contains the data of its children - * + * * @return array An array where each entry is a Nav object */ public function getRecursiveChildren() diff --git a/src/models/NavItem.php b/src/models/NavItem.php index 2cc29c8c..01e78d3a 100644 --- a/src/models/NavItem.php +++ b/src/models/NavItem.php @@ -410,7 +410,7 @@ public function copyPageItem(NavItem $targetNavItem) if ($blockItem->save()) { // store the old block id with the new block id $idLink[$block['id']] = $blockItem->id; - } + } unset($blockItem); } diff --git a/src/models/NavItemModule.php b/src/models/NavItemModule.php index 6b213af3..93d8503d 100644 --- a/src/models/NavItemModule.php +++ b/src/models/NavItemModule.php @@ -18,7 +18,7 @@ * @property string $controller_name * @property string $action_name * @property string $action_params - * + * * @author Basil Suter * @since 1.0.0 */ @@ -59,11 +59,11 @@ public function init() { parent::init(); - $this->on(self::EVENT_AFTER_FIND, function() { + $this->on(self::EVENT_AFTER_FIND, function () { $this->action_params = $this->getDecodedActionParams(); }); - $this->on(self::EVENT_BEFORE_VALIDATE, function() { + $this->on(self::EVENT_BEFORE_VALIDATE, function () { $this->action_params = $this->getEncodedActionParams(); }); } diff --git a/src/widgets/LangSwitcher.php b/src/widgets/LangSwitcher.php index 8e328268..f75cef86 100644 --- a/src/widgets/LangSwitcher.php +++ b/src/widgets/LangSwitcher.php @@ -187,7 +187,7 @@ private static function getDataArray() /** * Prefix the current link with the dedicated host info. - * + * * Assuming hostInfoMapping is defined in composition component, the correct domain will be taken from the * language information. * diff --git a/tests/src/frontend/BootstrapErrorPageTest.php b/tests/src/frontend/BootstrapErrorPageTest.php index d8fb3453..8bb0641c 100644 --- a/tests/src/frontend/BootstrapErrorPageTest.php +++ b/tests/src/frontend/BootstrapErrorPageTest.php @@ -29,4 +29,4 @@ public function testBootstrap() $this->expectException('yii\web\HeadersAlreadySentException'); $this->app->errorHandler->trigger(ErrorHandler::EVENT_BEFORE_EXCEPTION_RENDER, $event); } -} \ No newline at end of file +} diff --git a/tests/src/injectors/ActiveQuerySelectInjectorTest.php b/tests/src/injectors/ActiveQuerySelectInjectorTest.php new file mode 100644 index 00000000..4a798514 --- /dev/null +++ b/tests/src/injectors/ActiveQuerySelectInjectorTest.php @@ -0,0 +1,75 @@ + Layout::class, + 'fixtureData' => [ + 1 => [ + 'id' => 1, + 'name' => 'foo', + 'json_config' => '{"node":"value"}', + 'view_file' => 'none.php', + ] + ] + ]); + } + + public function testVariableResponse() + { + $block = new TestBlock(); + $block->setVarValues([ + 'foobar' => 1, + ]); + + $injector = new ActiveQuerySelectInjector([ + 'query' => Layout::find(), + 'varName' => 'foobar', + 'varLabel' => 'test', + 'label' => 'name', + 'context' => $block, + ]); + $injector->setup(); + + + $f = $block->getExtraValue('foobar'); + $x = $block->getVarValue('foobar'); + $y = $block->getConfigVarsExport(); + + $this->assertSame('foo', $y[0]['options'][0]['label']); + $this->assertSame(1, $x); + $this->assertSame(['node' => 'value'], $f->getJsonConfig()); + $this->assertSame('value', $f->getJsonConfig('node')); + } + + public function testVariableNotFoundId() + { + $block = new TestBlock(); + $block->setVarValues([ + 'foobar' => 0, + ]); + + $injector = new ActiveQuerySelectInjector([ + 'query' => Layout::find(), + 'varName' => 'foobar', + 'varLabel' => 'test', + 'label' => 'name', + 'context' => $block, + ]); + $injector->setup(); + + $this->assertFalse($block->getExtraValue('foobar')); + } +} diff --git a/tests/src/menu/ItemTest.php b/tests/src/menu/ItemTest.php index bd760779..28ae16c3 100644 --- a/tests/src/menu/ItemTest.php +++ b/tests/src/menu/ItemTest.php @@ -140,7 +140,7 @@ public function testGoDown() $itemWithParent = (new Query)->where(['nav_id' => 10])->one(); $this->assertSame(2, $itemWithParent->depth); - $f = $itemWithParent->down(function(Item $item) { + $f = $itemWithParent->down(function (Item $item) { if ($item->depth == 1) { return $item; } @@ -148,7 +148,7 @@ public function testGoDown() $this->assertSame(1, $f->depth); - $this->assertFalse($itemWithParent->down(function(Item $item) { + $this->assertFalse($itemWithParent->down(function (Item $item) { // just do nothing means pass all elements. })); }