<?php
namespace App\Form\ProductAttribute\Subscriber;
use App\Form\ProductAttribute\ProductAttributeValueType;
use App\Repository\ProductAttribute\ProductAttributeRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
class ProductAttributeSubscriber implements EventSubscriberInterface
{
public function __construct(private readonly ProductAttributeRepository $productAttributeRepository)
{
}
public static function getSubscribedEvents(): array
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
FormEvents::POST_SET_DATA => 'postSetData',
FormEvents::PRE_SUBMIT => 'preSubmit',
FormEvents::SUBMIT => ['onSubmit', 50],
];
}
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
if (!$data) {
$data = new ArrayCollection();
}
if (!$data instanceof Collection) {
throw new UnexpectedTypeException($data, Collection::class);
}
// First remove all rows
foreach ($form as $name => $child) {
$form->remove($name);
}
foreach ($data as $name => $value) {
$form->add($name, ProductAttributeValueType::class, [
'product_attribute' => $value->getProductAttribute(),
]);
}
}
public function postSetData(FormEvent $event)
{
}
public function preSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
if (!\is_array($data)) {
$data = [];
}
// Remove all empty rows
foreach ($form as $name => $child) {
if (!isset($data[$name])) {
$form->remove($name);
}
}
// Add all additional rows
foreach ($data as $name => $value) {
if (!$form->has($name)) {
$form->add($name, ProductAttributeValueType::class, [
'product_attribute' => $this->productAttributeRepository->find($value['productAttribute']),
]);
}
}
$event->setData($data);
}
public function onSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
// At this point, $data is an array or an array-like object that already contains the
// new entries, which were added by the data mapper. The data mapper ignores existing
// entries, so we need to manually unset removed entries in the collection.
if (null === $data) {
$data = new ArrayCollection();
}
if (is_array($data)) {
$data = new ArrayCollection($data);
}
if (!$data instanceof Collection) {
throw new UnexpectedTypeException($data, Collection::class);
}
/** @var FormInterface $child */
foreach ($form as $name => $child) {
if ($child->isEmpty()) {
unset($data[$name]);
$form->remove($name);
}
}
$toDelete = [];
foreach ($data as $name => $child) {
if (!$form->has($name)) {
$toDelete[] = $name;
}
}
foreach ($toDelete as $name) {
unset($data[$name]);
}
}
}