Skip to content
Code-Schnipsel Gruppen Projekte
Brick.php 16,7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Henning Leutz's avatar
    Henning Leutz committed
    <?php
    
    /**
     * This file contains \QUI\Bricks\Brick
     */
    
    namespace QUI\Bricks;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use Exception;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI\Control;
    
    use function array_filter;
    use function array_flip;
    use function array_merge;
    use function array_unique;
    
    use function array_values;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function class_exists;
    use function dirname;
    use function explode;
    use function fnmatch;
    use function get_class;
    use function implode;
    use function is_array;
    use function is_callable;
    use function is_object;
    use function is_string;
    use function json_decode;
    use function md5;
    use function serialize;
    use function trim;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    /**
     * Class Brick
     * A Brick from the Brickmanager
     *
     * @author  www.pcsg.de (Henning Leutz)
     * @package quiqqer/bricks
     */
    class Brick extends QUI\QDOM
    {
        /**
         * internal brick id
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        protected int|bool $id = false;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
        /**
         * internal unique ID
         * This ID is unique for the complete system
         */
    
        protected mixed $uniqueId = false;
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Brick settings
         *
         * @var array
         */
    
        protected array $settings = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
    
        /**
         * Fields can be overwritten by another user
         *
         * @var array
         */
    
        protected array $customfields = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
    
        /**
         * Internal control
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @var null|Control
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        protected ?Control $Control = null;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
        /**
         * List of extra css classes
         *
         * @var array
         */
    
        protected array $cssClasses = [];
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
        protected string $hash;
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Constructor
         *
         * @param array $params - brick params
    
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function __construct(array $params = [])
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            // default
    
                'type' => 'content',
                'content' => '',
                'title' => '',
                'description' => '',
                'project' => '',
                'lang' => '',
                'areas' => '',
                'height' => '',
                'width' => '',
                'classes' => '',
    
                'frontendTitle' => '',
    
                'hasContent' => 1,
                'cacheable' => 1, // if the brick is cacheable or not
                'deprecated' => 0
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            $this->setAttributes($default);
    
            foreach ($default as $key => $value) {
                if (isset($params[$key])) {
                    $this->setAttribute($key, $params[$key]);
                }
            }
    
            if (isset($params['id'])) {
    
                $this->id = (int)$params['id'];
    
            if (isset($params['uniqueId'])) {
                $this->uniqueId = $params['uniqueId'];
            }
    
    
            if (isset($params['classes'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $cssClasses = json_decode($params['classes'], true);
    
                foreach ($cssClasses as $cssClass) {
                    $this->addCSSClass($cssClass);
                }
    
                unset($params['classes']);
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            // default settings from control
    
            if (isset($params['Site'])) {
                $this->setAttribute('Site', $params['Site']);
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Control = $this->getControl();
            $Manager = Manager::init();
    
            $availableSettings = $Manager->getAvailableBrickSettingsByBrickType(
                $this->getAttribute('type')
            );
    
            foreach ($availableSettings as $entry) {
                $this->settings[$entry['name']] = false;
            }
    
    
            $availableAttributes = Utils::getAttributesForBrick($this);
    
            foreach ($availableAttributes as $attribute) {
                $this->settings[$attribute] = false;
            }
    
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            // control default settings
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_object($Control)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $controlSettings = $Control->getAttributes();
    
                foreach ($this->settings as $key => $value) {
                    if (isset($controlSettings[$key])) {
                        $this->settings[$key] = $controlSettings[$key];
                    }
                }
            }
    
            // settings from database
            if (isset($params['settings'])) {
                $settings = $params['settings'];
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_string($settings)) {
                    $settings = json_decode($settings, true);
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_array($settings)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    foreach ($this->settings as $key => $value) {
                        if (isset($settings[$key])) {
                            $this->settings[$key] = $settings[$key];
                        }
                    }
                }
            }
    
            // customfields
            if (isset($params['customfields'])) {
                $customfields = $params['customfields'];
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_string($customfields)) {
                    $customfields = json_decode($customfields, true);
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_array($customfields)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $this->customfields = $customfields;
                }
            }
    
            // deprecated
            $BricksManager = QUI\Bricks\Manager::init();
    
            $type = $this->getAttribute('type');
    
    
            $brick = array_filter($BricksManager->getAvailableBricks(), function ($brick) use ($type) {
                if (!isset($brick['control'])) {
                    return false;
                }
    
                return $brick['control'] === $type;
            });
    
            if ($brick) {
                $brick = array_values($brick)[0];
    
                if (!empty($brick['deprecated'])) {
                    $this->setAttribute('deprecated', 1);
                }
            }
    
    
            $this->hash = $this->createBrickHash();
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        /**
         * Return the class type
         *
         * @return String
    
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function getType(): string
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            $Control = $this->getControl();
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_object($Control)) {
                return get_class($Control);
    
    Henning Leutz's avatar
    Henning Leutz committed
            return get_class($this);
    
        /**
         * Checks if the internal control is of this class or has this class as one of its parents
         *
         * @param string $className
         * @return bool
    
         * @throws QUI\Exception
    
        public function isInstanceOf(string $className): bool
    
        {
            $Control = $this->getControl();
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_object($Control)) {
    
                return $Control instanceof $className;
            }
    
            return $this instanceof $className;
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
    
         * Check, if control can be created
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @return QUI\Bricks\Brick
    
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function check(): Brick
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            if ($this->getAttribute('type') == 'content') {
                return $this;
            }
    
            $Control = $this->getControl();
    
            if (!$Control) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'Control not found. Brick could not be created. Maybe wrong type ' . $this->getAttribute('type')
    
    Henning Leutz's avatar
    Henning Leutz committed
            }
    
            return $this;
        }
    
    
        /**
         * Create a unique brick hash
         * which is created from the brick data
         *
         * @return string
         */
    
        protected function createBrickHash(): string
    
        {
            $attributes = $this->getAttributes();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $hashParams = array_filter($attributes, function ($entry) {
                return is_object($entry) === false;
    
    Henning Leutz's avatar
    Henning Leutz committed
            $hash = serialize($hashParams);
    
            return md5($hash);
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Return the HTML of the Brick
         *
         * @return string
         *
         * @throws QUI\Exception
         */
    
        public function create(): string
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            $settings = $this->getSettings();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $settings = array_filter($settings, function ($entry) {
                return is_object($entry) === false;
    
            $cacheName = Manager::getBrickCacheNamespace()
    
    Henning Leutz's avatar
    Henning Leutz committed
                . md5($this->getType())
                . '/'
                . $this->hash
                . '/' . md5(serialize($settings));
    
                    $data = QUI\Cache\Manager::get($cacheName);
                    $cssFiles = $data['cssFiles'];
    
    Henning Leutz's avatar
    Henning Leutz committed
                    if (is_array($cssClasses)) {
    
                        foreach ($cssClasses as $cssClass) {
                            $this->addCSSClass($cssClass);
                        }
    
    Henning Leutz's avatar
    Henning Leutz committed
                    if (is_array($cssFiles)) {
    
                        foreach ($cssFiles as $cssFile) {
                            QUI\Control\Manager::addCSSFile($cssFile);
                        }
    
                } catch (Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($this->getAttribute('type') == 'content') {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'brick-' . $this->id
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                foreach ($this->cssClasses as $cssClass) {
                    $_classes[] = $cssClass;
                }
    
    
    
                $oldCssClasses = $this->getAttribute('classes');
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_string($oldCssClasses)) {
                    $oldCssClassesJson = json_decode($oldCssClasses, true);
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_array($oldCssClassesJson)) {
    
                    $oldCssClasses = $oldCssClassesJson;
                }
    
    
                $classes = $oldCssClasses;
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (is_string($oldCssClasses)) {
                    $classes = explode(' ', $oldCssClasses);
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $_classes[] = trim($class);
    
                $_classes = array_unique($_classes);
    
    Henning Leutz's avatar
    Henning Leutz committed
                $classesStr = implode(' ', $_classes);
                $classesStr = 'class="' . $classesStr . '"';
    
                    'this' => $this,
    
    Henning Leutz's avatar
    Henning Leutz committed
                $result = $Engine->fetch(dirname(__FILE__) . '/Brick.html');
    
    
                QUI\Cache\Manager::set($cacheName, [
    
                    'html' => $result,
    
                    'cssClasses' => $this->cssClasses,
    
                    'cssFiles' => []
    
    Henning Leutz's avatar
    Henning Leutz committed
            }
    
            $Control = $this->getControl();
    
            if (!$Control) {
                throw new QUI\Exception('Control not found. Brick could not be created');
            }
    
            $Control->setAttributes($this->getSettings());
    
            if ($this->getAttribute('classes')) {
    
                $Control->addCSSClass($this->getAttribute('classes'));
    
            if ($Control->existsAttribute('cacheable')) {
                $Control->setAttribute('cacheable', $Control->getAttribute('cacheable'));
            }
    
    
            // workaround wegen title bug
            // @todo backendTitle einführen und title als frontend Title nutzen (Versionssprung)
            $Control->setAttribute('title', $this->getAttribute('frontendTitle'));
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($this->id) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $Control->addCSSClass('brick-' . $this->id);
    
                $Control->setAttribute('data-brickid', $this->id);
            }
    
            if ($this->uniqueId) {
                $Control->setAttribute('data-brickuid', $this->uniqueId);
    
    Henning Leutz's avatar
    Henning Leutz committed
            }
    
            foreach ($this->cssClasses as $cssClass) {
                $Control->addCSSClass($cssClass);
            }
    
    
            $result = $Control->create();
    
            $cssFiles = $Control->getCSSFiles();
    
    
            QUI\Cache\Manager::set($cacheName, [
    
                'html' => $result,
    
                'cssClasses' => $this->cssClasses,
    
                'cssFiles' => $cssFiles
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        /**
         * Return the internal control
         *
    
         * @return Control|bool|null
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        protected function getControl(): Control|bool|null
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            if ($this->Control) {
                return $this->Control;
            }
    
            $Ctrl = $this->getAttribute('type');
    
            if ($Ctrl === 'content') {
                return true;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!is_callable($Ctrl) && !class_exists($Ctrl)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return false;
            }
    
    
            $Site = $this->getAttribute('Site');
    
            if ($Site instanceof QUI\Projects\Site) {
                $Project = $Site->getProject();
    
                $Ctrl = QUI\Bricks\Manager::init()->getAlternateClass(
                    $Ctrl,
                    $Project->getAttribute('template')
                );
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            /* @var $Control Control */
    
            $Control = new $Ctrl(
    
    Henning Leutz's avatar
    Henning Leutz committed
                array_merge($this->getSettings(), $this->getAttributes())
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            $Control->setAttribute('height', $this->getAttribute('height'));
            $Control->setAttribute('width', $this->getAttribute('width'));
            $Control->setAttribute('content', $this->getAttribute('content'));
    
    
            if ($this->getAttribute('Site')) {
                $Control->setAttribute('Site', $this->getAttribute('Site'));
            } else {
                $Control->setAttribute('Site', QUI::getRewrite()->getSite());
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!($Control instanceof Control)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return false;
            }
    
            $this->Control = $Control;
    
    
            if ($this->Control->existsAttribute('cacheable')) {
                $this->setAttribute('cacheable', $this->Control->getAttribute('cacheable'));
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $Control;
        }
    
        /**
         * Return the brick settings
         *
         * @return array
         */
    
        public function getSettings(): array
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            $this->settings['classes'] = $this->getCSSClasses();
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->settings;
        }
    
        /**
         * Set brick settings
         *
         * @param array $settings - list of settings
         *
         * @return void
         */
    
        public function setSettings(array $settings): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            foreach ($settings as $key => $value) {
    
                    $this->addCSSClass($value);
                    continue;
                }
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->setSetting($key, $value);
            }
        }
    
        /**
         * Return the setting of the brick
         *
         * @param String $name - Name of the setting
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function getSetting(string $name): bool|array|string
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            if ($name === 'classes') {
                return $this->getCSSClasses();
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (isset($this->settings[$name])) {
                return $this->settings[$name];
            }
    
            return false;
        }
    
        /**
         * Set a brick setting
         *
         * @param string $name - name of the setting
    
         * @param mixed $value - value of the setting
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @return void
         */
    
        public function setSetting(string $name, mixed $value): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            if (isset($this->settings[$name])) {
                $this->settings[$name] = $value;
            }
    
            if ($this->Control instanceof Control) {
    
                $this->Control->setAttribute($name, $value);
            }
    
        public function getAttribute(string $name): mixed
    
        {
            if ($name === 'classes') {
                return $this->getCSSClasses();
            }
    
            return parent::getAttribute($name);
        }
    
        /**
         * @return array
         */
    
        public function getAttributes(): array
    
            $attributes = parent::getAttributes();
    
            $attributes['classes'] = $this->getCSSClasses();
    
            return $attributes;
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * This fields can be overwritten by another user
         *
         * @return array
         */
    
        public function getCustomFields(): array
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            return $this->customfields;
        }
    
        /**
    
         * Add an extra CSS Class to the control
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * @param array|string $cssClass - Name of the CSS Class
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @return void
         */
    
        public function addCSSClass(array|string $cssClass): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_array($cssClass)) {
                $cssClass = implode(' ', $cssClass);
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!is_string($cssClass)) {
    
            $classes = QUI\ControlUtils::clearClassName($cssClass);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $classes = explode(' ', $classes);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $keys = array_flip($this->cssClasses);
    
    
            foreach ($classes as $cssClass) {
                if (!isset($keys[$cssClass])) {
                    $this->cssClasses[] = $cssClass;
    
                    $keys[$cssClass] = true;
    
        public function clearCSSClasses(): void
    
            $this->cssClasses = [];
    
        /**
         * Return all css classes
         *
         * @return array
         */
    
        public function getCSSClasses(): array
    
         * Match pattern against the css classes
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @param string $pattern - The shell wildcard pattern.
         *
         * @return boolean
         */
    
        public function hasCSSClass(string $pattern): bool
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            $cssClasses = $this->getAttribute('classes');
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_array($cssClasses)) {
                $cssClasses = implode(' ', $cssClasses);
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($cssClasses && fnmatch($pattern, $cssClasses)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return true;
            }
    
            if (empty($this->cssClasses)) {
                return false;
            }
    
            foreach ($this->cssClasses as $cssClass) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                if (fnmatch($pattern, $cssClass)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    return true;
                }
            }
    
            return false;
        }
    }