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.