diff --git a/README.md b/README.md index 03388bda67..9d6c7edb5d 100644 --- a/README.md +++ b/README.md @@ -129,8 +129,8 @@ It's easy to create your own application styling. Here are some example UI: As of version 2.0 - Agile Toolkit offers support for User Actions. Those are easy to define in your Data Model declaration: ```php -$this->addUserAction('archive', function (Model $m) { - $m->set('is_archived', true); +$this->addUserAction('archive', function (Model $entity) { + $this->set('is_archived', true); $this->saveAndUnload(); }); ``` diff --git a/demos/_includes/DemoActionsUtil.php b/demos/_includes/DemoActionsUtil.php index 1c19ad91b2..37bff6b041 100644 --- a/demos/_includes/DemoActionsUtil.php +++ b/demos/_includes/DemoActionsUtil.php @@ -4,7 +4,6 @@ namespace Atk4\Ui\Demos; -use Atk4\Data\Model; use Atk4\Data\Model\UserAction; use Atk4\Ui\Exception; use Atk4\Ui\Form; @@ -15,18 +14,18 @@ public static function setupDemoActions(Country $country): void { $country->addUserAction('callback', [ 'description' => 'Callback', - 'callback' => static function (Country $model) { - return 'callback execute using country ' . $model->getTitle(); + 'callback' => static function (Country $entity) { + return 'callback execute using country ' . $entity->getTitle(); }, ]); $country->addUserAction('preview', [ 'description' => 'Display Preview prior to run the action', - 'preview' => static function (Country $model) { - return 'Previewing country ' . $model->getTitle(); + 'preview' => static function (Country $entity) { + return 'Previewing country ' . $entity->getTitle(); }, - 'callback' => static function (Country $model) { - return 'Done previewing ' . $model->getTitle(); + 'callback' => static function (Country $entity) { + return 'Done previewing ' . $entity->getTitle(); }, ]); @@ -45,11 +44,11 @@ public static function setupDemoActions(Country $country): void 'args' => [ 'age' => ['type' => 'integer', 'required' => true], ], - 'callback' => static function (Country $model, int $age) { + 'callback' => static function (Country $entity, int $age) { if ($age < 18) { - $text = 'Sorry not old enough to visit ' . $model->getTitle(); + $text = 'Sorry not old enough to visit ' . $entity->getTitle(); } else { - $text = $age . ' is old enough to visit ' . $model->getTitle(); + $text = $age . ' is old enough to visit ' . $entity->getTitle(); } return $text; @@ -62,10 +61,10 @@ public static function setupDemoActions(Country $country): void 'args' => [ 'age' => ['type' => 'integer', 'required' => true], ], - 'preview' => static function (Country $model, int $age) { + 'preview' => static function (Country $entity, int $age) { return 'You age is: ' . $age; }, - 'callback' => static function (Model $model, $age) { + 'callback' => static function (Country $entity, $age) { return 'age = ' . $age; }, ]); @@ -98,13 +97,13 @@ public static function setupDemoActions(Country $country): void $country->addUserAction('confirm', [ 'caption' => 'User Confirmation', 'description' => 'Confirm the action using a ConfirmationExecutor', - 'confirmation' => static function (UserAction $a) { - $iso3 = Country::assertInstanceOf($a->getEntity())->iso3; + 'confirmation' => static function (UserAction $action) { + $iso3 = Country::assertInstanceOf($action->getEntity())->iso3; - return 'Are you sure you want to perform this action on: ' . $a->getEntity()->getTitle() . ' (' . $iso3 . ')'; + return 'Are you sure you want to perform this action on: ' . $action->getEntity()->getTitle() . ' (' . $iso3 . ')'; }, - 'callback' => static function (Country $model) { - return 'Confirm country ' . $model->getTitle(); + 'callback' => static function (Country $entity) { + return 'Confirm country ' . $entity->getTitle(); }, ]); @@ -126,14 +125,14 @@ public static function setupDemoActions(Country $country): void ], ], 'fields' => [$country->fieldName()->iso3], - 'callback' => static function (Country $model, int $age, string $city, string $gender) { + 'preview' => static function (Country $entity, int $age, string $city, string $gender) { + return 'Gender = ' . $gender . ' / Age = ' . $age; + }, + 'callback' => static function (Country $entity, int $age, string $city, string $gender) { $n = $gender === 'm' ? 'Mr.' : 'Mrs.'; return 'Thank you ' . $n . ' at age ' . $age; }, - 'preview' => static function (Country $model, int $age, string $city, string $gender) { - return 'Gender = ' . $gender . ' / Age = ' . $age; - }, ]); } } diff --git a/demos/_unit-test/lookup.php b/demos/_unit-test/lookup.php index ee371a8fc5..5bdaebb440 100644 --- a/demos/_unit-test/lookup.php +++ b/demos/_unit-test/lookup.php @@ -19,8 +19,8 @@ $app->getExecutorFactory()->useTriggerDefault(ExecutorFactory::TABLE_BUTTON); $edit = $model->getUserAction('edit'); -$edit->callback = static function (Product $model) { - return $model->product_category_id->getTitle() . ' - ' . $model->product_sub_category_id->getTitle(); +$edit->callback = static function (Product $entity) { + return $entity->product_category_id->getTitle() . ' - ' . $entity->product_sub_category_id->getTitle(); }; $crud = Crud::addTo($app); diff --git a/demos/collection/grid.php b/demos/collection/grid.php index a620ff2704..6a57790525 100644 --- a/demos/collection/grid.php +++ b/demos/collection/grid.php @@ -24,8 +24,8 @@ $grid = Grid::addTo($app); $model = new Country($app->db); -$model->addUserAction('test', static function (Model $model) { - return 'test from ' . $model->getTitle() . ' was successful!'; +$model->addUserAction('test', static function (Model $entity) { + return 'test from ' . $entity->getTitle() . ' was successful!'; }); $grid->setModel($model); diff --git a/demos/collection/table2.php b/demos/collection/table2.php index 07e44cf3ff..075a8d6ffa 100644 --- a/demos/collection/table2.php +++ b/demos/collection/table2.php @@ -61,8 +61,8 @@ $table->setModel($model, ['action']); // copy of amount through a PHP callback -$model->addExpression('amount_copy', ['expr' => static function (Model $model) { - return $model->get('amount'); +$model->addExpression('amount_copy', ['expr' => static function (Model $entity) { + return $entity->get('amount'); }, 'type' => 'atk4_money']); // column with 2 decorators that stack. Money will use red ink and alignment, format will change text. diff --git a/demos/tutorial/intro.php b/demos/tutorial/intro.php index 4ef4642c07..e18f4fa632 100644 --- a/demos/tutorial/intro.php +++ b/demos/tutorial/intro.php @@ -133,8 +133,8 @@ protected function init(): void session_start(); $model = new DemoInvoice(new Persistence\Array_($_SESSION['atk4_ui_intro_demo'] ?? [])); - $model->onHook(Model::HOOK_AFTER_SAVE, static function (Model $model) { - $_SESSION['atk4_ui_intro_demo'][$model->getId()] = (clone $model->getModel())->addCondition($model->idField, $model->getId())->export(null, null, false)[$model->getId()]; + $model->onHook(Model::HOOK_AFTER_SAVE, static function (Model $entity) { + $_SESSION['atk4_ui_intro_demo'][$entity->getId()] = (clone $entity->getModel())->addCondition($entity->idField, $entity->getId())->export(null, null, false)[$entity->getId()]; }); Header::addTo($owner, ['Set invoice data:']); @@ -188,8 +188,8 @@ protected function init(): void session_start(); $model = new DemoInvoice(new Persistence\Array_($_SESSION['atk4_ui_intro_demo'] ?? [])); - $model->onHook(Model::HOOK_AFTER_SAVE, static function (Model $model) { - $_SESSION['atk4_ui_intro_demo'][$model->getId()] = (clone $model->getModel())->addCondition($model->idField, $model->getId())->export(null, null, false)[$model->getId()]; + $model->onHook(Model::HOOK_AFTER_SAVE, static function (Model $entity) { + $_SESSION['atk4_ui_intro_demo'][$entity->getId()] = (clone $entity->getModel())->addCondition($entity->idField, $entity->getId())->export(null, null, false)[$entity->getId()]; }); Header::addTo($owner, ['Record display in Card View using model data.']); diff --git a/docs/breadcrumb.md b/docs/breadcrumb.md index 20640b44e4..afe4e9a2db 100644 --- a/docs/breadcrumb.md +++ b/docs/breadcrumb.md @@ -65,12 +65,12 @@ $model = new User($app->db); $id = $app->stickyGet('user_id'); if ($id) { // perhaps we edit individual user? - $model = $model->load($id); - $crumb->addCrumb($model->get('name'), []); + $entity = $model->load($id); + $crumb->addCrumb($entity->get('name'), []); // here we can check for additional criteria and display a deeper level on the crumb - Form::addTo($app)->setModel($model); + Form::addTo($app)->setModel($entity); } else { // display list of users $table = Table::addTo($app); diff --git a/docs/tablecolumn.md b/docs/tablecolumn.md index f6ce8fceef..092a6af42f 100644 --- a/docs/tablecolumn.md +++ b/docs/tablecolumn.md @@ -328,10 +328,10 @@ Sometimes your formatting may change depending on value. For example you may wan only on certain rows. For this you can use an `\Atk4\Ui\Table\Column\Multiformat` decorator: ``` -$table->addColumn('amount', [\Atk4\Ui\Table\Column\Multiformat::class, function (Model $model) { - if ($model->get('is_invoiced') > 0) { +$table->addColumn('amount', [\Atk4\Ui\Table\Column\Multiformat::class, function (Model $entity) { + if ($entity->get('is_invoiced') > 0) { return [\Atk4\Ui\Table\Column\Money::class, [\Atk4\Ui\Table\Column\Link::class, 'invoice', ['invoice_id' => 'id']]]; - } elseif (abs($model->get('is_refunded')) < 50) { + } elseif (abs($entity->get('is_refunded')) < 50) { return [[\Atk4\Ui\Table\Column\Template::class, 'Amount was refunded']]; } diff --git a/src/Card.php b/src/Card.php index a66503ca81..85f5ff3023 100644 --- a/src/Card.php +++ b/src/Card.php @@ -190,16 +190,16 @@ public function setModel(Model $entity, ?array $fields = null): void * * @return View */ - public function addSection(?string $title = null, ?Model $model = null, ?array $fields = null, bool $useTable = false, bool $useLabel = false) + public function addSection(?string $title = null, ?Model $entity = null, ?array $fields = null, bool $useTable = false, bool $useLabel = false) { $section = CardSection::addToWithCl($this, array_merge($this->cardSectionSeed, ['card' => $this]), ['Section']); if ($title) { View::addTo($section, [$title, 'class.header' => true]); } - if ($model && $fields) { - $section->setModel($model); - $section->addFields($model, $fields, $useTable, $useLabel); + if ($entity !== null && $fields) { + $section->setModel($entity); + $section->addFields($entity, $fields, $useTable, $useLabel); } return $section; diff --git a/src/CardSection.php b/src/CardSection.php index 4bf4a76180..7447edbee9 100644 --- a/src/CardSection.php +++ b/src/CardSection.php @@ -8,6 +8,8 @@ /** * Display a card section within a Card View. + * + * @property false $model use $entity property instead */ class CardSection extends View { @@ -28,6 +30,14 @@ protected function init(): void $this->addClass('content'); } + #[\Override] + public function setModel(Model $entity, ?array $fields = null): void + { + $entity->assertIsEntity(); + + parent::setModel($entity); + } + /** * Add Description to card section. * @@ -51,30 +61,30 @@ public function addDescription($description) /** * Add Model fields to a card section. */ - public function addFields(Model $model, array $fields, bool $useLabel = false, bool $useTable = false): void + public function addFields(Model $entity, array $fields, bool $useLabel = false, bool $useTable = false): void { - $model->assertIsLoaded(); + $entity->assertIsLoaded(); if ($useTable) { - $this->addTableSection($model, $fields); + $this->addTableSection($entity, $fields); } else { - $this->addSectionFields($model, $fields, $useLabel); + $this->addSectionFields($entity, $fields, $useLabel); } } /** * Add fields label and value to section. */ - private function addSectionFields(Model $model, array $fields, bool $useLabel = false): void + private function addSectionFields(Model $entity, array $fields, bool $useLabel = false): void { foreach ($fields as $field) { - if ($model->titleField === $field) { + if ($entity->titleField === $field) { continue; } - $value = $this->getApp()->uiPersistence->typecastSaveField($model->getField($field), $model->get($field)); + $value = $this->getApp()->uiPersistence->typecastSaveField($entity->getField($field), $entity->get($field)); if ($useLabel) { - $label = $model->getField($field)->getCaption(); + $label = $entity->getField($field)->getCaption(); $value = $label . $this->glue . $value; } @@ -87,9 +97,9 @@ private function addSectionFields(Model $model, array $fields, bool $useLabel = /** * Add field into section using a CardTable View. */ - private function addTableSection(Model $model, array $fields): void + private function addTableSection(Model $entity, array $fields): void { $cardTable = CardTable::addTo($this, ['class' => $this->tableClass]); - $cardTable->setModel($model, $fields); + $cardTable->setModel($entity, $fields); } } diff --git a/src/Crud.php b/src/Crud.php index 15893f5e40..0373e8de85 100644 --- a/src/Crud.php +++ b/src/Crud.php @@ -98,8 +98,8 @@ public function setModel(Model $model, ?array $fields = null): void // grab model ID when using delete // must be set before delete action execute - $this->model->onHook(Model::HOOK_AFTER_DELETE, function (Model $model) { - $this->deletedId = $model->getId(); + $this->model->onHook(Model::HOOK_AFTER_DELETE, function (Model $entity) { + $this->deletedId = $entity->getId(); }); if ($this->useMenuActions === null) { diff --git a/src/Table/Column/FilterModel.php b/src/Table/Column/FilterModel.php index 2551c5784d..19df9467c9 100644 --- a/src/Table/Column/FilterModel.php +++ b/src/Table/Column/FilterModel.php @@ -109,8 +109,8 @@ public function afterInit(): void } // add hook in order to persist data in session - $this->onHook(self::HOOK_AFTER_SAVE, function (Model $model) { - $this->memorize('data', $model->get()); + $this->onHook(self::HOOK_AFTER_SAVE, function (Model $entity) { + $this->memorize('data', $entity->get()); }); } diff --git a/src/Table/Column/FilterPopup.php b/src/Table/Column/FilterPopup.php index dbe92d9ac0..59e0a0f63c 100644 --- a/src/Table/Column/FilterPopup.php +++ b/src/Table/Column/FilterPopup.php @@ -47,8 +47,8 @@ protected function init(): void $this->setOption('delay', ['hide' => 1500]); $this->setHoverable(); - $model = FilterModel::factoryType($this->getApp(), $this->field); - $model = $model->createEntity(); + $entity = FilterModel::factoryType($this->getApp(), $this->field) + ->createEntity(); $this->form = Form::addTo($this)->addClass(''); $this->form->buttonSave->addClass(''); @@ -56,14 +56,14 @@ protected function init(): void $this->form->buttonSave->set('Set'); - $this->form->setControlsDisplayRules($model->getFormDisplayRules()); + $this->form->setControlsDisplayRules($entity->getFormDisplayRules()); // load data associated with this popup - $filter = $model->recallData(); + $filter = $entity->recallData(); if ($filter !== null) { - $model->setMulti($filter); + $entity->setMulti($filter); } - $this->form->setModel($model); + $this->form->setModel($entity); $this->form->onSubmit(function (Form $form) { $form->entity->save(); @@ -72,8 +72,8 @@ protected function init(): void }); Button::addTo($this->form, ['Clear', 'class.clear' => true]) - ->on('click', function (Jquery $j) use ($model) { - $model->clearData(); + ->on('click', function (Jquery $j) use ($entity) { + $entity->clearData(); return new JsBlock([ $this->form->js()->form('reset'), diff --git a/src/UserAction/StepExecutorTrait.php b/src/UserAction/StepExecutorTrait.php index 1aa940394c..cdcdb365ae 100644 --- a/src/UserAction/StepExecutorTrait.php +++ b/src/UserAction/StepExecutorTrait.php @@ -147,7 +147,7 @@ protected function doArgs(View $page): void $form->onSubmit(function (Form $form) { // collect arguments - $this->setActionDataFromModel('args', $form->entity, array_keys($form->entity->getFields())); + $this->setActionDataFromEntity('args', $form->entity, array_keys($form->entity->getFields())); return $this->jsStepSubmit($this->step); }); @@ -168,7 +168,7 @@ protected function doFields(View $page): void $form->onSubmit(function (Form $form) { // collect fields defined in Model\UserAction - $this->setActionDataFromModel('fields', $form->entity, $this->action->fields); + $this->setActionDataFromEntity('fields', $form->entity, $this->action->fields); return $this->jsStepSubmit($this->step); }); @@ -420,11 +420,11 @@ protected function getActionData(string $step): array /** * @param array $fields */ - private function setActionDataFromModel(string $step, Model $model, array $fields): void + private function setActionDataFromEntity(string $step, Model $entity, array $fields): void { $data = []; foreach ($fields as $k) { - $data[$k] = $model->get($k); + $data[$k] = $entity->get($k); } $this->actionData[$step] = $data; } diff --git a/src/View.php b/src/View.php index 852a3a961f..30fb4109b7 100644 --- a/src/View.php +++ b/src/View.php @@ -110,8 +110,6 @@ public function __construct($label = []) * * Do not try to create your own "Model" implementation, instead you must be looking for * your own "Persistence" implementation. - * - * @XXXphpstan-assert !null $this->model TODO enable once https://github.com/phpstan/phpstan/issues/10787 is fixed */ public function setModel(Model $model): void { @@ -137,7 +135,7 @@ public function setModel(Model $model): void * * @param array $fields Limit model to particular fields * - * @phpstan-assert !null $this->model TODO enable once https://github.com/phpstan/phpstan/issues/10787 is fixed + * @phpstan-assert !null $this->model */ public function setSource(array $data, $fields = null): Model { diff --git a/tests/FormTest.php b/tests/FormTest.php index e95b563f65..6259d845c5 100644 --- a/tests/FormTest.php +++ b/tests/FormTest.php @@ -117,14 +117,14 @@ public function testFormSubmit(): void self::assertSame('John', $form->entity->get('name')); return $form; - }, ['email' => 'john@yahoo.com', 'is_admin' => '1'], static function (Model $m) { + }, ['email' => 'john@yahoo.com', 'is_admin' => '1'], static function (Model $entity) { // field has default, but form send back empty value - self::assertSame('', $m->get('name')); + self::assertSame('', $entity->get('name')); - self::assertSame('john@yahoo.com', $m->get('email')); + self::assertSame('john@yahoo.com', $entity->get('email')); // security check, unspecified field must not be changed - self::assertFalse($m->get('is_admin')); + self::assertFalse($entity->get('is_admin')); }); } @@ -135,8 +135,8 @@ public function testTextareaSubmit(): void $form->addControl('foo'); return $form; - }, ['foo' => '0'], static function (Model $m) { - self::assertSame('0', $m->get('foo')); + }, ['foo' => '0'], static function (Model $entity) { + self::assertSame('0', $entity->get('foo')); }); } @@ -222,9 +222,9 @@ public function testSubmitNonFormFieldError(): void $form->setModel($m->createEntity(), ['foo']); return $form; - }, ['foo' => 'x'], static function (Model $model) use (&$submitReached) { + }, ['foo' => 'x'], static function (Model $entity) use (&$submitReached) { $submitReached = true; - $model->set('bar', null); + $entity->set('bar', null); }); } catch (UnhandledCallbackExceptionError $e) { $catchReached = true;