<commit_before><?php

declare(strict_types=1);

/*
 * This file is part of the FormHandler package.
 *
 * (c) SolidWorx <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace SolidWorx\FormHandler\Decorator;

use Doctrine\Common\Persistence\ManagerRegistry;
use ProxyManager\Proxy\ProxyInterface;
use SolidWorx\FormHandler\FormCollection;
use SolidWorx\FormHandler\FormCollectionHandlerInterface;
use SolidWorx\FormHandler\FormHandlerFailInterface;
use SolidWorx\FormHandler\FormHandlerInterface;
use SolidWorx\FormHandler\FormHandlerResponseInterface;
use SolidWorx\FormHandler\FormHandlerSuccessInterface;
use SolidWorx\FormHandler\FormRequest;
use SolidWorx\Util\ArrayUtil;
use Symfony\Component\Form\FormErrorIterator;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Response;

class FormCollectionDecorator implements FormHandlerInterface, FormCollectionHandlerInterface, FormHandlerFailInterface, FormHandlerResponseInterface, FormHandlerSuccessInterface
{
    /**
     * @var FormHandlerInterface
     */
    private $handler;

    /**
     * @var array
     */
    private $formData;

    /**
     * @var ManagerRegistry
     */
    private $registry;

    public function __construct(FormHandlerInterface $handler, ManagerRegistry $registry)
    {
        $this->handler = $handler;
        $this->registry = $registry;
    }

    /**
     * @return FormHandlerInterface
     */
    public function getInnerHandler(): FormHandlerInterface
    {
        return $this->handler;
    }

    /**
     * @return string
     */
    public function getInnerHandlerClass(): string
    {
        if ($this->handler instanceof ProxyInterface) {
            return get_parent_class($this->handler);
        }

        return get_class($this->handler);
    }

    /**
     * {@inheritdoc}
     */
    public function getForm(FormFactoryInterface $factory = null, ...$options)
    {
        $form = $this->handler->getForm($factory, ...$options);

        if ($form instanceof FormInterface) {
            $this->formData = FormCollection::getEntityCollections($form->getData());
        } else {
            $entity = array_reduce($options, function ($carry, $item) {
                if (is_object($carry) && method_exists('getId', $carry)) {
                    return $carry;
                }

                if (is_object($item) && method_exists('getId', $item)) {
                    return $item;
                }

                return null;
            });

            $this->formData = FormCollection::getEntityCollections($entity);
        }

        return $form;
    }

    /**
     * {@inheritdoc}
     */
    public function onFail(FormRequest $formRequest, FormErrorIterator $errors, $data = null): ?Response
    {
        if ($this->handler instanceof FormHandlerFailInterface) {
            return $this->handler->onFail($formRequest, $errors, $data);
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function getResponse(FormRequest $formRequest)
    {
        if ($this->handler instanceof FormHandlerResponseInterface) {
            return $this->handler->getResponse($formRequest);
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function onSuccess($data, FormRequest $form): ?Response
    {
        $this->resolveCollections($data);

        if ($this->handler instanceof FormHandlerSuccessInterface) {
            return $this->handler->onSuccess($data, $form);
        }

        return null;
    }

    private function resolveCollections($entity): void
    {
        if (!is_object($entity)) {
            return;
        }

        $em = $this->registry->getManager();

        foreach ($this->formData as $data) {
            if ($data['class'] !== get_class($entity) || $data['id'] !== $entity->getId()) {
                continue;
            }

            $values = $entity->{$data['method']}()->toArray();

            $toDel = array_filter($data['collection'], function ($object) use ($values) {
                try {
                    return !in_array($object->getId(), ArrayUtil::column($values, 'id'));
                } catch (\ErrorException $e) {
                    return false;
                }
            });

            array_walk($values, __METHOD__);

            array_walk($toDel, function ($e) use ($entity, $data, $em) {
                $removeMethod = 'remove'.$data['short_name'];

                if (method_exists($entity, $removeMethod)) {
                    $entity->$removeMethod($e);
                }

                $em->remove($e);
            });
        }
    }
}<commit_msg>Fix method parameters and handle empty collections<commit_after><?php

declare(strict_types=1);

/*
 * This file is part of the FormHandler package.
 *
 * (c) SolidWorx <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace SolidWorx\FormHandler\Decorator;

use Doctrine\Common\Persistence\ManagerRegistry;
use ProxyManager\Proxy\ProxyInterface;
use SolidWorx\FormHandler\FormCollection;
use SolidWorx\FormHandler\FormCollectionHandlerInterface;
use SolidWorx\FormHandler\FormHandlerFailInterface;
use SolidWorx\FormHandler\FormHandlerInterface;
use SolidWorx\FormHandler\FormHandlerResponseInterface;
use SolidWorx\FormHandler\FormHandlerSuccessInterface;
use SolidWorx\FormHandler\FormRequest;
use SolidWorx\Util\ArrayUtil;
use Symfony\Component\Form\FormErrorIterator;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Response;

class FormCollectionDecorator implements FormHandlerInterface, FormCollectionHandlerInterface, FormHandlerFailInterface, FormHandlerResponseInterface, FormHandlerSuccessInterface
{
    /**
     * @var FormHandlerInterface
     */
    private $handler;

    /**
     * @var array
     */
    private $formData;

    /**
     * @var ManagerRegistry
     */
    private $registry;

    public function __construct(FormHandlerInterface $handler, ManagerRegistry $registry)
    {
        $this->handler = $handler;
        $this->registry = $registry;
    }

    /**
     * @return FormHandlerInterface
     */
    public function getInnerHandler(): FormHandlerInterface
    {
        return $this->handler;
    }

    /**
     * @return string
     */
    public function getInnerHandlerClass(): string
    {
        if ($this->handler instanceof ProxyInterface) {
            return get_parent_class($this->handler);
        }

        return get_class($this->handler);
    }

    /**
     * {@inheritdoc}
     */
    public function getForm(FormFactoryInterface $factory = null, ...$options)
    {
        $form = $this->handler->getForm($factory, ...$options);

        if ($form instanceof FormInterface) {
            $this->formData = FormCollection::getEntityCollections($form->getData());
        } else {
            $entity = array_reduce($options, function ($carry, $item) {
                if (is_object($carry) && method_exists($carry, 'getId')) {
                    return $carry;
                }

                if (is_object($item) && method_exists($item, 'getId')) {
                    return $item;
                }

                return null;
            });

            $this->formData = FormCollection::getEntityCollections($entity);
        }

        return $form;
    }

    /**
     * {@inheritdoc}
     */
    public function onFail(FormRequest $formRequest, FormErrorIterator $errors, $data = null): ?Response
    {
        if ($this->handler instanceof FormHandlerFailInterface) {
            return $this->handler->onFail($formRequest, $errors, $data);
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function getResponse(FormRequest $formRequest)
    {
        if ($this->handler instanceof FormHandlerResponseInterface) {
            return $this->handler->getResponse($formRequest);
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function onSuccess($data, FormRequest $form): ?Response
    {
        $this->resolveCollections($data);

        if ($this->handler instanceof FormHandlerSuccessInterface) {
            return $this->handler->onSuccess($data, $form);
        }

        return null;
    }

    private function resolveCollections($entity): void
    {
        if (!is_object($entity)) {
            return;
        }

        $em = $this->registry->getManager();

        foreach ($this->formData as $data) {
            if ($data['class'] !== get_class($entity) || $data['id'] !== $entity->getId()) {
                continue;
            }

            $values = $entity->{$data['method']}()->toArray();

            if (0 === count($values) && 0 !== count($data['collection'])) {
                $toDel = $data['collection'];
            } else {
                $toDel = array_filter($data['collection'], function ($object) use ($values) {
                    try {
                        return !in_array($object->getId(), ArrayUtil::column($values, 'id'));
                    } catch (\ErrorException $e) {
                        return false;
                    }
                });
            }

            array_walk($values, __METHOD__);

            array_walk($toDel, function ($e) use ($entity, $data, $em) {
                $removeMethod = 'remove'.$data['short_name'];

                if (method_exists($entity, $removeMethod)) {
                    $entity->$removeMethod($e);
                }

                $em->remove($e);
            });
        }
    }
}
{'fraction_non_alphanumeric': 0.12494912494912495, 'fraction_numerical': 0.000407000407000407, 'mean_word_length': 2.275241586137954, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2222399', 'n_tokens_mistral': 2662, 'n_tokens_neox': 2558, 'n_words': 528}