mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-27 22:46:04 +00:00
refactoring, save context in late hooks
This commit is contained in:
@@ -43,6 +43,8 @@ interface LateAfterSave
|
||||
{
|
||||
/**
|
||||
* Processed after an entity is saved, after the transaction (if one is used).
|
||||
* To check whether the entity was new before save, obtain the save context
|
||||
* from the options and call `isNew`.
|
||||
*
|
||||
* @param TEntity $entity An entity.
|
||||
* @param SaveOptions $options Options.
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Espo\Core\ORM\Repository\Option;
|
||||
use Closure;
|
||||
use Espo\Core\Utils\Util;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* A save context.
|
||||
@@ -47,6 +48,7 @@ class SaveContext
|
||||
|
||||
private string $actionId;
|
||||
private bool $linkUpdated = false;
|
||||
private ?bool $isNew = null;
|
||||
|
||||
/** @var Closure[] */
|
||||
private array $deferredActions = [];
|
||||
@@ -159,4 +161,28 @@ class SaveContext
|
||||
{
|
||||
return new self($this->actionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @since 9.4.0
|
||||
*/
|
||||
public function setIsNew(bool $isNew): void
|
||||
{
|
||||
if ($this->isNew !== null) {
|
||||
throw new LogicException("Cannot set already set isNew.");
|
||||
}
|
||||
|
||||
$this->isNew = $isNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the entity new before save. Can be accessed only after save is started.
|
||||
* To be used for late hooks, when then entity is already not new, to check.
|
||||
*
|
||||
* @since 9.4.0
|
||||
*/
|
||||
public function isNew(): bool
|
||||
{
|
||||
return $this->isNew ?? throw new LogicException("Cannot access isNew before it's set.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,13 +69,6 @@ class Database extends RDBRepository
|
||||
*/
|
||||
protected $hooksDisabled = false;
|
||||
|
||||
/**
|
||||
* To save and remove in a DB transaction.
|
||||
*
|
||||
* @since 9.4.0
|
||||
*/
|
||||
protected bool $transactionalSave = false;
|
||||
|
||||
/** @var ?array<string, mixed> */
|
||||
private $restoreData = null;
|
||||
/** @var Metadata */
|
||||
@@ -136,22 +129,16 @@ class Database extends RDBRepository
|
||||
*/
|
||||
public function save(Entity $entity, array $options = []): void
|
||||
{
|
||||
if ($this->transactionalSave) {
|
||||
$this->entityManager->getTransactionManager()->run(function () use ($entity, $options) {
|
||||
$this->saveInternal($entity, $options);
|
||||
});
|
||||
} else {
|
||||
$this->saveInternal($entity, $options);
|
||||
}
|
||||
$this->prepareSaveInternal($entity, $options);
|
||||
|
||||
$this->lateAfterSave($entity, $options);
|
||||
parent::save($entity, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
private function saveInternal(Entity $entity, array $options = []): void
|
||||
private function prepareSaveInternal(Entity $entity, array $options = []): void
|
||||
{
|
||||
if (
|
||||
$entity->isNew() &&
|
||||
@@ -166,57 +153,30 @@ class Database extends RDBRepository
|
||||
}
|
||||
|
||||
$this->restoreData = [];
|
||||
|
||||
parent::save($entity, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
private function lateAfterSave(Entity $entity, array $options): void
|
||||
final protected function lateAfterSave(Entity $entity, array $options): void
|
||||
{
|
||||
if (!$this->hooksDisabled && empty($options[SaveOption::SKIP_HOOKS])) {
|
||||
$this->hookManager->process($this->entityType, 'lateAfterSave', $entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a record (mark as deleted).
|
||||
*/
|
||||
public function remove(Entity $entity, array $options = []): void
|
||||
{
|
||||
if ($this->transactionalSave) {
|
||||
$this->entityManager->getTransactionManager()->run(function () use ($entity, $options) {
|
||||
$this->removeInternal($entity, $options);
|
||||
});
|
||||
} else {
|
||||
$this->removeInternal($entity, $options);
|
||||
}
|
||||
|
||||
$this->lateAfterRemove($entity, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
private function lateAfterRemove(Entity $entity, array $options): void
|
||||
final protected function lateAfterRemove(Entity $entity, array $options): void
|
||||
{
|
||||
if (!$this->hooksDisabled && empty($options[SaveOption::SKIP_HOOKS])) {
|
||||
$this->hookManager->process($this->entityType, 'lateAfterRemove', $entity, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
private function removeInternal(Entity $entity, array $options = []): void
|
||||
{
|
||||
parent::remove($entity, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not extend. Use hooks.
|
||||
*
|
||||
|
||||
@@ -67,6 +67,13 @@ class RDBRepository implements Repository
|
||||
protected HookMediator $hookMediator;
|
||||
protected RDBTransactionManager $transactionManager;
|
||||
|
||||
/**
|
||||
* To save and remove in a DB transaction.
|
||||
*
|
||||
* @since 9.4.0
|
||||
*/
|
||||
protected bool $transactionalSave = false;
|
||||
|
||||
public function __construct(
|
||||
protected string $entityType,
|
||||
protected EntityManager $entityManager,
|
||||
@@ -137,6 +144,29 @@ class RDBRepository implements Repository
|
||||
$options[SaveContext::NAME] = new SaveContext();
|
||||
}
|
||||
|
||||
$context = $options[SaveContext::NAME];
|
||||
|
||||
if ($context instanceof SaveContext) {
|
||||
$context->setIsNew($entity->isNew());
|
||||
}
|
||||
|
||||
if ($this->transactionalSave) {
|
||||
$this->entityManager->getTransactionManager()->run(function () use ($entity, $options) {
|
||||
$this->saveInternal($entity, $options);
|
||||
});
|
||||
} else {
|
||||
$this->saveInternal($entity, $options);
|
||||
}
|
||||
|
||||
$this->lateAfterSave($entity, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
private function saveInternal(Entity $entity, array $options = []): void
|
||||
{
|
||||
$this->processCheckEntity($entity);
|
||||
|
||||
if ($entity instanceof BaseEntity) {
|
||||
@@ -191,6 +221,13 @@ class RDBRepository implements Repository
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
protected function lateAfterSave(Entity $entity, array $options): void
|
||||
{}
|
||||
|
||||
/**
|
||||
* Restore a record flagged as deleted.
|
||||
*/
|
||||
@@ -220,6 +257,30 @@ class RDBRepository implements Repository
|
||||
* Remove a record (mark as deleted).
|
||||
*/
|
||||
public function remove(Entity $entity, array $options = []): void
|
||||
{
|
||||
if ($this->transactionalSave) {
|
||||
$this->entityManager->getTransactionManager()->run(function () use ($entity, $options) {
|
||||
$this->removeInternal($entity, $options);
|
||||
});
|
||||
} else {
|
||||
$this->removeInternal($entity, $options);
|
||||
}
|
||||
|
||||
$this->lateAfterRemove($entity, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
protected function lateAfterRemove(Entity $entity, array $options): void
|
||||
{}
|
||||
|
||||
/**
|
||||
* @param TEntity $entity
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
private function removeInternal(Entity $entity, array $options = []): void
|
||||
{
|
||||
$this->processCheckEntity($entity);
|
||||
$this->beforeRemove($entity, $options);
|
||||
|
||||
Reference in New Issue
Block a user