2012-09-22 14 views
9

Korzystanie Symfony 2.1.3-dev i doktryny 2.3Korzystanie jednostka typ pola w formularzu symfony2.1

Ja próbuje zbudować formę, która zapewni wiele opcji dla użytkownika, aby filtrować zwrócony zestaw danych (Entity\EngineCodes) . Formularz składa się z 1 pola wprowadzania tekstu (id) i 3 pól wyboru (module, type, status). Próbuję użyć Symfony2 entity form_type do generowania wartości dla 3 wybranych pól z jednostki EngineCodes.

Ponieważ chcę filtrować tabelę za pomocą kombinacji 3 dowolnych pól wyboru. W oparciu o dokumentację 2.1 zdecydowałem się utworzyć formularz FormType (EngineCodesFilterType) i ustawić trzy pola formularza na entity z instrukcjami query_builder, aby zwrócić zestaw unikatowych wartości dla każdego z pól.

Niestety, otrzymuję następujący błąd i nie jestem do końca pewien, dlaczego zwraca tablicę zamiast obiektu.

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. 

Jeżeli ustawić data_class do null, otrzymuję ten błąd:

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. 

Ponieważ wciąż się uczę te cechy Symfony2, moim celem było dopasować 2.1 Dokumenty w zakresie budowy i formatu tak dużo jak to możliwe.

Oto funkcja wewnątrz kontrolera:

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(),)); 

Oto typ formularza:

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',)); 
    } 
} 

I tu jest klasa 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(); 
    } 
} 

Odpowiedz

14

Pierwszym problemem jest to, że $entity nie jest jednolita, ale raczej szereg podmiotów (czyli to, co jest zwracany przez metodę findAll()). Kiedy zdefiniowałeś typ formularza, powiedziałeś, że spodziewałeś się zbudować formularz z encji (do czego służy opcja data_class) i dlatego pojawia się pierwszy błąd.

Jeśli ustawisz data_class na wartość null, mówisz, że nie spodziewasz się, że formularz zostanie utworzony z obiektu, więc zaakceptuje on twój zestaw jednostek i nie będzie narzekał. Ale dlaczego przekazujesz tablicę elementów do typu formularza? To tylko forma filtra, która pozwala wybrać cztery możliwe wartości do filtrowania twoich obiektów. To nie potrzebuje tablicy jednostek jako podstawowych danych. Jeśli uważasz, że potrzebujesz go, aby uzyskać wartości dla kodu, pola typu i statusu, nie jest to tak, jak zostały już pobrane z kreatorami zapytań. Więc kod kontroler powinien być po prostu:

public function displayAction() { 

// ... 

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

// ... 

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

// ... 

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

Następnie pojawi się inny błąd, ponieważ jesteś dodając trzy pola formularza i każdy z nich pozwala wybrać z listy podmiotów. Ale jak "pokazujesz" ten byt? Symfony nie wie, które pole powinno pokazywać, aby reprezentować encję, więc zgłasza ten błąd.

Ten błąd można naprawić, dodając metodę __toString() do klasy EngineCodes, która po prostu mówi "hej, to jak chcę pokazać tę klasę", ale chociaż błąd nie zostanie zgłoszony, nie będzie działał tak jak oczekiwane, ponieważ każde z trzech pól chce pokazać inną właściwość.

Innym rozwiązaniem jest użycie opcji property w polu formularza, aby określić, która właściwość obiektu bazowego ma być używana do wyświetlania danych.

Na przykład:

$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 za znalezienie błędu tablicy. – gremo

+1

Ahhhh, ma to sens, aby nie stosować mojej tablicy jednostek do formularza. Dzięki za tę obserwację. –

+0

A teraz wygląda na to, że moje instrukcje query_builder nie zwracają tablic/obiektów, ale raczej liczby całkowite i ciągi. Będę musiała powrócić okiem świeżymi oczami rano. –

11

jesteś po prostu brakuje property option w typach jednostek "status", "typ" i "moduł":

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

Dzięki za obserwację. Zabawne, jak odejście na godzinę, a następnie powrót pomaga bardzo wyraźny komunikat o błędzie ma więcej sensu. –

Powiązane problemy