diff --git a/src/Autocomplete/src/AutocompleteResultsExecutor.php b/src/Autocomplete/src/AutocompleteResultsExecutor.php index 03d10e03466..ddbbaf26632 100644 --- a/src/Autocomplete/src/AutocompleteResultsExecutor.php +++ b/src/Autocomplete/src/AutocompleteResultsExecutor.php @@ -14,7 +14,6 @@ use Doctrine\ORM\Tools\Pagination\Paginator; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; -use Symfony\Component\PropertyAccess\PropertyAccessor; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\PropertyAccess\PropertyPathInterface; @@ -26,22 +25,11 @@ */ final class AutocompleteResultsExecutor { - private PropertyAccessorInterface $propertyAccessor; - private ?Security $security; - public function __construct( private DoctrineRegistryWrapper $managerRegistry, - $propertyAccessor, - /* Security $security = null */ + private PropertyAccessorInterface $propertyAccessor, + private ?Security $security = null, ) { - if ($propertyAccessor instanceof Security) { - trigger_deprecation('symfony/ux-autocomplete', '2.8.0', 'Passing a "%s" instance as the second argument of "%s()" is deprecated, pass a "%s" instance instead.', Security::class, __METHOD__, PropertyAccessorInterface::class); - $this->security = $propertyAccessor; - $this->propertyAccessor = new PropertyAccessor(); - } else { - $this->propertyAccessor = $propertyAccessor; - $this->security = \func_num_args() >= 3 ? func_get_arg(2) : null; - } } public function fetchResults(EntityAutocompleterInterface $autocompleter, string $query, int $page): AutocompleteResults diff --git a/src/Autocomplete/src/DependencyInjection/AutocompleteExtension.php b/src/Autocomplete/src/DependencyInjection/AutocompleteExtension.php index 3dec572a11b..c4f6f26672a 100644 --- a/src/Autocomplete/src/DependencyInjection/AutocompleteExtension.php +++ b/src/Autocomplete/src/DependencyInjection/AutocompleteExtension.php @@ -29,7 +29,6 @@ use Symfony\UX\Autocomplete\Form\AsEntityAutocompleteField; use Symfony\UX\Autocomplete\Form\AutocompleteChoiceTypeExtension; use Symfony\UX\Autocomplete\Form\BaseEntityAutocompleteType; -use Symfony\UX\Autocomplete\Form\ParentEntityAutocompleteType; use Symfony\UX\Autocomplete\Form\WrappedEntityTypeAutocompleter; use Symfony\UX\Autocomplete\Maker\MakeAutocompleteField; @@ -147,14 +146,6 @@ private function registerFormServices(ContainerBuilder $container): void ]) ->addTag('form.type'); - $container - ->register('ux.autocomplete.entity_type', ParentEntityAutocompleteType::class) - ->setDeprecated('symfony/ux-autocomplete', '2.13', 'The "%service_id%" form type is deprecated since 2.13. Use "ux.autocomplete.base_entity_type" instead.') - ->setArguments([ - new Reference('router'), - ]) - ->addTag('form.type'); - $container ->register('ux.autocomplete.choice_type_extension', AutocompleteChoiceTypeExtension::class) ->setArguments([ diff --git a/src/Autocomplete/src/Doctrine/EntityMetadata.php b/src/Autocomplete/src/Doctrine/EntityMetadata.php index 6094d0b45e1..b6fed37bc0a 100644 --- a/src/Autocomplete/src/Doctrine/EntityMetadata.php +++ b/src/Autocomplete/src/Doctrine/EntityMetadata.php @@ -42,17 +42,6 @@ public function isEmbeddedClassProperty(string $propertyName): bool return \array_key_exists($propertyNameParts[0], $this->metadata->embeddedClasses); } - public function getPropertyMetadata(string $propertyName): array - { - trigger_deprecation('symfony/ux-autocomplete', '2.15.0', 'Calling EntityMetadata::getPropertyMetadata() is deprecated. You should stop using it, as it will be removed in the future.'); - - try { - return $this->getFieldMetadata($propertyName); - } catch (\InvalidArgumentException $e) { - return $this->getAssociationMetadata($propertyName); - } - } - /** * @internal * diff --git a/src/Autocomplete/src/Form/AutocompleteEntityTypeSubscriber.php b/src/Autocomplete/src/Form/AutocompleteEntityTypeSubscriber.php deleted file mode 100644 index 24c255c705e..00000000000 --- a/src/Autocomplete/src/Form/AutocompleteEntityTypeSubscriber.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\Autocomplete\Form; - -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Utility\PersisterHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; - -/** - * Helps transform ParentEntityAutocompleteType into a EntityType that will not load all options. - * - * @internal - * - * @deprecated since Symfony UX 2.13 - */ -final class AutocompleteEntityTypeSubscriber implements EventSubscriberInterface -{ - public function __construct( - private ?string $autocompleteUrl = null, - ) { - } - - public function preSetData(FormEvent $event) - { - $form = $event->getForm(); - $data = $event->getData() ?: []; - - $options = $form->getConfig()->getOptions(); - $options['compound'] = false; - $options['choices'] = is_iterable($data) ? $data : [$data]; - // pass to AutocompleteChoiceTypeExtension - $options['autocomplete'] = true; - $options['autocomplete_url'] = $this->autocompleteUrl; - unset($options['searchable_fields'], $options['security'], $options['filter_query']); - - $form->add('autocomplete', EntityType::class, $options); - } - - public function preSubmit(FormEvent $event) - { - $data = $event->getData(); - $form = $event->getForm(); - $options = $form->get('autocomplete')->getConfig()->getOptions(); - - /** @var EntityManagerInterface $em */ - $em = $options['em']; - $repository = $em->getRepository($options['class']); - $queryBuilder = $options['query_builder'] ?: $repository->createQueryBuilder('o'); - $rootAlias = $queryBuilder->getRootAliases()[0]; - - if (!isset($data['autocomplete']) || '' === $data['autocomplete']) { - $options['choices'] = []; - } else { - $idField = $options['id_reader']->getIdField(); - $idType = PersisterHelper::getTypeOfField($idField, $em->getClassMetadata($options['class']), $em)[0]; - - if ($options['multiple']) { - $params = []; - $idx = 0; - - foreach ($data['autocomplete'] as $id) { - $params[":id_$idx"] = [$id, $idType]; - ++$idx; - } - - if ($params) { - $queryBuilder - ->andWhere(\sprintf("$rootAlias.$idField IN (%s)", implode(', ', array_keys($params)))) - ; - foreach ($params as $key => $param) { - $queryBuilder->setParameter($key, $param[0], $param[1]); - } - } - - $options['choices'] = $queryBuilder->getQuery()->getResult(); - } else { - $options['choices'] = $queryBuilder - ->andWhere("$rootAlias.$idField = :id") - ->setParameter('id', $data['autocomplete'], $idType) - ->getQuery() - ->getResult(); - } - } - - // reset some critical lazy options - unset($options['em'], $options['loader'], $options['empty_data'], $options['choice_list'], $options['choices_as_values']); - - $form->add('autocomplete', EntityType::class, $options); - } - - public static function getSubscribedEvents(): array - { - return [ - FormEvents::PRE_SET_DATA => 'preSetData', - FormEvents::PRE_SUBMIT => 'preSubmit', - ]; - } -} diff --git a/src/Autocomplete/src/Form/BaseEntityAutocompleteType.php b/src/Autocomplete/src/Form/BaseEntityAutocompleteType.php index 18804b7753f..8956a7a2300 100644 --- a/src/Autocomplete/src/Form/BaseEntityAutocompleteType.php +++ b/src/Autocomplete/src/Form/BaseEntityAutocompleteType.php @@ -19,7 +19,6 @@ use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\UX\Autocomplete\Form\ChoiceList\Loader\ExtraLazyChoiceLoader; /** * All form types that want to expose autocomplete functionality should use this for its getParent(). @@ -43,11 +42,7 @@ public function configureOptions(OptionsResolver $resolver): void return null; } - if (class_exists(LazyChoiceLoader::class)) { - return new LazyChoiceLoader($loader); - } - - return new ExtraLazyChoiceLoader($loader); + return new LazyChoiceLoader($loader); }; $resolver->setDefaults([ diff --git a/src/Autocomplete/src/Form/ChoiceList/Loader/ExtraLazyChoiceLoader.php b/src/Autocomplete/src/Form/ChoiceList/Loader/ExtraLazyChoiceLoader.php deleted file mode 100644 index c027ab65aaa..00000000000 --- a/src/Autocomplete/src/Form/ChoiceList/Loader/ExtraLazyChoiceLoader.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\Autocomplete\Form\ChoiceList\Loader; - -use Symfony\Component\Form\ChoiceList\ArrayChoiceList; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; - -/** - * Loads choices on demand only. - * - * @deprecated since Symfony UX 2.23 and will be removed in 3.0, use `Symfony\Component\Form\ChoiceList\Loader\LazyChoiceLoader` instead. - */ -class ExtraLazyChoiceLoader implements ChoiceLoaderInterface -{ - private ?ChoiceListInterface $choiceList = null; - - public function __construct( - private readonly ChoiceLoaderInterface $decorated, - ) { - } - - public function loadChoiceList(?callable $value = null): ChoiceListInterface - { - return $this->choiceList ??= new ArrayChoiceList([], $value); - } - - public function loadChoicesForValues(array $values, ?callable $value = null): array - { - $choices = $this->decorated->loadChoicesForValues($values, $value); - $this->choiceList = new ArrayChoiceList($choices, $value); - - return $choices; - } - - public function loadValuesForChoices(array $choices, ?callable $value = null): array - { - $values = $this->decorated->loadValuesForChoices($choices, $value); - $this->loadChoicesForValues($values, $value); - - return $values; - } -} diff --git a/src/Autocomplete/src/Form/ParentEntityAutocompleteType.php b/src/Autocomplete/src/Form/ParentEntityAutocompleteType.php deleted file mode 100644 index be088ce5089..00000000000 --- a/src/Autocomplete/src/Form/ParentEntityAutocompleteType.php +++ /dev/null @@ -1,118 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\Autocomplete\Form; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\DataMapperInterface; -use Symfony\Component\Form\Exception\RuntimeException; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\FormView; -use Symfony\Component\OptionsResolver\Options; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; - -/** - * All form types that want to expose autocomplete functionality should use this for its getParent(). - * - * @deprecated since Symfony UX 2.13, use "Symfony\UX\Autocomplete\Form\BaseEntityAutocompleteType" instead - */ -final class ParentEntityAutocompleteType extends AbstractType implements DataMapperInterface -{ - public function __construct( - private UrlGeneratorInterface $urlGenerator, - ) { - } - - public function buildForm(FormBuilderInterface $builder, array $options): void - { - $formType = $builder->getType()->getInnerType(); - $attribute = AsEntityAutocompleteField::getInstance($formType::class); - - if (!$attribute && empty($options['autocomplete_url'])) { - throw new \LogicException(\sprintf('You must either provide your own autocomplete_url, or add #[AsEntityAutocompleteField] attribute to "%s".', $formType::class)); - } - - // Use the provided URL, or auto-generate from the provided alias - $autocompleteUrl = $options['autocomplete_url'] ?? $this->urlGenerator->generate($attribute->getRoute(), [ - 'alias' => $attribute->getAlias() ?: AsEntityAutocompleteField::shortName($formType::class), - ]); - - $builder - ->addEventSubscriber(new AutocompleteEntityTypeSubscriber($autocompleteUrl)) - ->setDataMapper($this); - } - - public function finishView(FormView $view, FormInterface $form, array $options): void - { - // Add a custom block prefix to inner field to ease theming: - array_splice($view['autocomplete']->vars['block_prefixes'], -1, 0, 'ux_entity_autocomplete_inner'); - // this IS A compound (i.e. has children) field - // however, we only render the child "autocomplete" field. So for rendering, fake NOT compound - // This is a hack and we should check into removing it in the future - $view->vars['compound'] = false; - // the above, unfortunately, can also trick other things that might use - // "compound" for other reasons. This, at least, leaves a hint. - $view->vars['compound_data'] = true; - } - - public function configureOptions(OptionsResolver $resolver): void - { - $resolver->setDefaults([ - 'multiple' => false, - // force display errors on this form field - 'error_bubbling' => false, - // set to the fields to search on or null to search on all fields - 'searchable_fields' => null, - // override the search logic - set to a callable: - // function(QueryBuilder $qb, string $query, EntityRepository $repository) { - // $qb->andWhere('entity.name LIKE :filter OR entity.description LIKE :filter') - // ->setParameter('filter', '%'.$query.'%'); - // } - 'filter_query' => null, - // set to the string role that's required to view the autocomplete results - // or a callable: function(Symfony\Bundle\SecurityBundle\Security $security): bool - 'security' => false, - // set the max results number that a query on automatic endpoint return. - 'max_results' => 10, - ]); - - $resolver->setRequired(['class']); - $resolver->setAllowedTypes('security', ['boolean', 'string', 'callable']); - $resolver->setAllowedTypes('max_results', ['int', 'null']); - $resolver->setAllowedTypes('filter_query', ['callable', 'null']); - $resolver->setNormalizer('searchable_fields', function (Options $options, ?array $searchableFields) { - if (null !== $searchableFields && null !== $options['filter_query']) { - throw new RuntimeException('Both the searchable_fields and filter_query options cannot be set.'); - } - - return $searchableFields; - }); - } - - public function getBlockPrefix(): string - { - return 'ux_entity_autocomplete'; - } - - public function mapDataToForms($data, $forms): void - { - $form = current(iterator_to_array($forms, false)); - $form->setData($data); - } - - public function mapFormsToData($forms, &$data): void - { - $form = current(iterator_to_array($forms, false)); - $data = $form->getData(); - } -}