2012-09-22 21 views
9

Utilizando Symfony 2.1.3-dev y Doctrina 2.3entidad tipo de campo en forma symfony2.1

que estoy tratando de construir una forma que ofrecen múltiples opciones para un usuario para filtrar un conjunto devuelto de datos (Entity\EngineCodes) . El formulario se compone de 1 campo de entrada de texto (id) y 3 campos de selección (module, type, status). Estoy intentando usar Symfony2 entity form_type para generar valores para los 3 campos de selección de la entidad EngineCodes.

Como quiero filtrar la tabla usando una combinación de 3 de los campos de selección. En base a los documentos 2.1, decidí crear un FormType (EngineCodesFilterType) y establecer tres de los campos de formulario en entity con declaraciones query_builder para devolver un conjunto de valores únicos para cada uno de los campos.

Desafortunadamente, recibo el siguiente error y no estoy muy seguro de por qué devuelve una matriz en lugar de un objeto.

The form's view data is expected to be an instance of class 
    Vendor\IndexBundle\Entity\EngineCodes, but is a(n) array. 
    You can avoid this error by setting the "data_class" option 
    to null or by adding a view transformer that transforms a(n) 
    array to an instance of Vendor\IndexBundle\Entity\EngineCodes. 

Si fijo data_class a null, recibo este error:

A "__toString()" method was not found on the objects of type 
    "Vendor\IndexBundle\Entity\EngineCodes" passed to the choice 
    field. To read a custom getter instead, set the option 
    "property" to the desired property path. 

Dado que todavía estoy aprendiendo estas características Symfony2, mi objetivo era igualar los 2,1 Docs en términos de construcción y formato cuanto más se pueda.

Aquí es la función dentro del controlador:

public function displayAction() { 

    // ... 

    $entity = $this->getDoctrine()->getEntityManager() 
     ->getRepository('VendorIndexBundle:EngineCodes') 
     ->findAll(); 

    // ... 

    $form = $this->createForm(new EngineCodesFilterType(), $entity); 

    // ... 

    return $this->render(
     'VendorIndexBundle::layout.html.twig', 
     array(
      'entity' => $entity, 
      'form' => $form->createView(),)); 

Aquí es el tipo de formulario:

class EngineCodesFilterType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder->add(
      'id', 
      'integer', 
      array(
       'label' => 'Code ID',)); 
     $builder->add(
      'status', 
      'entity', 
      array(
       'label' => 'Code Status', 
       'class' => 'VendorIndexBundle:EngineCodes', 
       'query_builder' => function(EntityRepository $er) 
        { 
         return $er->createQueryBuilder('u') 
          ->select('u.status') 
          ->add('groupBy', 'u.status'); 
        }, 
       'multiple' => true,)); 
     $builder->add(
      'type', 
      'entity', 
      array(
       'label' => 'Code Type', 
       'class' => 'VendorIndexBundle:EngineCodes', 
       'query_builder' => function(EntityRepository $er) 
        { 
         return $er->createQueryBuilder('u') 
          ->select('u.type') 
          ->add('groupBy' ,'u.type'); 
        }, 
       'multiple' => true,)); 
     $builder->add(
      'module', 
      'entity', 
      array(
       'label' => 'Code Module', 
       'class' => 'VendorIndexBundle:EngineCodes', 
       'query_builder' => function(EntityRepository $er) 
        { 
         return $er->createQueryBuilder('u') 
          ->select('u.module') 
          ->add('groupBy', 'u.module'); 
        }, 
       'multiple' => true,)); 
    } 

    public function getName() 
    { 
     return 'EngineCodesFilter'; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(
      array(
       'data_class'  => 'Vendor\IndexBundle\Entity\EngineCodes', 
       /*'data_class'  => null,*/ 
       'validation_groups' => 'filter',)); 
    } 
} 

Y aquí está la clase Vendor\Entity\EngineCodes:

