具有特定query_buider的Symfony2 Entity表单类型

时间:2013-03-14 11:52:37

标签: symfony-2.1 symfony-forms

上下文

在我的情况下,我有一些订单带有“折扣优惠券”(折扣)。可以在不同条件下使用折扣。例如,折扣有过期日期,可供有限数量的客户使用,可专用于用户,......

每个折扣都可以附加到多个订单。

在我的后台,我想添加订单创建一个字段“折扣”,其中包含折扣列表,但只有正确的折扣。

我做了什么

  • 具有字段manyToMany

    的实体“订单”
    /**
    * @ORM\ManyToMany(targetEntity="PATH\MyBundle\Entity\Discount", inversedBy="orders")
     * @ORM\JoinTable(name="shop_discounts_orders",
     *      joinColumns={@ORM\JoinColumn(name="order_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="discount_id", referencedColumnName="id")}
     *      )
     */
    private $discounts;
    
  • 实体使用字段manyToMany“折扣”

     /**
     * @ORM\ManyToMany(targetEntity="PATH\MyBundle\Entity\Order", mappedBy="discounts")
     */
     private $orders;
    
  • 带有字段折扣的表单OrderType

    $builder->add('discounts', 'entity',
        array( 'label' => 'Discount vouchers',
            'required' => false,
            'expanded' => true,
            'class' => 'PATH\MyBundle\Entity\Discount',
            'property' => 'title',
            'multiple' => true,
            'query_builder' => function(EntityRepository $er) use ($params) {
                        return $er->getQuerySelectType($params);
                    },
        ));
    

使用此解决方案,我可以在我的实体存储库中返回由我的请求定义的特定折扣。例如,它适用于过期的日期条件。

我想要什么

我想在复选框列表中过滤结果。实际上,我希望将折扣限制用于专用用户,限制产品列表或限制使用次数......而这些条件不能通过简单的sql请求来完成。

我尝试创建特殊类型。我的想法是有一个实体数组折扣并加载一个选择列表......之后,我创建了一个dataTransformer但它不起作用!

感谢你的想法!

2 个答案:

答案 0 :(得分:1)

您可以使用$options中的public function buildForm(FormBuilderInterface $builder, array $options)来传递您的userproduct。通过这两个信息,您可以优化折扣列表(在您的查询中)

如果您这样做,则需要在setDefaultValue

中添加它们
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
        $resolver->setDefaults(array(
            'user_discount' => null,
            'product_discount' => null,
        ));
}

并在您的控制器中:

$form = $this->formFactory->create(new YourFormType(), $entity, array(
    'user_discount' => $this->getUser(),
    'product_discount' => $product,
));

答案 1 :(得分:0)

如果有人和我有同样的问题,我找到了解决方案并解释了它。

  • 创建自定义类型

我的自定义类型受Symfony \ Bridge \ Doctrine \ Form \ Type \ DoctrineType

的启发
class DiscountOrderType extends AbstractType
{
     // overide choiceList callback
     public function setDefaultOptions(OptionsResolverInterface $resolver)
     {
        $choiceListCache =& $this->choiceListCache;
        $type = $this;

        $choiceList = function (Options $options) use (&$choiceListCache, &$time, $container) {

          [[ Copy paste same as Doctrine type ]]
        // Create your own choiceList class (EntityChoiceList)
        if (!isset($choiceListCache[$hash])) {
            $choiceListCache[$hash] = new DiscountChoiceList(
                $options['em'],
                $options['class'],
                $options['property'],
                $options['loader'],
                $options['choices'],
                $options['group_by']
            );
            // If you want add container
            $choiceListCache[$hash]->setContainer($container);
        }

        return $choiceListCache[$hash];
    };

    $resolver->setDefaults(array(
        'choice_list'       => $choiceList,
    ));

}
  • 创建自定义EntityChoiceList

我的自定义类型的灵感来自Symfony \ Bridge \ Doctrine \ Form \ ChoiceList \ EntityChoiceList

class EntityChoiceList extends ObjectChoiceList
{
protected function load()
{
    if ($this->entityLoader) {
        $entities = $this->entityLoader->getEntities();
    } else {
        $entities = $this->em->getRepository($this->class)->findAll();
    }

    // You have access to the entities in the choice list
    // Add your custom code here to manipulate the choice list
    // you can do some check not properly possible with sql request (http requests on each result, ...) before add it in choice list
    // you can add some custom cache rules, ...
    // if you use gedmon and want apply a "join" with translate table, you can add $query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'); before playing request...
    // Possibilities are infinite

    // FOR INSTANCE : you already want unset first entity of the result
    if (isset($entities[0])) {
        unset($entities[0]);
    }
    // END OF CUSTOM CODE
    try {
        // The second parameter $labels is ignored by ObjectChoiceList
        // The third parameter $preferredChoices is currently not supported
        parent::initialize($entities, array(), array());
    } catch (StringCastException $e) {
        throw new StringCastException(str_replace('argument $labelPath', 'option "property"', $e->getMessage()), null, $e);
    }

    $this->loaded = true;
}

当然你可以尝试扩展symfony类以获得美丽的代码;)。

感谢@ maxwell2022的帮助!