EasyAdminBundle
EasyAdminBundle copied to clipboard
Custom entity name representation for autocomplete
Hi everyone!
Allow one to customize the string representation of an entity for the autocomplete field:
The current implementation doesn't allow one to change the way an entity is represented in an autocomplete field. The EntityPaginator::getResultsAsJson
method doesn't leverage any extension point.
class EntityPaginator
{
public function getResultsAsJson(): string
{
foreach ($this->getResults() ?? [] as $entityInstance) {
$entityDto = $this->entityFactory->createForEntityInstance($entityInstance);
$jsonResult['results'][] = [
'entityId' => $entityDto->getPrimaryKeyValueAsString(),
'entityAsString' => $entityDto->toString(), // <------------ unable to change this hardcoded statement
];
}
$jsonResult['has_next_page'] = $this->hasNextPage();
return json_encode($jsonResult);
}
}
Of course, we can use the __toString()
method but in my case I need a different representation that is not the one I use elsewhere with my already implemented __toString
method.
I'm using the autocomple feature to allow the user find and select a US city among thousands cities in the database. As you know, you can have cities with the same name in different US states. My current Locality::__toString
method already returns the city name because this is what I just need everywhere else I want to output a Locality
entity as a string.
However, for the autocomplete field, I need to render the Locality
instance a little bit differently to also show the US state name:
Nevada > Las Vegas
New Mexico > Las Vegas
For now, I'm fully overriding the autocomplete
action of the base CRUD controller but that's a lot of work for just changing the way an entity is converted to string.
Potential solutions
- Add the possibility to configure a callback function in the CRUD object for the autocomplete only
public function configureCrud(Crud $crud): Crud
{
return $crud
->setAutocompleteInstanceNormalizer(static fn (Locality $entity) => $entity->myCustomStringRendering());
}
- Inject this custom callback in the
EntityPaginator::getResultsAsJson
method
public function autocomplete(AdminContext $context): JsonResponse
{
// ...
return JsonResponse::fromJsonString($paginator->getResultsAsJson($context->getAutocompleteInstanceNormalizer()));
}
- The
getResultsAsJson
method will receive acallable
ornull
value. If it's given acallable
, then call it to compute the entity string name, otherwise fallback on__toString
(if it exists) or the default implementation.
class EntityPaginator
{
public function getResultsAsJson(callable $entityAsStringNormalizer = null): string
{
foreach ($this->getResults() ?? [] as $entityInstance) {
$entityDto = $this->entityFactory->createForEntityInstance($entityInstance);
// Solution 1: the normalizer is invoked here instead of the DTO::toString method
$entityAsString = $entityAsStringNormalizer ? \call_user_func_array($callable, [$entityInstance]) : $entityDto->toString();
// Solution 2: the normalizer is given to the DTO
$entityAsString = $entityDto->toString($entityAsStringNormalizer);
$jsonResult['results'][] = [
'entityId' => $entityDto->getPrimaryKeyValueAsString(),
'entityAsString' => $entityAsString
];
}
$jsonResult['has_next_page'] = $this->hasNextPage();
return json_encode($jsonResult);
}
}
What do you think of this pragmatic approach?
@javiereguiluz do you have any feedbacks to provide en this please?
@hhamon For me this looks like a perfect and really clean solution.. Do you plan to do a PR?
@hhamon Please create a PR for this as I also need this in my project.
I took a step forward and implemented this solution in #5189. It would be great if you guys took a spin on that and test it in your projects to make sure it works as expected and solves your requirements :smile_cat:
Also - code reviews would be great :+1:
@Lustmored - I have tested. Works great.
Thanks!!!!