Neos Workshop Teil 2 - Ein eigenes Sitepackage bauen

Nachdem wir Neos CMS im ersten Teil des Tutorials installiert und uns mit der Oberfläche vertraut gemacht haben, beginnen wir mit diesem Teil, eine Webseite mit dem System umzusetzen.

Ich liebe es wenn ein Plan funktioniert!

Daniel Lienert
Daniel ist immer auf der Suche nach technologisch innovativen aber dennoch nachhaltig stablilen Lösungen für unsere Kunden.
Lesedauer: ca. 6 Minuten

Im ersten Teil des Neos Workshops haben wir uns bereits eine virtuelle Umgebung für das CMS geschaffen und uns mit der Funktionsweise des Backends vertraut gemacht. Mit diesem Teil wollen wir nun beginnen, ein eigenes Projekt in Neos umzusetzen. Als Beispielprojekt soll uns die Präsenz eines lokalen Weinladens dienen.

Ein neues SitePackage erstellen

Jede neue Seite in Neos startet mit dem Anlegen eines neuen Site Packages. Das Site Package beinhaltet alle Teile, welche das Aussehen und die Grundfunktionen der Seite ausmachen. Um frisch starten zu können, entfernen wir sowohl den Content als auch das Site Package der bereits installierten Demo Seite. Das geht am bequemsten über das Kommandozeilen-Interface von Flow - Flow ist das Applikationsframework hinter Neos.

Dazu verzweigen wir in den Vagrant Ordner auf unserem System, den wir im letzten Workshop angelegt haben ("cd ~/vagrant-neosbox") und starten dort mit "vagrant up" die virtuelle Maschine. Dann loggen wir uns mit "vagrant ssh" auf unserer virtuellen Maschine ein, navigieren zum Projektordner (/var/www) und führen die folgenden Befehle aus:

Anmerkung: Bei den folgenden ./flow Befehlen ist es wichtig, die Gross-  und Kleinschreibung genauestens zu beachten!

./flow site:prune
composer remove neos/demo

./flow kickstart:site WL.WeinLaden weinladen.local
./flow site:import WL.WeinLaden

