ProcessWire - Hooks: Unterschied zwischen den Versionen
| Zeile 6: | Zeile 6: | ||
Beginnt eine Funktion in der Klasse mit '''3 Underscores wird Sie automatisch Hookable'''. | Beginnt eine Funktion in der Klasse mit '''3 Underscores wird Sie automatisch Hookable'''. | ||
| + | Das heißt also Hooks bestehen aus der hookable Funktion und den Hooks selbst die an dieser "einhaken". | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
| Zeile 18: | Zeile 19: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | + | '''Methoden die über Hooks erzeugt wurden sind selber Hookable''' | |
| + | Beispiele aus dem Core sind: Page::render(), Page::viewable() and Page::editable() | ||
| + | |||
| + | '''Es gibt in ProcessWire hookable Methoden die nichts tun sondern nur da sind um sich einzuhaken''' | ||
| + | Z.B. Pages::saveReady (wird aufgerufen wenn eine Seite gleich gespeichert wird aber noch nicht ist, oder Page::saved (nach dem Speichern). Es gibt an dieser Stelle auch noch Page::save, hier muss man entscheiden ob man before oder after wählt. Bei den anderen beiden ist es egal, da sie immer vorher oder nach dem Speichern aufgerufen werden. | ||
| + | |||
| + | |||
| + | === Das können Hooks === | ||
* Argumente für die Funktion holen oder modifizieren bevor sie verarbeitet werden (beforeHook) | * Argumente für die Funktion holen oder modifizieren bevor sie verarbeitet werden (beforeHook) | ||
* Den Rückgabewert der Funktion holen und/oder modifizieren nachdem die Argumente verarbeitet wurden (afterHook) | * Den Rückgabewert der Funktion holen und/oder modifizieren nachdem die Argumente verarbeitet wurden (afterHook) | ||
| Zeile 24: | Zeile 32: | ||
* Eine Methode in die Klasse einschleusen. Diese ist dann über $object->method() verfügbar. | * Eine Methode in die Klasse einschleusen. Diese ist dann über $object->method() verfügbar. | ||
* Eine Eigenschaft in die Klasse einschleusen. Diese ist dann über $object->property verfügbar. Das funktioniert '''nicht bei allen Hooks'''. | * Eine Eigenschaft in die Klasse einschleusen. Diese ist dann über $object->property verfügbar. Das funktioniert '''nicht bei allen Hooks'''. | ||
| + | |||
| + | === So definiert man Hooks == | ||
| + | ==== Welchen soll ich nehmen? ==== | ||
| + | Zunächst mal gibt es drei Funktionen mit denen seine eigenen Funktionen einklinkt: | ||
| + | addHookBefore(...) //do s.th. before hookable Method is running - i.e. modify arguments | ||
| + | addHookAfter(...) // do s.th. after hookable Method is running - i.e. modify return value | ||
| + | addHook(...) // inject a new method or property in to the class where the hookable Method is defined | ||
| + | Am Namen sieht man schon wo das ganze dann passiert. Bei addHook spielt es keine Rolle, denn diesen nutzt man um neue Methoden und Eigenschaften in die Klasse zu schleusen. | ||
| + | |||
| + | Zuerst mußt du schauen ob du in der selben (oder einer geerbten) Klasse bist. Dementsprechend greifst du mit $this-> oder wire()-> darauf zu. | ||
| + | $this->addHookBefore(…); // hook in the same class | ||
| + | wire()->addHookAfter(...); // hook from another class | ||
| + | |||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Zeile 41: | Zeile 62: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | |||
| − | |||
== Wo setzt man hooks am Besten ein == | == Wo setzt man hooks am Besten ein == | ||
Version vom 26. November 2020, 13:02 Uhr
Wie funktionieren Hooks
https://processwire.com/docs/modules/hooks/
Hier in Kürze die wichtigsten Infos.
Alle Klassen die von Wire abstammen können Hookable Methoden implementieren..
Beginnt eine Funktion in der Klasse mit 3 Underscores wird Sie automatisch Hookable. Das heißt also Hooks bestehen aus der hookable Funktion und den Hooks selbst die an dieser "einhaken".
public function ___hookableMethod($arg1, $arg2) {
// this method is hookable
}
Aufgerufen wird die Funktion ohne die Underscores
'''
$this->hookableMethod('a', 'b');
Methoden die über Hooks erzeugt wurden sind selber Hookable Beispiele aus dem Core sind: Page::render(), Page::viewable() and Page::editable()
Es gibt in ProcessWire hookable Methoden die nichts tun sondern nur da sind um sich einzuhaken Z.B. Pages::saveReady (wird aufgerufen wenn eine Seite gleich gespeichert wird aber noch nicht ist, oder Page::saved (nach dem Speichern). Es gibt an dieser Stelle auch noch Page::save, hier muss man entscheiden ob man before oder after wählt. Bei den anderen beiden ist es egal, da sie immer vorher oder nach dem Speichern aufgerufen werden.
Das können Hooks
- Argumente für die Funktion holen oder modifizieren bevor sie verarbeitet werden (beforeHook)
- Den Rückgabewert der Funktion holen und/oder modifizieren nachdem die Argumente verarbeitet wurden (afterHook)
- Die Methode komplett ersetzen (Variante des beforeHook)
- Eine Methode in die Klasse einschleusen. Diese ist dann über $object->method() verfügbar.
- Eine Eigenschaft in die Klasse einschleusen. Diese ist dann über $object->property verfügbar. Das funktioniert nicht bei allen Hooks.
= So definiert man Hooks
Welchen soll ich nehmen?
Zunächst mal gibt es drei Funktionen mit denen seine eigenen Funktionen einklinkt:
addHookBefore(...) //do s.th. before hookable Method is running - i.e. modify arguments addHookAfter(...) // do s.th. after hookable Method is running - i.e. modify return value addHook(...) // inject a new method or property in to the class where the hookable Method is defined
Am Namen sieht man schon wo das ganze dann passiert. Bei addHook spielt es keine Rolle, denn diesen nutzt man um neue Methoden und Eigenschaften in die Klasse zu schleusen.
Zuerst mußt du schauen ob du in der selben (oder einer geerbten) Klasse bist. Dementsprechend greifst du mit $this-> oder wire()-> darauf zu.
$this->addHookBefore(…); // hook in the same class wire()->addHookAfter(...); // hook from another class
Wo setzt man hooks am Besten ein
Es gibt einige Standard Dateien die für solche Zwecke geeignet sind:
/site/init.php
PW Boot -> Module mit autoload -> init.php
This file is included during ProcessWire's boot initialization, immediately after autoload modules have been loaded and had their init() methods called. Anything you do in here will behave the same as an init() method on a module. When this file is called, the current $page has not yet been determined. This is an excellent place to attach hooks that don't need to know anything about the current page.
/site/ready.php
API geladen und ready -> $page bereit aber noch nicht gerendert
This file is included immediately after the API is fully ready. It behaves the same as a ready() method in an autoload module. The current $page has been determined, but not yet rendered. This is an excellent place to attach hooks that may need to know something about the current page. It's also an excellent place to include additional classes or libraries that will be used on all pages in your site.
/site/finished.php
Seite gerendert
This file is included when ProcessWire has finished rendering and delivering a page, and is in the process of shutting down. It is called immediately before the API is disengaged, so you can still access any API variable and update $session values as needed. Admittedly, this is probably not the place you would put hooks, but it is an ideal place to perform your own shutdown, should your application call for it.
Beispiele für Hooks
Basic Starter Hook
Erster Schritt zum ausprobieren
// i.e. in ready.php
$wire->addHookAfter('Pages::saved', function(HookEvent $event) {
$page = $event->arguments(0);
bd($page); // tracy debugger output
});
// more specific
$wire->addHookAfter('Pages::added(template=basic-page)', function(HookEvent $event) {
$page = $event->arguments(0);
bd($page);
});
Feld manipulieren
Beim Speichern einer Seite ein Feld anpassen
$pages->addHookAfter('saveReady', function(HookEvent $event) {
$page = $event->arguments(0);
// If the page has the relevant template...
if($page->template == 'oe') {
// make title uppercase
$page->name = strtoupper($page->name);
}
});
Seiten im Backend sortieren
/*sort clients of key account manager by title in backend*/
$pages->addHookAfter('saveReady', function(HookEvent $event) {
$page = $event->arguments(0);
// If the page has the relevant template...
if($page->template == 'key_account_manager') {
// Sort the Page Reference field by title
$page->pr_kam_clients->sort('title') ;
}
});
Externe Klasse verfügbar machen
/site/ready.php
<?php
$pages->addHookAfter('saved', function($event) {
$page = $event->object;
if($page->template == 'product') {
// update other related pages when 'product' page is saved
}
});
if($page->template != 'admin') {
// include an external helper class...
require('./classes/ProductCart.php');
// ...and establish it as a new $cart API variable, and
// populate it with products saved in the user's session:
$wire->wire('cart', new ProductCart($session->productsInCart));
}
There is also a /site/finished.php that obtains the products from the $cart and saves them back to the session, ready for the next request:
/site/finished.php
<?php
if($page->template != 'admin') {
$session->productsInCart = $cart->getArray();
}
Custom Hook Methode
Beispiel aus der ready.php
/** @var ProcessWire $wire */
/**
* Example of a custom hook method
*
* This hook adds a “numPosts” method to pages using template “category”.
* The return value is the quantity of posts in category.
*
* Usage:
* ~~~~~
* $numPosts = $page->numPosts(); // returns integer
* numPosts = $page->numPosts(true); // returns string like "5 posts"
* ~~~~~
*
*/
$wire->addHook('Page(template=category)::numPosts', function($event) {
/** @var Page $page */
$page = $event->object;
// only category pages have numPosts
if($page->template != 'category') return;
// find number of posts
$numPosts = $event->pages->count("template=blog-post, categories=$page");
if($event->arguments(0) === true) {
// if true argument was specified, format it as a "5 posts" type string
$numPosts = sprintf(_n('%d post', '%d posts', $numPosts), $numPosts);
}
$event->return = $numPosts;
});
Rendering von Formularen anpassen
Manchmal rendern Module Formulare im Frontend, aber die Styles passen nicht ganz zum eigenen Style. Man kann aber vor dem Rendern des Formulars einhaken und noch ein paar Klassen nachschieben bevor es gerendert wird. Die Hookfunktion kann man in ready.php unterbringen. Also kurz bevor ProcessWire mit dem Rendern der Seite loslegt.
ready.php
/**
* add uikit classes to checkout forms
*/
$this->addHookBefore('InputfieldForm::render', function(HookEvent $event) {
if(page()->template->name == 'checkout'){
// Get the object the event occurred on
$InputfieldForm = $event->object;
foreach($InputfieldForm as $f){
bd(get_class($f),'Inputfield Hook->field');
switch (get_class($f)) {
case 'ProcessWire\InputfieldEmail':
case 'ProcessWire\InputfieldText':
$f->addClass('uk-input');
break;
case 'ProcessWire\InputfieldTextarea':
$f->addClass('uk-textarea');
break;
case 'ProcessWire\InputfieldRadios':
$f->addClass('uk-radio');
break;
case 'ProcessWire\InputfieldCheckbox':
$f->addClass('uk-checkbox');
break;
case 'ProcessWire\InputfieldSubmit':
$f->addClass('uk-button uk-button-primary');
break;
}
}
return $InputfieldForm; // send back manipulated object
}
});