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

Php Templates Bundle Laravel Package

setono/php-templates-bundle

Symfony bundle that integrates PHP file templates into the framework's templating system, letting you render plain PHP views alongside Twig. Useful for simple, dependency-light templates and gradual migration from legacy PHP templates.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package, so you're effectively borrowing a Symfony integration for the phptemplates library. It's a thin bridge: a compiler pass, a service definition for the engine, and (usually) a templating loader/engine registration so .php templates can be rendered from controllers.

1. Install and register.

composer require setono/php-templates-bundle
// config/bundles.php
return [
    // ...
    Setono\PhpTemplatesBundle\SetonoPhpTemplatesBundle::class => ['all' => true],
];

Note the release date — last tagged release was May 2020. Expect to constrain Symfony to whatever line the bundle's composer.json allows (^4.4/^5.0 territory), and confirm the PHP constraint before you plan anything on PHP 8.2+.

2. Look here first, in this order:

  • README.md — usually the only usage docs; check the example controller.
  • DependencyInjection/Configuration.php — the real config keys (template paths, cache dir, debug flags).
  • DependencyInjection/SetonoPhpTemplatesExtension.php — shows which services are wired and under which IDs.
  • Resources/config/services.* — the renderer/engine service ID you'll inject.
  • The underlying phptemplates library's README — template syntax ($this->layout(), $this->block(), section/insert helpers) lives there, not in this bundle.

3. First use case. Render one template from one controller and assert the output. Find the service ID first:

bin/console debug:container | grep -i template

Then:

final class HomeController extends AbstractController
{
    public function __invoke(/* renderer or engine service */ $renderer): Response
    {
        return new Response($renderer->render('home', ['name' => 'Ada']));
    }
}

Start with a single flat template, no layout, no inheritance. Verify that path resolution and escaping behave the way you expect before layering on blocks.

Implementation Patterns

Inject the renderer, not the container. The bundle exposes the engine as a service; autowire it into controllers, message handlers, or a small ViewRenderer wrapper of your own. If autowiring fails, the service is either not public or not aliased — add an alias in services.yaml pointing to the bundle's service ID.

Return strings, wrap in responses at the edge. Keep the renderer out of HTTP concerns. A pattern that works well:

final class TemplateView
{
    public function __construct(private $renderer, private string $templatesDir) {}

    public function render(string $name, array $vars = []): string
    {
        return $this->renderer->render($name, $vars + ['app' => [...]]);
    }
}

This gives you one seam to swap engines later (Twig, Blade, plain PHP includes) without touching controllers.

Lay out templates like Twig. Put templates under templates/ (or whatever the config key points at), use a layout.php with a $this->block('content') / $this->section() pair, and keep one template per file. Consistency beats cleverness here because the library has no auto-discovery.

Coexist with Twig rather than replacing it. Registering a second engine is where most bundles of this vintage break. The safest integration is: leave Twig as the framework's default templating engine, and use the PHP renderer only where you explicitly inject it. Don't tag it as a templating.engine unless you're on the exact Symfony version this bundle was tested against — the templating component was removed in Symfony 5.

Escape at the call site. There is no auto-escaping contract like Twig's. Either pass pre-escaped values into templates or wrap output with htmlspecialchars($x, ENT_QUOTES, 'UTF-8') inside the template. For anything user-supplied, make this the default, not the exception.

Test at the render boundary. Unit-test templates by calling the renderer directly with a fixture context and asserting substrings, not full string equality — whitespace and newlines from PHP templates are unstable.

Integrate with webpack-encore-free pages by treating the renderer output as a full HTML document; the bundle gives you no fragment/renderView helper, so sub-requests should go through HttpKernel or your own include mechanism.

Gotchas and Tips

It's effectively abandoned. 0 dependents, 1 star, last release 2020. Treat it as vendored code: pin the version exactly, vendor the repo if needed, and write down the upgrade/migration path the day you adopt it. The bus-factor risk is the main cost of the tiny dependency.

No auto-escaping means XSS is on you. This is the single biggest practical difference from Blade or Twig. Audit every echo in a template.

Service visibility. Symfony 4/5 private services + a bundle written for an older container can mean the engine service isn't injectable by its ID. Fix with an explicit alias:

services:
    Setono\PhpTemplatesBundle\...\EngineInterface:
        alias: 'setono_php_templates.engine'
        public: false

Confirm the real IDs with debug:container --show-private.

Path quirks. Template directories are usually resolved at container compile time. Use %kernel.project_dir% in config, and remember that adding a new template path requires a cache warmup — plain file changes typically don't, but config changes do.

Debugging a blank render. A PHP template that throws inside output buffering can produce a 200 with an empty body. Wrap the render in a try/catch in dev, check var/log/dev.log, and temporarily disable the cache to rule out stale compiled templates. Look for a cache/ directory the library owns and clear it after syntax changes.

Extension points are limited but real. You can decorate the renderer service (decorates:), add a CompilerPass to change constructor args, or override bundle services by declaring a service with the same ID in your app config. Template syntax itself is not extensible from the bundle side — that lives in the library.

Version pinning. Add "setono/php-templates-bundle": "0.1.*" (or the exact tag from composer show) and an extra. note in composer.json. If you're on PHP 8+, run the test suite once; code from 2020 often trips on create_function-era patterns or nullable deprecations.

Migration escape hatch. Because the public surface is one render(string, array): string call, replacing it is a 30-line adapter. If the bundle becomes a problem, swap the adapter to twig->render() or a plain include with extract(), and no controller changes are needed.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings