Install Blog Kit Bundle in a Symfony 7.4 or 8 application with Doctrine ORM, Twig, Security, FormKit, UiKit, RoutingKit, and AuditKit.
- Requirements
- Composer
- Symfony Flex recipe
- Manual registration
- Routes
- Database schema
- Security
- User entity
- Twig Extra Bundle
- Published assets
- Verify
- Demo application
| Component | Version |
|---|---|
| PHP | 8.4 - 8.5 |
| Symfony | ^7.4 or ^8.0 |
| Doctrine Bundle | ^2.10 or ^3.0 |
| Doctrine ORM | ^2.15 or ^3.0 |
| Twig Bundle | ^7.4 or ^8.0 |
| Security Bundle | ^7.4 or ^8.0 |
| FormKitBundle | nowo-tech/form-kit-bundle ^2.4 |
| UiKitBundle | nowo-tech/ui-kit-bundle ^1.5 |
| RoutingKitBundle | nowo-tech/routing-kit-bundle ^1.4 |
| AuditKitBundle | nowo-tech/audit-kit-bundle ^1.1 |
| Twig Extra | twig/extra-bundle and twig/string-extra |
composer require nowo-tech/blog-kit-bundle
composer require twig/extra-bundle twig/string-extratwig/extra-bundle is required because the bundle ships Twig templates that expect Twig Extra to be enabled in the host application.
When the Flex recipe is available, it copies:
config/packages/nowo_blog_kit.yamlconfig/packages/nowo_form_kit.yaml(filter profile +type_map.entityfor article tags)config/routes/nowo_blog_kit.yaml
Recipe source in this repository:
.symfony/recipe/nowo-tech/blog-kit-bundle/1.0/
If Flex is unavailable, register the bundles in config/bundles.php:
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Nowo\FormKitBundle\NowoFormKitBundle::class => ['all' => true],
Nowo\UiKitBundle\NowoUiKitBundle::class => ['all' => true],
Nowo\RoutingKitBundle\NowoRoutingKitBundle::class => ['all' => true],
Nowo\AuditKitBundle\NowoAuditKitBundle::class => ['all' => true],
Nowo\BlogKitBundle\NowoBlogKitBundle::class => ['all' => true],Then create config/packages/nowo_blog_kit.yaml:
nowo_blog_kit:
user_class: App\Entity\User
default_locale: es
locales: [es, en]
security:
access_roles: [ROLE_ADMIN]
manage_roles: [ROLE_EDITOR]
moderate_roles: [ROLE_MODERATOR]
configure_roles: [ROLE_ADMIN]
allow_unauthenticated: false
object_access:
strategy: none
web_ui:
layout_template: '@NowoBlogKitBundle/admin/layout.html.twig'
public_layout_template: '@NowoBlogKitBundle/public/layout.html.twig'
css_framework: bootstrap5
icon_set: bootstrap-icons
row_actions_display: icon
listing:
mode: paginated
masonry:
strategy: masonry
columns_mobile: 1
columns_tablet: 2
columns_desktop: 2
comments:
rate_limit:
strategy: fixed_window
limit: 5
interval_seconds: 60
captcha:
strategy: honeypot
html:
sanitize:
strategy: none
doctrine:
table_prefix: ''
connection: defaultSee CONFIGURATION.md for rate-limit, CAPTCHA, and HTML sanitizer strategies.
Import the bundle routes:
# config/routes/nowo_blog_kit.yaml
nowo_blog_kit:
resource: '@NowoBlogKitBundle/Resources/config/routing.yaml'This exposes public blog routes and admin CRUD routes handled by the bundle controllers.
The bundle registers Doctrine attribute mappings for articles, translations, tags, comments, resources, and settings.
Generate and run a migration:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrateOr update the schema directly in development:
php bin/console doctrine:schema:update --forceIf you set doctrine.table_prefix, the bundle prefixes its own entity tables automatically through a Doctrine metadata listener.
When security.allow_unauthenticated is false (the default), install and configure symfony/security-bundle.
Recommended host access_control:
# config/packages/security.yaml
security:
access_control:
- { path: ^/admin/blog, roles: ROLE_EDITOR }Tighten comment moderation and settings if those roles differ:
security:
access_control:
- { path: ^/admin/blog/comments, roles: ROLE_MODERATOR }
- { path: ^/admin/blog/settings, roles: ROLE_ADMIN }
- { path: ^/admin/blog, roles: ROLE_EDITOR }You can replace role-based access with a custom service via security.access_checker. Scope publications with security.object_access (owner or a host BlogKitResourceAccessCheckerInterface).
Set user_class to the host user FQCN that implements Nowo\BlogKitBundle\Model\BlogUserInterface. The extension maps that class as the Doctrine resolve_target_entities implementation for audit/blameable relations.
If your application does not already provide Twig Extra, install it explicitly:
composer require twig/extra-bundle twig/string-extraFlex usually registers Twig\Extra\TwigExtraBundle\TwigExtraBundle automatically. If not, add it manually to config/bundles.php.
Run php bin/console assets:install so blog.css and blog-kit.js are available under /bundles/nowoblogkit/ via the nowo_blog_kit asset package:
<link rel="stylesheet" href="{{ asset('blog.css', 'nowo_blog_kit') }}">
<script src="{{ asset('blog-kit.js', 'nowo_blog_kit') }}" defer></script>Rebuild frontend with make assets (Vite + pnpm).
The bundle does not ship Bootstrap, Tailwind, or Foundation CSS. Set web_ui.css_framework to match the host (bootstrap5, tailwind, foundation, custom) and load that stack in both layout_template (admin) and public_layout_template. Public markup stays on semantic blog-* classes plus UiKit buttons. For Bootstrap hosts, register twig.form_themes with @NowoFormKitBundle/form/static_blocks.html.twig then bootstrap_5_layout.html.twig, and load Bootstrap Icons if icon_set: bootstrap-icons.
- Open
/blogand confirm the public index loads. - Open
/admin/blogas an authorized editor and create a published article. - Open
/blog/{slug}and confirm the article body renders. - Submit a public comment and approve it at
/admin/blog/comments.
Clone this repository and run the FrankenPHP demo:
make -C demo/symfony8 upDefault URL: http://localhost:8105
See DEMO-FRANKENPHP.md.