sylius/categorizer-bundle
Sylius Categorizer Bundle adds flexible categorization to Symfony and Sylius apps. Build hierarchical category trees, assign categories to any Doctrine entity, and manage categorized resources through reusable models, repositories, and UI integration.
Do not start a new project with this package. The repository is archived, the description literally reads DEPRACATED, and the last supported stack is Symfony 2.x / PHP 5.x. There are zero dependents on Packagist, which means you will not find examples, StackOverflow answers, or a community to lean on. Treat this as a legacy artifact you inherit, not a tool you adopt.
Minimal steps if you find it in an existing composer.json:
composer show sylius/categorizer-bundle
grep -R "sylius_categorizer" app/config/config.yml
DependencyInjection/SyliusCategorizerExtension.php) and Resources/config/doctrine/model/*.orm.xml are the source of truth for class overrides, drivers, and tree strategy.Sylius\Bundle\CategorizerBundle\Model\Taxonomy and Category, the CategorizableInterface / Categorizable trait, and the repositories under Doctrine/ORM.SyliusTaxonomyBundle (Taxonomy + Taxon), and in current Sylius the taxonomy model lives in core (Sylius\Component\Taxonomy). Any feature request or bug fix you plan should be written against the successor API, then back-ported — not the other way around.First real use case in a legacy app: a product (or any domain entity) is "categorizable", categories live in a nested-set tree inside named taxonomies, and you render/query that tree for navigation and filtering. Confirm that is still the shape of your data before writing code:
// Legacy: attach taxonomy to an entity
class Product implements CategorizableInterface
{
use Categorizable; // provides getCategories()/setCategories()
}
Entity composition over inheritance. The trait/interface pair is the intended integration point — your model implements CategorizableInterface and uses the Categorizable trait, then you map the collection in your own Doctrine XML/YAML. Do not extend the bundle's concrete Category class directly unless you are happy owning its tree annotations forever.
Taxonomy-scoped trees, not one global tree. Categories belong to a Taxonomy; tree operations (move, reorder, levels) are always relative to a taxonomy root. Query patterns look like:
$taxonomy = $taxonomyRepository->findOneBy(['name' => 'main']);
$children = $categoryRepository->getChildren($parent, true); // direct children / whole subtree
Service-layer, not controller logic. Use the bundle's manager services rather than touching the tree repository directly — they wrap the Gedmo/Doctrine tree listener and keep the nested-set lft/rgt/root/level columns consistent:
$manager = $container->get('sylius_categorizer.manager.category');
$manager->move($category, $newParent);
Seeding via fixtures. Build taxonomies and categories in data fixtures (doctrine:fixtures:load) rather than creating them through admin UI on every environment. Trees are cheap to build in fixtures and expensive to repair afterwards.
Slug-driven lookups. Use Category slugs (generated by the Sluggable listener) for front-end routing and filtering instead of IDs, and always resolve within a taxonomy scope so two taxonomies can both have a shoes category.
Form integration through aliases. The bundle registers form types under names like sylius_categorizer_taxonomy and sylius_categorizer_category. Embed them via createNamed/get('form.factory') patterns rather than instantiating type classes by FQCN — this is the one place where upgrading the bundle silently breaks you, because aliases were renamed between versions.
Configuration shape. Expect something like:
sylius_categorizer:
driver: doctrine/orm
engine: doctrine/orm
classes:
taxonomy: Acme\AppBundle\Entity\Taxonomy
category: Acme\AppBundle\Entity\Category
Override classes here — never by editing vendor files — otherwise any composer operation wipes your customization.
$em->remove() / $em->persist() on a category bypasses the tree listener and leaves dangling lft/rgt values. Always go through the manager. After a bad import, run doctrine:tree-recover (Gedmo) and verify with getLevel() on children.cascade: ["persist", "remove"] on the categorizable collection is a footgun. Deleting one product can cascade into deleting shared category entities. Map the owning side as inversedBy-only and control deletion explicitly.onDelete FK setup. Decide policy up front: reparent children (move each one) or block deletion in the admin controller.categorizer vs taxonomy vs taxon — config keys, service IDs, and folder names do not agree between versions. Grep the actual DependencyInjection extension before trusting any tutorial snippet.ArrayCollection return types, and the old ->get() container calls will break on a modern runtime. If you must run it, pin the runtime in composer.json (platform.php) and accept that you cannot upgrade the rest of the app independently.sylius_categorizer.classes.* and add your own fields (image, description, position) via your app's mapping. Subclassing the bundle's form types is the second option; overriding services in services.yml with decorates is the third. Anything else means forking — and a fork of an archived repo is a maintenance cost with no upstream.SyliusTaxonomyBundle on the last Sylius version that supports it, (2) core Sylius\Component\Taxonomy if you are on modern Sylius, (3) if you are not actually on Sylius, gedmo/doctrine-extensions Tree + a small taxonomy entity of your own — you do not need this bundle to get nested categories, and the 200 lines it saves are not worth a deprecated dependency.Taxonomy → Taxonomy is easy; Category → Taxon needs a slug/position/parent mapping script and a tree rebuild. Do it on a copy of production data and diff the rendered navigation before switching over.How can I help you explore Laravel packages today?