Überblick
Symfony beinhaltet ein Pager Element: das sfPropelPager
Objekt. Es teilt eine Liste von Ergebnissen eines Crtiteria Objektes (der Criteria
Klasse) in eine Sammlung von Seiten zur Anzeige auf. Ausserdem bietet es Zugriffsmethoden auf Seiten und Ergebnissobjekte.
Das sfPropelPager
Objekt
Die sfPropelPager
Klasse benutzt die Propel Abstraktionsschicht, wie im Kapitel Modell beschrieben.
Diese Anleitung zeigt die Nutzung der sfPropelPager
Methoden anhand eines einfachen Beispiels: Eine Liste von Artikeln mit je 10 Einträgen je Seite. Angenommen das Article
Objekt hat folgende Zugriffsmethoden: getPublished()
, getTitle()
, getOverview()
und getContent()
Um eine durchgängige Liste, nur der veröffentlichten Artikel, mittels einer Abfrage über ein 'criteria' Ausdruck zu bekommen, würde man folgendes benutzen:
class articleActions extends sfActions { public function executeList() { ... $c = new Criteria(); $c->add(ArticlePeer::PUBLISHED, true); $articles = ArticlePeer::doSelect($c); $this->articles = $articles; ... } }
Die Variable $articles
, welche vom Template angesprochen werden kann, beinhaltet ein Array von Article
Objekten welche zur Abfrage passen.
Um eine blätterbare Liste zu erhalten, muss man eine etwas andere Vorgehensweise wählen. Die Ergebnisse werden in ein sfPropelPager
Objekt gepackt, anstatt in ein Array:
class articleActions extends sfActions { public function executeList() { ... $c = new Criteria(); $c->add(ArticlePeer::PUBLISHED, true); $pager = new sfPropelPager('Article', 10); $pager->setCriteria($c); $pager->setPage($this->getRequestParameter('page', 1)); $pager->init(); $this->pager = $pager; ... } }
Der Unterschied beginnt nach der Definition der Abfrage (criteria), da die Aktion:
- einen neuen Pager erzeugt, um die
Article
zehnstückweise zu blättern - die Abfrage (criteria) dem Pager zuweist
- die aktuelle Seite auf die angefragte oder auf die erste Seite setzt
- den Pager initialisiert (d.h. die Abfrage im criteria durchführt)
- den Pager unter der
$pager
Variable für das Template verfügbar macht
Im Template listSuccess.php
kann nun auf das sfPropelPager
Objekt zugegriffen werden. Das Objekt kennt die aktuelle Seitennummer und eine Liste aller Seiten. Es hat Methoden um auf die Seiten und auf die in den den Seiten enthaltenen Objekte zuzugreifen. Schauen wir mal wie man dies macht.
Um die Anzahl aller Ergebnisse anzuzeigen benutzt man die getNbResults()
Methode:
<?php echo $pager->getNbResults() ?> results found.<br /> Displaying results <?php echo $pager->getFirstIndice() ?> to <?php echo $pager->getLastIndice() ?>.
Um die Artikel der angeforderten Seite anzuzeigen, benutzt man die getResults()
Methode des pager
Objektes und erhält damit die Objekte der Seite.
<?php foreach ($pager->getResults() as $article): ?> <?php echo link_to($article->getTitle(), 'article/read?id='.$article->getId()) ?> <?php echo $article->getOverview() ?> <?php endforeach ?>
Seitenübergreifende Navigation
Das Pager Objekt weis, ob die maximale Anzahl an Ergebnissen welche auf eine Seite passen (10 in diesem Beispiel) überschritten wird. Dies zeigt es in der haveToPaginate()
Methode.
Um die Seitennavigations-Links am Ende der Liste anzuzeigen, benutzt man die Navigationsmethoden getFirstPage()
, getPreviousPage()
, getNextPage()
and getLastPage()
. Die aktuelle Seite bekommt man mit getPage()
. Alle Methoden geben einen Integer-Wert zurück, den Rang der angefragten Seite.
Um auf eine bestimmte Seite zu zeigen, durchläuft man die Collection von Links, welche man durch den Aufruf der getLinks()
Methode:
<?php if ($pager->haveToPaginate()): ?> <?php echo link_to('«', 'article/list?page='.$pager->getFirstPage()) ?> <?php echo link_to('<', 'article/list?page='.$pager->getPreviousPage()) ?> <?php $links = $pager->getLinks(); foreach ($links as $page): ?> <?php echo ($page == $pager->getPage()) ? $page : link_to($page, 'article/list?page='.$page) ?> <?php if ($page != $pager->getCurrentMaxLink()): ?> - <?php endif ?> <?php endforeach ?> <?php echo link_to('>', 'article/list?page='.$pager->getNextPage()) ?> <?php echo link_to('»', 'article/list?page='.$pager->getLastPage()) ?> <?php endif ?>
Dies führt zu einer Ausgabe, ähnlich der folgenden:
Um eine unmittelbare Navigation zum vorhergehenden oder nachfolgenden Artikel zu erhalten, ohne zurück zur blätterbaren Liste zu gehen, brauch man einen Cursor.
tip
Der oben stehende Code wird durch das sfPagerNavigation
Plugin automatisiert. Auf seiner Beschreibungsseite gibt es weitere Informationen zur Installation und Benutzung.
Navigation zwischen den Objekten
Seitenweise Navigation der Liste ist einfach, aber möglicherweise möchte der Benutzer nicht zurück zur Liste gehen um Objekt für Objekt durch zu gehen. Die cursor
Eigenschaft des sfPropelPager
kann den Offset des aktuellen Objektes aufnehmen.
Dies erlaubt eine Artikelweise Navigation im readSuccess.php
Template. Zuerst wird der Code des listSuccess.php
Templates etwas angepasst:
<?php $cursor = $pager->getFirstIndice(); foreach ($pager->getResults() as $article): ?> <?php echo link_to($article->getTitle(), 'article/read?cursor='.$cursor) ?> <?php echo $article->getOverview() ?> <?php ++$cursor; endforeach ?>
Die read
Aktion muss wissen wie sie mit einem cursor
Parameter umgehen muss:
class articleActions extends sfActions { public function executeRead() { ... if ($this->getRequestParameter('cursor')) { $article = $pager->getObjectByCursor($this->getRequestParameter('cursor')); } else if ($this->getRequestParameter('id')) { $article = ArticlePeer::retrieveByPK($this->getRequestParameter('id')); } // Error $this->forward404Unless($article); } }
Die getObjectByCursor($cursor)
Methode setzt den Cursor an eine angegebene Position und gibt das Objekt an genau dieser Position zurück.
Man kann den Cursor mit der setCursor($cursor)
Methode auch setzen, ohne das entsprechende Objekt zurück zu geben. Ist der Cursor erst mal gesetzt, kann man das Objekt an der akutellen Position (getCurrent()
) holen, eben so wie das vorhergehende (getPrevious()
) und das nachfolgende (getNext()
).
Das bedeutet, dass die read
Aktion mit geringen Anpassungen, die benötigten Informationen für eine Artikelweise Navigation an das Template übergeben kann.
class articleActions extends sfActions { public function executeRead() { ... if ($this->getRequestParameter('cursor')) { $pager->setCursor($this->getRequestParameter('cursor')); $previous_article = $pager->getPrevious(); $article = $pager->getCurrent(); $next_article = $pager->getNext(); } else if ($this->getRequestParameter('id')) { $article = ArticlePeer::retrieveByPK($this->getRequestParameter('id')); } // Error $this->forward404Unless($article); } }
note
Die getPrevious()
und getNext()
Methoden geben null
zurück, wenn es kein vorhergehendes oder nachfolgendes Objekt gibt.
Das readSuccess.php
Template kann wie folgt aussehen:
<h1><?php echo $article->getTitle() ?></h1> <p class="overview"><?php echo $article->getOverview() ?></p> <div class="content"> <?php echo $article->getContent() ?> </div> < <?php echo link_to_if($previous_article, $previous_article->getTitle(), 'article/read?id='.$previous_article->getId()) ?> - > <?php echo link_to_if($next_article, $next_article->getTitle(), 'article/read?id='.$next_article->getId()) ?>
Ändern der Sortierreihenfolge
Da das sfPropelPager
Objekt von einem Criteria
Objekt abhängt, wird das Ändern der Sortierreihenfolge einfach. Es erfolgt durch das Hinzufügen eines Sortierkriterums zum Criteria
Objekt bevor dieses dem Pager Objekt zugewiesen wird.
Zum Beispiel kann man die Auswahl der zu sortierenden Spalte zum Navigationsinterface hinzufügen:
class articleActions extends sfActions { public function executeList() { ... $c = new Criteria(); $c->add(ArticlePeer::PUBLISHED, true); if ($this->getRequestParameter('sort')) { $c->addAscendingOrderByColumn(ArticlePeer::translateFieldName($this->getRequestParameter('sort'), BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME)); } else { // sorted by date by default $c->addAscendingOrderByColumn(ArticlePeer::UPDATED_AT); } $pager = new sfPropelPager('Article', 10); $pager->setCriteria($c); $pager->init(); $this->pager = $pager; ... } }
Folgendes wird zum listSuccess.php
Template hinzugefügt:
Sortieren nach : <?php echo link_to('Title', 'article/list?sort=title') ?> - <?php echo link_to('Id', 'article/list?sort=Id') ?>
Ändern der Anzahl von Elementen je Seite
Die setMaxPerPage($max)
Methode ändert die Anzahl der Elemente die auf einer Seite angezeigt werden, ohne dass der Pager neu initialisiert werden muss (kein erneuter Aufruf von init()
notwendig). Wenn man den Wert 0
als Parameter übergibt, zeigt der Pager alle Elemente auf einer einzelnen Seite an.
class articleActions extends sfActions { public function executeList() { ... $c = new Criteria(); $c->add(ArticlePeer::PUBLISHED, true); $pager = new sfPropelPager('Article', 10); $pager->setCriteria($c); if ($this->getRequestParameter('maxperpage')) { $pager->setMaxPerPage($this->getRequestParameter('maxperpage')); } $pager->init(); $this->pager = $pager; ... } }
Nun kann man folgendes zum listSuccess.php
Template hinzufügen:
Anzeigen : <?php echo link_to('10', 'article/list?maxperpage=10') ?> - <?php echo link_to('20', 'article/list?maxperpage=20') ?> Elemente je Seite
Ändern der Select Methode
Wenn man die Geschwindigkeit einer Action optimieren muss, welche auf einem sfPropelPager
beruht, dann kann es sein, dass man den Pager dazu bewegen will einen doSelectJoinXXX()
statt einem einfachen doSelect()
. Dies wird einfach durch die setPeerMethod()
des sfPropelPager
Objektes erreicht:
$pager->setPeerMethod('doSelectJoinUser');
Zu beachten ist, dass der Pager die doSelect()
Abfrage dann durchführt, wenn eine Seite angezeigt wird. Die erste Abfrage (ausgelöst durch $pager->init()
) macht lediglich einen doCount
, und man kann auch diese Methode anpassen durch Aufruf von:
$pager->setPeerCountMethod('doCountJoinUser');
Weitere Informationen im Pager speichern
Manchmal ist es notwendig bestimmte Context Informationen in einem Pager Objekt zu speichern. Aus diesem Grund behandelt die sfPropelPager
Klasse Parameter auf die übliche Weise:
$pager->setParameter('foo', 'bar'); if ($pager->hasParameter('foo')) { $pager->getParameter('foo'); $pager->getParameterHolder()->removeParameter('foo'); } $pager->getParameterHolder()->clearParameters();
Diese Parameter werden nie direkt durch den Pager benutzt.
Mehr zu Benutzerparametern erfährt man im Kapitel 2.
This work is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.