Documentação do Symfony2
Renderizada do repositório symfony-docs-pt-BR no Github
Tipos de campo de formulário personalizados são ótimos quando você precisa de tipos de campo para um propósito específico, por exemplo para selecionar o gênero ou uma entrada de número de IVA.
Mas, às vezes, você realmente não precisa adicionar novos tipos de campo - você quer adicionar funcionalidades aos tipos existentes. É onde o tipo de formulário é usado.
As extensões do tipo de formulário têm dois casos de uso principais:
Em ambos os casos, é possível alcançar o seu objetivo com a renderização personalizada de formulário. Mas, usar extensões do tipo de formulário pode ser mais limpo (limitando a quantidade de lógica de negócios nos templates) e mais flexível (você pode adicionar várias extensões do tipo a um único tipo de formulário.
Extensões do tipo de formulário podem alcançar mais do que os tipos de campos personalizados podem fazer, mas, em vez de serem tipos de campos próprios, elas conectam em tipos existentes.
Imagine que você gerencia uma entidade Media, e que cada mídia está associada a um arquivo. Seu formulário Media usa um tipo file, mas, ao editar a entidade, você gostaria de ver sua imagem processada automaticamente ao lado do campo arquivo.
Você poderia, naturalmente, fazer isso personalizando a forma como este campo é renderizado em um template. Mas as extensões do tipo de formulário permitem que você faça isso de uma forma DRY agradável.
Sua primeira tarefa será criar a classe da extensão do tipo de formulário. Vamos chamá-la ImageTypeExtension. Por padrão, as extensões de formulário geralmente residem no diretório Form\Extension de um de seus bundles.
Ao criar uma extensão de tipo de formulário, você pode implementar a interface Symfony\Component\Form\FormTypeExtensionInterface ou estender a classe Symfony\Component\Form\AbstractTypeExtension. Na maioria dos casos, é mais fácil estender a classe abstrata:
// src/Acme/DemoBundle/Form/Extension/ImageTypeExtension.php
namespace Acme\DemoBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
class ImageTypeExtension extends AbstractTypeExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return 'file';
}
}
O único método que você deve implementar é o getExtendedType. Ele é usado para indicar o nome do tipo de formulário que será estendido pela sua extensão.
Tip
O valor que você retorna no método getExtendedType corresponde ao valor retornado pelo método getName na classe do tipo de formulário que você deseja estender.
Além da função``getExtendedType``, provavelmente você vai querer sobrescrever um dos seguintes métodos:
Para mais informações sobre o que esses métodos fazem, você pode consultar o artigo do cookbook Criando Tipos de Campo Personalizados.
O próximo passo tornar o Symfony ciente da sua extensão. Tudo o que você precisa fazer é declará-la como um serviço usando a tag form.type_extension.
A chave alias da tag é o tipo de campo que essa extensão deve ser aplicada. No seu caso, como você deseja estender o tipo de file, você vai usar o file como um alias.
O objetivo da sua extensão é exibir imagens agradáveis ao lado de campos arquivo (quando o modelo subjacente contém imagens). Para esta finalidade, vamos supor que você usa uma abordagem semelhante à descrita em Como manusear o upload de arquivos com o Doctrine: você tem um modelo Media com uma propriedade file (correspondente ao campo de arquivo, no formulário) e uma propriedade path (correspondendo ao caminho da imagem, no banco de dados):
// src/Acme/DemoBundle/Entity/Media.php
namespace Acme\DemoBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Media
{
// ...
/**
* @var string The path - typically stored in the database
*/
private $path;
/**
* @var \Symfony\Component\HttpFoundation\File\UploadedFile
* @Assert\File(maxSize="2M")
*/
public $file;
// ...
/**
* Get the image url
*
* @return null|string
*/
public function getWebPath()
{
// ... $webPath being the full image url, to be used in templates
return $webPath;
}
}
Sua classe da extensão do tipo de formulário terá que fazer duas coisas, a fim de estender o tipo de formulário file:
A lógica é a seguinte: quando adicionar um campo de formulário do tipo file, você poderá especificar uma nova opção: `` image_path ``. Esta opção irá dizer ao campo arquivo como obter o endereço real da imagem, a fim de exibí-la na visão:
// src/Acme/DemoBundle/Form/Extension/ImageTypeExtension.php
namespace Acme\DemoBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ImageTypeExtension extends AbstractTypeExtension
{
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return 'file';
}
/**
* Add the image_path option
*
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setOptional(array('image_path'));
}
/**
* Pass the image url to the view
*
* @param FormView $view
* @param FormInterface $form
* @param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
if (array_key_exists('image_path', $options)) {
$parentData = $form->getParent()->getData();
if (null !== $parentData) {
$propertyPath = new PropertyPath($options['image_path']);
$imageUrl = $propertyPath->getValue($parentData);
} else {
$imageUrl = null;
}
// set an "image_url" variable that will be available when rendering this field
$view->set('image_url', $imageUrl);
}
}
}
Cada tipo de campo é renderizado por um fragmento de template. Esses fragmentos de template podem ser sobrescritos, para personalizar a renderização formulário. Para mais informações você pode consultar o artigo O que são Temas de Formulário?.
Em sua classe de extensão, você adicionou uma nova variável (image_url), mas você ainda precisa aproveitar esta nova variável em seus templates. Especificamente, você precisa sobrescrever o bloco file_widget:
Note
Você precisará mudar o seu arquivo de configuração ou especificar explicitamente como você quer o tema do seu formulário, para que o Symfony utilize o seu bloco sobrecrito. Veja O que são Temas de Formulário? para mais informações.
A partir de agora, ao adicionar um campo do tipo file no seu formulário, você pode especificar uma opção image_path que será usada para exibir uma imagem próxima ao campo arquivo. Por exemplo:
// src/Acme/DemoBundle/Form/Type/MediaType.php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class MediaType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('file', 'file', array('image_path' => 'webPath'));
}
public function getName()
{
return 'media';
}
}
Ao exibir o formulário, se o modelo subjacente já foi associado com uma imagem, você vai vê-la ao lado do campo arquivo.