Skip to content

Commit

Permalink
Fix "field" action - all records, allow Action as scope condition
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Apr 22, 2021
1 parent 7a6eaf3 commit 3781e5f
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 15 deletions.
2 changes: 0 additions & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ parameters:
- '~^Call to an undefined method Atk4\\Data\\Reference\\HasOne\:\:addField\(\)\.$~'
# for tests/LookupSqlTest.php
- '~^Call to an undefined method Atk4\\Data\\Reference\\HasOne\:\:withTitle\(\)\.$~'
# for tests/PersistentArrayTest.php
- '~^Call to an undefined method Atk4\\Data\\Persistence\:\:applyScope\(\)\.$~'
# for tests/ReferenceSqlTest.php
- '~^Call to an undefined method Atk4\\Data\\Reference\\HasOne\:\:addFields\(\)\.$~'
- '~^Call to an undefined method Atk4\\Data\\Reference\:\:addTitle\(\)\.$~'
37 changes: 37 additions & 0 deletions src/Action/RenameColumnIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Atk4\Data\Action;

/**
* @internal
*/
final class RenameColumnIterator extends \IteratorIterator
{
/** @var string */
protected $origName;
/** @var string */
protected $newName;

/**
* @param \Traversable<array> $iterator
*/
public function __construct(\Traversable $iterator, string $origName, string $newName)
{
parent::__construct($iterator);

$this->origName = $origName;
$this->newName = $newName;
}

public function current(): array
{
$row = parent::current();

$keys = array_keys($row);
$keys[array_search($this->origName, $keys, true)] = $this->newName;

return array_combine($keys, $row);
}
}
21 changes: 11 additions & 10 deletions src/Persistence/Array_.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Atk4\Data\Persistence;

use Atk4\Data\Action\RenameColumnIterator;
use Atk4\Data\Exception;
use Atk4\Data\Model;
use Atk4\Data\Persistence;
Expand Down Expand Up @@ -199,15 +200,19 @@ public function tryLoad(Model $model, $id): ?array
$table = $this->seedDataAndGetTable($model);

if ($id === self::ID_LOAD_ONE || $id === self::ID_LOAD_ANY) {
if (iterator_count($table->getRows()) === 0) {
$action = $this->action($model, 'select');
$action->generator->rewind(); // needed for some reasons!

$selectRow = $action->getRow();
if ($selectRow === null) {
return null;
} elseif ($id === self::ID_LOAD_ONE && iterator_count($table->getRows()) !== 1) {
} elseif ($id === self::ID_LOAD_ONE && $action->getRow() !== null) {
throw (new Exception('Ambiguous conditions, more than one record can be loaded.'))
->addMoreInfo('model', $model)
->addMoreInfo('id', null);
}

$id = $table->getRows()->current()->getValue($model->id_field); // @phpstan-ignore-line
$id = $selectRow[$model->id_field];

$row = $this->tryLoad($model, $id);
$model->setId($id); // @TODO is it needed?
Expand Down Expand Up @@ -433,15 +438,11 @@ public function action(Model $model, $type, $args = [])
$this->applyScope($model, $action);
$this->setLimitOrder($model, $action);

// get first record
if ($row = $action->getRow()) {
if (isset($args['alias']) && array_key_exists($field, $row)) {
$row[$args['alias']] = $row[$field];
unset($row[$field]);
}
if (isset($args['alias'])) {
$action->generator = new RenameColumnIterator($action->generator, $field, $args['alias']);
}

return $row;
return $action;
case 'fx':
case 'fx0':
if (!isset($args[0], $args[1])) {
Expand Down
17 changes: 16 additions & 1 deletion src/Persistence/Array_/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ protected function match(array $row, Model\Scope\AbstractScope $condition)

protected function evaluateIf($v1, $operator, $v2): bool
{
if ($v2 instanceof self) {
$v2 = $v2->getRows();
}

if ($v2 instanceof \Traversable) {
throw new \Exception('Unexpected v2 type');
}

switch (strtoupper((string) $operator)) {
case '=':
$result = is_array($v2) ? $this->evaluateIf($v1, 'IN', $v2) : $v1 === $v2;
Expand Down Expand Up @@ -192,7 +200,14 @@ protected function evaluateIf($v1, $operator, $v2): bool

break;
case 'IN':
$result = is_array($v2) ? in_array($v1, $v2, true) : $this->evaluateIf($v1, '=', $v2);
$result = false;
foreach ($v2 as $v2Item) { // flatten rows, this looses column names!
if ($this->evaluateIf($v1, '=', $v2Item)) {
$result = true;

break;
}
}

break;
case 'NOT IN':
Expand Down
10 changes: 8 additions & 2 deletions tests/PersistentArrayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,17 @@ public function testActionField()

// use alias as array key if it is set
$q = $m->action('field', ['name', 'alias' => 'first_name']);
$this->assertSame(['first_name' => 'John'], $q);
$this->assertSame([
1 => ['first_name' => 'John'],
2 => ['first_name' => 'Sarah'],
], $q->getRows());

// if alias is not set, then use field name as key
$q = $m->action('field', ['name']);
$this->assertSame(['name' => 'John'], $q);
$this->assertSame([
1 => ['name' => 'John'],
2 => ['name' => 'Sarah'],
], $q->getRows());
}

/**
Expand Down

0 comments on commit 3781e5f

Please sign in to comment.