x-one/autocomplete-bundle
x-one/autocomplete-bundle adds autocomplete support to PHP applications, offering a simple backend for suggestion endpoints and helpers to connect search-as-you-type fields to your forms. Lightweight and framework-friendly, it reduces boilerplate when building autocomplete and suggestion features.
This bundle wraps symfony/ux-autocomplete (which in turn wraps Tom Select) and adds its own enhancements on top. Because the repository is small, private, and has no public dependents or star signal, treat the README as the primary spec and verify every claim against src/ before committing to it.
composer require x-one/autocomplete-bundle, then check config/bundles.php — if the bundle wasn't auto-registered, add it yourself. Confirm the composer.json constraint on symfony/ux-autocomplete and on PHP; a stale pin here is the most common reason the asset build silently produces the wrong Tom Select version.README.md → composer.json → src/DependencyInjection/*Extension.php → src/Resources/config/services.* → assets/ (or src/Resources/assets/) for the Stimulus controller. The DI extension tells you which services are public, what parameters exist (route names, default options), and whether anything is auto-configured by tag.controllers.json or in a manual app.register(...) call.<select> on an admin form (users, categories, tags) and convert it. Instantiate the bundle's field type (or AutocompleteField with the bundle's default options), point autocomplete at either a route name or a URL, and confirm the JSON response shape the controller expects. Get one field round-tripping in the browser before you touch config.The realistic day-one outcome is a single working autocomplete on an entity relation, plus a clear answer to "does this bundle add anything over plain symfony/ux-autocomplete, or is it just a convenience wrapper?"
Form-type-first usage. The bundle's value is almost certainly a form type that pre-configures options. Use it as the base class for your own field types rather than scattering 'autocomplete' => true across every form:
final class UserAutocompleteType extends AbstractType
{
public function getParent(): string
{
return UserAutocompleteFieldType::class; // from the bundle
}
}
This keeps route names, minimum query length, and Tom Select config in one place and makes a future swap back to vanilla UX Autocomplete a one-file change.
Endpoint contract. Whatever controller you write for the AJAX source must return the shape the JS expects — typically {"results": [{"value": 1, "text": "Jane Doe"}, ...]}. Wrap your Doctrine query in a small service so the controller stays thin, and always apply setMaxResults() plus a minimum-length guard. Return [] for queries under the threshold rather than leaking a full table scan.
Transformer pattern for entities. For entity selection, back the field with an EntityType-style transformer and have the endpoint accept ?query= and return id/label pairs. On the read side, hydrate the initial selected value server-side so the field renders correctly before any JS runs — this is where hand-rolled autocompletes usually break, and it's worth checking whether the bundle handles it for you.
Cascading / dependent fields. For country → city style flows, chain controllers: on change of the parent, set the child's Tom Select load URL or clear and re-init with a query parameter. Do the URL templating in Twig data-* attributes, not by string-concatenating in JS, so route generation stays in one place.
Integration tips.
assets/controllers.json if possible; if the bundle predates that convention, register it manually in app.js and note it in your upgrade checklist.#[AsDecorator]) rather than forking — enhancement layers like this tend to be thin, and decoration survives upstream updates better.$client->request('GET', '/autocomplete/users', ['query' => 'ja'])) asserting status, content type, and payload shape. This is your regression net if the bundle's JS assumptions drift.maxItems + server-side paging over loading everything; verify the bundle doesn't override your maxItems in its default options.Adoption risk is the headline. Zero stars, zero dependents, and a Bitbucket-only repo means no community debugging surface. Before production use: pin an exact commit (not ^1.0), read the whole src/ tree (it's likely under a few hundred lines), and be prepared to vendor-fork. If the "enhancements" turn out to be minor, using symfony/ux-autocomplete directly is the lower-risk choice.
Version alignment. The bundle must agree with your installed symfony/ux-autocomplete and, transitively, the Tom Select version. A mismatch shows up as missing methods on TomSelect instances or a controller that never fires — check node_modules/tom-select/package.json against the bundle's expectations.
Config quirks. Look for a config/packages/*.yaml tree in the bundle's docs; defaults are usually registered as container parameters, so bin/console debug:container --parameters | grep -i autocomplete is the fastest way to find what's actually overridable. Bundle config is often validated strictly — an unknown key throws at cache warmup, not at runtime, so run cache:clear after edits.
Debugging order of operations. (1) Symfony profiler → confirm the AJAX request hits your route with the expected query param; (2) Network tab → confirm the response JSON shape matches the controller's valueKey/labelKey options; (3) browser console → confirm the Stimulus controller is connected (data-controller present, no "Missing controller" error); (4) only then look at Tom Select options. Skipping to step 4 wastes the most time.
Security. Autocomplete endpoints are GET routes that leak entity labels. Gate them with the same voter you use for the parent form, apply setMaxResults(), and don't return fields the user can't otherwise see. Be aware CSRF protection doesn't apply to GET — if the bundle offers a POST mode, prefer it for anything sensitive.
Extension points to check before forking: service definitions (decoration), the form type's configureOptions (option overrides), and Twig form theme blocks (rendering). If all three are clean, the bundle is a reasonable thin layer; if the logic is baked into a single controller class, budget for a fork.
Twig rendering. Custom form themes in this space often drop attr merging. If attr: {class: '...'} stops applying, check whether the bundle's theme block calls {{ block('widget_attributes') }}.
How can I help you explore Laravel packages today?