diff --git a/bin/Site/Area.js b/bin/Site/Area.js index 242c0c58b731c6761ace49fa1e6e5de0528c8d56..2f9d21092244de3c0439db566aaf43ba478275dd 100644 --- a/bin/Site/Area.js +++ b/bin/Site/Area.js @@ -337,8 +337,10 @@ define('package/quiqqer/bricks/bin/Site/Area', [ return; } - this.$brickCustomData[BrickNode.get('id')] = brickData.customfields; - + this.$brickCustomData[BrickNode.get('id')] = { + customfields: brickData.customfields, + uid : brickData.uid + }; }.bind(this)); }, @@ -443,22 +445,25 @@ define('package/quiqqer/bricks/bin/Site/Area', [ }]; } - var i, len, custom, brickId; + var i, len, uid, custom, brickId; var data = [], bricks = this.$Elm.getElements('select'); for (i = 0, len = bricks.length; i < len; i++) { custom = ''; + uid = ''; brickId = bricks[i].getParent().get('id'); if (brickId in this.$brickCustomData) { - custom = this.$brickCustomData[brickId]; + custom = this.$brickCustomData[brickId].customfields; + uid = this.$brickCustomData[brickId].uid; } data.push({ brickId : bricks[i].value, - customfields: custom + customfields: custom, + uid : uid }); } @@ -788,20 +793,17 @@ define('package/quiqqer/bricks/bin/Site/Area', [ require([ 'package/quiqqer/bricks/bin/Site/BrickEdit' ], function (BrickEdit) { - var brickId = Select.getParent().get('id'); var custom = ''; if (brickId in self.$brickCustomData) { - custom = self.$brickCustomData[brickId]; + custom = self.$brickCustomData[brickId].customfields; } - custom = JSON.decode(custom); - var Edit = new BrickEdit({ brickId : Select.value, Site : self.getAttribute('Site'), - customfields: custom, + customfields: JSON.decode(custom), styles : { height: Win.getContent().getSize().y } @@ -826,7 +828,7 @@ define('package/quiqqer/bricks/bin/Site/Area', [ data = QUIFormUtils.getFormData(Form), brickId = Select.getParent().get('id'); - self.$brickCustomData[brickId] = JSON.encode(data); + self.$brickCustomData[brickId].customfields = JSON.encode(data); Win.close(); }); diff --git a/bin/Site/Category.js b/bin/Site/Category.js index f50632d8d06e402ba08e8d7a9d0e54dcf9b4fea4..4f2d0892372e160737d51a17d1247b02015231eb 100644 --- a/bin/Site/Category.js +++ b/bin/Site/Category.js @@ -116,6 +116,10 @@ define('package/quiqqer/bricks/bin/Site/Category', [ areas = JSON.decode(areas); } + var loadData = function (brickData) { + AC.addBrick(brickData); + }; + for (i = 0, len = bricks.length; i < len; i++) { AC = self.$insertBrickAreaEdit(bricks[i]); @@ -124,10 +128,7 @@ define('package/quiqqer/bricks/bin/Site/Category', [ } data = areas[AC.getAttribute('name')]; - - data.each(function (brickData) { - AC.addBrick(brickData); - }); + data.each(loadData); } self.Loader.hide(); diff --git a/database.xml b/database.xml index c412f87a732468edaddc77e4f859356a8232c5ce..46e6575079685c01dc32ddb1af355c06cc2d481c 100644 --- a/database.xml +++ b/database.xml @@ -20,12 +20,13 @@ </table> <table name="bricksUID"> - <field type="INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY">id</field> + <field type="VARCHAR(80) NOT NULL PRIMARY KEY">uid</field> <field type="INT(3)">brickId</field> <field type="VARCHAR(255)">project</field> <field type="VARCHAR(2)">lang</field> <field type="BIGINT(20)">siteId</field> - <field type="TEXT NULL">settings</field> + <field type="LONGTEXT NULL">customfields</field> + <field type="LONGTEXT NULL">attributes</field> </table> </global> diff --git a/events.xml b/events.xml index 8e2817694088f78049d407493b3ede8df7507910..97d3fbeecaadf72b49b8de4667ba635ee23d75a2 100644 --- a/events.xml +++ b/events.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <events> - <event on="onSiteSave" fire="\QUI\Bricks\Events::onSiteSave" /> - <event on="onSmartyInit" fire="\QUI\Bricks\Events::onSmartyInit" /> + <event on="onSiteSave" fire="\QUI\Bricks\Events::onSiteSave"/> + <event on="onSmartyInit" fire="\QUI\Bricks\Events::onSmartyInit"/> + <event on="onPackageSetup" fire="\QUI\Bricks\Events::onPackageSetup"/> </events> \ No newline at end of file diff --git a/patches/uniqueIds.php b/patches/uniqueIds.php new file mode 100644 index 0000000000000000000000000000000000000000..4a75145b79525218bcc6e15f65e364d4b4417c3f --- /dev/null +++ b/patches/uniqueIds.php @@ -0,0 +1,71 @@ +<?php + +define('QUIQQER_SYSTEM', true); +require dirname(dirname(dirname(dirname(__FILE__)))).'/header.php'; + +// workaround for older patch +$Bricks = QUI\Bricks\Manager::init(); +$result = QUI::getDataBase()->fetch(array( + 'count' => 'count', + 'from' => $Bricks->getUIDTable(), +)); + +// if unique ids already exist, the pages no longer have to be passed through +if (isset($result[0]) && isset($result[0]['count']) && $result[0]['count']) { + echo 'Already executed'.PHP_EOL; + + return; +} + +$projects = QUI::getProjectManager()->getProjectList(); + +// helper to look if areas are empty +$areasEmpty = function ($areas) { + if (!is_array($areas)) { + return true; + } + + foreach ($areas as $area => $data) { + if (!empty($data)) { + return false; + } + } + + return true; +}; + +echo PHP_EOL; + +/* @var $Project QUI\Projects\Project */ +foreach ($projects as $Project) { + $ids = $Project->getSitesIds(); + + foreach ($ids as $id) { + $id = $id['id']; + + try { + $Site = $Project->get($id); + $areas = $Site->getAttribute('quiqqer.bricks.areas'); + + if ($areas === false) { + continue; + } + + $areas = json_decode($areas, true); + + if ($areasEmpty($areas)) { + continue; + } + + echo $Project->getName().'-'.$Project->getLang().'-'.$id.PHP_EOL; + + $Edit = $Site->getEdit(); + $Edit->save(QUI::getUsers()->getSystemUser()); + } catch (QUI\Exception $Exception) { + continue; + } + } + + unset($Edit); + unset($Project); +} diff --git a/src/QUI/Bricks/Brick.php b/src/QUI/Bricks/Brick.php index a44c3fa3965401a4141d03ab91bce45d1b087e79..6c8b0b61fc7beb034c624ef1d2e82c9acf99a105 100644 --- a/src/QUI/Bricks/Brick.php +++ b/src/QUI/Bricks/Brick.php @@ -74,6 +74,7 @@ public function __construct($params = array()) 'title' => '', 'description' => '', 'project' => '', + 'lang' => '', 'areas' => '', 'height' => '', 'width' => '', @@ -213,7 +214,9 @@ public function check() $Control = $this->getControl(); if (!$Control) { - throw new QUI\Exception('Control not found. Brick could not be created'); + throw new QUI\Exception( + 'Control not found. Brick could not be created. Maybe wrong type '.$this->getAttribute('type') + ); } return $this; @@ -230,7 +233,7 @@ public function create() { if ($this->getAttribute('type') == 'content') { $_classes = array( - 'brick-' . $this->id + 'brick-'.$this->id ); foreach ($this->cssClasses as $cssClass) { @@ -250,7 +253,7 @@ public function create() $_classes = array_unique($_classes); $classesStr = implode($_classes, ' '); - $classesStr = 'class="' . $classesStr . '"'; + $classesStr = 'class="'.$classesStr.'"'; $Engine = QUI::getTemplateManager()->getEngine(); @@ -259,7 +262,7 @@ public function create() 'classesStr' => $classesStr )); - return $Engine->fetch(dirname(__FILE__) . '/Brick.html'); + return $Engine->fetch(dirname(__FILE__).'/Brick.html'); } $Control = $this->getControl(); @@ -279,7 +282,7 @@ public function create() $Control->setAttribute('title', $this->getAttribute('frontendTitle')); if ($this->id) { - $Control->addCSSClass('brick-' . $this->id); + $Control->addCSSClass('brick-'.$this->id); $Control->setAttribute('data-brickid', $this->id); } @@ -380,7 +383,7 @@ public function setSettings($settings) * * @param String $name - Name of the setting * - * @return boolean|string + * @return boolean|string|array */ public function getSetting($name) { diff --git a/src/QUI/Bricks/Events.php b/src/QUI/Bricks/Events.php index 3c81bd0dc8c5abf265a87ce74fac3dae3b0fdfa7..8c70aaed8922c101aa15e40744471368341a31cf 100644 --- a/src/QUI/Bricks/Events.php +++ b/src/QUI/Bricks/Events.php @@ -36,11 +36,13 @@ public static function onSiteSave($Site) $Manager = Manager::init(); - // get inharitance areas + // get inheritance areas $Project = $Site->getProject(); $projectAreas = $Manager->getAreasByProject($Project); $projectTable = QUI::getDBProjectTableName(Manager::TABLE_CACHE, $Project); + $uidTable = QUI\Bricks\Manager::getUIDTable(); + $availableUniqueIds = array(); foreach ($projectAreas as $area) { if (!$area['inheritance']) { @@ -74,25 +76,38 @@ public static function onSiteSave($Site) continue; } + foreach ($bricks as $bricksKey => $brick) { + try { + $Manager->getBrickById($brick['brickId']); + } catch (QUI\Exception $Exception) { + unset($areas[$area['name']][$bricksKey]); + continue; + } + + try { + $uid = $Manager->createUniqueSiteBrick($Site, $brick); + } catch (QUI\Exception $Exception) { + unset($areas[$area['name']][$bricksKey]); + continue; + } + + $areas[$area['name']][$bricksKey]['uid'] = $uid; + + $availableUniqueIds[] = $uid; + - foreach ($bricks as $brick) { $customFields = array(); - if (isset($brick['customfields']) - && is_string($brick['customfields']) - ) { + // Custom data cache + if (isset($brick['customfields']) && is_string($brick['customfields'])) { $customFields = json_decode($brick['customfields'], true); } - if (isset($brick['customfields']) - && is_array($brick['customfields']) - ) { + if (isset($brick['customfields']) && is_array($brick['customfields'])) { $customFields = $brick['customfields']; } - if (!isset($customFields['inheritance']) - || !(int)$customFields['inheritance'] - ) { + if (!isset($customFields['inheritance']) || !(int)$customFields['inheritance']) { continue; } @@ -103,6 +118,37 @@ public static function onSiteSave($Site) )); } } + + // cleanup unique ids + $uniquerIdsInDataBase = QUI::getDataBase()->fetch(array( + 'select' => 'uid', + 'from' => $uidTable, + 'where' => array( + 'project' => $Project->getName(), + 'lang' => $Project->getLang(), + 'siteId' => $Site->getId() + ) + )); + + $uniquerIdsInDataBase = array_map(function ($uid) { + return $uid['uid']; + }, $uniquerIdsInDataBase); + + $availableUniqueIds = array_flip($availableUniqueIds); + + foreach ($uniquerIdsInDataBase as $uid) { + if (isset($availableUniqueIds[$uid])) { + continue; + } + + QUI::getDataBase()->delete($uidTable, array( + 'uid' => $uid + )); + } + + // save bricks with unique ids + $Site->setAttribute('quiqqer.bricks.areas', json_encode($areas)); + $Site->save(); } /** @@ -126,7 +172,7 @@ public static function onSmartyInit($Smarty) * * @param array $params - function parameter * @param \Smarty $smarty - * @return string + * @return string|array */ public static function brickarea($params, $smarty) { @@ -136,6 +182,7 @@ public static function brickarea($params, $smarty) } $smarty->assign($params['assign'], array()); + return ''; } @@ -152,6 +199,17 @@ public static function brickarea($params, $smarty) } $smarty->assign($params['assign'], $result); + return ''; } + + /** + * @param QUI\Package\Package $Package + */ + public static function onPackageSetup(QUI\Package\Package $Package) + { + if ($Package->getName() !== 'quiqqer/bricks') { + return; + } + } } diff --git a/src/QUI/Bricks/Manager.php b/src/QUI/Bricks/Manager.php index fa27ef3f1494fa20bb1831f6b6fea8a82b26264d..8ef9e309b2314a3ae0765fb3fd46ae15dc5f7ab1 100644 --- a/src/QUI/Bricks/Manager.php +++ b/src/QUI/Bricks/Manager.php @@ -10,6 +10,8 @@ use QUI\Projects\Project; use QUI\Projects\Site; use QUI\Utils\Text\XML; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; /** * Brick Manager @@ -93,7 +95,6 @@ public function createBrickForProject(Project $Project, Brick $Brick) { QUI\Permissions\Permission::checkPermission('quiqqer.bricks.create'); - QUI::getDataBase()->insert( $this->getTable(), array( @@ -110,6 +111,98 @@ public function createBrickForProject(Project $Project, Brick $Brick) return $lastId; } + /** + * Create and update a unique site brick + * + * @param Site $Site + * @param array $brickData + * @return string - Unique ID + */ + public function createUniqueSiteBrick(Site $Site, $brickData = array()) + { + if (isset($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); + } + + $customFields = array(); + + if (isset($brickData['customfields'])) { + $customFields = $brickData['customfields']; + } + + if (is_array($customFields)) { + $customFields = json_encode($customFields); + } + + QUI::getDataBase()->update($this->getUIDTable(), array( + 'customfields' => $customFields + ), array( + 'uid' => $uid + )); + + + return $uid; + } + + /** + * Create a new unique Brick ID + * + * @param integer $brickId - Brick ID + * @param Site $Site - Current Site + * @return bool + */ + protected function createUniqueBrickId($brickId, $Site) + { + $Project = $Site->getProject(); + $uId = md5(microtime()); + $Brick = $this->getBrickById($brickId); + + try { + $UUID = Uuid::uuid1(); + $uId = $UUID->toString(); + + QUI::getDataBase()->insert($this->getUIDTable(), array( + 'uid' => $uId, + 'brickId' => $brickId, + 'project' => $Project->getName(), + 'lang' => $Project->getLang(), + 'siteId' => $Site->getId(), + 'attributes' => json_encode($Brick->getAttributes()) + )); + } catch (UnsatisfiedDependencyException $Exception) { + QUI\System\Log::writeException($Exception); + } catch (QUI\Exception $Exception) { + QUI\System\Log::writeException($Exception); + } + + return $uId; + } + + /** + * Check if an unique brick ID exists + * + * @param string $uid - Brick Unique ID + * @return bool + */ + public function existsUniqueBrickId($uid) + { + $result = QUI::getDataBase()->fetch(array( + 'from' => $this->getUIDTable(), + 'where' => array( + 'uid' => $uid + ), + 'limit' => 1 + )); + + return isset($result[0]); + } + /** * CLears the bricks cache */ @@ -128,11 +221,47 @@ public function deleteBrick($brickId) QUI\Permissions\Permission::checkPermission('quiqqer.bricks.delete'); // check if brick exist - $this->getBrickById($brickId); + $Brick = $this->getBrickById($brickId); QUI::getDataBase()->delete($this->getTable(), array( 'id' => $brickId )); + + if (isset($this->bricks[$brickId])) { + unset($this->bricks[$brickId]); + } + + + $uniqueBrickIds = QUI::getDataBase()->fetch(array( + 'select' => 'siteId, project, lang', + 'from' => QUI\Bricks\Manager::getUIDTable(), + 'where' => array( + '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']; + + $Project = QUI::getProject($project, $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(), array( + 'brickId' => $brickId, + 'project' => $Brick->getAttribute('project'), + 'lang' => $Brick->getAttribute('lang') + )); } /** @@ -323,9 +452,9 @@ public function getBrickByUID($uid) } $data = QUI::getDataBase()->fetch(array( - 'from' => $this->getTable(), + 'from' => $this->getUIDTable(), 'where' => array( - 'id' => (int)$uid + 'uid' => $uid ), 'limit' => 1 )); @@ -334,12 +463,34 @@ public function getBrickByUID($uid) throw new QUI\Exception('Brick not found'); } - $Brick = new Brick($data[0]); - $Brick->setAttribute('id', $uid); + $data = $data[0]; + $brickId = $data['brickId']; + $custom = $data['customfields']; + + $attributes = $data['attributes']; + $attributes = json_decode($attributes, true); + + $Original = new Brick($attributes); + $Original->setAttribute('id', $brickId); + + $Clone = clone $Original; + + if (!empty($custom)) { + $custom = json_decode($custom, true); + + if ($custom) { + $Clone->setSettings($custom); + } + + // workaround + if (isset($custom['brickTitle'])) { + $Clone->setAttribute('frontendTitle', $custom['brickTitle']); + } + } - $this->brickUIDs[$uid] = $Brick; + $this->brickUIDs[$uid] = $Clone; - return $this->brickUIDs[$uid]; + return $Clone; } /** @@ -483,10 +634,17 @@ public function getBricksByArea($brickArea, Site $Site) $result = array(); - foreach ($bricks as $brickData) { + foreach ($bricks as $key => $brickData) { $brickId = (int)$brickData['brickId']; try { + if (isset($brickData['uid'])) { + $Brick = $this->getBrickByUID($brickData['uid']); + $result[] = $Brick->check(); + continue; + } + + // fallback $Brick = $this->getBrickById($brickId); $Clone = clone $Brick; @@ -502,13 +660,11 @@ public function getBricksByArea($brickArea, Site $Site) $result[] = $Clone->check(); } catch (QUI\Exception $Exception) { - QUI\System\Log::addWarning( - $Exception->getMessage().' Brick-ID:'.$brickId - ); + QUI\System\Log::writeRecursive($brickData); + QUI\System\Log::writeException($Exception); } } - return $result; } @@ -646,8 +802,35 @@ public function saveBrick($brickId, array $brickData) 'id' => (int)$brickId )); - // @todo it is a workaround - QUI\Cache\Manager::clearAll(); + // refresh all bricks with this id + $uniqueBricks = QUI::getDataBase()->fetch(array( + 'from' => QUI\Bricks\Manager::getUIDTable(), + 'where' => array( + 'project' => $Project->getName(), + 'lang' => $Project->getLang(), + 'brickId' => (int)$brickId + ) + )); + + foreach ($uniqueBricks as $uniqueBrick) { + $customFieldsUniqueBrick = json_decode($uniqueBrick['customfields'], true); + $attributes = $Brick->getAttributes(); + + if (isset($attributes['attributes'])) { + unset($attributes['attributes']); + } + + if (!is_array($customFieldsUniqueBrick)) { + $customFieldsUniqueBrick = array(); + } + + QUI::getDataBase()->update(QUI\Bricks\Manager::getUIDTable(), array( + 'customfields' => json_encode($customFieldsUniqueBrick), + 'attributes' => json_encode($attributes) + ), array( + 'uid' => $uniqueBrick['uid'] + )); + } } /** @@ -663,9 +846,9 @@ protected function getTable() /** * @return string */ - protected function getUIDTable() + public static function getUIDTable() { - return QUI::getDBTableName(self::TABLE); + return QUI::getDBTableName(self::TABLE_UID); } /**