snicco / templating
Provides a unified API for various templating engines.
Installs: 16 450
Dependents: 4
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
pkg:composer/snicco/templating
Requires
- php: ^7.4|^8.0
- snicco/str-arr: ^2.0
- webmozart/assert: ^1.10
Requires (Dev)
- phpunit/phpunit: ^9.5.13
Conflicts
- snicco/better-wp-api: <2.0.0-beta.9
- snicco/better-wp-cache: <2.0.0-beta.9
- snicco/better-wp-cache-bundle: <2.0.0-beta.9
- snicco/better-wp-cli: <2.0.0-beta.9
- snicco/better-wp-cli-testing: <2.0.0-beta.9
- snicco/better-wp-hooks: <2.0.0-beta.9
- snicco/better-wp-hooks-bundle: <2.0.0-beta.9
- snicco/better-wp-mail: <2.0.0-beta.9
- snicco/better-wp-mail-bundle: <2.0.0-beta.9
- snicco/better-wp-mail-testing: <2.0.0-beta.9
- snicco/better-wpdb: <2.0.0-beta.9
- snicco/better-wpdb-bundle: <2.0.0-beta.9
- snicco/blade-bridge: <2.0.0-beta.9
- snicco/blade-bundle: <2.0.0-beta.9
- snicco/content-negotiation-middleware: <2.0.0-beta.9
- snicco/debug-bundle: <2.0.0-beta.9
- snicco/default-headers-middleware: <2.0.0-beta.9
- snicco/eloquent: <2.0.0-beta.9
- snicco/encryption-bundle: <2.0.0-beta.9
- snicco/event-dispatcher: <2.0.0-beta.9
- snicco/event-dispatcher-testing: <2.0.0-beta.9
- snicco/guests-only-middleware: <1.0.0
- snicco/http-routing: <2.0.0-beta.9
- snicco/http-routing-bundle: <2.0.0-beta.9
- snicco/http-routing-testing: <2.0.0-beta.9
- snicco/https-only-middleware: <2.0.0-beta.9
- snicco/illuminate-container-bridge: <2.0.0-beta.9
- snicco/kernel: <2.0.0-beta.9
- snicco/kernel-testing: <2.0.0-beta.9
- snicco/method-override-middleware: <2.0.0-beta.9
- snicco/minimal-logger: <2.0.0-beta.9
- snicco/must-match-route-middleware: <2.0.0-beta.9
- snicco/no-robots-middleware: <2.0.0-beta.9
- snicco/open-redirect-protection-middleware: <2.0.0-beta.9
- snicco/payload-middleware: <2.0.0-beta.9
- snicco/pimple-bridge: <2.0.0-beta.9
- snicco/psr7-error-handler: <2.0.0-beta.9
- snicco/redirect-middleware: <2.0.0-beta.9
- snicco/session: <2.0.0-beta.9
- snicco/session-bundle: <2.0.0-beta.9
- snicco/session-psr16-bridge: <2.0.0-beta.9
- snicco/session-testing: <2.0.0-beta.9
- snicco/session-wp-bridge: <2.0.0-beta.9
- snicco/share-cookies-middleware: <2.0.0-beta.9
- snicco/signed-url: <2.0.0-beta.9
- snicco/signed-url-psr15-bridge: <2.0.0-beta.9
- snicco/signed-url-psr16-bridge: <2.0.0-beta.9
- snicco/signed-url-testing: <2.0.0-beta.9
- snicco/signed-url-wp-bridge: <2.0.0-beta.9
- snicco/templating-bundle: <2.0.0-beta.9
- snicco/testable-clock: <2.0.0-beta.9
- snicco/testing-bundle: <2.0.0-beta.9
- snicco/trailing-slash-middleware: <2.0.0-beta.9
- snicco/wp-auth-only-middleware: <2.0.0-beta.9
- snicco/wp-capability-middleware: <2.0.0-beta.9
- snicco/wp-capapility-middleware: <1.0.0
- snicco/wp-guests-only-middleware: <2.0.0-beta.9
- snicco/wp-nonce-middleware: <2.0.0-beta.9
- dev-master
- v2.0.0-beta.9
- v2.0.0-beta.8
- v2.0.0-beta.7
- v2.0.0-beta.6
- v2.0.0-beta.5
- v2.0.0-beta.4
- v2.0.0-beta.3
- v2.0.0-beta.2
- v2.0.0-beta.1
- v1.10.1
- v1.10.0
- v1.9.1
- v1.9.0
- v1.8.1
- v1.8.0
- v1.7.0
- v1.6.2
- v1.6.1
- v1.6.0
- v1.5.0
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.0
- v1.2.1
- v1.2.0
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.2
- v1.0.1
- v1.0.0
- dev-beta
This package is auto-updated.
Last update: 2025-10-07 17:12:10 UTC
README
The Templating component of the Snicco project provides a simple, object-oriented API around popular PHP template engines.
Table of contents
Installation
composer require snicco/templating
Usage
This package consists of the following main components:
- An immutable
Viewobject, which can be rendered to its string representation with a givencontext. - The
TemplateEngine, which is a facade class used to create and renderViewobjects. - The
ViewFactoryinterface, which abstracts away implementation details of how aViewinstance is rendered. See Using view factories; - The
ViewContextResolver, which is responsible for adding globalcontextand view composercontextto a view that is being rendered.
The following directory structure is assumed for the examples in this README:
your-project-root
├── templates/
│ ├── users/
│ │ ├── profile.php
│ │ └── ...
│ └── hello-world.php
└── ...
// ./templates/hello-world.php echo "Hello $first_name";
Creating a view
An instance of View is always created by a call to TemplateEngine::make().
Context can be added to a View instance which will be available to the underlying template
once the View is rendered.
use Snicco\Component\Templating\TemplateEngine; // The TemplateEngine accepts one or more instances of ViewFactory. // See #Using view factories for available implementations. $view_factory = /* */ $engine = new TemplateEngine($view_factory); // hello-world is relative to the root directory "templates" $view = $engine->make('hello-world'); $view1 = $view->with('first_name', 'Calvin'); $output = $engine->renderView($view1); var_dump($output); // Hello Calvin $view2 = $view->with('first_name', 'Marlon'); $output = $engine->renderView($view2); var_dump($output); // Hello Marlon // Views can also be created by passing an absolute path $view = $engine->make('/path/to/templates/hello-world.php');
Directly rendering a view
If you want to render a template right away you can use the render method on
the TemplateEngine.
use Snicco\Component\Templating\TemplateEngine; $view_factory = /* */ $engine = new TemplateEngine($view_factory); $output = $engine->render('hello-world', ['first_name' => 'Calvin']); var_dump($output); // Hello Calvin
Finding the first existing view
Both the make and render method of the TemplateEngine accept an array of strings in
order to use the first existing view.
use Snicco\Component\Templating\TemplateEngine; $view_factory = /* */ $engine = new TemplateEngine($view_factory); $view = $engine->make(['hello-world-custom', 'hello-world']); $output = $engine->render(['hello-world-custom', 'hello-world'], ['first_name' => 'Calvin']); var_dump($output); // Hello Calvin
If no view can be found, a ViewNotFound exception will be thrown.
Referencing nested directories
Both the make and render method of the TemplateEngine will expand dots to allow directory
traversal. This works independently of the concrete ViewFactory that is being used.
use Snicco\Component\Templating\TemplateEngine; $view_factory = /* */ $engine = new TemplateEngine($view_factory); $view = $engine->make('users.profile'); $output = $engine->render('users.profile', ['first_name' => 'Calvin']);
Global context / View composers
Before a view is rendered, it's passed to the ViewContextResolver, which is
responsible for applying:
- global
contextthat should be available in all views contextprovided by view composers to some views
A view composer can be a Closure or class that implements ViewComposer.
The ViewContextResolver will be needed to instantiate the concrete
implementations of the view factory interface.
Adding global context:
use Snicco\Component\Templating\Context\ViewContextResolver; use Snicco\Component\Templating\Context\GlobalViewContext; $global_context = new GlobalViewContext() // All templates now have access to a variable called $site_name $global_context->add('site_name', 'snicco.io'); // The value can be a closure which will be called lazily. $global_context->add('some_var', fn() => 'some_value'); $context_resolver = new ViewContextResolver($global_context);
If you pass an array as the second argument to GlobalViewContext::add you can reference nested values in your views
like so:
use Snicco\Component\Templating\Context\ViewContextResolver; use Snicco\Component\Templating\Context\GlobalViewContext; $global_context = new GlobalViewContext() $global_context->add('app', [ 'request' => [ 'path' => '/foo', 'query_string' => 'bar=baz' ] ]); // Inside any template echo $app['request.path'] echo $app['request.query_string']
Adding view composers:
$context_resolver = /* */ // Using a closure $context_resolver->addComposer('hello-world', fn(View $view) => $view->with('foo', 'bar')); // Using a class that implements ViewComposer $context_resolver->addComposer('hello-world', HelloWorldComposer::class); // Adding a composer to multiple views $context_resolver->addComposer(['hello-world', 'other-view'], fn(View $view) => $view->with('foo', 'bar')); // Adding a composer by wildcard // This will make the current user available to all views inside the templates/users directory. $context_resolver->addComposer('users.*', fn(View $view) => $view->with('current_user', Auth::user()));
Using view factories
All view factories implement the ViewFactory interface.
They are used by the TemplateEngine and contain the underlying logic to render a View instance to its string
representation.
It's possible to use multiple view factories together in which case the first factory that can render a given View
will be used.
The following view factories are currently available:
PHPViewFactory, included in this package. A bare-bones implementation that works great for small projects with only a handful of views.BladeViewFactory, included in a separate package. Integrates Laraval's Blade as a standalone template engine with this package, while retaining all features of both.TwigViewFactory- coming soon.
The PHPViewFactory
The PHPViewFactory is a bare-bones implementation that is great for small
projects where you might only have a handful of views.
Instantiation
The PHPViewFactory takes
a ViewContextResolver
as the first argument and an array of root template directories as the second argument.
If a view exists in more than one template directory, the first matching one will be used. This is great for allowing certain templates to be overwritten by templates in another (custom) template directory.
use Snicco\Component\Templating\TemplateEngine; use Snicco\Component\Templating\ViewFactory\PHPViewFactory; $context_resolver = /* */ $php_view_factory = new PHPViewFactory( $context_resolver, [__DIR__.'/templates'] ); $template_engine = new TemplateEngine($php_view_factory);
Template inheritance
The PHPViewFactory allows for very basic template inheritance.
Assuming that we have the following two templates:
<?php // post.php /* * Extends: post-layout */ echo "Post one content"
<?php // post-layout.php ?> <html lang="en"> <head> Head content goes here <title><?= htmlentities($title, ENT_QUOTES, 'UTF-8') ?></title> </head> <body> <main> <?= $__content ?> </main> <footer> Footer content goes here </footer> </body> </html>
Rendering the post view will yield:
$template_engine->render('post', ['title' => 'Post 1 Title']);
<html lang="en"> <head> Head content goes here <title>Post 1 Title</title> </head> <body> <main> Post one content </main> <footer> Footer content goes here </footer> </body> </html>
A couple of things to note:
- The parent template is indicated by putting
Extends: parent-view-nameinside/* */comments within the first 100 bytes of the template. Contextthat is passed to a child view is available to the parent view.- The parent view can output the child-content by using the
$__contentvariable. - Nested inheritance is possible.
post-layout.phpcould for example extendlayout.php
Contributing
This repository is a read-only split of the development repo of the Snicco project.
This is how you can contribute.
Reporting issues and sending pull requests
Please report issues in the Snicco monorepo.
Security
If you discover a security vulnerability, please follow our disclosure procedure.