diff --git a/src/Form/Type/Helper/StructuralEntityChoiceLoader.php b/src/Form/Type/Helper/StructuralEntityChoiceLoader.php index 87658398..241f57b3 100644 --- a/src/Form/Type/Helper/StructuralEntityChoiceLoader.php +++ b/src/Form/Type/Helper/StructuralEntityChoiceLoader.php @@ -20,6 +20,7 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + namespace App\Form\Type\Helper; use App\Entity\Base\AbstractNamedDBElement; @@ -28,7 +29,10 @@ use App\Repository\StructuralDBElementRepository; use App\Services\Trees\NodesListBuilder; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\ChoiceList\Loader\AbstractChoiceLoader; +use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\Options; +use Symfony\Contracts\Translation\TranslatorInterface; class StructuralEntityChoiceLoader extends AbstractChoiceLoader { @@ -36,8 +40,14 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader private ?AbstractNamedDBElement $starting_element = null; - public function __construct(private readonly Options $options, private readonly NodesListBuilder $builder, private readonly EntityManagerInterface $entityManager) - { + private ?FormInterface $form = null; + + public function __construct( + private readonly Options $options, + private readonly NodesListBuilder $builder, + private readonly EntityManagerInterface $entityManager, + private readonly TranslatorInterface $translator + ) { } protected function loadChoices(): iterable @@ -67,14 +77,22 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader if ($this->starting_element !== null && $this->starting_element->getID() === null //Element must not be persisted yet && $this->options['choice_value']($this->starting_element) === $value) { - //Then reuse the starting element $this->entityManager->persist($this->starting_element); return [$this->starting_element]; } + if (!$this->options['allow_add']) { - throw new \RuntimeException('Cannot create new entity, because allow_add is not enabled!'); + //If we have a form, add an error to it, to improve the user experience + if ($this->form !== null) { + $this->form->addError( + new FormError($this->translator->trans('entity.select.creating_new_entities_not_allowed') + ) + ); + } else { + throw new \RuntimeException('Cannot create new entity, because allow_add is not enabled!'); + } } $class = $this->options['class']; @@ -85,10 +103,13 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader $results = []; - foreach($entities as $entity) { + foreach ($entities as $entity) { //If the entity is newly created (ID null), add it as result and persist it. if ($entity->getID() === null) { - $this->entityManager->persist($entity); + //Only persist the entities if it is allowed + if ($this->options['allow_add']) { + $this->entityManager->persist($entity); + } $results[] = $entity; } } @@ -115,6 +136,16 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader return $this->starting_element; } + /** + * Sets the form that this loader is bound to. + * @param FormInterface|null $form + * @return void + */ + public function setForm(?FormInterface $form): void + { + $this->form = $form; + } + /** * Sets the initial value used to populate the field. This will always be an allowed value. * @param AbstractNamedDBElement|null $starting_element diff --git a/src/Form/Type/StructuralEntityType.php b/src/Form/Type/StructuralEntityType.php index 236288aa..41ad1c97 100644 --- a/src/Form/Type/StructuralEntityType.php +++ b/src/Form/Type/StructuralEntityType.php @@ -67,6 +67,7 @@ class StructuralEntityType extends AbstractType $choice_loader = $options['choice_loader']; if ($choice_loader instanceof StructuralEntityChoiceLoader) { $choice_loader->setAdditionalElement($data); + $choice_loader->setForm($form); } }); @@ -83,7 +84,7 @@ class StructuralEntityType extends AbstractType 'subentities_of' => null, //Only show entities with the given parent class 'disable_not_selectable' => false, //Disable entries with not selectable property 'choice_value' => fn(?AbstractNamedDBElement $element) => $this->choice_helper->generateChoiceValue($element), //Use the element id as option value and for comparing items - 'choice_loader' => fn(Options $options) => new StructuralEntityChoiceLoader($options, $this->builder, $this->em), + 'choice_loader' => fn(Options $options) => new StructuralEntityChoiceLoader($options, $this->builder, $this->em, $this->translator), 'choice_label' => fn(Options $options) => fn($choice, $key, $value) => $this->choice_helper->generateChoiceLabel($choice), 'choice_attr' => fn(Options $options) => fn($choice, $key, $value) => $this->choice_helper->generateChoiceAttr($choice, $options), 'group_by' => fn(AbstractNamedDBElement $element) => $this->choice_helper->generateGroupBy($element), diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 45480ada..b28db2d9 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -11801,5 +11801,11 @@ Please note, that you can not impersonate a disabled user. If you try you will g Ends with + + + entity.select.creating_new_entities_not_allowed + You are not allowed to create new entities of this type! Please choose a pre-existing one. + +