. */ namespace Xibo\Entity; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Xibo\Factory\ModuleTemplateFactory; use Xibo\Service\LogServiceInterface; use Xibo\Storage\StorageServiceInterface; use Xibo\Widget\Definition\Asset; /** * Represents a module template * @SWG\Definition() */ class ModuleTemplate implements \JsonSerializable { use EntityTrait; use ModulePropertyTrait; /** @var int The database ID */ public $id; /** * @SWG\Property() * @var string The templateId */ public $templateId; /** * @SWG\Property() * @var string Type of template (static|element|stencil) */ public $type; /** * @SWG\Property() * @var \Xibo\Widget\Definition\Extend|null If this template extends another */ public $extends; /** * @SWG\Property() * @var string The datatype of this template */ public $dataType; /** * @SWG\Property() * @var string The title */ public $title; /** * @SWG\Property(description="Description of the Module Template") * @var string */ public $description; /** * @SWG\Property() * @var string Icon */ public $icon; /** * @SWG\Property() * Thumbnail * this is the location to a module template's thumbnail, which should be added to the installation * relative to the module class file. * @var string */ public $thumbnail; /** @var int The width of the zone */ public $startWidth; /** @var int The height of the zone */ public $startHeight; /** @var bool Does this template have dimensions? */ public $hasDimensions; /** @var bool Can this template be rotated? */ public $canRotate; /** * @SWG\Property(description="A flag indicating whether the template should be excluded from the Layout Editor") * @var string */ public $showIn = 'both'; /** * @SWG\Property() * @var \Xibo\Widget\Definition\Property[]|null Properties */ public $properties; /** * @SWG\Property() * @var bool Is Visible? */ public $isVisible = true; /** * @SWG\Property() * @var bool Is Enabled? */ public $isEnabled = true; /** * @SWG\Property(description="An array of additional module specific group properties") * @var \Xibo\Widget\Definition\PropertyGroup[] */ public $propertyGroups = []; /** * @SWG\Property() * @var \Xibo\Widget\Definition\Stencil|null A stencil, if needed */ public $stencil; /** * @SWG\Property() * @var Asset[] */ public $assets; /** @var string A Renderer to run if custom rendering is required. */ public $onTemplateRender; /** @var string JavaScript function run when the template becomes visible. */ public $onTemplateVisible; /** @var string A data parser for elements */ public $onElementParseData; /** @var bool $isError Does this module have any errors? */ public $isError; /** @var string[] $errors An array of errors this module has. */ public $errors; /** @var string $ownership Who owns this file? system|custom|user */ public $ownership; /** @var int $ownerId User ID of the owner of this template */ public $ownerId; /** * @SWG\Property(description="A comma separated list of groups/users with permissions to this template") * @var string */ public $groupsWithPermissions; /** @var string $xml The XML used to build this template */ private $xml; /** @var \DOMDocument The DOM Document for this templates XML */ private $document; /** @var \Xibo\Factory\ModuleTemplateFactory */ private $moduleTemplateFactory; /** * Entity constructor. * @param \Xibo\Storage\StorageServiceInterface $store * @param LogServiceInterface $log * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher * @param \Xibo\Factory\ModuleTemplateFactory $moduleTemplateFactory * @param string $file The file this template resides in */ public function __construct( StorageServiceInterface $store, LogServiceInterface $log, EventDispatcherInterface $dispatcher, ModuleTemplateFactory $moduleTemplateFactory, private readonly string $file ) { $this->setCommonDependencies($store, $log, $dispatcher); $this->setPermissionsClass('Xibo\Entity\ModuleTemplate'); $this->moduleTemplateFactory = $moduleTemplateFactory; } public function getId() { return $this->id; } public function getOwnerId() { return $this->ownerId; } public function __clone() { $this->id = null; $this->templateId = null; } /** * Get assets * @return \Xibo\Widget\Definition\Asset[] */ public function getAssets(): array { return $this->assets; } /** * Set XML for this Module Template * @param string $xml * @return void */ public function setXml(string $xml): void { $this->xml = $xml; } /** * Get XML for this Module Template * @return string */ public function getXml(): string { // for system templates if ($this->file !== 'database') { $xml = new \DOMDocument(); // load whole file to document $xml->loadXML(file_get_contents($this->file)); // go through template tags foreach ($xml->getElementsByTagName('template') as $templateXml) { if ($templateXml instanceof \DOMElement) { foreach ($templateXml->childNodes as $childNode) { if ($childNode instanceof \DOMElement) { // match the template to what was requested // set the xml and return it. if ($childNode->nodeName === 'id' && $childNode->nodeValue == $this->templateId) { $this->setXml($xml->saveXML($templateXml)); } } } } } } return $this->xml; } /** * Set Document * @param \DOMDocument $document * @return void */ public function setDocument(\DOMDocument $document): void { $this->document = $document; } /** * Get this templates DOM document * @return \DOMDocument */ public function getDocument(): \DOMDocument { if ($this->document === null) { $this->document = new \DOMDocument(); $this->document->load($this->getXml()); } return $this->document; } /** * Save * @return void */ public function save(): void { if ($this->file === 'database') { if ($this->id === null) { $this->add(); } else { $this->edit(); } } } /** * Delete * @return void */ public function delete(): void { if ($this->file === 'database') { $this->getStore()->update('DELETE FROM module_templates WHERE id = :id', [ 'id' => $this->id ]); } } /** * Invalidate this module template for any widgets that use it * @return void */ public function invalidate(): void { // TODO: can we improve this via the event mechanism instead? $this->getStore()->update(' UPDATE `widget` SET modifiedDt = :now WHERE widgetId IN ( SELECT widgetId FROM widgetoption WHERE `option` = \'templateId\' AND `value` = :templateId ) ', [ 'now' => time(), 'templateId' => $this->templateId, ]); } /** * Add * @return void */ private function add(): void { $this->id = $this->getStore()->insert(' INSERT INTO `module_templates` (`templateId`, `dataType`, `xml`, `ownerId`) VALUES (:templateId, :dataType, :xml, :ownerId) ', [ 'templateId' => $this->templateId, 'dataType' => $this->dataType, 'xml' => $this->xml, 'ownerId' => $this->ownerId, ]); } /** * Edit * @return void */ private function edit(): void { $this->getStore()->update(' UPDATE `module_templates` SET `templateId` = :templateId, `dataType`= :dataType, `enabled` = :enabled, `xml` = :xml, `ownerId` = :ownerId WHERE `id` = :id ', [ 'templateId' => $this->templateId, 'dataType' => $this->dataType, 'xml' => $this->xml, 'enabled' => $this->isEnabled ? 1 : 0, 'ownerId' => $this->ownerId, 'id' => $this->id, ]); } }