Všechny formuláře ať mají vlastní šablonu
- Jan Endel
- Člen | 1016
Zdravím, dělám teď velkou aplikaci a řekl jsem si, že si formuláře nadefinuju každý ve vlastní třídě a chtěl jsem si udělat to, aby každý formulář měl vlastní šablonu přes kterou by se vykresloval.
Jenže ouha, formuláře nejsou ve skutečnosti komponenty, takže nemají k sobě přidrátovaný šablonovací systém. V současnosti jsem dospěl k něčemu takovému. Mám předka pro všechny formuláře a v něm zadefinováno (má protected proměnou template):
public function render()
{
$templateName = lcfirst($this->name);
$dir = dirname($this->getReflection()->getFileName());
$this->template = new \Nette\Templating\FileTemplate("$dir/templates/$templateName.latte");
$this->template->registerFilter(new \Nette\Latte\Engine);
$this->template->formName = $this->name;
$this->template->_control = $this;
$this->template->render();
}
žel mi to nadává, že komponenta s daným názvem neexistuje. Jdu na to úplně špatně? Jak tohleto vyřešit?
Editoval pilec (26. 2. 2012 17:22)
- duke
- Člen | 650
A nebude jednodušší udělat si komponentu na renderování
formulářů?
Použití v presenteru by pak vypadalo:
protected function createComponentMyForm($name)
{
return new FormRendererControl(new MyForm);
}
Konstruktor FormRendererControl by pak mohl vypadat takto:
public function __construct(Nette\Application\UI\Form $form, Nette\ComponentModel\IContainer $parent = NULL, $name = NULL)
{
parent::__construct($parent, $name);
$this->addComponent($form, 'form');
}
Konkrétní cestu k šabloně můžeš injektovat přes setter komponenty,
případně ji nějak vypočítávat z $name. A v šabloně bys použil
{form form} ... {/form}
, případně si to makro nějak přiohnul
aby bralo „form“ jako výchozí parametr a tys mohl mít v šabloně jen
{form} ... {/form}
.
- Šaman
- Člen | 2659
Edit: Variantu s komponentou, která obsahuje $form jsem úspěšně používal, ale není to úplně čisté – já chci přiřadit šablonu (resp. renderer) formuláři a ne vytvářet novou komponentu okolo formuláře jenom proto, že ona už se šablonou umí pracovat..
Taky mě to dost trápilo, tak jsem vytvořil FormTemplateRenderer:
<?php
class FormTemplateRenderer extends \Nette\Object implements \Nette\Forms\IFormRenderer
{
/** @var ITemplate */
protected $template;
public function __construct($templateOrFile = NULL)
{
if ( $templateOrFile instanceof \Nette\Templating\Template )
{
$this->template = $templateOrFile;
}
elseif ( is_file($templateOrFile) )
{
$this->template = new \Nette\Templating\FileTemplate($templateOrFile);
}
elseif ( isset ($templateOrFile) )
{
throw new \Nette\UnexpectedValueException('Argument musí být soubor nebo instance template!');
}
}
public function render(\Nette\Forms\Form $form)
{
$template = $this->getTemplate();
$template->onPrepareFilters[] = function($template)
{
$template->registerFilter(new \Nette\Latte\Engine);
};
$template->_control = $form->presenter;
$template->form = $form->name;
$template->render();
}
public function getTemplate()
{
if( $this->template instanceof \Nette\Templating\Template )
{
return $this->template;
}
else
{
throw new \Nette\InvalidStateException("Není nastavena šablona!");
}
}
public function setTemplate(\Nette\Templating\Template $template)
{
$this->template;
}
}
?>
A používám ho v BaseFormu, který si šablonu dohledává dokonce sám v adresáři s .php souborem
<?php
/**
* Formulář, který si umí dohledat šablonu
*/
class BaseForm extends \Nette\Application\UI\Form
{
public function __construct()
{
parent::__construct();
foreach ( $this->formatTemplateFiles() as $file )
{
if ( is_file($file) )
{
$this->renderer = new FormTemplateRenderer($file);
break;
}
}
// tady si můžeš zkontrolovat, jestli se dohledala šablona a pokud ne, použít např. DefaultFormRenderer
}
/**
* Vrací pole souborů, které mohou obsahovat šablonu formuláře
*/
protected function formatTemplateFiles()
{
$dir = dirname($this->reflection->getFilename());
return array
(
"$dir/{$this->reflection->name}.latte",
);
}
}
?>
Editoval Šaman (26. 2. 2012 21:49)
- Šaman
- Člen | 2659
@Pilec: Aha, to je věc, která se mi na nových makrech nelíbí.
Interně makro potřebuje název formu a komponentu, ve kterém se ten form
vyskytuje. Je to proto, zby se dalo v šabloně psát
{form 'MujForm'}.....{/form}
.
A makro si ten formulář dohledá v tom $_control
podle jména.
Daleko raději bych do šablony předával $form = $this
. A pak
to použil {form $form}....{/form}
. Bohužel to ve stávající
podobě formulářových maker nejde. (V těch původních co byly
v doplňcích toto šlo.)
Editoval Šaman (26. 2. 2012 22:54)
- David Grudl
- Nette Core | 8218
Šaman napsal(a):
…A pak to použil
{form $form}....{/form}
. Bohužel to ve stávající podobě formulářových maker nejde.
Fixed
- 22
- Člen | 1478
…jen pro jistotu, imho stačí tedy do potomka
Nette\Application\UI\Form
, pokud chcete rendreovat šablonu přímo
u formuláře:
...
public function render()
{
$template = new FileTemplate(__DIR__ . '/formTemplate.latte');
$template->registerFilter(new Engine());
$template->form = $this;
$template->render();
}
je to tak?
Editoval 22 (27. 8. 2012 5:17)
- Vojtěch Dobeš
- Gold Partner | 1316
Myslím, že toto je snazší řešení, jak jednoduše svázat formulář s vlastní šablonou: https://forum.nette.org/…-jeho-limity
- Vojtěch Dobeš
- Gold Partner | 1316
Pokud to dobře chápu, tu tvoji metodu render
bych umístil do
poděděného UI\Form
. Jediný rozdíl je tedy v tom, že nebudu
dědit od UI\Form
ale od UI\Control
, a definici
formuláře nedám do attached
, konstruktoru nebo nějaké vlastní
alá configure
metody, ale do createComponentForm
.
UI\Control
má automaticky nachystanou šablonu, podporuje v té
šabloně snippety atd… rozdíl množství je kódu je minimální, možná
i menší :).
https://gist.github.com/3486768
Editoval vojtech.dobes (27. 8. 2012 10:56)
- Hafran
- Člen | 121
@22 Hm, tak z tohohle moc moudrej nejsem – jakej je teda závěr? :) Že je lepší dědit od Container než od Control?
@vojtech.dobes a nemůže se mi rozpadnout v nějakých situacích callback, třeba onSuccess, když bude formulář volat callback z rodičovskýho Control? A když to nejni v attached, nejsou nějaké situace, kde mi to bude dělat neplechu, pač to nebude připojený?
Pardon za hafo otázek :)
- petr.jirous
- Člen | 128
Zdravím,
používám toto řešení, které napsal Šaman v příspěvku #4. Funguje to,
ale když do šablony formuláře chci dát snippet, tak mi to hází undefined
varible: basePath.
Za všechny nápady/připomínky předem díky
- Šaman
- Člen | 2659
Dneska už bych to řešil jinak – mám pravou komponentu (takže fungují snippety, vytváření šablon apod.) a do ní předávám formulář definovaný pomocí továrničky. Až se najím, tak sem postnu postup, ale už tu několikrát zazněl od Vojty Dobeše.
Řešení s TemplateRendererem stále funguje, ale už ho nerozvíjím, takže ti mohu jen obecně poradit vložit do šablony všechny defaultní porměnné Nette ($basePath, $user, nevím co dalšího), abys dosáhl plné kompatibility vytvořené šablony.