0

I didn't find any subject related to my question and my case is very particular that's why i am calling for help.

I have 4 involved entities : PurchaseOrder, SapPO, project and Product. As shown below there is a one to many association between PurchaseOrder and SapPo, and a one to many bidirectional association between SapPo and Project and a many to many association between purchaseOrder and product.

PurchaseOder.php :

/**
 * @ORM\ManyToMany(targetEntity="SapPo",cascade={"persist","remove"})
 * @ORM\JoinTable(name="po_sappo",
 *      joinColumns={@ORM\JoinColumn(name="po_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="sappo_id", referencedColumnName="id", unique=true,onDelete="CASCADE")}
 *      )
 */
private $sapPo;

/**
 * @ORM\ManyToMany(targetEntity="Product", mappedBy="purchaseOrders")
 */
private $products;

SapPo.php

/**
 * @ORM\ManyToOne(targetEntity="Project", inversedBy="sapPos")
 * @ORM\JoinColumn(name="project_sap", referencedColumnName="id")
 */
private $project ;

Project.php :

/**
 * @ORM\OneToMany(targetEntity="SapPo", mappedBy="project")
 */
private $sapPos ;

/**
 * @ORM\ManyToMany(targetEntity="Product", inversedBy="projet")
 * @ORM\JoinTable(name="product_project")
 */
private $products;

And finally Product.php :

/**
 * @ORM\ManyToMany(targetEntity="PurchaseOrder", inversedBy="products", 
  cascade={"persist"})
 * @ORM\JoinTable(name="purchaseOrders_products")
 */
private $purchaseOrders;

/**
 * @ORM\ManyToMany(targetEntity="Project", mappedBy="products")
 */
private $projet;

What i want to do is to populate the form with products that represent the intersection between the chosen projects data. For example we have to chosen project "Project 1" that has two products "product 1" and "product 2" and an other project "project 2" that has two products "product 2" and "product 3".

In this example "product 2" is the intersection and the form need to be populated with it.

Using the code shown below and using the FormEvents i have succeeded to populate the form with the necessary data using the necessary AJAX calls and afterward an ArrayCollection Filter. The problem is that once i submit the form i don't get the products chosen but i get an empty ArrayCollection.

PurchaseOrderType.php :

        /**
     * Product modifier used to modify products after the SAP PO choice validation
     * @param FormInterface $form
     * @param $sapPos
     */

    $productModifier = function (FormInterface $form, $names){


        $form->add('products', EntityType::class,array(
            'class' => 'FollowupBundle:Product',
            'multiple' => true,
            'expanded' => false,
            'query_builder' => function(EntityRepository $er) use ($names) {
                $qb = $er->createQueryBuilder('u') ;
                $qb->where("u.name IN (:projects)")
                    ->setParameter('projects',$names) ;
                return $qb ;
            },
            'choice_label' => 'name',
            'placeholder' => 'Selectionner le produit'
        ));
    };



    $builder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function (FormEvent $event) {
            $form = $event->getForm();
            $data = $event->getData();
            $sapPos = $data->getSapPo();



            $form->add('products',EntityType::class,array(
                'class' => 'FollowupBundle:Product',
                'multiple' => true,
                'expanded' => false,
                'required' => false,
                'choices' => [],
                'placeholder' => 'selectionner les produits',
                'choice_label' => 'name'


            )) ;

        }) ;



    $builder->get('sapPo')->addEventListener(
        FormEvents::POST_SUBMIT,
        function (FormEvent $event) use ($productModifier){
            $sapPos = $event->getForm()->getData() ;
            $namesList = $this->getNamesFromSapPo($sapPos) ;

            $productModifier($event->getForm()->getParent(), $namesList);
        },900
    ) ;

EDIT

This are the function used to filter and extract products names to be used in the query builder.

 /**
 * @param Product $product
 * @param ArrayCollection $sapPos
 * @return bool
 */
public function filterProducts(Product $product, $sapPos){
    $isCommon = true ;
    foreach ($sapPos as $sapPo){
        if (!$sapPo->getProject()->getProducts()->contains($product)){
            $isCommon = false;
        }else {
        }
    }
    return $isCommon;
}



public function getNamesFromSapPo($sapPos){
    $primilnaryProducts  = new ArrayCollection() ;
    $lastProducts = new ArrayCollection() ;
    $namesList = [] ;
    foreach ($sapPos as $sapPo){
        foreach ($sapPo->getProject()->getProducts() as $product){
            $primilnaryProducts->add($product) ;
        }
    }
    // filter products

    $lastProducts = $primilnaryProducts->filter(
        function ($entry) use ($sapPos){
            return $this->filterProducts($entry,$sapPos) ;
        }
    ) ;

    //get Names

    foreach ($lastProducts as $product){
        $namesList[] = $product->getName() ;
    }


    return $namesList ;



}

Any hint or technical advice is welcomed ! thanks.

  • As I see from `https://symfony.com/doc/current/reference/forms/types/entity.html#choices` (and as I remember): your `'choices' => []` will override any data in field – Ilya Yarkovets Jan 17 '18 at 09:38
  • Thanks ! The problem is that i forgot to use the form modifier in the POST_SUBMIT function. – Houssem Balty Jan 17 '18 at 10:02
  • Great. You found solution. BTW, more debugging while working with form events - is the best way to find all problems, of course if you are not writing them often. – Ilya Yarkovets Jan 17 '18 at 10:22
  • I generally use PSR/Logger but sadly i can't log objects as in Java. – Houssem Balty Jan 17 '18 at 13:46
  • You could try to serialize your object before logging it. And, imo, logging is not the best way of debugging - try to play with xdebug, it is much more better. – Ilya Yarkovets Jan 18 '18 at 09:40

1 Answers1

0

I forgot to use the form modifier in the POST_SUBMIT function and i had to remove the 'choices' => [] from the form builder that overrides the data sent to the server.