代码之家  ›  专栏  ›  技术社区  ›  Clotaire

Symfony2具有特定query_buider的实体表单类型

  •  1
  • Clotaire  · 技术社区  · 12 年前

    上下文

    就我而言,我有一些带有“折扣券”(折扣)的订单。折扣可以在不同的条件下使用。例如,折扣有过期日期,可以由有限数量的客户使用,可以专用于用户。。。

    每个折扣都可以附加在几个订单上。

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

    我做了什么

    • 带有字段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 回复  |  直到 12 年前
        1
  •  1
  •   maxwell2022    12 年前

    你可以使用 $options 从…起 public function buildForm(FormBuilderInterface $builder, array $options) 通过你的 user product 例如。有了这两个信息,你可以完善你的折扣清单(在你的查询中)

    如果这样做,则需要将它们添加到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,
    ));
    
        2
  •  0
  •   Clotaire    12 年前

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

    • 创建自定义类型

    我的自定义类型的灵感来自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;
    }
    

    当然,您可以尝试为beautyfull代码扩展symfony类;)。

    感谢@maxwell2022的帮助!