Development Content
Introduction
Note: This documentation refers to version 5 or newer. For older versions of Cloudrexx, please refer to Content V4.
Structure / 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.
Pages
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:
Slugs / URLs
Definition: a slug is a part of an URL: http://www.example.com/thisIsASlug/andAnotherSlug
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:
- Node B is available via http://example.com/Level1
- Node A is available via http://example.com/Level1/Level2a
- Node C is available via http://example.com/Level1/Level2b
Every page stores it's slug name. The slug is automatically set when first giving the page a title.
Nodes
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:
[[NODE_(<node_id>|<module>[_<cmd>])[_<lang_id>]]]
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.
Examples
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 |
Model
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
Class diagram
Integration
Find Pages
Find the actual page
$page = $this->cx->getPage();
Find a single page
$pageRepo = $this->cx->getDb()->getEntityManager()->getRepository(
'Cx\Core\ContentManager\Model\Entity\Page'
);
// 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(
'Cx\Core\ContentManager\Model\Entity\Page'
);
// 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();
$qb->select('p')
->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(
'Cx\Core\ContentManager\Model\Entity\Page'
);
// 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)
$nodeToMove->setParent($newParentNode);
// 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
$em->persist($nodeToMove);
$em->persist($newParentNode);
// Sanitize page paths
foreach ($nodeToMove->getPages() as $page) {
$page->setupPath($page->getLang());
$em->persist($page);
}
// Flush entity manager
$em->flush();
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();
$node->setParent($parentNode);
//set some data on our page
$page = new \Cx\Core\ContentManager\Model\Entity\Page();
$page->setTitle('myPage');
$page->setLang($parentPage->getLang());
//assign the page to our node
$page->setNode($node);
// move it to where you want it (below same parent Node)
$nodeRepo->moveDown($node, 3);
//save
$em->persist($node);
$em->persist($page);
//empty entity manager so the node tree is correctly re-read
$em->flush();
Delete a single page
$page = $pageRepo->findOneBy(array('id'=>$id));
$em->remove($page);
$em->flush();
Delete a node with all its pages and subnodes
$node = $nodeRepo->findOneBy(array('id'=>$id));
$em->remove($node);
$em->flush();
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.
Example:
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
$translatedPage->setContent('foo');
// save and flush changes
$em->persist($translatedPage);
$em->flush();