Controller einbinden
Bisher haben wir Page Controller erstellt, welche einfache Page Methoden beinhalteten, die definierte Views aufrufen. Jetzt wollen wir einen komplizierteren Controller als Page einbinden.
Page Controller für Blog erstellen
Jetzt wird es Zeit, dass wir unser qs
Modul aus dem n2n Quickstart wieder hervornehmen. Das einzige, was wir tun müssen, ist einen PageController
erstellen, welcher den Aufruf an den BlogController
delegiert.
Im Gegensatz zum TemplatePageController
, möchten wir unseren BlogPageController
konfigurierbar machen. In Rocket soll bestimmt werden können, ob nur BlogArticle
von einer BlogCategory
auf der Seite angezeigt werden sollen. Aus diesem Grund brauchen wir auf BlogPageController
die Eigenschaft $category
, welche über Getter- und Setter-Methoden verfügt.
\qs\controller\BlogPageController.php
<?php namespace qs\controller; use page\bo\PageController; use page\annotation\AnnoPage; use n2n\reflection\annotation\AnnoInit; use qs\bo\BlogCategory; use n2n\persistence\orm\annotation\AnnoManyToOne; class BlogPageController extends PageController { private static function _annos(AnnoInit $ai) { $ai->m('blog', new AnnoPage()); $ai->p('category', new AnnoManyToOne(BlogCategory::getClass())); } private $category; public function getCategory() { return $this->category; } public function setCategory(BlogCategory $category = null) { $this->category = $category; } public function blog(BlogController $blogController, array $delegateCmds = null) { $blogController->setCategory($this->category); $this->delegate($blogController); } }
Neben der Get- und Set-Methoden verfügt unser Controller auch über die Page-Methode blog()
. Diese delegiert den Request an den BlogController, den wir im n2n Quickstart ertstellt haben.
Jetzt müssen wir uns bewusst sein, dass jeder PageController
eine Entität ist. Jede Entität müssen wir im registrieren. Passe var/etc/qs/app.ini
wie folgt an:
[orm] entities[] = "qs\bo\BlogArticle" entities[] = "qs\bo\BlogCategory" entities[] = "qs\bo\BlogComment" entities[] = "qs\controller\BlogPageController"
Den Routing Eintrag kannst du löschen, da unser Modul neu über eine Seite zugänglich sein wird.
Ausserdem müssen wir noch auf der Datenbank die entsprechende Tabelle eröffnen:
CREATE TABLE `blog_page_controller` ( `id` int(10) UNSIGNED NOT NULL, `category_id` int(10) UNSIGNED DEFAULT NULL ) ENGINE=InnoDB; ALTER TABLE `blog_page_controller` ADD PRIMARY KEY (`id`); ALTER TABLE `blog_page_controller` MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
Jetzt brauchen wir noch die EiSpec für Rocket. Gehe dazu in den Hangar und öffne in der Entities Spalte qs\controller\BlogPageController
. Klicke rechts darauf und wähle: Generate EiSpec. Konfiguriere die EiSpec von BlogPageController
wie folgt:
- General: Wähle ein plausibles Label für deinen Content Editoren. Z.B. Blog Modul
- Fields: Füge unter Add auto EiField Category hinzu. Diese soll nicht mandatory sein, damit man auch alle Artikel-Kategorien anzeigen lassen kann!
Das reicht bereits. Vergiss nicht zu speichern.
Jetzt kannst du in Rocket eine Page Blog eröffnen und den Controller hinzufügen. Zusätzlich zum Controller kannst du auch eine Kategorie hinzufügen. Die Kategorie übergeben wir zwar vor der Delegation an den BlogController
, dort gibt es aber noch Anpassungsbedarf!
app\qs6\controller\Blog6PageController.php
. Dieser PageController speichert seine Daten auf der Tabelle blog6_page_controller
.Blog Modul Anpassen
Zuerst passen wir qs\controller\BlogController
an.
class BlogController extends ControllerAdapter { // ... private $category; // ... public function setCategory(BlogCategory $category = null) { $this->category = $category; } public function index() { // Kategorie übergeben $blogArticles = $this->blogDao->getOnlineBlogArticles($this->category); $this->forward('..\view\overview.html', array('blogArticles' => $blogArticles)); } // ... }
Neu hat unser Controller die private Eigenschaft $category
. Diese kann mit setCategory()
von aussen gesetzt werden. In der Methode getOnlineBlogArticles()
geben wir neu $this->category
mit.
Model
Das bedeutet, dass wir auch qs\model\BlogDao
anpassen müssen:
public function getOnlineBlogArticles(BlogCategory $category = null) { $criteria = $this->em->createCriteria()->select('ba')->from(BlogArticle::getClass(), 'ba'); $criteria->where(array('ba.online' => true)); if ($category) { $criteria->where()->match('ba.categories', 'CONTAINS', $category); } return $criteria->toQuery()->fetchArray(); }
Mit traditionellem SQL müssten wir eine JOIN
Verbindung über die Verbindungstabelle auf BlogCategory
machen. Weil eine solche Abfrage komplizierter wird, reicht ein SimpleCriteria
nicht mehr aus. Wir erstellen ein normales Criteria
und bestimmen dort gleich, dass wir BlogArticles
selektieren wollen, welchen wir ein Alias 'ba'
geben.
Über ->where()
definieren wir, dass wir nur die BlogArticle
wünschen, welche online sind. ->where()
erlaubt nur abfragen mit '='. Beispiel: ba.online = true
. Sind die Abfragen komplizierter, müssen wir an ->where()
eine ->match()
Methode anhängen. Im Beispiel oben machen wir dies, wenn eine $category
übergeben wird. Dann verlangen wir, dass nur die BlogArticles
zurückgegeben werden, welche die übergebene $categorie
enthalten (CONTAINS
).
Wie du siehst, ist auch eine Abfrage über mehrere Tabellen mit n2n gar nicht so kompliziert. Du findest nähere Informationen zu komplexeren Datenbankabfragen in der n2n Dokumentation. Eine spannende Alternative zu Criteria ist NQL. Dies ist besonders für Entwickler mit SQL Erfahrung eine intuitive Methode. Informationen zu NQL findest du auch bei den komplexeren Datenbankabfragen in der n2n Dokumentation.
Views
Du kannst auch noch deine Views etwas anpassen. Wirklich neues haben wir aber nur unter qs\view\comment.html.php
:
<?php use n2n\impl\web\ui\view\html\HtmlView; use qs\model\BlogCommentForm; $view = HtmlView::view($this); $html = HtmlView::html($view); $formHtml = HtmlView::formHtml($view); $commentForm = $view->getParam('commentForm'); $view->assert($commentForm instanceof BlogCommentForm); $view->useTemplate('\template\view\boilerplate.html'); ?> <h1>Kommentar schreiben</h1> <?php $formHtml->open($commentForm) ?> <?php // $formHtml->messageList(null, array('class' => 'alert alert-danger list-unstyled')) ?> <div class="form-group row<?php $formHtml->outOnError('email', ' has-danger') ?>"> <?php $formHtml->label('email', null, array("class" => "col-sm-3 col-lg-2 col-form-label")) ?> <div class="col-sm-9 col-lg-4"> <?php $formHtml->input('email', array('maxlength' => 120, 'class' => 'form-control')) ?> <?php $formHtml->message('email', 'div', array('class' => 'form-control-feedback')) ?> </div> </div> <div class="form-group row<?php $formHtml->outOnError('content', ' has-danger') ?>"> <?php $formHtml->label('content', null, array("class" => "col-sm-3 col-lg-2 col-form-label")) ?> <div class="col-sm-9 col-lg-4"> <?php $formHtml->textarea('content', array('rows' => 5, 'cols' => 30, 'class' => 'form-control')) ?> <?php $formHtml->message('content', 'div', array('class' => 'form-control-feedback')) ?> </div> </div> <div class="form-group row<?php $formHtml->outOnError('image', ' has-danger') ?>"> <?php $formHtml->label('image', null, array("class" => "col-sm-3 col-lg-2 col-form-label"))?> <div class="col-sm-9 col-lg-4"> <?php $formHtml->inputFileWithLabel('image') ?> <?php $formHtml->message('image', 'div', array('class' => 'form-control-feedback'))?> </div> </div> <div class="form-group row"> <div class="col-sm-9 col-lg-4 offset-sm-3 offset-lg-2"> <?php $formHtml->buttonSubmit('save', 'Kommentar speichern', array('class' => 'btn btn-primary'))?> </div> </div> <?php $formHtml->close() ?>
Zuerst fallen sicher alle Bootstrap Klassen auf! Ausserdem geben wir die messageList()
nicht mehr zu Beginn aus, sondern geben jeden Fehler beim entsprechenden Formluarfeld aus ($formHtml->message()
). Ebenfalls neu ist $formHtml->outOnError()
. Diese Mehtode prüft, ob die Property, welche im ersten Parameter bestimmt wurde einen Fehler hat. Nur wenn dies der Fall ist, wird Parameter 2 ausgegeben.
In den anderen Views gibt es keine dramatischen Änderungen. Die wichtigste Anpassung ist, dass überall das Template \template\view\boilerplate.html
verwendet werden soll ($view->useTemplate()
). Wir stellen dir darum hier alle Views zum Download zur Verfügung.
BlogController
und die Views findest du unter app\qs6\
wenn du das Composer Projekt für den Page Quickstart installiert hast. Beachte, dass alle Namespaces unterschiedlich sind! Ebenfalls: die Views des \qs6
Moduls benutzen nicht \template\view\boilerplate.html
, sondern \qst\view\boilerplate.html
.Das war das Wichtigste
Wir haben dir jetzt die Basics gezeigt, wie man mit n2n, Rocket und Page eine Webseite erstellen kann. Bei diesem Quickstart sind wir bewusst so vorgegangen, dass wir dir die einzelnen Schritte erklärt haben. Du hast gelernt, wie man mit dem Page Modul eine Webseite aufbauen kann. Ebenso hast du gelernt, wie du deine individuellen Controller ins Page Modul einbauen kannst. Natürlich haben wir auch viele Dinge aus den drei Modulen weggelassen. Weitere Informationen findest du in der restlichen Dokumentation der Module und der API.
Die Arbeit mit n2n wird effizient, wenn du dir eine Sammlung Module zulegst, welche du immer wieder verwenden kannst.
Als nächsten Schritt empfehlen wir dir, unser "Demo Page" Projekt anzuschauen. Dort haben wir eine vollständige Webseite für dich vorbereitet. Mit dem Wissen aus den Quickstarts wirst du viele Dinge verstehen und sie für eigene Projekte nutzen können!