In der ersten Zeile löschen wir mit site:prune alle Inhalte und Seiten der Demo Seite aus der Datenbank (unter http://http://172.17.28.28/ erhalten Sie nun eine Fehlermeldung; das ist korrekt) . Mit package:delete löschen wir dann das Package der Demo Seite und entfernen es dann auch aus der Liste der per composer installierten Pakete. 
Nun erstellen wir mit kickstart:site unser neues, leeres Site Package welchem wird den Vendornamen WW und den Paketnamen WhiskeyWorld geben. Mit dem site:import in der letzten Zeile importieren wir die root-page welche für das Anzeigen der Seite nötig ist.

Die Flow Kommandozeile

Die Flow Kommandozeile bietet noch jede Menge weitere nützliche Kommandos. Die komplette Liste zeigt der Befehl ./flow help an.
Eine genaue Beschreibung der Befehle, inklusive alle Parameter erhalten Sie mit dem Befehl
./flow help <BefehlName>.

Der Kickstarter legt uns im Verzeichnis Packages/Sites/WL.WeinLaden eine Reihe von Verzeichnissen und Dateien an, deren Bedeutung ich kurz beschreiben möchte.

.
|-- Classes
|-- Configuration
|   `-- NodeTypes.yaml
|-- Resources
|   `-- Private
|       |-- Content
|       |   `-- Sites.xml
|       |-- Templates
|       |   `-- Page
|       |       `-- Default.html
|       `-- Fusion
|           `-- Root.fusion
|-- Tests
|   |-- Functional
|   `-- Unit
`-- composer.json

Werden PHP Klassen für die Umsetzung der Seite benötigt, werden diese unter Classes abgelegt und von dort automatisch geladen. Das Verzeichnis Configuration enthällt bereits eine Datei "NodeTypes.yaml" welche für die Definition eigener Inhaltstypen verwendet werden kann. 
Unter Resources/Private liegen Dateien, welche für das Projekt benötigt werden, aber nicht von aussen zugänglich sein sollen. Unter anderem wurden hier schon eine rudimentäre Template Datei sowie eine Datei für Fusion Code angelegt.

Entwicklungsumgebung vorbereiten

Um komfortabel an unserer Seite entwickeln zu können, ist die Verwendung einer IDE, welche zumindest ein Syntax Highlighting der gängigen Websprachen beherrscht, zu empfehlen. Das kann beispielsweise das leichtgewichtige SublimeText oder das mächtige PHPStorm sein.

Um mit einer IDE an unserer Seite arbeiten zu können, kopieren wir uns die Dateien am besten in einen lokalen Ordner. Dazu wechseln wir in das vagrant Verzeichnis (~/vagrant-neosbox) und führen den folgenden, etwas sperrigen Befehl aus, welcher die Dateien in den Ordner neos-workshop in unserem Home Verzeichnis kopiert:

rsync -avP --rsh="ssh -i "$(vagrant ssh-config | grep IdentityFile | awk  '{print $2}')"" vagrant@172.17.28.28:/var/www/Packages/Sites/ ~/neos-workshop

Änderungen, welche wir im Laufe des Workshops an dem SitePackage vornehmen, sollen am Besten automatisch zurück in die Box kopiert werden. Vagrant bringt dafür eine elegante Lösung mit. Um diese zu nutzen, bearbeiten wir die Datei Vagrantfile in unserem Vagrant Ordner (~/vagrant-neosbox) und fügen die unten markierten Zeilen 5 und 6 hinzu.

Die neuen Zeilen führen dazu, dass Änderungen im Ordner neos-workshop von Vagrant automatisch erkannt werden und per rsync an die richtige Stelle in die Box kopiert werden.

Vagrant.configure("2") do |config|
  config.vm.box = 'punktde/workshop'
  config.vm.box_url = "https://punkt.de/Download/workshop.box"
  config.vm.synced_folder '.', '/vagrant', id: 'vagrant-root', disabled: true
  config.vm.synced_folder "~/neos-workshop/", "/var/www/Packages/Sites/", type: "rsync",
    rsync__exclude: ".git/"
  config.vm.network 'private_network', ip: '172.17.28.28'
  config.ssh.forward_agent = true
  config.vm.provider 'virtualbox' do |vb|
    vb.memory = '4096'
    vb.cpus = '1'
    vb.name = 'workshopbox'
  end
end

Nach der Änderung muss die Box einmal neu gestartet werden. Das geschieht mit dem Befehl:

vagrant reload

Die automatische Synchronisation steht nun bereit und kann mit folgendem Befehl gestartet werden:

vagrant rsync-auto

Erstes Templating mit Fusion und Fluid

Nun kann es richtig los gehen! Im folgenden werden wir die vom Kickstarter erstellten Dateien Schritt für Schritt erweitern, um eine Seite mit Menü Content und Footer Bereich zu erhalten. Das Endergebnis lässt sich immer auch im GitHub Repository zu diesem Workshop nachschauen.

Da wir uns in diesem Workshop hauptsächlich auf die Funktionen von Neos konzentrieren, beschränken wir uns bei den anderen Bausteinen einer Webseite wie HTML, CSS und Javascript auf das Allernötigste. Etwas Farbe tut unserer Seite aber trotzdem gut, daher beginnen wir mit dem Einbinden einer auf dem CSS Framework Bootstrap basierenden CSS Datei.

Alle direkt herunterladbaren Dateien wie CSS oder Javascript Dateien müssen sich bei Neos im Pfad Resources/Public befinden. Wir erstellen innerhalb unseres Site-Packages daher in diesem Pfad die Datei Resources/Public/Styles/Main.css, welche wir mit dem Inhalt aus https://github.com/punktDe/neos-workshop/blob/master/Resources/Public/Styles/Main.css befüllen.

(Das geht am schnellsten mit fetch https://github.com/punktDe/neos-workshop/blob/master/Resources/Public/Styles/Main.css).

Fluid

Fluid ist eine einfache aber mächtige Template Engine, welche eigens für das Application Framework Flow entwickelt worden ist und auch im CMS TYPO3 Verwendung findet. Alle Konstrukte zur Umsetzung von Beispielsweise Schleifen oder Bedingungen sind selbst valides XML-Markup. Mit eigenen ViewHelpern lässt sich die Sprache beliebig erweitern und an die Anforderungen des eigenen Projektes anpassen. Eine Beschreibung aller Sprachkonstrukte findet sich hier.

Zur Einbindung der Datei ist bereits eine Section im HEAD-Bereich der generierten ./Resources/Private/Templates/Page/Default.html vorgesehen. Der Fluid Resource ViewHelper generiert uns den Pfad zu den Dateien unter Resources/Public.


<head>
	<f:section name="stylesheets">
		<link rel="stylesheet" href="{f:uri.resource(path: 'Styles/Main.css', package: 'WL.WeinLaden')}" />
	</f:section>
	<f:section name="headScripts">
	<!-- Put your scripts inclusions for the head here, they will be included in your website by Fusion -->
	</f:section>
</head>

Welche Sections aus der Template Datei gerendert werden, wird in der TypoScript Datei ./Resources/Private/TypoScript/Datei Root.ts2 definiert.
Hier wird auch das Menü mit dem einfachen Konstrukt "menu = Menu" aus dem TypoScript-Objekt Menu instanziiert und in den Variablen menu bereit gestellt. Die Erstellung des Menüs können wir mit diversen Parametern anpassen. In unserem Beispiel benötigen wir weitere CSS Klassen, damit das CSS von Bootstrap Wirkung zeigt. Die Zeile wird also folgendermaßen erweitert:

menu = Menu {
	attributes.class = 'nav navbar-nav pull-right'
}

Viele weitere Parameter des Menüs und seiner Elemente können hiermit angepasst werden. Eine komplette Liste findet sich in der Fusion Referenz.

Als letztes erweitern wir das Markup der Default.html um das Menü und ein Logo für unsere Seite.

<f:section name="body">
    <nav class="navbar navbar-default">
        <div class="container">
            <a class="navbar-brand" href="/">Wein<span>Laden</span></a>
            {parts.menu -> f:format.raw()}
        </div>
    </nav>

	<div class="container">
		{content.main -> f:format.raw()}
	</div>
</f:section>

Ein Footerbereich für alle Seiten

Nun fehlt der Seite noch ein frei gestaltbarer Footer Bereich. Dazu reichen kleine Erweiterungen in der Seitenkonfiguration, im Fusion und dem Template, die im Folgenden Schritt für Schritt erklärt werden. Die genaueren Hintergründe, wie Neos die Daten speichert und in welcher Weise wir darauf zugreifen können, soll aber erst Inhalt des dritten Teils des Workshops sein.

Zunächst legen wir in der NodeTypes.yaml, welche wir im Verzeichnis Configuration finden, mit den folgenden Zeilen einen neuen Bereich mit dem Namen footer an:

'Neos.NodeTypes:Page':
  childNodes:
    'footer':
      type: 'Neos.Neos:ContentCollection'

Damit erhalten alle neu angelegten Seiten einen weiteren Content-Bereich für den Footer. Dieser Bereich muss nun auch allen bereits angelegten Seiten hinzugefügt werden. Dazu verwenden wir den Befehl node:repair des flow Kommandos auf der Console, welcher die bestehenden Seiten an die neue Konfiguration anpasst und den Footer Bereich auch dort anlegt:

./flow node:repair

In der Fusion Datei Root.fusion können wir nun den Footer (Zeile 7-9) ähnlich dem Hauptbereich selektieren und an das Template übergeben ...

content {
// The default content section
	main = PrimaryContent {
		nodePath = 'main'
	}

	footer = PrimaryContent {
		nodePath = 'footer'
	}
}

... und dort im Template "Resources/Private/Templates/Page/Default.html" anzeigen:

<footer>
	<div class="container">
		{content.footer -> f:format.raw()}
	</div>
</footer>

Sollen alle Seiten den gleichen Footer erhalten, reicht es, die obige Zuweisung in Fusion durch die Folgende zu ersetzen. Durch die folgenden Zeilen wird nicht der Footer der jeweils gewählten Seite selektiert und bearbeitet, sondern stets der Footer der Root-Seite. 

footer = ContentCollection {
	nodePath = ${q(site).children('footer').property('_path')}
	collection = ${q(site).children('footer').children()}
}
Ansicht der Weinladen Seite nach unserem Workshop

Somit ist unsere erste Seite mit zwei Inhaltsbereichen und dem Menü fertig und kann mit Inhalten gefüllt werden. Der Stand des Sitepackages nach diesem Teil des Workshops kann auch noch einmal auf dem dazugehörigen Repository auf github nachvollzogen werden.

Teilen:

Weitere Beiträge

Ihre Probleme möchte er haben
Fabian Stein, Geschäftsführer / Digital Consultant bei punkt.de
Arbeiten bei punkt.de