From aaa9dd63aa8eeef1ac5b700971b0ee44f954c15e Mon Sep 17 00:00:00 2001 From: Eugene Tupikov Date: Sat, 14 Aug 2021 20:52:11 +0300 Subject: [PATCH 1/4] bump dependencies --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bd75afd..aadb6a3 100644 --- a/composer.json +++ b/composer.json @@ -22,11 +22,11 @@ } ], "require": { - "php": ">=5.4.0", + "php": ">=7.4", "yiisoft/yii2": ">=2.0.38" }, "require-dev": { - "phpunit/phpunit": "5.7.*" + "phpunit/phpunit": "9.*" }, "autoload": { "psr-4": { From 93d013db50adbf1fd8c3443b1e1e3c11434cb88b Mon Sep 17 00:00:00 2001 From: Eugene Tupikov Date: Tue, 31 Aug 2021 20:51:45 +0300 Subject: [PATCH 2/4] rename ValuePreparer to ValueResolver --- CHANGELOG.md | 5 ++ composer.json | 8 +- phpunit.xml | 9 +++ phpunit.xml.dist | 22 ----- src/components/BaseColumn.php | 16 ++-- src/components/ValuePreparer.php | 82 ------------------- src/components/ValueResolver.php | 73 +++++++++++++++++ tests/unit/components/ValuePreparerTest.php | 84 ------------------- tests/unit/components/ValueResolverTest.php | 90 +++++++++++++++++++++ 9 files changed, 192 insertions(+), 197 deletions(-) create mode 100644 phpunit.xml delete mode 100644 phpunit.xml.dist delete mode 100644 src/components/ValuePreparer.php create mode 100644 src/components/ValueResolver.php delete mode 100644 tests/unit/components/ValuePreparerTest.php create mode 100644 tests/unit/components/ValueResolverTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 34a6269..f36a452 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Yii2 multiple input change log ============================== +3.0.0 (in development) +======================= +- rename ValuePreparer to ValueResolver + + 2.27.0 (in development) ======================= diff --git a/composer.json b/composer.json index aadb6a3..8e678d0 100644 --- a/composer.json +++ b/composer.json @@ -34,5 +34,11 @@ "unclead\\multipleinput\\": "src/", "unclead\\multipleinput\\tests\\": "tests/" } - } + }, + "repositories": [ + { + "type": "composer", + "url": "https://asset-packagist.org" + } + ] } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..28136ee --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,9 @@ + + + + + ./tests/unit/ + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index fd3fa65..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - ./tests - ./vendor - - - - - ./tests/unit/ - - - - - - \ No newline at end of file diff --git a/src/components/BaseColumn.php b/src/components/BaseColumn.php index d4a9928..6e385d5 100644 --- a/src/components/BaseColumn.php +++ b/src/components/BaseColumn.php @@ -232,25 +232,25 @@ public function isHiddenInput() /** * Prepares the value of column. + * * @param array $contextParams the params who passed to closure: * string $id the id of input element * string $name the name of input element - * string $indexPlaceholder The index placeholder of multiple input. The {$indexPlaceholder} template will be replace by $index + * string $indexPlaceholder The index placeholder of multiple input. The {$indexPlaceholder} template will be replaced by $index * int $index The index of multiple input * int $columnIndex The index of current model attributes + * * @return mixed */ - protected function prepareValue($contextParams = []) + protected function resolveValue(array $contextParams = []) { $data = $this->getModel(); if ($this->value instanceof \Closure) { - $value = call_user_func($this->value, $data, $contextParams); - } else { - $valuePreparer = new ValuePreparer($this->name, $this->defaultValue); - $value = $valuePreparer->prepare($data); + return call_user_func($this->value, $data, $contextParams); } - return $value; + $resolver = new ValueResolver(); + return $resolver->resolve($this->name, $data, $this->defaultValue); } /** @@ -315,7 +315,7 @@ public function renderInput($name, $options, $contextParams = []) $value = null; if ($this->type !== self::TYPE_DRAGCOLUMN) { - $value = $this->prepareValue($contextParams); + $value = $this->resolveValue($contextParams); } if (isset($options['items'])) { diff --git a/src/components/ValuePreparer.php b/src/components/ValuePreparer.php deleted file mode 100644 index 91e01fb..0000000 --- a/src/components/ValuePreparer.php +++ /dev/null @@ -1,82 +0,0 @@ -name = $name; - $this->defaultValue = $defaultValue; - } - - /** - * @param $data Prepared data - * - * @return int|mixed|null|string - */ - public function prepare($data) - { - $value = null; - if ($data instanceof ActiveRecordInterface) { - if ($data->canGetProperty($this->name)) { - $value = $data->{$this->name}; - } else { - $relation = $data->getRelation($this->name, false); - if ($relation !== null) { - $value = $relation->findFor($this->name, $data); - } else { - $value = $data->{$this->name}; - } - } - } elseif ($data instanceof Model) { - $value = $data->{$this->name}; - } elseif (is_array($data)) { - $value = ArrayHelper::getValue($data, $this->name, null); - } elseif(is_string($data) || is_numeric($data)) { - $value = $data; - } - - if ($this->defaultValue !== null && $this->isEmpty($value)) { - $value = $this->defaultValue; - } - - return $value; - } - - protected function isEmpty($value) - { - return $value === null || $value === [] || $value === ''; - } -} \ No newline at end of file diff --git a/src/components/ValueResolver.php b/src/components/ValueResolver.php new file mode 100644 index 0000000..2b78efd --- /dev/null +++ b/src/components/ValueResolver.php @@ -0,0 +1,73 @@ +resolveActiveRecordValue($name, $data); + } elseif ($data instanceof Model) { + $value = $data->{$name}; + } elseif (is_array($data)) { + $value = $data[$name] ?? null; + } elseif(is_string($data) || is_numeric($data)) { + $value = $data; + } + + if ($defaultValue !== null && $this->isEmpty($value)) { + $value = $defaultValue; + } + + return $value; + } + + /** + * @param string $name + * @param ActiveRecordInterface $model + * @return mixed + * + * @throws \RuntimeException + */ + private function resolveActiveRecordValue(string $name, ActiveRecordInterface $model) + { + if ($model->canGetProperty($name)) { + return $model->{$name}; + } + + $relation = $model->getRelation($name, false); + if ($relation !== null) { + return $relation->findFor($name, $model); + } + + throw new \RuntimeException('Failed to resolve value for column: ' . $name); + } + + private function isEmpty($value): bool + { + return $value === null || $value === [] || $value === ''; + } +} diff --git a/tests/unit/components/ValuePreparerTest.php b/tests/unit/components/ValuePreparerTest.php deleted file mode 100644 index 6f28606..0000000 --- a/tests/unit/components/ValuePreparerTest.php +++ /dev/null @@ -1,84 +0,0 @@ -assertEquals($defaultValue, $preparer->prepare(null)); - $this->assertEquals($defaultValue, $preparer->prepare([])); - $this->assertEquals($defaultValue, $preparer->prepare('')); - } - - public function testPrepareStringOrNumber() { - $model = new TestModel(); - $preparer = new ValuePreparer(); - $this->assertEquals(1, $preparer->prepare(1)); - $this->assertEquals('1', $preparer->prepare('1')); - } - - public function testPrepareArrayKey() { - $model = new TestModel(); - $preparer = new ValuePreparer('test'); - $this->assertEquals(1, $preparer->prepare([ - 'test' => 1 - ])); - } - - public function testPrepareModelAttribute() { - $model = new TestModel(); - $exprectedValue = [ - 'test' - ]; - $model->email = $exprectedValue; - $preparer = new ValuePreparer('email'); - $this->assertEquals($exprectedValue, $preparer->prepare($model)); - } - - public function testPrepareActiveRecordDirectAttribute() { - $model = new TestActiveRecord(); - $exprectedValue = 'test'; - $model->email = $exprectedValue; - $preparer = new ValuePreparer('email'); - $this->assertEquals($exprectedValue, $preparer->prepare($model)); - } - - public function testPrepareActiveRecordRelation() { - $relatedModel = new TestActiveRecordRelated(); - $model = $this->createMock(TestActiveRecord::class); - $query = $this->createMock(ActiveQuery::class); - $query->expects($this->once()) - ->method('findFor') - ->with('testRelation', $model) - ->willReturn($relatedModel); - - $model->expects($this->once()) - ->method('getRelation') - ->with('testRelation', false) - ->willReturn($query); - - $preparer = new ValuePreparer('testRelation'); - - $result = $preparer->prepare($model); - - $this->assertEquals($relatedModel, $result); - } - - public function testPrepareActiveRecordRelationWithSameAsAttributeName() { - $model = new TestActiveRecord(); - $relatedModel = new TestActiveRecordRelated(); - $model->testRelation = $relatedModel; - - $preparer = new ValuePreparer( 'testRelation'); - $this->assertEquals($relatedModel, $preparer->prepare($model)); - } -} \ No newline at end of file diff --git a/tests/unit/components/ValueResolverTest.php b/tests/unit/components/ValueResolverTest.php new file mode 100644 index 0000000..0bbd0a8 --- /dev/null +++ b/tests/unit/components/ValueResolverTest.php @@ -0,0 +1,90 @@ +assertEquals($defaultValue, $resolver->resolve($columnName, null, $defaultValue)); + $this->assertEquals($defaultValue, $resolver->resolve($columnName, [], $defaultValue)); + $this->assertEquals($defaultValue, $resolver->resolve($columnName, '', $defaultValue)); + } + + public function testResolveWhenDataIsStringOrNumber() { + $columnName = 'columnName'; + + $resolver = new ValueResolver(); + $this->assertEquals(100500, $resolver->resolve($columnName, 100500)); + $this->assertEquals('string', $resolver->resolve($columnName, 'string')); + } + + public function testResolveWhenDataIsArray() { + $data = [ + 'test' => 'value' + ]; + + $resolver = new ValueResolver(); + $this->assertEquals('value', $resolver->resolve('test', $data)); + } + + public function testResolveModelProperty() { + $expectedValue = 'test@test.com'; + + $model = new TestModel(); + $model->email = $expectedValue; + + $resolver = new ValueResolver(); + $this->assertEquals($expectedValue, $resolver->resolve('email', $model)); + } + + public function testResolveActiveRecordDirectAttribute() { + $expectedValue = 'test@test.com'; + + $model = new TestActiveRecord(); + $model->email = $expectedValue; + + $resolver = new ValueResolver(); + $this->assertEquals($expectedValue, $resolver->resolve('email', $model)); + } + + public function testResolveActiveRecordRelation() { + $relatedModel = new TestActiveRecordRelated(); + $model = $this->createMock(TestActiveRecord::class); + $query = $this->createMock(ActiveQuery::class); + $query->expects($this->once()) + ->method('findFor') + ->with('testRelation', $model) + ->willReturn($relatedModel); + + $model->expects($this->once()) + ->method('getRelation') + ->with('testRelation', false) + ->willReturn($query); + + $resolver = new ValueResolver(); + + $result = $resolver->resolve('testRelation', $model); + + $this->assertEquals($relatedModel, $result); + } + + public function testResolveActiveRecordRelationWithSameNameAsAttributeName() { + $relatedModel = new TestActiveRecordRelated(); + + $model = new TestActiveRecord(); + $model->testRelation = $relatedModel; + + $resolver = new ValueResolver(); + $this->assertEquals($relatedModel, $resolver->resolve('testRelation', $model)); + } +} From b817678c4f56450083740a76173856fe2b275fd6 Mon Sep 17 00:00:00 2001 From: Eugene Tupikov Date: Sat, 4 Sep 2021 18:21:21 +0300 Subject: [PATCH 3/4] rename phpunit.xml to phpunit.xml.dist --- .gitignore | 2 ++ phpunit.xml => phpunit.xml.dist | 0 2 files changed, 2 insertions(+) rename phpunit.xml => phpunit.xml.dist (100%) diff --git a/.gitignore b/.gitignore index 60ad359..5d58775 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ node_modules/ vendor/ composer.lock package-lock.json + +.phpunit.result.cache diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 100% rename from phpunit.xml rename to phpunit.xml.dist From 6f5a24b2e93b66a143294fc408ce476d808868d1 Mon Sep 17 00:00:00 2001 From: Eugene Tupikov Date: Sat, 4 Sep 2021 19:09:39 +0300 Subject: [PATCH 4/4] columns can not be empty now --- src/MultipleInput.php | 25 ++++--------------------- src/TabularInput.php | 4 ++++ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/MultipleInput.php b/src/MultipleInput.php index dcad5eb..0e18cb3 100644 --- a/src/MultipleInput.php +++ b/src/MultipleInput.php @@ -222,6 +222,10 @@ class MultipleInput extends InputWidget */ public function init() { + if (count($this->columns) === 0) { + throw new InvalidConfigException('You must specify at least one column'); + } + if ($this->form !== null && !$this->form instanceof ActiveForm) { throw new InvalidConfigException('Property "form" must be an instance of yii\widgets\ActiveForm'); } @@ -229,8 +233,6 @@ public function init() if ($this->showGeneralError && $this->field === null) { $this->showGeneralError = false; } - - $this->guessColumns(); $this->initData(); parent::init(); @@ -269,25 +271,6 @@ protected function initData() } } - /** - * This function tries to guess the columns to show from the given data - * if [[columns]] are not explicitly specified. - */ - protected function guessColumns() - { - if (empty($this->columns)) { - $column = [ - 'name' => $this->hasModel() ? $this->attribute : $this->name, - 'type' => MultipleInputColumn::TYPE_TEXT_INPUT - ]; - - if ($this->enableGuessTitle && $this->hasModel()) { - $column['title'] = $this->model->getAttributeLabel($this->attribute); - } - $this->columns[] = $column; - } - } - /** * Run widget. */ diff --git a/src/TabularInput.php b/src/TabularInput.php index 95e2f89..7d735a6 100644 --- a/src/TabularInput.php +++ b/src/TabularInput.php @@ -211,6 +211,10 @@ class TabularInput extends Widget */ public function init() { + if (count($this->columns) === 0) { + throw new InvalidConfigException('You must specify at least one column'); + } + if (empty($this->models) && !$this->modelClass) { throw new InvalidConfigException('You must at least specify "models" or "modelClass"'); }