Form Extension – bude líp?
- Landsman
- Člen | 152
Ahoj,
vytvářím svou první form extension a samozřejmě se inspiruji,
procházím řešení.
Mám před sebou tuto funkční registraci:
public function afterCompile(Code\ClassType $class)
{
parent::afterCompile($class);
$init = $class->methods['initialize'];
$config = $this->getConfig($this->defaults);
$init->addBody('\App\Components\Imager\ImageUploadControl::register(?, ?);', ['addImagerUpload', $config]);
}
… ale mrzí mě, že metodu addImagerUpload nevidím v IDE jako
nalezitelnou, rozumím proč.
Horší však je, pokud mám nějaké metody na setování vlastností form
prvku, ve výsledku mám pak vedle kód extension a studuji ho řádek po
řádku. V lepším případě dokumentaci.
Jedno z řešeních je mít nějaký base form, kde mám anotace a dědím ho, ale to se mi také příliš nelíbí.
Zajímá mě, jestli se s tím plánuje v budoucnu něco dělat, aby to nebyla taková magie, či se to dá zapsat lépe, aniž bych použil samotnou class a bušil parametry constructoru, uprostřed formuláře. Především z pohledu nezasvěceného člověka, který neproleze fórum křížem krážem je to taková skrytá věc.
Druhý problém na který jsem narazil je, jak docílit automatické vyrenderování extension, které má v control více inputů (checkbox, hidden, …). Je to porod. Přitom kdo chce každý formulář kvůli drobnostem ručně renderovat? :[
ping @DavidGrudl
díky a omluvte prosím případnou okázalost :)
Editoval Landsman (16. 9. 2016 21:50)
- Martk
- Člen | 661
Vytvoříš si 2 traity, jednu s přepsáním funkce addContainer a druhou s vlastními komponenty:
trait TReplaceFormContainer {
public function addContainer() {
$control = new MyContainer();
$control->currentGroup = $this->currentGroup;
if ($this->currentGroup !== NULL) {
$this->currentGroup->add($control);
}
return $this[$name] = $control;
}
}
trait TFormControls {
public function addImagerUploader(...) {
// ...
}
}
Vytvoříš novou třídu form a container:
class MyContainer extends Nette\Forms\Container {
use TReplaceFormContainer;
use TFormControls;
}
class MyForm extends Nette\Application\UI\Form {
use TReplaceFormContainer;
use TFormControls;
}
Nic lepšího mě zatím nenapadlo.
Editoval Antik (16. 9. 2016 8:44)
- Landsman
- Člen | 152
@CZechBoY @Antik Jop, to je pěkné, ale stále je to jakýsi hack a není to příliš přívětivé pokud chci používat další 3rd-party rozšíření.
To Andrejovské „Bude líp?“ bylo myšleno, zda to půjde v budoucnu nějakou oficiální cestou a bude se s rozšířením podobného typu počítat & zda je to technicky vůbec reálné udělat jinak.
- CZechBoY
- Člen | 3608
Takový psycho řešení co mě teď napadlo by bylo vygenerovat traitu pro
container přes DI\Compiler.
Ve form containeru by bylo
class Container ...
{
use CompiledTrait;
...
}
a pak compiler by vygeneroval traitu a ostatní extensions by mohli do těla traity doplňovat funkce
$compiler->addFormContantainerTraitMethod('addImagerUpload', 'public function addImagerUpload(string $name, string $label) {
return new App\Forms\FormControls\ImagerUploader($name, $label);
}');
Případně přes callback místo těla funkce.
Editoval CZechBoY (16. 9. 2016 18:30)
- Martk
- Člen | 661
@Landsman Ještě by šlo udělat toto, abys nemusel kontrolovat změny:
trait TFormControls {
/** @var callable[] */
private static $_cacheMethods = [];
public function addImagerUploader(...$args) {
$this->tryControl(__METHOD__, $args);
}
private function tryControl($name, array $args) {
if (!isset(self::$_cacheMethods[$name])) {
if (!($callback = ObjectMixin::getExtensionMethod(get_class($this), $name))) {
throw new \Exception();
}
self::$_cacheMethods[$name] = $callback;
}
Callback::invoke(self::$_cacheMethods[$name], $this, ...$args);
}
}
Editoval Antik (16. 9. 2016 20:08)