来自连接实体的Symfony表单实体

时间:2013-01-04 16:30:26

标签: php symfony-2.1 symfony-forms

我想创建一个表单选择字段,如下所示:

<select>
<option value="product.product_id">product_details.detail_name</option>
etc...
</select>

价值不是问题,问题在于标签。

我有一个产品实体和一个productDetails实体,其中包含有关产品的翻译数据。

所以,在我的表单类型类中,在buildForm方法中,我有:

    $builder->add('product', 'entity', array(
        'class' => 'MyBundle:Product',
        'property' => 'details.detail_name',
        'query_builder' => function(EntityRepository $er) {
            return $er->createQueryBuilder('p')
                ->select('p, pd')
                ->join('p.details', 'pd')
                ->where('pd.language_id = :lang')
                ->setParameter('lang', 'en');
        }));

我希望该属性为details.detail_name。

我为此属性值尝试了不同的值。例如'details.detail_name','pd.detail_name'和'p.details.detail_name'。

但似乎无法让属性显示详细信息名称。

当我使用上述代码时,我收到此错误:

Neither property "detail_name" nor method "getDetailName()" nor method "isDetailName()" exists in class "Doctrine\ORM\PersistentCollection"

这个getDetailName()方法确实存在于ProductDetails实体中,我检查了实体,它们似乎都没问题。此外,当我在表单之外使用这些实体时,它们的工作正常。

我还尝试直接在我的数据库上执行生成的查询,它给了我预期的结果。 detail_name使用正确的语言。

那么,有人可以通过加入查询帮助我制作我想要的选择列表吗?

2 个答案:

答案 0 :(得分:1)

从我看到你的方法Product::getDetails返回Doctrine\ORM\PersistentCollection而不是'ProductDetails'实体(所以集合不是单个对象)。这意味着产品使用一对多/多对多关联与细节相关。

您可以尝试从产品详细信息方面执行此操作:

$builder->add(
    'product',
    'entity',
    array(
        'class' => 'MyBundle:ProductDetails',
        'property' => 'detail_name',
        'query_builder' => function(EntityRepository $er) {
            return $er->createQueryBuilder('pd')
                ->select('pd, p')
                ->join('pd.product', 'p')
                ->where('pd.language_id = :lang')
                ->setParameter('lang', 'en');
         }
    )

);

答案 1 :(得分:1)

我终于设法让这个工作了。下面,我正在展示我是如何做到这一点的,以防其他人遇到同样的问题。

我现在正在使用自定义表单类型。

在setDefaultOptions中,我调用的是一个存储库方法,它返回一个带有“product_id”=&gt;的数组。 “DETAIL_NAME”。

class ProductChoiceType extends AbstractType
{
    private $repository;

    public function __construct(EntityRepository $repository)
    {
        $this->repository = $repository;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
                'choices' => $this->repository->findAllProductsForForm('nl', true)
            ));
    }

    public function getParent()
    {
        return 'choice';
    }

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

在$ this-&gt; repository-&gt; findAllProductsForForm方法中,我使用查询和foreach循环使数组适合选择列表。

然后,我必须在我的services.xml文件中注册存储库和此类型:

<service id="mybundle.repository.product"
         factory-service="doctrine.orm.default_entity_manager"
         factory-method="getRepository"
         class="MyBundle\Repository\ProductRepository" >
    <argument>MyBundle:Product</argument> <!-- not sure why I need this, but it wouldn't work without it -->
</service>

<service id="mybundle.xxx.form.product_choice_type" class="Mybundle\Form\Type\ProductChoiceType">
    <argument type="service" id="mybundle.repository.product" />
    <tag name="form.type" alias="product_choice" />
</service>

然后,在根表单类型中(我认为它被称为)我使用'product_choice'作为表单类型。

我不确定这是否是最好的方法,但至少它是有效的。

现在我只需要弄清楚如何将用户的当前语言传递给存储库,但这是以后的问题。