Eigene Seite per Extension erstellen
Oft will man mit einer Extension das Forum um eine eigene Seite erweitern. In diesem Tutorial wird gezeigt wie man eine eigene einfache HTML Seite mit Hilfe eines Controllers erstellt.
In dem Beispiel wird foo\bar als Extension Name verwendet, das sollte man durch den Namen seiner Extension austauschen.
Controller anlegen
Für den PHP Code seiner Seite braucht man einen Controller in den sämtliche PHP Befehle die auf der Seite ausgeführt werden kommen. Auch wenn man kein eigenes PHP ausführen will benötigt man
ein Grundgerüst das die Seite ausgibt. Ein Controller kann mehrere Modi haben und so gleich mehrere Seiten in einer Datei ausgeben.
Für jeden Modus wird eine Methode mit dem Namen des Modus benötigt die als Return $this->helper->render()
aufruft. Eine minimale Methode die einfach Variablen an das Template sendet
sieht folgendermaßen aus:
public function handle() { $this->template->assign_vars(array( 'FOOBAR' => 'foobar', 'DATE' => date(DATE_RFC822), 'U_LINK' => $this->helper->route('foo_bar_variable', array('id' => 'meine_id')), )); return $this->helper->render('my_page.html', $this->user->lang['MY_PAGE']); }
Mit $template->assign_vars(array());
werden die Variablen FOOBAR, DATE und U_LINK an das Template gesendet. Hier wird
einmal der String "foobar", einmal das Datum nach RFC822 und ein Link zu einer Route an das Template gesendet. Natürlich kann man hier je nach Bedarf jede beliebige PHP Variable vom Typ String
verwenden und an das Template ausgeben.
Am Ende wird mit return $this->helper->render('my_page.html', $this->user->lang['MY_PAGE']);
angegeben welche Template Datei verwendet werden soll (hier my_page.html)
und wie der Titel im Browser lauten soll, dazu wird in dem Beispiel die Sprachvariable MY_PAGE
verwendet.
Seite mit Variabler URL
Oft will man eine Variable wie eine ID oder ähnliches an seine Seite per URL übergeben. Dazu bauen wir in den Controller eine zweite Methode die später einen Teil der URL als Variable benutzt.
public function variable($id) { $this->user->add_lang_ext('foo/bar', 'common'); $this->template->assign_vars(array( 'ID' => $id, )); return $this->helper->render('my_variable.html', $this->user->lang['MY_PAGE']); }
Der Aufbau der Methode ist im Prinzip der selbe wie bei der ersten Methode, nur dass hier die Variable $id
als Argument übergeben wird. In $id
ist später der
Inhalt der per URL übergeben wird enthalten und kann nach belieben im PHP Code verwendet werden. Da es sich dabei um eine beliebige Benutzer Eingabe handelt sollte man den Inhalt noch prüfen um
sicher zu stellen dass hier keine bösartigen Werte übergeben werden. Da hier gezeigte Beispiel wäre anfällig für XSS da der Benutzer in $id
auch HTML oder Javascript übergeben könnte.
Da das aber nur als Beispiel wie man Variablen aus der URL nutzt dienen soll, will ich darauf aber hier nicht näher eingehen. Die Variable wird nun einer Template Variable zugewiesen um sie später
im Template auszugeben zu können.
Auch hier wird zusätzlich noch die Sprachdatei geladen und im Unterschied zur ersten Methode my_variable.html
als Template Datei benutzt.
Jetzt braucht man noch einen Konstruktor in dem man die benötigten Objekte und Variablen lädt.
public function __construct(\phpbb\controller\helper $helper, \phpbb\template\template $template, \phpbb\user $user) { $this->helper = $helper; $this->template = $template; $this->user = $user; }
Da wir in unseren Methoden die Objekte $helper
, $template
und $user
verwenden fragen wir im Konstruktor die drei Objekte ab und übergeben sie an lokalen
Variablen innerhalb der Klasse. Wenn weitere Objekte oder Variablen benötigt werden muss der Konstruktor entsprechend erweitert werden.
Wenn man Sprach-Variablen in der Datei verwenden möchte kann man mit $this->user->add_lang_ext('foo/bar', 'common');
eine Sprachdatei laden. Dabei wird vorne der Name der
Extension (foo/bar) und hinten der Name der Datei ohne Endung angegeben (common).
Zum Schluss muss man noch den Namespace anpassen namespace foo\bar\controller;
<?php /** * * @package phpBB Extension - bar * @copyright (c) 2015 foo (https://example.com) * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 * */ namespace foo\bar\controller; class main { /** @var \phpbb\controller\helper */ protected $helper; /** @var \phpbb\template\template */ protected $template; /** @var \phpbb\user */ protected $user; /** * Constructor * * @param \phpbb\controller\helper $helper Controller helper object * @param \phpbb\template\template $template Template object * @param \phpbb\user $user User object */ public function __construct(\phpbb\controller\helper $helper, \phpbb\template\template $template, \phpbb\user $user) { $this->helper = $helper; $this->template = $template; $this->user = $user; } /** * Controller for route /my_page/ * * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object */ public function handle() { $this->user->add_lang_ext('foo/bar', 'common'); $this->template->assign_vars(array( 'FOOBAR' => 'foobar', 'DATE' => date(DATE_RFC822), 'U_LINK' => $this->helper->route('foo_bar_variable', array('id' => 'meine_id')), )); return $this->helper->render('my_page.html', $this->user->lang['MY_PAGE']); } /** * Controller for route /my_variable/$id * * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object */ public function variable($id) { $this->user->add_lang_ext('foo/bar', 'common'); $this->template->assign_vars(array( 'ID' => $id, )); return $this->helper->render('my_variable.html', $this->user->lang['MY_PAGE']); } }
Da die Datei main.php heißt muss auch die Klasse main heißen (class main
), wenn man die Datei anders nennt muss auch die Klasse entsprechend umbenannt werden.
Services an den Controller übergeben
Damit die Objekte $helper
$template
und $user
die der Controller verwendet verfügbar sind müssen sie an den Konstruktor übergeben werden.
Dazu wird die Datei config/services.yml benötigt. Der Inhalt der Datei sieht folgendermaßen aus:
services: foo.bar.main: class: foo\bar\controller\main arguments: - @controller.helper - @template - @user
Oben wird der Name der Extension und der Datei durch Punkte getrennt angegeben, unter class:
muss man den Namespace der Controller Klasse angeben. Jetzt kann man
unter arguments:
alle benötigten Objekte und Variablen auflisten.
Wichtig ist das man in der Datei richtig einrückt und dabei nur Leerzeichen und keine Tabs verwendet. Eine Liste der verfügbaren Services gibt es
hier.
Das Routing
Damit die Seite aufgerufen werden kann muss noch eine Route angelegt werden. In der Route wird festgelegt welche Methode für eine bestimmte URL geladen werden soll. Routen werden in der Datei config/routing.yml inerhalb der Extension angelegt. Wenn man mehrere Routen benötigt kann man sie einfach untereinander schreiben.
Die komplette Datei config/routing.ymlfoo_bar_index: pattern: /my_page/ defaults: { _controller: foo.bar.main:handle } foo_bar_variable: pattern: /variable/{id} defaults: { _controller: foo.bar.main:variable }
In der ersten Zeile wird der Name der Route festgelegt über den später mit $this->helper->route('foo_bar_index', array())
in anderen Dateien auf die Route zugegriffen
werden kann. In der zweiten Zeile wird die URL angegeben über die man die Route aufrufen möchte. In der dritten Zeile wird dann noch angegeben welche Methode über die Route aufgerufen werden soll.
Dabei ist foo.bar
der Name der Extension, main
der Name der Datei und handle
der Name der Methode.
Darunter gibt es eine zweite Route die eine Variable übergibt und auf Seitenaufrufe wie variabke/1 hört. Der Aufbau ist im Prinzip der selbe wie bei der ersten Route,
nur das eben noch die Variable in der URL angegeben wird. Der Name der Variable muss hier gleich wie das Argument in der entsprechenden Methode sein, in dem Fall
also {id}
da wir in unserem Controler auch $id
verwenden (public function variable($id)
). Um die zweite Route in einer PHP Datei aufzurufen kann
man $this->helper->route('foo_bar_variable', array('id' => 'meine_id'))
verwenden. In dem zweiten Parameter wird also ein Array mit dem Namen und dem Wert der Variable übergeben.
Wenn man noch weitere Routen in einer Datei behandeln möchte kann man einfach eine weitere Methode in den Controller einfügen und sie über eine zusätzliche Route ansprechen.
Die Template Datei
Damit die Seite funktioniert wird noch die im Controller angegebene Template Datei (my_page.html) benötigt. Die Datei legt man einfach in styles/prosilver/template an und
füllt sie mit seinem HTML Code. In der Datei können jetzt auch die Template Variablen die man im Controller ausgibt verwendet werden. Variablen aus Sprachdateien kann man
verwenden indem man ein L_
voranstellt.
<!-- INCLUDE overall_header.html --> <strong>{L_FOOBAR}</strong> <a href="{U_LINK}">{FOOBAR}</a><br> <strong>{L_DATE}</strong> {DATE}<br> <!-- INCLUDE overall_footer.html -->
Auch für den zweiten Controller wird eine Template Datei benötigt in der die an das Template zugewiesene Variable ausgegeben wird.
Die komplette Datei styles/prosilver/template/my_variable.html<!-- INCLUDE overall_header.html --> <strong>{L_MY_VARIABLE}</strong> {ID} <!-- INCLUDE overall_footer.html -->
Die Sprachdatei
Damit die Sprach-Variablen gefüllt werden braucht man noch eine Sprachdatei die man innerhalb seiner Extension im Ordner language/de anlegt. Der Dateiname muss so wie im Controller angegeben lauten, hier also common.php
Die komplette Datei language/de/common.php<?php /** * * @package phpBB Extension - bar * @copyright (c) 2015 foo (https://example.com) * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 * */ if (!defined('IN_PHPBB')) { exit; } if (empty($lang) || !is_array($lang)) { $lang = array(); } // DEVELOPERS PLEASE NOTE // // All language files should use UTF-8 as their encoding and the files must not contain a BOM. // // Placeholders can now contain order information, e.g. instead of // 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows // translators to re-order the output of data while ensuring it remains correct // // You do not need this where single placeholders are used, e.g. 'Message %d' is fine // equally where a string contains only two placeholders which are used to wrap text // in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine // // Some characters you may want to copy&paste: // ’ » “ ” … // $lang = array_merge($lang, array( 'FOOBAR' => 'Foo Bar', 'DATE' => 'Datum', 'MY_PAGE' => 'Meine Seite', 'MY_VARIABLE' => 'Meine Variable', ));
Eigene CSS oder JS Datei einbinden
Oft will man für seine erstellte Seite ein eigenes CSS oder JavaScript einbinden, das geht am besten über ein Template Event. Aber zu erst muss
man seine Datei anlegen, für eine CSS Datei legt man unter /styles/prosilver/theme/style.css seine CSS Datei an und füllt sie mit dem
gewünschten CSS Code.
Danach legt man unter /styles/prosilver/template/event/overall_header_head_append.html ein Template Event an um die CSS Datei einzubinden.
Das Event fügt HTML Code in den Head jeder Seite ein und eignet sich deshalb perfekt für das einbinden von CSS Dateien. In die Datei schreibt man dann:
<!-- INCLUDECSS @foo_bar/style.css -->
Mit INCLUDECSS
gibt man an das man eine CSS Datei einbinden möchte, mit @foo_bar
gibt man den Namen der Extension an, am Ende
muss dann nur noch der Dateiname der CSS Datei stehen.
Die Datei wird jetzt allerdings auf allen Seiten und nicht nur innerhalb der Extension eingebunden. Wenn man möchte, dass die Datei nur auf Seiten die zur Extension gehören eingebunden wird muss man dazu eine Template Variable definieren die angibt ob man sich innerhalb der Extension befindet oder nicht. Dazu fügt man folgenden Code in die Controller Klasse die für die jeweilige Seite zuständig ist ein:
$this->template->assign_vars(array( 'S_IN_FOOBAR' => true, ));
Falls man mehrere Seiten über einen Controller laufen lässt und das CSS auf jeder Seite einbinden möchte muss man die Template Variable auch in jeder
Controller Klasse ausgeben oder alternativ den Code in den Konstroktor (unter __construct
) des Controllers einfügen. Wenn man schon
einen Block hat in dem man Variablen an das Template übergibt kann man den natürlich auch einfach erweitern. Dadurch wird die Template
Variable S_IN_FOOBAR
auf true
gesetzt. Wie man die Template Variable nennt ist eigentlich egal so lange man nichts
verwendet was schon von phpBB verwendet wird. Solche Switch Variablen sollte man immer mit S_
beginnen lassen damit klar ist dass es sich
hier um einen Switch handelt.
Jetzt muss man im Template Event wo die CSS Datei eingebunden wird nur noch prüfen ob die Variable gesetzt ist oder nicht, dazu ändert man
in /styles/prosilver/template/event/overall_header_head_append.html einfach den Code in:
<!-- IF S_IN_FOOBAR --> <!-- INCLUDECSS @foo_bar/style.css --> <!-- ENDIF -->
So wird die CSS Datei nur noch dann eingebunden wenn sie auch wirklich benötigt wird, das verhindert dass viele Dateien eingebunden werden wenn man viele Extensions installiert hat. Außerdem sinkt so die Change das man mit mehreren CSS Dateien sich gegenseitig irgendwas überschreibt.
Mit einer JS Datei geht das genau so, nur das man hier statt INCLUDECSS
eben INCLUDEJS
verwenden muss.
Jetzt kann man nachdem man die Extension installiert hat unter /my_page/ seine eigene Seite aufrufen und dort auf den Link zur zweiten Seite mit der Variable klicken, wenn man die Variable in der URL verändert sieht man das sich auch die Ausgabe auf der Seite ändert. Das ganze sieht natürlich noch nicht wirklich schön aus und muss nach Bedarf angepasst werden.
Wenn man einen Link zu seiner Seite in die Navigation des Forums einfügen möchte kann man sich das Tutorial anschauen.