Komponenta – jak si sahnout na model

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

Chci se zeptat, jak si z komponenty sahnu na model, takze z ni muzu posilat dotazy na databazi?
dik

duke
Člen | 650
+
0
-

Nejlíp tak, že ji patřičnou službu předáš v konstruktoru.

simPod
Člen | 383
+
0
-

muzu poprosit o nakopnuti?
vytvoril jsem tedy v komponente funkci

public function __construct()
    {
        parent::__construct();
    }

a jak postupovat dal?

Foowie
Člen | 269
+
0
-

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)

simPod
Člen | 383
+
0
-

super, diky moc

jen takovy dotaz, proc se ve vytvareni komponenty uvadi jako parametr $name, kdyz se pak nepouzije?

ViPEr*CZ*
Člen | 812
+
0
-

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)

Ani
Člen | 226
+
0
-

Jestli komponenta dědí o controlu bylo by vhodné v constructoru zachovat $parent a $name a následně ho předat rodiči…

<?php
$component = new ComponentName($model, $this, $name);
?>

Sice to neni nutný, když je v továrně return, ale…

Aurielle
Člen | 1281
+
0
-

Ani: to není potřeba, naopak to znepřehledňuje kód…

simPod: za $name dosazuje Nette automaticky název komponenty. Není možné ho nahradit jiným parametrem nebo způsob volání změnit.

Ani
Člen | 226
+
0
-

No píšu, že to neni nutně potřeba, když tam má ten return… Mě zase přijde přehlednější zachovat závislosti předka u potomků, přesto že jsou nepoviné…

simPod
Člen | 383
+
0
-

diky

Jan Suchánek
Člen | 404
+
0
-

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
+
0
-

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
+
0
-

@**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);
Nox
Člen | 378
+
0
-

Pokud bude člověk mít v továrně vždy return a jméno používané podle jména komponenty (jak je to s NS?), bude to fungovat vše jako s explicitním uvedení $this, $name, nebo je ještě něco třeba nebo něco na co si dávat pozor?

Editoval Nox (22. 1. 2012 20:29)

Filip Procházka
Moderator | 4668
+
0
-

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
+
0
-

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
+
0
-

@**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
+
0
-

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.

  1. Předat ji službu modelu s tím, že komponenta si s ní už sama musí umět poradit
  2. Předat ji callback, který umí ze služby vytáhnout potřebné položky pro danou stránku
  3. 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?

Nox
Člen | 378
+
0
-

No #1 se řeší interfacem, dokud mají třídy stejný interface, obsluhujícímu ví co může použít a je mu jedno, o jakou jde třídu

Nevýhoda ke #2 mě taky zatím nenapadá

newPOPE
Člen | 648
+
0
-

#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

Etch
Člen | 403
+
0
-

Já osobně bych šel cestou definice interface. V určitých případech bych pak možná zvážil i používání adaptérů.

llook
Člen | 407
+
0
-

duke napsal(a):

Máme v podstatě 3 způsoby, jak tuto komponentu naplnit daty.

  1. Předat ji službu modelu s tím, že komponenta si s ní už sama musí umět poradit
  2. Předat ji callback, který umí ze služby vytáhnout potřebné položky pro danou stránku
  3. Předat ji konkrétní položky už při jejím vytváření
  1. Není co dodat, vystihl jsi to přesně. Jedná se o tzv. programování proti implementaci.
  2. 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ér SelectionPageable):

    $ctrl = new PagingControl(new SelectionPageable($model));
  3. 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
+
0
-

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ů).