代码之家  ›  专栏  ›  技术社区  ›  Alan Scott

使用symfony2.1表单中的实体字段类型

  •  9
  • Alan Scott  · 技术社区  · 12 年前

    使用Symfony 2.1.3-dev和条令2.3

    我正在尝试构建一个表单,为用户提供多个选项来筛选返回的数据集( Entity\EngineCodes )。表单由1个文本输入字段组成( id )和3个选择字段( module , type , status )。我正在尝试使用Symfony2 entity form_type从 EngineCodes 实体

    因为我想使用任意3个选择字段的组合来筛选表。基于2.1文档,我决定创建一个FormType( EngineCodesFilterType )并将其中三个表单字段设置为 实体 键入 query_builder 语句为每个字段返回一组唯一的值。

    不幸的是,我收到了以下错误,我不确定为什么它返回的是数组而不是对象。

        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.
    

    如果我设置 data_class null ,我收到此错误:

        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.
    

    由于我仍在学习Symfony2的这些功能,我的目标是尽可能在结构和格式方面与2.1文档相匹配。

    以下是控制器中的功能:

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

    以下是表单类型:

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

    这是 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();
        }
    }
    
    2 回复  |  直到 12 年前
        1
  •  14
  •   Carrie Kendall netcult    11 年前

    你的第一个问题是 $entity 不是单个实体,而是一个实体数组( findAll() 方法)。当您定义表单类型时,您说您希望从一个实体构建表单(即 data_class 选项为),这就是为什么您会得到第一个错误。

    如果你设置 数据类别 对于null,你是说你不希望表单是从一个实体创建的,所以它会接受你的实体数组,而不会抱怨。但是,为什么要将实体数组传递给表单类型?这只是一个过滤器表单,允许您选择四个可能的值来过滤实体。这不需要实体数组作为其基础数据。如果您认为需要它来获取代码、类型和状态字段的值,那么事实并非如此,因为它们已经由查询生成器获取。因此,您的控制器代码应该只是:

    public function displayAction() {
    
    // ...
    
    $entity = $this->getDoctrine()->getEntityManager()
        ->getRepository('VendorIndexBundle:EngineCodes')
        ->findAll();
    
    // ...
    
    $form = $this->createForm(new EngineCodesFilterType());
    
    // ...
    
    return $this->render( // ...
    

    然后您会得到另一个错误,因为您添加了三个表单字段,每个字段都允许您从实体列表中进行选择。但是,你如何“展示”这个实体?Symfony不知道应该向您显示哪个字段来表示实体,所以它抛出了这个错误。

    这个错误可以通过向EngineCodes类添加__toString()方法来修复,该方法只会说“嘿,这就是我想要显示这个类的方式”,但尽管不会抛出错误,但它不会按预期工作,因为三个字段中的每一个都想显示不同的属性。

    另一个解决方案是使用 property 表单字段的选项,说明要使用基础对象的哪个属性来显示数据。

    例如:

    $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,));
    
        2
  •  11
  •   gremo    12 年前

    你只是错过了 property option 在“状态”、“类型”和“模块”实体类型中:

    所有物

    类型:字符串

    这是应用于显示实体的属性 作为HTML元素中的文本。如果留空,实体对象将 强制转换为字符串,因此必须具有__toString()方法。