Skip to content

Commit

Permalink
add dynamic row field type support to Table in general
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Jan 6, 2023
1 parent 763db43 commit 31d5af5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 14 deletions.
9 changes: 8 additions & 1 deletion demos/interactive/cardtable.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@

Header::addTo($app, ['Card displays read-only data of a single record']);

CardTable::addTo($app)->setModel((new Stat($app->db))->loadAny());
$entity = (new Stat($app->db))->loadAny();
$entity->project_code .= ' <b>no reload</b>';

CardTable::addTo($app)->setModel($entity);

// CardTable uses internally atk4_local_object type which uses weak references,
// force GC to test the data are kept referenced correctly
gc_collect_cycles();
17 changes: 5 additions & 12 deletions src/CardTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Atk4\Ui;

use Atk4\Data\Field;
use Atk4\Data\Model;

/**
Expand Down Expand Up @@ -34,32 +35,24 @@ public function setModel(Model $entity, array $columns = null): void
}

$data = [];
$values = [];
foreach ($entity->get() as $key => $value) {
foreach (array_keys($entity->get()) as $key) {
if (in_array($key, $columns, true)) {
$data[] = [
'id' => $key,
'field' => $entity->getField($key)->getCaption(),
'value' => null,
'value' => new Model\EntityFieldPair($entity, $key),
];
$values[$key] = new Model\EntityFieldPair($entity, $key);
}
}

$this->_bypass = true;
try {
$mm = parent::setSource($data);
parent::setSource($data);
} finally {
$this->_bypass = false;
}

$mm->getField('value')->type = 'atk4_local_object';
foreach ($mm as $entity) {
$entity->save(['value' => $values[$entity->get('id')]]);
}

$this->addDecorator('value', [Table\Column\Multiformat::class, function (Model $row) use ($entity) {
$field = $entity->getField($row->getId());
$this->addDecorator('value', [Table\Column\Multiformat::class, function (Model $row, Field $field) {
$c = $this->decoratorFactory($field);
if ($c instanceof Table\Column\Money) {
$c->attr['all']['class'] = ['single line'];
Expand Down
39 changes: 38 additions & 1 deletion src/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,40 @@ public function setModel(Model $model, array $columns = null): void
}
}

public function setSource(array $data, $fields = null): Model
{
// mainly for CardTable to support different field type for different row 1/2
// related with https://github.com/atk4/data/blob/4.0.0/tests/Persistence/StaticTest.php#L142
$dataWithObjects = [];
if (is_array(reset($data))) {
foreach ($data as $rowKey => $row) {
foreach ($row as $k => $v) {
if ($v instanceof EntityFieldPair) {
$dataWithObjects[$row['id']][$k] = $v;
$data[$rowKey][$k] = null;
}
}
}
}

$model = parent::setSource($data, $fields);

foreach ($dataWithObjects as $id => $row) {
$entity = $model->load($id);
foreach ($row as $k => $v) {
$model->getField($k)->type = 'atk4_local_object';
$entity->set($k, $v);
}
$entity->save();
}
$model->onHook(Model::HOOK_BEFORE_LOAD, function () use ($dataWithObjects) {
// useless hook, but make sure the $dataWithObjects is kept referenced from $model
$count = count($dataWithObjects);
});

return $model;
}

protected function renderView(): void
{
if (!$this->columns) {
Expand Down Expand Up @@ -422,14 +456,17 @@ protected function renderView(): void
$modelBackup = $this->model;
try {
foreach ($this->model as $entityOrig) {
// clone entity mainly for CardTable to support different field type for different row
// mainly for CardTable to support different field type for different row 2/2
$entityCloned = (clone $entityOrig->getModel())->createEntity();
$entityCloned->setId($entityOrig->getId());
\Closure::bind(function () use ($entityOrig, $entityCloned) {
foreach ($entityOrig->data as $k => $v) {
$field = $entityCloned->getField($k);
if ($field->type === 'atk4_local_object' && $v instanceof EntityFieldPair) {
$field->type = $v->getField()->type;
$field->enum = $v->getField()->enum;
$field->values = $v->getField()->values;
$field->ui = $v->getField()->ui;
$v = $v->get();
}
$entityCloned->data[$k] = $v;
Expand Down

0 comments on commit 31d5af5

Please sign in to comment.