Skip to content

Commit 01bb58e

Browse files
committed
Clone user actions for entity lazily
1 parent 292fd11 commit 01bb58e

File tree

3 files changed

+70
-29
lines changed

3 files changed

+70
-29
lines changed

src/Model.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,15 @@ public function createEntity(): self
437437
{
438438
$this->assertIsModel();
439439

440-
$this->_model = $this;
440+
$userActionsBackup = $this->userActions;
441441
try {
442+
$this->_model = $this;
443+
$this->userActions = [];
444+
442445
$model = clone $this;
443446
} finally {
444447
$this->_model = null;
448+
$this->userActions = $userActionsBackup;
445449
}
446450
$model->_entityId = null;
447451

@@ -458,6 +462,8 @@ public function createEntity(): self
458462
*/
459463
protected function init(): void
460464
{
465+
$this->assertIsModel();
466+
461467
$this->_init();
462468

463469
if ($this->id_field) {

src/Model/UserAction.php

+26-26
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,32 @@ class UserAction
7979
/** @var bool Atomic action will automatically begin transaction before and commit it after completing. */
8080
public $atomic = true;
8181

82+
/**
83+
* Return model associated with this action.
84+
*/
85+
public function getModel(): Model
86+
{
87+
return $this->getOwner()->getModel(true); // @phpstan-ignore-line
88+
}
89+
90+
public function getEntity(): Model
91+
{
92+
if ($this->getOwner()->isEntity()) { // @phpstan-ignore-line
93+
return $this->getOwner(); // @phpstan-ignore-line
94+
}
95+
96+
if ($this->entity === null) {
97+
$this->setEntity($this->getOwner()->createEntity()); // @phpstan-ignore-line
98+
}
99+
100+
return $this->entity;
101+
}
102+
103+
public function setEntity(Model $entity): void
104+
{
105+
$this->entity = $entity;
106+
}
107+
82108
/**
83109
* Attempt to execute callback of the action.
84110
*
@@ -210,32 +236,6 @@ public function getConfirmation()
210236
return $this->confirmation;
211237
}
212238

213-
/**
214-
* Return model associated with this action.
215-
*/
216-
public function getModel(): Model
217-
{
218-
return $this->getOwner()->getModel(true); // @phpstan-ignore-line
219-
}
220-
221-
public function getEntity(): Model
222-
{
223-
if ($this->getOwner()->isEntity()) { // @phpstan-ignore-line
224-
return $this->getOwner(); // @phpstan-ignore-line
225-
}
226-
227-
if ($this->entity === null) {
228-
$this->setEntity($this->getOwner()->createEntity()); // @phpstan-ignore-line
229-
}
230-
231-
return $this->entity;
232-
}
233-
234-
public function setEntity(Model $entity): void
235-
{
236-
$this->entity = $entity;
237-
}
238-
239239
public function getCaption(): string
240240
{
241241
return $this->caption ?? ucwords(str_replace('_', ' ', $this->short_name));

src/Model/UserActionsTrait.php

+37-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Atk4\Data\Model;
66

77
use Atk4\Core\Factory;
8+
use Atk4\Data\Exception;
89

910
trait UserActionsTrait
1011
{
@@ -28,6 +29,10 @@ trait UserActionsTrait
2829
*/
2930
public function addUserAction(string $name, $defaults = []): UserAction
3031
{
32+
if ($this->isEntity() && $this->getModel()->hasUserAction($name)) {
33+
$this->assertIsModel();
34+
}
35+
3136
if ($defaults instanceof \Closure) {
3237
$defaults = ['callback' => $defaults];
3338
}
@@ -49,9 +54,27 @@ public function addUserAction(string $name, $defaults = []): UserAction
4954
*/
5055
public function hasUserAction(string $name): bool
5156
{
57+
if ($this->isEntity() && $this->getModel()->hasUserAction($name)) {
58+
return true;
59+
}
60+
5261
return $this->_hasInCollection($name, 'userActions');
5362
}
5463

64+
private function addUserActionFromModel(string $name, UserAction $action): void
65+
{
66+
$this->assertIsEntity();
67+
$action->getOwner()->assertIsModel();
68+
if (\Closure::bind(fn () => $action->entity, null, UserAction::class)() !== null) {
69+
throw new Exception('Model action entity is expected to be null');
70+
}
71+
72+
// clone action and store it in entity
73+
$action = clone $action;
74+
$action->unsetOwner();
75+
$this->_addIntoCollection($name, $action, 'userActions');
76+
}
77+
5578
/**
5679
* Returns list of actions for this model. Can filter actions by records they apply to.
5780
* It will also skip system user actions (where system === true).
@@ -62,6 +85,12 @@ public function hasUserAction(string $name): bool
6285
*/
6386
public function getUserActions(string $appliesTo = null): array
6487
{
88+
if ($this->isEntity()) {
89+
foreach (array_diff_key($this->getModel()->getUserActions($appliesTo), $this->userActions) as $name => $action) {
90+
$this->addUserActionFromModel($name, $action);
91+
}
92+
}
93+
6594
return array_filter($this->userActions, function ($action) use ($appliesTo) {
6695
return !$action->system && ($appliesTo === null || $action->appliesTo === $appliesTo);
6796
});
@@ -72,6 +101,10 @@ public function getUserActions(string $appliesTo = null): array
72101
*/
73102
public function getUserAction(string $name): UserAction
74103
{
104+
if ($this->isEntity() && !$this->_hasInCollection($name, 'userActions') && $this->getModel()->hasUserAction($name)) {
105+
$this->addUserActionFromModel($name, $this->getModel()->getUserAction($name));
106+
}
107+
75108
return $this->_getFromCollection($name, 'userActions');
76109
}
77110

@@ -82,10 +115,12 @@ public function getUserAction(string $name): UserAction
82115
*/
83116
public function removeUserAction(string $name)
84117
{
85-
foreach ((array) $name as $action) {
86-
$this->_removeFromCollection($action, 'userActions');
118+
if ($this->isEntity() && $this->getModel()->hasUserAction($name)) {
119+
$this->assertIsModel();
87120
}
88121

122+
$this->_removeFromCollection($name, 'userActions');
123+
89124
return $this;
90125
}
91126

0 commit comments

Comments
 (0)