x-one/autocomplete-bundle
Composer 安装命令:
composer require x-one/autocomplete-bundle
包简介
Integrates Symfony UX Autocomplete with additional enhancements
关键字:
README 文档
README
Paczka integrująca Symfony UX Autocomplete, oferująca pomocnicze klasy rozwijające funkcjonalność oraz ułatwiające definicję pól typu autocomplete.
- Instalacja
- Różnice w stosunku do Symfony UX Autocomplete
- Parametry w polach niepowiązanych z encjami
- Rozwój bundle
Instalacja
Dodaj prywatne repozytorium do pliku composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "git@bitbucket.org:majchw/autocomplete-bundle.git"
}
]
}
Uwaga: wymagana będzie autoryzacja poprzez klucz SSH — instrukcja.
Następnie, zainstaluj paczkę:
composer require x-one/autocomplete-bundle
Symfony Flex powinien automatycznie dodać nowe wpisy do plików config/bundles.php oraz assets/controllers.json:
return [
// ...
XOne\Bundle\AutocompleteBundle\XOneAutocompleteBundle::class => ['all' => true],
];
{
"controllers": {
"@x-one/autocomplete-bundle": {
"autocomplete": {
"enabled": true,
"fetch": "eager"
}
}
}
}
Finalnie, przebuduj assety:
yarn install --force
yarn watch
Różnice w stosunku do Symfony UX Autocomplete
Ogólna definicja pól oraz możliwości konfiguracji znajdują się w oficjalnej dokumentacji Symfony UX Autocomplete.
Definicja pola autocomplete
Klasy formularzy definiujące pola typu autocomplete powinny rozszerzać klasę AbstractEntityAutocompleteType:
// src/Form/Type/ProductAutocompleteFormType.php
use Symfony\UX\Autocomplete\Form\AsEntityAutocompleteField;
use Symfony\UX\Autocomplete\Form\ParentEntityAutocompleteType;
use XOne\Bundle\AutocompleteBundle\Form\Type\AbstractEntityAutocompleteType;
#[AsEntityAutocompleteField]
class ProductAutocompleteFormType extends AbstractEntityAutocompleteType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => Product::class,
'choice_label' => 'name',
]);
}
}
Dzięki temu nie trzeba podawać getParent(), które w rozszerzanej klasie zwraca AutocompleteEntityType
zamiast ParentEntityAutocompleteType przedstawianego w oficjalnej dokumentacji.
Obsługa filtracji w repozytoriach
Repozytoria mogą teraz implementować interfejs AutocompleteRepositoryInterface,
dzięki czemu będą automatyczne wykorzystywane w procesie filtracji. Przykładowo:
// src/Repository/ProductRepository.php
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use XOne\Bundle\AutocompleteBundle\Repository\AutocompleteRepositoryInterface;
class ProductRepository extends ServiceEntityRepository implements AutocompleteRepositoryInterface
{
public function addAutocompleteCriteria(QueryBuilder $queryBuilder, array $parameters): void
{
$rootAlias = current($queryBuilder->getRootAliases());
if ($query = $parameters['query']) {
$queryBuilder
->andWhere($queryBuilder->expr()->like("$rootAlias.name", ':query'))
->setParameter('query', "%$query%");
}
}
}
Tablica $parameters zawiera parametry query z URL. Wyszukiwana wartość zawsze dostępna jest pod kluczem query.
Uwaga: zwrócenie QueryBuilder w opcji filter_query pola autocomplete pomija repozytorium!
Przekazywanie parametrów
Największym problemem Symfony UX Autocomplete jest brak możliwości przekazania dodatkowych parametrów do podzapytania — ponieważ opcje, jakie przekażemy do formularza, są utracone w momencie wysłania żądania AJAX dla autocomplete.
W celu rozwiązania tego problemu bundle wprowadza nową opcję autocomplete_parameters:
// src/Form/Type/CategoryFormType.php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class CategoryFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
/** @var null|Category $category */
$category = $options['data'];
$builder
->add('products', ProductAutocompleteFormType::class, [
'autocomplete_parameters' => [
'category_id' => $data?->getId(),
],
])
;
}
}
Parametry te zostają przekazywane w URL zapytań AJAX. W powyższym przykładzie (zakładając, że przekazane ID kategorii to "1") będzie to:
/autocomplete/product?query=&product_id=1
Dzięki temu parametr ten można wyciągnąć w repozytorium:
// src/Repository/ProductRepository.php
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use XOne\Bundle\AutocompleteBundle\Repository\AutocompleteRepositoryInterface;
class ProductRepository extends ServiceEntityRepository implements AutocompleteRepositoryInterface
{
public function addAutocompleteCriteria(QueryBuilder $queryBuilder, array $parameters): void
{
$rootAlias = current($queryBuilder->getRootAliases());
if (isset($categoryId = $parameters['category_id'] ?? null)) {
$queryBuilder
->andWhere($queryBuilder->expr()->eq("$rootAlias.category", ':category'))
->setParameter('category', $categoryId);
}
}
}
Parametry o wartościach z innych pól formularza
W przypadku, gdy wartość parametr ma być pobrany z innego pola formularza,
do opcji autocomplete_parameters można przekazać konkretne pole formularza.
Poniższy przykład zakłada, że mamy formularz dla produktu, w którym możemy wybrać jego klasę oraz grupę. Grupa może być wybrana tylko spośród tych, które należą do wybranej klasy.
// src/Form/Type/ProductFormType.php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ProductFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('productClass', ProductClassAutocompleteFormType::class)
->add('productGroup', ProductGroupAutocompleteFormType::class, [
'autocomplete_parameters' => [
'product_class_id' => $builder->get('productClass'),
],
])
;
}
}
Jeśli nie ma opcji na pobranie pola formularza (bo powstaje on później w procesie budowania),
można przekazać instancję FormReference, w której podajemy jedynie nazwę pola:
// src/Form/Type/ProductFormType.php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use XOne\Bundle\AutocompleteBundle\Form\FormReference;
class ProductFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('productClass', ProductClassAutocompleteFormType::class)
->add('productGroup', ProductGroupAutocompleteFormType::class, [
'autocomplete_parameters' => [
'product_class_id' => new FormReference('productClass'),
],
])
;
}
}
Jeśli natomiast mamy pewność co do selektora CSS pola formularza, możemy przekazać go bezpośrednio:
// src/Form/Type/ProductFormType.php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use XOne\Bundle\AutocompleteBundle\Form\FormReference;
class ProductFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('productClass', ProductClassAutocompleteFormType::class)
->add('productGroup', ProductGroupAutocompleteFormType::class, [
'autocomplete_parameters' => [
'product_class_id' => '#product_form_productClass',
],
])
;
}
}
W powyższych przypadkach, do żądania AJAX pobierającego grupy produktów możliwe do wyboru,
zostanie doklejony parametr product_class_id z wartością wybraną w polu klasy produktu.
Przetwarzanie parametrów
Jeśli zaistnieje potrzeba, aby przetworzyć tablicę parametrów przed przekazaniem jej do repozytorium,
w klasie typu pola autocomplete można zaimplementować interfejs AutocompleteParametersTransformerInterface:
// src/Form/Type/ProductAutocompleteFormType.php
use Symfony\Component\Security\Core\Security;
use Symfony\UX\Autocomplete\Form\AsEntityAutocompleteField;
use Symfony\UX\Autocomplete\Form\ParentEntityAutocompleteType;
use XOne\Bundle\AutocompleteBundle\Form\AutocompleteParametersTransformerInterface;
use XOne\Bundle\AutocompleteBundle\Form\Type\AbstractEntityAutocompleteType;
#[AsEntityAutocompleteField]
class ProductAutocompleteFormType extends AbstractEntityAutocompleteType implements AutocompleteParametersTransformerInterface
{
public function __construct(
private Security $security,
) {
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => Product::class,
'choice_label' => 'name',
]);
}
public function transformAutocompleteParameters(array $parameters): array
{
// Add defaults...
$parameters += [
'category_id' => null,
];
// Cast to proper types if needed...
if ($parameters['category_id']) {
$parameters['category_id'] = (int) $parameters['category_id'];
}
// Add additional parameters...
$parameters['user_id'] = $this->security->getUser()?->getId();
return $parameters;
}
}
Metoda transformAutocompleteParameters() otrzymuje tablicę parametrów (wraz z wartościami), które przyszły podczas żądania AJAX.
Parametry w polach niepowiązanych z encjami
W niektórych sytuacjach zachodzi potrzeba funkcjonalności autocomplete na polach ChoiceType z opcjami ładowanymi
w sposób niestandardowy, np. customowym zapytaniem do bazy danych zwracającym tablicę klucz-wartość zamiast encji, lub z API.
W takim przypadku takowe pole konfigurujemy w następujący sposób:
$builder->add('client', ChoiceType::class, [
// Włączamy mechanizm autocomplete — wtedy pole renderuje się jako TomSelect
'autocomplete' => true,
// Ustawiamy URL, na którym zwracamy listę opcji zawężonych przez parametry
'autocomplete_url' => $this->urlGenerator->generate('panel_dummy_client_autocomplete'),
// Ustawiamy parametry, na podstawie których chcemy zawężać listę opcji
'autocomplete_parameters' => [
'name' => '#id_pola_po_ktorym_chcemy_ograniczać_klientów_po_nazwie',
],
]);
Następnie tworzymy endpoint, który zwróci listę opcji w formacie JSON z uwzględnieniem parametrów:
#[Route('/dummy-clients/autocomplete', name: 'panel_dummy_client_autocomplete', methods: ['GET'])]
public function autocomplete(Request $request): JsonResponse
{
$queryBuilder = $this->getEntityManager()->createQueryBuilder()
->select('DISTINCT c.name AS text', 'c.id AS value')
->from(DummyClient::class, 'c');
if ($name = $request->get('name')) {
$queryBuilder->andWhere('c.name LIKE :name')
->setParameter('name', '%'.$name.'%');
}
return new JsonResponse([
'results' => $queryBuilder->getQuery()->getResult(),
]);
}
W tym przypadku zapytanie nie zwraca encji DummyClient, a tablicę z kluczami text oraz value.
Z requestu jesteśmy w stanie pobrać przekazane parametry i na ich podstawie zawęzić wyniki — tak,
jak na przykładzie robimy to z ograniczeniem klientów po nazwie.
Co ważne, endpoint wg. dokumentacji UX Autocomplete musi zwrócić dane w formacie:
{
"results": [
{ "text": "Nagłówek 1", "value": "Wartość 1" },
{ "text": "Nagłówek 2", "value": "Wartość 2" }
]
}
Jeśli pole to może zawierać domyślną wartość (np. w akcji edycji), należy pamiętać o tym, aby zwrócić ją w początkowej tablicy choices, aby TomSelect mógł ją wyrenderować przed otwarciem selektora, np.:
$builder->add('clientId', ChoiceType::class, [
// W tym przypadku wartością tego pola może być ID jakiegoś klienta. Dla przykładu załóżmy,
// że wynosi ono "1". Taki identyfikator musi znaleźć się w tablicy "choices" jako "value".
// Pobrać go możemy w dowolny sposób, np. za pomocą repozytorium.
'choices' => [
['value' => 1, 'text' => 'Klient testowy 1'],
],
]);
Rozwój bundle
Upewnij się, że testy nie zwracają żadnego błędu, oraz kod jest poprawnie sformatowany:
composer run-script pre-commit-checks
Zbuduj pliki wynikowe:
bin/build-js
Wersjonowanie
Aby paczkę dało się zaktualizować przez composera, po zmergowaniu zmian do głównego brancha, należy utworzyć tag w formacie vX.Y.Z, np.
git tag -a v1.1.0 -m "Version v1.1.0"
git push origin --tags
x-one/autocomplete-bundle 适用场景与选型建议
x-one/autocomplete-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 3.83k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2023 年 10 月 10 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「symfony-ux」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 x-one/autocomplete-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 x-one/autocomplete-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 x-one/autocomplete-bundle 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Sylius eCommerce administration panel component.
Doctrine Block management made easy
Symfony bundle for the Rekapager library
File input dropzones multiple for Symfony Forms
Symfony UX Table with search, filter and sorting options.
Effortless file management with Symfony UX and Mezcalito UX FileManager
统计信息
- 总下载量: 3.83k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: Unknown
- 更新时间: 2023-10-10