Skip to content

Commit

Permalink
add relation property for SelectRelationActiveQuery closes luyadev#331
Browse files Browse the repository at this point in the history
  • Loading branch information
nadar authored and slowfox089 committed Dec 10, 2020
1 parent e8e25d4 commit 5f2ca66
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 32 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 23 additions & 18 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 53 additions & 13 deletions src/ngrest/plugins/SelectRelationActiveQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -17,6 +18,7 @@
* 'client_id' => [
* 'class' => SelectRelationActiveQuery::class,
* 'query' => $this->getClient(),
* 'relation' => 'client',
* 'labelField' => ['client_number', 'firstname', 'lastname']
* ],
* ```
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

namespace admintests\admin\ngrest\plugins;

use admintests\AdminModelTestCase;
use luya\testsuite\fixtures\NgRestModelFixture;
use luya\admin\models\User;
use luya\admin\ngrest\plugins\SelectRelationActiveQuery;
use luya\admin\ngrest\base\NgRestModel;
use yii\base\Event;

class SelectRelationActiveQueryTestSqlLite extends AdminModelTestCase
{
/**
* @runInSeparateProcess
*/
public function testRelationLoad()
{
$user = new NgRestModelFixture([
'modelClass' => 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']);
}

};
6 changes: 5 additions & 1 deletion tests/data/configs/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -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:',
Expand Down

0 comments on commit 5f2ca66

Please sign in to comment.