kerrialnewham/autocomplete
Composer 安装命令:
composer require kerrialnewham/autocomplete
包简介
README 文档
README
Server-side rendered autocomplete for Symfony. No Tom Select, no build step. Twig templates + Stimulus. Highly customizable, just override the twig template.
Installation
composer require kerrialnewham/autocomplete
Add routes to config/routes.yaml:
autocomplete: resource: '@AutocompleteBundle/config/routes.php'
or
return static function (RoutingConfigurator $routingConfigurator): void { $routingConfigurator->import('@AutocompleteBundle/config/routes.php'); }
Add the form theme to config/packages/twig.yaml:
twig: form_themes: - '@Autocomplete/form/autocomplete_widget.html.twig'
or
return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->extension('twig', [ 'form_themes' => [ '@Autocomplete/form/autocomplete_widget.html.twig', ], ]); };
Include the CSS:
<link rel="stylesheet" href="{{ asset('bundles/autocomplete/autocomplete.css') }}">
Requires APP_SECRET in your .env for HMAC-signed requests.
Demos
Form Types
AutocompleteType
use Kerrialnewham\Autocomplete\Form\Type\AutocompleteType; $builder->add('user', AutocompleteType::class, [ 'provider' => UserProvider::class, 'placeholder' => 'Search for a user...', ]); $builder->add('tags', AutocompleteType::class, [ 'provider' => TagProvider::class, 'multiple' => true, 'theme' => 'dark', 'min_chars' => 2, 'debounce' => 500, 'limit' => 20, ]);
| Option | Type | Default | Description |
|---|---|---|---|
provider |
string | null |
Provider FQCN (e.g. UserProvider::class) |
multiple |
bool | false |
Multiple selections |
placeholder |
string | 'Search...' |
Placeholder text |
min_chars |
int | 1 |
Min characters before search |
debounce |
int | 300 |
Debounce in ms |
limit |
int | 10 |
Max results |
theme |
string|null | null |
Theme name |
floating_label |
bool|null | null |
Bootstrap 5 floating label support |
extra_params |
array | [] |
Extra query parameters passed to the provider |
attr |
array | [] |
HTML attributes |
InternationalDialCodeType
use Kerrialnewham\Autocomplete\Form\Type\InternationalDialCodeType; $builder->add('dialCode', InternationalDialCodeType::class);
Displays flag emoji, country name, and dial code.
Adding Autocomplete to Existing Types
Pass 'autocomplete' => true to any Symfony choice or entity type. Providers are resolved automatically.
$builder->add('author', EntityType::class, [ 'class' => User::class, 'autocomplete' => true, ]); $builder->add('status', EnumType::class, [ 'class' => Status::class, 'autocomplete' => true, ]); $builder->add('country', CountryType::class, [ 'autocomplete' => true, 'theme' => 'dark', ]); $builder->add('language', LanguageType::class, [ 'autocomplete' => true, ]); $builder->add('currency', CurrencyType::class, [ 'autocomplete' => true, ]); $builder->add('timezone', TimezoneType::class, [ 'autocomplete' => true, ]); $builder->add('locale', LocaleType::class, [ 'autocomplete' => true, ]);
Note: EntityType with autocomplete: true does not support the query_builder or closure-based choice_label options, because closures cannot survive the HTTP boundary between form rendering and the AJAX search request. Use a string choice_label (e.g. 'name') or create a custom provider instead.
Providers
Providers are identified by their fully qualified class name (FQCN). The AutocompleteProviderInterface has a single search() method — no getName() required.
Built-in
The built-in Symfony Intl providers are resolved automatically when using the corresponding form types with autocomplete: true (CountryType, LanguageType, etc.).
| Provider | Data |
|---|---|
CountryProvider |
Countries |
LanguageProvider |
Languages |
LocaleProvider |
Locales |
CurrencyProvider |
Currencies |
TimezoneProvider |
Timezones |
DialCodeProvider |
Dial codes with flag emoji |
Custom Provider
Implement AutocompleteProviderInterface for search. Add ChipProviderInterface for server-side chip rendering in multiple mode.
use Kerrialnewham\Autocomplete\Provider\Contract\AutocompleteProviderInterface; use Kerrialnewham\Autocomplete\Provider\Contract\ChipProviderInterface; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; #[AutoconfigureTag('autocomplete.provider')] class UserProvider implements AutocompleteProviderInterface, ChipProviderInterface { public function __construct(private readonly UserRepository $userRepository) {} public function search(string $query, int $limit, array $selected): array { return array_map(fn($user) => [ 'id' => (string) $user->getId(), 'label' => $user->getFullName(), 'meta' => ['email' => $user->getEmail()], ], $this->userRepository->searchByName($query, $limit, $selected)); } public function get(string $id): ?array { $user = $this->userRepository->find($id); if (!$user) return null; return [ 'id' => (string) $user->getId(), 'label' => $user->getFullName(), 'meta' => ['email' => $user->getEmail()], ]; } }
Reference the provider by its class name:
$builder->add('user', AutocompleteType::class, [ 'provider' => UserProvider::class, ]);
Results must return id (required), label (required), and meta (optional).
Extra Parameters
Use extra_params to pass context to your provider via the AJAX request. This is useful for dependent/filtered selects where the provider needs runtime context (e.g. filtering cities by the selected country).
$builder->add('city', AutocompleteType::class, [ 'provider' => CityProvider::class, 'extra_params' => [ 'country' => $country->getId(), ], ]);
Read them in your provider via RequestStack:
use Symfony\Component\HttpFoundation\RequestStack; #[AutoconfigureTag('autocomplete.provider')] class CityProvider implements AutocompleteProviderInterface { public function __construct( private readonly CityRepository $cityRepository, private readonly RequestStack $requestStack, ) {} public function search(string $query, int $limit, array $selected): array { $request = $this->requestStack->getCurrentRequest(); $countryId = $request?->query->get('country'); $qb = $this->cityRepository->createQueryBuilder('c') ->leftJoin('c.country', 'country') ->orderBy('c.name', 'ASC'); if ($countryId) { $qb->andWhere('country.id = :country') ->setParameter('country', $countryId, 'uuid'); } if (!empty($selected)) { $qb->andWhere($qb->expr()->notIn('c.id', ':selected')) ->setParameter('selected', $selected); } $cities = $qb->getQuery()->getResult(); $results = []; foreach ($cities as $city) { $label = $city->getName(); if ($query !== '' && !str_contains(mb_strtolower($label), mb_strtolower($query))) { continue; } $results[] = ['id' => (string) $city->getId(), 'label' => $label]; } return array_slice($results, 0, $limit); } }
Overriding Entity Providers
When using EntityType with autocomplete: true, a provider is auto-generated using the entity FQCN as the provider name (e.g. App\Entity\User). To override it, register a custom provider under the same name:
#[AutoconfigureTag('autocomplete.provider')] class UserProvider implements AutocompleteProviderInterface, ChipProviderInterface { // ... your custom search/get logic }
Then pass it via the provider option:
$builder->add('author', EntityType::class, [ 'class' => User::class, 'provider' => UserProvider::class, 'autocomplete' => true, ]);
Security
All AJAX requests are signed with HMAC-SHA256 using APP_SECRET. This happens automatically.
The signature binds the route name, provider, theme, translation domain, choice parameters, locale, user ID, and timestamp. Signatures expire after 10 minutes.
This prevents provider tampering, parameter injection, cross-user replay, and replay attacks. Invalid signatures return 403 Forbidden.
PhoneNumberType
Compound form type: dial code autocomplete + phone number text input. Stores as E.164 (e.g. +447911123456).
use Kerrialnewham\Autocomplete\Form\Type\PhoneNumberType; $builder->add('phone', PhoneNumberType::class, [ 'theme' => 'flowbite', ]);
GB+7911123456becomes+447911123456+447911123456becomes dial codeGB, number7911123456- NANP: longest dial code wins (
+1242...resolves to Bahamas, not US)
Doctrine DBAL Type
Registers automatically when Doctrine DBAL is available.
#[ORM\Column(type: 'phone_number', nullable: true)] private ?string $phone = null;
Maps to VARCHAR(20).
Themes
5 built-in themes, all in one CSS file, scoped via data-autocomplete-theme:
| Theme | Description |
|---|---|
default |
Clean, modern, pill-shaped chips |
dark |
Dark mode |
cards |
Card layout with metadata (avatar, email, role) |
bootstrap-5 |
Bootstrap 5 compatible |
flowbite |
Flowbite UI |
$builder->add('country', AutocompleteType::class, [ 'provider' => CountryProvider::class, 'theme' => 'dark', ]);
Floating Labels (Bootstrap 5)
The bootstrap-5 theme supports Bootstrap 5 floating labels. Set floating_label to true:
$builder->add('country', CountryType::class, [ 'autocomplete' => true, 'theme' => 'bootstrap-5', 'floating_label' => true, ]);
The label floats up on focus and when the input has content. Without floating_label, the label renders above the input as usual.
Overriding Templates
Override any template using Symfony's bundle template override. Create the file at templates/bundles/AutocompleteBundle/ with whatever markup you want.
Each theme has three templates:
| Template | Override path |
|---|---|
| Widget | templates/bundles/AutocompleteBundle/theme/{theme}/autocomplete.html.twig |
| Options | templates/bundles/AutocompleteBundle/theme/{theme}/_options.html.twig |
| Chip | templates/bundles/AutocompleteBundle/theme/{theme}/_chip.html.twig |
Example — override the options template:
{# templates/bundles/AutocompleteBundle/theme/default/_options.html.twig #} {% if results is empty %} <div class="no-results">Nothing found</div> {% else %} <ul> {% for item in results %} <li class="autocomplete-option" data-autocomplete-option-value="{{ item.id }}" data-autocomplete-option-label="{{ item.label|e('html_attr') }}"> {{ item.label }} </li> {% endfor %} </ul> {% endif %}
Use any HTML, any CSS framework. The only requirement is data-autocomplete-option-value / data-autocomplete-option-label on options and Stimulus data-*-target attributes on chips.
Overriding CSS
Target a specific theme:
[data-autocomplete-theme="default"] .autocomplete-input { border: 2px solid #4f46e5; }
Target all themes:
.autocomplete-option:hover { background-color: #eef2ff; }
Custom Theme
CSS-only — the default theme HTML is used, your CSS overrides styling:
[data-autocomplete-theme="my-theme"] .autocomplete-input { background: #667eea; color: white; }
$builder->add('field', AutocompleteType::class, [ 'provider' => UserProvider::class, 'theme' => 'my-theme', ]);
Full custom — create templates at templates/bundles/AutocompleteBundle/theme/my-theme/ with any markup you want.
Events
document.addEventListener('autocomplete:select', (e) => console.log(e.detail.item)); document.addEventListener('autocomplete:remove', (e) => console.log(e.detail.value));
Requirements
- PHP 8.1+, Symfony 6.4+, Stimulus Bundle 2.9+
- Doctrine ORM (optional, for entity autocomplete)
- Doctrine DBAL (optional, for phone number column type)
License
MIT
kerrialnewham/autocomplete 适用场景与选型建议
kerrialnewham/autocomplete 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.21k 次下载、GitHub Stars 达 6, 最近一次更新时间为 2026 年 01 月 05 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「autocomplete」 「symfony-bundle」 「stimulus」 「symfony-ux」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 kerrialnewham/autocomplete 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 kerrialnewham/autocomplete 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 kerrialnewham/autocomplete 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
The Cassandra php driver library IDE stubs which enables autocompletion in modern IDEs.
Use Stimulus in your Laravel app
Indexed Search Autocomplete - Extends the TYPO3 Core Extension Indexed_Search searchform with an autocomplete feature.
Symfony bundle for the Rekapager library
Symfony bundle for Cloudflare integration: trusted proxies, real client IP detection, forwarded headers.
Dadata API client (https://dadata.ru)
统计信息
- 总下载量: 1.21k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 6
- 点击次数: 14
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-01-05