DatePaginator – stránkování po dnech

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
stekycz
Člen | 152
+
0
-

Díky Davidovi máme VisualPaginator, ale občas je potřeba stránkovat podle data. Ideální příklad je třeba stránka archivu na blogu. Protože jsem se s potřebou této kontrolky občas setkal, rozhodl jsem se o implementaci pokud možno nějaké univerzální.

Samotný repozitář je na GitHubu a verzovaná aplikace je k vyzkoušení jako demo. Projekt obsahuje i PHPUnit testy.

Samotné použití není složité. Nejdůležitější je nastavit rozmezí dat pro stránkování.

/**
 * @return \steky\nette\DatePaginator\VisualDatePaginator
 */
public function createComponentDatePaginator() {
	$date_paginator = new \steky\nette\DatePaginator\VisualDatePaginator();
	$date_paginator->getPaginator()->setOldestDate($this->model->getOldestDate());
	$date_paginator->getPaginator()->setNewestDate($this->model->getNewestDate());
	return $date_paginator;
}

Aktuálně plugin pracuje jen s DateTime objekty, ale pokud bude potřeba, je možné doplnit i fungování s textovými řetězci (např.: přes Proxy pattern).

Pro zobrazení dat pak stačí je z modelu vyselektovat ty potřebné:

public function renderDefault() {
	$date = $this->getComponent('datePaginator')->getPaginator()->getDate();
	$this->template->data = $this->model->getForDate($date);
}

Kontrolku stačí vykreslit typickým {control datePaginator}.

Základní krok stránkování je jeden den, ale je možné nastavit jakékoli jiné celé kladné číslo. Může se hodit v případě, že na stránce chceme ukazovat články/novinky/whatever za celý jeden týden.

public function createComponentDatePaginator() {
	...
	$date_paginator->getPaginator()->setStep(7);
	...
}

Chybí vám v popisu něco důležitého? Nebo chybí nějaká feature, která by se někomu hodila? A kdyby náhodou někdo narazil na chybu, rád ji opravím :-)

Editoval Gruw (8. 8. 2012 1:15)

jtousek
Člen | 951
+
0
-

Jestli to dobře chápu tak to stránkuje po dnech, případně po určitém počtu dní. Bylo by ale fajn umět stránkovat i po měsících nebo letech – v takovém případě bych očekával, že dostanu zvlášť počátek a konec daného období.

stekycz
Člen | 152
+
0
-

jtousek napsal(a):

Jestli to dobře chápu tak to stránkuje po dnech, případně po určitém počtu dní. Bylo by ale fajn umět stránkovat i po měsících nebo letech – v takovém případě bych očekával, že dostanu zvlášť počátek a konec daného období.

Myslíš aby bylo možné stránkovat po dnech, měsících i letech současně? Nebo jen v rámci jednoho typu data? Přejít o větší časový úsek je možné přímým nastavením data metodou $date_paginator->setDate(new DateTime());.

Pokud by se jednalo o stránkování jedním, druhým nebo třetím způsobem, tak je řešení relativně jednoduché (interface/abstraktní třída), ale pokud budu chtít stránkovat stylem:

<<< Previous year | << Previous month | < Previous day | 23.7.2012 | Next day > | Next month >> | Next Year >>>

Tak tohle bude asi trošku jinačí, ale určitě rozumně a snad i jednoduše řešitelné.

jtousek
Člen | 951
+
0
-

Myslel jsem jedním, druhým nebo třetím způsobem v rámci jednoho typu. To co popisuješ zní ale taky docela zajímavě. :-)

stekycz
Člen | 152
+
0
-

jtousek napsal(a):

Myslel jsem jedním, druhým nebo třetím způsobem v rámci jednoho typu. To co popisuješ zní ale taky docela zajímavě. :-)

Zní to sice zajímavě, ale nevidím příliš velký důvod k implementaci, když je možnost přejít přímo na konkrétní datum.

