Development Content

From Cloudrexx Development Wiki
Jump to: navigation, search


Note: This documentation refers to version 5 or newer. For older versions of Cloudrexx, please refer to Content V4.

Structure / Tree

Cloudrexx Content Tree

As Cloudrexx is a native multilingual content management system, a website consists of just one content tree that is being used by all localized versions of it. The content tree consists of nodes (\Cx\Core\ContentManager\Model\Entity\Node) which do determine the structure (branches) of the site. As only one tree is being used, the site structure on every locale is identical. Each node contains a set of localized pages (\Cx\Core\ContentManager\Model\Entity\Page).

Note: There exists a special node called **root node**. It has no content (meaning no assigned pages), it's just the invisible root of the node tree.


Each node can contain a page for every set up locale. A page's behavior is defined by its type. Available types are as follows:

Name (GUI) Name (CODE) Description Comment
Content Page CONTENT A normal content page
Redirect REDIRECTION A redirection to another node or website
Application APPLICATION A module page
Use Fallback Version FALLBACK A page using the content of another language
ALIAS An alias for a page or website This is a special case. Alias pages are not shown in Content Manager (more information at Find an alias).

Status Icons

Depending on the page's type and its publication state, it will be displayed in the Content Manager by a specific icon:

Page Status Icons

Slugs / URLs

Definition: a slug is a part of an URL:

URLs are built by traversing the node tree from the root down to the desired page. For all parent nodes we visit, the slug of the assigned page in the same language as the target page is appended to the url.

Example (see figure):

  • Assume the german Page assigned to node B has the slug 'Level1'
  • Assume the german Page assigned to node A has the slug 'Level2a'
  • Assume the german Page assigned to node C has the slug 'Level2b'

The following URLs would then be valid:

Every page stores it's slug name. The slug is automatically set when first giving the page a title.


Node-URL Notation

Areas of application
  • The MediaBrowser uses the Node-URL Notation to link to a internal webpage
  • Internal redirections (page type: REDIRECTION) should use the Node-URL Notation
Schema definition

A node URL can be represented by the following placeholder notation:


Part Description
<node_id> ID of the page's node
<module> name of the page's application
<cmd> additional CMD of the page's application
<lang_id> a specific language version of the page
Resolving the Node-URL Notation

Normally it's better to store the Node-URL placeholder instead of an URL and parse it when generating the output, since the placeholder is more flexible!

Use \Cx\Core\Routing\NodePlaceholder to convert from and to placeholder format. See the API documentation for further details.

Node Placeholder Description
[[NODE_2]] URL pointing to the page of the current (requested) locale of node having ID 2
[[NODE_SHOP]] URL pointing to the application Shop
[[NODE_SHOP_CART]] URL pointing to the application Shop that uses the area (cmd) cart (i.e ?section=Shop&cmd=cart)
[[NODE_SHOP_CART_2]] same as above, but localized version of the page having ID 2


Concept of owning or inverse side of a relation

In the context of the Doctrine the page model is owning side and the node the inverse side.

Database Structure

Important: This diagram is outdated.

Class diagram

Important: This diagram is outdated.


Find Pages

Find the actual page

$page = $this->cx->getPage();

Find a single page

