/**
  * Saves the node tree from the structure in text format
  * @param string $locale Locale of the structure
  * @param \ride\library\cms\node\Node $parent Parent node of the structure
  * @param \ride\library\cms\node\NodeModel $nodeModel Instance of the node
  * model
  * @param string $structure Node tree in text format
  * @return null
  */
 public function setStructure($locale, Node $parent, NodeModel $nodeModel, $structure)
 {
     $site = $parent->getRootNode();
     if ($site->isLocalizationMethodUnique()) {
         $isUniqueTree = true;
     } else {
         $isUniqueTree = false;
     }
     $previousNodeId = null;
     $previousSpaces = null;
     $level = 0;
     $levels = array(0 => $site->getId());
     $order = array($site->getId() => 0);
     $spaces = array();
     $structure = $this->parseStructure($structure);
     foreach ($structure as $index => $nodeArray) {
         $structure[$index]['node'] = $this->saveNode($locale, $site, $nodeModel, $nodeArray, $isUniqueTree);
         $structure[$index]['id'] = $structure[$index]['node']->getId();
         if ($previousSpaces === null) {
             $spaces[$level] = $nodeArray['spaces'];
         } elseif ($nodeArray['spaces'] > $previousSpaces) {
             $level++;
             $levels[$level] = $previousNodeId;
             $spaces[$level] = $nodeArray['spaces'];
         } elseif ($nodeArray['spaces'] < $previousSpaces) {
             krsort($spaces);
             foreach ($spaces as $spaceLevel => $numSpaces) {
                 if ($nodeArray['spaces'] >= $numSpaces) {
                     $level = $spaceLevel;
                     break;
                 }
             }
         }
         $order[$levels[$level]]++;
         $order[$structure[$index]['id']] = 0;
         $previousNodeId = $structure[$index]['id'];
         $previousSpaces = $nodeArray['spaces'];
     }
     $siblings = $nodeModel->getNodesByPath($site->getId(), $site->getRevision(), $parent->getId());
     foreach ($siblings as $siblingId => $sibling) {
         if (isset($order[$siblingId]) || $isUniqueTree && !$sibling->isAvailableInLocale($locale)) {
             continue;
         }
         $nodeModel->removeNode($sibling, false, null, false);
     }
     unset($order[$parent->getId()]);
     $nodeModel->orderNodes($site->getId(), $site->getRevision(), $parent->getId(), $order, $locale);
 }
 /**
  * Dispatches the node
  * @param \ride\library\mvc\Request $request
  * @param \ride\library\mvc\Response $response
  * @param \ride\library\security\SecurityManager $securityManager
  * @param \ride\library\cache\pool\CachePool $cache
  * @return array Array with the region name as key and a view array as
  * value. The view array has the widget id as key and the dispatched
  * widget view as value
  */
 public function dispatch(Request $request, Response $response, SecurityManager $securityManager, CachePool $cache = null)
 {
     $this->locale = $this->view->getLocale();
     // initialize context
     $context = array('title' => array('site' => $this->node->getRootNode()->getName($this->locale, 'title'), 'node' => $this->node->getName($this->locale, 'title')), 'breadcrumbs' => $this->breadcrumbs, 'styles' => array(), 'scripts' => array());
     // prepare and process incoming route arguments
     $route = $request->getRoute();
     $this->routeArguments = $route->getArguments();
     unset($this->routeArguments['node']);
     unset($this->routeArguments['locale']);
     if (isset($this->routeArguments['site'])) {
         // preview has site and revision
         unset($this->routeArguments['site']);
         unset($this->routeArguments['revision']);
     }
     $nodeRoute = $this->node->getRoute($this->locale);
     $nodeRouteTokens = explode('/', ltrim($nodeRoute, '/'));
     foreach ($nodeRouteTokens as $tokenIndex => $tokenValue) {
         if (isset($this->routeArguments[$tokenIndex]) && $this->routeArguments[$tokenIndex] === $tokenValue) {
             unset($this->routeArguments[$tokenIndex]);
         }
     }
     $route->setPredefinedArguments(array());
     $route->setArguments();
     $routeArgumentsMatched = false;
     // check for cache
     $cacheKey = null;
     $cacheItem = null;
     $cachedViews = array();
     $dispatchedViews = array();
     $nodeCacheTtl = false;
     if ($cache) {
         $method = $request->getMethod();
         $isCacheable = $method == 'GET' || $method == 'HEAD' ? true : false;
         $isNoCache = $request->isNoCache();
         if ($isCacheable) {
             $parameters = $this->routeArguments ? '-' . implode('-', $this->routeArguments) : '';
             $parameters .= $request->getQueryParametersAsString();
             $containsUserContent = false;
             $nodeCacheTtl = 0;
             $cacheKey = 'node.view.' . $this->node->getId() . '.' . $this->node->getRevision() . '.' . $this->locale . '.' . substr(md5($parameters), 0, 10);
             if ($securityManager->getUser()) {
                 $cacheKey .= '.authenticated';
             }
             $cacheItem = $cache->get($cacheKey);
             if ($cacheItem->isValid()) {
                 $cachedViews = $cacheItem->getValue();
             } else {
                 $cachedViews = array();
             }
         }
     } else {
         $isCacheable = false;
     }
     foreach ($this->widgets as $this->region => $sections) {
         $dispatchedViews[$this->region] = array();
         foreach ($sections as $this->section => $blocks) {
             $dispatchedViews[$this->region][$this->section] = array();
             foreach ($blocks as $this->block => $widgets) {
                 $dispatchedViews[$this->region][$this->section][$this->block] = array();
                 foreach ($widgets as $widgetId => $widget) {
                     if ($this->log) {
                         $this->log->logDebug('Rendering widget ' . $widget->getName() . '#' . $widgetId . ' for region ' . $this->region, null, ApplicationListener::LOG_SOURCE);
                     }
                     $widgetProperties = $this->node->getWidgetProperties($widgetId);
                     if (!$widgetProperties->isPublished()) {
                         if ($this->log) {
                             $this->log->logDebug('Widget ' . $widget->getName() . '#' . $widgetId . ' is not published', null, ApplicationListener::LOG_SOURCE);
                         }
                         continue;
                     } elseif (!$widgetProperties->isAllowed($securityManager)) {
                         if ($this->log) {
                             $this->log->logDebug('Widget ' . $widget->getName() . '#' . $widgetId . ' is not allowed', null, ApplicationListener::LOG_SOURCE);
                         }
                         continue;
                     }
                     if ($isCacheable) {
                         $widgetCacheKey = $this->region . '.' . $this->section . '.' . $this->block . '.' . $widgetId . '.';
                     }
                     $isWidgetCache = $widgetProperties->isCacheEnabled() || $widgetProperties->isAutoCache() && $widget->isAutoCache();
                     if ($isCacheable && !$isNoCache && $isWidgetCache) {
                         if (isset($cachedViews[$this->region][$this->section][$this->block][$widgetId])) {
                             if ($this->log) {
                                 $this->log->logDebug('Retrieved widget ' . $widget->getName() . '#' . $widgetId . ' from cache', null, ApplicationListener::LOG_SOURCE);
                             }
                             $cacheView = $cachedViews[$this->region][$this->section][$this->block][$widgetId];
                             if ($cacheView->areRoutesMatched()) {
                                 $widgetMatchedRouteArguments = true;
                             }
                             $cacheContext = $cacheView->getContext();
                             if ($cacheContext) {
                                 foreach ($cacheContext as $key => $value) {
                                     if ($value !== null) {
                                         $context[$key] = $value;
                                     } elseif (isset($context[$key])) {
                                         unset($context[$key]);
                                     }
                                 }
                             }
                             if ($cacheView->isContent()) {
                                 $dispatchedViews = null;
                                 $this->view->setContentView($view, $widgetId, $this->block, $this->section, $this->region);
                                 break 4;
                             } elseif ($cacheView->isRegion()) {
                                 $dispatchedViews[$this->region] = array($this->section => array($this->block => array($widgetId => $cacheView->getView())));
                                 break 3;
                             } elseif ($cacheView->isSection()) {
                                 $dispatchedViews[$this->region][$this->section] = array($this->block => array($widgetId => $cacheView->getView()));
                                 break 2;
                             } elseif ($cacheView->isBlock()) {
                                 $dispatchedViews[$this->region][$this->section][$this->block] = array($widgetId => $cacheView->getView());
                                 break;
                             } else {
                                 $dispatchedViews[$this->region][$this->section][$this->block][$widgetId] = $cacheView->getView();
                                 continue;
                             }
                         }
                     }
                     $widget->setProperties($widgetProperties);
                     $widget->setContext($context);
                     $widgetMatchedRouteArguments = $this->dispatchWidget($request, $response, $widgetId, $widget);
                     if ($widgetMatchedRouteArguments) {
                         $routeArgumentsMatched = true;
                     }
                     $statusCode = $response->getStatusCode();
                     if ($statusCode != Response::STATUS_CODE_OK && $statusCode != Response::STATUS_CODE_BAD_REQUEST && $statusCode != Response::STATUS_CODE_UNPROCESSABLE_ENTITY) {
                         return;
                     }
                     $view = $response->getView();
                     $response->setView(null);
                     $isContent = $widget->isContent();
                     $isRegion = $widget->isRegion();
                     $isSection = $widget->isSection();
                     $isBlock = $widget->isBlock();
                     if ($isCacheable && !$containsUserContent && $widget->containsUserContent()) {
                         $containsUserContent = true;
                     }
                     $oldContext = $context;
                     $context = $widget->getContext();
                     if ($isCacheable && $isWidgetCache) {
                         $widgetContext = $this->getContextDifference($context, $oldContext);
                         if (!$widgetContext) {
                             // calculate node cache time based on the least widget cache time
                             $cacheTtl = $widgetProperties->getCacheTtl();
                             if ($nodeCacheTtl !== false && $cacheTtl) {
                                 if ($nodeCacheTtl == 0) {
                                     $nodeCacheTtl = $cacheTtl;
                                 } else {
                                     $nodeCacheTtl = min($nodeCacheTtl, $cacheTtl);
                                 }
                             }
                             $widgetCachedView = new WidgetCacheData($widgetContext, $isContent, $isRegion, $isSection, $isBlock, $widgetMatchedRouteArguments);
                             $cachedViews[$this->region][$this->section][$this->block][$widgetId] = $widgetCachedView;
                         }
                     }
                     if ($isContent) {
                         $dispatchedViews = null;
                         $this->view->setContentView($view, $widgetId, $this->block, $this->section, $this->region);
                         break 4;
                     } elseif ($isRegion) {
                         $dispatchedViews[$this->region] = array($this->section => array($this->block => array($widgetId => $view)));
                         break 3;
                     } elseif ($isSection) {
                         $dispatchedViews[$this->region][$this->section] = array($this->block => array($widgetId => $view));
                         break 2;
                     } elseif ($isBlock) {
                         $dispatchedViews[$this->region][$this->section][$this->block] = array($widgetId => $view);
                         break;
                     }
                     $dispatchedViews[$this->region][$this->section][$this->block][$widgetId] = $view;
                 }
                 if (!$dispatchedViews[$this->region][$this->section][$this->block]) {
                     unset($dispatchedViews[$this->region][$this->section][$this->block]);
                 }
             }
             if (!$dispatchedViews[$this->region][$this->section]) {
                 unset($dispatchedViews[$this->region][$this->section]);
             }
         }
         if (!$dispatchedViews[$this->region]) {
             unset($dispatchedViews[$this->region]);
         }
     }
     if ($this->routeArguments && !$routeArgumentsMatched) {
         // sub route provided but never matched
         $response->setStatusCode(Response::STATUS_CODE_NOT_FOUND);
         $response->setView(null);
         $dispatchedViews = null;
     }
     // if ($this->eventManager && $isCacheable && $nodeCacheTtl !== false) {
     // if ($user && $containsUserContent) {
     // $isCacheable = false;
     // }
     // if ($isCacheable) {
     // $this->cache = $cache;
     // $this->cacheTtl = $nodeCacheTtl;
     // $this->eventManager->addEventListener(WebApplication::EVENT_POST_RESPONSE, array($this, 'cacheResponse'));
     // }
     // }
     $this->view->setContext($context);
     if (is_array($dispatchedViews)) {
         $this->view->setDispatchedViews($dispatchedViews);
         $this->view->setRegions($this->regions);
         if ($nodeCacheTtl !== false && $cachedViews) {
             $cacheItem->setValue($cachedViews);
             $cacheItem->setTtl($nodeCacheTtl);
             $this->view->setCachedViews($cache, $cacheItem);
         }
     }
     $response->setView($this->view);
 }
