odiseoteam/blog-bundle
A Symfony bundle that adds a full-featured blog to your project—posts, categories, tags, and comments—with an admin panel built on Sonata Admin. Quick to install and easy to customize, it gives you a ready-made content system without starting from scratch.
This is a Symfony bundle, not a Laravel package — the mental model is closest to a Laravel package that ships models, migrations, routes, and views all at once, except the "models" are Doctrine entities and the "views" are Twig templates you override by path.
composer require odiseoteam/blog-bundle. Then check composer show odiseoteam/blog-bundle for the required symfony/* and php constraints before assuming it fits your project. With Symfony Flex the bundle should be auto-registered in config/bundles.php; otherwise add Odiseo\Bundle\BlogBundle\OdiseoBlogBundle::class => ['all' => true].vendor/odiseoteam/blog-bundle/src/Entity/ (what the domain actually models — posts, categories, tags, comments), then src/Resources/config/ (services, routing, Doctrine mappings) and the bundle's README for the config key name and route prefix. Read the entity classes before writing anything; the whole bundle's value and limits are visible there.config/packages/odiseo_blog.yaml (check the bundle's extension class or README for the exact root key and available options). Most bundles like this let you choose the entity classes to map — that's your extension point later.bin/console doctrine:migrations:diff and inspect the generated migration rather than running doctrine:schema:update --force. You want to see which tables it wants to create before touching a real database.config/routes.yaml if it isn't auto-loaded, e.g. a resource import with a prefix: you control. Then bin/console debug:router | grep -i blog to see exactly what URLs you got.Repository-driven, controllers are yours. The reliable pattern with small bundles is: treat it as a data layer. Inject PostRepository (or whatever the bundle names it), add your own query methods via a custom repository class if the bundle's repositoryClass is configurable, and own the controllers and templates. This keeps you free to change the bundle later without rewriting routes.
Template override by path. If the bundle ships Twig templates, override them by placing files under templates/bundles/OdiseoBlogBundle/<subpath>/<file>.twig. Paths must match the bundle's internal structure exactly — copy the original file out of vendor/ first, then edit the copy. Never edit in vendor/.
Entity extension via inheritance mapping. The standard Symfony bundle idiom: create src/Entity/Post.php extending the bundle's Post, mark the parent as @MappedSuperclass/configure resolve_target_entities, and point the bundle config at your subclass. This is how you add fields (a cover image relation, SEO metadata, an author relation to your User). Do this before you run the first migration — changing it afterward means table churn.
Admin integration is a separate decision. These bundles usually assume an admin generator (Sonata or EasyAdmin depending on the version). Check what the bundle's forms/services expect. In practice it's often faster to build EasyAdmin CRUD for the entities yourself than to wire up a heavyweight admin dependency just for this bundle.
Publish workflow as an explicit state. Model draft vs. published with a nullable publishedAt timestamp and scope every public query to publishedAt IS NOT NULL AND publishedAt <= :now. Don't rely on a boolean flag the bundle may or may not expose — you want scheduled publishing for free.
Slug handling in one place. Whether the bundle generates slugs via a Doctrine listener or expects you to set them, centralize it. If you override the entity, add your own prePersist/preUpdate listener using a slugger service rather than sprinkling Str::slug-equivalents through controllers.
Feature-flag the bundle's own controllers. If you use them, namespace the route prefix (/blog) so you can replace one route at a time with your own implementation. Don't let bundle routes occupy /.
composer.json, and budget for forking it or copying the entities into your app if you hit an incompatibility with a newer Symfony or Doctrine ORM major (Doctrine 3 attribute mapping, #[ORM\...] vs. annotations, is the usual breakage point).doctrine:mapping:info.There is no extension able to load the configuration for "odiseo_blog" means the bundle isn't in config/bundles.php or the config key is misspelled. Run bin/console debug:container --parameter=... or debug:config odiseo_blog after registering.schema:update. Use doctrine:schema:validate after mapping changes; it catches bad association mappings (mappedBy/inversedBy mismatches and wrong targetEntity) far faster than a runtime exception on a page render.post table, the auto-generated diff will try to drop/alter columns. Read it line by line before applying.templates/bundles/OdiseoBlogBundle/... means Symfony just falls back to the vendor template with no warning. Verify with bin/console debug:twig | grep -i blog, which lists the resolved override paths.config/routes.yaml (or with a distinct prefix) so your own routes win. debug:router shows the final resolved order.debug:container for autowiring. If repository injection fails, bin/console debug:container PostRepository shows whether an alias exists. If not, define one in config/services.yaml with an explicit arguments: binding — cheaper than guessing at the bundle's service IDs.bin/console cache:clear before you start debugging anything else. Mapping and container metadata are cached aggressively.services.yaml, (3) extend entities via inheritance mapping, (4) fork. Try them in that order — each step up costs significantly more maintenance.doctrine/doctrine-fixtures-bundle to seed posts so your functional tests don't depend on whatever the bundle's own test setup assumes. Given the project's size, don't expect comprehensive upstream test coverage to lean on.How can I help you explore Laravel packages today?