HEX
Server: Apache
System: Linux server2.voipitup.com.au 4.18.0-553.109.1.lve.el8.x86_64 #1 SMP Thu Mar 5 20:23:46 UTC 2026 x86_64
User: posscale (1027)
PHP: 8.2.30
Disabled: exec,passthru,shell_exec,system
Upload Files
File: /home/posscale/subdomains/xibo/lib/Upgrade/LayoutStructureStep.php
<?php
/*
 * Spring Signage Ltd - http://www.springsignage.com
 * Copyright (C) 2015 Spring Signage Ltd
 * (LayoutStructureStep.php)
 */


namespace Xibo\Upgrade;


use Xibo\Factory\LayoutFactory;
use Xibo\Factory\PermissionFactory;
use Xibo\Helper\Install;
use Xibo\Service\ConfigServiceInterface;
use Xibo\Service\LogServiceInterface;
use Xibo\Storage\StorageServiceInterface;

/**
 * Class LayoutStructureStep
 * @package Xibo\Upgrade
 */
class LayoutStructureStep implements Step
{
    /** @var  StorageServiceInterface */
    private $store;

    /** @var  LogServiceInterface */
    private $log;

    /** @var  ConfigServiceInterface */
    private $config;

    /**
     * DataSetConvertStep constructor.
     * @param StorageServiceInterface $store
     * @param LogServiceInterface $log
     * @param ConfigServiceInterface $config
     */
    public function __construct($store, $log, $config)
    {
        $this->store = $store;
        $this->log = $log;
        $this->config = $config;
    }

    /**
     * @param \Slim\Helper\Set $container
     * @throws \Xibo\Exception\NotFoundException
     */
    public function doStep($container)
    {
        /** @var PermissionFactory $permissionFactory */
        $permissionFactory = $container->get('permissionFactory');

        /** @var LayoutFactory $layoutFactory */
        $layoutFactory = $container->get('layoutFactory');

        // Create the new structure
        $dbh = $this->store->getConnection();

        // Run the SQL to create the necessary tables
        $statements = Install::remove_remarks(self::$dbStructure);
        $statements = Install::split_sql_file($statements, ';');

        foreach ($statements as $sql) {
            $dbh->exec($sql);
        }

        // Build a keyed array of existing widget permissions
        $mediaPermissions = [];
        foreach ($this->store->select('SELECT groupId, layoutId, regionId, mediaId, `view`, `edit`, `del` FROM `lklayoutmediagroup`', []) as $row) {
            $permission = $permissionFactory->createEmpty();
            $permission->entityId = 6; // Widget
            $permission->groupId = $row['groupId'];
            $permission->objectId = $row['layoutId'];
            $permission->objectIdString = $row['regionId'];
            $permission->view = $row['view'];
            $permission->edit = $row['edit'];
            $permission->delete = $row['del'];

            $mediaPermissions[$row['mediaId']] = $permission;
        }

        // Build a keyed array of existing region permissions
        $regionPermissions = [];
        foreach ($this->store->select('SELECT groupId, layoutId, regionId, `view`, `edit`, `del` FROM `lklayoutregiongroup`', []) as $row) {
            $permission = $permissionFactory->createEmpty();
            $permission->entityId = 7; // Widget
            $permission->groupId = $row['groupId'];
            $permission->objectId = $row['layoutId'];
            $permission->view = $row['view'];
            $permission->edit = $row['edit'];
            $permission->delete = $row['del'];

            $regionPermissions[$row['regionId']] = $permission;
        }

        // Get the library location to store backups of existing XLF
        $libraryLocation = $this->config->GetSetting('LIBRARY_LOCATION');

        // We need to go through each layout, save the XLF as a backup in the library and then upgrade it.
        foreach ($this->store->select('SELECT layoutId, xml FROM `layout`', []) as $oldLayout) {

            $oldLayoutId = intval($oldLayout['layoutId']);

            try {
                // Does this layout have any XML associated with it? If not, then it is an empty layout.
                if (empty($oldLayout['xml'])) {
                    // This is frankly, odd, so we better log it
                    $this->log->critical('Layout upgrade without any existing XLF, i.e. empty. ID = ' . $oldLayoutId);

                    // Pull out the layout record, and set some best guess defaults
                    $layout = $layoutFactory->getById($oldLayoutId);
                    $layout->schemaVersion = 2;
                    $layout->width = 1920;
                    $layout->height = 1080;

                } else {
                    // Save off a copy of the XML in the library
                    file_put_contents($libraryLocation . 'archive_' . $oldLayoutId . '.xlf', $oldLayout['xml']);

                    // Create a new layout from the XML
                    $layout = $layoutFactory->loadByXlf($oldLayout['xml'], $layoutFactory->getById($oldLayoutId));
                }

                // Save the layout
                $layout->save(['notify' => false]);

                // Now that we have new ID's we need to cross reference them with the old IDs and recreate the permissions
                foreach ($layout->regions as $region) {
                    /* @var \Xibo\Entity\Region $region */
                    if (array_key_exists($region->tempId, $regionPermissions)) {
                        $permission = $regionPermissions[$region->tempId];
                        /* @var \Xibo\Entity\Permission $permission */
                        // Double check we are for the same layout
                        if ($permission->objectId == $layout->layoutId) {
                            $permission = clone $permission;
                            $permission->objectId = $region->regionId;
                            $permission->save();
                        }
                    }

                    foreach ($region->playlists as $playlist) {
                        /* @var \Xibo\Entity\Playlist $playlist */
                        foreach ($playlist->widgets as $widget) {
                            /* @var \Xibo\Entity\Widget $widget */
                            if (array_key_exists($widget->tempId, $mediaPermissions)) {
                                $permission = $mediaPermissions[$widget->tempId];
                                /* @var \Xibo\Entity\Permission $permission */
                                if ($permission->objectId == $layout->layoutId && $region->tempId == $permission->objectIdString) {
                                    $permission = clone $permission;
                                    $permission->objectId = $widget->widgetId;
                                    $permission->save();
                                }
                            }
                        }
                    }
                }
            } catch (\Exception $e) {
                $this->log->critical('Error upgrading Layout, this should be checked post-upgrade. ID: ' . $oldLayoutId);
                $this->log->error($e->getMessage() . ' - ' . $e->getTraceAsString());
            }
        }

        // Drop the permissions
        $dbh->exec('DROP TABLE `lklayoutmediagroup`;');
        $dbh->exec('DROP TABLE `lklayoutregiongroup`;');
    }

