Seiten-Inhalte
Bisher ist unsere Seite noch sehr leer. Es fehlt an Inhalten. Inhalte werden mit n2n Rocket über Content Items gelöst. Content Items sind Inhalts-Bausteine, aus welchen Inhalte zum Beispiel für unsere Seiten zusammen gebaut werden können.
Früher war es üblich, dass man für Seiten einfach einen HTML Editor zur Verfügung gestellt hat. Darin konnte der Content Editor alles machen: grelle Farben, Tabellen zu Layout-Zwecken missbrauchen, Bilder, Youtube Videos. Wir brauchen dir nicht zu sagen, wie der generierte HTML Code schlussendlich aussah. Kannst du dir vorstellen eine solche Seite responsive anzubieten?
Aus diesem Grund sind wir auf das Konzept der Content Items umgestiegen. Content Items sind Definitionen von bestimmten Inhaltsblöcken. Das Content Item CiArticle
, welches wir gleich erstellen werden, besteht beispielsweise immer aus einem Bild, Titel und einer Beschreibung. Dank diesen Inhaltsblöcken kannst du die Funktionen, welche im HTML Editor angeboten werden müssen, deutlich reduzieren. Wir erlauben beispielsweise keine Einbindung mehr von Bilder im HTML-Editor. Den einzelnen Content Items können wir dann Regeln hinterlegen, wie sie auf den verschiedenen Bildschirmgrössen ausgegeben werden sollen.
Content Items erstellen
Weil Content Items nicht nur für Seiten verwendet werden, erstellen wir ein eigenes Modul. Du wirst dieses für die meisten deiner Projekte verwenden können! Für das neue Modul (Namespace ci
) legen wir wieder die drei bekannten Verzeichnisse an:
app/ci
var/etc/ci
public/assets/ci
Content Items speichern wir wie unsere BusinessObjects unter app/ci/bo
. Erstelle die Content Items CiArticle
, CiAttachment
, CiImage
, CiWysiwyg
. Wir stellen sie dir hier zum Download zur Verfügung:
Die Content Items erben nicht von EntityAdapter
, sondern von ContentItem
. Trotzdem funktionieren sie praktisch gleich. Es gibt eine Ausnahme: die Methode createUiComponent()
. Diese Methode gibt den HTML Code für die Ausgabe zurück. Dies kann auf zwei verschiedene Arten geschehen:
- Das Content Item erstellt selber ein
HtmlElement
und gibt dieses zurück.CiWysiwyg
undCiAttachment
sind Beispiele für diese Methode. - Das Content Item ruft eine View auf und gibt diese zurück. Das kannst du in
CiImage
undCiArticle
beobachten.
CiWysiwyg->contentHtml
bearbeiten wir in Rocket. Wir können die Eigenschaft nicht direkt ausgeben, weil Rocket Links (zum Beispiel auf Pages) codiert speichert. Darum funktioniert new HtmlElement('div', null, $this->contentHtml)
nicht. Um die Links zu decoden, braucht es den WysiwygHtmlBuilder
. Dies gilt für jede Html Eigenschaft, welche generierte Links beinhalten kann.Nun müssen wir noch die Views für CiImage
und CiArticle
erstellen:
app/ci/view/article.html.php
schaut so aus:
<?php use n2n\impl\web\ui\view\html\HtmlView; use n2n\web\ui\view\View; use ci\bo\CiArticle; use rocket\spec\ei\component\field\impl\string\wysiwyg\WysiwygHtmlBuilder; use n2n\io\managed\img\impl\ThSt; $view = HtmlView::view($this); $html = HtmlView::html($view); $article = $view->getParam('article'); $view->assert($article instanceof CiArticle); $htmlWysiwyg = new WysiwygHtmlBuilder($view); ?> <article class="ci ci-article row"> <div class="col-sm-4"> <?php $html->image($article->getFileImage(), ThSt::crop(400, 300), array('class' => 'img-fluid')) ?> </div> <div class="col-sm-8"> <h2><?php $html->out($article->getTitle()) ?></h2> <?php $htmlWysiwyg->out($article->getDescriptionHtml()) ?> </div> </article>
app/ci/view/image.html.php
ist nicht komplizierter:
<?php use n2n\impl\web\ui\view\html\HtmlView; use n2n\web\ui\view\View; use ci\bo\CiImage; use n2n\io\managed\img\impl\ThSt; $view = HtmlView::view($this); $html = HtmlView::html($view); $image = $view->getParam('image'); $view->assert($image instanceof CiImage); ?> <figure class="ci ci-image"> <?php $html->image($image->getFileImage(), ThSt::prop(600, 400)) ?> <?php if (null !== ($title = $image->getTitle())): ?> <figcaption><?php $html->out($title) ?></figcaption> <?php endif; ?> </figure>
Damit die ContentItems auch gespeichert werden können, musst du die entsprechenden Datentabellen auf deiner Datenbank eröffnen. Führe dazu die CREATE
Statements aus dem folgenden SQL File aus:
Content Items registrieren
Alle Entitäten müssen in n2n registriert werden. Wir eröffnen dazu var/etc/ci/app.ini
mit folgendem Inhalt:
[orm] entities[] = "ci\bo\CiWysiwyg" entities[] = "ci\bo\CiImage" entities[] = "ci\bo\CiArticle" entities[] = "ci\bo\CiAttachment"
EiSpecs erstellen
Dieser Abschnitt wiederholt EiSpec erstellen aus dem Rocket Quickstart. Wir gehen darum nicht nochmals auf die Details ein. Starte den Hangar von deinem Projekt:
http://localhost/[pfad-zu-deinem-projekt]/hangar/
Zuerst müssen wir unter den Entitäten die EiSpecs für Rocket erstellen. Dies machen wir, indem wir in Hangar die Content Item Klassen unter den Entitäten suchen, Rechts-klicken und Generate EiSpec klicken.
Jetzt ist es wichtig, dass du bei jeder EiSpec folgende Schritte ausführst:
- General: korrekte Labels aussuchen. Beispiel: "Ci Wysiwyg" ist ein schlechtes Label für deine Content Editoren. Wir schlagen "Freitext" vor.
- Fields: Klicke auf "add auto EiFields", um die Eigenschaften der Content Items zu erkennen
- Fields: Jetzt kontrolliere alle Eigenschaften der Felder. Welche Felder müssen obligatorisch (mandatory) sein? Beachte, dass
CiArticle
,CiImage
undCiAttachment
zwingend ein File brauchen. Wo hast du String Felder mit begrenzten Längen? Beim Attachment könntest du die erlaubten Formate begrenzen. - Speichere alles (Save all)
Der Hangar hat dir jetzt var/etc/ci/rocket/specs.json
gespeichert. Du kannst sie mit unseren vergleichen:
Panels registrieren
Wir wollen mit Content Items Seiteninhalte erfassen. Content Items werden in Panels ausgegeben. Bisher haben wir aber noch keine Panels registriert. Für die Anzeige unserer Seiten haben wir app/template/TemplatePageController
erstellt. Um unsere Pannels zu registrieren, kannst du die Annotations-Methode von TemplatePageController
wie folgt anpassen:
private static function _annos(AnnoInit $ai) { $ai->m('startPage', new AnnoPage(), new AnnoPageCiPanels('hero', 'main')); $ai->m('standardPage', new AnnoPage(), new AnnoPageCiPanels('main')); }
Wir fügen einfach eine zweite Annotation AnnoPageCiPanels()
hinzu. Als Parameter geben wir die Namen all unserer Panels mit.
'hero'
so zu konfigurieren, dass nur ein Content Item darin platziert werden kann?Wenn du jetzt ins Rocket gehst und die Startseite oder eine Contentseite bearbeitest, kannst du bei diesen Seiten die Panels mit Content Items befüllen. Damit die Inhalte unserer Panels aber ausgegeben werden, müssen wir die Views anpassen.
Views anpassen
Unsere Seiten werden von app/template/TemplatePageController
ausgegeben. Dieser ruft wiederum app/template/view/startPage.html.php
und app/template/view/standardPage.html.php
auf. Hier müssen wir die Content Items nun auslesen.
app/template/view/startPage.html.php
schaut neu so aus:
<?php use n2n\impl\web\ui\view\html\HtmlView; use n2n\web\ui\view\View; use page\ui\PageHtmlBuilder; $view = HtmlView::view($view); $pageHtml = new PageHtmlBuilder($view); $view->useTemplate('boilerplate.html'); ?> <div class="jumbotron"> <div class="container"> <h1><?php $pageHtml->title() ?></h1> <?php $pageHtml->contentItems('hero') ?> </div> </div> <div class="container"> <?php $pageHtml->contentItems('main') ?> </div>
Das einzige was sich verändert hat, ist dass wir $pageHtml->contentItems()
zweimal eingebaut haben. In app/template/view/standardPage.html.php
ist die Anpassung analog:
<?php use n2n\impl\web\ui\view\html\HtmlView; use n2n\web\ui\view\View; use page\ui\PageHtmlBuilder; $view = HtmlView::view($view); $pageHtml = new PageHtmlBuilder($view); $view->useTemplate('boilerplate.html'); ?> <div class="container"> <h1><?php $pageHtml->title() ?></h1> <?php $pageHtml->contentItems('main') ?> </div>
Hier müssen wir nur einmal die Content Items einbauen. $pageHtml->contentItems()
macht nichts anders, als über die angehängten Content Items zu iterieren und die HTML Ausgaben zusammen zu setzen.
Wenn du soweit bist, kannst du das Page Modul einmal ausführlich testen, indem du den verschiedenen Seiten Inhalte hinzufügst. Ebenfalls ist es natürlich denkbar, dass du eigene Content Items entwickelst und verwendest!
app\qsci
. Jetzt stimmt auch der Stand von qst\controller\QstPageController
und den Views überein.