Documentação do Symfony2
Renderizada do repositório symfony-docs-pt-BR no Github
O Symfony dispõe de uma grande variedade de maneiras para personalizar como um formulário é renderizado. Neste guia, você vai aprender a personalizar cada parte possível do seu formulário com o menor esforço, se você usa o Twig ou PHP como sua templating engine.
Lembre-se que o widget HTML, a label e o erro de um campo do formulário podem ser facilmente renderizados usando a função Twig form_row ou o método helper PHP row:
Você também pode renderizar cada uma das três partes do campo individualmente:
Em ambos os casos, a label do formulário, os erros e o widget HTML são renderizados usando um conjunto de marcação que vem por padrão com o symfony. Por exemplo, ambos os templates acima seriam renderizados da seguinte forma:
<div>
<label for="form_age">Age</label>
<ul>
<li>This field is required</li>
</ul>
<input type="number" id="form_age" name="form[age]" />
</div>
Para protótipos rápidos e para testar um formulário, você pode renderizar todo o formulário com apenas uma linha:
O restante desta receita irá explicar como cada parte de marcação do formulário pode ser modificada em vários níveis diferentes. Para mais informações sobre a renderização do formulário em geral, consulte Renderizando um formulário em um Template.
O Symfony utiliza fragmentos de formulário - um pequeno pedaço de um template que renderiza apenas uma parte de um formulário - para renderizar cada parte de um formulário - labels de campo, os erros, campos de texto input, tags select, etc
Os fragmentos são definidos como blocos no Twig e como arquivos de template no PHP.
Um tema é nada mais do que um conjunto de fragmentos que você deseja usar quando está renderizando um formulário. Em outras palavras, se você quiser personalizar uma parte de como um formulário é processado, você vai importar um tema que contém uma personalização dos fragmentos apropriados do formulário.
O Symfony vem com um tema padrão (form_div_layout.html.twig no Twig e FrameworkBundle:Form no PHP) que define cada fragmento necessário para renderizar cada parte de um formulário.
Na seção seguinte, você vai aprender a personalizar um tema, sobrescrevendo alguns ou todos os seus fragmentos.
Por exemplo, quando o widget de um campo do tipo integer é renderizado, um campo input number é gerado
renderiza:
<input type="number" id="form_age" name="form[age]" required="required" value="33" />
Internamente, o symfony usa o fragmento integer_widget para renderizar o campo. Isso ocorre porque o tipo de campo é integer e você está renderizando seu widget (em oposição a sua label ou errors).
No Twig ele seria por padrão o bloco integer_widget do template form_div_layout.html.twig.
No PHP ele seria o arquivo integer_widget.html.php localizado no diretório FrameworkBundle/Resources/views/Form.
A implementação padrão do fragmento integer_widget seria parecida com esta:
Como você pode ver, este próprio fragmento renderiza outro fragmento - field_widget:
O ponto é, os fragmentos ditam a saída HTML de cada parte de um formulário. Para personalizar a saída do formulário, você só precisa identificar e substituir o fragmento apropriado. O conjunto dessas personalizações de fragmentos de formulário é conhecida como “tema” de formulário. Ao renderizar um formulário, você pode escolher qual(ais) tema(s) de formulário deseja aplicar.
No Twig, um tema é um único arquivo de template e os fragmentos são os blocos definidos neste arquivo.
No PHP um tema é um diretório e os fragmentos são os arquivos de template individuais neste diretório.
Para ver o poder da tematização de formulários, suponha que você queira envolver cada campo input number com uma tag div. A chave para fazer isso é personalizar o fragmento integer_widget.
Ao personalizar o bloco de campo de formulário no Twig, você tem duas opções de onde o bloco de formulário personalizado pode residir:
Método | Prós | Contras |
---|---|---|
Dentro do mesmo template que o formulário | Rápido e fácil | Não pode ser reutilizado em outros templates |
Dentro de um template separado | Pode ser reutilizado por muitos templates | Requer que um template extra seja criado |
Ambos os métodos têm o mesmo efeito, mas são melhores em situações diferentes.
A maneira mais fácil de personalizar o bloco integer_widget é personalizá-lo diretamente no mesmo template que está renderizando o formulário.
{% extends '::base.html.twig' %}
{% form_theme form _self %}
{% block integer_widget %}
<div class="integer_widget">
{% set type = type|default('number') %}
{{ block('field_widget') }}
</div>
{% endblock %}
{% block content %}
{# ... render the form #}
{{ form_row(form.age) }}
{% endblock %}
Ao usar a tag especial {% form_theme form _self %}, o Twig procura dentro do mesmo template por qualquer blocos de formulários sobrescritos. Assumindo que o campo form.age é um tipo de campo integer, quando o widget é renderizado, o bloco integer_widget personalizado irá ser utilizado.
A desvantagem deste método é que o bloco de formulário personalizado não pode ser reutilizado ao renderizar outros formulários em outros templates. Em outras palavras, este método é mais útil ao fazer personalizações de formulários que são específicas para um único formulário em sua aplicação. Se você quiser reutilizar uma personalização em vários (ou todos) os formulários de sua aplicação, leia a próxima seção.
Você também pode optar por colocar o bloco de formulário integer_widget personalizado em um template totalmente separado. O código e o resultado final é o mesmo, mas agora você pode reutilizar a personalização de formulário em muitos templates:
{# src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #}
{% block integer_widget %}
<div class="integer_widget">
{% set type = type|default('number') %}
{{ block('field_widget') }}
</div>
{% endblock %}
Agora que você já criou o bloco de formulário personalizado, você precisa dizer ao Symfony para usá-lo. Dentro do template onde você está renderizando o seu formulário, diga ao Symfony para usar o template através da tag form_theme:
{% form_theme form 'AcmeDemoBundle:Form:fields.html.twig' %}
{{ form_widget(form.age) }}
Quando o widget form.age é renderizado, o Symfony usará o bloco integer_widget do novo template e a tag input vai ser envolvida no elemento div especificado no bloco personalizado.
Ao usar o PHP como templating engine, o único método de personalizar um fragmento é criar um novo arquivo template - é semelhante ao segundo método utilizado pelo Twig.
O arquivo de template deve ser nomeado após o fragmento. Você deve criar um arquivo integer_widget.html.php para personalizar o fragmento integer_widget.
<!-- src/Acme/DemoBundle/Resources/views/Form/integer_widget.html.php -->
<div class="integer_widget">
<?php echo $view['form']->renderBlock('field_widget', array('type' => isset($type) ? $type : "number")) ?>
</div>
Agora que você criou o template de formulário personalizado, você precisa dizer ao Symfony para usá-lo. Dentro do template onde você está renderizando o seu formulário, diga ao Symfony para usar o tema através do método helper setTheme:
<?php $view['form']->setTheme($form, array('AcmeDemoBundle:Form')) ;?>
<?php $view['form']->widget($form['age']) ?>
Quando o widget form.age é renderizado, o Symfony vai usar o template integer_widget.html.php personalizado e a tag input será envolvida pelo elemento div.
Até agora, para sobrescrever um bloco de formulário em particular, o melhor método é copiar o bloco padrão de form_div_layout.html.twig, colá-lo em um template diferente, e, em seguida, personalizá-lo. Em muitos casos, você pode evitar ter que fazer isso através da referência ao bloco base quando for personalizá-lo.
Isso é fácil de fazer, mas varia um pouco dependendo se as personalizações de seu bloco de formulário estão no mesmo template que o formulário ou em um template separado.
Importe os blocos adicionando uma tag use no template onde você está renderizando o formulário:
{% use 'form_div_layout.html.twig' with integer_widget as base_integer_widget %}
Agora, quando os blocos do form_div_layout.html.twig são importados, o bloco integer_widget é chamado base_integer_widget. Isto significa que quando você redefinir o bloco integer_widget, você pode fazer referência a marcação padrão através do base_integer_widget:
{% block integer_widget %}
<div class="integer_widget">
{{ block('base_integer_widget') }}
</div>
{% endblock %}
Se as personalizações do formulário residirem dentro de um template externo, você pode fazer referência ao bloco base usando a função parent() do Twig:
{# src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #}
{% extends 'form_div_layout.html.twig' %}
{% block integer_widget %}
<div class="integer_widget">
{{ parent() }}
</div>
{% endblock %}
Note
Não é possível fazer referência ao bloco base quando se utiliza o PHP como template engine. Você tem que copiar manualmente o conteúdo do bloco base para o seu novo arquivo de template.
Se você deseja que uma certa personalização de formulário seja global para a sua aplicação, você pode conseguir isso fazendo as personalizações de formulário em um template externo e depois importá-lo dentro da sua configuração da aplicação:
Usando a seguinte configuração, quaisquer blocos de formulários personalizados dentro do template AcmeDemoBundle:Form:fields.html.twig serão usados globalmente quando um formulário é renderizado.
Por padrão, o Twig usa um layout div ao renderizar os formulários. Algumas pessoas, no entanto, podem preferir renderizar formulários em um layout de tabela. Para isso use o recurso form_table_layout.html.twig como layout:
Se você quer fazer a alteração somente em um template, adicione a seguinte linha em seu arquivo de template em vez de adicionar o template como um recurso:
{% form_theme form 'form_table_layout.html.twig' %}
Note que a variável form no código acima é a variável de visão do formulário que você passou para o seu template.
Usando a seguinte configuração, quaisquer fragmentos de formulários personalizados no interior do diretório src/Acme/DemoBundle/Resources/views/Form serão usados globalmente quando um formulário é renderizado.
Por padrão, a engine PHP usa um layout div ao renderizar formulários. Algumas pessoas, no entanto, podem preferir renderizar formulários em um layout de tabela. Para isso use o recurso FrameworkBundle:FormTable como layout:
Se você quer fazer a alteração somente em um template, adicione a seguinte linha em seu arquivo de template em vez de adicionar o template como um recurso:
<?php $view['form']->setTheme($form, array('FrameworkBundle:FormTable')); ?>
Note que a variável $form no código acima é a variável de visão do formulário que você passou para o seu template.
Até agora, você viu as diferentes maneiras que pode personalizar a saída dos widgets de todos os tipos de campo texto. Você também pode personalizar campos individuais. Por exemplo, supondo que você tenha dois campos text - first_name e last_name - mas você só quer personalizar um dos campos. Isto pode ser feito pela personalização de um fragmento cujo nome é uma combinação do atributo id do campo e qual parte do campo está sendo personalizada. Por exemplo:
Aqui, o fragmento _product_name_widget define o template a ser usado para o campo cujo id é product_name (e o nome é product[name]).
Tip
A parte product do campo é o nome do formulário, que pode ser definido manualmente ou gerado automaticamente com base no nome do tipo de formulário (por exemplo, ProductType equivale ao product). Se você não tem certeza de qual é o nome de seu formulário, apenas visualize o código fonte do formulário gerado.
Você também pode sobrescrever a marcação de uma linha inteira de campo utilizando o mesmo método:
Até agora, esta receita tem demonstrado diversas maneiras de personalizar um único pedaço de como um formulário é renderizado. A chave é personalizar um fragmento específico que corresponde à parte do formulário que você deseja controlar (veja naming form blocks).
Nas próximas seções, você vai ver como é possível fazer várias personalizações comuns de formulário. Para aplicar essas personalizações, utilize um dos métodos descritos na seção Tematizando os Formulários.
Note
O componente de formulário só lida com como os erros de validação são renderizados, e não com as mensagens de erro de validação. As mensagens de erro em si são determinadas pelas restrições de validação que você aplicou aos seus objetos. Para mais informações, consulte o capítulo sobre validation.
Há muitas formas diferentes para personalizar como os erros são renderizados quando um formulário é enviado com erros. As mensagens de erro para um campo são renderizadas quando você usa o helper form_errors:
Por padrão, os erros são renderizados dentro de uma lista não ordenada:
<ul>
<li>This field is required</li>
</ul>
Para sobrecrever como os erros são renderizados para todos os campos, basta copiar, colar e personalizar o fragmento field_errors.
Tip
Veja Tematizando os Formulários para saber como aplicar essa personalização.
Você também pode personalizar a saída de erro de apenas um tipo de campo específico. Por exemplo, certos erros que são mais globais para o seu formulário (ou seja, não específico para apenas um campo) são renderizados separadamente, geralmente no topo do seu formulário:
Para personalizar apenas a marcação usada para esses erros, siga as mesmas instruções acima, mas agora chame o bloco form_errors (Twig) / o arquivo form_errors.html.php (PHP). Agora, quando os erros para o tipo form são renderizados, o seu fragmento personalizado será usado em vez do padrão field_errors.
Quando você pode gerenciá-lo, a maneira mais fácil de renderizar um campo de formulário é através da função form_row, que renderiza a label, os erros e o widget HTML de um campo. Para personalizar a marcação usada para renderizar todas as linhas de campo do formulário, sobrescreva o fragmento field_row. Por exemplo, suponha que você deseja adicionar uma classe para o elemento div que envolve cada linha:
Tip
Veja Tematizando os Formulários para saber como aplicar essa personalização.
Se você quiser indicar todos os seus campos obrigatórios com um asterisco (*), você pode fazer isso personalizando o fragmento field_label.
No Twig, se você estiver fazendo a personalização de formulário dentro do mesmo template que o seu formulário, modifique a tag use e adicione o seguinte:
{% use 'form_div_layout.html.twig' with field_label as base_field_label %}
{% block field_label %}
{{ block('base_field_label') }}
{% if required %}
<span class="required" title="This field is required">*</span>
{% endif %}
{% endblock %}
No Twig, se você estiver fazendo a personalização do formulário dentro de um template separado, use o seguinte:
{% extends 'form_div_layout.html.twig' %}
{% block field_label %}
{{ parent() }}
{% if required %}
<span class="required" title="This field is required">*</span>
{% endif %}
{% endblock %}
Ao usar o PHP como template engine você tem que copiar o conteúdo do template original:
<!-- field_label.html.php -->
<!-- original content -->
<label for="<?php echo $view->escape($id) ?>" <?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape($view['translator']->trans($label)) ?></label>
<!-- customization -->
<?php if ($required) : ?>
<span class="required" title="This field is required">*</span>
<?php endif ?>
Tip
Veja Tematizando os Formulários para saber como aplicar essa personalização.
Você também pode personalizar os widgets do formulário para ter uma mensagem opcional de “ajuda”.
No Twig, se você está fazendo a personalização do formulário dentro do mesmo template que o seu formulário, modifique a tag use e adicione o seguinte:
{% use 'form_div_layout.html.twig' with field_widget as base_field_widget %}
{% block field_widget %}
{{ block('base_field_widget') }}
{% if help is defined %}
<span class="help">{{ help }}</span>
{% endif %}
{% endblock %}
No Twig, se você está fazendo a personalização do formulário dentro de um template separado, use o seguinte:
{% extends 'form_div_layout.html.twig' %}
{% block field_widget %}
{{ parent() }}
{% if help is defined %}
<span class="help">{{ help }}</span>
{% endif %}
{% endblock %}
Ao usar o PHP como template engine você tem que copiar o conteúdo do template original:
<!-- field_widget.html.php -->
<!-- Original content -->
<input
type="<?php echo isset($type) ? $view->escape($type) : "text" ?>"
value="<?php echo $view->escape($value) ?>"
<?php echo $view['form']->renderBlock('attributes') ?>
/>
<!-- Customization -->
<?php if (isset($help)) : ?>
<span class="help"><?php echo $view->escape($help) ?></span>
<?php endif ?>
Para renderizar uma mensagem de ajuda abaixo de um campo, passe em uma variável help:
Tip
Veja:ref:cookbook-form-theming-methods para saber como aplicar essa personalização.
A maioria das funções disponíveis para renderizar diferentes partes de um formulário (por exemplo, o widget de formulário, a label do formulário, os erros de formulário, etc) também permitem que você faça certas personalizações diretamente. Veja o exemplo a seguir:
O array passado como segundo argumento contém “variáveis” de formulário. Para mais detalhes sobre este conceito no Twig, veja twig-reference-form-variables.