Create custom markup processor
Phrozn was created with plugin architecture in mind, so extending it should be relatively simple process.
All extension classes MUST reside in .phrozn/plugins folder.
Base namespace used for plugin code is PhroznPlugin.
1. Create Processor Class
In order for your class to be used as drop-in replacement for some standard
text processor it MUST implement \Phrozn\Processor interface:
namespace Phrozn;
interface Processor
{
/**
* Parse the incoming template
*
* @param string $tpl Source template content
* @param array $vars List of variables passed to template engine
*
* @return string Processed template
*/
public function render($tpl, $vars = array());
/**
* Gateway to pass concrete Processor some configuration options
*
* @param array $options Options to pass to engine
*
* @return \Phrozn\Processor
*/
public function setConfig($options);
/**
* Get processor configuration
*
* @return array
*/
public function getConfig();
}
Standard location for processor classes is plugins/Processor:
// .phrozn/plugins/Processor/Test.php
namespace PhroznPlugin\Processor;
class Test
extends \Phrozn\Processor\Base
implements \Phrozn\Processor
{
public function render($tpl, $vars = array())
{
return '<b>' . $tpl . '</b>';
}
}
As you see, Test processor inherits from \Phrozn\Processor\Base
- base class which simplifies things by implementing some accessor/mutator methods
(fancy names for getters/setters).
Thus, if you rely on \Phrozn\Processor\Base, the only method you need to implement is
render().
So far we have Test processor which simply wraps incoming template into <b> tags.
2. Create View
For rendering given entry into static HTML page, you need to create content rendering View class. Basically, whenever Phrozn encounters file with extension that matches name of some registered View class, object of this class is used for rendering.
So, all *.twig files, for instance, are actually compiled using
\Phrozn\Site\View\Twig class, which in turn uses
\Phrozn\Processor\Twig text processor for rendering.
Views actually can rely on as many processors as you like, but for now, let's create trivial view which will simply proxy our Test processor.
View classes MUST implement \Phrozn\Site\View interface:
namespace Phrozn\Site;
use Phrozn\Has;
interface View
extends
Has\SiteConfig,
Has\InputFile,
Has\OutputFile,
Has\OutputDir,
Has\Param,
Has\Processors,
Has\FrontMatter,
Has\Template
{
/**
* Render and save static version of a concrete view
*
* @param array $vars List of variables passed to text processors
*
* @return \Phrozn\Site\View
*/
public function compile($vars = array());
/**
* Render input template
*
* @param array $vars List of variables passed to text processors
*
* @return string
*/
public function render($vars = array());
}
As you can see, this interface relies on many other interfaces
(yep, I am fan of ISP),
which makes it harder for clients to implement \Phrozn\Site\View directly.
Fortunately, as with processors, we have base implementation \Phrozn\Site\View\Base
which takes care of most of the auxiliary methods, thus
allowing to concentrate only on methods directly related to rendering.
Standard location for your View renderers is plugins/Site/View:
// .phrozn/plugins/Site/View/Test.php
namespace PhroznPlugin\Site\View;
use PhroznPlugin\Processor;
class Test
extends \Phrozn\Site\View\Base
implements \Phrozn\Site\View
{
/**
* Initialize view
*
* @param string $inputFile Path to view source file
* @param string $outputDir File destination path
*
* @return \Phrozn\Site\View
*/
public function __construct($inputFile = null, $outputDir = null)
{
parent::__construct($inputFile, $outputDir); // manners
// assign processors used by this renderer
$this->addProcessor(new Processor\Test());
}
}
For basic proxy view, all we needed to do is to assign our custom text processor to the view, all the rest is handled automagically - basically base view fetches registered processors and applies them in FIFO order.
Now, let's actually test the whole thing.
3. Register View Renderer
As mentioned before, Phrozn matches extensions of entries to view names, so our Test view will be used every time entry with ".test" extension is located. Time to add one:
# .phrozn/entries/tmp/sample.test --- This entry should be rendered with \PhroznPlugin\Site\View\Test View renderer.
As you will immediately notice your entry was rendered without layout applied.
In order to enable entry rendering within layout
(which layout to use with given entry is settable via front matter) we will need
to override render() method:
// .phrozn/plugins/Site/View/Test.php
namespace PhroznPlugin\Site\View;
use PhroznPlugin\Processor;
class Test
extends \Phrozn\Site\View\Base
implements \Phrozn\Site\View
{
/**
* Initialize view
*
* @param string $inputFile Path to view source file
* @param string $outputDir File destination path
*
* @return \Phrozn\Site\View
*/
public function __construct($inputFile = null, $outputDir = null)
{
parent::__construct($inputFile, $outputDir); // manners
// assign processors used by this renderer
$this->addProcessor(new Processor\Test());
}
/**
* Render view. Twig views are rendered within layout.
*
* @param array $vars List of variables passed to text processors
*
* @return string
*/
public function render($vars = array())
{
$view = parent::render($vars);
if ($this->hasLayout()) {
// inject global site and front matter options into template
$vars = array_merge($vars, $this->getParams());
$view = $this->applyLayout($view, $vars);
}
return $view;
}
}
This summarizes the usage and implementation of custom processors, for inspiration
make sure you check \Phrozn\Processor classes which come out-of-box
with every Phrozn installation.
