Δημιουργία προσαρμοσμένων φίλτρων
Τα φίλτρα είναι ισχυρά εργαλεία για τη μορφοποίηση και
τροποποίηση δεδομένων απευθείας στα πρότυπα Latte. Προσφέρουν καθαρή
σύνταξη χρησιμοποιώντας το σύμβολο της κάθετης γραμμής (|
) για
τη μετατροπή μεταβλητών ή αποτελεσμάτων εκφράσεων στην επιθυμητή
μορφή εξόδου.
Τι είναι τα φίλτρα;
Τα φίλτρα στο Latte είναι ουσιαστικά συναρτήσεις PHP σχεδιασμένες
ειδικά για τη μετατροπή μιας τιμής εισόδου σε μια τιμή εξόδου.
Εφαρμόζονται χρησιμοποιώντας τη σημειογραφία με την κάθετη γραμμή
(|
) εντός των εκφράσεων προτύπου ({...}
).
Ευκολία: Τα φίλτρα σας επιτρέπουν να ενσωματώσετε κοινές εργασίες μορφοποίησης (όπως μορφοποίηση ημερομηνιών, αλλαγή πεζών-κεφαλαίων, περικοπή) ή χειρισμό δεδομένων σε επαναχρησιμοποιήσιμες μονάδες. Αντί να επαναλαμβάνετε πολύπλοκο κώδικα PHP στα πρότυπά σας, μπορείτε απλά να εφαρμόσετε ένα φίλτρο:
{* Αντί για πολύπλοκο PHP για περικοπή: *}
{$article->text|truncate:100}
{* Αντί για κώδικα μορφοποίησης ημερομηνίας: *}
{$event->startTime|date:'Y-m-d H:i'}
{* Εφαρμογή πολλαπλών μετασχηματισμών: *}
{$product->name|lower|capitalize}
Αναγνωσιμότητα: Η χρήση φίλτρων καθιστά τα πρότυπα πιο καθαρά και περισσότερο εστιασμένα στην παρουσίαση, καθώς η λογική μετασχηματισμού μεταφέρεται στον ορισμό του φίλτρου.
Ευαισθησία στο περιβάλλον: Ένα βασικό πλεονέκτημα των φίλτρων στο Latte είναι η ικανότητά τους να είναι ευαίσθητα στο περιβάλλον. Αυτό σημαίνει ότι ένα φίλτρο μπορεί να αναγνωρίσει τον τύπο του περιεχομένου με το οποίο εργάζεται (HTML, JavaScript, απλό κείμενο κ.λπ.) και να εφαρμόσει την αντίστοιχη λογική ή το escaping, το οποίο είναι ζωτικής σημασίας για την ασφάλεια και την ορθότητα, ειδικά κατά τη δημιουργία HTML.
Ενσωμάτωση με τη λογική της εφαρμογής: Όπως και οι προσαρμοσμένες συναρτήσεις, το PHP callable πίσω από ένα φίλτρο μπορεί να είναι ένα closure, μια στατική μέθοδος ή μια μέθοδος στιγμιότυπου. Αυτό επιτρέπει στα φίλτρα να έχουν πρόσβαση σε υπηρεσίες ή δεδομένα της εφαρμογής, εάν χρειάζεται, αν και ο κύριος σκοπός τους παραμένει η μετατροπή της τιμής εισόδου.
Το Latte παρέχει από προεπιλογή ένα πλούσιο σύνολο τυπικών φίλτρων. Τα προσαρμοσμένα φίλτρα σας επιτρέπουν να επεκτείνετε αυτό το σύνολο με μορφοποιήσεις και μετασχηματισμούς ειδικούς για το έργο σας.
Αν χρειάζεται να εκτελέσετε λογική βασισμένη σε πολλαπλές εισόδους ή δεν έχετε μια κύρια τιμή για μετασχηματισμό, είναι πιθανώς πιο κατάλληλο να χρησιμοποιήσετε μια προσαρμοσμένη συνάρτηση. Αν χρειάζεται να δημιουργήσετε πολύπλοκο markup ή να ελέγξετε τη ροή του προτύπου, εξετάστε ένα προσαρμοσμένο tag.
Δημιουργία και καταχώριση φίλτρων
Υπάρχουν διάφοροι τρόποι για να ορίσετε και να καταχωρήσετε προσαρμοσμένα φίλτρα στο Latte.
Άμεση καταχώριση μέσω addFilter()
Ο απλούστερος τρόπος για να προσθέσετε ένα φίλτρο είναι η χρήση της
μεθόδου addFilter()
απευθείας στο αντικείμενο Latte\Engine
.
Καθορίζετε το όνομα του φίλτρου (όπως θα χρησιμοποιηθεί στο πρότυπο)
και το αντίστοιχο PHP callable.
$latte = new Latte\Engine;
// Απλό φίλτρο χωρίς ορίσματα
$latte->addFilter('initial', fn(string $s): string => mb_substr($s, 0, 1) . '.');
// Φίλτρο με προαιρετικό όρισμα
$latte->addFilter('shortify', function (string $s, int $len = 10): string {
return mb_substr($s, 0, $len);
});
// Φίλτρο που επεξεργάζεται έναν πίνακα
$latte->addFilter('sum', fn(array $numbers): int|float => array_sum($numbers));
Χρήση στο πρότυπο:
{$name|initial} {* Εκτυπώνει 'J.' αν το $name είναι 'John' *}
{$description|shortify} {* Χρησιμοποιεί την προεπιλεγμένη διάρκεια 10 *}
{$description|shortify:50} {* Χρησιμοποιεί τη διάρκεια 50 *}
{$prices|sum} {* Εκτυπώνει το άθροισμα των στοιχείων στον πίνακα $prices *}
Πέρασμα ορισμάτων:
Η τιμή στα αριστερά της κάθετης γραμμής (|
) περνιέται πάντα ως
το πρώτο όρισμα στη συνάρτηση του φίλτρου. Οποιεσδήποτε παράμετροι
αναφέρονται μετά την άνω και κάτω τελεία (:
) στο πρότυπο περνούν
ως τα επόμενα ορίσματα.
{$text|shortify:30}
// Καλεί τη συνάρτηση PHP shortify($text, 30)
Καταχώριση μέσω επέκτασης
Για καλύτερη οργάνωση, ειδικά κατά τη δημιουργία επαναχρησιμοποιήσιμων συνόλων φίλτρων ή την κοινή χρήση τους ως πακέτα, ο συνιστώμενος τρόπος είναι η καταχώρισή τους εντός μιας επέκτασης Latte:
namespace App\Latte;
use Latte\Extension;
class MyLatteExtension extends Extension
{
public function getFilters(): array
{
return [
'initial' => $this->initial(...),
'shortify' => $this->shortify(...),
];
}
public function initial(string $s): string
{
return mb_substr($s, 0, 1) . '.';
}
public function shortify(string $s, int $len = 10): string
{
return mb_substr($s, 0, $len);
}
}
// Καταχώριση
$latte = new Latte\Engine;
$latte->addExtension(new App\Latte\MyLatteExtension);
Αυτή η προσέγγιση διατηρεί τη λογική του φίλτρου σας ενσωματωμένη και την καταχώριση απλή.
Χρήση φορτωτή φίλτρων
Το Latte επιτρέπει την καταχώριση ενός φορτωτή φίλτρων χρησιμοποιώντας
το addFilterLoader()
. Πρόκειται για ένα μοναδικό callable που το Latte ζητά για
οποιοδήποτε άγνωστο όνομα φίλτρου κατά τη μεταγλώττιση. Ο φορτωτής
επιστρέφει το PHP callable του φίλτρου ή null
.
$latte = new Latte\Engine;
// Ο φορτωτής μπορεί να δημιουργεί/ανακτά δυναμικά callable φίλτρα
$latte->addFilterLoader(function (string $name): ?callable {
if ($name === 'myLazyFilter') {
// Φανταστείτε εδώ μια απαιτητική αρχικοποίηση...
$service = get_some_expensive_service();
return fn($value) => $service->process($value);
}
return null;
});
Αυτή η μέθοδος προοριζόταν κυρίως για την τεμπέλικη φόρτωση (lazy loading) φίλτρων με πολύ απαιτητική αρχικοποίηση. Ωστόσο, οι σύγχρονες πρακτικές dependency injection συνήθως διαχειρίζονται τις lazy services πιο αποτελεσματικά.
Οι φορτωτές φίλτρων προσθέτουν πολυπλοκότητα και γενικά δεν
συνιστώνται υπέρ της άμεσης καταχώρισης με addFilter()
ή εντός μιας
επέκτασης με getFilters()
. Χρησιμοποιήστε φορτωτές μόνο αν έχετε
σοβαρό, συγκεκριμένο λόγο που σχετίζεται με προβλήματα απόδοσης κατά
την αρχικοποίηση φίλτρων που δεν μπορούν να αντιμετωπιστούν
διαφορετικά.
Φίλτρα που χρησιμοποιούν μια κλάση με attributes
Ένας άλλος κομψός τρόπος για να ορίσετε φίλτρα είναι η χρήση μεθόδων
στην κλάση παραμέτρων του
προτύπου σας. Απλά προσθέστε το attribute #[Latte\Attributes\TemplateFilter]
στη
μέθοδο.
use Latte\Attributes\TemplateFilter;
class TemplateParameters
{
public function __construct(
public string $description,
// άλλες παράμετροι...
) {}
#[TemplateFilter]
public function shortify(string $s, int $len = 10): string
{
return mb_substr($s, 0, $len);
}
}
// Πέρασμα του αντικειμένου στο πρότυπο
$params = new TemplateParameters(description: '...');
$latte->render('template.latte', $params);
Το Latte αναγνωρίζει και καταχωρεί αυτόματα τις μεθόδους που
επισημαίνονται με αυτό το attribute, όταν το αντικείμενο TemplateParameters
περνιέται στο πρότυπο. Το όνομα του φίλτρου στο πρότυπο θα είναι το
ίδιο με το όνομα της μεθόδου (shortify
σε αυτήν την περίπτωση).
{* Χρήση του φίλτρου που ορίζεται στην κλάση παραμέτρων *}
{$description|shortify:50}
Φίλτρα περιβάλλοντος
Μερικές φορές ένα φίλτρο χρειάζεται περισσότερες πληροφορίες από την απλή τιμή εισόδου. Μπορεί να χρειάζεται να γνωρίζει τον τύπο περιεχομένου της συμβολοσειράς με την οποία εργάζεται (π.χ. HTML, JavaScript, απλό κείμενο) ή ακόμα και να τον τροποποιήσει. Αυτή είναι η κατάσταση για τα φίλτρα περιβάλλοντος.
Ένα φίλτρο περιβάλλοντος ορίζεται όπως ένα κανονικό φίλτρο, αλλά η
πρώτη του παράμετρος πρέπει να είναι type-hinted ως Latte\Runtime\FilterInfo
.
Το Latte αναγνωρίζει αυτόματα αυτή την υπογραφή και περνά ένα
αντικείμενο FilterInfo
κατά την κλήση του φίλτρου. Οι επόμενες
παράμετροι λαμβάνουν τα ορίσματα του φίλτρου ως συνήθως.
use Latte\Runtime\FilterInfo;
use Latte\ContentType;
$latte->addFilter('money', function (FilterInfo $info, float $amount): string {
// 1. Ελέγξτε τον τύπο περιεχομένου εισόδου (προαιρετικό, αλλά συνιστάται)
// Επιτρέψτε null (μεταβλητή είσοδος) ή απλό κείμενο. Απορρίψτε αν εφαρμόζεται σε HTML κ.λπ.
if (!in_array($info->contentType, [null, ContentType::Text], true)) {
$actualType = $info->contentType ?? 'mixed';
throw new \RuntimeException(
"Το φίλτρο |money χρησιμοποιήθηκε σε μη συμβατό τύπο περιεχομένου $actualType. Αναμενόταν κείμενο ή null."
);
}
// 2. Εκτελέστε τον μετασχηματισμό
$formatted = number_format($amount, 2, '.', ',') . ' EUR';
$htmlOutput = '<i>' . htmlspecialchars($formatted) . '</i>'; // Διασφαλίστε σωστό escaping!
// 3. Δηλώστε τον τύπο περιεχομένου εξόδου
$info->contentType = ContentType::Html;
// 4. Επιστρέψτε το αποτέλεσμα
return $htmlOutput;
});
Το $info->contentType
είναι μια σταθερά συμβολοσειράς από το
Latte\ContentType
(π.χ. ContentType::Html
, ContentType::Text
,
ContentType::JavaScript
, κ.λπ.) ή null
, εάν το φίλτρο εφαρμόζεται σε μια
μεταβλητή ({$var|filter}
). Μπορείτε να διαβάσετε αυτή την τιμή για
να ελέγξετε το περιβάλλον εισόδου, και να γράψετε σε αυτήν για να
δηλώσετε τον τύπο του περιβάλλοντος εξόδου.
Ορίζοντας τον τύπο περιεχομένου σε HTML, λέτε στο Latte ότι η συμβολοσειρά που επιστρέφεται από το φίλτρο σας είναι ασφαλές HTML. Το Latte τότε δεν θα εφαρμόσει το προεπιλεγμένο αυτόματο escaping σε αυτό το αποτέλεσμα. Αυτό είναι ζωτικής σημασίας εάν το φίλτρο σας παράγει markup HTML.
Εάν το φίλτρο σας παράγει HTML, είστε υπεύθυνοι για το σωστό
escaping οποιωνδήποτε δεδομένων εισόδου που χρησιμοποιούνται σε αυτό το
HTML (όπως στην περίπτωση της κλήσης htmlspecialchars($formatted)
παραπάνω). Η
παράλειψη μπορεί να δημιουργήσει ευπάθειες XSS. Εάν το φίλτρο σας
επιστρέφει μόνο απλό κείμενο, δεν χρειάζεται να ορίσετε το
$info->contentType
.
Φίλτρα σε μπλοκ
Όλα τα φίλτρα που εφαρμόζονται σε μπλοκ πρέπει να είναι ευαίσθητα στο περιβάλλον. Αυτό συμβαίνει επειδή το περιεχόμενο του μπλοκ έχει έναν καθορισμένο τύπο περιεχομένου (συνήθως HTML), τον οποίο το φίλτρο πρέπει να γνωρίζει.
{block heading|money}1000{/block}
{* Το φίλτρο 'money' λαμβάνει το '1000' ως το δεύτερο όρισμα
και το $info->contentType θα είναι ContentType::Html *}
Τα φίλτρα περιβάλλοντος παρέχουν ισχυρό έλεγχο στο πώς επεξεργάζονται τα δεδομένα βάσει του περιβάλλοντός τους, επιτρέπουν προηγμένες λειτουργίες και διασφαλίζουν τη σωστή συμπεριφορά του escaping, ειδικά κατά τη δημιουργία περιεχομένου HTML.