    private static $dbStructure = <<<END
CREATE TABLE IF NOT EXISTS `lkregionplaylist` (
`regionId` int(11) NOT NULL,
`playlistId` int(11) NOT NULL,
`displayOrder` int(11) NOT NULL,
PRIMARY KEY (`regionId`,`playlistId`,`displayOrder`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `lkwidgetmedia` (
`widgetId` int(11) NOT NULL,
`mediaId` int(11) NOT NULL,
PRIMARY KEY (`widgetId`,`mediaId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `playlist` (
`playlistId` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(254) DEFAULT NULL,
`ownerId` int(11) NOT NULL,
PRIMARY KEY (`playlistId`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `region` (
`regionId` int(11) NOT NULL AUTO_INCREMENT,
`layoutId` int(11) NOT NULL,
`ownerId` int(11) NOT NULL,
`name` varchar(254) DEFAULT NULL,
`width` decimal(12,4) NOT NULL,
`height` decimal(12,4) NOT NULL,
`top` decimal(12,4) NOT NULL,
`left` decimal(12,4) NOT NULL,
`zIndex` smallint(6) NOT NULL,
`duration` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`regionId`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `regionoption` (
`regionId` int(11) NOT NULL,
`option` varchar(50) NOT NULL,
`value` text NULL,
PRIMARY KEY (`regionId`,`option`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `widget` (
`widgetId` int(11) NOT NULL AUTO_INCREMENT,
`playlistId` int(11) NOT NULL,
`ownerId` int(11) NOT NULL,
`type` varchar(50) NOT NULL,
`duration` int(11) NOT NULL,
`displayOrder` int(11) NOT NULL,
`calculatedDuration` int(11) NOT NULL,
`useDuration` tinyint(4) DEFAULT '1',
PRIMARY KEY (`widgetId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `widgetoption` (
`widgetId` int(11) NOT NULL,
`type` varchar(50) NOT NULL,
`option` varchar(254) NOT NULL,
`value` text NULL,
PRIMARY KEY (`widgetId`,`type`,`option`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
END;

}