/** 
* Vendor\IndexBundle\Entity\EngineCodes 
* 
* @ORM\Table(name="engine_codes") 
* @ORM\Entity(repositoryClass="Vendor\IndexBundle\Entity\EngineCodesRepository") 
* @UniqueEntity(fields="id", message="ID already in use! Enter a unique ID for the code.") 
*/ 
class EngineCodes 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer", nullable=false, unique=true) 
    * @ORM\Id 
    * @Assert\NotBlank(message="ID cannot be blank!") 
    * @Assert\Regex(pattern="/^\d+$/", match=true, message="ID must be an integer!") 
    * @Assert\MinLength(limit=8, message="ID must be 8 numbers in length!") 
    * @Assert\MaxLength(limit=8, message="ID must be 8 numbers in length!") 
    */ 
    private $id; 

    /** 
    * @var string $token 
    * 
    * @ORM\Column(name="token", type="string", length=255, nullable=false, unique=true) 
    */ 
    private $token; 

    /** 
    * @var boolean $status 
    * 
    * @ORM\Column(name="status", type="integer", nullable=false) 
    * @Assert\NotBlank(message="Status cannot be blank!") 
    */ 
    private $status; 

    /** 
    * @var string $module 
    * 
    * @ORM\Column(name="module", type="string", length=255, nullable=false) 
    * @Assert\NotBlank(message="Module cannot be blank!") 
    */ 
    private $module; 

    /** 
    * @var string $submodule 
    * 
    * @ORM\Column(name="submodule", type="string", length=255, nullable=false) 
    * @Assert\NotBlank(message="Submodule cannot be blank!") 
    */ 
    private $submodule; 

    /** 
    * @var string $type 
    * 
    * @ORM\Column(name="type", type="string", length=255, nullable=false) 
    * @Assert\NotBlank(message="Type cannot be blank!") 
    */ 
    private $type; 

    /** 
    * @var string $description 
    * 
    * @ORM\Column(name="description", type="text", nullable=false) 
    * @Assert\NotBlank(message="Description cannot be blank!") 
    */ 
    private $description; 

    /** 
    * @var string $title 
    * 
    * @ORM\Column(name="title", type="string", length=255, nullable=false) 
    * @Assert\NotBlank(message="Title cannot be blank!") 
    */ 
    private $title; 

    /** 
    * @var string $definition 
    * 
    * @ORM\Column(name="definition", type="text", nullable=true) 
    */ 
    private $definition; 

    /** 
    * @var string $color 
    * 
    * @ORM\Column(name="color", type="string", length=10, nullable=true) 
    */ 
    private $color; 

    /** 
    * @var \DateTime $createTimestamp 
    * 
    * @ORM\Column(name="create_timestamp", type="datetime", nullable=false) 
    */ 
    private $createTimestamp; 

    /** 
    * @var Accounts 
    * 
    * @ORM\ManyToOne(targetEntity="Accounts") 
    * @ORM\JoinColumns({ 
    * @ORM\JoinColumn(name="create_account_fk", referencedColumnName="id") 
    * }) 
    */ 
    private $createAccountFk; 


    // getters and setters ... 

    /** 
    * Set createAccountFk 
    * 
    * @param Vendor\IndexBundle\Entity\Accounts $createAccountFk 
    * @return EngineCodes 
    */ 
    public function setCreateAccountFk(\Vendor\IndexBundle\Entity\Accounts $createAccountFk = null) 
    { 
     $this->createAccountFk = $createAccountFk; 

     return $this; 
    } 

    /** 
    * @ORM\PrePersist 
    */ 
    public function setCreateTimestampValue() 
    { 
     $this->createTimestamp = new \DateTime(); 
    } 
} 

Respuesta

14

Su primer problema es que $entity no es una entidad única, sino más bien un conjunto de entidades (que es lo que se devuelve por el método findAll()). Cuando definió el tipo de formulario, dijo que esperaba construir el formulario desde una entidad (para eso es la opción data_class) y es por eso que obtiene el primer error.

Si configura data_class como nulo, está diciendo que no espera que el formulario se cree desde una entidad, por lo que aceptará su conjunto de entidades y no se quejará. Pero, ¿por qué está pasando una matriz de entidades al tipo de formulario? Esto es solo un formulario de filtro que le permite elegir cuatro valores posibles para filtrar sus entidades. Esto no necesita una matriz de entidades como sus datos subyacentes. Si cree que lo necesita para obtener los valores para los campos de código, tipo y estado, esto no es así ya que ya se han obtenido con sus constructores de consultas. Por lo que su código del controlador debe ser justo:

public function displayAction() { 

// ... 

$entity = $this->getDoctrine()->getEntityManager() 
    ->getRepository('VendorIndexBundle:EngineCodes') 
    ->findAll(); 

// ... 

$form = $this->createForm(new EngineCodesFilterType()); 

// ... 

return $this->render(// ... 

A continuación presentamos lo mejor otro error, porque va a agregar tres campos de formulario y cada uno le permite elegir entre una lista de entidad. Pero, ¿cómo "muestras" esta entidad? Symfony no sabe qué campo debería mostrarte para representar a la entidad, por lo que arroja este error.

Este error podría solucionarse agregando un método __toString() a la clase EngineCodes, que solo dice "hey, así es como quiero mostrar esta clase", pero aunque el error no se producirá, no funcionará. esperado ya que cada uno de los tres campos quiere mostrar una propiedad diferente.

Otra solución es utilizar la opción property del campo de formulario para indicar qué propiedad del objeto subyacente que desea utilizar para mostrar los datos.

Por ejemplo:

$builder->add(
     'status', 
     'entity', 
     array(
      'label' => 'Code Status', 
      'class' => 'VendorIndexBundle:EngineCodes', 
      'property' => 'status' 
      'query_builder' => function(EntityRepository $er) 
       { 
        return $er->createQueryBuilder('u') 
         ->select('u.status') 
         ->add('groupBy', 'u.status'); 
       }, 
      'multiple' => true,)); 
+1

+1 para encontrar el error de matriz. – gremo

+1

Ahhhh, tiene mucho sentido no aplicar mi matriz de entidades al formulario. Gracias por esa observación. –

+0

Y ahora parece que mis instrucciones query_builder no devuelven matrices/objetos, sino enteros y cadenas. Voy a tener que volver a visitarme con ojos nuevos por la mañana. –

11

Simplemente están perdiendo property option en tipos de entidad "estado", "tipo" y "módulo":

property

type: string

This is the property that should be used for displaying the entities as text in the HTML element. If left blank, the entity object will be cast into a string and so must have a __toString() method.

+2

Gracias por la observación. Es curioso cómo alejarse durante una hora y luego regresar ayuda a que el mensaje de error muy claro tenga más sentido. –

Cuestiones relacionadas