Exemplo n.º 3
0
 /**
  * Publishes a site to the provided revision
  * @param \ride\library\cms\node\Node $node
  * @param string $revision
  * @param boolean $recursive Flag to see if the node's children should be
  * published as well
  * @return array|null Nodes have been deleted
  */
 public function publish(Node $node, $revision, $recursive)
 {
     $deletedNodes = array();
     if ($node->getRevision() == $revision) {
         return $deletedNodes;
     }
     $site = $node->getRootNode();
     $siteId = $site->getId();
     $nodeId = $node->getId();
     $publishDirectory = $this->path->getChild($siteId . '/' . $revision);
     if (!$publishDirectory->exists()) {
         // first publish
         $sourceDirectory = $this->path->getChild($siteId . '/' . $node->getRevision());
         $sourceDirectory->copy($publishDirectory);
         return $deletedNodes;
     }
     // publish revision exists, archive the revision before publishing
     $archiveDirectory = $this->path->getChild($siteId . '/' . $this->archiveName . '/' . date('YmdHis'));
     $publishDirectory->copy($archiveDirectory);
     // publish node
     $deletedNode = $this->publishNode($site, $node, $revision, $publishDirectory, false);
     if ($deletedNode) {
         $deletedNodes[$deletedNode->getId()] = $deletedNode;
     }
     if (!$recursive) {
         return $deletedNodes;
     }
     // publish recursive nodes
     $oldNodes = $this->getNodesByPath($siteId, $revision, $node->getPath());
     $nodes = $this->getNodesByPath($siteId, $site->getRevision(), $node->getPath());
     foreach ($nodes as $nodeId => $node) {
         $this->publishNode($site, $node, $revision, $publishDirectory, true);
         if (isset($oldNodes[$nodeId])) {
             unset($oldNodes[$nodeId]);
         }
     }
     // deleted the removed nodes
     foreach ($oldNodes as $oldNodeId => $oldNode) {
         $oldNodeFile = $this->getNodeFile($oldNode);
         $oldNodeFile->delete();
         $deletedNodes[$oldNodeId] = $oldNode;
     }
     $this->expiredRouteModel->removeExpiredRoutesByNode($siteId, array_keys($oldNodes));
     return $deletedNodes;
 }
