Exponovat Control místo Presenteru
- jiriknesl
- Člen | 56
Presentery jsou v Nette nadbytečné.
Ve svém novém projektu už bych chtěl využívat výhradně controly a hledám způsob, jak exponovat controly ven (abych označil control za „root“ – tzn. obdobu dnešního presenteru) a celou aplikaci napsat v nich.
Obejdu se bez nějakého presenteru, který bude „control loader“? Respektive, je v Nette cesta, jak používat místo presenterů controly?
- Filip Procházka
- Moderator | 4668
Stačí aby tvůj Control implementovat
Nette\Application\IPresenter
a služba
Nette\Application\IPresenterFactory
ho vrátila na požádání
aplikaci.
- jiriknesl
- Člen | 56
Následující kód vypíše Notice (missing basePath).
Předpokládám, že těch věcí, které má presenter a nemá defaultně control, se asi najde víc.
<?php
class HomepagePresenter extends Nette\Application\UI\Control implements Nette\Application\IPresenter
{
private $context;
private $template;
private $request;
public function setContext($context)
{
return $this->context = $context;
}
public function run(Nette\Application\Request $request)
{
$this->request = $request;
$this->renderDefault();
}
public function renderDefault()
{
$this->template = $this->createTemplate();
$this->template->anyVariable = 'any value';
$this->template->setFIle(dirname(__DIR__) . '/templates/Homepage/default.latte');
return new Nette\Application\Responses\TextResponse($this->template->render());
}
}
Zkoušel někdo opravdu exponovat control a ví, jak to udělat, aby bylo použití podobně pohodlné, jako presenter?
- Filip Procházka
- Moderator | 4668
Pravda, šablony nejsou úplně připraveny být osekány o presenter.
Pohledem do kódu zjistíš, že spousta věcí se získává z presenteru,
když si vytvoříš BaseControl
a překryješ
createTemplate
nějak takto, tak by to mohlo pro
začátek stačit
abstract class BaseControl extends Nette\Application\UI\Control implements Nette\Application\IPresenter
{
/** @var Nette\DI\IContainer */
protected $context;
/** @var Nette\Application\Request */
protected $request;
/**
* @param Nette\DI\IContainer $context
*/
public function setContext(Nette\DI\IContainer $context)
{
return $this->context = $context;
}
/**
* @param Nette\Application\Request $request
* @return Nette\Application\IResponse
*/
public function run(Nette\Application\Request $request)
{
$this->request = $request;
return $this->render();
}
/**
* @return Nette\Templating\ITemplate
*/
protected function createTemplate($class = NULL)
{
$template = parent::createTemplate($class);
if ($this->context) {
$template->setCacheStorage($this->context->templateCacheStorage);
$template->user = $this->context->user;
$template->netteHttpResponse = $this->context->httpResponse;
$template->netteCacheStorage = $this->context->cacheStorage;
$template->baseUri = $template->baseUrl = rtrim($this->context->httpRequest->getUrl()->getBaseUrl(), '/');
$template->basePath = preg_replace('#https?://[^/]+#A', '', $template->baseUrl);
}
return $template;
}
/**
* @return Nette\Application\IResponse
*/
abstract public function render();
}
Nyní stačí vložit do komponenty $context
a implementovat
metodu render()
.
class HomepagePresenter extends BaseControl
{
public function render()
{
$foo = $this->request->params['foo'];
$this->template->anyVariable = $foo;
$this->template->setFIle(dirname(__DIR__) . '/templates/Homepage/default.latte');
return new Nette\Application\Responses\TextResponse($this->template);
}
}
PS TextResponse
rozlišuje,
jestli mu předáváš šablonu.
- Majkl578
- Moderator | 1364
Rozhodně bez presenteru nebudou fungovat třeba ani odkazy, flagy requestů, kanonizace, flash message nebo responses.
Ale v důsledku, Presenter přeci Control je, tudíž výhradně controly používáš i takhle. :)
- jiriknesl
- Člen | 56
hAssasin: Jde o to, že sémantika presenterů je nadbytečná. Presenter je Control a Control může obsahovat další Controly. Není důvod, proč by Control nemohl být označen za „root“ a tím pádem se stát presenterem.
Nakonec by pak bylo možné vytrhnout kus aplikace a udělat z něj samostatný presenter nebo naopak vzít aplikaci a zabudovat ji někam jako control.
- Ondřej Mirtes
- Člen | 1536
V Nette je blbý, že Nette\Application\UI\Presenter
zařizuje
spoustu věcí, který vypsal Majkl578. Krásná ukázka FRP (Five
Responsibilities Principle).
Taky jsem jednou chtěl zkusit jen naimplementovat IPresenter
,
ale narazil jsem, protože jsem si tím odstřihl možnost používat většinu
elegantních featur Nette. A taky to rozhraní lže, protože kromě metody
run() je potřeba
přidat i setContext :o)
- Ondřej Mirtes
- Člen | 1536
Líbilo by se mi, kdyby charakteristikou Nette\Application\UI\Presenter bylo jen spouštění životního cyklu na základě příchozích parametrů v Requestu v metodě run() (dal by se tedy přejmenovat na LifecyclePresenter, stejně jako máme MicroPresenter). Všechna ostatní funkcionalita by se dala přesunout do tříd jako LinkGenerator, Canonicalizator, FlashMessenger a dala by se znovupoužívat i v jiných kontextech – vlastních presenterech, vlastních knihovnách a frameworcích.
Taky si pohrávám s myšlenkou, že by se komponentový model nemusel řešit dědičností a komponenty by mohly být připojeny v nějakém stromu, aniž by o tom samy věděly. Architektura Nette by byla zas o něco volnější a použitelnější.
- David Grudl
- Nette Core | 8218
Ondřej Mirtes napsal(a):
Líbilo by se mi, kdyby charakteristikou Nette\Application\UI\Presenter bylo jen spouštění životního cyklu na základě příchozích parametrů v Requestu v metodě run() (dal by se tedy přejmenovat na LifecyclePresenter, stejně jako máme MicroPresenter). Všechna ostatní funkcionalita by se dala přesunout do tříd jako LinkGenerator, Canonicalizator, FlashMessenger a dala by se znovupoužívat i v jiných kontextech – vlastních presenterech, vlastních knihovnách a frameworcích.
To by se mi líbilo taky. A moc. Ale znamená to docela hodně práce a ptám se, zda se toho někdo ujme?