Skip to content
Code-Schnipsel Gruppen Projekte
Manager.php 36,9 KiB
Newer Older
  • Learn to ignore specific revisions
  • Henning Leutz's avatar
    Henning Leutz committed
    <?php
    
    /**
     * This file contains \QUI\Bricks\Manager
     */
    
    namespace QUI\Bricks;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use DOMElement;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use DOMXPath;
    
    use Exception;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI;
    
    use QUI\ExceptionStack;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI\Projects\Project;
    use QUI\Projects\Site;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function array_filter;
    use function array_flip;
    use function array_map;
    use function array_merge;
    use function array_reverse;
    use function array_unique;
    use function array_values;
    use function class_exists;
    use function count;
    
    use function defined;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function explode;
    
    use function file_exists;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function implode;
    use function in_array;
    use function is_array;
    use function is_callable;
    use function json_decode;
    use function json_encode;
    use function md5;
    use function realpath;
    use function str_replace;
    use function trim;
    use function usort;
    
    
    use const OPT_DIR;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    /**
     * Brick Manager
     *
     * @package quiqqer/bricks
     */
    class Manager
    {
        /**
         * Bricks table name
         */
        const TABLE = 'bricks';
    
    
        /**
         * Bricks uid table name
         */
        const TABLE_UID = 'bricksUID';
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Brick Cache table name
         */
        const TABLE_CACHE = 'bricksCache';
    
        /**
         * Brick temp collector
         *
         * @var array
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        protected array $bricks = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
        /**
         * Brick UID temp collector
         *
         * @var array
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        protected array $brickUIDs = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Initialized brick manager
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public static ?Manager $BrickManager = null;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
        /**
         * Return the global QUI\Bricks\Manager
         *
    
         * @return Manager|null
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public static function init(): ?Manager
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (self::$BrickManager === null) {
    
                self::$BrickManager = new Manager(true);
    
    Henning Leutz's avatar
    Henning Leutz committed
            return self::$BrickManager;
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        /**
         * Constructor
         * Please use \QUI\Bricks\Manager::init()
         *
         * @param boolean $init - please use \QUI\Bricks\Manager::init()
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function __construct(bool $init = false)
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            if ($init === false) {
                QUI\System\Log::addWarning('Please use \QUI\Bricks\Manager::init()');
            }
        }
    
    
         *
         * @return String
         */
    
        public static function getTable(): string
    
        {
            return QUI::getDBTableName(self::TABLE);
        }
    
        /**
         * @return string
         */
    
        public static function getUIDTable(): string
    
        {
            return QUI::getDBTableName(self::TABLE_UID);
        }
    
    
        /**
         * Return the long time cache namespace
         *
         * @return string
         */
    
        public static function getBrickCacheNamespace(): string
    
        {
            return 'quiqqer/package/quiqqer/bricks/';
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Creates a new brick for the project
         *
         * @param Project $Project
         * @param Brick $Brick
         *
         * @return integer - Brick-ID
    
         *
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function createBrickForProject(Project $Project, Brick $Brick): int
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            QUI\Permissions\Permission::checkPermission('quiqqer.bricks.create');
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            QUI::getDataBase()->insert(
                $this->getTable(),
    
                    'project' => $Project->getName(),
                    'lang' => $Project->getLang(),
                    'title' => $Brick->getAttribute('title'),
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'description' => $Brick->getAttribute('description'),
    
                    'type' => $Brick->getAttribute('type')
    
            $brickId = QUI::getPDO()->lastInsertId();
    
            try {
                QUI::getEvents()->fireEvent('quiqqerBricksCreate', [$brickId]);
    
            } catch (Exception $Exception) {
    
                QUI\System\Log::writeException($Exception);
            }
    
    
         * @param QUI\Interfaces\Projects\Site $Site
    
         * @param array $brickData
         * @return string - Unique ID
    
         *
         * @throws QUI\Exception
    
        public function createUniqueSiteBrick(QUI\Interfaces\Projects\Site $Site, array $brickData = []): string
    
            if (!empty($brickData['uid'])) {
    
                $uid = $brickData['uid'];
    
                if ($this->existsUniqueBrickId($uid) === false) {
                    $uid = $this->createUniqueBrickId((int)$brickData['brickId'], $Site);
                }
            } else {
                $uid = $this->createUniqueBrickId((int)$brickData['brickId'], $Site);
            }
    
    
    
            if (isset($brickData['customfields'])) {
                $customFields = $brickData['customfields'];
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_array($customFields)) {
                $customFields = json_encode($customFields);
    
            QUI::getDataBase()->update($this->getUIDTable(), [
    
    
    
            return $uid;
        }
    
        /**
         * Create a new unique Brick ID
         *
         * @param integer $brickId - Brick ID
    
         * @param QUI\Interfaces\Projects\Site $Site - Current Site
    
         *
         * @throws QUI\Exception
    
        protected function createUniqueBrickId(int $brickId, QUI\Interfaces\Projects\Site $Site): string
    
            $uuid = QUI\Utils\Uuid::get();
            $Brick = $this->getBrickById($brickId);
    
            QUI::getDataBase()->insert($this->getUIDTable(), [
    
                'uid' => $uuid,
                'brickId' => $brickId,
                'project' => $Project->getName(),
                'lang' => $Project->getLang(),
                'siteId' => $Site->getId(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                'attributes' => json_encode($Brick->getAttributes())
    
            return $uuid;
    
        }
    
        /**
         * Check if an unique brick ID exists
         *
         * @param string $uid - Brick Unique ID
         * @return bool
         */
    
        public function existsUniqueBrickId(string $uid): bool
    
            try {
                $result = QUI::getDataBase()->fetch([
    
                    'from' => $this->getUIDTable(),
    
                    'where' => [
                        'uid' => $uid
                    ],
                    'limit' => 1
                ]);
    
            } catch (QUI\Database\Exception $Exception) {
    
                QUI\System\Log::addError($Exception->getMessage());
    
                return false;
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
    
         * Clears the bricks cache
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function clearCache(): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            QUI\Cache\Manager::clear('quiqqer/bricks');
        }
    
        /**
         * Delete the brick
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @param integer $brickId - Brick-ID
    
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function deleteBrick(int $brickId): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            QUI\Permissions\Permission::checkPermission('quiqqer.bricks.delete');
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            // check if brick exist
    
            QUI::getEvents()->fireEvent('quiqqerBricksBrickDeleteBefore', [$Brick]);
    
    
            QUI::getDataBase()->delete($this->getTable(), [
    
    Henning Leutz's avatar
    Henning Leutz committed
                'id' => $brickId
    
    
            if (isset($this->bricks[$brickId])) {
                unset($this->bricks[$brickId]);
            }
    
    
            $uniqueBrickIds = QUI::getDataBase()->fetch([
    
                'from' => QUI\Bricks\Manager::getUIDTable(),
                'where' => [
    
                    'brickId' => $brickId,
                    'project' => $Brick->getAttribute('project'),
    
                    'lang' => $Brick->getAttribute('lang')
    
                'group' => 'siteId, project, lang'
    
    
            // delete bricks in sites
            foreach ($uniqueBrickIds as $uniqueBrickId) {
                $project = $uniqueBrickId['project'];
    
                $lang = $uniqueBrickId['lang'];
    
                $Site = $Project->get($uniqueBrickId['siteId']);
                $Edit = $Site->getEdit();
    
    
                $Edit->load();
                $Edit->save(QUI::getUsers()->getSystemUser());
            }
    
            // delete unique ids
    
            QUI::getDataBase()->delete(QUI\Bricks\Manager::getUIDTable(), [
    
                'brickId' => $brickId,
                'project' => $Brick->getAttribute('project'),
    
                'lang' => $Brick->getAttribute('lang')
    
    
            QUI::getEvents()->fireEvent('quiqqerBricksBrickDeleteAfter', [$brickId]);
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        /**
         * Return the areas which are available in the project
         *
         * @param Project $Project
    
         * @param boolean|string $layoutType - optional, returns only the areas
    
    Henning Leutz's avatar
    Henning Leutz committed
         *                                     for the specific layout type
         *                                     (default = false)
    
         * @param boolean|string $siteType - optional, returns only the areas
    
         *                                     for the specific site type
         *                                     (default = false)
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @return array
         */
    
        public function getAreasByProject(
            Project $Project,
    
            bool | string $layoutType = false,
            bool | string $siteType = false
    
        ): array {
    
            $bricks = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            $projectName = $Project->getName();
    
            if ($Project->getAttribute('template')) {
                $templates[] = $Project->getAttribute('template');
            }
    
    
            // inheritance
            try {
                $Package = QUI::getPackage($Project->getAttribute('template'));
    
                $Parent = $Package->getTemplateParent();
    
    
                if ($Parent) {
                    $templates[] = $Parent->getName();
                }
    
            } catch (QUI\Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
            // get all vhosts, and the used templates of the project
            $vhosts = QUI::getRewrite()->getVHosts();
    
            foreach ($vhosts as $vhost) {
                if (!isset($vhost['template'])) {
                    continue;
                }
    
                if ($vhost['project'] != $projectName) {
                    continue;
                }
    
                $templates[] = $vhost['template'];
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $templates = array_unique($templates);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            // get bricks
            foreach ($templates as $template) {
    
                $brickXML = realpath(OPT_DIR . $template . '/bricks.xml');
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                if (!$brickXML) {
                    continue;
                }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                $bricks = array_merge(
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $bricks,
    
                    Utils::getTemplateAreasFromXML($brickXML, $layoutType, $siteType)
    
    Henning Leutz's avatar
    Henning Leutz committed
            foreach ($bricks as $val) {
                if (!isset($cleaned[$val['name']])) {
                    $cleaned[$val['name']] = $val;
                }
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $bricks = array_values($cleaned);
    
    Henning Leutz's avatar
    Henning Leutz committed
            // use @ because: https://bugs.php.net/bug.php?id=50688
    
    Henning Leutz's avatar
    Henning Leutz committed
            @usort($bricks, function ($a, $b) {
    
                if (isset($a['priority']) && isset($b['priority'])) {
                    if ($a['priority'] == $b['priority']) {
                        return 0;
                    }
    
                    return ($a['priority'] < $b['priority']) ? -1 : 1;
                }
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                $transA = QUI::getLocale()->get(
                    $a['title']['group'],
                    $a['title']['var']
                );
    
                $transB = QUI::getLocale()->get(
                    $b['title']['group'],
                    $b['title']['var']
                );
    
                return $transA > $transB ? 1 : -1;
            });
    
    
            try {
                QUI::getEvents()->fireEvent(
                    'onBricksGetAreaByProject',
                    [$this, $Project, &$bricks]
                );
            } catch (QUI\Exception $Exception) {
                QUI\System\Log::writeException($Exception);
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            return $bricks;
        }
    
        /**
         * Returns the available bricks
         *
         * @return array
         */
    
        public function getAvailableBricks(): array
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            $cache = 'quiqqer/bricks/availableBricks';
    
            try {
                return QUI\Cache\Manager::get($cache);
    
            } catch (QUI\Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
            }
    
            $xmlFiles = $this->getBricksXMLFiles();
    
            $result = [];
    
                'title' => ['quiqqer/bricks', 'brick.content.title'],
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'quiqqer/bricks',
                    'brick.content.description'
    
                'control' => 'content'
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            foreach ($xmlFiles as $bricksXML) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $result = array_merge($result, Utils::getBricksFromXML($bricksXML));
    
    Henning Leutz's avatar
    Henning Leutz committed
            $result = array_filter($result, function ($brick) {
    
                return !empty($brick['title']);
            });
    
            // js workaround
    
    
            foreach ($result as $entry) {
                $list[] = $entry;
            }
    
    
            try {
                QUI\Cache\Manager::set($cache, $list);
    
            } catch (Exception $Exception) {
    
                QUI\System\Log::writeException($Exception);
            }
    
            return $list;
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        /**
         * Get a Brick by its Brick-ID
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @param integer $id
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @return Brick
         * @throws QUI\Exception
         */
    
        public function getBrickById(int $id): Brick
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (isset($this->bricks[$id])) {
                return $this->bricks[$id];
    
            $data = QUI::getDataBase()->fetch([
    
                'from' => $this->getTable(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'id' => $id
    
    Henning Leutz's avatar
    Henning Leutz committed
                'limit' => 1
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            if (!isset($data[0])) {
                throw new QUI\Exception('Brick not found');
            }
    
    
            $Brick = new Brick($data[0]);
            $Brick->setAttribute('id', $id);
    
            $this->bricks[$id] = $Brick;
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->bricks[$id];
    
        /**
         * Get a Brick by its unique ID
         *
    
         * @param string $uid - unique id
    
         * @param QUI\Interfaces\Projects\Site|null $Site - unique id
    
         *
         * @return Brick
         * @throws QUI\Exception
         */
    
        public function getBrickByUID(string $uid, null | QUI\Interfaces\Projects\Site $Site = null): Brick
    
        {
            if (isset($this->brickUIDs[$uid])) {
                return $this->brickUIDs[$uid];
            }
    
    
            $data = QUI::getDataBase()->fetch([
    
                'from' => $this->getUIDTable(),
    
                'limit' => 1
    
    
            if (!isset($data[0])) {
                throw new QUI\Exception('Brick not found');
            }
    
    
            $data = $data[0];
    
            $custom = $data['customfields'];
    
    Henning Leutz's avatar
    Henning Leutz committed
            $attributes = json_decode($attributes, true);
    
            $real = QUI::getDataBase()->fetch([
    
                'from' => $this->getTable(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'id' => (int)$brickId
    
    Henning Leutz's avatar
    Henning Leutz committed
                'limit' => 1
    
            $real[0]['Site'] = $Site;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Original = new Brick($real[0]);
    
            $Original->setAttribute('id', $brickId);
    
            $Clone = clone $Original;
    
            if (!empty($custom)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $custom = json_decode($custom, true);
    
    
                if ($custom) {
                    $Clone->setSettings($custom);
                }
    
                // workaround
                if (isset($custom['brickTitle'])) {
                    $Clone->setAttribute('frontendTitle', $custom['brickTitle']);
                }
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Return the available brick settings by the brick type
         *
         * @param $brickType
         *
         * @return array
         */
    
        public function getAvailableBrickSettingsByBrickType($brickType): array
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            $cache = 'quiqqer/bricks/brickType/' . md5($brickType);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            try {
                return QUI\Cache\Manager::get($cache);
    
            } catch (QUI\Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
                'name' => 'width',
                'text' => ['quiqqer/bricks', 'site.area.window.settings.setting.width'],
                'type' => '',
                'class' => '',
    
    Henning Leutz's avatar
    Henning Leutz committed
                'data-qui' => '',
    
                'options' => false
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
                'name' => 'height',
                'text' => ['quiqqer/bricks', 'site.area.window.settings.setting.height'],
                'type' => '',
                'class' => '',
    
    Henning Leutz's avatar
    Henning Leutz committed
                'data-qui' => '',
    
                'options' => false
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
                'name' => 'classes',
                'text' => ['quiqqer/bricks', 'site.area.window.settings.setting.classes'],
                'type' => '',
                'class' => '',
    
    Henning Leutz's avatar
    Henning Leutz committed
                'data-qui' => '',
    
                'options' => false
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $xmlFiles = $this->getBricksXMLFiles();
    
            foreach ($xmlFiles as $brickXML) {
    
                $Dom = XML::getDomFromXml($brickXML);
    
    Henning Leutz's avatar
    Henning Leutz committed
                $Path = new DOMXPath($Dom);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                $Settings = $Path->query(
    
    Henning Leutz's avatar
    Henning Leutz committed
                    "//quiqqer/bricks/brick[@control='$brickType']/settings/setting"
    
                $Globals = $Path->query(
                    "//quiqqer/bricks/brick[@control='*']/settings/setting"
                );
    
                foreach ($Globals as $Setting) {
                    $settings[] = $this->parseSettingToBrickArray($Setting);
    
    Henning Leutz's avatar
    Henning Leutz committed
                }
    
                foreach ($Settings as $Setting) {
    
                    $settings[] = $this->parseSettingToBrickArray($Setting);
                }
            }
    
            // cleanup duplicated
            // quiqqer/package-bricks#90
            $exists = [];
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $settings = array_filter($settings, function ($entry) use (&$exists) {
    
                $name = $entry['name'];
    
                if (isset($exists[$name])) {
                    return false;
                }
    
                $exists[$name] = true;
    
                return true;
            });
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $settings = array_values($settings);
    
            try {
                QUI\Cache\Manager::set($cache, $settings);
    
            } catch (Exception $Exception) {
    
                QUI\System\Log::writeException($Exception);
            }
    
    
        /**
         * Parse a xml setting element to a brick array
         *
    
         * @param DOMNode|DOMElement $Setting
    
        protected function parseSettingToBrickArray(DOMNode | DOMElement $Setting): array
    
            if (
                method_exists($Setting, 'getAttribute')
                && method_exists($Setting, 'getElementsByTagName')
                && $Setting->getAttribute('type') == 'select'
            ) {
    
                $optionElements = $Setting->getElementsByTagName('option');
    
                foreach ($optionElements as $Option) {
    
                        'value' => $Option->getAttribute('value'),
    
                        'text' => QUI\Utils\DOM::getTextFromNode($Option, false)
    
            $description = '';
    
    
            foreach ($Setting->attributes as $attribute) {
                if ($attribute->nodeName === 'data-qui') {
                    continue;
                }
    
    
                if (str_contains($attribute->nodeName, 'data-')) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $dataAttributes[$attribute->nodeName] = trim($attribute->nodeValue);
    
            if (method_exists($Setting, 'getElementsByTagName')) {
                $Description = $Setting->getElementsByTagName('description');
    
                if ($Description->length) {
                    $description = QUI\Utils\DOM::getTextFromNode($Description->item(0), false);
                }
    
                'name' => method_exists($Setting, 'getAttribute') ? $Setting->getAttribute('name') : '',
    
                'text' => QUI\Utils\DOM::getTextFromNode($Setting, false),
                'description' => $description,
    
                'type' => method_exists($Setting, 'getAttribute') ? $Setting->getAttribute('type') : '',
                'class' => method_exists($Setting, 'getAttribute') ? $Setting->getAttribute('class') : '',
                'data-qui' => method_exists($Setting, 'getAttribute') ? $Setting->getAttribute('data-qui') : '',
    
                'options' => $options,
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        /**
         * Return the bricks from the area
         *
         * @param string $brickArea - Name of the area
    
         * @param QUI\Interfaces\Projects\Site $Site
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @return array
    
         * @throws ExceptionStack
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function getBricksByArea(
            string $brickArea,
            QUI\Interfaces\Projects\Site $Site
        ): array {
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (empty($brickArea)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
            }
    
            $brickAreas = $Site->getAttribute('quiqqer.bricks.areas');
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!is_array($brickAreas)) {
                $brickAreas = json_decode($brickAreas, true);
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (empty($brickAreas[$brickArea])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $bricks = $this->getInheritedBricks($brickArea, $Site);
            } else {
    
                $bricks = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
                $brickData = $brickAreas[$brickArea];
    
                foreach ($brickData as $brick) {
                    if (isset($brick['deactivate'])) {
                        break;
                    }
    
                    $bricks[] = $brick;
                }
            }
    
    
    
            QUI::getEvents()->fireEvent(
                'onQuiqqerBricksGetBricksByAreaBegin',
                [$brickArea, $Site, &$result]
            );
    
    Henning Leutz's avatar
    Henning Leutz committed
            foreach ($bricks as $brickData) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $brickId = (int)$brickData['brickId'];
    
                try {
    
                    if (!empty($brickData['uid'])) {
    
                        $Brick = $this->getBrickByUID($brickData['uid'], $Site);
    
                } catch (QUI\Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $Brick = $this->getBrickById($brickId);
    
                    if (!empty($brickData['customfields'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                        $custom = json_decode($brickData['customfields'], true);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                        if ($custom) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                } catch (QUI\Exception $Exception) {
    
                    QUI\System\Log::writeRecursive($brickData);
                    QUI\System\Log::writeException($Exception);
    
            QUI::getEvents()->fireEvent(
                'onQuiqqerBricksGetBricksByAreaEnd',
                [$brickArea, $Site, &$result]
            );
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $result;
        }
    
        /**
         * Return a list with \QUI\Bricks\Brick which are assigned to a project
         *
         * @param Project $Project
         * @return array
    
         *
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function getBricksFromProject(Project $Project): array
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            $list = QUI::getDataBase()->fetch([
    
                'from' => $this->getTable(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'project' => $Project->getName(),
    
                    'lang' => $Project->getLang()
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            foreach ($list as $entry) {
                $result[] = $this->getBrickById($entry['id']);
            }
    
            return $result;
        }
    
    
    
        /**
         * Return a list with \QUI\Bricks\Brick which are assigned to a project
         *
         * @param Brick $Brick
         * @return array
         */
    
        public function getSitesByBrick(Brick $Brick): array
    
            try {
                $list = QUI::getDataBase()->fetch([
                    'select' => ['brickId', 'project', 'lang', 'siteId'],
    
                    'from' => $this->getUIDTable(),
                    'where' => [
    
                        'project' => $Brick->getAttribute('project'),
    
                        'lang' => $Brick->getAttribute('lang'),
    
                        'brickId' => $Brick->getAttribute('id')
                    ]
                ]);
    
                $Project = QUI::getProject(
                    $Brick->getAttribute('project'),
                    $Brick->getAttribute('lang')
                );
            } catch (QUI\Exception $Exception) {
                QUI\System\Log::addError($Exception->getMessage());
    
    
            foreach ($list as $entry) {
                try {
                    $result[] = $Project->get($entry['siteId']);
                } catch (QUI\Exception $Exception) {
                    QUI\System\Log::writeDebugException($Exception);
                    continue;
                }
            }
    
            return $result;
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
    
         * @param integer|string $brickId - Brick-ID
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @param array $brickData - Brick data
    
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function saveBrick(int | string $brickId, array $brickData): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            QUI\Permissions\Permission::checkPermission('quiqqer.bricks.edit');
    
            QUI::getEvents()->fireEvent('quiqqerBricksSaveBefore', [$brickId]);
    
    
            $Brick = $this->getBrickById($brickId);
            $areas = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
            $areaString = '';
    
            if (isset($brickData['id'])) {
                unset($brickData['id']);
            }
    
            // check areas
            $Project = QUI::getProjectManager()->getProject(
                $Brick->getAttribute('project')
            );
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $availableAreas = array_map(function ($data) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (isset($data['name'])) {
                    return $data['name'];
                }
    
                return '';
            }, $this->getAreasByProject($Project));
    
    
            if (isset($brickData['attributes']['areas'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $brickData['areas'] = $brickData['attributes']['areas'];
            }
    
            if (isset($brickData['areas'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $parts = explode(',', $brickData['areas']);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                foreach ($parts as $area) {
    
                    if (defined('QUIQQER_BRICKS_IGNORE_AREA_CHECK')) {
                        $areas[] = $area;
                        continue;
                    }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                    if (in_array($area, $availableAreas)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                        $areas[] = $area;
                    }
                }
            }
    
            if (!empty($areas)) {
    
                $areaString = ',' . implode(',', $areas) . ',';
    
    Henning Leutz's avatar
    Henning Leutz committed
            }
    
            $Brick->setAttributes($brickData);
    
            // fields
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (isset($brickData['attributes']) && is_array($brickData['attributes'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                foreach ($brickData['attributes'] as $key => $value) {
                    if ($key == 'areas') {
                        continue;
                    }
    
                    $Brick->setAttribute($key, $value);
                }
            }
    
            // brick settings
            if (isset($brickData['settings'])) {
                $Brick->setSettings($brickData['settings']);
            }
    
    
            $brickAttributes = Utils::getAttributesForBrick($Brick);
    
            foreach ($brickAttributes as $attribute) {
                if (isset($brickData['attributes'][$attribute])) {
                    $Brick->setSetting($attribute, $brickData['attributes'][$attribute]);
                }
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            // custom fields
    
    Henning Leutz's avatar
    Henning Leutz committed
            $customFields = [];