Die Route für den Controller
Um in Magento 2 einen Controller anzulegen brauchen wir, genau wie in Magento 1.x, eine Route. Definiert wird diese in Magento 2 in der Datei etc/frontend/routes.xml:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="helloworld" frontName="helloworld">
<module name="Tudock_HelloWorld" />
</route>
</router>
</config>
In dieser Datei gibt es folgende Dinge zu beachten:
- router_id für das Frontend ist standard.
- route_id ist der Name unserer Route.
- frontName ist der Pfad zu der Route, dort wird sie später erreichbar sein (<shop>.de/<route>/<controller>/<action>). route_id und frontName sollten identisch sein.
- <module name=““ /> muss den Vendor-Prefix und Namen unseres Moduls beinhalten.
Jetzt wo unsere Route angelegt ist, können wir den Controller erstellen.
Controller und Actions
Anders als in Magento 1.x gibt es keine Klasse für die Controller, die dann Methoden hat, welche ihre Actions repräsentieren. Stattdessen ist jede Action eine Klasse.
Controller sind nur noch durch einen Ordner repräsentiert (und optional durch eine abstrakte Klasse als Basis für jede Action).
Für einen Index Controller unserer helloworld Route brauchen wir also im Ordner Controller einen neuen Ordner Index. Alle Klassen in diesem Ordner sind die Actions unseres Index Controllers.
Für die Index-Action brauchen wir nun nur noch eine Klasse mit dem Dateipfad Controller/Index/Index.php anzulegen. Diese Action wird erreichbar sein unter <shop>.de/helloworld/index/index, wobei die beiden Index-Teile optional sind, genau wie in Magento 1.x.
<?php
namespace Tudock\HelloWorld\Controller\Index;
use \Magento\Framework\App\Action\Action;
class Index extends Action
{
/** @var \Magento\Framework\View\Result\Page */
protected $resultPageFactory;
/**
*
* Hier laden wir die Result\PageFactory.
* Diese wird benutzt um unsere darzustellen (siehe unten).
* Das Ganze geschieht via Dependency Injection, was genau
* das bedeutet und wie DI in Magento 2 funktioniert wird im
* nächsten Kapitel erklärt.
*
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Framework\View\Result\Page $resultPageFactory
*/
public function __construct(\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory) {
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
}
/**
* Benutzt die geladene PageFactory um die Seite zu erzeugen.
* Die PageFactory wird das Layout laden und rendern.
* Das Layout und die Blöcke definieren wir im nächsten Schritt
*
* @return \Magento\Framework\View\Result\PageFactory
*/
public function execute() {
return $this->resultPageFactory->create();
}
}
Jede Action implementiert das Interface \Magento\Framework\App\Action\Action und ist im Namespace <Vendor>\<Modul>\Controller\<ControllerName>. Der Name der Klasse ist gleich dem Namen der Action.
Wie in den Kommentaren beschrieben, nutzt unsere execute-Methode (die ausgeführt wird, wenn die Action aufgerufen wird), die vorher via DependencyInjection geladene PageFactory. Eine Factory erstellt ein Objekt eines bestimmten Typs, in diesem Fall eine Page.
execute soll ein Objekt zurückgeben, das \Magento\Framework\Controller\ResultInterface implementiert. Page ist so ein Objekt.
Mehr über DependencyInjections und Factorys folgt in den nächsten Kapiteln dieser Blogserie.
Alle Klassen, die ResultInterface implementieren, können eine Seite rendern. Im Falle von Page wird das gesamte Layout für die Action geladen und dann gerendert.
Es gibt auch noch andere Klassen, die das ResultInterface implementieren und bspw. erlauben, rohen HTML Code zu rendern oder JSON-formatierte Daten für AJAX-Requests.
Layouts und Blöcke für die neue Action
Unser Controller lädt nun also das Layout für seine Seite und rendert es. Dieses Layout müssen wir jetzt noch definieren.
Wie genau das funktioniert, werde ich im letzten Kapitel der Blogserie erklären. Hier daher jetzt nur der Schnelldurchlauf:
Wir legen eine neue Layout-XML an. Diese muss zum Layout-Handle unserer Action passen, also helloworld_index_index.
view/frontend/layout/helloworld_index_index.xml:
[korrigiert am 24.08.2016, dank an Tobias für den Hinweis]
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template" name="hello-world" template="Tudock_HelloWorld::helloworld.phtml"/>
</referenceContainer>
</body>
</page>
Besonders ist hier im Vergleich zum letzten Kapitel, dass wir keinen eigenen Block benutzen, sondern den einfachen Template-Block, den Magento zur Verfügung stellt, um beliebige Templates zu rendern.
Wenn man einen Block rendert, der nicht im selben Modul liegt, so muss man für template ein Prefix zum Namen des Templates hinzufügen im Format Vendor_Modul::.
Unser Template (view/frontend/templates/helloworld.phtml) beinhaltet schlicht diesen Text:
<p>
<?php echo __('Hello World') ?>!
</p>
Und die dazugehörige Übersetzung sieht so aus:
"Hello World", "Hallo Welt"
Testen
Wir können jetzt die neue Version unseres Moduls in den Shop installieren.
Dafür rufen wir unseren Shop auf und dann die URL /helloworld/index/index/.
Dort sollten wir jetzt den Text „Hallo Welt!“ sehen.
Action verlinken
Aber was bringt uns eine neue Action, wenn niemand unsere tolle neue Seite sehen kann?
Als kleine Übung folgende Aufgabe:
Verlinke unsere neue Action in dem HelloProduct Block, den wir im letzten Teil angelegt haben. „Wie geht es dir?“ soll auf die neue Action verlinken.
Die Lösung gibt es auf Github.
Tipp:
Die Klasse \Magento\Framework\View\Element\AbstractBlock hat eine Methode mit dem Namen getUrl. Sie funktioniert ähnlich wie in Magento 1.x .
Weiter geht es im nächsten Kapitel mit Dependency Injection und der Frage: „Was ist eigentlich mit Mage:: passiert?“
Die weiteren Beiträge der Serie
- Magento 2 Modulentwicklung – Teil 1: Vorbereitung
- Magento 2 Modulentwicklung – Teil 2: Frontend Entwicklung
- Magento 2 Modulentwicklung – Teil 4: Models und Dependency Injection
- Magento 2 Modulentwicklung – Teil 5: Wichtige Objekte
- Magento 2 Modulentwicklung – Teil 6: Resource Models und Install-Scripts
- Magento 2 Modulentwicklung – Teil 7: Observer, Helper und Fazit