diff --git a/CHANGELOG.md b/CHANGELOG.md index c85c86f8ab..48afc9f614 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,14 @@ In order to read more about upgrading and BC breaks have a look at the [UPGRADE ## 2.0.4 +### Changed + + [#328](https://github.com/luyadev/luya-module-admin/issues/328) Empty default selection for "new value" in scheduler overlay. +### Added + ++ [#331](https://github.com/luyadev/luya-module-admin/issues/331) Add new `relation` property for SelectRelationActiveQuery. + ## 2.0.3 (25. June 2019) ### Changed diff --git a/composer.lock b/composer.lock index 8c82f2d4db..701e672ec9 100644 --- a/composer.lock +++ b/composer.lock @@ -11,7 +11,7 @@ "version": "3.3.11", "source": { "type": "git", - "url": "https://github.com/RobinHerbots/Inputmask.git", + "url": "git@github.com:RobinHerbots/Inputmask.git", "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b" }, "dist": { @@ -675,7 +675,7 @@ "version": "0.9.0", "source": { "type": "git", - "url": "https://github.com/chieffancypants/angular-loading-bar.git", + "url": "git@github.com:chieffancypants/angular-loading-bar.git", "reference": "d734873e52ded18fa27d67f52272ae43267dfd63" }, "dist": { @@ -1069,34 +1069,34 @@ }, { "name": "luyadev/luya-module-cms", - "version": "1.0.9.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/luyadev/luya-module-cms.git", - "reference": "e8325864007f4ca0ed7a860d844cff10d48c4475" + "reference": "252e25a333559155041a9d489e7f090b59c3e8e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/luyadev/luya-module-cms/zipball/e8325864007f4ca0ed7a860d844cff10d48c4475", - "reference": "e8325864007f4ca0ed7a860d844cff10d48c4475", + "url": "https://api.github.com/repos/luyadev/luya-module-cms/zipball/252e25a333559155041a9d489e7f090b59c3e8e6", + "reference": "252e25a333559155041a9d489e7f090b59c3e8e6", "shasum": "" }, "require-dev": { - "luyadev/luya-testsuite": "~1.0.0", - "php-coveralls/php-coveralls": "^1.0", - "twbs/bootstrap": "v4.0.0-beta" + "luyadev/luya-testsuite": "^1.0@dev", + "twbs/bootstrap": "~4.3.0", + "unglue/client": "^1.3" }, "type": "luya-core", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" }, "luya": { "bootstrap": [ "\\luya\\cms\\frontend\\Bootstrap" ], "blocks": [ - "src/frontend/blocks" + "src{{DS}}frontend{{DS}}blocks" ] } }, @@ -1129,31 +1129,36 @@ "yii2", "yii2-cms" ], - "time": "2019-05-27T13:33:24+00:00" + "time": "2019-06-26T12:52:58+00:00" }, { "name": "luyadev/luya-testsuite", - "version": "1.0.17.1", + "version": "1.0.17.2", "source": { "type": "git", "url": "https://github.com/luyadev/luya-testsuite.git", - "reference": "33f9f454a5a069cfe48d6347039fdef5f4d47efd" + "reference": "828c9b6de876fd60ec81ad105b1dc5b45eb24ee2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/luyadev/luya-testsuite/zipball/33f9f454a5a069cfe48d6347039fdef5f4d47efd", - "reference": "33f9f454a5a069cfe48d6347039fdef5f4d47efd", + "url": "https://api.github.com/repos/luyadev/luya-testsuite/zipball/828c9b6de876fd60ec81ad105b1dc5b45eb24ee2", + "reference": "828c9b6de876fd60ec81ad105b1dc5b45eb24ee2", "shasum": "" }, "require": { "curl/curl": "^2.0 || ^1.0", "luyadev/luya-core": "^1.0", "luyadev/luya-module-admin": "^1.0 || ^2.0", - "luyadev/luya-module-cms": "^1.0", + "luyadev/luya-module-cms": "^1.0 || ^2.0", "phpunit/phpunit": "^6.0", "twig/twig": "^1.0" }, "type": "luya-core", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { "luya\\testsuite\\": "src/" @@ -1177,7 +1182,7 @@ "module", "php" ], - "time": "2019-06-16T16:39:14+00:00" + "time": "2019-06-26T13:55:17+00:00" }, { "name": "myclabs/deep-copy", diff --git a/src/ngrest/plugins/SelectRelationActiveQuery.php b/src/ngrest/plugins/SelectRelationActiveQuery.php index 83fdb74cde..979a82b4ae 100644 --- a/src/ngrest/plugins/SelectRelationActiveQuery.php +++ b/src/ngrest/plugins/SelectRelationActiveQuery.php @@ -7,6 +7,7 @@ use yii\db\ActiveQuery; use yii\helpers\Json; use yii\base\InvalidConfigException; +use luya\helpers\ArrayHelper; /** * Performance optimised select relation plugin. @@ -17,6 +18,7 @@ * 'client_id' => [ * 'class' => SelectRelationActiveQuery::class, * 'query' => $this->getClient(), + * 'relation' => 'client', * 'labelField' => ['client_number', 'firstname', 'lastname'] * ], * ``` @@ -53,6 +55,20 @@ class SelectRelationActiveQuery extends Plugin * @since 1.2.2 */ public $asyncList = false; + + /** + * @var string The name of the relation which should be used to load the data. For example if you have `getPerson()` the relation name would be `person`. + * In order to reduce sql queries you can eager load the given relation in {{luya\admin\ngrest\base\Api::prepareListQuery()}}: + * + * ```php + * public function prepareListQuery() + * { + * return parent::prepareListQuery()->with(['person']); + * } + * ``` + * @since 2.0.4 + */ + public $relation; private $_labelField; @@ -160,28 +176,52 @@ public function renderUpdate($id, $ngModel) */ public function onListFind($event) { + // async list ignores the onListFind event if ($this->asyncList) { return; } + // ensure a value exists for the given field. $value = $event->sender->getAttribute($this->name); + // render empty list value if ($this->emptyListValue && empty($value)) { - $this->writeAttribute($event, $this->emptyListValue); - } else { - $model = $this->_query->modelClass; - $row = $model::ngRestFind()->select($this->labelField)->where(['id' => $value])->asArray(true)->one(); + return $this->writeAttribute($event, $this->emptyListValue); + } - if (!empty($row)) { - $row = array_map(function ($fieldValue, $fieldName) use ($model) { - if ((new $model)->isI18n($fieldName)) { - return $this->i18nDecodedGetActive($this->i18nFieldDecode($fieldValue)); - } - return $fieldValue; - }, $row, array_keys($row)); - - $this->writeAttribute($event, implode(" ", $row)); + // if a relation is defined, take the relation to render the value + if ($this->relation) { + $model = $event->sender->{$this->relation}; + // unable to find the model relation. Maybe an old entry + if (!$model) { + return; } + + $values = $model->toArray($this->labelField); + $row = []; + foreach ($this->labelField as $name) { + $row[] = $values[$name]; + } + + return $this->writeAttribute($event, implode(" ", $row)); } + + // fallback solution to load relation by a query, not recommend. + $model = $this->_query->modelClass; + $row = $model::ngRestFind()->select($this->labelField)->where(['id' => $value])->asArray(true)->one(); + + // unable to find the given model + if (!$row) { + return; + } + + $row = array_map(function ($fieldValue, $fieldName) use ($model) { + if ((new $model)->isI18n($fieldName)) { + return $this->i18nDecodedGetActive($this->i18nFieldDecode($fieldValue)); + } + return $fieldValue; + }, $row, array_keys($row)); + + return $this->writeAttribute($event, implode(" ", $row)); } } diff --git a/tests/admin/ngrest/plugins/SelectRelationActiveQuerySqlLiteTest.php b/tests/admin/ngrest/plugins/SelectRelationActiveQuerySqlLiteTest.php new file mode 100644 index 0000000000..764efab506 --- /dev/null +++ b/tests/admin/ngrest/plugins/SelectRelationActiveQuerySqlLiteTest.php @@ -0,0 +1,90 @@ + User::class, + 'fixtureData' => [ + "user1" => [ + 'id' => 1, + 'title' => 1, + 'firstname' => 'John', + 'lastname' => 'Doe', + 'email' => 'john@luya.io', + 'password' => 'nohash', + 'is_deleted' => 0, + 'is_api_user' => 0, + ] + ] + ]); + + $userModel = $user->getModel('user1'); + + $pluginModel = new NgRestModelFixture([ + 'modelClass' => TestModel::class, + 'fixtureData' => [ + 1 => [ + 'id' => 1, + 'user_id' => 1, + ] + ] + ]); + + $pluginModel1 = $pluginModel->getModel(1); + + $plugin = new SelectRelationActiveQuery([ + 'name' => 'user_id', + 'alias' => 'user_id', + 'i18n' => false, + 'relation' => 'user', + 'labelField' => ['lastname', 'firstname'], + ]); + + $event = new Event(); + $event->sender = $pluginModel1; + + $plugin->onListFind($event); + + $this->assertSame('Doe John', $pluginModel1->user_id); + } +} + +class TestModel extends NgRestModel { + + public static function ngRestApiEndpoint() + { + return 'api-end-point'; + } + + public static function tableName() + { + return 'footable'; + } + + public function rules() + { + return [ + [['id', 'user_id'], 'string'], + ]; + } + + public function getUser() + { + return $this->hasOne(User::class, ['id' => 'user_id']); + } + +}; \ No newline at end of file diff --git a/tests/data/configs/admin.php b/tests/data/configs/admin.php index 5516e0288c..daa2a387d8 100644 --- a/tests/data/configs/admin.php +++ b/tests/data/configs/admin.php @@ -25,13 +25,17 @@ 'isAdmin' => true, 'isConsoleRequest' => false ], - 'db' => [ + 'dbold' => [ 'class' => 'yii\db\Connection', 'dsn' => DB_DSN, 'username' => DB_USER, 'password' => DB_PASS, 'charset' => 'utf8', ], + 'db' => [ + 'class' => 'yii\db\Connection', + 'dsn' => 'sqlite::memory:', + ], 'sqlite' => [ 'class' => 'yii\db\Connection', 'dsn' => 'sqlite::memory:',