Komponenta – jak si sahnout na model
- Foowie
- Člen | 269
Komponenta:
protected $model;
public function __construct($model) {
parent::__construct();
$this->model = $model;
}
Presenter:
public function createComponentXYZ($name) {
$model = ...
$component = new ComponentName($model);
return $component;
}
Editoval Foowie (21. 1. 2012 14:17)
- ViPEr*CZ*
- Člen | 817
Autor ho asi uvedl, aby bylo vidět, že je možné si poslat parametr $name do modelu… pokud na komponentě chcete zobrazit konkrétní hodnotu, kterou vytáhne model podle nějakého parametru, pak si musíte do modelu poslat takto parametr, aby model do komponenty vrátil onu hodnotu.
Editoval ViPEr*CZ* (21. 1. 2012 16:00)
- Jan Suchánek
- Člen | 404
Zdravím, a proč předávát vlastně model, když už ho mám v presenteru a předávám mu $parent a $name?
<?php
$component = new ComponentName($model, $this, $name);
?>
není lepší?
<?php
$component = new ComponentName;
?>
- Ani
- Člen | 226
Není. Je v tom skrytá závislost na modelu presenteru, která není
vidět. Když to za půl roku připojíš k jinýmu presenteru s jiným model
nebude ti to fungovat.
Když to nepřipojíš přes constructor, tak musíš ten model tahat až
v metodě attached, pak třeba zapomeneš na return v továrně a nepřipojí
se ti to vůbec.
Můžeš to psát jak chceš, ale komponenta by měla být co nejvíce znovupoužitelná a robustní.
- Filip Procházka
- Moderator | 4668
@**jenicek**: https://pla.nette.org/…cy-injection
Co se týče new ComponentName($model, $this, $name)
, tak to
vyloženě nesnáším :)
raději pouze
return new ComponentName($model);
- Filip Procházka
- Moderator | 4668
Připojení pomocí return i pomocí konstruktoru se chová úplně stejně. Jediný rozdíl je v tom, kdy se komponenta připojí.
Vzhledem k tomu, že se volají na komponentě události (attached, detached), pokud komponenta monitoruje připojení, je podle mě vhodnější, nejdříve komponentu vytvořit, nastavit a až poté připojit.
Rozdíl v chování tedy možný je. Ale pouze u individuálních komponent, které spoléhají na pozdější připojení, pokud zpracovává nějaké nastavení při připojování v attached.
- bojovyletoun
- Člen | 667
No třeba když je ve formu hidden prvek, tak korektní je nastavovat (defaultní)hodnoty až po připojení, jinak může dojít k nečekanému přepsání (odeslanými hodnotami).
- Filip Procházka
- Moderator | 4668
@**bojovyletoun**: to teda korektní není ani trošku. Jaký má význam vytvářet ve formuláři prvek, když pak jeho hodnotu zahodíš a přepíšeš ji něčím jiným? Zjisti si prosím, na co je hidden, než budeš šířit další polopravdy, díky. Na ty vaše hiddeny jsem už vyloženě alergický…
- duke
- Člen | 650
V souvislosti s touto otázkou, bych rád znal Váš názor na následující úvahu.
V případě, že chci poměrně univerzální komponentu, která nebude mít konkrétní vazbu na konkrétní model, nehodí se předávat přímo službu modelu (ne každá služba musí mít stejný interface), ale např. callbacky, které poskytnou konkrétní způsob(y) přístupu ke konkrétní službě a vším potřebným, co se službou souvisí. (V případě, že by callbacků bylo příliš mnoho, je asi vhodnější předávat nějaký propojovací objekt, s jasně daným rozhraním.)
Souvisí to i se způsobem připojování komponenty, jak zde bylo rozebíráno. Uvažme např. případ, že chceme vytvořit komponentu, která má za úkol zobrazit nějaký seznam položek, a která ho umí stránkovat. Ke stránkování přitom používá sub-komponentu. Máme v podstatě 3 způsoby, jak tuto komponentu naplnit daty.
- Předat ji službu modelu s tím, že komponenta si s ní už sama musí umět poradit
- Předat ji callback, který umí ze služby vytáhnout potřebné položky pro danou stránku
- Předat ji konkrétní položky už při jejím vytváření
Nevýhoda způsobu 1 je, že vytváříme konkrétní závislost komponenty
na modelu.
Nevýhoda způsobu 3 je, že musíme komponentu připojit už před plnění
daty, neboť dokud ji nepřipojíme, nemáme přístup k informaci, která že
to stránka se má zobrazit (a nevíme proto, jakými daty ji naplnit).
Přehlédl jsem nějakou nevýhodu způsobu 2?
- newPOPE
- Člen | 648
#1 tak ako pise @Nox definujem rozhranie a je mi jedno co dostanem. (mensi problem s tym, ze ked uz raz to rzohranie „zverejnis“ mas potom problem ho len tak zmenit)
#2 mi pride trocha divoka, take behanie tam a spat. Ale mozne riesenie…
Priklonil by som sa k #1 s tym, ze si dobre premyslim ako to rozhranie navrhnem
- llook
- Člen | 407
duke napsal(a):
…
Máme v podstatě 3 způsoby, jak tuto komponentu naplnit daty.
- Předat ji službu modelu s tím, že komponenta si s ní už sama musí umět poradit
- Předat ji callback, který umí ze služby vytáhnout potřebné položky pro danou stránku
- Předat ji konkrétní položky už při jejím vytváření
- Není co dodat, vystihl jsi to přesně. Jedná se o tzv. programování proti implementaci.
- Přihořívá, ale nevýhodou je, že musíš nějak někde popsat, jak ten
callback má vypadat (jaké mu budeš předávat parametry a jaký očekáváš
return).
V podstatě programuješ proti rozhraní, akorát že to rozhraní není popsáno standardními prostředky, ale jen někde v dokumentaci. Programování proti standardně deklarovanému rozhraní je z několika důvodů většinou lepší.
Služba samotná to rozhraní ani sama implementovat nemusí, můžeš pro ni vytvořit adaptér (ty tvoje callbacky vlastně jsou jednoduchým případem Adaptéru).
Potom bys místo podobného kódu:
$ctrl = new PagingControl(function ($itemsPerPage, $page) use ($model) { return $model->limit($itemsPerPage, $page * $itemsPerPage - $itemsPerPage); });
Psal něco na tento způsob (za předpokladu, že
PagingControl
by vyžadoval objekt rozhraníIPageable
, který tvůj$model
neimplementuje, takže bys pro něj vytvořil adaptérSelectionPageable
):$ctrl = new PagingControl(new SelectionPageable($model));
- Tady komponentu deklasuješ na jednoduché vykreslovátko pole. Logiku pro výběr dat (u stránkovače stanovení odkud-pokud) přesouváš výš.
Editoval llook (20. 2. 2012 17:52)
- duke
- Člen | 650
Díky za reakce.
Souhlasím, že nejčistší řešení je přes adaptéry. Uvědomuji si, že callbacky jsou jakousi primitivní (ne zcela čistou) obdobou adaptérů, ale někdy (u měnších projektů) může být praktičtější řešit to přes callbacky, než psát desítky triviálních adaptérů.
Snad jen jednu věc bych upřesnil. Případ #1 bych nevnímal jako „programování proti implementaci“, neboť tím, že „komponenta si se službou už sama musí umět poradit“ není řečeno, že to není zajištěno např. prostřednictvím stanoveného rozhraní (tj. na způsob adaptérů).