Schwierigkeitsgrad: leicht
zu implementieren in: Model, View, Controller
Zunächst einmal sei erwähnt, dass es sicher auch andere Möglichkeiten gibt, diese Aufgabe zu lösen, doch ich denke diese Lösung ist einfach nachzuvollziehen und auch einfach selbst zu implementieren. Ihr solltet Euch mit dem Paginator ein wenig auskennen, das MVC Prinzip verstanden haben und ein wenig selber mitdenken können (aber sonst hättet Ihr auch den falschen Job, richtig?)
Fangen wir an mit dem Model, in das ich ein paar einfache Methoden eingebaut habe, um die entsprechenden Filteroptionen zu hinterlegen (sowas kann man selbstverständlich auch im Controller machen…). Wir gehen davon aus, dass unser zu paginierendes Model ‘Customer’ heißt.
im Model:
public function getLimits() {
return array(
5 => __('5', true),
10 => __('10', true),
15 => __('15', true),
20 => __('20', true),
50 => __('50', true)
);
}
public function getSortBies() {
return array(
'lastname' => __('Lastname', true),
'firstname' => __('Firstname', true),
'office' => __('Office', true),
'email' => __('Email', true)
);
}
public function getOrders() {
return array(
'ASC' => __('Ascending', true),
'DESC' => __('Descending', true)
);
}
Bis hierhin eigentlich noch nichts spannendes. Hier werden lediglich die Arrays definiert, deren Inhalte wir nachher in den DropDowns der Filterliste wiedersehen werden. Wie gesagt, man kann das auch im Controller definieren, aber das würde dem Prinzip von ‘Fat Models, Skinny Controllers’ widersprechen, was als Best-Practice bei Cake (und anderen MVC-Frameworks natürlich auch!) gilt…
Als nächstes nehmen wir uns das View vor, um dem User die entsprechenden Filtermöglichkeiten anzubieten. Hier setzt ihr einfach da wo es euch paßt folgendes ein:
im View:
<div class="filter_container">
<?php echo $form->create('Customer', array('action' => 'index'));?>
<fieldset>
<legend><?php __('Filter Options');?></legend>
<?php
echo $form->input('Customer.limit', array(
'selected' => $session->read('Customer.limit')
));
echo $form->input('Customer.sortby', array(
'selected' => $session->read('Customer.sortby')
));
echo $form->input('Customer.order', array(
'selected' => $session->read('Customer.order')
));
?>
</fieldset>
<?php echo $form->end('Submit');?>
</div>
An sich ist auch das hier alles wie immer bei Cake. Auffallend ist hier der zugewiesene ’selected’ Wert, der gesetzt wird sollte für das Model Customer der entsprechende Filterschlüssel bereits in der Session hinterlegt sein. Die Form wird an die index-action gesendet, welche dann die übergebenen Parameter auswertet und den Paginator entsprechend verändern wird. Hierzu gleich mehr im Controller-Teil.
Ich habe mich für den Weg über die Sessions entschieden, da ich kein Freund von unnötigen GET-Parametern bin und die Session für persönliche Einstellungen genutzt werden darf. Wer Lust hat, kann das Ganze auch als Cookie hinterlegen, oder sogar als eine Art permanent-setting in der Datenbank speichern. Der Kreativität sind dabei keine Grenzen gesetzt!
Ist das View erledigt, folgt noch der Controller. Hier werden wir übergebene Werte in die Session schreiben, die Variablen des Paginators zuweisen und dem View unsere im Model hinterlegten Drop-Down Arrays zur Verfügung stellen. Zunächst aber hier einmal des gesamte Code:
im Controller:
public function index() {
if(!empty($this->data['Customer']['limit'])) {
$this->Session->write('Customer.limit', $this->data['Customer']['limit']);
}
if(!empty($this->data['Customer']['order'])) {
$this->Session->write('Customer.order', $this->data['Customer']['order']);
}
if(!empty($this->data['Customer']['sortby'])) {
$this->Session->write('Customer.sortby', $this->data['Customer']['sortby']);
}
$limit = $this->Session->read('Customer.limit');
$order = $this->Session->read('Customer.order');
$sortby = $this->Session->read('Customer.sortby');
if(empty($limit)) {
$limit = 10;
}
if(empty($order)) {
$order = 'ASC';
}
if(empty($sortby)) {
$sortby = 'lastname';
}
$this->paginate['Customer'] = array(
'contain' => false,
'conditions' => array(
'Customer.deleted' => 0,
),
'limit' => $limit,
'order' => array(
'Customer.'.$sortby => $order
)
);
$limits = $this->Customer->getLimits();
$orders = $this->Customer->getOrders();
$sortbies = $this->Customer->getSortbies();
$professors = $this->paginate('Customer');
$this->set(compact('customers', 'limits', 'orders', 'sortbies'));
}
Was passiert hier also?
Wir checken ob uns das Filter-Formular Daten gesendet hat, sprich ob der Benutzer Filter eingestellt und dann abgeschickt hat. Wenn es Daten gibt, dann werden sie in die Session geschrieben. Danach werden die Session-Daten wieder ausgelesen, und danach geprüft ob wirklich Daten vorhanden sind. Benutzt man die Action zum ersten Mal nach dem Login, gibt es ja noch keine Daten in der Session, also muss man dafür sorgen, dass Standardwerte übernommen werden. Das geschieht im folgenden Teil.
Danach wird der Paginator customized angelegt. Dieser Weg ist besonders dann von Vorteil, wenn man in einem Controller mehrmals verschiedenen “verseiten” muss. Man hat somit einfach eine klarere und bessere Eingriffsmöglichkeit, als wenn man dies am Anfang des Controller über var $paginate tuen würde.
Als letztes werden die Variablen für die DropDowns aus dem Model gelesen, und dem View über $this->set() zur Verfügung gestellt.
Das wars auch schon. Ihr habt jetzt eine Paginierung mit Filtermöglichkeiten, die sich während der gesamten Session speichert und dem Benutzer so eine bessere Möglichkeit der Eingrenzung und Filterung bietet.
Da ich absichtlich das Model mittels Punktnotation in der Session abgelegt habe, kann für jedes Model in jedem Controller und in jeder Action eine eigene Filterung angeboten werden. Ganz coole Leute bringen sowas wahrscheinlich in einer gekapselten Component unter, was ich evtl. in den nächsten Wochen nachholen werde.
Viel Spaß beim PAGINIEREN