dev-master
9999999-devNamespaced template resolver for templating packages that do not provide one
MIT
The Requires
- php >=5.5
- psr/cache ^1.0
The Development Requires
Namespaced template resolver for templating packages that do not provide one
Namespaced template resolver for templating systems that do not provide one., (*1)
Install via Composer:, (*3)
composer require kynx/template-resolver
The simplest usage is with a single filesystem resolver. This will resolve the content of templates it finds on the
paths you specify. Assuming you have a template engine called MyRenderer
:, (*4)
$renderer = new MyRenderer(); $resolver = new FilesystemResolver(); $resolver->addPath('/path/to/templates') ->setExtension('tpl'); $template = $resolver->resolve('test'); echo $renderer->render((string) $template); // will output the contents of '/path/to/templates/test.tpl'
Namespaces enable you to separate your templates out into distinct search paths:, (*5)
$renderer = new MyRenderer(); $resolver = new FilesystemResolver(); $resolver->addPath('/path/to/templates') ->addPath('/path/to/namespace', 'mynamespace') ->setExtension('tpl'); $template = $resolver->resolve('mynamesapce::test'); echo $renderer->render((string) $template); // will output the contents of '/path/to/namespace/test.tpl'
The mynamespace::test
syntax tells the resolver to first search for the template in the mynamespace
path(s). If it is
not found there the default namespace will be searched., (*6)
To speed up subsequent lookups for templates you can store them in any PSR-6
compliant caching engine. The example below uses bravo3/cache. The
AggregateResolver
enables you to search the cache for templates first before hitting the filesystem:, (*7)
$resolver = new AggregateResolver(); $cachePool = new RedisCachePool('tcp://10.0.0.1:6379'); $cacheResolver = new CacheResolver($cachePool); $fileResolver = new FilesystemResolver(); $fileResolver->addPath('/path/to/templates') ->addPath('/path/to/namespace', 'mynamespace') ->setExtension('tpl'); $resolver->accept($cacheResolver, 1); $resolver->accept($fileResolver, 0); $result = $resolver->resolve('mynamespace::test'); if (! $result->isCached()) { // store the result in cache $resolver->save($result->getKey(), (string) $result); } echo (string) $result; // outputs temple contents
The second argument to AggregateResolver::accept()
determines the priority: higher values are searched first, and first
result found is returned. Note that it is up to your implementation to store the result back in the cache., (*8)
Many template systems can compile templates to speed up subsequent processing. The compiled template may be an array of tokens, a PHP function or, as in my own Handlebars implementation, javascript. All of these make an excellent candidate for caching. Extending the above example:, (*9)
// ... $cacheResolver = new CacheResolver($cachePool); $cachResolver->setIsCompiled(true); // ... $result = $resolver->resolve('mynamesapce::test'); if ($result->isCompiled()) { $compiled = $result->getContents(); } else { // compile the result $compiled = $handlebars->precompile((string) $result); $resolver->save($result->getKey(), $compiled); } // do something with your compiled template
The AggregateResolver
will save the result in the first resolver in it's queue that supports the save()
method., (*10)
Result
objectsAs shown in the examples above, the return value of ResolverInterfae::resolve()
is an object with a __toString()
convenience method for accessing the content. Other methods of interest are:, (*11)
getContent()
: returns the template content. If your compiled template is an array, use this instead of (string) $result
getKey()
: this returns the namespace::template
that was actually matched. So if you request mynamespace::test
which does not exist in mynamespace
but is found in the default namespace, the key will look something like
__DEFAULT__::test
. Using this as the cache key will result in two cache hits for subsequent searches, but will
ensure duplicates are not stored in cache.isCached()
: returns true if the content was found in a caching resolverisCompiled()
: returns true if the resolver was marked as a compiled resolver via setIsCompiled()
To create other resolvers - for instance, to fetch templates from a DB - implement the ResolverInterface
. This contains
only two methods, resolve()
and setIsCompiled()
., (*12)
If your resolver can handle multiple paths it should implement the PathedResolverInterface
, which augments the above
with an addPath()
and getPaths()
method., (*13)
If your resolver supports saving results back, implement the SavingResolverInterface
., (*14)
For convenience there is an AbstractResolver
class you can extend, which contains some useful utility methods., (*15)
Much of the inspiration from this, and much of the AggregateResolver
code, came from phly-mustache's
template resolver., (*16)
Namespaced template resolver for templating packages that do not provide one
MIT