Nicméně přemýšlím, jakým způsobem implementovat různé typy stránkování:

  1. pro každý typ vlastní třída se společným předkem, rozdíl jen při výpočtu předchozího/následujícího data
  2. zachovat aktuální třídu, které nějakým způsobem předám nějaký FLAG, který mi řekne, jak stránkovat

Z pohledu čistého návrhu mi lépe vychází první varianta. Na druhou stranu druhá varianta umožní vyřešit stránkování po letech hackem (nastavím měsíce a krok dělitelný dvanácti).

Osobně nejvíce přemýšlím nad první variantou, ale se stránkováním jen pro měsíce a dny. Pokud někdo bude chtít stránkovat po letech, nastaví si pro měsíce krok dělitelný dvanácti sám. Málokdo podle mě asi bude chtít tak velký krok pro jednotlivé stránky :-)

Měsíce ale musejí mít vlastní implementaci, protože nastavit "+ 30 days" by nefungovalo vždy správně.

Pokud máte někdo jiný nápad nebo byste to řešili jen trochu jinak, budu rád za připomínky i návrhy.

LeonardoCA
Člen | 296
+
0
-

Pár nápadů spíše k funkčnosti

  1. roční/měsíční/týdenní/denní stránkování – dokážu si představit využití pro různé statistiky nebo reporty – ať už tabulky nebo grafy
  2. naopak mne nenapadá praktický význam parametru $step.
  3. místo popisek previous/next/oldest/newest(tuto informaci sdělují už ikonky) bych dal na tlačítka přímo datum/číslo týdne/název měsíce
  4. praktické pro stránkování po dnech by možná bylo, kdyby byla možnost provázat komponentu více s modelem aby se ve stránkování neobjevovaly datumy, na které nejsou navázány žádné data (režim nastavitelný volitelným parametrem) – dalo by se efektivně realizovat zjištěním nejbližšího záznamu před a po aktuálně vybraném období

5. Pro definování časových intervalů bych definoval interface (někdo by si chtěl třeba přidat čtvrtletní intervaly)
přibližně takto

<?php
interface IPeriod
{
/**
 * @returns string  Period type name (Year/Month/Week/Day etc.)
*/
public function getName;

/**
 * @returns array  Returns period information for $timestamp
 *	('label' => 'june 2012',
 *	'start' = > '2012-06-01 00:00:00',
 *	'end'=> '2012-06-30 23:59:59')
*/
public fuction getPeriod($timestamp);
}
?>
  • pro jednoznacnou identifikaci „stranky“ by se pouzilo <name>-<label>
  • ‚start‘/‚end‘ udaje mohou by se mohly použit v title="" tlačítek
  • predesla a dalsi perioda by se zjistila dle bodu 4 a nebo o sekundu nizsim casem start/vyssim casem end a volanim getPeriod
  • first/last opet volanim getPeriod na min/max hodnoty

6. Kdyby se ti chtelo hodne s tim hrat, tak prepinani druhu period bych realizoval

  • samostatnou komponentou – nekdo muze chtit selectbox, nekdo radio buttony, nekdo buttons panel
  • byl by volitelně zobrazitelný

7. I pro model definovat interface a předávat rovnou model místo volání dvou nebo více method set/get v createComponenent, i vzhledem k bodu 4 (ale možná překombinovávám)

8. Translator

tak nakonec mne napadlo i něco k realizaci a už radši končím :-)

Editováno:

9. Nevím jestli jestli se mi podařilo představu sepsat srozumitelně. Tak pro jistotu ještě popis základní myšlenky přidávání různých typů období:

class DatePaginator extends Object
{
	$private $periodTypes;

	public function registerPeriodType($name, IPeriod $periodType) {
		$this->periodTypes[$name] = $periodType;
	}
}

10. případně by možná vůbec nebyl potřeba interface a aby každý PeriodType byl definován vlastní třídou, ale dalo by se to implementovat obdobně jako registrace helperů šablon (pro výpočet období by to určitě stačilo, ale už se mi nechce přemýšlet jak by se dal řešit v takovém případě translator)

11. chtělo by to, aby se dalo definovat pořadí typu období pro prvek přepínače typu – teď mne nenapadá jak co nejšikovněji

Editoval LeonardoCA (24. 7. 2012 23:59)

stekycz
Člen | 152
+
0
-

K tomuhle musím odpovědět po částech :-)

  1. Reporty a grafy mě nenapadly, ale ta myšlenka se mi líbí.
  2. Aktuálně do jisté míry zastupuje různá stránkovací období (např.: 7 je pro týden). Pokud bych ovšem omezil na řekněme 4 nebo 5 základních typů stránkování, mohl by zmizet (minimálně veřejně).
  3. Líbí! Do dema jsem dával první co mě napadlo :-) Jedná se prakticky o šablonu, kterou si může každý upravit dle sebe.
  4. To mě také napadlo, ale bohužel mě (zatím) nenapadlo žádné rozumné řešení. Nerad bych přidal zbytečnou složitost zpracování. Také by mohlo být náročnější omezení výběru data pomocí typického DatePicker+ doplňku, který umožňuje omezení jen MIN a MAX. Znamenalo by to vytvořit něco vlastního, což ale vzhledem k výběru specifického týdne/měsíce/roku bude do jisté míry také potřeba.
  5. Interface je dobrý nápad, jen se trochu zamyslím, jak by mělo vypadat. Uvedené si vezmu jako inspiraci.
  6. Na stránky reportů nebo do administrace určitě užitečné. Pokud navíc změním z týdne na měsíc, tak je jasné, jaký měsíc zobrazím. Co ale pokud z měsíce skočím na týden? Mám skočit na první týden v daném měsíci nebo si někde pamatovat poslední týden v tomhle konkrétním měsíci a na něj skočit, jinak skákat na první? Osobně mi přijde logičtější vždy zobrazit první týden daného měsíce.
  7. Pro větší aplikace jednoznačně ano, takhle by to mělo fungovat, tam určitě model je. Jenže menší aplikace mohou pracovat přímo s NotORM, Nette\Database, Dibi nebo jinou knihovnou a model nemají definovaný. To, že bych měl mít model prakticky vždy neřeším. Některé jednoduché aplikace ho opravdu nemusí potřebovat a zbytečně se přidává byrokracie kvůli čistému kódu. Tímhle bych nutil, že nějaký model musí existovat.
  8. Jasně :-) Tomu ale asi aktuálně dávám nejnižší prioritu. Na druhou stranu, asi se jedná o jednu z jednodušších úprav.
LeonardoCA
Člen | 296
+
0
-

Těsně před tvou odpovědí jsem ještě dopsal dodatek, tak jsem ho teď ještě taky očísloval, ať se dá případně odkazovat :-) (tj. body 9.-11.)

3. Šablona je jedna věc, jiná věc je, že popisky tlačítek musí generovat objekt implementující PeriodType.

4. Omezení při stránkování dopředu dozadu by mělo být poměrně jednoduché, tak jak jsem popisoval. Na omezení přímého výběru jsem zapomněl a to už by byl oříšek napsat to dobře.

6. Asi nejpřirozenější by bylo skočit na období do kterého spadá první den současně zobrazeného období. Tj mám únor 2012 tak skočím na týden ve kterém je 1.2.2012. Mám zobrazen týden od 28.1.2012–4.2.2012 a skočím na denní zobrazení, tak se zobrazí 28.1. (možná myslíme to sámé, jen nevím čemu říkáš daný měsíc a čemu konkrétní měsíc)

8. Chtělo by to pak i podporu pro nastavení formátu data, času, prvního dne v týdnu … (a zvlášť to poslední to dost zkomplikuje)

stekycz
Člen | 152
+
0
-

LeonardoCA napsal(a):

Těsně před tvou odpovědí jsem ještě dopsal dodatek, tak jsem ho teď ještě taky očísloval, ať se dá případně odkazovat :-) (tj. body 9.-11.)

3. Šablona je jedna věc, jiná věc je, že popisky tlačítek musí generovat objekt implementující PeriodType.

4. Omezení při stránkování dopředu dozadu by mělo být poměrně jednoduché, tak jak jsem popisoval. Na omezení přímého výběru jsem zapomněl a to už by byl oříšek napsat to dobře.

6. Asi nejpřirozenější by bylo skočit na období do kterého spadá první den současně zobrazeného období. Tj mám únor 2012 tak skočím na týden ve kterém je 1.2.2012. Mám zobrazen týden od 28.1.2012–4.2.2012 a skočím na denní zobrazení, tak se zobrazí 28.1. (možná myslíme to sámé, jen nevím čemu říkáš daný měsíc a čemu konkrétní měsíc)

8. Chtělo by to pak i podporu pro nastavení formátu data, času, prvního dne v týdnu … (a zvlášť to poslední to dost zkomplikuje)

  1. Souhlasím, tím že se to takhle „komplikuje“ je to něco jiného.
  2. Tohle jsem dříve (na jiném projektu bez Nette) řešil tím, že při přímém výběru tahle kontrola prostě neprobíhala a ukázala se stránka bez záznamu. Asi by bylo možné někde asi v action metodě zkontrolovat, zda něco mám a pokud ne, tak se nechám přesměrovat na nejbližší den, kdy mám co zobrazit. Jenže to by mohlo u uživatele vyvolat dojem, že to nefunguje správně. Nejlépe se mi tedy jeví varianta s kontrolováním pouze odkazů previous/next a při přímém výběru to neřešit. Případně zakázat přímou volbu není ani tak moc složité – prostě v šabloně nebude formulář :-)
  3. Myslíme to samé, jen to asi popisuju moc komplikovaně (používám synonyma) :-)
  4. To sice ano, ale tohle jsou všechno akce, které by měla zvládat kontrolka pro výběr data. Formát data bych využil možná jen při stránkování po dnech a zobrazování přesného data na tlačítkách.

A ještě i k doplněným bodům :-)

9. a 10. na tohle si sednu jeden dlouhý večer a popřemýšlím :-)

  1. To může záležet dost na tom, jak budu implementovat různé typy stránkování. Pokud použiju nějaké flagy, tak tohle bude brnkačka. V případě vlastních tříd bych ještě musel přemýšlet…
stekycz
Člen | 152
+
0
-

Na GitHub jsem si přidal Issues, ať na to nezapomenu. Případné komentáře k založeným Issue asi raději tam než zde prosím. Mělo by tam být vše, co tady doposud bylo napsáno.

Snad se mi podaří splnit milestony v termínech :-)

Editoval Gruw (8. 8. 2012 1:16)

stekycz
Člen | 152
+
0
-

Provedl jsem rozdělení dema a samotného addonu v repozitáři na GitHubu. Přesunul jsem i jednotlivá issues. Důvod je prostý – přidání podpory Composeru.

Addon je tedy možné najít na Packagistovi. Bohužel zatím jen alpha verzi, ale do týdne chci všechno dokončit, aby byla stabilní verze 1.1.0 dostupná.

Jen se zeptám – na stránku addonů může zapisovat každý? Nejspíše bych to tam hodil, než dávám změny sem…

stekycz
Člen | 152
+
0
-

Tak to netrvalo týden, ale o dost déle, přestože tam tolik práce nebylo :-/ Nicméně verze 1.1.0-beta je vydaná. Pokud tedy budete někdo chtít otestovat, budu rád. Případné chyby nebo poznámky prosím přímo na GitHub.