diff --git a/application/Espo/Services/Team.php b/application/Espo/Classes/RecordHooks/Team/ClearCacheAfterLink.php similarity index 51% rename from application/Espo/Services/Team.php rename to application/Espo/Classes/RecordHooks/Team/ClearCacheAfterLink.php index ee54a763ef..43130c4bf0 100644 --- a/application/Espo/Services/Team.php +++ b/application/Espo/Classes/RecordHooks/Team/ClearCacheAfterLink.php @@ -27,55 +27,32 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\Services; +namespace Espo\Classes\RecordHooks\Team; -use Espo\Core\Acl\Cache\Clearer as AclCacheClearer; -use Espo\Entities\User as UserEntity; -use Espo\Core\Di; +use Espo\Core\Acl\Cache\Clearer; +use Espo\Core\DataManager; +use Espo\Core\Record\Hook\LinkHook; +use Espo\Entities\Team; +use Espo\Entities\User; +use Espo\ORM\Entity; /** - * @extends Record<\Espo\Entities\Team> + * @implements LinkHook */ -class Team extends Record implements - - Di\DataManagerAware +class ClearCacheAfterLink implements LinkHook { - use Di\DataManagerSetter; + public function __construct( + private Clearer $clearer, + private DataManager $dataManager + ) {} - public function link(string $id, string $link, string $foreignId): void + public function process(Entity $entity, string $link, Entity $foreignEntity): void { - parent::link($id, $link, $foreignId); - - if ($link === 'users') { - /** @var ?UserEntity $user */ - $user = $this->entityManager->getEntityById(UserEntity::ENTITY_TYPE, $foreignId); - - if ($user) { - $this->createAclCacheClearer()->clearForUser($user); - } - - $this->dataManager->updateCacheTimestamp(); + if ($link !== 'users' || !$foreignEntity instanceof User) { + return; } - } - public function unlink(string $id, string $link, string $foreignId): void - { - parent::unlink($id, $link, $foreignId); - - if ($link === 'users') { - /** @var ?UserEntity $user */ - $user = $this->entityManager->getEntityById(UserEntity::ENTITY_TYPE, $foreignId); - - if ($user) { - $this->createAclCacheClearer()->clearForUser($user); - } - - $this->dataManager->updateCacheTimestamp(); - } - } - - private function createAclCacheClearer(): AclCacheClearer - { - return $this->injectableFactory->create(AclCacheClearer::class); + $this->clearer->clearForUser($foreignEntity); + $this->dataManager->updateCacheTimestamp(); } } diff --git a/application/Espo/Classes/RecordHooks/Team/ClearCacheAfterUnlink.php b/application/Espo/Classes/RecordHooks/Team/ClearCacheAfterUnlink.php new file mode 100644 index 0000000000..76bd5e2245 --- /dev/null +++ b/application/Espo/Classes/RecordHooks/Team/ClearCacheAfterUnlink.php @@ -0,0 +1,58 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Classes\RecordHooks\Team; + +use Espo\Core\Acl\Cache\Clearer; +use Espo\Core\DataManager; +use Espo\Core\Record\Hook\UnlinkHook; +use Espo\Entities\Team; +use Espo\Entities\User; +use Espo\ORM\Entity; + +/** + * @implements UnlinkHook + */ +class ClearCacheAfterUnlink implements UnlinkHook +{ + public function __construct( + private Clearer $clearer, + private DataManager $dataManager + ) {} + + public function process(Entity $entity, string $link, Entity $foreignEntity): void + { + if ($link !== 'users' || !$foreignEntity instanceof User) { + return; + } + + $this->clearer->clearForUser($foreignEntity); + $this->dataManager->updateCacheTimestamp(); + } +} diff --git a/application/Espo/Core/Record/Hook/Provider.php b/application/Espo/Core/Record/Hook/Provider.php index 2c78551801..b241213c61 100644 --- a/application/Espo/Core/Record/Hook/Provider.php +++ b/application/Espo/Core/Record/Hook/Provider.php @@ -55,6 +55,8 @@ class Provider Type::AFTER_DELETE => [DeleteHook::class], Type::BEFORE_LINK => [LinkHook::class], Type::BEFORE_UNLINK => [UnlinkHook::class], + Type::AFTER_LINK => [LinkHook::class], + Type::AFTER_UNLINK => [UnlinkHook::class], ]; private BindingContainer $bindingContainer; diff --git a/application/Espo/Core/Record/Hook/Type.php b/application/Espo/Core/Record/Hook/Type.php index ec2e77714b..a8b7a7bb88 100644 --- a/application/Espo/Core/Record/Hook/Type.php +++ b/application/Espo/Core/Record/Hook/Type.php @@ -43,4 +43,6 @@ class Type public const BEFORE_LINK = 'beforeLink'; public const BEFORE_UNLINK = 'beforeUnlink'; + public const AFTER_LINK = 'afterLink'; + public const AFTER_UNLINK = 'afterUnlink'; } diff --git a/application/Espo/Core/Record/HookManager.php b/application/Espo/Core/Record/HookManager.php index 53c5e3a5f9..38ccb3eec3 100644 --- a/application/Espo/Core/Record/HookManager.php +++ b/application/Espo/Core/Record/HookManager.php @@ -165,6 +165,20 @@ class HookManager } } + public function processAfterLink(Entity $entity, string $link, Entity $foreignEntity): void + { + foreach ($this->getAfterLinkHookList($entity->getEntityType()) as $hook) { + $hook->process($entity, $link, $foreignEntity); + } + } + + public function processAfterUnlink(Entity $entity, string $link, Entity $foreignEntity): void + { + foreach ($this->getAfterUnlinkHookList($entity->getEntityType()) as $hook) { + $hook->process($entity, $link, $foreignEntity); + } + } + /** * @return ReadHook[] */ @@ -245,4 +259,22 @@ class HookManager /** @var UnlinkHook[] */ return $this->provider->getList($entityType, Type::BEFORE_UNLINK); } + + /** + * @return LinkHook[] + */ + private function getAfterLinkHookList(string $entityType): array + { + /** @var LinkHook[] */ + return $this->provider->getList($entityType, Type::AFTER_LINK); + } + + /** + * @return UnlinkHook[] + */ + private function getAfterUnlinkHookList(string $entityType): array + { + /** @var UnlinkHook[] */ + return $this->provider->getList($entityType, Type::AFTER_UNLINK); + } } diff --git a/application/Espo/Core/Record/Service.php b/application/Espo/Core/Record/Service.php index ff1077303f..bb82e4fed0 100644 --- a/application/Espo/Core/Record/Service.php +++ b/application/Espo/Core/Record/Service.php @@ -1275,6 +1275,8 @@ class Service implements Crud, $this->getRepository() ->getRelation($entity, $link) ->relate($foreignEntity, null, [SaveOption::API => true]); + + $this->getRecordHookManager()->processAfterLink($entity, $link, $foreignEntity); } /** @@ -1331,6 +1333,8 @@ class Service implements Crud, $this->getRepository() ->getRelation($entity, $link) ->unrelate($foreignEntity, [SaveOption::API => true]); + + $this->getRecordHookManager()->processAfterUnlink($entity, $link, $foreignEntity); } /** diff --git a/application/Espo/Core/Utils/Metadata/Builder.php b/application/Espo/Core/Utils/Metadata/Builder.php index 6fbbd1112c..7977f90eed 100644 --- a/application/Espo/Core/Utils/Metadata/Builder.php +++ b/application/Espo/Core/Utils/Metadata/Builder.php @@ -68,6 +68,8 @@ class Builder ['recordDefs', self::ANY_KEY, 'afterDeleteHookClassNameList'], ['recordDefs', self::ANY_KEY, 'beforeLinkHookClassNameList'], ['recordDefs', self::ANY_KEY, 'beforeUnlinkHookClassNameList'], + ['recordDefs', self::ANY_KEY, 'afterLinkHookClassNameList'], + ['recordDefs', self::ANY_KEY, 'afterUnlinkHookClassNameList'], ]; private const ANY_KEY = '__ANY__'; diff --git a/application/Espo/Resources/metadata/recordDefs/Team.json b/application/Espo/Resources/metadata/recordDefs/Team.json index c3f088c340..cd66ec0c5d 100644 --- a/application/Espo/Resources/metadata/recordDefs/Team.json +++ b/application/Espo/Resources/metadata/recordDefs/Team.json @@ -9,5 +9,11 @@ ], "beforeLinkHookClassNameList": [ "Espo\\Classes\\RecordHooks\\Team\\BeforeLinkUserCheck" + ], + "afterLinkHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Team\\ClearCacheAfterLink" + ], + "afterUnlinkHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Team\\ClearCacheAfterUnlink" ] } diff --git a/schema/metadata/recordDefs.json b/schema/metadata/recordDefs.json index 3a60c5246c..01971c828b 100644 --- a/schema/metadata/recordDefs.json +++ b/schema/metadata/recordDefs.json @@ -242,6 +242,20 @@ "items": { "type": "string" } + }, + "afterLinkHookClassNameList": { + "description": "After-link hooks. Should implement the Espo\\Core\\Record\\Hook\\LinkHook interface. As of v8.2.", + "type": "array", + "items": { + "type": "string" + } + }, + "afterUnlinkHookClassNameList": { + "description": "After-unlink hooks. Should implement the Espo\\Core\\Record\\Hook\\UnlinkHook interface. As of v8.2.", + "type": "array", + "items": { + "type": "string" + } } } }