Page Controller

CMS

Bevor du im Rocket Seiten erfassen kannst, musst du zuerst Seiten-Typen implementieren. Dies machst du anhand von Page-Methoden in Page Controllern.

  1. Page Controller definieren
  2. ContentItems
  3. Page-Methoden
  4. Konfigurierbare Page Controller

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;
Ist dir nicht klar, wie dieser Tabellennamen zustande kommt oder wie du ihn anpassen kannst, dann solltest du den Abschnitt Tabellen- und Spaltennamen der ORM-Dokumentation kurz durchlesen. Denk auch daran, dass die Id in Page Controller-Tabellen nicht automatisch generiert werden darf (z. B. 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. 

Eine Anleitung, wie du Seiten im Rocket verwalten kannst, findest du im Artikel Seitenverwaltung im Rocket.

 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.).

Weitere Informationen über den 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.

Ist nichts weiter konfiguriert, kann der Nutzer im Rocket für diese zwei Panels eine beliebige Anzahl ContentItems beliebiger Typen erfassen. Im Artikel Konfiguration erfährst du, wie du dies einschränken kannst.

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"
                }
            }
        }
Nutze den Hangar, um EiSpecs und EiFields einfach erfassen zu können. Ausschnitte der 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"
                }
            }
        }
Nutze den Hangar, um EiSpecs und EiFields einfach erfassen zu können. Ausschnitte der 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.

« Entwicklung Navigieren »

Kommentare

Du musst eingeloggt sein, damit du Beiträge erstellen kannst.

Fragen