$pageRepo = $this->cx->getDb()->getEntityManager()->getRepository(

// If you want to find a page by Page ID
$crit = array(
    'id' => $id,
$page = $pageRepo->findOneBy($crit);

// If you want to find a page by Node ID and lang
$crit = array(
    'node' => $nodeId,
    'lang' => $langId,
$page = $pageRepo->findOneBy($crit);

// If you want to find a page by Module, CMD and lang
$crit = array(
    'module' => $moduleName,
    'cmd' => $cmd,
    'lang' => $langId,
$page = $pageRepo->findOneBy($crit);

// If you want to find a module page by Module, CMD and lang which searches also in fallback pages if the page doesn't exist:
$page = $pageRepo->findOneByModuleCmdLang($module, $cmd, $lang);

Find a list of pages

$pageRepo = $this->cx->getDb()->getEntityManager()->getRepository(

// If your search arguments match 'field' = 'value'
$crit = array(
    'lang' => $langId,
// Pages will contain an Array of Page Objects
$pages = $pageRepo->findBy($crit);

// If you need full SQL search capabilities
// You can get Page Objects by using Doctrine DQL
$qb = $this->em->createQueryBuilder();
    ->from('Cx\Core\ContentManager\Model\Entity\Page', 'p')
    ->where($qb->expr()->like('module', '?1')
    ->setParameter(1, '%'.$string.'%');

$pages = $qb->getQuery()->getResult();

Find an alias

$pageRepo = $this->cx->getDb()->getEntityManager()->getRepository(

// find an alias by title
$criteria = array(
'title' => $title,
'type'  => \Cx\Core\ContentManager\Model\Entity\Page::TYPE_ALIAS,

$page = $pageRepo->findOneBy($criteria, true);

Aliases have the language id 0 which is not assigned to the active languages. For this reason you can't find them by passing the criteria "'lang' => 0". But you have the possibility to pass the boolean "true" as second parameter of "findOneBy()" which causes that the page repository also searches in the inactive languages.

Move an existing node

// Find the node we want to move
$nodeToMove = $nodeRepo->findOneBy(array('id'=>$moveNodeId));

// Find the new parent node (if different)
$newParentNode = $nodeRepo->findOneBy(array('id'=>$newParentId));

// Set new parent node (if different)

// Move the node to the top of the branch
$nodeRepo->moveUp($nodeToMove, true);

// Move the node to its new position within the branch
// $newPosition is the new position as an integer
$nodeRepo->moveDown($nodeToMove, $newPosition);

// Save changes to nodes

// Sanitize page paths
foreach ($nodeToMove->getPages() as $page) {

// Flush entity manager

Creating a Page

 //retrieve the doctrine entity manager
 $em = $this->cx->getDb()->getEntityManager();
 //retrieve the parent node
 $pageRepo = $em->getRepository('Cx\Core\ContentManager\Model\Entity\Page');
 $nodeRepo = $em->getRepository('Cx\Core\ContentManager\Model\Entity\Node');
 //parent page has id 3
 $parentPage = $pageRepo->findOneBy(array('id'=>3));
 $parentNode = $parentPage->getNode();
 //append a new child node for our page
 $node = new \Cx\Core\ContentManager\Model\Entity\Node();
 //set some data on our page
 $page = new \Cx\Core\ContentManager\Model\Entity\Page();
 //assign the page to our node

 // move it to where you want it (below same parent Node)
 $nodeRepo->moveDown($node, 3);
 //empty entity manager so the node tree is correctly re-read

Delete a single page

$page = $pageRepo->findOneBy(array('id'=>$id));

Delete a node with all its pages and subnodes

$node = $nodeRepo->findOneBy(array('id'=>$id));

Translating a Page

Every page with a language L must have all of it's parent pages available in translation to language L. If that is not the case, the page is lost and invisible. Remember how URLs are built - we can't build an URL for a page where we do not find the slugs in language L for the parent pages.

Look at the figure again. If we want to translate the german page on node A to english, we also need to insert a translated page on node B. As this is a common task, the PageRepository provides a method for translating a page in language X to language Y and automatically inserting the needed parent pages. The slugs of the translated parent pages are taken from the pages in language X.

// retrieve the doctrine entity manager
$em = Env::em();

// retrieve the page to translate
$pageRepo = $em->getRepository('Cx\Core\ContentManager\Model\Entity\Page');
$sourcePage = $pageRepo->getPagesAtPath('Level1/Level2a');

// translate it to english
$english = 2;
// see phpdoc for all available parameters of translate()
$translatedPage = $pageRepo->translate($sourcePage, $english);
// the page is now translated (copied to different language)

// set different content

// save and flush changes