Controller einbinden

Page

Bisher haben wir Page Controller erstellt, welche einfache Page Methoden beinhalteten, die definierte Views aufrufen. Jetzt wollen wir einen komplizierteren Controller als Page einbinden.

  1. Page Controller für Blog erstellen
  2. Blog Modul Anpassen
  3. Das war das Wichtigste

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.

specs.json

Wenn alles geklappt hat, wurde in var/etc/qs/rocket/specs.json die EiSpec 'qs-blog-page-controller' erstellt.

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!

Die Musterlösung findest du im Composer Projekt unter 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.

n2n bringt ein ORM nach JPA Standard mit. JPA ist Standard für Datenzugriffe in Java. Entsprechend mächtig sind die Möglichkeiten von n2n für komplexe Datenabfragen. Im Quickstart gehen wir aber nicht genauer darauf ein.

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.

Den angepassten 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.
Views mit Bootstrap Klassen

Entpacke diese Views unter \qs\views

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!

« Seiten-Inhalte Demo Page »

comments_title

post_login_to_create

questions_title