/** * Updates the associated definition of the set of metadata. * * @param array $definitions * @param \BackBee\CoreDomain\NestedNode\Page $page */ public function update(array $definitions = null, Page $page = null) { $content = null === $page ? null : $page->getContentSet(); if (null !== $definitions) { foreach ($definitions as $name => $definition) { if (false === is_array($definition)) { continue; } if (null === ($metadata = $this->get($name))) { $metadata = new MetaData($name); $this->add($metadata); } foreach ($definition as $attrname => $attrvalue) { if (false === is_array($attrvalue)) { $attrvalue = '' === $metadata->getAttribute($attrname) ? $attrvalue : $metadata->getAttribute($attrname); $metadata->setAttribute($attrname, $attrvalue, $content); continue; } if (true === $metadata->hasAttribute($attrname)) { if (null !== $page && true === array_key_exists('layout', $attrvalue)) { $layout_uid = $page->getLayout()->getUid(); if (true === array_key_exists($layout_uid, $attrvalue['layout'])) { $scheme = is_array($attrvalue['layout'][$layout_uid]) ? reset($attrvalue['layout'][$layout_uid]) : $attrvalue['layout'][$layout_uid]; $metadata->updateAttributeScheme($attrname, $scheme, $content); } } continue; } if (true === array_key_exists('default', $attrvalue)) { $value = is_array($attrvalue['default']) ? reset($attrvalue['default']) : $attrvalue['default']; $metadata->setAttribute($attrname, $value, $content); } if (null !== $page && true === array_key_exists('layout', $attrvalue)) { $layout_uid = $page->getLayout()->getUid(); if (true === array_key_exists($layout_uid, $attrvalue['layout'])) { $value = is_array($attrvalue['layout'][$layout_uid]) ? reset($attrvalue['layout'][$layout_uid]) : $attrvalue['layout'][$layout_uid]; $metadata->setAttribute($attrname, $value, $content); } } } } } }
public function getRoutesByNames($names) { if (null === $names) { $collection = new RouteCollection(); $pages = $this->entityManager->getRepository('BackBee\\CoreDomain\\NestedNode\\Page')->findBy(array('_site' => $this->siteContext->getSite(), '_state' => Page::getUndeletedStates())); foreach ($pages as $page) { $name = $page->getUrl(); $collection->add($name, $this->createRouteFromEntity($page, $name)); } return $collection; } $routes = array(); foreach ($names as $name) { try { $routes[] = $this->getRouteByName($name); } catch (RouteNotFoundException $e) { // not found } } return $routes; }
/** * Replace root contentset for a page and its descendants. * * @param \BackBee\CoreDomain\NestedNode\Page $page * @param \BackBee\CoreDomain\ClassContent\ContentSet $oldContentSet * @param \BackBee\CoreDomain\ClassContent\ContentSet $newContentSet * @param \BackBee\Security\Token\BBUserToken $userToken */ public function updateRootContentSetByPage(Page $page, ContentSet $oldContentSet, ContentSet $newContentSet, BBUserToken $userToken) { $em = $this->_em; $q = $this->createQueryBuilder('c'); $results = $q->leftJoin('c._pages', 'p')->leftJoin('p._section', 'sp')->leftJoin('c._subcontent', 'subcontent')->where('subcontent = :contentToReplace')->andWhere('sp._root = :cpageRoot')->andWhere('sp._leftnode > :cpageLeftnode')->andWhere('sp._rightnode < :cpageRightnode')->setParameters(['contentToReplace' => $oldContentSet, 'cpageRoot' => $page->getSection()->getRoot(), 'cpageLeftnode' => $page->getLeftnode(), 'cpageRightnode' => $page->getRightnode()])->getQuery()->getResult(); if ($results) { foreach ($results as $parentContentSet) { /* create draft for the main container */ $draft = $em->getRepository('BackBee\\CoreDomain\\ClassContent\\Revision')->getDraft($parentContentSet, $userToken, true); if (null !== $draft) { $parentContentSet->setDraft($draft); } /* Replace the old ContentSet by the new one */ $parentContentSet->replaceChildBy($oldContentSet, $newContentSet); $em->persist($parentContentSet); } } }
/** * Custom patch process for Page's sibling or parent node. * * @param Page $page * @param array $operations passed by reference */ private function patchSiblingAndParentOperation(Page $page, array &$operations) { $sibling_operation = null; $parent_operation = null; foreach ($operations as $key => $operation) { $op = array('key' => $key, 'op' => $operation); if ('/sibling_uid' === $operation['path']) { $sibling_operation = $op; } elseif ('/parent_uid' === $operation['path']) { $parent_operation = $op; } } if (null !== $sibling_operation || null !== $parent_operation) { if ($page->isRoot()) { throw new BadRequestHttpException('Cannot move root node of a site.'); } if ($page->isOnline(true)) { $this->granted('PUBLISH', $page); // user must have publish permission on the page } } try { if (null !== $sibling_operation) { unset($operations[$sibling_operation['key']]); $sibling = $this->getPageByUid($sibling_operation['op']['value']); $this->granted('EDIT', $sibling->getParent()); $this->getPageRepository()->moveAsPrevSiblingOf($page, $sibling); } elseif (null !== $parent_operation) { unset($operations[$parent_operation['key']]); $parent = $this->getPageByUid($parent_operation['op']['value']); if ($this->isFinal($parent)) { throw new BadRequestHttpException('Can\'t create children of ' . $parent->getLayout()->getLabel() . ' layout'); } $this->moveAsFirstChildOf($page, $parent); } } catch (InvalidArgumentException $e) { throw new BadRequestHttpException('Invalid node move action: ' . $e->getMessage()); } }
/** * Computes the URL of a page according to a scheme. * * @param array $scheme The scheme to apply * @param Page $page The page * @param AbstractClassContent $content The optionnal main content of the page * @return string The generated URL */ private function doGenerate($scheme, Page $page, AbstractClassContent $content = null) { $replacement = ['$parent' => $page->isRoot() ? '' : $page->getParent()->getUrl(false), '$title' => StringUtils::urlize($page->getTitle()), '$datetime' => $page->getCreated()->format('ymdHis'), '$date' => $page->getCreated()->format('ymd'), '$time' => $page->getCreated()->format('His')]; $matches = []; if (preg_match_all('/(\\$content->[a-z]+)/i', $scheme, $matches)) { foreach ($matches[1] as $pattern) { $property = explode('->', $pattern); $property = array_pop($property); try { $replacement[$pattern] = StringUtils::urlize($content->{$property}); } catch (\Exception $e) { $replacement[$pattern] = ''; } } } $matches = []; if (preg_match_all('/(\\$ancestor\\[([0-9]+)\\])/i', $scheme, $matches)) { foreach ($matches[2] as $level) { $ancestor = $this->application->getEntityManager()->getRepository('BackBee\\CoreDomain\\NestedNode\\Page')->getAncestor($page, $level); if (null !== $ancestor && $page->getLevel() > $level) { $replacement['$ancestor[' . $level . ']'] = $ancestor->getUrl(false); } else { $replacement['$ancestor[' . $level . ']'] = ''; } } } $url = preg_replace('/\\/+/', '/', str_replace(array_keys($replacement), array_values($replacement), $scheme)); return $this->getUniqueness($page, $url); }
/** * Compute values of attributes according to the AbstractClassContent provided. * * @param \BackBee\CoreDomain\ClassContent\AbstractClassContent $content * * @return \BackBee\MetaData\MetaData */ public function computeAttributes(AbstractClassContent $content, Page $page = null) { foreach ($this->attributes as $attribute => $value) { if (true === $this->is_computed[$attribute] && true === array_key_exists($attribute, $this->scheme)) { try { $functions = explode('||', $value); $matches = array(); if (false !== preg_match_all('/(\\$([a-z_\\/\\\\]+)(\\[([0-9]+)\\]){0,1}(->){0,1})+/i', $this->scheme[$attribute], $matches, PREG_PATTERN_ORDER)) { $this->attributes[$attribute] = $this->scheme[$attribute]; $initial_content = $content; $count = count($matches[0]); for ($i = 0; $i < $count; $i++) { $content = $initial_content; foreach (explode('->', $matches[0][$i]) as $scheme) { $draft = null; if (true === is_object($content)) { if (null !== ($draft = $content->getDraft())) { $content->releaseDraft(); } } $newcontent = $content; $m = array(); if (preg_match('/\\$([a-z\\/\\\\]+)(\\[([0-9]+)\\]){0,1}/i', $scheme, $m)) { if (3 < count($m) && $content instanceof ContentSet && 'ContentSet' === $m[1]) { $newcontent = $content->item($m[3]); } elseif (3 < count($m) && $content instanceof ContentSet) { $index = intval($m[3]); $classname = 'BackBee\\CoreDomain\\ClassContent\\' . str_replace('/', NAMESPACE_SEPARATOR, $m[1]); foreach ($content as $subcontent) { if (get_class($subcontent) == $classname) { if (0 === $index) { $newcontent = $subcontent; } else { $index--; } } } } elseif (true === is_object($content) && 1 < count($m)) { $property = $m[1]; try { $newcontent = $content->{$property}; } catch (\Exception $e) { $newcontent = new Text(); } } } if (null !== $draft) { $content->setDraft($draft); } $content = $newcontent; } if ($content instanceof AbstractClassContent && $content->isElementContent()) { if (null !== ($draft = $content->getDraft())) { $content->releaseDraft(); } if ($content instanceof File) { $new_value = $content->path; } else { $new_value = trim(str_replace(array("\n", "\r"), '', strip_tags('' . $content))); } $this->attributes[$attribute] = str_replace($matches[0][$i], $new_value, $this->attributes[$attribute]); if (null !== $draft) { $content->setDraft($draft); } } elseif (true === is_array($content)) { $v = array(); foreach ($content as $c) { if ($c instanceof Keyword) { } $v[] = trim(str_replace(array("\n", "\r"), '', strip_tags('' . $c))); } $this->attributes[$attribute] = str_replace($matches[0][$i], implode(',', $v), $this->attributes[$attribute]); } else { $new_value = trim(str_replace(array("\n", "\r"), '', strip_tags($content))); $this->attributes[$attribute] = str_replace($matches[0][$i], $new_value, $this->attributes[$attribute]); } } } array_shift($functions); if (0 < count($functions)) { foreach ($functions as $fct) { $parts = explode(':', $fct); $functionName = array_shift($parts); array_unshift($parts, $this->attributes[$attribute]); $this->attributes[$attribute]; $this->attributes[$attribute] = call_user_func_array($functionName, $parts); } } } catch (\Exception $e) { } } elseif (preg_match('/^\\#([a-z]+)$/i', $value, $matches)) { switch (strtolower($matches[1])) { case 'url': if (null !== $page) { $this->attributes[$attribute] = $page->getUrl(); } default: break; } } } return $this; }
/** * Persists the page is need and valid * * @param Page $page The page to be built. */ private function doPersistIfValid(Page $page) { if (null === $page->getParent() && !empty($this->persist)) { // If root, only persist $this->em->persist($page); return; } $method = ''; if (self::PERSIST_AS_FIRST_CHILD === $this->persist) { $method = 'insertNodeAsFirstChildOf'; } elseif (self::PERSIST_AS_LAST_CHILD === $this->persist) { $method = 'insertNodeAsLastChildOf'; } if (!empty($method)) { $this->em->getRepository('BackBee\\CoreDomain\\NestedNode\\Page')->{$method}($page, $page->getParent(), $this->isSection); $this->em->persist($page); } }
/** * Sets the parent node. * * @param Page $parent * * @return Page */ public function setParent(Page $parent) { if (!$parent->hasMainSection()) { throw new InvalidArgumentException('A parent page must be a section'); } if (!$this->hasMainSection() || $this->isRoot()) { $this->setSection($parent->getSection()); } else { $this->getSection()->setParent($parent->getSection()); } return $this; }
/** * Remove stored page-content and site-content indexes from a page. * * @param Page $page * * @return IndexationRepository */ public function removeIdxPage(Page $page) { $query = 'DELETE FROM idx_page_content WHERE page_uid = :page'; $params = array('page' => $page->getUid()); return $this->removeIdxSite($page)->_executeQuery($query, $params); }
/** * Returns the maximum position of children of $page. * * @param Page $page * * @return integer */ private function getMaxPosition(Page $page) { if (false === $page->hasMainSection()) { return 0; } $query = $this->createQueryBuilder('p'); $max = $query->select($query->expr()->max('p._position'))->andParentIs($page)->getQuery()->getResult(\Doctrine\ORM\Query::HYDRATE_SINGLE_SCALAR); return null === $max ? 0 : $max; }
/** * Add query part to select descendants of $page. * * @param Page $page The page to look for descendants * @param boolean $strict Optional, if false (by default) $node is include to the selection * @param integer|null $depth Optional, filter ancestors by their level * @param string[]|null $order Optional, ordering spec ( [$field => $sort] ) * @param integer|null $limit Optional, max number of results, if null no limit * @param integer $start Optional, first result index (0 by default) * @param boolean $limitToSection Optional, if true limits to descendants being section * * @return PageQueryBuilder */ public function andIsDescendantOf(Page $page, $strict = false, $depth = null, array $order = null, $limit = null, $start = 0, $limitToSection = false) { $suffix = $this->getSuffix(); $this->andWhere($this->getSectionAlias() . '._root = :root' . $suffix)->andWhere($this->expr()->between($this->getSectionAlias() . '._leftnode', $page->getSection()->getLeftnode(), $page->getSection()->getRightnode()))->setParameter('root' . $suffix, $page->getSection()->getRoot()); if (true === $strict) { $this->andWhere($this->getAlias() . ' != :page' . $suffix)->setParameter('page' . $suffix, $page); } if (null !== $depth) { $this->andWhere($this->getAlias() . '._level <= :level' . $suffix)->setParameter('level' . $suffix, $page->getLevel() + $depth); } if (null !== $order) { $this->addMultipleOrderBy($order); } if (null !== $limit) { $this->setMaxResults($limit)->setFirstResult($start); } if (true === $limitToSection) { $this->andIsSection(); } return $this; }
/** * Sets the associated page for this section. * * @param Page $page * * @return Section */ public function setPage(Page $page) { $this->_page = $page; $page->setMainSection($this); return $this; }
/** * Set a page to filter the query on a nested portion. * * @param BackBee\CoreDomain\NestedNode\Page $page */ public function addPageFilter(Page $page) { if ($page && !$page->isRoot()) { $this->leftJoin('cc._mainnode', 'p')->leftJoin('p._section', 'sp')->andWhere('sp._root = :selectedPageRoot')->andWhere('sp._leftnode >= :selectedPageLeftnode')->andWhere('sp._rightnode <= :selectedPageRightnode')->setParameters(['selectedPageRoot' => $page->getSection()->getRoot(), 'selectedPageLeftnode' => $page->getLeftnode(), 'selectedPageRightnode' => $page->getRightnode()]); } }