1577 lines
50 KiB
PHP
1577 lines
50 KiB
PHP
<?php
|
|
/*
|
|
* Copyright (C) 2025 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 Stash\Interfaces\PoolInterface;
|
|
use Xibo\Event\DisplayGroupLoadEvent;
|
|
use Xibo\Event\TriggerTaskEvent;
|
|
use Xibo\Factory\DisplayFactory;
|
|
use Xibo\Factory\DisplayGroupFactory;
|
|
use Xibo\Factory\DisplayProfileFactory;
|
|
use Xibo\Factory\FolderFactory;
|
|
use Xibo\Factory\LayoutFactory;
|
|
use Xibo\Helper\DateFormatHelper;
|
|
use Xibo\Service\ConfigServiceInterface;
|
|
use Xibo\Service\LogServiceInterface;
|
|
use Xibo\Storage\StorageServiceInterface;
|
|
use Xibo\Support\Exception\DeadlockException;
|
|
use Xibo\Support\Exception\GeneralException;
|
|
use Xibo\Support\Exception\InvalidArgumentException;
|
|
use Xibo\Support\Exception\NotFoundException;
|
|
|
|
/**
|
|
* Class Display
|
|
* @package Xibo\Entity
|
|
*
|
|
* @SWG\Definition()
|
|
*/
|
|
class Display implements \JsonSerializable
|
|
{
|
|
public static $STATUS_DONE = 1;
|
|
public static $STATUS_DOWNLOADING = 2;
|
|
public static $STATUS_PENDING = 3;
|
|
|
|
use EntityTrait;
|
|
use TagLinkTrait;
|
|
|
|
/**
|
|
* @SWG\Property(description="The ID of this Display")
|
|
* @var int
|
|
*/
|
|
public $displayId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Display Type ID of this Display")
|
|
* @var int
|
|
*/
|
|
public $displayTypeId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Venue ID of this Display")
|
|
* @var int
|
|
*/
|
|
public $venueId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Location Address of this Display")
|
|
* @var string
|
|
*/
|
|
public $address;
|
|
|
|
/**
|
|
* @SWG\Property(description="Is this Display mobile?")
|
|
* @var int
|
|
*/
|
|
public $isMobile;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Languages supported in this display location")
|
|
* @var string
|
|
*/
|
|
public $languages;
|
|
|
|
/**
|
|
* @SWG\Property(description="The type of this Display")
|
|
* @var string
|
|
*/
|
|
public $displayType;
|
|
|
|
/**
|
|
* @SWG\Property(description="The screen size of this Display")
|
|
* @var int
|
|
*/
|
|
public $screenSize;
|
|
|
|
/**
|
|
* @SWG\Property(description="Is this Display Outdoor?")
|
|
* @var int
|
|
*/
|
|
public $isOutdoor;
|
|
|
|
/**
|
|
* @SWG\Property(description="The custom ID (an Id of any external system) of this Display")
|
|
* @var string
|
|
*/
|
|
public $customId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Cost Per Play of this Display")
|
|
* @var double
|
|
*/
|
|
public $costPerPlay;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Impressions Per Play of this Display")
|
|
* @var double
|
|
*/
|
|
public $impressionsPerPlay;
|
|
|
|
/**
|
|
* @SWG\Property(description="Optional Reference 1")
|
|
* @var string
|
|
*/
|
|
public $ref1;
|
|
|
|
/**
|
|
* @SWG\Property(description="Optional Reference 2")
|
|
* @var string
|
|
*/
|
|
public $ref2;
|
|
|
|
/**
|
|
* @SWG\Property(description="Optional Reference 3")
|
|
* @var string
|
|
*/
|
|
public $ref3;
|
|
|
|
/**
|
|
* @SWG\Property(description="Optional Reference 4")
|
|
* @var string
|
|
*/
|
|
public $ref4;
|
|
|
|
/**
|
|
* @SWG\Property(description="Optional Reference 5")
|
|
* @var string
|
|
*/
|
|
public $ref5;
|
|
|
|
/**
|
|
* @SWG\Property(description="Flag indicating whether this Display is recording Auditing Information from XMDS")
|
|
* @var int
|
|
*/
|
|
public $auditingUntil;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Name of this Display")
|
|
* @var string
|
|
*/
|
|
public $display;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Description of this Display")
|
|
* @var string
|
|
*/
|
|
public $description;
|
|
|
|
/**
|
|
* @SWG\Property(description="The ID of the Default Layout")
|
|
* @var int
|
|
*/
|
|
public $defaultLayoutId = 4;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Display Unique Identifier also called hardware key")
|
|
* @var string
|
|
*/
|
|
public $license;
|
|
|
|
/**
|
|
* @SWG\Property(description="A flag indicating whether this Display is licensed or not")
|
|
* @var int
|
|
*/
|
|
public $licensed;
|
|
private $currentlyLicensed;
|
|
|
|
/**
|
|
* @SWG\Property(description="A flag indicating whether this Display is currently logged in")
|
|
* @var int
|
|
*/
|
|
public $loggedIn;
|
|
|
|
/**
|
|
* @SWG\Property(description="A timestamp in CMS time for the last time the Display accessed XMDS")
|
|
* @var int
|
|
*/
|
|
public $lastAccessed;
|
|
|
|
/**
|
|
* @SWG\Property(description="A flag indicating whether the default layout is interleaved with the Schedule")
|
|
* @var int
|
|
*/
|
|
public $incSchedule;
|
|
|
|
/**
|
|
* @SWG\Property(description="A flag indicating whether the Display will send email alerts.")
|
|
* @var int
|
|
*/
|
|
public $emailAlert;
|
|
|
|
/**
|
|
* @SWG\Property(description="A timeout in seconds for the Display to send email alerts.")
|
|
* @var int
|
|
*/
|
|
public $alertTimeout;
|
|
|
|
/**
|
|
* @SWG\Property(description="The MAC Address of the Display")
|
|
* @var string
|
|
*/
|
|
public $clientAddress;
|
|
|
|
/**
|
|
* @SWG\Property(description="The media inventory status of the Display")
|
|
* @var int
|
|
*/
|
|
public $mediaInventoryStatus;
|
|
|
|
/**
|
|
* @SWG\Property(description="The current Mac Address of the Player")
|
|
* @var string
|
|
*/
|
|
public $macAddress;
|
|
|
|
/**
|
|
* @SWG\Property(description="A timestamp indicating the last time the Mac Address changed")
|
|
* @var int
|
|
*/
|
|
public $lastChanged;
|
|
|
|
/**
|
|
* @SWG\Property(description="A count of Mac Address changes")
|
|
* @var int
|
|
*/
|
|
public $numberOfMacAddressChanges;
|
|
|
|
/**
|
|
* @SWG\Property(description="A timestamp indicating the last time a WOL command was sent")
|
|
* @var int
|
|
*/
|
|
public $lastWakeOnLanCommandSent;
|
|
|
|
/**
|
|
* @SWG\Property(description="A flag indicating whether Wake On Lan is enabled")
|
|
* @var int
|
|
*/
|
|
public $wakeOnLanEnabled;
|
|
|
|
/**
|
|
* @SWG\Property(description="A h:i string indicating the time to send a WOL command")
|
|
* @var string
|
|
*/
|
|
public $wakeOnLanTime;
|
|
|
|
/**
|
|
* @SWG\Property(description="The broad cast address for this Display")
|
|
* @var string
|
|
*/
|
|
public $broadCastAddress;
|
|
|
|
/**
|
|
* @SWG\Property(description="The secureOn WOL settings for this display.")
|
|
* @var string
|
|
*/
|
|
public $secureOn;
|
|
|
|
/**
|
|
* @SWG\Property(description="The CIDR WOL settings for this display")
|
|
* @var string
|
|
*/
|
|
public $cidr;
|
|
|
|
/**
|
|
* @SWG\Property(description="The display Latitude")
|
|
* @var double
|
|
*/
|
|
public $latitude;
|
|
|
|
/**
|
|
* @SWG\Property(description="The display longitude")
|
|
* @var double
|
|
*/
|
|
public $longitude;
|
|
|
|
/**
|
|
* @SWG\Property(description="A string representing the player type")
|
|
* @var string
|
|
*/
|
|
public $clientType;
|
|
|
|
/**
|
|
* @SWG\Property(description="A string representing the player version")
|
|
* @var string
|
|
*/
|
|
public $clientVersion;
|
|
|
|
/**
|
|
* @SWG\Property(description="A number representing the Player version code")
|
|
* @var int
|
|
*/
|
|
public $clientCode;
|
|
|
|
/**
|
|
* @SWG\Property(description="The display settings profile ID for this Display")
|
|
* @var int
|
|
*/
|
|
public $displayProfileId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The current layout ID reported via XMDS")
|
|
* @var int
|
|
*/
|
|
public $currentLayoutId;
|
|
|
|
/**
|
|
* @SWG\Property(description="A flag indicating that a screen shot should be taken by the Player")
|
|
* @var int
|
|
*/
|
|
public $screenShotRequested;
|
|
|
|
/**
|
|
* @SWG\Property(description="The number of bytes of storage available on the device.")
|
|
* @var int
|
|
*/
|
|
public $storageAvailableSpace;
|
|
|
|
/**
|
|
* @SWG\Property(description="The number of bytes of storage in total on the device")
|
|
* @var int
|
|
*/
|
|
public $storageTotalSpace;
|
|
|
|
/**
|
|
* @SWG\Property(description="The ID of the Display Group for this Device")
|
|
* @var int
|
|
*/
|
|
public $displayGroupId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The current layout")
|
|
* @var string
|
|
*/
|
|
public $currentLayout;
|
|
|
|
/**
|
|
* @SWG\Property(description="The default layout")
|
|
* @var string
|
|
*/
|
|
public $defaultLayout;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Display Groups this Display belongs to")
|
|
* @var DisplayGroup[]
|
|
*/
|
|
public $displayGroups = [];
|
|
|
|
/**
|
|
* @SWG\Property(description="The Player Subscription Channel")
|
|
* @var string
|
|
*/
|
|
public $xmrChannel;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Player Public Key")
|
|
* @var string
|
|
*/
|
|
public $xmrPubKey;
|
|
|
|
/**
|
|
* @SWG\Property(description="The last command success, 0 = failure, 1 = success, 2 = unknown")
|
|
* @var int
|
|
*/
|
|
public $lastCommandSuccess = 0;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Device Name for the device hardware associated with this Display")
|
|
* @var string
|
|
*/
|
|
public $deviceName;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Display Timezone, or empty to use the CMS timezone")
|
|
* @var string
|
|
*/
|
|
public $timeZone;
|
|
|
|
/**
|
|
* @SWG\Property(description="Tags associated with this Display, array of TagLink objects")
|
|
* @var TagLink[]
|
|
*/
|
|
public $tags = [];
|
|
|
|
/**
|
|
* @SWG\Property(description="The configuration options that will overwrite Display Profile Config")
|
|
* @var string|array
|
|
*/
|
|
public $overrideConfig = [];
|
|
|
|
/**
|
|
* @SWG\Property(description="The display bandwidth limit")
|
|
* @var int
|
|
*/
|
|
public $bandwidthLimit;
|
|
|
|
/**
|
|
* @SWG\Property(description="The new CMS Address")
|
|
* @var string
|
|
*/
|
|
public $newCmsAddress;
|
|
|
|
/**
|
|
* @SWG\Property(description="The new CMS Key")
|
|
* @var string
|
|
*/
|
|
public $newCmsKey;
|
|
|
|
/**
|
|
* @SWG\Property(description="The orientation of the Display, either landscape or portrait")
|
|
* @var string
|
|
*/
|
|
public $orientation;
|
|
|
|
/**
|
|
* @SWG\Property(description="The resolution of the Display expressed as a string in the format WxH")
|
|
* @var string
|
|
*/
|
|
public $resolution;
|
|
|
|
/**
|
|
* @SWG\Property(description="Status of the commercial licence for this Display. 0 - Not licensed, 1 - licensed, 2 - trial licence, 3 - not applicable")
|
|
* @var int
|
|
*/
|
|
public $commercialLicence;
|
|
|
|
/**
|
|
* @SWG\Property(description="The TeamViewer serial number for this Display")
|
|
* @var string
|
|
*/
|
|
public $teamViewerSerial;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Webkey serial number for this Display")
|
|
* @var string
|
|
*/
|
|
public $webkeySerial;
|
|
|
|
/**
|
|
* @SWG\Property(description="A comma separated list of groups/users with permissions to this Display")
|
|
* @var string
|
|
*/
|
|
public $groupsWithPermissions;
|
|
|
|
/**
|
|
* @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 Folder this Display belongs to")
|
|
* @var int
|
|
*/
|
|
public $folderId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The id of the Folder responsible for providing permissions for this Display")
|
|
* @var int
|
|
*/
|
|
public $permissionsFolderId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The count of Player reported faults")
|
|
* @var int
|
|
*/
|
|
public $countFaults;
|
|
|
|
/**
|
|
* @SWG\Property(description="LAN IP Address, if available on the Player")
|
|
* @var string
|
|
*/
|
|
public $lanIpAddress;
|
|
|
|
/**
|
|
* @SWG\Property(description="The Display Group ID this Display is synced to")
|
|
* @var int
|
|
*/
|
|
public $syncGroupId;
|
|
|
|
/**
|
|
* @SWG\Property(description="The OS version of the Display")
|
|
* @var string
|
|
*/
|
|
public $osVersion;
|
|
|
|
/**
|
|
* @SWG\Property(description="The SDK version of the Display")
|
|
* @var string
|
|
*/
|
|
public $osSdk;
|
|
|
|
/**
|
|
* @SWG\Property(description="The manufacturer of the Display")
|
|
* @var string
|
|
*/
|
|
public $manufacturer;
|
|
|
|
/**
|
|
* @SWG\Property(description="The brand of the Display")
|
|
* @var string
|
|
*/
|
|
public $brand;
|
|
|
|
/**
|
|
* @SWG\Property(description="The model of the Display")
|
|
* @var string
|
|
*/
|
|
public $model;
|
|
|
|
/** @var array The configuration from the Display Profile */
|
|
private $profileConfig;
|
|
|
|
/** @var array Combined config */
|
|
private $combinedConfig;
|
|
|
|
/** @var \Xibo\Entity\DisplayProfile the resolved DisplayProfile for this Display */
|
|
private $_displayProfile;
|
|
|
|
private $datesToFormat = ['auditingUntil'];
|
|
|
|
/**
|
|
* Commands
|
|
* @var array[Command]
|
|
*/
|
|
private $commands = null;
|
|
|
|
public static $saveOptionsMinimum = ['validate' => false, 'audit' => false, 'setModifiedDt' => false];
|
|
|
|
/**
|
|
* @var ConfigServiceInterface
|
|
*/
|
|
private $config;
|
|
|
|
/**
|
|
* @var DisplayGroupFactory
|
|
*/
|
|
private $displayGroupFactory;
|
|
|
|
/**
|
|
* @var DisplayProfileFactory
|
|
*/
|
|
private $displayProfileFactory;
|
|
|
|
/**
|
|
* @var DisplayFactory
|
|
*/
|
|
private $displayFactory;
|
|
|
|
/**
|
|
* @var LayoutFactory
|
|
*/
|
|
private $layoutFactory;
|
|
|
|
/** @var FolderFactory */
|
|
private $folderFactory;
|
|
|
|
/**
|
|
* Entity constructor.
|
|
* @param StorageServiceInterface $store
|
|
* @param LogServiceInterface $log
|
|
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
|
|
* @param ConfigServiceInterface $config
|
|
* @param DisplayGroupFactory $displayGroupFactory
|
|
* @param DisplayProfileFactory $displayProfileFactory
|
|
* @param DisplayFactory $displayFactory
|
|
*/
|
|
public function __construct($store, $log, $dispatcher, $config, $displayGroupFactory, $displayProfileFactory, $displayFactory, $folderFactory)
|
|
{
|
|
$this->setCommonDependencies($store, $log, $dispatcher);
|
|
$this->excludeProperty('mediaInventoryXml');
|
|
$this->setPermissionsClass('Xibo\Entity\DisplayGroup');
|
|
$this->setCanChangeOwner(false);
|
|
|
|
$this->config = $config;
|
|
$this->displayGroupFactory = $displayGroupFactory;
|
|
$this->displayProfileFactory = $displayProfileFactory;
|
|
$this->displayFactory = $displayFactory;
|
|
$this->folderFactory = $folderFactory;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getId()
|
|
{
|
|
return $this->displayGroupId;
|
|
}
|
|
|
|
public function getPermissionFolderId()
|
|
{
|
|
return $this->permissionsFolderId;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getOwnerId()
|
|
{
|
|
// No owner
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get the cache key
|
|
* @return string
|
|
*/
|
|
public static function getCachePrefix()
|
|
{
|
|
return 'display/';
|
|
}
|
|
|
|
/**
|
|
* Get the cache key
|
|
* @return string
|
|
*/
|
|
public function getCacheKey()
|
|
{
|
|
return self::getCachePrefix() . $this->displayId;
|
|
}
|
|
|
|
/**
|
|
* @return \Xibo\Entity\DisplayProfile
|
|
* @throws \Xibo\Support\Exception\NotFoundException
|
|
*/
|
|
public function getDisplayProfile(): DisplayProfile
|
|
{
|
|
if ($this->_displayProfile === null) {
|
|
try {
|
|
if ($this->displayProfileId == 0) {
|
|
// Load the default profile
|
|
$displayProfile = $this->displayProfileFactory->getDefaultByType($this->clientType);
|
|
} else {
|
|
// Load the specified profile
|
|
$displayProfile = $this->displayProfileFactory->getById($this->displayProfileId);
|
|
}
|
|
} catch (NotFoundException) {
|
|
$this->getLog()->error('getDisplayProfile: Cannot get display profile, '
|
|
. $this->clientType . ' not found.');
|
|
|
|
$displayProfile = $this->displayProfileFactory->getUnknownProfile($this->clientType);
|
|
}
|
|
|
|
// Set our display profile
|
|
$this->_displayProfile = $displayProfile;
|
|
}
|
|
|
|
return $this->_displayProfile;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getLanguages()
|
|
{
|
|
return empty($this->languages) ? [] : explode(',', $this->languages);
|
|
}
|
|
|
|
/**
|
|
* @return bool true is this display is a PWA
|
|
*/
|
|
public function isPwa(): bool
|
|
{
|
|
return $this->clientType === 'chromeOS';
|
|
}
|
|
|
|
/**
|
|
* @return bool true is this display supports WebSocket XMR
|
|
*/
|
|
public function isWebSocketXmrSupported(): bool
|
|
{
|
|
return $this->clientType === 'chromeOS'
|
|
|| ($this->clientType === 'windows' && $this->clientCode >= 406)
|
|
|| ($this->clientType === 'android' && $this->clientCode >= 408);
|
|
}
|
|
|
|
/**
|
|
* Is this display auditing?
|
|
* return bool
|
|
*/
|
|
public function isAuditing(): bool
|
|
{
|
|
$this->getLog()->debug(sprintf(
|
|
'Testing whether this display is auditing. %d vs %d.',
|
|
$this->auditingUntil,
|
|
Carbon::now()->format('U')
|
|
));
|
|
|
|
// Test $this->auditingUntil against the current date.
|
|
return (!empty($this->auditingUntil) && $this->auditingUntil >= Carbon::now()->format('U'));
|
|
}
|
|
|
|
/**
|
|
* Does this display has elevated log level?
|
|
* @return bool
|
|
* @throws NotFoundException
|
|
*/
|
|
public function isElevatedLogging(): bool
|
|
{
|
|
$elevatedUntil = $this->getSetting('elevateLogsUntil', 0);
|
|
|
|
$this->getLog()->debug(sprintf(
|
|
'Testing whether this display has elevated log level. %d vs %d.',
|
|
$elevatedUntil,
|
|
Carbon::now()->format('U')
|
|
));
|
|
|
|
return (!empty($elevatedUntil) && $elevatedUntil >= Carbon::now()->format('U'));
|
|
}
|
|
|
|
/**
|
|
* Get current log level for this Display
|
|
* @return string
|
|
* @throws NotFoundException
|
|
*/
|
|
public function getLogLevel(): string
|
|
{
|
|
$restingLogLevel = $this->getSetting('logLevel', 'error');
|
|
$isElevated = $this->isElevatedLogging();
|
|
|
|
return $isElevated ? 'audit' : $restingLogLevel;
|
|
}
|
|
|
|
/**
|
|
* Set the Media Status to Incomplete
|
|
*/
|
|
public function notify()
|
|
{
|
|
$this->getLog()->debug($this->display . ' requests notify');
|
|
|
|
$this->displayFactory->getDisplayNotifyService()->collectNow()->notifyByDisplayId($this->displayId);
|
|
}
|
|
|
|
/**
|
|
* Validate the Object as it stands
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function validate()
|
|
{
|
|
if (!v::stringType()->notEmpty()->validate($this->display)) {
|
|
throw new InvalidArgumentException(__('Can not have a display without a name'), 'name');
|
|
}
|
|
|
|
if (!v::stringType()->notEmpty()->validate($this->license)) {
|
|
throw new InvalidArgumentException(__('Can not have a display without a hardware key'), 'license');
|
|
}
|
|
|
|
if ($this->wakeOnLanEnabled == 1 && $this->wakeOnLanTime == '') {
|
|
throw new InvalidArgumentException(
|
|
__('Wake on Lan is enabled, but you have not specified a time to wake the display'),
|
|
'wakeonlan'
|
|
);
|
|
}
|
|
// Broadcast Address
|
|
if ($this->broadCastAddress != '' && !v::ip()->validate($this->broadCastAddress)) {
|
|
throw new InvalidArgumentException(
|
|
__('BroadCast Address is not a valid IP Address'),
|
|
'broadCastAddress'
|
|
);
|
|
}
|
|
|
|
// CIDR
|
|
if (!empty($this->cidr) && !v::numeric()->between(0, 32)->validate($this->cidr)) {
|
|
throw new InvalidArgumentException(
|
|
__('CIDR subnet mask is not a number within the range of 0 to 32.'),
|
|
'cidr'
|
|
);
|
|
}
|
|
|
|
// secureOn
|
|
if ($this->secureOn != '') {
|
|
$this->secureOn = strtoupper($this->secureOn);
|
|
$this->secureOn = str_replace(':', '-', $this->secureOn);
|
|
|
|
if ((!preg_match('/([A-F0-9]{2}[-]){5}([0-9A-F]){2}/', $this->secureOn))
|
|
|| (strlen($this->secureOn) != 17)
|
|
) {
|
|
throw new InvalidArgumentException(
|
|
__('Pattern of secureOn-password is not "xx-xx-xx-xx-xx-xx" (x = digit or CAPITAL letter)'),
|
|
'secureOn'
|
|
);
|
|
}
|
|
}
|
|
|
|
// Mac Address Changes
|
|
if ($this->hasPropertyChanged('macAddress')) {
|
|
// Mac address change detected
|
|
$this->numberOfMacAddressChanges++;
|
|
$this->lastChanged = Carbon::now()->format('U');
|
|
}
|
|
|
|
// Lat/Long
|
|
if (!empty($this->longitude) && !v::longitude()->validate($this->longitude)) {
|
|
throw new InvalidArgumentException(__('The longitude entered is not valid.'), 'longitude');
|
|
}
|
|
|
|
if (!empty($this->latitude) && !v::latitude()->validate($this->latitude)) {
|
|
throw new InvalidArgumentException(__('The latitude entered is not valid.'), 'latitude');
|
|
}
|
|
|
|
if ($this->bandwidthLimit !== null && !v::intType()->min(0)->validate($this->bandwidthLimit)) {
|
|
throw new InvalidArgumentException(
|
|
__('Bandwidth limit must be a whole number greater than 0.'),
|
|
'bandwidthLimit'
|
|
);
|
|
}
|
|
|
|
// do we have default Layout set?
|
|
if (empty($this->defaultLayoutId)) {
|
|
// do we have global default Layout ?
|
|
$globalDefaultLayoutId = $this->config->getSetting('DEFAULT_LAYOUT');
|
|
if (!empty($globalDefaultLayoutId)) {
|
|
$this->getLog()->debug(
|
|
'No default Layout set on Display ID '
|
|
. $this->displayId
|
|
. ' falling back to global default Layout.'
|
|
);
|
|
$this->defaultLayoutId = $globalDefaultLayoutId;
|
|
$this->notify();
|
|
} else {
|
|
// we have no Default Layout and no global Default Layout
|
|
$this->getLog()->error(
|
|
'No global default Layout set and no default Layout set for Display ID ' . $this->displayId
|
|
);
|
|
throw new InvalidArgumentException(
|
|
__('Please set a Default Layout directly on this Display or in CMS Administrator Settings'),
|
|
'defaultLayoutId'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if there is display slot available, returns true when there are display slots available, return false if there are no display slots available
|
|
* @return boolean
|
|
*/
|
|
public function isDisplaySlotAvailable()
|
|
{
|
|
$maxDisplays = $this->config->GetSetting('MAX_LICENSED_DISPLAYS');
|
|
|
|
// Check the number of licensed displays
|
|
if ($maxDisplays > 0) {
|
|
$this->getLog()->debug(sprintf('Testing authorised displays against %d maximum. Currently authorised = %d, authorised = %d.', $maxDisplays, $this->currentlyLicensed, $this->licensed));
|
|
|
|
if ($this->currentlyLicensed != $this->licensed && $this->licensed == 1) {
|
|
$countLicensed = $this->getStore()->select('SELECT COUNT(DisplayID) AS CountLicensed FROM display WHERE licensed = 1', []);
|
|
|
|
$this->getLog()->debug(sprintf('There are %d authorised displays and we the maximum is %d', $countLicensed[0]['CountLicensed'], $maxDisplays));
|
|
|
|
if (intval($countLicensed[0]['CountLicensed']) + 1 > $maxDisplays) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Load
|
|
* @throws NotFoundException
|
|
*/
|
|
public function load()
|
|
{
|
|
if ($this->loaded)
|
|
return;
|
|
|
|
// Load this displays group membership
|
|
$this->displayGroups = $this->displayGroupFactory->getByDisplayId($this->displayId);
|
|
|
|
$this->loaded = true;
|
|
}
|
|
|
|
/**
|
|
* Save the media inventory status
|
|
*/
|
|
public function saveMediaInventoryStatus()
|
|
{
|
|
try {
|
|
$this->getStore()->updateWithDeadlockLoop('UPDATE `display` SET mediaInventoryStatus = :mediaInventoryStatus WHERE displayId = :displayId', [
|
|
'mediaInventoryStatus' => $this->mediaInventoryStatus,
|
|
'displayId' => $this->displayId
|
|
]);
|
|
} catch (DeadlockException $deadlockException) {
|
|
$this->getLog()->error('Media Inventory Status save failed due to deadlock');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save
|
|
* @param array $options
|
|
* @throws GeneralException
|
|
*/
|
|
public function save($options = [])
|
|
{
|
|
$options = array_merge([
|
|
'validate' => true,
|
|
'audit' => true,
|
|
'checkDisplaySlotAvailability' => true,
|
|
'setModifiedDt' => true,
|
|
], $options);
|
|
|
|
if ($options['validate']) {
|
|
$this->validate();
|
|
}
|
|
|
|
if ($options['checkDisplaySlotAvailability']) {
|
|
// Check if there are display slots available
|
|
$maxDisplays = $this->config->GetSetting('MAX_LICENSED_DISPLAYS');
|
|
|
|
if (!$this->isDisplaySlotAvailable()) {
|
|
throw new InvalidArgumentException(sprintf(
|
|
__('You have exceeded your maximum number of authorised displays. %d'),
|
|
$maxDisplays
|
|
), 'maxDisplays');
|
|
}
|
|
}
|
|
|
|
if ($this->displayId == null || $this->displayId == 0) {
|
|
$this->add();
|
|
} else {
|
|
$this->edit($options);
|
|
}
|
|
|
|
if ($options['audit'] && $this->getChangedProperties() != []) {
|
|
$this->getLog()->audit('Display', $this->displayId, 'Display Saved', $this->getChangedProperties());
|
|
}
|
|
|
|
// Trigger an update of all dynamic DisplayGroups?
|
|
if ($this->hasPropertyChanged('display') || $this->hasPropertyChanged('tags')) {
|
|
// Background update.
|
|
$this->getDispatcher()->dispatch(
|
|
new TriggerTaskEvent('\Xibo\XTR\MaintenanceRegularTask', 'DYNAMIC_DISPLAY_GROUP_ASSESSED'),
|
|
TriggerTaskEvent::$NAME
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete
|
|
* @throws GeneralException
|
|
*/
|
|
public function delete()
|
|
{
|
|
$this->load();
|
|
|
|
// Delete references
|
|
$this->getStore()->update('DELETE FROM `display_media` WHERE displayId = :displayId', [
|
|
'displayId' => $this->displayId
|
|
]);
|
|
$this->getStore()->update('DELETE FROM `requiredfile` WHERE displayId = :displayId', [
|
|
'displayId' => $this->displayId
|
|
]);
|
|
$this->getStore()->update('DELETE FROM `player_faults` WHERE displayId = :displayId', [
|
|
'displayId' => $this->displayId
|
|
]);
|
|
$this->getStore()->update('DELETE FROM `schedule_sync` WHERE displayId = :displayId', [
|
|
'displayId' => $this->displayId
|
|
]);
|
|
|
|
// Remove our display from any groups it is assigned to
|
|
foreach ($this->displayGroups as $displayGroup) {
|
|
$this->getDispatcher()->dispatch(new DisplayGroupLoadEvent($displayGroup), DisplayGroupLoadEvent::$NAME);
|
|
$displayGroup->load();
|
|
$displayGroup->unassignDisplay($this);
|
|
$displayGroup->save(['validate' => false, 'manageDynamicDisplayLinks' => false, 'allowNotify' => false]);
|
|
}
|
|
|
|
// Delete our display specific group
|
|
$displayGroup = $this->displayGroupFactory->getById($this->displayGroupId);
|
|
$this->getDispatcher()->dispatch(new DisplayGroupLoadEvent($displayGroup), DisplayGroupLoadEvent::$NAME);
|
|
$displayGroup->delete();
|
|
|
|
// Delete the display
|
|
$this->getStore()->update('DELETE FROM `display` WHERE displayId = :displayId', [
|
|
'displayId' => $this->displayId
|
|
]);
|
|
|
|
$this->getLog()->audit('Display', $this->displayId, 'Display Deleted', [
|
|
'displayId' => $this->displayId,
|
|
'display' => $this->display,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @throws GeneralException
|
|
* @throws NotFoundException
|
|
*/
|
|
private function add()
|
|
{
|
|
$this->displayId = $this->getStore()->insert('
|
|
INSERT INTO display (display, auditingUntil, defaultlayoutid, license, licensed, lastAccessed, inc_schedule, email_alert, alert_timeout, clientAddress, xmrChannel, xmrPubKey, lastCommandSuccess, macAddress, lastChanged, lastWakeOnLanCommandSent, client_type, client_version, client_code, overrideConfig, newCmsAddress, newCmsKey, commercialLicence, lanIpAddress, syncGroupId, osVersion, osSdk, manufacturer, brand, model)
|
|
VALUES (:display, :auditingUntil, :defaultlayoutid, :license, :licensed, :lastAccessed, :inc_schedule, :email_alert, :alert_timeout, :clientAddress, :xmrChannel, :xmrPubKey, :lastCommandSuccess, :macAddress, :lastChanged, :lastWakeOnLanCommandSent, :clientType, :clientVersion, :clientCode, :overrideConfig, :newCmsAddress, :newCmsKey, :commercialLicence, :lanIpAddress, :syncGroupId, :osVersion, :osSdk, :manufacturer, :brand, :model)
|
|
', [
|
|
'display' => $this->display,
|
|
'auditingUntil' => 0,
|
|
'defaultlayoutid' => $this->defaultLayoutId,
|
|
'license' => $this->license,
|
|
'licensed' => $this->licensed,
|
|
'lastAccessed' => $this->lastAccessed,
|
|
'inc_schedule' => 0,
|
|
'email_alert' => 0,
|
|
'alert_timeout' => 0,
|
|
'clientAddress' => $this->clientAddress,
|
|
'xmrChannel' => $this->xmrChannel,
|
|
'xmrPubKey' => ($this->xmrPubKey === null) ? '' : $this->xmrPubKey,
|
|
'lastCommandSuccess' => $this->lastCommandSuccess,
|
|
'macAddress' => $this->macAddress,
|
|
'lastChanged' => ($this->lastChanged === null) ? 0 : $this->lastChanged,
|
|
'lastWakeOnLanCommandSent' => ($this->lastWakeOnLanCommandSent === null) ? 0 : $this->lastWakeOnLanCommandSent,
|
|
'clientType' => $this->clientType,
|
|
'clientVersion' => $this->clientVersion,
|
|
'clientCode' => $this->clientCode,
|
|
'overrideConfig' => ($this->overrideConfig == '') ? null : json_encode($this->overrideConfig),
|
|
'newCmsAddress' => null,
|
|
'newCmsKey' => null,
|
|
'commercialLicence' => $this->commercialLicence,
|
|
'lanIpAddress' => empty($this->lanIpAddress) ? null : $this->lanIpAddress,
|
|
'syncGroupId' => empty($this->syncGroupId) ? null : $this->syncGroupId,
|
|
'osVersion' => $this->osVersion,
|
|
'osSdk' => $this->osSdk,
|
|
'manufacturer' => $this->manufacturer,
|
|
'brand' => $this->brand,
|
|
'model' => $this->model,
|
|
]);
|
|
|
|
|
|
$displayGroup = $this->displayGroupFactory->create();
|
|
$displayGroup->displayGroup = $this->display;
|
|
$displayGroup->tags = $this->tags;
|
|
|
|
// this is added from xmds, by default new displays will end up in root folder.
|
|
// Can be overridden per DISPLAY_DEFAULT_FOLDER setting
|
|
$folderId = $this->folderId ?? 1;
|
|
|
|
// If folderId is not set to Root Folder
|
|
// We need to check what permissionsFolderId should be set on the Display Group
|
|
if ($folderId !== 1) {
|
|
// just in case protect against no longer existing Folder.
|
|
try {
|
|
$folder = $this->folderFactory->getById($folderId, 0);
|
|
|
|
$displayGroup->folderId = $folder->getId();
|
|
$displayGroup->permissionsFolderId = $folder->getPermissionFolderIdOrThis();
|
|
} catch (NotFoundException $e) {
|
|
$this->getLog()->error('Display Default Folder no longer exists');
|
|
|
|
// if the Folder from settings no longer exists, default to Root Folder.
|
|
$displayGroup->folderId = 1;
|
|
$displayGroup->permissionsFolderId = 1;
|
|
}
|
|
} else {
|
|
$displayGroup->folderId = 1;
|
|
$displayGroup->permissionsFolderId = 1;
|
|
}
|
|
|
|
$displayGroup->setDisplaySpecificDisplay($this);
|
|
|
|
$this->getLog()->debug('Creating display specific group with userId ' . $displayGroup->userId);
|
|
|
|
$displayGroup->save();
|
|
}
|
|
|
|
|
|
/**
|
|
* @throws GeneralException
|
|
* @throws NotFoundException
|
|
*/
|
|
private function edit($options = [])
|
|
{
|
|
$this->getStore()->update('
|
|
UPDATE display
|
|
SET display = :display,
|
|
defaultlayoutid = :defaultLayoutId,
|
|
displayTypeId = :displayTypeId,
|
|
venueId = :venueId,
|
|
address = :address,
|
|
isMobile = :isMobile,
|
|
languages = :languages,
|
|
screenSize = :screenSize,
|
|
isOutdoor = :isOutdoor,
|
|
`customId` = :customId,
|
|
costPerPlay = :costPerPlay,
|
|
impressionsPerPlay = :impressionsPerPlay,
|
|
inc_schedule = :incSchedule,
|
|
license = :license,
|
|
licensed = :licensed,
|
|
auditingUntil = :auditingUntil,
|
|
email_alert = :emailAlert,
|
|
alert_timeout = :alertTimeout,
|
|
WakeOnLan = :wakeOnLanEnabled,
|
|
WakeOnLanTime = :wakeOnLanTime,
|
|
lastWakeOnLanCommandSent = :lastWakeOnLanCommandSent,
|
|
BroadCastAddress = :broadCastAddress,
|
|
SecureOn = :secureOn,
|
|
Cidr = :cidr,
|
|
GeoLocation = POINT(:latitude, :longitude),
|
|
displayprofileid = :displayProfileId,
|
|
lastaccessed = :lastAccessed,
|
|
loggedin = :loggedIn,
|
|
ClientAddress = :clientAddress,
|
|
MediaInventoryStatus = :mediaInventoryStatus,
|
|
client_type = :clientType,
|
|
client_version = :clientVersion,
|
|
client_code = :clientCode,
|
|
MacAddress = :macAddress,
|
|
LastChanged = :lastChanged,
|
|
NumberOfMacAddressChanges = :numberOfMacAddressChanges,
|
|
screenShotRequested = :screenShotRequested,
|
|
storageAvailableSpace = :storageAvailableSpace,
|
|
storageTotalSpace = :storageTotalSpace,
|
|
osVersion = :osVersion,
|
|
osSdk = :osSdk,
|
|
manufacturer = :manufacturer,
|
|
brand = :brand,
|
|
model = :model,
|
|
xmrChannel = :xmrChannel,
|
|
xmrPubKey = :xmrPubKey,
|
|
`lastCommandSuccess` = :lastCommandSuccess,
|
|
`deviceName` = :deviceName,
|
|
`timeZone` = :timeZone,
|
|
`overrideConfig` = :overrideConfig,
|
|
`newCmsAddress` = :newCmsAddress,
|
|
`newCmsKey` = :newCmsKey,
|
|
`orientation` = :orientation,
|
|
`resolution` = :resolution,
|
|
`commercialLicence` = :commercialLicence,
|
|
`teamViewerSerial` = :teamViewerSerial,
|
|
`webkeySerial` = :webkeySerial,
|
|
`lanIpAddress` = :lanIpAddress,
|
|
`syncGroupId` = :syncGroupId
|
|
WHERE displayid = :displayId
|
|
', [
|
|
'display' => $this->display,
|
|
'defaultLayoutId' => $this->defaultLayoutId,
|
|
'displayTypeId' => $this->displayTypeId === 0 ? null : $this->displayTypeId,
|
|
'venueId' => $this->venueId === 0 ? null : $this->venueId,
|
|
'address' => $this->address,
|
|
'isMobile' => $this->isMobile,
|
|
'languages' => $this->languages,
|
|
'screenSize' => $this->screenSize,
|
|
'isOutdoor' => $this->isOutdoor,
|
|
'customId' => $this->customId,
|
|
'costPerPlay' => $this->costPerPlay,
|
|
'impressionsPerPlay' => $this->impressionsPerPlay,
|
|
'incSchedule' => ($this->incSchedule == null) ? 0 : $this->incSchedule,
|
|
'license' => $this->license,
|
|
'licensed' => $this->licensed,
|
|
'auditingUntil' => ($this->auditingUntil == null) ? 0 : $this->auditingUntil,
|
|
'emailAlert' => $this->emailAlert,
|
|
'alertTimeout' => $this->alertTimeout,
|
|
'wakeOnLanEnabled' => $this->wakeOnLanEnabled,
|
|
'wakeOnLanTime' => $this->wakeOnLanTime,
|
|
'lastWakeOnLanCommandSent' => $this->lastWakeOnLanCommandSent,
|
|
'broadCastAddress' => $this->broadCastAddress,
|
|
'secureOn' => $this->secureOn,
|
|
'cidr' => $this->cidr,
|
|
'latitude' => $this->latitude,
|
|
'longitude' => $this->longitude,
|
|
'displayProfileId' => ($this->displayProfileId == null) ? null : $this->displayProfileId,
|
|
'lastAccessed' => $this->lastAccessed,
|
|
'loggedIn' => $this->loggedIn,
|
|
'clientAddress' => $this->clientAddress,
|
|
'mediaInventoryStatus' => $this->mediaInventoryStatus,
|
|
'clientType' => $this->clientType,
|
|
'clientVersion' => $this->clientVersion,
|
|
'clientCode' => $this->clientCode,
|
|
'macAddress' => $this->macAddress,
|
|
'lastChanged' => $this->lastChanged,
|
|
'numberOfMacAddressChanges' => $this->numberOfMacAddressChanges,
|
|
'screenShotRequested' => $this->screenShotRequested,
|
|
'storageAvailableSpace' => $this->storageAvailableSpace,
|
|
'storageTotalSpace' => $this->storageTotalSpace,
|
|
'xmrChannel' => $this->xmrChannel,
|
|
'xmrPubKey' => ($this->xmrPubKey === null) ? '' : $this->xmrPubKey,
|
|
'lastCommandSuccess' => $this->lastCommandSuccess,
|
|
'deviceName' => $this->deviceName,
|
|
'timeZone' => $this->timeZone,
|
|
'overrideConfig' => ($this->overrideConfig == '') ? null : json_encode($this->overrideConfig),
|
|
'newCmsAddress' => $this->newCmsAddress,
|
|
'newCmsKey' => $this->newCmsKey,
|
|
'orientation' => $this->orientation,
|
|
'resolution' => $this->resolution,
|
|
'commercialLicence' => $this->commercialLicence,
|
|
'teamViewerSerial' => empty($this->teamViewerSerial) ? null : $this->teamViewerSerial,
|
|
'webkeySerial' => empty($this->webkeySerial) ? null : $this->webkeySerial,
|
|
'lanIpAddress' => empty($this->lanIpAddress) ? null : $this->lanIpAddress,
|
|
'syncGroupId' => empty($this->syncGroupId) ? null : $this->syncGroupId,
|
|
'displayId' => $this->displayId,
|
|
'osVersion' => $this->osVersion,
|
|
'osSdk' => $this->osSdk,
|
|
'manufacturer' => $this->manufacturer,
|
|
'brand' => $this->brand,
|
|
'model' => $this->model,
|
|
]);
|
|
|
|
// Maintain the Display Group
|
|
if ($this->hasPropertyChanged('display')
|
|
|| $this->hasPropertyChanged('description')
|
|
|| $this->hasPropertyChanged('tags')
|
|
|| $this->hasPropertyChanged('bandwidthLimit')
|
|
|| $this->hasPropertyChanged('folderId')
|
|
|| $this->hasPropertyChanged('ref1')
|
|
|| $this->hasPropertyChanged('ref2')
|
|
|| $this->hasPropertyChanged('ref3')
|
|
|| $this->hasPropertyChanged('ref4')
|
|
|| $this->hasPropertyChanged('ref5')
|
|
) {
|
|
$this->getLog()->debug('Display specific DisplayGroup properties need updating');
|
|
|
|
$displayGroup = $this->displayGroupFactory->getById($this->displayGroupId);
|
|
$displayGroup->load();
|
|
$displayGroup->displayGroup = $this->display;
|
|
$displayGroup->description = $this->description;
|
|
$displayGroup->bandwidthLimit = $this->bandwidthLimit;
|
|
$displayGroup->ref1 = $this->ref1;
|
|
$displayGroup->ref2 = $this->ref2;
|
|
$displayGroup->ref3 = $this->ref3;
|
|
$displayGroup->ref4 = $this->ref4;
|
|
$displayGroup->ref5 = $this->ref5;
|
|
|
|
// Tags
|
|
$saveTags = false;
|
|
if ($this->hasPropertyChanged('tags')) {
|
|
$saveTags = true;
|
|
$displayGroup->updateTagLinks($this->tags);
|
|
}
|
|
|
|
// If the folderId has changed, we should check this user has permissions to the new folderId
|
|
// it shouldn't ever be null, but just in case.
|
|
$displayGroup->folderId = ($this->folderId == null) ? 1 : $this->folderId;
|
|
if ($this->hasPropertyChanged('folderId')) {
|
|
$folder = $this->folderFactory->getById($displayGroup->folderId, 0);
|
|
// We have permission, so assert the new folder's permission id
|
|
$displayGroup->permissionsFolderId = $folder->getPermissionFolderIdOrThis();
|
|
}
|
|
|
|
// manageDisplayLinks is false because we never update a display specific display group's display links
|
|
$displayGroup->save([
|
|
'validate' => false,
|
|
'saveGroup' => true,
|
|
'manageLinks' => false,
|
|
'manageDisplayLinks' => false,
|
|
'manageDynamicDisplayLinks' => false,
|
|
'allowNotify' => true,
|
|
'saveTags' => $saveTags,
|
|
'setModifiedDt' => $options['setModifiedDt'],
|
|
]);
|
|
} else if ($options['setModifiedDt']) {
|
|
// Bump the modified date.
|
|
$this->store->update('
|
|
UPDATE displaygroup
|
|
SET `modifiedDt` = :modifiedDt
|
|
WHERE displayGroupId = :displayGroupId
|
|
', [
|
|
'modifiedDt' => Carbon::now()->format(DateFormatHelper::getSystemFormat()),
|
|
'displayGroupId' => $this->displayGroupId
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the Settings Profile for this Display
|
|
* @param array $options
|
|
* @return array
|
|
* @throws GeneralException
|
|
*/
|
|
public function getSettings($options = [])
|
|
{
|
|
$options = array_merge([
|
|
'displayOverride' => false
|
|
], $options);
|
|
|
|
return $this->setConfig($options);
|
|
}
|
|
|
|
/**
|
|
* @return Command[]
|
|
*/
|
|
public function getCommands()
|
|
{
|
|
if ($this->commands == null) {
|
|
$displayProfile = $this->getDisplayProfile();
|
|
|
|
// Set any commands
|
|
$this->commands = $displayProfile->commands;
|
|
}
|
|
|
|
return $this->commands;
|
|
}
|
|
|
|
/**
|
|
* Get a particular setting
|
|
* @param string $key
|
|
* @param mixed $default
|
|
* @param array $options
|
|
* @return mixed
|
|
* @throws NotFoundException
|
|
*/
|
|
public function getSetting($key, $default = null, $options = [])
|
|
{
|
|
$options = array_merge([
|
|
'displayOverride' => true,
|
|
'displayOnly' => false
|
|
], $options);
|
|
|
|
$this->setConfig($options);
|
|
|
|
// Find
|
|
$return = $default;
|
|
if ($options['displayOnly']) {
|
|
// Only get an option if set from the override config on this display
|
|
foreach ($this->overrideConfig as $row) {
|
|
if ($row['name'] == $key || $row['name'] == ucfirst($key)) {
|
|
$return = array_key_exists('value', $row) ? $row['value'] : ((array_key_exists('default', $row)) ? $row['default'] : $default);
|
|
break;
|
|
}
|
|
}
|
|
} else if ($options['displayOverride']) {
|
|
// Get the option from the combined array of config
|
|
foreach ($this->combinedConfig as $row) {
|
|
if ($row['name'] == $key || $row['name'] == ucfirst($key)) {
|
|
$return = array_key_exists('value', $row) ? $row['value'] : ((array_key_exists('default', $row)) ? $row['default'] : $default);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
// Get the option from the profile only
|
|
foreach ($this->profileConfig as $row) {
|
|
if ($row['name'] == $key || $row['name'] == ucfirst($key)) {
|
|
$return = array_key_exists('value', $row) ? $row['value'] : ((array_key_exists('default', $row)) ? $row['default'] : $default);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Set the config array
|
|
* @param array $options
|
|
* @return array
|
|
* @throws NotFoundException
|
|
*/
|
|
private function setConfig(array $options = []): array
|
|
{
|
|
$options = array_merge([
|
|
'displayOverride' => false
|
|
], $options);
|
|
|
|
if ($this->profileConfig == null) {
|
|
$this->load();
|
|
|
|
// Get the display profile
|
|
try {
|
|
$displayProfile = $this->getDisplayProfile();
|
|
} catch (NotFoundException) {
|
|
$displayProfile = $this->displayProfileFactory->getUnknownProfile($this->clientType);
|
|
}
|
|
|
|
// Merge in any overrides we have on our display.
|
|
$this->profileConfig = $displayProfile->getProfileConfig();
|
|
$this->combinedConfig = $this->mergeConfigs($this->profileConfig, $this->overrideConfig);
|
|
}
|
|
|
|
return ($options['displayOverride']) ? $this->combinedConfig : $this->profileConfig;
|
|
}
|
|
|
|
/**
|
|
* Merge two configs
|
|
* @param $default
|
|
* @param $override
|
|
* @return array
|
|
*/
|
|
private function mergeConfigs($default, $override): array
|
|
{
|
|
// No overrides, then nothing to do.
|
|
if (empty($override) || !is_array($override)) {
|
|
return $default;
|
|
}
|
|
|
|
// Merge the settings together
|
|
foreach ($default as &$defaultItem) {
|
|
for ($i = 0; $i < count($override); $i++) {
|
|
if ($defaultItem['name'] == $override[$i]['name']) {
|
|
// For special json fields, we need to decode, merge, encode and save instead
|
|
if (in_array($defaultItem['name'], ['timers', 'pictureOptions', 'lockOptions'])
|
|
&& isset($defaultItem['value']) && isset($override[$i]['value'])
|
|
) {
|
|
// Decode values
|
|
$defaultItemValueDecoded = json_decode($defaultItem['value'], true);
|
|
$overrideValueDecoded = json_decode($override[$i]['value'], true);
|
|
|
|
// Merge values, encode and save
|
|
$defaultItem['value'] = json_encode(array_merge(
|
|
$defaultItemValueDecoded,
|
|
$overrideValueDecoded
|
|
));
|
|
} else {
|
|
// merge
|
|
$defaultItem = array_merge($defaultItem, $override[$i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Merge the remainder
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* @param PoolInterface $pool
|
|
* @return int|null
|
|
*/
|
|
public function getCurrentLayoutId($pool, LayoutFactory $layoutFactory)
|
|
{
|
|
$item = $pool->getItem('/currentLayoutId/' . $this->displayId);
|
|
|
|
$data = $item->get();
|
|
|
|
if ($item->isHit()) {
|
|
$this->currentLayoutId = $data;
|
|
|
|
try {
|
|
$this->currentLayout = $layoutFactory->getById($this->currentLayoutId)->layout;
|
|
}
|
|
catch (NotFoundException $notFoundException) {
|
|
// This is ok
|
|
}
|
|
} else {
|
|
$this->getLog()->debug('Cache miss for setCurrentLayoutId on display ' . $this->display);
|
|
}
|
|
|
|
return $this->currentLayoutId;
|
|
}
|
|
|
|
/**
|
|
* @param PoolInterface $pool
|
|
* @param int $currentLayoutId
|
|
* @return $this
|
|
* @throws \Exception
|
|
*/
|
|
public function setCurrentLayoutId($pool, $currentLayoutId)
|
|
{
|
|
// Cache it
|
|
$this->getLog()->debug('Caching currentLayoutId with Pool');
|
|
|
|
$item = $pool->getItem('/currentLayoutId/' . $this->displayId);
|
|
$item->set($currentLayoutId);
|
|
$item->expiresAfter(new \DateInterval('P1W'));
|
|
|
|
$pool->saveDeferred($item);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param PoolInterface $pool
|
|
* @return int|null
|
|
*/
|
|
public function getCurrentScreenShotTime($pool)
|
|
{
|
|
$item = $pool->getItem('/screenShotTime/' . $this->displayId);
|
|
|
|
return $item->get();
|
|
}
|
|
|
|
/**
|
|
* @param PoolInterface $pool
|
|
* @param string $date
|
|
* @return $this
|
|
* @throws \Exception
|
|
*/
|
|
public function setCurrentScreenShotTime($pool, $date)
|
|
{
|
|
// Cache it
|
|
$this->getLog()->debug('Caching currentLayoutId with Pool');
|
|
|
|
$item = $pool->getItem('/screenShotTime/' . $this->displayId);
|
|
$item->set($date);
|
|
$item->expiresAfter(new \DateInterval('P1W'));
|
|
|
|
$pool->saveDeferred($item);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param PoolInterface $pool
|
|
* @return array
|
|
*/
|
|
public function getStatusWindow($pool)
|
|
{
|
|
$item = $pool->getItem('/statusWindow/' . $this->displayId);
|
|
|
|
if ($item->isMiss()) {
|
|
return [];
|
|
} else {
|
|
// special handling for Android
|
|
if ($this->clientType === 'android') {
|
|
return nl2br($item->get());
|
|
} else {
|
|
return $item->get();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param PoolInterface $pool
|
|
* @param array $status
|
|
* @return $this
|
|
*/
|
|
public function setStatusWindow($pool, $status)
|
|
{
|
|
// Cache it
|
|
$this->getLog()->debug('Caching statusWindow with Pool');
|
|
|
|
$item = $pool->getItem('/statusWindow/' . $this->displayId);
|
|
$item->set($status);
|
|
$item->expiresAfter(new \DateInterval('P1D'));
|
|
|
|
$pool->saveDeferred($item);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Check if this Display is set as Lead Display on any Sync Group
|
|
* @return bool
|
|
*/
|
|
public function isLead(): bool
|
|
{
|
|
$syncGroups = $this->getStore()->select(
|
|
'SELECT syncGroupId FROM `syncgroup` WHERE `syncgroup`.leadDisplayId = :displayId',
|
|
['displayId' => $this->displayId]
|
|
);
|
|
|
|
return count($syncGroups) > 0;
|
|
}
|
|
}
|