Skip to content

Commit

Permalink
[Autocomplete] Configurable results
Browse files Browse the repository at this point in the history
  • Loading branch information
J-Ben87 authored and smnandre committed Feb 6, 2025
1 parent ec09cdf commit 44c0e1d
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/Autocomplete/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Deprecate `ExtraLazyChoiceLoader` in favor of `Symfony\Component\Form\ChoiceList\Loader\LazyChoiceLoader`
- Reset TomSelect when updating url attribute #1505
- Add `getAttributes()` method to define additional attributes for autocomplete results #2541

## 2.22.0

Expand Down
27 changes: 19 additions & 8 deletions src/Autocomplete/src/AutocompleteResultsExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ public function fetchResults(EntityAutocompleterInterface $autocompleter, string

if (!method_exists($autocompleter, 'getGroupBy') || null === $groupBy = $autocompleter->getGroupBy()) {
foreach ($paginator as $entity) {
$results[] = [
'value' => $autocompleter->getValue($entity),
'text' => $autocompleter->getLabel($entity),
];
$results[] = $this->formatResult($autocompleter, $entity);
}

return new AutocompleteResults($results, $hasNextPage);
Expand Down Expand Up @@ -104,10 +101,7 @@ public function fetchResults(EntityAutocompleterInterface $autocompleter, string
$optgroupLabels = [];

foreach ($paginator as $entity) {
$result = [
'value' => $autocompleter->getValue($entity),
'text' => $autocompleter->getLabel($entity),
];
$result = $this->formatResult($autocompleter, $entity);

$groupLabels = $groupBy($entity, $result['value'], $result['text']);

Expand All @@ -124,4 +118,21 @@ public function fetchResults(EntityAutocompleterInterface $autocompleter, string

return new AutocompleteResults($results, $hasNextPage, $optgroups);
}

/**
* @return array<string, mixed>
*/
private function formatResult(EntityAutocompleterInterface $autocompleter, object $entity): array
{
$attributes = [];
if (method_exists($autocompleter, 'getAttributes')) {
$attributes = $autocompleter->getAttributes($entity);
}

return [
...$attributes,
'value' => $autocompleter->getValue($entity),
'text' => $autocompleter->getLabel($entity),
];
}
}
24 changes: 23 additions & 1 deletion src/Autocomplete/src/EntityAutocompleterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,50 @@
/**
* Interface for classes that will have an "autocomplete" endpoint exposed.
*
* @method mixed getGroupBy() Return group_by option.
* @template T of object
*
* TODO Remove next lines for Symfony UX 3
*
* @method array getAttributes(object $entity) Returns extra attributes to add to the autocomplete result.
* @method mixed getGroupBy() Return group_by option.
*/
interface EntityAutocompleterInterface
{
/**
* The fully-qualified entity class this will be autocompleting.
*
* @return class-string<T>
*/
public function getEntityClass(): string;

/**
* Create a query builder that filters for the given "query".
*
* @param EntityRepository<T> $repository
*/
public function createFilteredQueryBuilder(EntityRepository $repository, string $query): QueryBuilder;

/**
* Returns the "choice_label" used to display this entity.
*
* @param T $entity
*/
public function getLabel(object $entity): string;

/**
* Returns the "value" attribute for this entity, usually the id.
*
* @param T $entity
*/
public function getValue(object $entity): mixed;

/**
* Returns extra attributes to add to the autocomplete result.
*
* TODO Uncomment for Symfony UX 3
*/
/* public function getAttributes(object $entity): array; */

/**
* Return true if access should be granted to the autocomplete results for the current user.
*
Expand All @@ -51,6 +71,8 @@ public function isGranted(Security $security): bool;

/*
* Return group_by option.
*
* TODO Uncomment for Symfony UX 3
*/
/* public function getGroupBy(): mixed; */
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Symfony\UX\Autocomplete\Tests\Fixtures\Autocompleter;

class CustomAttributesProductAutocompleter extends CustomProductAutocompleter
{
public function getAttributes(object $entity): array
{
return [
'disabled' => true,
'value' => 'This value should be replaced with the result of getValue()',
'text' => 'This value should be replaced with the result of getText()',
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
use Symfony\UX\Autocomplete\EntityAutocompleterInterface;
use Symfony\UX\Autocomplete\Tests\Fixtures\Entity\Product;

/**
* @implements EntityAutocompleterInterface<Product>
*/
class CustomProductAutocompleter implements EntityAutocompleterInterface
{
public function __construct(
Expand Down Expand Up @@ -58,6 +61,11 @@ public function getValue(object $entity): mixed
return $entity->getId();
}

public function getAttributes(object $entity): array
{
return [];
}

public function isGranted(Security $security): bool
{
if ($this->requestStack->getCurrentRequest()?->query->get('enforce_test_security')) {
Expand Down
8 changes: 8 additions & 0 deletions src/Autocomplete/tests/Fixtures/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\UX\Autocomplete\AutocompleteBundle;
use Symfony\UX\Autocomplete\DependencyInjection\AutocompleteFormTypePass;
use Symfony\UX\Autocomplete\Tests\Fixtures\Autocompleter\CustomAttributesProductAutocompleter;
use Symfony\UX\Autocomplete\Tests\Fixtures\Autocompleter\CustomGroupByProductAutocompleter;
use Symfony\UX\Autocomplete\Tests\Fixtures\Autocompleter\CustomProductAutocompleter;
use Symfony\UX\Autocomplete\Tests\Fixtures\Form\ProductType;
Expand Down Expand Up @@ -176,6 +177,13 @@ protected function configureContainer(ContainerConfigurator $c): void
'alias' => 'custom_group_by_product',
]);

$services->set(CustomAttributesProductAutocompleter::class)
->public()
->arg(1, new Reference('ux.autocomplete.entity_search_util'))
->tag(AutocompleteFormTypePass::ENTITY_AUTOCOMPLETER_TAG, [
'alias' => 'custom_attributes_product',
]);

$services->alias('public.results_executor', 'ux.autocomplete.results_executor')
->public();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\Autocomplete\Tests\Integration;

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\UX\Autocomplete\AutocompleteResultsExecutor;
use Symfony\UX\Autocomplete\Tests\Fixtures\Autocompleter\CustomAttributesProductAutocompleter;
use Symfony\UX\Autocomplete\Tests\Fixtures\Factory\ProductFactory;
use Symfony\UX\Autocomplete\Tests\Fixtures\Kernel;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;

class AutocompleteResultsExecutorTest extends KernelTestCase
{
use Factories;
use ResetDatabase;

public function testItReturnsExtraAttributes(): void
{
$kernel = new Kernel('test', true);
$kernel->disableForms();
$kernel->boot();

$product = ProductFactory::createOne(['name' => 'Foo']);

/** @var AutocompleteResultsExecutor $executor */
$executor = $kernel->getContainer()->get('public.results_executor');
$autocompleter = $kernel->getContainer()->get(CustomAttributesProductAutocompleter::class);
$data = $executor->fetchResults($autocompleter, '', 1);
$this->assertCount(1, $data->results);
$this->assertSame(['disabled' => true, 'value' => $product->getId(), 'text' => 'Foo'], $data->results[0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
use Symfony\UX\LiveComponent\Test\InteractsWithLiveComponents;
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\Component2;
use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CategoryFixtureEntityFactory;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;

/**
* @author Kevin Bond <[email protected]>
*/
final class InteractsWithLiveComponentsTest extends KernelTestCase
{
use Factories;
use InteractsWithLiveComponents;
use ResetDatabase;

Expand Down
2 changes: 2 additions & 0 deletions src/LiveComponent/tests/Unit/Form/ComponentWithFormTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\FormComponentWithManyDifferentFieldsType;
use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CategoryFixtureEntityFactory;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;

/**
* @author Jakub Caban <[email protected]>
*/
class ComponentWithFormTest extends KernelTestCase
{
use Factories;
use ResetDatabase;

public function testFormValues(): void
Expand Down

0 comments on commit 44c0e1d

Please sign in to comment.