Author: domluc
Date: 2010-01-29 20:14:05 +0100 (Fri, 29 Jan 2010)
New Revision: 27312

Added:
   doc/branches/1.4/more-with-symfony/pt/06-Advanced-Forms.markdown
Log:
[1.4][doc] Advanced Froms PT translate

Added: doc/branches/1.4/more-with-symfony/pt/06-Advanced-Forms.markdown
===================================================================
--- doc/branches/1.4/more-with-symfony/pt/06-Advanced-Forms.markdown            
                (rev 0)
+++ doc/branches/1.4/more-with-symfony/pt/06-Advanced-Forms.markdown    
2010-01-29 19:14:05 UTC (rev 27312)
@@ -0,0 +1,1001 @@
+Formulários Avançados
+=====================
+
+* por Ryan Weaver, Fabien potencier *
+
+O framework de formulários do Symfony prepara o desenvolvedor com as 
ferramentas 
+necessárias para facilmente processar e validar os dados do formulário de uma 
+formulário orientada a objeto. Graças as classes ~`sfFormDoctrine`~ and 
~`sfFormPropel`~ 
+o ferecidas por cada ORM, o framework de formulários pode facilmente mostrar e 
+salvar formulários que estão intimamente relacionados a camada de dados.
+
+Situações do mundo real, porém, muitas vezes exigem ao desenvolvedor 
personalizar
+e estender os formulários. Neste capítulo iremos apresentar e resolver várias 
comuns 
+e desafiadores problemas de formulários. Também vamos dissecar o objeto 
~`sfForm`~ e
+remover alguns de seus mistérios.
+
+Mini-Projeto: Produtos & Fotos
+-------------------------------
+
+O primeiro problema gira em torno da edição de um produto individual e um
+número ilimitado de fotos para esse produto. O usuário deve ser capaz de editar
+tanto o produto e fotos do produto no mesmo formulário. Nós também precisamos
+permiter ao usuário fazer upload de até duas fotos novas do produto de cada 
vez.
+Aqui está um possível esquema:
+
+    [yml]
+    Product:
+      columns:
+        name:           { type: string(255), notnull: true }
+        price:          { type: decimal, notnull: true }
+
+                ProductPhoto:
+      columns:
+        product_id:     { type: integer }
+        filename:       { type: string(255) }
+        caption:        { type: string(255), notnull: true }
+      relations:
+        Product:
+          alias:        Product
+          foreignType:  many
+          foreignAlias: Photos
+          onDelete:     cascade
+
+Quando concluído, o formulário será parecido com isto:
+
+![Formulário de Produto e 
Foto](http://www.symfony-project.org/images/more-with-symfony/advanced_forms_01.png
 "Form de Produto com form ProductPhoto inserido")
