. */ namespace Xibo\Listener; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Xibo\Event\DisplayGroupLoadEvent; use Xibo\Event\FolderMovingEvent; use Xibo\Event\MediaDeleteEvent; use Xibo\Event\MediaFullLoadEvent; use Xibo\Event\ParsePermissionEntityEvent; use Xibo\Event\TagDeleteEvent; use Xibo\Event\TagEditEvent; use Xibo\Event\TriggerTaskEvent; use Xibo\Event\UserDeleteEvent; use Xibo\Factory\DisplayFactory; use Xibo\Factory\DisplayGroupFactory; use Xibo\Storage\StorageServiceInterface; use Xibo\Support\Exception\GeneralException; use Xibo\Support\Exception\NotFoundException; /** * DisplayGroup events */ class DisplayGroupListener { use ListenerLoggerTrait; /** * @var DisplayGroupFactory */ private $displayGroupFactory; /** * @var DisplayFactory */ private $displayFactory; /** * @var StorageServiceInterface */ private $storageService; /** * @param DisplayGroupFactory $displayGroupFactory * @param DisplayFactory $displayFactory * @param StorageServiceInterface $storageService */ public function __construct( DisplayGroupFactory $displayGroupFactory, DisplayFactory $displayFactory, StorageServiceInterface $storageService ) { $this->displayGroupFactory = $displayGroupFactory; $this->displayFactory = $displayFactory; $this->storageService = $storageService; } /** * @param EventDispatcherInterface $dispatcher * @return $this */ public function registerWithDispatcher(EventDispatcherInterface $dispatcher): DisplayGroupListener { $dispatcher->addListener(MediaDeleteEvent::$NAME, [$this, 'onMediaDelete']); $dispatcher->addListener(UserDeleteEvent::$NAME, [$this, 'onUserDelete']); $dispatcher->addListener(MediaFullLoadEvent::$NAME, [$this, 'onMediaLoad']); $dispatcher->addListener(ParsePermissionEntityEvent::$NAME . 'displayGroup', [$this, 'onParsePermissions']); $dispatcher->addListener(FolderMovingEvent::$NAME, [$this, 'onFolderMoving']); $dispatcher->addListener(TagDeleteEvent::$NAME, [$this, 'onTagDelete']); $dispatcher->addListener(TagEditEvent::$NAME, [$this, 'onTagEdit']); return $this; } /** * @param MediaDeleteEvent $event * @param string $eventName * @param EventDispatcherInterface $dispatcher * @return void * @throws \Xibo\Support\Exception\GeneralException * @throws \Xibo\Support\Exception\NotFoundException */ public function onMediaDelete(MediaDeleteEvent $event, string $eventName, EventDispatcherInterface $dispatcher) { $media = $event->getMedia(); $parentMedia = $event->getParentMedia(); foreach ($this->displayGroupFactory->getByMediaId($media->mediaId) as $displayGroup) { $dispatcher->dispatch(new DisplayGroupLoadEvent($displayGroup), DisplayGroupLoadEvent::$NAME); $displayGroup->load(); $displayGroup->unassignMedia($media); if ($parentMedia != null) { $displayGroup->assignMedia($parentMedia); } $displayGroup->save(['validate' => false]); } } /** * @param UserDeleteEvent $event * @param $eventName * @param EventDispatcherInterface $dispatcher * @return void * @throws \Xibo\Support\Exception\GeneralException * @throws \Xibo\Support\Exception\NotFoundException */ public function onUserDelete(UserDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher) { $user = $event->getUser(); $function = $event->getFunction(); $newUser = $event->getNewUser(); $systemUser = $event->getSystemUser(); if ($function === 'delete') { // we do not want to delete Display specific Display Groups, reassign to systemUser instead. foreach ($this->displayGroupFactory->getByOwnerId($user->userId, -1) as $displayGroup) { if ($displayGroup->isDisplaySpecific === 1) { $displayGroup->setOwner($systemUser->userId); $displayGroup->save(['saveTags' => false, 'manageDynamicDisplayLinks' => false]); } else { $displayGroup->load(); $dispatcher->dispatch(new DisplayGroupLoadEvent($displayGroup), DisplayGroupLoadEvent::$NAME); $displayGroup->delete(); } } } else if ($function === 'reassignAll') { foreach ($this->displayGroupFactory->getByOwnerId($user->userId, -1) as $displayGroup) { ($displayGroup->isDisplaySpecific === 1) ? $displayGroup->setOwner($systemUser->userId) : $displayGroup->setOwner($newUser->getOwnerId()); $displayGroup->save(['saveTags' => false, 'manageDynamicDisplayLinks' => false]); } } else if ($function === 'countChildren') { $displayGroups = $this->displayGroupFactory->getByOwnerId($user->userId, -1); $count = count($displayGroups); $this->getLogger()->debug( sprintf( 'Counted Children Display Groups on User ID %d, there are %d', $user->userId, $count ) ); $event->setReturnValue($event->getReturnValue() + $count); } } /** * @param MediaFullLoadEvent $event * @return void * @throws \Xibo\Support\Exception\NotFoundException */ public function onMediaLoad(MediaFullLoadEvent $event) { $media = $event->getMedia(); $media->displayGroups = $this->displayGroupFactory->getByMediaId($media->mediaId); } /** * @param ParsePermissionEntityEvent $event * @return void * @throws \Xibo\Support\Exception\NotFoundException */ public function onParsePermissions(ParsePermissionEntityEvent $event) { $this->getLogger()->debug('onParsePermissions'); $event->setObject($this->displayGroupFactory->getById($event->getObjectId())); } /** * @param FolderMovingEvent $event * @return void * @throws \Xibo\Support\Exception\NotFoundException */ public function onFolderMoving(FolderMovingEvent $event) { $folder = $event->getFolder(); $newFolder = $event->getNewFolder(); foreach ($this->displayGroupFactory->getbyFolderId($folder->getId()) as $displayGroup) { $displayGroup->folderId = $newFolder->getId(); $displayGroup->permissionsFolderId = $newFolder->getPermissionFolderIdOrThis(); $displayGroup->updateFolders('displaygroup'); } } /** * @param TagDeleteEvent $event * @param $eventName * @param EventDispatcherInterface $dispatcher * @return void */ public function onTagDelete(TagDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher): void { $displays = $this->storageService->select(' SELECT lktagdisplaygroup.displayGroupId FROM `lktagdisplaygroup` INNER JOIN `displaygroup` ON `lktagdisplaygroup`.displayGroupId = `displaygroup`.displayGroupId AND `displaygroup`.isDisplaySpecific = 1 WHERE `lktagdisplaygroup`.tagId = :tagId', [ 'tagId' => $event->getTagId() ]); $this->storageService->update( 'DELETE FROM `lktagdisplaygroup` WHERE `lktagdisplaygroup`.tagId = :tagId', ['tagId' => $event->getTagId()] ); if (count($displays) > 0) { $dispatcher->dispatch( new TriggerTaskEvent('\Xibo\XTR\MaintenanceRegularTask', 'DYNAMIC_DISPLAY_GROUP_ASSESSED'), TriggerTaskEvent::$NAME ); } } /** * Update dynamic display groups' dynamicCriteriaTags when a tag is edited from the tag administration. * * @param TagEditEvent $event * @return void * @throws NotFoundException * @throws GeneralException */ public function onTagEdit(TagEditEvent $event): void { // Retrieve all dynamic display groups $displayGroups = $this->displayGroupFactory->getByIsDynamic(1); foreach ($displayGroups as $displayGroup) { // Convert the tag string into an array for easier processing $tags = explode(',', $displayGroup->dynamicCriteriaTags); $displayGroup->setDisplayFactory($this->displayFactory); foreach ($tags as &$tag) { $tag = trim($tag); // Split tag into name and value (e.g. "tagName|tagValue") $parts = explode('|', $tag, 2); $tagName = $parts[0]; $tagValue = $parts[1] ?? null; // If tag name matches the old tag, update the name while keeping the value (if any) if ($tagName == $event->getOldTag()) { $tagName = $event->getNewTag(); $tag = $tagValue !== null ? $tagName . '|' . $tagValue : $tagName; $displayGroup->dynamicCriteriaTags = implode(',', $tags); $displayGroup->save(); } } } } }