Enhance document synchronization hooks to handle linking and unlinking; update sync status for related entities; modify state file for cache and microtime values
This commit is contained in:
@@ -2,14 +2,22 @@
|
|||||||
namespace Espo\Custom\Hooks\CDokumente;
|
namespace Espo\Custom\Hooks\CDokumente;
|
||||||
|
|
||||||
use Espo\ORM\Entity;
|
use Espo\ORM\Entity;
|
||||||
|
use Espo\ORM\Repository\Option\RemoveOptions;
|
||||||
use Espo\ORM\Repository\Option\SaveOptions;
|
use Espo\ORM\Repository\Option\SaveOptions;
|
||||||
|
use Espo\Core\Hook\Hook\AfterRemove;
|
||||||
use Espo\Core\Hook\Hook\AfterSave;
|
use Espo\Core\Hook\Hook\AfterSave;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook: Bei Änderung eines Dokuments syncStatus und aiSyncStatus auf "unclean" setzen
|
* Hook: Bei Änderung, Verlinkung oder Löschung eines Dokuments syncStatus und
|
||||||
* und die verknüpfte CAkten-Entity aktualisieren.
|
* aiSyncStatus auf "unclean" setzen und die verknüpfte CAkten-Entity aktualisieren.
|
||||||
|
*
|
||||||
|
* Auslöser:
|
||||||
|
* - afterSave: Feldänderungen (name, description, file, …)
|
||||||
|
* - afterSave: Neues Dokument mit cAktenId
|
||||||
|
* - afterSave: cAktenId-Änderung (Verlinkung / Entlinkung über CAkten-Panel)
|
||||||
|
* - afterRemove: Gelöschtes Dokument → verknüpfte Akte neu berechnen
|
||||||
*/
|
*/
|
||||||
class UpdateJunctionSyncStatus implements AfterSave
|
class UpdateJunctionSyncStatus implements AfterSave, AfterRemove
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private \Espo\ORM\EntityManager $entityManager
|
private \Espo\ORM\EntityManager $entityManager
|
||||||
@@ -17,30 +25,83 @@ class UpdateJunctionSyncStatus implements AfterSave
|
|||||||
|
|
||||||
public function afterSave(Entity $entity, SaveOptions $options): void
|
public function afterSave(Entity $entity, SaveOptions $options): void
|
||||||
{
|
{
|
||||||
if ($entity->isNew()) {
|
// Kein Re-Eintritt wenn dieser Hook selbst gespeichert hat
|
||||||
return;
|
if ($options->get('skipHooks')) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->hasRelevantChanges($entity)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$entity->get('cAktenId')) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Fall 1: Neues Dokument → verknüpfte Akte neu berechnen
|
||||||
|
if ($entity->isNew()) {
|
||||||
|
if ($entity->get('cAktenId')) {
|
||||||
|
$this->triggerAkteUpdate($entity->get('cAktenId'));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall 2: cAktenId geändert (Dokument verlinkt oder entlinkt)
|
||||||
|
if ($entity->isAttributeChanged('cAktenId')) {
|
||||||
|
$oldAktenId = $entity->getFetched('cAktenId');
|
||||||
|
$newAktenId = $entity->get('cAktenId');
|
||||||
|
|
||||||
|
// Dokument der neuen Akte zugewiesen → als unclean markieren
|
||||||
|
if ($newAktenId) {
|
||||||
|
$entity->set('syncStatus', 'unclean');
|
||||||
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
|
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
$this->triggerAkteUpdate($newAktenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alte Akte ebenfalls neu berechnen (Dokument entfernt)
|
||||||
|
if ($oldAktenId && $oldAktenId !== $newAktenId) {
|
||||||
|
$this->triggerAkteUpdate($oldAktenId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall 3: Relevante Feldänderungen (Datei, Name, Beschreibung, …)
|
||||||
|
if (!$this->hasRelevantChanges($entity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$entity->get('cAktenId')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$entity->set('syncStatus', 'unclean');
|
$entity->set('syncStatus', 'unclean');
|
||||||
$entity->set('aiSyncStatus', 'unclean');
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
$this->triggerAkteUpdate($entity->get('cAktenId'));
|
||||||
|
|
||||||
// Akte triggern → BeforeSave-Hook UpdateLastSyncFromDocuments aggregiert Status
|
|
||||||
$akte = $this->entityManager->getEntityById('CAkten', $entity->get('cAktenId'));
|
|
||||||
if ($akte) {
|
|
||||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$GLOBALS['log']->error('CDokumente UpdateJunctionSyncStatus Hook Error: ' . $e->getMessage());
|
$GLOBALS['log']->error('CDokumente UpdateJunctionSyncStatus afterSave Error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function afterRemove(Entity $entity, RemoveOptions $options): void
|
||||||
|
{
|
||||||
|
$akteId = $entity->get('cAktenId');
|
||||||
|
if (!$akteId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->triggerAkteUpdate($akteId);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$GLOBALS['log']->error('CDokumente UpdateJunctionSyncStatus afterRemove Error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert die CAkten-Entity neu, damit UpdateLastSyncFromDocuments
|
||||||
|
* den Sync-Status aller verknüpften Dokumente neu aggregiert.
|
||||||
|
*/
|
||||||
|
private function triggerAkteUpdate(string $akteId): void
|
||||||
|
{
|
||||||
|
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||||
|
if ($akte) {
|
||||||
|
// silent=true → keine Audit-Einträge; kein skipHooks → UpdateLastSyncFromDocuments läuft
|
||||||
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
|
|||||||
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
||||||
$foreignEntity->set('syncStatus', 'new'); // Mark as new for Advoware sync
|
$foreignEntity->set('syncStatus', 'new'); // Mark as new for Advoware sync
|
||||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
|
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
||||||
|
$akte = $this->entityManager->getEntityById('CAkten', $advowareAkten->getId());
|
||||||
|
if ($akte) {
|
||||||
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hole verbundene AIKnowledge
|
// Hole verbundene AIKnowledge
|
||||||
@@ -97,8 +103,15 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
|
|||||||
|
|
||||||
// Remove direct belongsTo relationship from document
|
// Remove direct belongsTo relationship from document
|
||||||
if ($advowareAkten && $foreignEntity->get('cAktenId') === $advowareAkten->getId()) {
|
if ($advowareAkten && $foreignEntity->get('cAktenId') === $advowareAkten->getId()) {
|
||||||
|
$akteId = $advowareAkten->getId(); // Vor dem Löschen merken
|
||||||
$foreignEntity->set('cAktenId', null);
|
$foreignEntity->set('cAktenId', null);
|
||||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
|
// Akte über Entlinkung informieren → syncStatus neu berechnen
|
||||||
|
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||||
|
if ($akte) {
|
||||||
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hole verbundene AIKnowledge
|
// Hole verbundene AIKnowledge
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
|
|||||||
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
||||||
$foreignEntity->set('syncStatus', 'new'); // Mark as new for Advoware sync
|
$foreignEntity->set('syncStatus', 'new'); // Mark as new for Advoware sync
|
||||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
|
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
||||||
|
$akte = $this->entityManager->getEntityById('CAkten', $advowareAkten->getId());
|
||||||
|
if ($akte) {
|
||||||
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hole verbundene AIKnowledge
|
// Hole verbundene AIKnowledge
|
||||||
@@ -97,8 +103,15 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
|
|||||||
|
|
||||||
// Remove direct belongsTo relationship from document
|
// Remove direct belongsTo relationship from document
|
||||||
if ($advowareAkten && $foreignEntity->get('cAktenId') === $advowareAkten->getId()) {
|
if ($advowareAkten && $foreignEntity->get('cAktenId') === $advowareAkten->getId()) {
|
||||||
|
$akteId = $advowareAkten->getId(); // Vor dem Löschen merken
|
||||||
$foreignEntity->set('cAktenId', null);
|
$foreignEntity->set('cAktenId', null);
|
||||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
|
// Akte über Entlinkung informieren → syncStatus neu berechnen
|
||||||
|
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||||
|
if ($akte) {
|
||||||
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hole verbundene AIKnowledge
|
// Hole verbundene AIKnowledge
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
'cacheTimestamp' => 1774562639,
|
'cacheTimestamp' => 1774566125,
|
||||||
'microtimeState' => 1774562639.79198,
|
'microtimeState' => 1774566125.048162,
|
||||||
'currencyRates' => [
|
'currencyRates' => [
|
||||||
'EUR' => 1.0
|
'EUR' => 1.0
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user