jungi/theme-bundle
JungiThemeBundle adds flexible theme management to Symfony/PHP applications, letting you define multiple themes, use inheritance, override templates and assets, and select the active theme through configuration or custom resolvers.
Check the Symfony version first. v1.0.1 added Symfony 3 support, so the bundle now runs on Symfony 2.x and 3.x (still PHP 5.x/7.0-era Twig, still no Symfony 4+ or Twig 2+). If the project is on Symfony 4 or later, stop here — you will spend more time shimming the DI container and Twig loader than the theming is worth. For a greenfield app, use Twig namespaced paths (@theme_default/...) or liip/theme-bundle instead; the concepts map almost 1:1.
Minimal steps for a legacy Symfony 2/3 app:
jungi/theme-bundle) at ^1.0.1 — earlier tags predate Symfony 3 support — and register new Jungi\Bundle\ThemeBundle\JungiThemeBundle() in AppKernel.Resources/doc/ in the repository, then at DependencyInjection/Configuration.php. The docs are from 2015 and drift from the code; the configuration tree is the authoritative source for exact key names.jungi_theme.themes map with one default theme pointing at your existing views directory, and set default_theme: default. Confirm nothing breaks — the bundle should be transparent at this point.xmas) whose path(s) contain only the templates you actually want to override.First real use case: override a single template for a seasonal/white-label skin without duplicating controllers. Put the overriding file at the same relative path inside the second theme's directory, switch the current theme, and let the bundle's loader prefer the theme file while falling back to the bundle's original. If that fallback doesn't happen, your theme paths are wrong, not your templates.
Switch the current theme via the manager, not by hand-editing config. Inject jungi_theme.theme_manager and call setCurrentTheme('xmas') early in the request (a kernel.request listener is the right place). Read back with getCurrentTheme(). Keep the "which theme" decision in exactly one listener so controllers and subrequests stay consistent.
Prefer automatic resolution over manual switching. The bundle ships theme resolvers (rule-based, and a device-oriented one if the companion device bundle is installed). Configure a rule resolver so a cookie/session/query parameter selects the theme, and fall back to default_theme. This is the pattern you actually want day-to-day: one config block, zero controller code.
Write a custom resolver when rules aren't enough. Implement the bundle's theme-resolver interface as a service and tag it (check Resources/config/*.xml for the exact tag name). Keep it side-effect free and cheap — it runs on every request. Typical cases: resolve by hostname for multi-tenant, by authenticated user's preference, by A/B bucket.
Render through the template manager for engine-agnostic code. The bundle exposes a template-manager service implementing render($name, $params) and renderResponse($name, $params, Response $response = null). Using this in controllers means the theme lookup happens once, in one place, rather than relying on every template include being theme-aware. For Twig-only apps, the theme-aware Twig loader is enough.
Structure themes as a thin overlay, not a fork. A theme directory should contain only the files that differ. Rely on parent/fallback so the 90% of templates that don't change stay in one place. This is the single biggest maintainability lever with this bundle.
Persist the choice outside the request. Store the selected theme in the session or a cookie in the same listener that calls setCurrentTheme, so the next request resolves identically. Without this, theme selection resets to default_theme on every page load.
Test it explicitly. In functional tests, set the theme in setUp and assert on rendered output or on getCurrentTheme(). Also add one test that runs with the default theme to catch accidental coupling.
composer.json, and plan to fork rather than wait for upstream. If you fork, add a vcs repository entry and keep the namespace.ContainerAware/deprecated API calls as unverified until you exercise them. Smoke-test bundle registration and template resolution on the exact Symfony 3 minor you run; a 2016-era bundle on Symfony 3.4 is not the same as on 3.0.tearDown or you'll get order-dependent failures.debug:container | grep jungi_theme that your service and tag are actually registered.Configuration.php. When in doubt, read the config tree and let config:dump-reference jungi_theme (if available on your Symfony version) tell you the truth.default_theme be the single fallback.getCurrentTheme() and the theme's resource paths from a throwaway controller or a kernel.request listener. Most "wrong template" reports are actually "theme resolved to default" — check the theme before checking the template.vendor/; a decorator on the locator covers most override needs.@theme_mobile/...), replace setCurrentTheme calls with a request attribute, and delete the bundle. Do it incrementally, one theme at a time, using the fallback behaviour to keep both systems rendering the same output.How can I help you explore Laravel packages today?