Exemplo n.º 4
0
 /**
  * Get the widgets for a section in a region for the provided node
  * @param Node $node Node to query
  * @param string $region Name of the region
  * @param string $section Name of the section
  * @param boolean $inherited Fetch only inherited properties of the node
  * @return array Array with the block id as key and as value an array with the
  * widget instance id as key and the widget id as value
  */
 protected function getSectionWidgets(Node $node, $region, $section, $inherited)
 {
     // resolve set widgets
     $sectionString = $node->get(self::PROPERTY_REGION . '.' . $region . '.' . $section . '.' . self::PROPERTY_WIDGETS, null, true, $inherited);
     if (!$sectionString) {
         return array();
     }
     // parse widget string
     $sectionWidgets = $this->parseSectionString($node->getRootNode(), $sectionString);
     if ($inherited) {
         return $sectionWidgets;
     }
     // resolve inherited widgets
     $inheritedSectionWidgets = $this->getInheritedWidgets($region, $section);
     foreach ($sectionWidgets as $blockId => $blockWidgets) {
         if (!$blockWidgets && isset($inheritedSectionWidgets[$blockId])) {
             $sectionWidgets[$blockId] = $inheritedSectionWidgets[$blockId];
         }
     }
     return $sectionWidgets;
 }
Exemplo n.º 5
0
 /**
  * Clones the node's properties to the destination
  * @param \ride\library\cms\node\Node $source Source node
  * @param \ride\library\cms\node\Node $destination Destination node
  * @param boolean $keepOriginalName Set to true to keep the name untouched
  * @param boolean $cloneRoutes Set to true to clone the routes of the nodes
  * @return null
  */
 protected function cloneNodeProperties(Node $source, Node $destination, $keepOriginalName, $cloneRoutes)
 {
     $widgetPropertyPrefixLength = strlen(Node::PROPERTY_WIDGET) + 1;
     try {
         $site = $destination->getRootNode();
     } catch (CmsException $exception) {
         $site = $destination;
     }
     $parent = $source->getParentNode();
     $sourceProperties = $source->getProperties();
     $destinationProperties = array();
     // duplicate the regions and the set widgets
     foreach ($sourceProperties as $index => $sourceProperty) {
         $key = $sourceProperty->getKey();
         if (strpos($key, Node::PROPERTY_REGION) !== 0 || !strpos($key, '.' . Node::PROPERTY_WIDGETS)) {
             continue;
         }
         $tokens = explode('.', $key);
         $region = $tokens[1];
         $section = $tokens[2];
         $newValue = array();
         $inheritedWidgetIds = array();
         if ($parent) {
             $inheritedValue = $parent->get($key, null, true, true);
             if ($inheritedValue) {
                 $inheritedWidgetIds = $source->parseSectionString($source->getRootNode(), $inheritedValue);
             }
         }
         $sourceWidgetIds = $source->parseSectionString($source->getRootNode(), $sourceProperty->getValue());
         foreach ($sourceWidgetIds as $blockId => $blockWidgets) {
             $newValue[$blockId] = array();
             foreach ($blockWidgets as $widgetId => $widget) {
                 if (isset($this->widgetTable[$widgetId])) {
                     $newWidgetId = $this->widgetTable[$widgetId];
                 } elseif (isset($inheritedWidgetIds[$blockId][$widgetId])) {
                     // use the same widget id for inherited widgets
                     $this->widgetTable[$widgetId] = $widgetId;
                     $newWidgetId = $widgetId;
                 } else {
                     // create a new widget for node widgets
                     $widget = $source->getWidget($widgetId);
                     $newWidgetId = $site->createWidget($widget);
                     $this->widgetTable[$widgetId] = $newWidgetId;
                 }
                 $newValue[$blockId][] = $newWidgetId;
             }
             $newValue[$blockId] = Node::BLOCK_OPEN . implode(NodeProperty::LIST_SEPARATOR, $newValue[$blockId]) . Node::BLOCK_CLOSE;
         }
         $destinationProperty = new NodeProperty($key, implode(NodeProperty::LIST_SEPARATOR, $newValue), $sourceProperty->getInherit());
         $destinationProperties[$key] = $destinationProperty;
         unset($sourceProperties[$index]);
     }
     // duplicate the remaining properties
     foreach ($sourceProperties as $index => $sourceProperty) {
         $key = $sourceProperty->getKey();
         $value = $sourceProperty->getValue();
         $destinationProperty = new NodeProperty($key, $value, $sourceProperty->getInherit());
         if (!$keepOriginalName && strpos($key, Node::PROPERTY_NAME . '.') === 0) {
             // add copy suffix to the name
             $locale = str_replace(Node::PROPERTY_NAME . '.', '', $key);
             if ($source->getLevel() === 0) {
                 $children = $this->io->getSites();
             } else {
                 $children = $this->io->getChildren($source->getRootNodeId(), $source->getRevision(), $source->getParent(), 0);
             }
             $baseName = $value;
             $name = $baseName . ' (clone)';
             $index = 2;
             do {
                 $found = false;
                 foreach ($children as $child) {
                     $childName = $child->getName();
                     if ($childName == $name) {
                         $name = $baseName . ' (clone ' . $index . ')';
                         $index++;
                         $found = true;
                         break;
                     }
                 }
             } while ($found);
             $destinationProperty->setValue($name);
         } elseif (!$cloneRoutes && strpos($key, Node::PROPERTY_ROUTE . '.') === 0) {
             // skip this property as it's a route and it's flagged to not clone routes
             continue;
         } elseif (strpos($key, Node::PROPERTY_WIDGET . '.') === 0) {
             // remap the widget ids for widget properties
             $propertyKey = substr($key, $widgetPropertyPrefixLength);
             $positionPropertySeparator = strpos($propertyKey, '.');
             if ($positionPropertySeparator === false) {
                 continue;
             }
             $widgetId = substr($propertyKey, 0, $positionPropertySeparator);
             $propertyKey = substr($propertyKey, $positionPropertySeparator);
             if (!isset($this->widgetTable[$widgetId])) {
                 continue;
             }
             $destinationProperty = new NodeProperty(Node::PROPERTY_WIDGET . '.' . $this->widgetTable[$widgetId] . $propertyKey, $destinationProperty->getValue(), $destinationProperty->getInherit());
         }
         $destinationProperties[$destinationProperty->getKey()] = $destinationProperty;
     }
     $destination->setProperties($destinationProperties);
 }
 /**
  * Validates the route of the node
  * @param \ride\library\cms\node\Node $node Node to be validated
  * @param \ride\library\cms\node\NodeModel $nodeModel Model of the nodes
  * @param \ride\library\validation\exception\ValidationException $exception
  * @return null
  */
 protected function validateRoute(Node $node, NodeModel $nodeModel, ValidationException $exception)
 {
     if (!$node->getParent()) {
         return;
     }
     $rootNode = $node->getRootNode();
     $rootNodeId = $rootNode->getId();
     $nodeId = $node->getId();
     $modelNodes = $nodeModel->getNodes($rootNodeId, $node->getRevision());
     $propertyPrefix = Node::PROPERTY_ROUTE . '.';
     $lengthPropertyPrefix = strlen($propertyPrefix);
     // loop all properties
     $properties = $node->getProperties();
     foreach ($properties as $key => $property) {
         if (strpos($key, $propertyPrefix) !== 0) {
             // we're only interested in route properties
             continue;
         }
         $routeLocale = substr($key, $lengthPropertyPrefix);
         $route = $property->getValue();
         // normalize route
         $route = trim($route, '/');
         $baseUrls[$routeLocale] = $rootNode->getBaseUrl($routeLocale);
         $tokens = explode('/', $route);
         foreach ($tokens as $index => $token) {
             if ($token) {
                 $token = StringHelper::safeString($token);
             }
             if (empty($token)) {
                 unset($tokens[$index]);
             } else {
                 $tokens[$index] = $token;
             }
         }
         $route = '/' . implode('/', $tokens);
         // check for duplicate routes
         $errors = array();
         foreach ($modelNodes as $modelNode) {
             $modelNodeId = $modelNode->getId();
             if ($modelNodeId == $nodeId || $modelNode->getRootNodeId() != $rootNodeId || !$modelNode->hasParent() || $modelNode->getType() == ReferenceNodeType::NAME) {
                 // same node, different site or root node or a reference node
                 continue;
             }
             $modelNodeRoutes = $modelNode->getRoutes();
             foreach ($modelNodeRoutes as $locale => $modelNodeRoute) {
                 if (!array_key_exists($locale, $baseUrls)) {
                     $baseUrls[$locale] = $rootNode->getBaseUrl($locale);
                 }
                 if ($baseUrls[$routeLocale] . $route != $baseUrls[$locale] . $modelNodeRoute) {
                     continue;
                 }
                 $errors[$modelNodeId] = new ValidationError('error.route.used.node', "Route '%route%' is already used by node %node% in locale %locale%", array('route' => $route, 'node' => $modelNodeId, 'locale' => $locale));
             }
         }
         foreach ($errors as $error) {
             $exception->addErrors(Node::PROPERTY_ROUTE, array($error));
         }
         // update property with normalized route
         $property->setValue($route);
     }
 }
 /**
  * Checks if this action is available for the node
  * @param \ride\library\cms\node\Node $node
  * @return boolean True if available
  */
 public function isAvailableForNode(Node $node)
 {
     return !$node->getRootNode()->isAutoPublish();
 }