Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Taxonomies Bundle Laravel Package

sylius/taxonomies-bundle

Sylius Taxonomies Bundle adds taxonomy management to Sylius e-commerce apps, letting you organize products into hierarchical, translatable taxons such as categories and tags via the admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you type composer require, open the repo's composer.json and read the require block. This is a Symfony2-era bundle (the pjedrzejewski/SyliusTaxonomiesBundle repository predates the rename to sylius/taxonomy-bundle), and its framework/PHP constraints almost certainly cap you at Symfony 2.8 / PHP 5.6–7.x. With zero stars and zero dependents, treat it as legacy-only: viable for maintaining an existing app, not for new projects.

Minimal setup on a Symfony 2.x app:

// app/AppKernel.php
$bundles = [
    // ...
    new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
    new Sylius\Bundle\TaxonomiesBundle\SyliusTaxonomiesBundle(),
];
# app/config/config.yml
stof_doctrine_extensions:
    orm:
        default:
            tree: true   # the Taxon entity is a nested-set node

The Doctrine tree listener is non-negotiable — the bundle maps Taxon as a Gedmo nested-set tree, and if the listener isn't registered you get a flat table that silently breaks every tree method.

Where to look first, in this order:

  1. Model/TaxonomyInterface.php and Model/TaxonInterface.php — this is the contract; everything else is wiring.
  2. Entity/Taxonomy.php / Entity/Taxon.php — concrete Doctrine mappings (usually XML in Resources/config/doctrine/).
  3. DependencyInjection/Configuration.php — shows the classes and driver knobs you'll use for extension.
  4. Repository/TaxonRepository.php — the query helpers you'll actually call from controllers.

First use case — a nested "Categories" taxonomy:

$taxonomy = new Taxonomy();
$taxonomy->setName('Categories');

$root = new Taxon();
$root->setName('Clothing');
$root->setTaxonomy($taxonomy);

$child = new Taxon();
$child->setName('T-Shirts');
$child->setParent($root);

$taxonomy->addTaxon($root);
$em->persist($taxonomy);
$em->flush();

echo $child->getPath(); // /clothing/t-shirts

Implementation Patterns

One taxonomy per concern. The bundle is a generic container, so use separate Taxonomy rows for Category, Brand, and Tag rather than overloading a single tree. For tags/facets, keep the taxon tree one level deep — nested sets are wasteful for flat vocabularies and the tree maintenance cost (see Gotchas) is real.

Extend via the resource/DI config, not by editing vendor. This is the Sylius pattern and the bundle's main extension point:

# app/config/config.yml
sylius_taxonomies:
    driver: doctrine/orm
    classes:
        taxonomy:
            model: AppBundle\Entity\Taxonomy
        taxon:
            model: AppBundle\Entity\Taxon
namespace AppBundle\Entity;

use Sylius\Bundle\TaxonomiesBundle\Model\Taxon as BaseTaxon;

class Taxon extends BaseTaxon
{
    // add your own relations, e.g. a Product many-to-many
}

Map your subclass with your own Doctrine metadata (XML/YAML) in AppBundle; do not annotate the parent. Forget the classes block and the DI will hand you base classes while Doctrine persists your subclass — a confusing half-broken state.

Attaching domain entities. Wire products/posts to Taxon with a many-to-many join table. Resolving "everything in this category and below" requires the subtree, not just the node:

$taxons = $taxonRepository->getChildren($taxon, false, null, 'ASC', true);
$taxons[] = $taxon;

$products = $productRepository->createQueryBuilder('p')
    ->innerJoin('p.taxons', 't')
    ->where('t IN (:taxons)')
    ->setParameter('taxons', $taxons)
    ->getQuery()
    ->getResult();

Watch N+1 here — add ->addSelect('t') or a fetch join on p.taxons if you render taxon names per product.

Rendering trees. Two approaches: a recursive Twig macro over getChildren(), or one childrenHierarchy() call from Gedmo's tree repository followed by a single-pass render of the nested array. The second avoids per-node queries and is the one to use for menu generation.

Breadcrumbs come free from the materialized path:

$trail = [];
$node = $taxon;
while ($node = $node->getParent()) {
    $trail[] = $node;
}
// reverse for root-to-leaf order

Admin/routing. If the bundle version you have ships route imports (Resources/config/routing/…), prefix them under /{_locale}/admin in app/config/routing.yml. Older releases assume the Sylius admin stack; on a plain Symfony app you'll likely reimplement the CRUD with forms in an afternoon rather than fight the routing.

Gotchas and Tips

  • Abandonment risk is the headline. Zero dependents and zero stars means no upstream fixes. Before committing, run the bundle's test suite and write integration tests around node moves and deletions — that's where the subtle bugs live.
  • Repository name vs. Packagist name. The GitHub repo is pjedrzejewski/SyliusTaxonomiesBundle, but the installable package is sylius/taxonomies-bundle (and later sylius/taxonomy-bundle). Confirm which one you actually pulled; forks diverge in mapping and interface names.
  • Nested sets are expensive on write. Moving or inserting a taxon can touch many rows. Wrap bulk imports in a transaction, flush in batches, and rebuild afterward — don't flush per node inside a loop.
  • Materialized paths go stale. getPath() and the permalink are stored, not computed. Renaming a taxon or re-parenting a subtree requires an explicit update/rebuild; the bundle doesn't guarantee uniqueness on slug or permalink, so enforce a unique constraint in your own schema.
  • Deletion semantics. Deleting a node in a nested set can orphan or silently cascade children depending on your onDelete config. Decide explicitly whether delete means "delete subtree" or "re-parent children," implement it in your service, and test both.
  • Repairing a tree. If manual SQL or a failed migration breaks left/right values, Gedmo's repository verify() and recover() are your escape hatch. Keep them handy.
  • Missing tree listener = silent breakage. Symptom: getChildren() returns empty, getLevel() is null, getPath() is blank. Check stof_doctrine_extensions.orm.default.tree: true and that the bundle is registered before Doctrine's mappings load.
  • Migration path. For anything greenfield, skip this bundle entirely: a plain Doctrine entity with gedmo/doctrine-extensions (or a simple parent_id + recursive CTE on Postgres/MySQL 8) gives you the same capability with a maintained dependency. The bundle's remaining value is as a reference implementation of the Sylius resource/DI extension pattern — read DependencyInjection/Configuration.php even if you don't install it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource