Komponenta průvodce
- _Martin_
- Generous Backer | 679
Jak již někteří vědí, léta letoucí se snažím o dokonalou komponentu pro Průvodce. V jisté zbastlené verzi tato komponenta již existuje a nyní nastává onen okamžik velkého refactoringu. A to je chvíle, kdy se obracím o radu na vás, kolegy Nettisty.
Rozhoduji se, jakým způsobem přidávat do průvodce kroky. V hlavě mám dva nápady a nyní je předkládám před vás, odbornou veřejnost, k posouzení. A samozřejmě můžete přijít i s nápadem vlastním.
Verze 1 – jako formuláře
protected function createComponentRegistrationWizard($name)
{
$wizard = new Wizard($this, $name);
$wizard->caption = 'Průvodce registrací';
$wizard->onProcess[] = array($this, 'process');
$wizard->onCancel[] = array($this, 'canceled');
/** sekce: ZÁKAZNÍK *******************************************************/
$wizard->addStep('zakaznik', 'Informace o zákazníkovi')
->addDescription('Vyplňte informace o zákazníkovi.');
/** sekce: DODAVATEL ******************************************************/
$wizard->addStep('obchodniZalezitosti', 'Obchodní záležitosti')
->addDescription('Vyplňte informace, které se týkají obchodní stránky věci.');
$wizard->addStep('dodavatel', 'Základní informace o dodavateli')
->addDescription('Vyplňte základní informace o dodavateli.')
->setNext($wizard['obchodniZalezitosti']);
/** křižovatka: UŽIVATEL **************************************************/
$wizard->addCrossroad('uzivatel', 'Kdo se registruje')
->addDescription('Chcete se registrovat jako náš zákazník nebo dodavatel?')
->addWay('Zákazník', $wizard['zakaznik'], 'Můžete nakupovat, jak je ctěná libost.', 'zakaznik.gif')
->addWay('Dodavatel', $wizard['dodavatel'], 'Budete nás zásobovat, pane Karfíku.', 'dodavatel.gif');
/** DOKONČENÍ *************************************************************/
$wizard->addStep('dokonceni', 'Kontrola údajů')
->addDescription('Zkontrolujte vyplněné údaje. Registraci dokončíte stisknutím tlačítka Registrovat.');
$wizard->setFirst($wizard['uzivatel']);
$wizard['zakaznik']->setNext($wizard['dokonceni']);
$wizard['obchodniZalezitosti']->setNext($wizard['dokonceni']);
return $wizard;
}
Výhody:
- vytváří se stejně jako formuláře
- jednoduchý a objektově čistý
Nevýhody:
- kroky, na které chci odkazovat, musím buď vytvořit předem nebo je odkázat dodatečně → v obou případech to dělá kód těžším, než by mohlo být (a nutí mě kupříkladu ručně nastavit první krok)
Verze 2 – kroky jako komponenty z továrničky
// v presenteru
protected function createComponentRegistrationWizard($name)
{
$wizard = new RegistrationWizard($this, $name);
$wizard->caption = 'Průvodce registrací';
$wizard->onProcess[] = array($this, 'process');
$wizard->onCancel[] = array($this, 'canceled');
return $wizard;
}
// RegistrationWizard
class RegistrationWizard extends Wizard
{
/** křižovatka: UŽIVATEL **************************************************/
protected function createComponentUzivatel($name)
{
return $this->addCrossroad($name, 'Kdo se registruje')
->addDescription('Chcete se registrovat jako náš zákazník nebo dodavatel?')
->addWay('Zákazník', $this['zakaznik'], 'Můžete nakupovat, jak je ctěná libost.', 'zakaznik.gif')
->addWay('Dodavatel', $this['dodavatel'], 'Budete nás zásobovat, pane Karfíku.', 'dodavatel.gif');
}
/** sekce: ZÁKAZNÍK *******************************************************/
protected function createComponentZakaznik($name)
{
return $this->addStep($name, 'Informace o zákazníkovi')
->addDescription('Vyplňte informace o zákazníkovi.')
->setNext($this['dokonceni']);
}
/** sekce: DODAVATEL ******************************************************/
protected function createComponentDodavatel($name)
{
return $this->addStep($name, 'Základní informace o dodavateli')
->addDescription('Vyplňte základní informace o dodavateli.')
->setNext($this['obchodniZalezitosti']);
}
protected function createComponentObchodniZalezitosti($name)
{
return $this->addStep($name, 'Obchodní záležitosti')
->addDescription('Vyplňte informace, které se týkají obchodní stránky věci.')
->setNext($this['dokonceni']);
}
/** DOKONČENÍ *************************************************************/
protected function createComponentDokonceni($name)
{
return $this->addStep($name, 'Kontrola údajů')
->addDescription('Zkontrolujte vyplněné údaje. Registraci dokončíte stisknutím tlačítka Registrovat.');
}
}
Výhody:
- kroky jsou pěkně za sebou a vše ohledně kroku je na jednom místě
Nevýhody:
- nutnost vytvářet vlastního potomka třídy Wizard
- více kódu
Tak co vy na to?
Editoval _Martin_ (2. 11. 2009 17:29)
- _Martin_
- Generous Backer | 679
Honza M. napsal(a):
Co dělaj ty metody addCrossroad a addStep, když jsou v továrničce?
Zhruba to samé, co metody addSubmit
, addText
,…
u formuláře. V těch továrničkách jsem je nechal z toho důvodu, že je
to uživatelsky přívětivější, než psát pro každý krok:
protected function createComponentUzivatel($name)
{
$step = new Crossroad;
$step->caption = 'Kdo se registruje';
$step->addDescription('Chcete se registrovat jako náš zákazník nebo dodavatel?');
$step->addWay('Zákazník', $this['zakaznik'], 'Můžete nakupovat, jak je ctěná libost.', 'zakaznik.gif');
$step->addWay('Dodavatel', $this['dodavatel'], 'Budete nás zásobovat, pane Karfíku.', 'dodavatel.gif');
if(isset($this->values[$name])) {
$step->setValues($this->values[$name]);
}
return $this[$name] = $step;
}
Edit: ta továrnička je tam především kvůli tomu, aby se mohlo na krok odkazovat, ikdyž ještě nebyl vytvořen.
Editoval _Martin_ (2. 11. 2009 18:16)
- Jerry123456789
- Člen | 37
A co třeba (jen příklad, inspirace)
<?php
$w = new Wizard(...);
...
$w->addStep($this['wizardStep1'],...);
$w->addStep($this['wizardStep2'],...);
...
?>
přičemž wizardStep1/2 by bylo AppForm (spíše potomek Formu – WizardForm), normálně v továrničce stvořený.
Editoval Jerry123456789 (2. 11. 2009 18:49)
- _Martin_
- Generous Backer | 679
Jerry123456789 napsal(a):
…
Pokud ti dobře rozumím, spojil jsi obě dvě mnou uvedené verze do
jedné – bohužel v tom nevidím změnu oproti tomu, co jsem psal.
A přidávat potomek Formu rozhodně ne (formulář není třeba v každém
kroku) – jsou zde třídy pro různé kroky, jako třeba
Crossroad
pro „rozcestí“ (něco jako výběr typu sítě ve
Windows 7).
- Honza Kuchař
- Člen | 1662
Já myslím, že je to dilema, protože na jednoduché průvodce bude hezčí ten první způsob. Na složitější ten druhý.
- JakubKohout
- Člen | 92
honzakuchar napsal(a):
Já myslím, že je to dilema, protože na jednoduché průvodce bude hezčí ten první způsob. Na složitější ten druhý.
souhlasím
asi bych preferoval způsob zápisu ala TabControl, je to vlastně příklad
co už uvedl kolega Jerry.
Je to lepší z hlediska toho když budu chtít v nějakém kroku vykreslit
například dataGrid, či jenom formulář (asi ani jedno bych nevyužil ale
třeba se v budoucnu objeví nějaká super componenta která by
sem sedla)
- _Martin_
- Generous Backer | 679
Když se na to dívám znovu, tak z implementačního hlediska to je jedno a to samé – jde spíše o takové Best practice. Na TabControlu se mi líbí definování továrních metod, to je šikovné a umožňovalo by to líné vytváření obsahu jednotlivých kroků (praktické zvláště u velkých formulářů) – takže vím, kde brát inspiraci=)
Z vašich reakcí mám ovšem pocit, že jsem se špatně vyjádřil – řešil jsem především problém, jak jednomu kroku říct, že vede na druhý, když druhý ještě neexistuje.
$a = new Wizard;
$a->addStep('krok1')->setNext(???); // $a['krok2'] dát nemůžu, ještě neexistuje
$a->addStep('krok2');
- Honza Marek
- Člen | 1664
_Martin_ napsal(a):
protected function createComponentUzivatel($name) { $step = new Crossroad; ... return $this[$name] = $step; }
Ta továrnička by měla stačit taková:
protected function createComponentUzivatel()
{
$step = new Crossroad;
...
return $step;
}
nebo
protected function createComponentUzivatel($name)
{
$step = new Crossroad($this, $name);
...
}
A taky teda myslim, že pokud step i crossroad jsou obě přímými podkomponentami wizardu, tak je to na implementátorovi, jaký způsob použije.
- Jerry123456789
- Člen | 37
_Martin_:
ad 1) addStep($this[‚…‘]) nemusí dostat jen form, stačí nějaký „embedder“ (může embedovat form, text, apod.)
ad 2) ->setNext(string $name, boolead $need);
to by snad stačilo ne? $need – throw exception if next step doesn't
exists?
- _Martin_
- Generous Backer | 679
Honza M. napsal(a): …
Jj, kopíroval jsem to z metody Wizard::addStep
a tam to oproti
továrničce bylo třeba.
Jerry123456789 napsal(a):
ad 1) addStep($this[‚…‘]) nemusí dostat jen form, stačí nějaký „embedder“ (může embedovat form, text, apod.)
Já nechci krok vázat jen na jednu komponentu (buď form nebo nějakou jinou), byť by byla upravená. Tady pravděpodobně zvolím způsob podobný TabControlu, čili továrničky na obsah.
ad 2) ->setNext(string $name, boolead $need);
to by snad stačilo ne? $need – throw exception if next step doesn't exists?
Nad tím jsem taky uvažoval. Technicky to jde, ale má to jednu nevýhodu: když zadáš krok špatně (třeba neexistující), tak ti Laděnka nemůže říct, na jakým řádku k chybě došlo (protože se na tu chybu přijde až někdě později při zpracování).
Teď si říkám, že bude lepší mít možnost nastavit následující krok za běhu (například pokud chci krok měnit v závislosti na vyplnění formuláře) – a nastavení kroků přímo v definici průvodce bude jen zjednodušením kvůli triviálním průvodcům.
- Jerry123456789
- Člen | 37
_Martin_ napsal(a):
Jerry123456789 napsal(a):
ad 1) addStep($this[‚…‘]) nemusí dostat jen form, stačí nějaký „embedder“ (může embedovat form, text, apod.)
Já nechci krok vázat jen na jednu komponentu (buď form nebo nějakou jinou), byť by byla upravená. Tady pravděpodobně zvolím způsob podobný TabControlu, čili továrničky na obsah.
Však jeden embedder by mohl mít v sobě schováno cokoli, ne jen jednu komponentu.