Files
Cloud-CMS/lib/Entity/SyncGroup.php
Matt Batchelder 05ce0da296 Initial Upload
2025-12-02 10:32:59 -05:00

454 lines
15 KiB
PHP
Executable File

<?php
/*
* Copyright (C) 2024 Xibo Signage Ltd
*
* Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
* Xibo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Xibo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Xibo\Entity;
use Carbon\Carbon;
use Respect\Validation\Validator as v;
use Xibo\Factory\DisplayFactory;
use Xibo\Factory\PermissionFactory;
use Xibo\Factory\ScheduleFactory;
use Xibo\Factory\SyncGroupFactory;
use Xibo\Helper\DateFormatHelper;
use Xibo\Support\Exception\InvalidArgumentException;
use Xibo\Support\Exception\NotFoundException;
use Xibo\Support\Sanitizer\SanitizerInterface;
/**
* @SWG\Definition()
*/
class SyncGroup implements \JsonSerializable
{
use EntityTrait;
/**
* @SWG\Property(description="The ID of this Entity")
* @var int
*/
public $syncGroupId;
/**
* @SWG\Property(description="The name of this Entity")
* @var string
*/
public $name;
/**
* @SWG\Property(description="The datetime this entity was created")
* @var string
*/
public $createdDt;
/**
* @SWG\Property(description="The datetime this entity was last modified")
* @var ?string
*/
public $modifiedDt;
/**
* @SWG\Property(description="The ID of the user that last modified this sync group")
* @var int
*/
public $modifiedBy;
/**
* @SWG\Property(description="The name of the user that last modified this sync group")
* @var string
*/
public $modifiedByName;
/**
* @SWG\Property(description="The ID of the owner of this sync group")
* @var int
*/
public $ownerId;
/**
* @SWG\Property(description="The name of the owner of this sync group")
* @var string
*/
public $owner;
/**
* @SWG\Property(description="The publisher port number")
* @var int
*/
public $syncPublisherPort = 9590;
/**
* @SWG\Property(description="The delay (in ms) when displaying the changes in content")
* @var int
*/
public $syncSwitchDelay = 750;
/**
* @SWG\Property(description="The delay (in ms) before unpausing the video on start.")
* @var int
*/
public $syncVideoPauseDelay = 100;
/**
* @SWG\Property(description="The ID of the lead Display for this sync group")
* @var int
*/
public $leadDisplayId;
/**
* @SWG\Property(description="The name of the lead Display for this sync group")
* @var string
*/
public $leadDisplay;
/**
* @SWG\Property(description="The id of the Folder this Sync Group belongs to")
* @var int
*/
public $folderId;
/**
* @SWG\Property(description="The id of the Folder responsible for providing permissions for this Sync Group")
* @var int
*/
public $permissionsFolderId;
private SyncGroupFactory $syncGroupFactory;
private DisplayFactory $displayFactory;
private PermissionFactory $permissionFactory;
private $permissions = [];
private ScheduleFactory $scheduleFactory;
/**
* @param $store
* @param $log
* @param $dispatcher
* @param SyncGroupFactory $syncGroupFactory
* @param DisplayFactory $displayFactory
*/
public function __construct(
$store,
$log,
$dispatcher,
SyncGroupFactory $syncGroupFactory,
DisplayFactory $displayFactory,
PermissionFactory $permissionFactory,
ScheduleFactory $scheduleFactory
) {
$this->setCommonDependencies($store, $log, $dispatcher);
$this->setPermissionsClass('Xibo\Entity\SyncGroup');
$this->syncGroupFactory = $syncGroupFactory;
$this->displayFactory = $displayFactory;
$this->permissionFactory = $permissionFactory;
$this->scheduleFactory = $scheduleFactory;
}
/**
* @return Display[]
* @throws NotFoundException
*/
public function getSyncGroupMembers(): array
{
return $this->displayFactory->getBySyncGroupId($this->syncGroupId);
}
/**
* @return array
*/
public function getGroupMembersForForm(): array
{
return $this->getStore()->select('SELECT `display`.displayId, `display`.display, `display`.syncGroupId, `syncgroup`.leadDisplayId, `displaygroup`.displayGroupId
FROM `display`
INNER JOIN `syncgroup` ON `syncgroup`.syncGroupId = `display`.syncGroupId
INNER JOIN `lkdisplaydg` ON lkdisplaydg.displayid = display.displayId
INNER JOIN `displaygroup` ON displaygroup.displaygroupid = lkdisplaydg.displaygroupid AND `displaygroup`.isDisplaySpecific = 1
WHERE `display`.syncGroupId = :syncGroupId
ORDER BY IF(`syncgroup`.leadDisplayId = `display`.displayId, 0, 1), displayId', [
'syncGroupId' => $this->syncGroupId
]);
}
public function getGroupMembersForEditForm($eventId): array
{
return $this->getStore()->select('SELECT `display`.displayId, `display`.display, `display`.syncGroupId, `syncgroup`.leadDisplayId, `schedule_sync`.layoutId, `displaygroup`.displayGroupId
FROM `display`
INNER JOIN `syncgroup` ON `syncgroup`.syncGroupId = `display`.syncGroupId
INNER JOIN `schedule_sync` ON `schedule_sync`.displayId = `display`.displayId
INNER JOIN `lkdisplaydg` ON lkdisplaydg.displayid = display.displayId
INNER JOIN `displaygroup` ON displaygroup.displaygroupid = lkdisplaydg.displaygroupid AND `displaygroup`.isDisplaySpecific = 1
WHERE `display`.syncGroupId = :syncGroupId AND `schedule_sync`.eventId = :eventId
ORDER BY IF(`syncgroup`.leadDisplayId = `display`.displayId, 0, 1), displayId', [
'syncGroupId' => $this->syncGroupId,
'eventId' => $eventId
]);
}
public function getLayoutIdForDisplay(int $eventId, int $displayId)
{
$layout = $this->getStore()->select('SELECT `schedule_sync`.layoutId
FROM `display`
INNER JOIN `schedule_sync` ON `schedule_sync`.displayId = `display`.displayId
WHERE `display`.syncGroupId = :syncGroupId AND `schedule_sync`.eventId = :eventId AND `schedule_sync`.displayId = :displayId', [
'eventId' => $eventId,
'displayId' => $displayId,
'syncGroupId' => $this->syncGroupId
]);
if (count($layout) <= 0) {
return null;
}
return $layout[0]['layoutId'];
}
/**
* @return int
*/
public function getId(): int
{
return $this->syncGroupId;
}
/**
* @return int
*/
public function getPermissionFolderId(): int
{
return $this->permissionsFolderId;
}
/**
* @return int
*/
public function getOwnerId(): int
{
return $this->ownerId;
}
/**
* Set the owner of this group
* @param $userId
*/
public function setOwner($userId): void
{
$this->ownerId = $userId;
}
/**
* Load the contents for this display group
* @param array $options
* @throws NotFoundException
*/
public function load($options = [])
{
$options = array_merge([], $options);
if ($this->loaded || $this->syncGroupId == null || $this->syncGroupId == 0) {
return;
}
$this->permissions = $this->permissionFactory->getByObjectId(get_class($this), $this->syncGroupId);
// We are loaded
$this->loaded = true;
}
/**
* @param $options
* @return void
* @throws InvalidArgumentException
*/
public function save($options = []): void
{
$options = array_merge([
'validate' => true,
], $options);
if ($options['validate']) {
$this->validate();
}
if (!isset($this->syncGroupId)) {
$this->add();
} else {
$this->edit();
}
}
/**
* @return void
* @throws InvalidArgumentException
*/
public function validate(): void
{
if (!v::stringType()->notEmpty()->validate($this->name)) {
throw new InvalidArgumentException(__('Name cannot be empty'), 'name');
}
if ($this->syncPublisherPort <= 0 || $this->syncPublisherPort === null) {
throw new InvalidArgumentException(__('Sync Publisher Port cannot be empty'), 'syncPublisherPort');
}
if (!isset($this->leadDisplayId) && isset($this->syncGroupId)) {
throw new InvalidArgumentException(__('Please select lead Display for this sync group'), 'leadDisplayId');
}
if ($this->syncSwitchDelay < 0) {
throw new InvalidArgumentException(__('Switch Delay value cannot be negative'), 'syncSwitchDelay');
}
if ($this->syncVideoPauseDelay < 0) {
throw new InvalidArgumentException(__('Video Pause Delay value cannot be negative'), 'syncVideoPauseDelay');
}
}
public function validateForSchedule(SanitizerInterface $sanitizer)
{
foreach ($this->getSyncGroupMembers() as $display) {
if (empty($sanitizer->getInt('layoutId_' . $display->displayId))) {
$this->getLog()->error('Sync Event : Missing Layout for DisplayID ' . $display->displayId);
throw new InvalidArgumentException(
__('Please make sure to select a Layout for all Displays in this Sync Group.')
);
}
}
}
private function add(): void
{
$time = Carbon::now()->format(DateFormatHelper::getSystemFormat());
$this->syncGroupId = $this->getStore()->insert('
INSERT INTO syncgroup (`name`, `createdDt`, `modifiedDt`, `ownerId`, `modifiedBy`, `syncPublisherPort`, `syncSwitchDelay`, `syncVideoPauseDelay`, `folderId`, `permissionsFolderId`)
VALUES (:name, :createdDt, :modifiedDt, :ownerId, :modifiedBy, :syncPublisherPort, :syncSwitchDelay, :syncVideoPauseDelay, :folderId, :permissionsFolderId)
', [
'name' => $this->name,
'createdDt' => $time,
'modifiedDt' => null,
'modifiedBy' => $this->modifiedBy,
'ownerId' => $this->ownerId,
'syncPublisherPort' => $this->syncPublisherPort,
'syncSwitchDelay' => $this->syncSwitchDelay,
'syncVideoPauseDelay' => $this->syncVideoPauseDelay,
'folderId' => $this->folderId,
'permissionsFolderId' => $this->permissionsFolderId
]);
}
private function edit(): void
{
$this->getLog()->debug(sprintf('Updating Sync Group. %s, %d', $this->name, $this->syncGroupId));
$time = Carbon::now()->format(DateFormatHelper::getSystemFormat());
$this->getStore()->update('
UPDATE syncgroup
SET `name` = :name,
`modifiedDt` = :modifiedDt,
`ownerId` = :ownerId,
`modifiedBy` = :modifiedBy,
`syncPublisherPort` = :syncPublisherPort,
`syncSwitchDelay` = :syncSwitchDelay,
`syncVideoPauseDelay` = :syncVideoPauseDelay,
`leadDisplayId` = :leadDisplayId,
`folderId` = :folderId,
`permissionsFolderId` = :permissionsFolderId
WHERE syncGroupId = :syncGroupId
', [
'name' => $this->name,
'modifiedDt' => $time,
'ownerId' => $this->ownerId,
'modifiedBy' => $this->modifiedBy,
'syncPublisherPort' => $this->syncPublisherPort,
'syncSwitchDelay' => $this->syncSwitchDelay,
'syncVideoPauseDelay' => $this->syncVideoPauseDelay,
'leadDisplayId' => $this->leadDisplayId == 0 ? null : $this->leadDisplayId,
'folderId' => $this->folderId,
'permissionsFolderId' => $this->permissionsFolderId,
'syncGroupId' => $this->syncGroupId,
]);
}
/**
* @return void
* @throws NotFoundException
*/
public function delete(): void
{
// unlink Displays from this syncGroup
foreach ($this->getSyncGroupMembers() as $display) {
$this->getStore()->update('UPDATE `display` SET `display`.syncGroupId = NULL WHERE `display`.displayId = :displayId', [
'displayId' => $display->displayId
]);
}
// go through events using this syncGroupId and remove them
// this will also remove links in schedule_sync table
foreach ($this->scheduleFactory->getBySyncGroupId($this->syncGroupId) as $event) {
$event->delete();
}
$this->getStore()->update('DELETE FROM `syncgroup` WHERE `syncgroup`.syncGroupId = :syncGroupId', [
'syncGroupId' => $this->syncGroupId
]);
}
/**
* @param array $displayIds
* @return void
* @throws InvalidArgumentException
* @throws NotFoundException
*/
public function setMembers(array $displayIds): void
{
foreach ($displayIds as $displayId) {
$display = $this->displayFactory->getById($displayId);
if (empty($display->syncGroupId)) {
$this->getStore()->update('UPDATE `display` SET `display`.syncGroupId = :syncGroupId WHERE `display`.displayId = :displayId', [
'syncGroupId' => $this->syncGroupId,
'displayId' => $display->displayId
]);
$display->notify();
} else if (!empty($display->syncGroupId) && $display->syncGroupId !== $this->syncGroupId) {
throw new InvalidArgumentException(
sprintf(
__('Display %s already belongs to a different sync group ID %d'),
$display->display,
$display->syncGroupId
)
);
}
}
}
/**
* @param array $displayIds
* @return void
* @throws NotFoundException
*/
public function unSetMembers(array $displayIds): void
{
foreach ($displayIds as $displayId) {
$display = $this->displayFactory->getById($displayId);
if ($display->syncGroupId === $this->syncGroupId) {
$this->getStore()->update('UPDATE `display` SET `display`.syncGroupId = NULL WHERE `display`.displayId = :displayId', [
'displayId' => $display->displayId
]);
$this->getStore()->update(' DELETE FROM `schedule_sync` WHERE `schedule_sync`.displayId = :displayId
AND `schedule_sync`.eventId IN (SELECT eventId FROM schedule WHERE schedule.syncGroupId = :syncGroupId)', [
'displayId' => $display->displayId,
'syncGroupId' => $this->syncGroupId
]);
}
$display->notify();
}
}
}