Formulários Symfony mais limpos
Formulários são componentes essenciais para o desenvolvimento de aplicativos da web Symfony. Mas se eu olhar para a forma típica do Symfony , vejo várias violações das Quatro Regras do Design Simples .
Problemas em formulários do symfony
- Alias de formulário duplicado –
getName
e o alias definido nos serviços deve corresponder - Acoplamento desnecessário ao Symfony – eu realmente preciso saber
OptionsResolverInterface
? - Opcional
$options
–
Forma típica do Symfony
namespace AppBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class TaskType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundleEntityTask'
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
if (is_null($options['data']->getId())) {
$builder->add('assignee');
}
}
public function getName()
{
return 'task';
}
}
Formulário registrado como serviço:
services:
acme_demo.form.type.task:
class: AppBundleFormTypeTaskType
tags:
- { name: form.type, alias: task }
Solução mais limpa
Eu sigo regras de design simples, ao invés das Melhores Práticas do Symfony, para manter a forma o mais legível e simples possível. Essa abordagem funcionou muito bem para mim, especialmente em aplicativos com muitos formulários. Não herde o Symfony AbstractType
, mas CleanFormType
(desculpe o nome fictício) que resolve os problemas anteriores:
- Alias é definido em um lugar (em
services.yml
) - O formulário é acoplado apenas a
FormBuilderInterface
- As opções são verdadeiramente opcionais
namespace AppBundleFormType;
use SymfonyComponentFormFormBuilderInterface;
class TaskType extends CleanFormType
{
private $isNewTaskCreated;
public function getDefaults()
{
return array(
'data_class' => 'AppBundleEntityTask'
);
}
protected function loadOptions(array $options)
{
$this->isNewTaskCreated = is_null($options['data']->getId());
}
protected function build(FormBuilderInterface $builder)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
if ($this->isNewTaskCreated) {
$builder->add('assignee');
}
}
}
services:
acme_demo.form.type.task:
class: AppBundleFormTypeTaskType
arguments:
- "task"
tags:
- { name: form.type, alias: task }
A definição do formulário é ainda mais simples sem padrões e opções :
class TaskType extends CleanFormType
{
protected function build(FormBuilderInterface $builder)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
}
}
Código fonte
O CleanFormType está disponível na essência . Você pode usá-lo e modificá-lo como quiser. Aqui está a aula:
namespace AppBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
abstract class CleanFormType extends AbstractType
{
private $formName;
public function __construct($formName)
{
$this->formName = $formName;
}
public function getName()
{
return $this->formName;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
$this->getDefaults()
);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->loadOptions($options);
$this->build($builder);
}
protected function getDefaults()
{
return array();
}
/** @SuppressWarnings("unused") */
protected function loadOptions(array $options)
{
}
abstract protected function build(FormBuilderInterface $builder);
}