+
+Saiba mais fazendo o Exemplos
+--------------------------------
+
+A melhor maneira de aprender técnicas avançadas é acompanhar e testar o 
exemplos
+passo a passo. Graças ao recurso `--installer` do [symfony](#chapter_03), nós 
+fornecemos uma maneira simples para você criar um projeto funcional com um 
banco de 
+dados SQLite, o esquema do banco Doctrine, algumas fixtures, uma aplicação 
`frontend`
+e um módulo `produto` para trabalhar.
+Baixe o instalador
+[script] 
(http://www.symfony-project.org/images/more-with-symfony/advanced_form_installer.php.src)
+e executar o seguinte comando para criar o projeto symfony:
+
+    $ php symfony generate:project advanced_form 
--installer=/path/to/advanced_form_installer.php
+
+Este comando cria um projeto totalmente funcional com o esquema de banco de 
dados 
+que temos haviamos introduzido na seção anterior.
+
+>**NOTA**
+>Neste capítulo, os caminhos de arquivo são para um projeto symfony rodando 
com o
+>Doctrine, como gerado na tarefa anterior.
+
+Configuração básica de Formulário
+--------------------------------
+
+Como os requisitos envolvem mudanças de dois modelos diferentes ( `Product`
+e `ProductPhoto`), a solução terá de incorporar dois diferentes formulários
+symfony ( `ProductForm` e `ProductPhotoForm`). Felizmente, o framework de 
+formulário pode facilmente combinar múltiplas forms em uma via 
~`sfForm::embedForm()`~.
+Primeiramente, a configuração do `ProductPhotoForm` de formulário 
independente.  
+Neste exemplo, vamos usar o campo `filename` como um campo de upload de 
arquivo:
+
+    [php]
+    // lib/form/doctrine/ProductPhotoForm.class.php
+    public function configure()
+    {
+      $this->useFields(array('filename', 'caption'));
+
+      $this->setWidget('filename', new sfWidgetFormInputFile());
+      $this->setValidator('filename', new sfValidatorFile(array(
+        'mime_types' => 'web_images',
+        'path' => sfConfig::get('sf_upload_dir').'/products',
+      )));
+    }
+
+Para este formulário, tanto os campos `caption` quanto `filename` são 
automaticamente
+requeridos, mas por razões diferentes. O campo `caption` é necessária porque
+a coluna relacionada no esquema do banco de dados foi definida com um `não 
nulo`.
+O campo `filename` é requerido por padrão porque um objeto validador padrão 
pede.
+
+>**NOTA**
+>~`sfForm::useFields()`~ é uma nova função no symfony 1.3 que permite que o
+>desenvolvedor especifique exatamente quais os campos do formulário deve usar 
e em que
+>ordem que deve ser exibido. Todos os outros campos não ocultos são removidos
+>do formulário.
+
+Até agora nós não fizemos nada mais do que a configuração de formulário 
simples. 
+A seguir, vamos combinar os formulários em um.
+
+Embutindo Formulários
+---------------------
+
+Ao utilizar ~`sfForm::embedForm()`~, o `ProductForm` e `ProductPhotoForms` 
+podem ser combinados com um esforço muito pequeno. O trabalho é sempre feito
+na *formulário* principal, que neste caso é `ProductForm`. O requisito é a 
+capacidade de enviar até duas fotos do produto de uma vez.
+Para realizar isso, inserir dois objetos `ProductPhotoForm` no `ProductForm`:
+
+    [php]
+    // lib/form/doctrine/ProductForm.class.php
+    public function configure()
+    {
+      $subForm = new sfForm();
+      for ($i = 0; $i < 2; $i++)
+      {
+        $productPhoto = new ProductPhoto();
+        $productPhoto->Product = $this->getObject();
+
+        $form = new ProductPhotoForm($productPhoto);
+
+        $subForm->embedForm($i, $form);
+      }
+      $this->embedForm('newPhotos', $subForm);
+    }
+
+Se você apontar seu navegador para o módulo `product`, agora você pode fazer de
+upload de dois `ProductPhoto`, bem como modificar o próprio objeto `Product`.
+
+O Symfony salva automaticamente os novos objetos `ProductPhoto` relacionaeles
+ao objeto correspondente `Product`. Mesmo o upload do arquivo, definido em
+`ProductPhotoForm`, executa normalmente.
+
+Verifique se os registros são salvos corretamente no banco de dados:
+
+    $ php symfony doctrine:dql --table "FROM Product"
+    $ php symfony doctrine:dql --table "FROM ProductPhoto"
+
+Na tabela `ProductPhoto`, você vai notar os nomes das fotos.
+Tudo está funcionando como esperado se você pode encontrar arquivos com os 
mesmos nomes
+do banco de dados no diretório `web/upload/products/`.
+
+> ** NOTA **
+> Porque o nome do arquivo e campos da legenda são necessários 
`ProductPhotoForm»,
+> validação do formulário principal será sempre a não ser que o usuário está 
carregando
+> duas novas fotos. Continue lendo para saber como corrigir este problema.
+
+Re-fatoração(Refactoring)
+--------------------------
+
+Mesmo o formulário anterior funcionando como esperado, seria interessante 
refatorar
+o código para facilitar os testes e para permitir que o código seja facilmente 
reutilizado.
+
+Primeiro, vamos criar um novo formulário que representa uma coleção de
+`ProductPhotoForm`s, com base no código já foi escrito:
+
+    [php]
+    // lib/form/doctrine/ProductPhotoCollectionForm.class.php
+    class ProductPhotoCollectionForm extends sfForm
+    {
+      public function configure()
+      {
+        if (!$product = $this->getOption('product'))
+        {
+          throw new InvalidArgumentException('You must provide a product 
object.');
+        }
+
+        for ($i = 0; $i < $this->getOption('size', 2); $i++)
+        {
+          $productPhoto = new ProductPhoto();
+          $productPhoto->Product = $product;
+
+          $form = new ProductPhotoForm($productPhoto);
+
+          $this->embedForm($i, $form);
+        }
+      }
+    }
+
+Este formulário tem duas opções:
+
+ * `product`: O produto qual se cria uma coleção de
+   `ProductPhotoForm`s;
+
+ * `size`: O número de `ProductPhotoForm`s a ser criado (duas por padrão).
+
+Agora você pode alterar o método de configuração do `ProductForm` como a 
seguir:
+
+    [php]
+    // lib/form/doctrine/ProductForm.class.php
+    public function configure()
+    {
+      $form = new ProductPhotoCollectionForm(null, array(
+        'product' => $this->getObject(),
+        'size'    => 2,
+      ));
+
+      $this->embedForm('newPhotos', $form);
+    }
+
+Dissecando o objeto sfForm
+----------------------------
+
+No sentido mais básico, um formulário da web é uma coleção de campos que são 
processados
+e enviados de volta para o servidor. No mesmo caminho, o objeto ~`sfForm`~  é
+essencialmente um array de *campos* de formulário. Enquanto ~`sfForm`~ 
gerencia o processo,
+os campos individuais são responsáveis por definir o modo como cada um será 
processado
+e validado.
+
+No symfony, cada campo de formulário * * é definida por dois objetos 
diferentes:
+
+  * Um *widget* que controla a marcação XHTML do campo;
+
+  * Um *validator* que limpa e valida os dados enviados
+
+>**Dica**
+>No symfony, um *widget* é definida como qualquer objeto cujo único trabalho é 
saída
+>em marcação XHTML. Embora mais comumente usados com formulários, um objeto 
Widget
+>poderia ser criado para mostrar qualquer marcação.
+
+### Um formulário é um array
+
+Lembre-se que o objeto ~`sfForm`~ é "essencialmente um array de *campos* de 
formulário."
+Para ser mais preciso, `sfForm` guarda tanto um array de elementos como um 
array
+de validadores para todos os campos do formulário. Estes dois arrays, chamados
+`widgetSchema` e `validatorSchema` são propriedades da classe `sfForm`.
+A fim de adicionar um campo a um formulário, basta adicionar o campo do widget 
para o
+array `widgetSchema` e o validador do campo para a array `validatorSchema`.
+Por exemplo, o código a seguir adiciona um campo `email` para um formulário:
+
+    [php]
+    public function configure()
+    {
+      $this->widgetSchema['email'] = new sfWidgetFormInputText();
+      $this->validatorSchema['email'] = new sfValidatorEmail();
+    }
+
+>**NOTA**
+>Os arrays `widgetSchema` e `validatorSchema` são na verdade classes especiais
+>chamadas ~`sfWidgetFormSchema`~ e ~`sfValidatorSchema`~ que implementam a
+>interface `ArrayAccess`.
+
+### Dissecando o `ProductForm`
+
+Como em ultima estância a classe `ProductForm` estende a `sfForm`, ela também 
abriga todos os
+seus widgets e validadores nos arrays `widgetSchema` e `validatorSchema`.
+Vamos analisar como cada array é organizado no objeto final `ProductForm`.
+
+    [php]
+    widgetSchema    => array
+    (
+      [id]          => sfWidgetFormInputHidden,
+      [name]        => sfWidgetFormInputText,
+      [price]       => sfWidgetFormInputText,
+      [newPhotos]   => array(
+        [0]           => array(
+          [id]          => sfWidgetFormInputHidden,
+          [filename]    => sfWidgetFormInputFile,
+          [caption]     => sfWidgetFormInputText,
+        ),
+        [1]           => array(
+          [id]          => sfWidgetFormInputHidden,
+          [filename]    => sfWidgetFormInputFile,
+          [caption]     => sfWidgetFormInputText,
+        ),
+      ),
+    )
+
+    validatorSchema => array
+    (
+      [id]          => sfValidatorDoctrineChoice,
+      [name]        => sfValidatorString,
+      [price]       => sfValidatorNumber,
+      [newPhotos]   => array(
+        [0]           => array(
+          [id]          => sfValidatorDoctrineChoice,
+          [filename]    => sfValidatorFile,
+          [caption]     => sfValidatorString,
+        ),
+        [1]           => array(
+          [id]          => sfValidatorDoctrineChoice,
+          [filename]    => sfValidatorFile,
+          [caption]     => sfValidatorString,
+        ),
+      ),
+    )
+
+>**Dica**
+>Assim como `widgetSchema` e `validatorSchema` são na verdade  objetos que se 
comportam
+>como arrays, as arrays acima definidos pelas chaves `newPhotos`, `0` e `1`
+>Também são objetos `sfWidgetSchema` e `sfValidatorSchema`.
+
+Como esperado, os campos básicos ( `id`, `name` e `price`) estão representados 
no primeiro
+nível de cada array. Em um formulário que não incorpora outros formulário, os 
arrays `widgetSchema` 
+e `validatorSchema` têm apenas um nível, que representa os campos básicos no 
formulário.
+Os widgets e validadores de qualquer formulário incorporados são representados 
como arrays filhos
+em `widgetSchema` e `validatorSchema` como visto acima. 
+O métodoque gere este processo é explicado a seguir.
+
+### Por trás de ~`sfForm::embedForm()`~
+
+Tenha em mente que um formulário é composto por uma variedade de widgets e um 
conjunto de
+validadores. Incorporação de um formulário em outro, essencialmente, significa 
que o 
+arrays de widget e validador de um formulário são adicionados aos array de 
widgets
+e validadores do formulário principal. Isto é inteiramente realizado via
+`sfForm::embedForm()`. O resultado é sempre uma adição multi-dimensional em 
`widgetSchema` 
+e `validatorSchema` como visto acima.
+
+A seguir, vamos discutir a configuração do `ProductPhotoCollectionForm`, que 
liga
+objetos `ProductPhotoForm` em si. Essa formulário meio age como um "wrapper" 
de formulário
+e contribui com a organização de forma global. Vamos começar com o seguinte 
código
+de `ProductPhotoCollectionForm::configure()`:
+
+    [php]
+    $form = new ProductPhotoForm($productPhoto);
+    $this->embedForm($i, $form);
+
+O próprio formulário `ProductPhotoCollectionForm` começa como um novo objeto 
`sfForm`.
+Como tal, seus arrays `widgetSchema` e `validatorSchema` estão vazias.
+
+    [php]
+    widgetSchema    => array()
+    validatorSchema => array()
+
+Cada `ProductPhotoForm`, no entanto, já está preparada com três campos (`id`, 
`filename`,
+e `caption`) e três itens correspondentes em seu `widgetSchema` e 
`validatorSchema`.
+
+
+    [php]
+    widgetSchema    => array
+    (
+      [id]            => sfWidgetFormInputHidden,
+      [filename]      => sfWidgetFormInputFile,
+      [caption]       => sfWidgetFormInputText,
+    )
+
+    validatorSchema => array
+    (
+      [id]            => sfValidatorDoctrineChoice,
+      [filename]      => sfValidatorFile,
+      [caption]       => sfValidatorString,
+    )
+
+O método ~`sfForm::embedForm()`~ simplesmente adiciona os arrays 
`widgetSchema` e `validatorSchema`
+de cada `ProductPhotoForm` aos arrays `widgetSchema` e `validatorSchema`
+do objeto `ProductPhotoCollectionForm` vazio.
+
+Quando terminar, os arrays `widgetSchema` e `validatorSchema` do formulário
+"wrapper" (`ProductPhotoCollectionForm`) serão arrays multi-nível que mantem os
+widgets e validadores de ambos os`ProductPhotoForm`.
+
+    [php]
+    widgetSchema    => array
+    (
+      [0]             => array
+      (
+        [id]            => sfWidgetFormInputHidden,
+        [filename]      => sfWidgetFormInputFile,
+        [caption]       => sfWidgetFormInputText,
+      ),
+      [1]             => array
+      (
+        [id]            => sfWidgetFormInputHidden,
+        [filename]      => sfWidgetFormInputFile,
+        [caption]       => sfWidgetFormInputText,
+      ),
+    )
+
+    validatorSchema => array
+    (
+      [0]             => array
+      (
+        [id]            => sfValidatorDoctrineChoice,
+        [filename]      => sfValidatorFile,
+        [caption]       => sfValidatorString,
+      ),
+      [1]             => array
+      (
+        [id]            => sfValidatorDoctrineChoice,
+        [filename]      => sfValidatorFile,
+        [caption]       => sfValidatorString,
+      ),
+    )
+
+Na etapa final do nosso processo, a formulário "wrapper" resultante,
+`ProductPhotoCollectionForm`, é encaixado(`embedded`) diretamente no 
`ProductForm`.
+Isso ocorre dentro de `ProductForm::configure()`, que tira proveito de
+todo o trabalho que foi feito dentro de `ProductPhotoCollectionForm`:
+
+    [php]
+    $form = new ProductPhotoCollectionForm(null, array(
+      'product' => $this->getObject(),
+      'size'    => 2,
+    ));
+
+    $this->embedForm('newPhotos', $form);
+
+Isso nos dá a estrutura final dos arrays `widgetSchema` e `validatorSchema`
+vista acima. Observe que o método `embedForm()` é muito parecido com o simples
+ato de combinar os arrays `widgetSchema` e `validatorSchema` manualmente:
+
+    [php]
+    $this->widgetSchema['newPhotos'] = $form->getWidgetSchema();
+    $this->validatorSchema['newPhotos'] = $form->getValidatorSchema();
+
+Renderizando formulários incorporados na Visão
+----------------------------------------------
+
+O template atual `_form.php` do modelo do `produto` é parecido com o
+seguinte:
+
+    [php]
+    // apps/frontend/module/product/templates/_form.php
+    <!-- ... -->
+
+    <tbody>
+      <?php echo $form ?>
+    </tbody>
+
+    <!-- ... -->
+
+A declaração `<?php echo $ form?>` é a maneira mais simples de mostrar um 
formulário,
+mesmo os mais complexos. São de grande ajuda durante a prototipagem, mas logo
+que você desejar alterar o layout, sera necessário substituí-lo com sua própria
+lógica. Remova esta linha agora, ja que iremos substituí-la nesta seção.
+
+A coisa mais importante para compreender quando renderizando formulários 
incorporadas no
+ponto de vista é a organização do multi-nível do array `widgetSchema` como 
explicado
+nas seções anteriores. Para este exemplo, vamos começar renderizando os campos 
básicos
+`name` e `price` do ProductForm` na visão:
+
+    [php]
+    // apps/frontend/module/product/templates/_form.php
+    <?php echo $form['name']->renderRow() ?>
+
+    <?php echo $form['price']->renderRow() ?>
+
+    <?php echo $form->renderHiddenFields() ?>
+
+Como o próprio nome indica, o `renderHiddenFields()` processa todos os campos 
ocultos
+do formulário.
+
+>**NOTA**
+>O código da actions não foi mostrado propositadamente aqui, porque não requer 
especial
+>atenção. Dê uma olhada no arquivo 
`apps/frontend/modules/product/actions/actions.class.php`.
+>É como qualquer CRUD normal e pode ser gerado automaticamente via
+>a tarefa(task) `doctrine:generate-module`.
+
+Como já aprendemos, a classe `sfForm` guarda os arrays `widgetSchema` e 
+`validatorSchema` que definem os nossos campos. Além disso, a classe `sfForm`
+implementa a interface `ArrayAccess`, nativa do PHP 5, o que significa que 
pode acessar diretamente
+campos do formulário usando a sintaxe chave array vista acima.
+
+Para a saída de campos, você pode simplesmente acessá-los diretamente e chamar 
o método
+`renderRow()`. Mas que tipo de objeto é `$form['name']`? Enquanto você pôde 
esperar
+que a resposta seja um `sfWidgetFormInputText` para o campo `name`,
+A resposta é realmente algo um pouco diferente.
+
+### Renderizando cada campo de formulário com ~`sfFormField`~
+
+Ao utilizar os arrays `widgetSchema` e `validatorSchema` definidos em cada 
+classe de formulário, `sfForm` gera automaticamente um terceiro array chamado
+`sfFormFieldSchema`. Esta array contém um objeto especial para cada campo
+que atua como uma classe auxiliar responsável pela saída do campo. 
+O objeto, do tipo ~`sfFormField`~, é uma combinação de cada elemento de campo
+e de validação e é criado automaticamente.
+
+    [php]
+    <?php echo $form['name']->renderRow() ?>
+
+No trecho acima, `$form['name']` é um objeto `sfFormField`, que abriga
+o método `renderRow()` junto com diversas outras funções de processamento útil.
+
+### Métodos de renderização do sfFormField 
+
+Cada objeto `sfFormField pode ser usado para facilmente tornar cada aspecto do 
campo
+que representa (por exemplo, o próprio campo, o rótulo, mensagens de erro, 
etc.)
+Alguns dos métodos úteis dentro sfFormField `` incluem o seguinte. Outro:
+podem ser encontrados através do [symfony 1,3 API] 
http://www.symfony-project.org/api/1_3/sfFormField ().
+
+ * `sfFormField->render()`: Processa o campo do formulário (por exemplo, 
`input`, `select`)
+   com o valor correto usando o objeto widget do campo.
+
+ * `sfFormField->renderError()`: Processa quaisquer erros de validação no campo
+   usando o objeto validador do campo.
+
+ * `sfFormField->renderRow()`: Tudo-englobado: renderiza o rótulo, o formulário
+   o campo, o erro e a mensagem de ajuda dentro de um invólucro de marcação 
XHTML.
+
+>**NOTA**
+>Na realidade, cada função de renderização da classe `sfFormField` também 
utiliza informação
+>a partir da propriedade `widgetSchema` do formulário( o objeto 
`sfWidgetFormSchema` que
+>agrega todos os widgets para o formulário). Esta classe auxilia na geração
+>dos atributos de cada campo `name` e `id`, controla o rótulo para cada
+>campo, e define a marcação XHTML usada com `renderRow()`.
+
+Uma coisa importante a notar é que o array `formFieldSchema` sempre
+espelha a estrutura do arrays `widgetSchema` e `validatorSchema` 
+do formulário. Por exemplo, o array `formFieldSchema` do `ProductForm` 
+concluído teria a seguinte estrutura, que é a chave para renderizar cada
+campo na visão:
+
+    [php]
+    formFieldSchema    => array
+    (
+      [id]          => sfFormField
+      [name]        => sfFormField,
+      [price]       => sfFormField,
+      [newPhotos]   => array(
+        [0]           => array(
+          [id]          => sfFormField,
+          [filename]    => sfFormField,
+          [caption]     => sfFormField,
+        ),
+        [1]           => array(
+          [id]          => sfFormField,
+          [filename]    => sfFormField,
+          [caption]     => sfFormField,
+        ),
+      ),
+    )
+
+### Renderizando novo ProductForm
+
+Usando a tabela acima como o nosso mapa, podemos saída facilmente incorporadas 
`` ProductPhotoForm
+campos na vista por localizar e tornar o bom `` sfFormField objetos:
+
+    [php]
+    // apps/frontend/module/product/templates/_form.php
+    <?php foreach ($form['newPhotos'] as $photo): ?>
+      <?php echo $photo['caption']->renderRow() ?>
+      <?php echo $photo['filename']->renderRow() ?>
+    <?php endforeach; ?>
+
+O bloco acima loops duas vezes: uma para o `0` array campo formulário e
+uma vez para o `1` array campo de formulário. Como visto no diagrama acima,
+os objetos subjacentes de cada array são `` sfFormField os objetos, que podemos
+saída como quaisquer outros campos.
+
+Saving Objeto Formulários
+-------------------
+
+Na maioria das circunstâncias, uma formulário que se relacionam diretamente a 
um ou mais banco de dados
+tabelas e provocar alterações de dados nas tabelas apresentadas com base no
+valores. Symfony gera automaticamente um objeto de formulário para um modelo 
de esquema,
+que se estende tanto sfFormDoctrine `` ou `` sfFormPropel dependendo da sua
+ORM. Cada classe de formulário semelhante e, finalmente, permite que os 
valores apresentados
+ser facilmente mantido no banco de dados.
+
+> ** NOTA **
+> ~ `` ~ sfFormObject é uma nova classe adicionada no symfony 1,3 para tratar 
de todos os
+> tarefas comuns sfFormDoctrine do `` e `` sfFormPropel. Cada classe se estende
+> `sfFormObject», que agora administra parte do formulário de poupança 
processo descrito abaixo.
+
+# # # O Formulário de processo de gravação
+
+No nosso exemplo, o symfony automaticamente salva tanto o «produto de 
informulárioção» e
+`novo` ProductPhoto objetos sem qualquer esforço adicional por parte do 
desenvolvedor.
+O método que dispara a magia, ~ `sfFormObject:: save ()`~, executa uma 
variedade
+de métodos nos bastidores. Entender este processo é fundamental para a 
prorrogação
+o processo em situações mais avançadas.
+
+A formulário de poupança processo consiste em uma série de métodos 
internamente executado,
+tudo o que acontece depois de chamar ~ `sfFormObject:: save ()`~. A maioria
+do trabalho está envolto na ~ `sfFormObject:: UpdateObject ()` ~ método, que
+é chamado recursivamente em todas as suas formulários incorporado.
+
+! [Forma processo de gravação] 
(http://www.symfony-project.org/images/more-with-symfony/advanced_forms_06.png 
"formulário pormenorizada processo de gravação")
+
+> ** NOTA **
+> A maioria do processo de poupança ocorre dentro do ~ `sfFormObject:: DoSave 
()` ~
+> método, que é chamado pelo `sfFormObject:: save ()` e envolto em um banco de 
dados
+> transação. Se você precisar modificar o processo de poupança própria, 
`sfFormObject:: DoSave ()`
+> geralmente é o melhor lugar para fazê-lo.
+
+Ignorando as Formas Embedded
+-----------------------
+
+O actual ProductForm `` implementação tem um grande déficit. Porque o
+`filename` e `` legenda campos são obrigatórios em `ProductPhotoForm», 
validação
+do formulário principal será sempre a não ser que o usuário enviar duas novas 
fotos.
+Em outras palavras, o usuário não pode simplesmente mudar o preço do produto 
»,« sem
+também estão sendo obrigados a carregar duas novas fotos.
+
+! [Tipo de produto não validação foto] 
(http://www.symfony-project.org/images/more-with-symfony/advanced_forms_04.png 
tipo de produto "falha de validação nas fotos")
+
+Vamos redefinir os requisitos para incluir o seguinte. Se o usuário deixa
+todos os campos de um `` ProductPhotoForm em branco, que formulário deve ser 
ignorado
+completamente. No entanto, se pelo menos um campo tem dados (ou seja, legenda 
`` ou `filename`),
+o formulário deve validar e salvar normalmente. Para conseguir isso, vamos 
contratar
+uma técnica avançada que envolvam a utilização de um posto de validação 
personalizado.
+
+O primeiro passo, no entanto, é modificar o `ProductPhotoForm« formulário de 
tornar o
+`legenda` e `filename` campos opcionais:
+
+    [php]
+    / / Lib / form / doutrina / ProductPhotoForm.class.php
+    public function configure ()
+    (
+      $ this-setValidator> ( 'sfValidatorFile filename', novo (array (
+        'mime_types' => 'web_images',
+        'path' => sfConfig:: get ( 'sf_upload_dir').'/ produtos,
+        'required' => false,
+      )));
+
+      $ this-> validatorSchema [ 'legenda'] - setOption> ( 'required', false);
+    )
+
+No código acima, temos que definir a opção `` necessários para quando «falso»
+substituindo o validador padrão para o `campo` filename. Além disso,
+temos definir explicitamente a opção `` necessário `legenda do campo» a 
«falsa».
+
+Agora, vamos adicionar o validador após a ProductPhotoCollectionForm `:
+
+    [php]
+    / / Lib / form / doutrina / ProductPhotoCollectionForm.class.php
+    public function configure ()
+    (
+      / / ...
+
+      mergePostValidator $ this-> (ProductPhotoValidatorSchema novo ());
+    )
+
+Um validador post é um tipo especial de validação que valida em todas as
+os valores apresentados (em oposição ao validar o valor de um campo único).
+Um dos validadores post mais comum é o `que` sfValidatorSchemaCompare
+verifica, por exemplo, que uma área é inferior a outro campo.
+
+# # # Criando um validador personalizado
+
+Felizmente, criando um validador personalizado é realmente muito fácil. Crie 
uma
+novo arquivo, `ProductPhotoValidatorSchema.class.php» e colocá-lo no
+`validador / lib /` (você precisa criar este diretório):
+
+    [php]
+    / Lib validador / ProductPhotoValidatorSchema.class.php
+    classe ProductPhotoValidatorSchema estende sfValidatorSchema
+    (
+      protected function configure ($ options = array (), $ messages = array 
())
+      (
+        $ this-> addMessage ( 'caption', 'A legenda é necessária. ");
+        $ this-> addMessage ( 'filename', 'O nome é obrigatório. ");
+      )
+
+      protegidos Doclean função ($ valores)
+      (
+        errorSchema $ = sfValidatorErrorSchema novo ($ this);
+
+        foreach ($ valores as $ chave => $ value)
+        (
+          $ errorSchemaLocal sfValidatorErrorSchema = new ($ this);
+
+          / / Nome do arquivo é preenchido, mas nenhuma legenda
+          if ($ valor [ 'filename'] & &!$ value [ 'legenda'])
+          (
+            $ errorSchemaLocal-> addError sfValidatorError (novo ($ this, 
'required'), 'caput');
+          )
+
+          / / Legenda é preenchido, mas nenhum nome de arquivo
+          if ($ valor [ 'caption'] & &!$ value [ 'filename'])
+          (
+            $ errorSchemaLocal-> addError sfValidatorError (novo ($ this, 
'required'), 'filename');
+          )
+
+          / / Sem legenda e não nome do arquivo, remova os valores vazios
+          if (!$ value [ 'filename'] & &!$ value [ 'legenda'])
+          (
+            unset ($ values [$ key]);
+          )
+
+          / / Algum erro para este incorporado em formulário
+          if (count ($ errorSchemaLocal))
+          (
+            errorSchema $-> addError ($ errorSchemaLocal, (string) $ key);
+          )
+        )
+
+        / / Gera o erro para o formulário principal
+        if (count ($ errorSchema))
+        (
+          throw sfValidatorErrorSchema novo (errorSchema $ this, $);
+        )
+
+        return $ valores;
+      )
+    )
+
+> ** Dica **
+> Todos os validadores estender `sfValidatorBase» e exigem apenas o Doclean 
`()`
+> método. O configure () `método também pode ser utilizado para adicionar 
opções ou mensagem
+> validador. Neste caso, duas mensagens são adicionadas ao validador.
+> Da mesma formulário, opções adicionais podem ser adicionados através do 
addOption »()» método.
+
+O `Doclean ()» método é responsável pela limpeza e validação dos vinculados
+valores. A lógica do validador em si é bastante simples:
+
+* Se uma foto é apresentada apenas com o nome do arquivo ou uma legenda, 
jogamos um
+   erro ( `sfValidatorErrorSchema») com a mensagem adequada;
+
+* Se uma foto é apresentado com nenhum nome de arquivo e sem legenda, que 
remova o
+   valores completamente para evitar a salvar uma foto de vazio;
+
+* Se não ocorreram erros de validação, o método retorna a array de
+   valores limpos.
+
+> ** Dica **
+> Porque o validador personalizado nesta situação é para ser usado como um
+> validador post, o Doclean «()» método espera um array do limite
+> valores e retorna um array de valores limpos. Validadores personalizados, no 
entanto,
+> podem ser facilmente criados para campos individuais. Nesse caso, o
+> `Doclean ()» método irá esperar apenas um valor (o valor do apresentado
+> campo) e irá retornar apenas um valor.
+
+O último passo é substituir o saveEmbeddedForms »()» método de «ProductForm`
+para remover as formulários photo vazio de não salvar uma foto em branco no 
banco de dados (que
+caso contrário gera uma exceção como a legenda «coluna» é obrigatório):
+
+    [php]
+    saveEmbeddedForms função pública ($ con = null, $ formulário = null)
+    (
+      if (null === $ formulários)
+      (
+        fotos = $ this-> getValue ( 'newPhotos');
+        formulários = $ this-> embeddedForms;
+        foreach ($ this-> embeddedForms [ 'newPhotos'] as $ name => $ form)
+        (
+          if (!isset ($ fotos [$ name]))
+          (
+            unset ($ formulários [ 'newPhotos'] [$ name]);
+          )
+        )
+      )
+
+      return parent:: saveEmbeddedForms ($ con, $ formulários);
+    )
+
+Facilmente Embedding Doutrina-Formas Conexas
+---------------------------------------
+
+Novo no symfony 1,3 é a sfFormDoctrine ~ `:: embedRelation ()` ~ função que
+permite ao desenvolvedor incorporar n-para-muitos em um formulário
+automaticamente. Suponha, por exemplo, que além de permitir que o usuário
+upload dois novos `ProductPhotos», queremos também permitir ao usuário 
modificar o
+existente »ProductPhoto` objetos relacionados a este «produto».
+
+Em seguida, use o embedRelation »()» método para adicionar um adicional
+`` ProductPhotoForm objeto para cada existente »ProductPhoto» Objeto:
+
+    [php]
+    / / Lib / form / doutrina / ProductForm.class.php
+    public function configure ()
+    (
+      / / ...
+
+      $ this-embedRelation> ( 'Fotos');
+    )
+
+Internamente, sfFormDoctrine ~ `:: embedRelation ()` ~ é quase exatamente o 
que fizemos
+manualmente para inserir nossos dois novos `` ProductPhotoForm objetos. Se 
dois ProductPhoto ``
+relações já existem, então o resultado widgetSchema `` e `` validatorSchema
+de nossa formulário tomaria a seguinte forma:
+
+    [php]
+    widgetSchema => array
+    (
+      [id] => sfWidgetFormInputHidden,
+      [nome] = sfWidgetFormInputText>,
+      [preço] = sfWidgetFormInputText>,
+      [newPhotos] => array (...)
+      [Fotos] => array (
+        [0] => array (
+          [id] => sfWidgetFormInputHidden,
+          [legenda] = sfWidgetFormInputText>,
+        ),
+        [1] => array (
+          [id] => sfWidgetFormInputHidden,
+          [legenda] = sfWidgetFormInputText>,
+        ),
+      ),
+    )
+
+    validatorSchema => array
+    (
+      [ID] => sfValidatorDoctrineChoice,
+      [nome] => sfValidatorString,
+      [preço] = sfValidatorNumber>,
+      [newPhotos] => array (...)
+      [Fotos] => array (
+        [0] => array (
+          [ID] => sfValidatorDoctrineChoice,
+          [legenda] => sfValidatorString,
+        ),
+        [1] => array (
+          [id] => sfValidatorDoctrineChoice,
+          [legenda] => sfValidatorString,
+        ),
+      ),
+    )
+
+! [Produto formulário com 2 fotos existentes] 
(http://www.symfony-project.org/images/more-with-symfony/advanced_forms_03.png 
tipo de produto ", com 2 fotos existentes")
+
+A próxima etapa é adicionar código para o ponto de vista que irá processar o 
novo incorporado
+* Foto formulários *:
+
+    [php]
+    / Apps / frontend / módulo / produto / templates / _form.php
+    <?php foreach ($ form [ 'Photos'] as $ foto):?>
+      <?php echo $ foto [ 'legenda'] - RenderRow> ()?>
+      <?php echo $ foto [ 'filename'] -> RenderRow (array ( 'width' => 100))?>
+    <?php endif;?>
+
+Este trecho é exatamente o que usamos anteriormente para inserir as 
formulários nova foto.
+
+O último passo é converter o arquivo de upload por um campo que permite ao 
usuário
+Para ver a foto atual e mudá-lo por um novo
+( `sfWidgetFormInputFileEditable»):
+
+    [php]
+    public function configure ()
+    (
+      $ this-> useFields (array ( 'filename', 'caption'));
+
+      $ this-setValidator> ( 'sfValidatorFile arquivo', novo (array (
+        'mime_types' => 'web_images',
+        'path' => sfConfig:: get ( 'sf_upload_dir').'/ produtos,
+        'required' => false,
+      )));
+
+      $ this-setWidget> ( 'filename', nova série 
(sfWidgetFormInputFileEditable (
+        'file_src' => '/ uploads / produtos / ". $ this-> GetObject () - 
filename>,
+        'edit_mode' =>!$ this-> isNew (),
+        'is_image' => true,
+        'with_delete' => false,
+      )));
+
+      $ this-> validatorSchema [ 'legenda'] - setOption> ( 'required', false);
+    )
+
+Formulário de Eventos
+-----------
+
+Novo no symfony 1.3 são eventos de formulário que pode ser usado para estender 
qualquer formulário
+objeto de qualquer parte do projeto. Symfony expõe o seguinte formulário quatro
+Ocorrências:
+
+* `` Form.post_configure: Este evento é notificada após cada formulário está 
configurado
+* `` Form.filter_values: Este evento filtros da concentração, os parâmetros de 
arquivos contaminados e arrayes pouco antes da ligação
+* `` Form.validation_error: Este evento é notificado sempre que não validação 
do formulário
+* `` Form.method_not_found: Este evento é notificado sempre que um método 
desconhecido é chamado
+
+# # # Custom Logging via `` form.validation_error
+
+Usando a eventos de formulário, é possível adicionar registo personalizado 
para validação
+erros de qualquer formulário em seu projeto. Isto pode ser útil se você deseja 
acompanhar
+quais as formulários e os campos estão causando confusão para os usuários.
+
+Comece por registar um ouvinte com o despachante de eventos para o
+`form.validation_error evento». Adicionar o seguinte à instalação »()» método
+de «ProjectConfiguration`, que está localizado dentro do diretório `` config:
+
+    [php]
+    configuração da função pública ()
+    (
+      / / ...
+
+      $ this-getEventDispatcher> () -> connect (
+        'form.validation_error',
+        array ( 'BaseForm', 'listenToValidationError')
+      );
+    )
+
+`BaseForm», localizado em `lib / form`, é uma classe especial de formulário 
que todas as formas
+Aulas de estender. Essencialmente, o `BaseForm» é uma classe em que o código 
pode ser colocado
+e acessadas por todos os objetos de formulário através do projeto. Para 
activar o registo de
+erros de validação, basta adicionar o seguinte para o `BaseForm classe»:
+
+    [php]
+    listenToValidationError public static function ($ evento)
+    (
+      foreach ($ eventos [ 'error'] as $ key => $ erro)
+      (
+        self:: getEventDispatcher () -> notify (sfEvent novo (
+          $ event-> getSubject (),
+          'application.log',
+          array (
+            «prioridade» sfLogger =>:: COMUNICAÇÃO,
+            sprintf ( 'Erro de validação:% s:% s', $ key, (string) $ erro)
+          )
+        ));
+      )
+    )
+
+! [Registo de erros de validação] 
(http://www.symfony-project.org/images/more-with-symfony/advanced_forms_05.png 
"Web ferramentas de depuração de erros de validação")
+
+Custom Styling, quando um elemento de formulário tem um erro
+-----------------------------------------------
+
+Como exercício final, vamos voltar a um tema um pouco mais leve relacionados 
com a
+estilização de elementos de formulário. Suponha, por exemplo, que o projeto 
para o Produto `
+página inclui um estilo especial para campos que não conseguiram a validação.
+
+! [Produto formulário com erros] 
(http://www.symfony-project.org/images/more-with-symfony/advanced_forms_02.png 
tipo de produto "com campos de erro denominado")
+
+Suponha que o designer já implementou o estilo que será aplicado o erro
+denominar a qualquer campo `input` `dentro de uma div com a classe` `` 
form_error_row.
+Como podemos facilmente adicionar o `` form_row_error classe para os campos 
com erros?
+
+A resposta está em um objeto especial chamado * formuláriotador esquema forma 
*. Every
+formulário symfony usa um esquema de forma formatador * * para determinar a 
exata
+formuláriotação HTML para usar quando a saída de elementos do formulário. Por 
padrão o symfony,
+formuláriotador usa um formulário que utiliza tags HTML tabela.
+
+Primeiro, vamos criar uma nova formulário de classe formatador esquema que 
emprega pouco
+isqueiro marcação quando emitir o formulário. Criar um novo arquivo chamado
+`sfWidgetFormSchemaFormatterAc2009.class.php» e colocá-lo no
+`widget / lib /` (você precisa criar este diretório):
+
+    [php]
+    classe sfWidgetFormSchemaFormatterAc2009 estende 
sfWidgetFormSchemaFormatter
+    (
+      protegidos
+        $ rowFormat = "<div class=\"form_row\">
+                            %% marcador \ erro% n%%% <br/> campo
+                            ajuda%%%% hidden_fields \ n </ div> \ n ",
+        $ errorRowFormat = "<div>%% erros </ div>",
+        $ helpFormat = '<div class="form_help">%% de ajuda </ div>',
+        $ decoratorFormat = "<div> \% n% de conteúdo </ div>";
+    )
+
+Embora o formulárioto dessa classe é estranha, a idéia geral é que o RenderRow 
`()`
+método irá utilizar o `$` rowFormat marcação para organizar sua saída. Um 
esquema de formulário
+classe formuláriotador oferece muitas outras opções de formatação que não vou 
abordar aqui
+em detalhe. Forma mais informulárioções, consultar o
+[symfony 1,3 API] 
(http://www.symfony-project.org/api/1_3/sfWidgetFormSchemaFormatter).
+
+Para usar o formuláriotador novo esquema forma em todos os objetos de 
formulário no seu projeto,
+adicione o seguinte a `` ProjectConfiguration:
+
+    [php]
+    ProjectConfiguration classe estende sfProjectConfiguration
+    (
+      configuração da função pública ()
+      (
+        / / ...
+
+        sfWidgetFormSchema:: setDefaultFormFormatterName ( 'ac2009');
+      )
+    )
+
+O objetivo é adicionar uma classe form_row_error `` o `form_row` elemento div
+apenas se um campo não validação. Adicionar um `%% row_class` token para o
+`$ rowFormat propriedade» e substituir o sfWidgetFormSchemaFormatter ~ `:: 
formuláriotRow ()` ~
+método da seguinte formulário:
+
+    [php]
+    classe sfWidgetFormSchemaFormatterAc2009 estende 
sfWidgetFormSchemaFormatter
+    (
+      protegidos
+        $ rowFormat = "<div class=\"form_row%row_class%\">
+                            %% \ label erro% n% <br/>% campo%
+                            ajuda%%%% hidden_fields \ n </ div> \ n ",
+        / / ...
+
+      formuláriotRow função pública ($ label, field, $ erros = array (), $ 
help ='', $ = HiddenFields null)
+      (
+        $ row = parent:: formuláriotRow (
+          label
+          $ field,
+          $ errors,
+          Ajuda
+          HiddenFields $
+        );
+
+        return strtr ($ row, array (
+          '%% row_class' => count (($ erros)> 0)? 'Form_row_error':'',
+        ));
+      )
+    )
+
+Com esta adição, cada elemento que está de saída através da RenderRow () 
`método
+será automaticamente cercado por um `form_row_error` div `se o campo tem
+validação falha.
+
+Reflexões finais
+--------------
+
+O quadro é simultaneamente uma formulário de o mais poderoso e mais
+componentes complexos dentro symfony. O trade-off para a validação de 
formulário apertada,
+CSRF proteção, e as formulários de objeto é que o alargamento do quadro pode 
rapidamente
+tornar-se uma tarefa difícil. Gaining a deeper understanding of the form 
system,
+No entanto, é a chave para libertar todo o seu potencial. Espero que este 
capítulo tem
+exame de você um passo mais perto.
+
+Evolução do quadro de formulário incidirá sobre a preservação do poder, 
enquanto
+diminuindo a complexidade e dando mais flexibilidade para o desenvolvedor. O
+quadro formulário só agora está em sua infância.

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to