Page Controller
Bevor du im Rocket Seiten erfassen kannst, musst du zuerst Seiten-Typen implementieren. Dies machst du anhand von Page-Methoden in Page Controllern.
Page Controller definieren
Page Controller funktionieren gleich wie normale Controller, jedoch bindest du Methoden nicht an Pfade, sondern an Seiten-Typen. Konkret bedeutet dies, dass du Methoden nicht mit AnnoPath
, AnnoExt
oder "do"-Prefex annotierst, sondern mit page\annotation\AnnoPage
. Jede mit page\annotation\AnnoPage
annotierte Methode definiert einen Seiten-Typ und generiert dessen Ausgabe. Im weiteren Verlauf dieser Dokumentation nennen wir solche Methoden "Page-Methoden". Page Controller müssen page\model\bo\PageController
erweitern.
<?php namespace atusch\controller; use page\model\bo\PageController; use page\annotation\AnnoPage; use n2n\reflection\annotation\AnnoInit; class ExamplePageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->m('startPage', new AnnoPage()); $ai->m('standardPage', new AnnoPage()); } public function startPage() { $this->forward('\atusch\view\startPage.html'); } public function standardPage() { $this->forward('\atusch\view\standardPage.html'); } }
Im oben stehenden Beispiel haben wir die zwei Seiten-Typen "startPage" und "standardPage" definiert. Beim Aufruf einer entsprechenden Seite wird die jeweilige Page-Methode ausgeführt.
Damit wir diese Seiten-Typen im Rocket auch verwenden können, müssen wir den ExamplePageController
im app.ini
unter der Gruppe[orm]
als Entity registrieren.
[orm] entities[] = "atusch\controller\ExamplePageController"
Page Controller sind Entities mit Vererbungs-Strategie Joined, welche für jede Entity eine eigene Tabelle benötigt. Dies bedeutet, dass wir auch für unseren ExamplePageController
eine Tabelle erstellen müssen. Da er aber über keine Eigenschaften verfügt, enthält die Tabelle nur eine Spalte "id". Die Tabelle sieht also folgendermassen aus:
CREATE TABLE `example_page_controller` ( `id` int(10) unsigned NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
AUTO_INCREMENT
), da für Page Controller-Entities die Vererbungs-Strategie Joined verwendet wird.Als Letztes müssen wir für die Entity ExamplePageController
eine EiSpec erstellen. Danach solltest du im Rocket bereits Seiten dieser zwei Typen erfassen können. Wird eine dieser Seiten im Frontend aufgerufen, wird die entsprechende Page-Methode im ExamplePageController
ausgeführt.
Views
In Views (im oben stehenden Beispiel startPage.html
und standardPage.html
) kannst du den page\ui\PageHtmlBuilder
verwenden, um Eigenschaften der aktuellen Seite auszugeben.
<?php use page\ui\PageHtmlBuilder; $pageHtml = new PageHtmlBuilder($view); $view->useTemplate('template.html'); ?> <article> <h2><?php $pageHtml->title() ?></h2> <!-- content --> </article>
Mit $pageHtml->title()
gibst du den Titel der aktuellen Seite aus.
Natürlich kannst du den PageHtmlBuilder
auch im template.html
verwenden.
<?php use page\ui\PageHtmlBuilder; $pageHtml = new PageHtmlBuilder($view); $pageHtml->meta()->applyMeta(); ?> <!DOCTYPE html> <html> <?php $html->headStart() ?> <meta charset="utf-8" /> <?php $html->headEnd() ?> <?php $html->bodyStart() ?> <h1>Site Heading</h1> <div> <?php $view->importContentView() ?> </div> <?php $html->bodyEnd() ?> </html>
$pageHtml->meta()->applyMeta();
fügt die im Rocket erfassten Metainformationen der aktuellen Seite dem Html-Header hinzu (z. B. <title>
, <meta name="description" content=".." />
usw.).
PageHtmlBuilder
findest du in der Api-Dokumentation.ContentItems
Nutze die Annotation page\annotation\AnnoPageCiPanels
, um ContentItem-Panels für Page-Methoden (Seiten-Typen) zu definieren.
class ExamplePageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->m('startPage', new AnnoPage(), new AnnoPageCiPanels('main', 'info')); } public function startPage() { $this->forward('\atusch\view\startPage.html'); } }
Im oben stehenden Beispiel haben wir für die Page-Methode startPage()
die Panels "main" und "info" definiert. Erstellst oder bearbeitest du im Rocket nun eine Seite dieses Typs, kannst du für diese beiden Panels ContentItems erfassen.
In der View kannst du ContentItems einfach über page\ui\PageHtmlBuilder::contentItems()
einbinden. standardPage.html
könnte zum Beispiel folgendermassen aussehen:
<?php use page\ui\PageHtmlBuilder; $pageHtml = new PageHtmlBuilder($view); $view->useTemplate('template.html'); ?> <article> <h2><?php $pageHtml->title() ?></h2> <?php $pageHtml->contentItems('main') ?> <aside> <?php $pageHtml->contentItems('info') ?> </aside> </article>
Page-Methoden
Page-Methoden sind magisch und verhalten sich auch sonst wie Action-Methoden in Controllern.
class ExamplePageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->m('articlePage', new AnnoPage()); } public function articlePage(BlogDao $blogDao, $categoryPathPart = null) { $blogArticles = null; if ($categoryPathPart === null) { $blogArticles = $blogDao->getLatestBlogArticles(); } else { $category = $blogDao->getCategoryByPathPart($categoryPathPart); if ($category === null) { throw new PageNotFoundException(); } $blogArticles = $blogDao->getBlogArticlesByCategory($category); } $this->forward('..\view\blogArticles.html', array('blogArticles' => $blogArticles)); } }
Im oben stehenden Beispiel haben wir den Seiten-Typ "articlePage" definiert. Gehen wir davon aus, dass wir eine Seite dieses Typs unter http://[url-to-n2n-public]/articles
eingerichtet haben, so werden beim Aufruf dieser Url über $blogDao->getLatestBlogArticles()
die neusten Blog-Artikel abgefragt und an die View blogArticles.html
übergeben. Der optionale Pfad-Parameter $categoryPathPart
ist nur dann gesetzt, wenn die Seite zum Beispiel über http://[url-to-n2n-public]/articles/category1
aufgerufen wird. In diesem Fall werden nur die Blog-Artikel der Kategorie mit zugehörigem Pfad-Teil "category1" abgefragt und der View übergeben.
Gleich wie bei normalen Controllern, kannst du auch bei Page Controllern Requests delegieren.
class ExamplePageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->m('articlePage', new AnnoPage()); } public function articlePage(BlogArticleController $blogArticleController, array $delegateParams = null) { $this->delegate($blogArticleController); } }
Konfigurierbare Page Controller
In vielen Fällen möchtest du dem Nutzer beim Erfassen von Seiten gewisser Typen weitere Konfigurationsmöglichkeiten bieten. Dies kannst du über normale Entity-Eigenschaften in deinem Page Controller erreichen, für die du EiFields definierst.
Beispiel 1
Der Nutzer soll für die beiden Seiten-Typen "foo" und "bar" eine Option "advanced" haben. Wir fassen diese zwei Seiten-Typen also im FooBarController
zusammen und fügen die Entity-Eigenschaft FooBarPageController::$advanced
hinzu.
class FooBarPageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->m('fooPage', new AnnoPage()); $ai->m('barPage', new AnnoPage()); } private $advanced = false; public function isAdvanced(): bool { return $this->advanced; } public function setAdvanced(bool $advanced) { $this->advanced = $advanced; } public function fooPage() { $this->forward('..\view\fooPage.hml', array('advanced' => $this->advanced)); } public function barPage() { $this->forward('..\view\barPage.hml', array('advanced' => $this->advanced)); } }
Die Tabelle für die Entity FooBarController
sieht folgendermassen aus:
CREATE TABLE IF NOT EXISTS `foo_bar_page_controller` ( `id` int(10) unsigned NOT NULL, `advanced` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Als Letztes müssen wir für unseren FooBarController
noch eine EiSpec definieren.
"atusch-foo-bar-page-controller": { "type": "entity", "entity": "atusch\\controller\\FooBarPageController", "dataSourceName": null, "label": "Foo Bar Page Controller", "pluralLabel": "Foo Bar Page Controllers", "fields": { "advanced": { "class": "rocket\\spec\\ei\\component\\field\\impl\\bool\\BooleanEiField", "props": { "mandatory": true }, "label": "Advanced", "objectProperty": "advanced", "entityProperty": "advanced" } } }
specs.json
in dieser Dokumentation dienen nur der Veranschaulichung. Es ist nicht nötig, die specs.json
manuell zu bearbeiten.Erfasst der Nutzer im Rocket nun eine Seite vom Typ "fooPage" oder "barPage", trifft er eine Option "advanced" an.
Beispiel 2
Als Grundlage des folgenden Beispiels dienen die Entities BlogArticle
und Category
des Artikels Persistence / ORM - Beziehungen. Gehen wir davon aus, du hast Blog-Artikel verschiedener Kategorien erfasst und für beide Entities bereits eine EiSpec definiert. Nun möchtest du dem Rocket-Nutzer einen Seiten-Typ anbieten, der die Blog-Artikel einer einzigen Kategorie anzeigt. Die Kategorie soll vom Nutzer beim Erfassen der Seite gewählt werden können.
class BlogPageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->p('category', new AnnoManyToOne(Category::getClass())); $ai->m('blogPage', new AnnoPage()); } private $category; public function getCategory() { return $this->category; } public function setCategory(Category $category) { $this->category = $category; } public function blogPage(BlogController $blogController, array $delegateCmds = null) { $blogController->setCategory($this->category); $this->delegate($blogController); } }
Die passende Tabelle könnte folgendermassen aussehen:
CREATE TABLE `blog_page_controller` ( `id` int(10) unsigned NOT NULL, `category_id` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8
Die passende EiSpec könnte folgendermassen aussehen:
"atusch-blog-page-controller": { "type": "entity", "entity": "atusch\\controller\\BlogPageController", "dataSourceName": null, "label": "Blog Page Controller", "pluralLabel": "Blog Page Controllers", "fields": { "category": { "class": "rocket\\spec\\ei\\component\\field\\impl\\relation\\ManyToOneSelectEiField", "props": { "mandatory": true }, "label": "Category", "objectProperty": "category", "entityProperty": "category" } } }
specs.json
in dieser Dokumentation dienen nur der Veranschaulichung. Es ist nicht nötig, die specs.json
manuell zu bearbeiten.Erfasst der Nutzer im Rocket nun eine Blog-Seite, kann er die Kategorie wählen. Beim Aufruf der Page-Methode, ist die gewählte Kategorie über die Eigenschaft BlogPageController::$category
zugreifbar und kann so weiterverwendet werden.