- <?php
- declare(strict_types=1);
- /*
-  * This file is part of the Sonata Project package.
-  *
-  * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
-  *
-  * For the full copyright and license information, please view the LICENSE
-  * file that was distributed with this source code.
-  */
- namespace Sonata\AdminBundle\Builder;
- use Sonata\AdminBundle\FieldDescription\FieldDescriptionInterface;
- use Sonata\AdminBundle\Form\Type\AdminType;
- use Sonata\AdminBundle\Form\Type\ModelAutocompleteType;
- use Sonata\AdminBundle\Form\Type\ModelHiddenType;
- use Sonata\AdminBundle\Form\Type\ModelListType;
- use Sonata\AdminBundle\Form\Type\ModelReferenceType;
- use Sonata\AdminBundle\Form\Type\ModelType;
- use Sonata\Form\Type\CollectionType;
- use Symfony\Component\Form\Extension\Core\Type\FormType;
- use Symfony\Component\Form\FormBuilderInterface;
- use Symfony\Component\Form\FormFactoryInterface;
- use Symfony\Component\Form\FormRegistryInterface;
- /**
-  * @psalm-suppress DeprecatedInterface
-  */
- abstract class AbstractFormContractor implements FormContractorInterface
- {
-     /**
-      * @var FormFactoryInterface
-      */
-     protected $formFactory;
-     /**
-      * @var FormRegistryInterface
-      */
-     protected $formRegistry;
-     public function __construct(FormFactoryInterface $formFactory, FormRegistryInterface $formRegistry)
-     {
-         $this->formFactory = $formFactory;
-         $this->formRegistry = $formRegistry;
-     }
-     final public function fixFieldDescription(FieldDescriptionInterface $fieldDescription): void
-     {
-         $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'standard'));
-         if ($fieldDescription->describesAssociation() || null !== $fieldDescription->getOption('admin_code')) {
-             $fieldDescription->getAdmin()->attachAdminClass($fieldDescription);
-         }
-     }
-     final public function getFormFactory(): FormFactoryInterface
-     {
-         return $this->formFactory;
-     }
-     final public function getFormBuilder(string $name, array $formOptions = []): FormBuilderInterface
-     {
-         return $this->getFormFactory()->createNamedBuilder($name, FormType::class, null, $formOptions);
-     }
-     final public function getDefaultOptions(
-         ?string $type,
-         FieldDescriptionInterface $fieldDescription,
-         array $formOptions = [],
-     ): array {
-         $options = [];
-         $options['sonata_field_description'] = $fieldDescription;
-         if ($this->isAnyInstanceOf($type, [
-             ModelType::class,
-             ModelListType::class,
-             ModelHiddenType::class,
-             ModelAutocompleteType::class,
-             ModelReferenceType::class,
-         ])) {
-             $options['class'] = $fieldDescription->getTargetModel();
-             $options['model_manager'] = $fieldDescription->getAdmin()->getModelManager();
-             if ($this->isAnyInstanceOf($type, [ModelAutocompleteType::class])) {
-                 if (!$fieldDescription->hasAssociationAdmin()) {
-                     throw new \InvalidArgumentException(\sprintf(
-                         'The current field `%s` is not linked to an admin.'
-                         .' Please create one for the target model: `%s`.',
-                         $fieldDescription->getName(),
-                         $fieldDescription->getTargetModel() ?? ''
-                     ));
-                 }
-             }
-         } elseif ($this->isAnyInstanceOf($type, [AdminType::class])) {
-             if (!$fieldDescription->hasAssociationAdmin()) {
-                 throw new \InvalidArgumentException(\sprintf(
-                     'The current field `%s` is not linked to an admin.'
-                     .' Please create one for the target model: `%s`.',
-                     $fieldDescription->getName(),
-                     $fieldDescription->getTargetModel() ?? ''
-                 ));
-             }
-             if (!$fieldDescription->describesSingleValuedAssociation()) {
-                 throw new \InvalidArgumentException(\sprintf(
-                     'You are trying to add `%s` field `%s` which is not a One-To-One or Many-To-One association.'
-                     .' You SHOULD use `%s` instead.',
-                     AdminType::class,
-                     $fieldDescription->getName(),
-                     CollectionType::class
-                 ));
-             }
-             // set sensitive default value to have a component working fine out of the box
-             $options['btn_add'] = false;
-             $options['delete'] = false;
-             $options['data_class'] = $fieldDescription->getAssociationAdmin()->getClass();
-             $options['empty_data'] = static fn (): object => $fieldDescription->getAssociationAdmin()->getNewInstance();
-             $fieldDescription->setOption('edit', $fieldDescription->getOption('edit', 'admin'));
-         } elseif ($this->isAnyInstanceOf($type, [
-             CollectionType::class,
-         ])) {
-             if (!$fieldDescription->hasAssociationAdmin()) {
-                 throw new \InvalidArgumentException(\sprintf(
-                     'The current field `%s` is not linked to an admin.'
-                     .' Please create one for the target model: `%s`.',
-                     $fieldDescription->getName(),
-                     $fieldDescription->getTargetModel() ?? ''
-                 ));
-             }
-             $options['type'] = AdminType::class;
-             $options['modifiable'] = true;
-             $options['type_options'] = $this->getDefaultAdminTypeOptions($fieldDescription, $formOptions);
-         }
-         return $options;
-     }
-     /**
-      * @param string[] $classes
-      *
-      * @phpstan-param class-string[] $classes
-      */
-     private function isAnyInstanceOf(?string $type, array $classes): bool
-     {
-         if (null === $type) {
-             return false;
-         }
-         foreach ($classes as $class) {
-             if (is_a($type, $class, true)) {
-                 return true;
-             }
-         }
-         // handle form type inheritance and check all parent types
-         $resolvedType = $this->formRegistry->getType($type);
-         $parentType = $resolvedType->getParent();
-         if (null !== $parentType) {
-             $parentType = $parentType->getInnerType()::class;
-             // all types have "Symfony\Component\Form\Extension\Core\Type\FormType" as parent
-             // so we ignore it here for performance reasons
-             if (FormType::class !== $parentType) {
-                 return $this->isAnyInstanceOf($parentType, $classes);
-             }
-         }
-         return false;
-     }
-     /**
-      * @param array<string, mixed> $formOptions
-      *
-      * @return array<string, mixed>
-      */
-     private function getDefaultAdminTypeOptions(FieldDescriptionInterface $fieldDescription, array $formOptions): array
-     {
-         $typeOptions = [
-             'sonata_field_description' => $fieldDescription,
-             'data_class' => $fieldDescription->getAssociationAdmin()->getClass(),
-             'empty_data' => static fn (): object => $fieldDescription->getAssociationAdmin()->getNewInstance(),
-         ];
-         if (isset($formOptions['by_reference'])) {
-             $typeOptions['collection_by_reference'] = $formOptions['by_reference'];
-         }
-         return $typeOptions;
-     }
- }
-