Práce se seznamy dat - Jet\DataListing
Jet DataList je sada tříd velice usnadňující tvorbu seznamů data. Umožňuje tyto funkce:
- Propojení s ORM Jet DataModel
- Stránkování
- Definice sloupců a jejich chování.
- Vytváření libovolných filtrů.
- Stav seznamu (nastavení filtrů a tak dále) je v URL. Je tedy možné snadno posílat vyfiltrovaný seznam dat mezi uživateli.
- Exporty dat
- Hromadné operace nad vyfiltrovanými seznamy dat
- Procházení detailu položek pomocí tlačítek "předchozí" a "další".
Princip fungování
Pokud jste to ještě neudělali, tak se prosím koukněte do administrace ukázkové aplikace a vyzkoušejte si třeba prohlížeč událostí. To je dobrý reprezentativní příklad práce se seznamem.
Je vidět že:
- Nad samotným gridem s výpisem seznamu je formulář s různými filtry
- Formulář filtrů samozřejmě využívá systém formulářů pro definici, validaci i vykreslení.
- Formulář filtrů se odesílá jako POST, zachytává se, validuje a následně je sestavena URL s GET parametry, které finálně definují aktuální nastavení filtru.
- V URL nejsou pouze GET parametry filtru, ale rovněž čísla stránky a taktéž indikace řazení (podle jakého sloupce a v jakém směru se má seznam řadit)
- Tedy URL plně definuje aktuální nastavení seznamu a jakmile jí otevře jiný uživatel, dostane stejný seznam (pokud se data mezi tím nezmění - samozřejmě).
- Pod filtrem je data grid - tedy UI prvek pro jehož vykreslení a základní obsluhu je využit systém UI a jeho prvku UI_dataGrid.
- Automaticky se předpokládá že s daty se operuje pomocí DataModel a je využíván i stránkovač.
- Data je možné exportovat.
Je zřejmé, že Jet\DataListing je ve skutečnosti integrační prostředek, který využívá ostatní prvky platformy Jet a usnadňuje a sjednocuje tvorbu takovýchto rozhraní pro práci se seznamy. Tedy dále se budeme soustředit právě na onu integrační funkci. Více o práci s formuláři, s DataModel a UI_dataGrid se dozvíte v příslušných kapitolách.
Vytvoření seznamu
Třída Jet\DataListing je abstraktní třída a má řadu abstraktních metod, které je nutné implementovat.
Každý konkrétní seznam bude reprezentováni vlastní třídou, která jej definuje a která tedy musí od třídy Jet\DataListing dědit.
Ukažme si rovnou jednu zcela konkrétní třídu z ukázkové aplikace a to právě seznam událostí z aplikačního modulu EventViewer.Admin:
namespace JetApplicationModule\EventViewer\Admin;
use Jet\DataListing;
use Jet\DataModel_Fetch_Instances;
use Jet\MVC_View;
use JetApplication\Logger_Admin_Event as Event;
class Listing extends DataListing {
protected MVC_View $column_view;
protected MVC_View $filter_view;
public function __construct( MVC_View $column_view, MVC_View $filter_view )
{
$this->column_view = $column_view;
$this->filter_view = $filter_view;
$this->addColumn( new Listing_Column_ID() );
$this->addColumn( new Listing_Column_DateTime() );
$this->addColumn( new Listing_Column_EventClass() );
$this->addColumn( new Listing_Column_Event() );
$this->addColumn( new Listing_Column_EventMessage() );
$this->addColumn( new Listing_Column_ContextObjectId() );
$this->addColumn( new Listing_Column_ContextObjectName() );
$this->addColumn( new Listing_Column_UserId() );
$this->addColumn( new Listing_Column_UserName() );
$this->setDefaultSort( '-id' );
$this->addFilter( new Listing_Filter_Search() );
$this->addFilter( new Listing_Filter_EventClass() );
$this->addFilter( new Listing_Filter_Event() );
$this->addFilter( new Listing_Filter_DateTime() );
$this->addFilter( new Listing_Filter_User() );
$this->addFilter( new Listing_Filter_ContextObject() );
$this->addExport( new Listing_Export_CSV() );
}
protected function getItemList(): DataModel_Fetch_Instances
{
return Event::getList();
}
protected function getIdList(): array
{
$ids = Event::fetchIDs( $this->getFilterWhere() );
$ids->getQuery()->setOrderBy( $this->getQueryOrderBy() );
return $ids->toArray();
}
public function itemGetter( int|string $id ): mixed
{
return Event::get( $id );
}
public function getFilterView(): MVC_View
{
return $this->filter_view;
}
public function getColumnView(): MVC_View
{
return $this->column_view;
}
public function getItemURI( int $item_id ) : string
{
$this->setParam('id', $item_id );
$URI = $this->getURI();
$this->unsetParam('id');
return $URI;
}
}
... a tím je seznam definován.
Definice sloupců
Každý datový sloupeček je reprezentován vlastní třídou, která musí dědit od abstraktní třídy Jet\DataListing_Column. Definici každého sloupečku tedy určí samostatná třída, která má široké možnosti jak chování sloupce ovlivnit. A to nejen ovlivnit jeho titulek, možnosti řazení, ale například i to jak bude sloupec exportován v hromadném exportu. Samozřejmě je možné sloupce skrývat, či měnit jejich pořadí. Stačí pro to implementovat potřebné UI.
Rovněž platí, že každý sloupeček má svůj view skript pro zobrazení dat.
Více se dozvíte v kapitole o sloupečcích.
Definice filtrů
Totéž platí pro filtry. Každý filtr je reprezentován vlastní třídou, která dědí od abstraktní třídy Jet\DataListing_Filter. Každá třída filtru řídí logiku daného filtru, generuje filtrační formulářová pole, zachycuje GET parametry a sestavuje filtrační dotaz pro ORM.
I zde doporučuji nastudovat kapitolu věnovanou filtrům.
Definice exportů
A ani exporty nejsou výjimkou. Každý export je reprezentován vlastní třídou, která dědí od abstraktní třídy Jet\DataListing_Export.
Export však nemá žádné předpřipravené view. Implementace UI je na vás. Ovšem tvorba exportů je velice snadná. DataListing připraví data a implementace exportu je vlastně o pouhém převedení dat do požadovaného datového formátu. Existuje již předpřipravený export Jet\DataListing_Export_CSV.
Také exportům je věnována samostatná kapitola, kde se dozvíte víc.
Definice hromadných operací
Hromadné operace jsou operace, které je možné provést naráz nad vyfiltrovaným seznamem dat (například smazat všechny vyfiltrované položky).
Princip je stále stejný. Každá operace je reprezentován vlastní třídou, která dědí od abstraktní třídy Jet\DataListing_Operation.
A pochopitelně i operacím je věnována příslušná kapitola.
Použití seznamu v kontroleru
Opět se budeme držet našeho ukázkového prohlížeče událostí a ukážeme si příslušné metody kontroleru daného modulu:
protected function getListing() : Listing
{
if(!$this->listing) {
$column_view = new MVC_View( $this->view->getScriptsDir().'list/column/' );
$column_view->setController( $this );
$filter_view = new MVC_View( $this->view->getScriptsDir().'list/filter/' );
$filter_view->setController( $this );
$this->listing = new Listing(
column_view: $column_view,
filter_view: $filter_view
);
}
return $this->listing;
}
public function listing_Action(): void
{
$listing = $this->getListing();
$listing->handle();
$this->view->setVar( 'listing', $listing );
$this->output( 'list' );
}
Metoda getListing slouží jako továrna pro vytvoření instance seznamu. V tomto případě je nutné do seznamu vložit závislosti na view, tedy inicializované view.
Instance seznamu figuruje v kontroleru jako singleton, protože tuto instanci je možné použít pro více věcí než pouhé procházení dat, jak si ukážeme za chvíli.
Metoda listing_Action je již ukázka konkrétní akce kontroleru jejíž účelem je právě zobrazit seznam dat. Akce nemusí dělat nic jiného než získat instanci seznamu, zavolat metodu $listing->handle(); která zabezpečí obsluhu celé logiky elementu a následně předat instanci seznamu do view.
Použití ve view
Zobrazení seznamu, včetně jeho filtrů a operací, je snadné, jak se můžete sami přesvědčit v ukázkové aplikaci, například ve view skriptu ~/application/Modules/EventViewer/Admin/views/listing.phtml.
Důležité je ve view získat instanci filtračního formuláře (pokud seznam filtry obsahuje) a UI elementu dataGrid:
namespace JetApplicationModule\EventViewer\Admin;
use Jet\MVC_View;
/**
* @var MVC_View $this
* @var Listing $listing
*/
$listing = $this->getRaw('listing');
$grid = $listing->getGrid();
$filter_form = $listing->getFilterForm();
Zobrazení filtrů se pak provádí takto:
<?=$filter_form->start()?>
<div>
<?=$listing->filter(Listing_Filter_Search::KEY)->renderForm()?>
</div>
<div>
<?=$listing->filter(Listing_Filter_EventClass::KEY)->renderForm()?>
</div>
<div>
<?=$listing->filter(Listing_Filter_Event::KEY)->renderForm()?>
</div>
<?=$filter_form->end()?>
Připomeňme si, že každý filtr má svůj view skript. Je tak zabezpečena přehlednost. Tímto voláním je příslušný view skript vygenerován a výstup umístěn na patřičnou pozici.
Zobrazení samotného data gridu je pak již velice jednoduché:
<div>
<?=$grid->render();?>
</div>
I zde platí, že každý datový sloupeček má svůj view skript. Ale samozřejmě je možné dále ovlivnit podobu a chování sloupců. Například takto:
$grid->getColumn( Listing_Column_ID::KEY )->addCustomCssStyle( 'width:120px;' );
Použití pro procházení položek - další / předchozí
V ukázkové aplikaci jste si v prohlížeči událostí možná všimli, že události je možné procházet na detailu události pomocí tlačítek "další" a "předchozí".
Zde je příslušný kód kontroleru, který se postará o získání URI předchozí či následující položky seznamu relativních k aktuálně otevřené položce:
if(($prev_item_id = $listing->getPrevItemId( $event->getId() ))) {
$this->view->setVar( 'prev_item_url', $listing->getItemURI( $prev_item_id ) );
}
if(($next_item_id = $listing->getNextItemId( $event->getId() ))) {
$this->view->setVar( 'next_item_url', $listing->getItemURI( $next_item_id ) );
}
Ve view pak už stačí pouze tyto URI použít:
$prev_item_url = $this->getRaw('prev_item_url');
$next_item_url = $this->getRaw('next_item_url');
?>
<div>
<?=UI::button_goBack()->setUrl( $this->getString( 'list_url' ))?>
<?php if($prev_item_url): ?>
<?=UI::button('')->setIcon('chevron-left')->setUrl($prev_item_url)->setClass(UI_button::CLASS_INFO)?>
<?php endif; ?>
<?php if($next_item_url): ?>
<?=UI::button('')->setIcon('chevron-right')->setUrl($next_item_url)->setClass(UI_button::CLASS_INFO)?>
<?php endif; ?>
</div>
Třída Jet\DataListing
Abstraktní metody, které je nutné implementovat
Metoda | Význam |
---|---|
protected getItemList( ) : DataModel_Fetch_Instances |
Vrátí seznam položek prostřednictvím ORM DataModel. Metoda nemusí stastavovat žádné filtry, ani řazení. Vše provede DataListing. Příklad:
protected function getItemList(): DataModel_Fetch_Instances
|
protected getIdList( ) : array |
Metoda určená pro získání ID zobrazených položek. Používá se zejména pro hromadné operace. Na rozdíl od getItemList je zde získání seznamu ID plně záležitostí implementace metody. Příklad:
protected function getIdList(): array
|
public getFilterView( ) : MVC_View |
Seznam musí poskytovat již plně inicializovanou instanci view určenou ke generování filtrů. V praxi se řeší nejčastěji vložením závislostí pomocí konstruktoru při vytváření instance seznamu. |
public getColumnView( ) : MVC_View |
Seznam musí poskytovat již plně inicializovanou instanci view určenou ke generování datových buněk. V praxi se řeší nejčastěji vložením závislostí pomocí konstruktoru při vytváření instance seznamu. |
public itemGetter( int|string $id ) : mixed |
Pro účel exportování dat je nutné implementovat metodu, která na základě ID vrátí konkrétní položku. Příklad:
public function itemGetter( int|string $id ): mixed
|
Práce se sloupci
Metoda | Význam |
---|---|
public getColumns( ) : DataListing_Column[] |
Vrátí seznam všech definovaných sloupců. |
public addColumn( DataListing_Column $column ) : void |
Přidá definici sloupce. |
public columnExists( string $column_key ) : bool |
Indikuje zda daný sloupec existuje. |
public column( string $column_key ) : DataListing_Column |
Vrátí konkrétní sloupec. |
public getVisibleColumns( ) : DataListing_Column[] |
Vrátí seznam sloupců, které jsou aktuálně nastaveny jako viditelné. |
public getNotVisibleColumns( ) : DataListing_Column[] |
Vrátí seznam sloupců, které jsou aktuálně nastaveny jako neviditelné. |
Práce s exporty
Metoda | Význam |
---|---|
public getExports( ) : DataListing_Export[] |
Vrátí seznam všech definovaných exportů. |
public addExport( DataListing_Export $export ) : void |
Přidá definici exportu. |
public exportExists( string $key ) : bool |
Indikuje zda daný export existuje. |
public export( string $key ) : DataListing_Export |
Vrátí definici konkrétního exportu. |
public getExportTypes( ) : array |
Vrátí seznam známých exportů v podobě pole, kde klíč odpovídá klíči exportu a hodnota titulku exportu. |
public getExportLimit( ) : int |
Vrátí omezení počtu položek exportu. Pokud neexistuje omezení, pak je vrácena hodnota -1. |
public setExportLimit( int $export_limit ) : void |
Nastavuje omezení počtu položek exportu. |
Práce s filtry
Metoda | Význam |
---|---|
public getFilters( ) : DataListing_Filter[] |
Vrátí seznam všech definovaných filtrů. |
public addFilter( DataListing_Filter $filter ) : void |
Přidá definici filtru. |
public filterExists( string $filter_key ) : bool |
Indikuje zda daný filtr existuje. |
public filter( string $key ) : DataListing_Filter |
Vrátí konkrétní filtr. |
protected catchFilterParams( ) : void |
Vnitřní metoda. Zabezpečuje zachycení parametrů filtrů. |
public getFilterForm( ) : Form |
Vygeneruje a vrátí filtrační formulář. |
protected catchFilterForm( ) : void |
Vnitřní metoda. Zabezpečuje zachycení filtračního formuláře. |
public addFilterWhere( array $where ) : void |
Metoda pomocí které jednotlivé filtry nastavují vygenerovaný WHERE pro ORM. |
protected getDefaultFilterWhere( ) : array |
Pomocí přetížení této metody je možné generovat výchozí část WHERE pro ORM. |
public getFilterWhere( ) : array |
Vrátí vygenerovaný WHERE pro ORM. |
Práce s hromadnými operacemi
Metoda | Význam |
---|---|
public getOperations( ) : DataListing_Operation[] |
Vrátí seznam definovaných operací. |
public addOperation( DataListing_Operation $operation ) : void |
Přidá definici operace. |
public operationExists( string $operation ) : bool |
Indikuje zda daná operace existuje. |
public operation( string $operation ) : DataListing_Operation |
Vrátí instanci konkrétní operace. |
Generátor UI_dataGrid
Metoda | Význam |
---|---|
public getGrid( ) : UI_dataGrid |
Vrátí plně inicializovaný element UI_dataGrid. |
protected createGridColumns( ) : void |
Vnitřní metoda. Definice sloupců převádí na definice sloupců pro UI_dataGrid. |
Stránkování dat
Metoda | Význam |
---|---|
public createPaginator( ) : Data_Paginator |
Vytvoří, plně inicializuje a vrátí stránkovač. |
protected setPageNo( int $page_no ) : void |
Metoda vnitřní logiky. Nastavuje číslo aktuální stránky seznamu. |
protected setItemsPerPage( int $items_per_page ) : void |
Metoda vnitřní logiky. Nastavuje počet položek na stránku seznamu. |
protected catchPaginationParams( ) : void |
Metoda vnitřní logiky. Zachytává z požadavku aktuální číslo stránky. |
protected getPageNo( ) : int |
Metoda vnitřní logiky. Vrací aktuální číslo stránky. |
protected getItemsPerPage( ) : int |
Metoda vnitřní logiky. Vrací aktuální počet položek na stránku seznamu. |
protected getPaginatorURLCreator( ) : callable |
Metoda vnitřní logiky. Vrací vytvářeč URL stránek pro stránkovač. |
Metody pro funkci "předchozí" - "další" položka
Metoda | Význam |
---|---|
public getPrevItemId( int $item_id ) : string|int|null |
Na základě ID položky vrátí ID předchozí položky v seznamu (nebo null, pokud je daná položka v seznamu první). Plně respektuje filtrování a řazení - tedy aktuální nastavení seznamu. |
public getNextItemId( int $item_id ) : string|int|null |
Na základě ID položky vrátí ID následující položky v seznamu (nebo null, pokud již žádná další položka není). Plně respektuje filtrování a řazení - tedy aktuální nastavení seznamu. |
Řazení dat
Metoda | Význam |
---|---|
public setDefaultSort( string $default_sort ) : void |
Nastavuje výchozí řazení pro ORM. |
public getDefaultSort( ) : string |
Vrací výchozí řazení pro ORM. |
public getQueryOrderBy( ) : string|array |
Vrací aktuální řazení pro ORM reflektující nastavení seznamu. |
protected setSort( string $sort_by ) : void |
Metoda vnitřní logiky. Nastavuje řazení podle sloupce. |
protected catchSortParams( ) : void |
Metoda vnitřní logiky. Zachycuje parametr řazení. |
protected getGridSortBy( ) : string |
Metoda vnitřní logiky. Vrací nastavení řazení pro element UI dataGrid. |
protected getSortURLCreator( ) : callable |
Metoda vnitřní logiky. Generuje vytvářeč URL řazení pro element UI dataGrid. |
Parametry a generování URI
Metoda | Význam |
---|---|
public setParam( string $parameter, mixed $value ) : void |
Nastavuje hodnotu parametru seznamu. Důležitá metoda používána zejména filtry. |
public unsetParam( string $parameter ) : void |
Ruší parametr seznamu. Důležitá metoda používána zejména filtry. |
public getURI( ) : string |
Vygeneruje URI seznamu na základě aktuálního nastavení parametrů. |
Obecné metody
Metoda | Význam |
---|---|
public handle( ) : void |
Metoda zabezpečující zpracování vnitřní logiky seznamu. Zachytí parametry, obslouží logiku filtrů, logiku řazení a stránkování. Po volání této metody je již seznam v patřičném stavu a je možné s ním dále pracovat (zobrazit, exportovat data, či provádět operace). |
public getList( ) : DataModel_Fetch_Instances |
Vrací již plně nastavený seznam dat pomocí ORM. |
public getAllIds( ) : array |
Vrátí seznam všech ID položek dle aktuálního stavu nastavení seznamu. |