9

使用 Symfony 2.1.3-dev 和 Doctrine 2.3

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

因为我想使用任意 3 个选择字段的组合来过滤表格。根据 2.1 文档,我决定创建一个 FormType ( EngineCodesFilterType) 并设置三个表单字段来entity键入 withquery_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_classnull,我会收到此错误:

    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();
    }
}
4

2 回答 2

14

您的第一个问题是这$entity不是单个实体,而是实体数组(这是该findAll()方法返回的内容)。当您定义表单类型时,您说您希望从实体构建表单(这就是data_class选项的用途),这就是您收到第一个错误的原因。

如果您设置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,));
于 2012-09-22T07:26:23.533 回答
11

您只是缺少“状态”、“类型”和“模块”实体类型中的属性选项:

财产

类型:字符串

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

于 2012-09-22T07:17:27.590 回答