Skip to content

Instantly share code, notes, and snippets.

@wizhippo
Last active February 8, 2025 20:04
Show Gist options
  • Save wizhippo/597bf56cd69dfd3682d8a0eee67ac5c0 to your computer and use it in GitHub Desktop.
Save wizhippo/597bf56cd69dfd3682d8a0eee67ac5c0 to your computer and use it in GitHub Desktop.
<?php
namespace App\Form\Filter\Type;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\CrudAutocompleteType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AutocompleteEntityFilterType extends CrudAutocompleteType
{
public function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);
// Needed because EasyCorp\Bundle\EasyAdminBundle\Filter\Configurator\EntityConfigurator
// sets a placeholder which CrudAutocompleteType does not support
$resolver->setDefault('placeholder', '');
}
}
<?php
class CrudController extends AbstractCrudController
{
public function configureFields(string $pageName): iterable
{
...
$adminContext = $this->getContext();
yield AssociationField::new('parent', 'Parent')
->autocomplete()
->setQueryBuilder(
function (QueryBuilder $qb) use ($adminContext) {
return $qb
->andWhere(
$qb->expr()->like(
$qb->expr()->upper('entity.commonname'),
':name'
)
)
->setParameter('name', '%'.strtoupper($adminContext->getSearch()->getQuery()).'%')
;
}
)
->setSortProperty('commonname');
...
}
...
}
<?php
namespace App\EasyAdmin\Filter\Configurator;
use App\Form\Filter\Type\AutocompleteEntityFilterType;
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Filter\FilterConfiguratorInterface;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FilterDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
final class EntityConfigurator implements FilterConfiguratorInterface
{
private AdminUrlGenerator $adminUrlGenerator;
public function __construct(AdminUrlGenerator $adminUrlGenerator)
{
$this->adminUrlGenerator = $adminUrlGenerator;
}
public function supports(
FilterDto $filterDto,
?FieldDto $fieldDto,
EntityDto $entityDto,
AdminContext $context
): bool {
return EntityFilter::class === $filterDto->getFqcn();
}
public function configure(
FilterDto $filterDto,
?FieldDto $fieldDto,
EntityDto $entityDto,
AdminContext $context
): void {
$propertyName = $filterDto->getProperty();
if (!$entityDto->isAssociation($propertyName)) {
return;
}
if ($fieldDto && $fieldDto->getCustomOption(AssociationField::OPTION_AUTOCOMPLETE)) {
$doctrineMetadata = $entityDto->getPropertyMetadata($propertyName);
$targetEntityFqcn = $doctrineMetadata->get('targetEntity');
$targetCrudControllerFqcn = $context->getCrudControllers()->findCrudFqcnByEntityFqcn($targetEntityFqcn);
if (null === $targetCrudControllerFqcn) {
throw new \RuntimeException(
sprintf(
'The "%s" field cannot be autocompleted because it doesn\'t define the related CRUD controller FQCN with the "setCrudController()" method.',
$filterDto->getProperty()
)
);
}
if ($targetCrudControllerFqcn) {
$filterDto->setFormTypeOptionIfNotSet('value_type', AutocompleteEntityFilterType::class);
try {
$autocompleteEndpointUrl = $this->adminUrlGenerator
->unsetAll()
->set('page', 1)
->setController($targetCrudControllerFqcn)
->setAction('autocomplete')
->set(AssociationField::PARAM_AUTOCOMPLETE_CONTEXT, [
// when using pretty URLs, the data is in the request attributes instead of the autocomplete context
EA::CRUD_CONTROLLER_FQCN => $context->getRequest()->attributes->get(
EA::CRUD_CONTROLLER_FQCN
) ?? $context->getRequest()->query->get(EA::CRUD_CONTROLLER_FQCN),
'propertyName' => $propertyName,
'originatingPage' => $context->getCrud()->getCurrentAction(),
])
->generateUrl()
;
} catch (RouteNotFoundException $e) {
// this may throw a "route not found" exception if the associated entity is not
// accessible from this dashboard; do nothing in that case.
}
$filterDto->setFormTypeOptionIfNotSet(
'value_type_options.attr.data-ea-autocomplete-endpoint-url',
$autocompleteEndpointUrl ?? null
);
}
}
}
}
services:
_defaults:
autowire: true
autoconfigure: true
App\EasyAdmin\Filter\Configurator\:
resource: '../../src/EasyAdmin/Filter/Configurator/*'
exclude: '../../src/EasyAdmin/Filter/Configurator/Abstract*'
App\EasyAdmin\Filter\Configurator\EntityConfigurator:
tags:
- { name: ea.filter_configurator, priority: -5 }
@walva
Copy link

walva commented Dec 21, 2024

Many Thanks, it helps a lot !!

@gregoire-jianda
Copy link

gregoire-jianda commented Jan 21, 2025

@wizhippo This was working perfectly for me but now it fails due to missing parameters (CrudControllerFqcn). I think it's related to the new friendly urls somehow, did you encounter the issue ?

EDIT : for anyone looking, replace line 62 of EntityFilterConfigurator with :

EA::CRUD_CONTROLLER_FQCN => $context->getRequest()->attributes->get(EA::CRUD_CONTROLLER_FQCN) ?? $context->getRequest()->query->get(EA::CRUD_CONTROLLER_FQCN)

@wizhippo
Copy link
Author

@gregoire-jianda I updated today and did not run into this. thanks for reporting incase others do return into it.

@gregoire-jianda
Copy link

@wizhippo The issue only arises if you use friendly URLs, and for some reason there is a caching effect. I only noticed the filter was broken a few days after I enabled friendly urls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment