Skip to content

Instantly share code, notes, and snippets.

Created June 17, 2015 20:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/dd63bccdb955f49a1e76 to your computer and use it in GitHub Desktop.
Save anonymous/dd63bccdb955f49a1e76 to your computer and use it in GitHub Desktop.
<?php
use Closure;
use LightnCandy;
class MobileTemplateParser {
/**
* @var string
*/
protected $templateDir;
/**
* @var callable[]
*/
protected $renderers;
/**
* @var bool Always compile template files
*/
protected $forceRecompile = false;
/**
* @param string $templateDir
* @param boolean $forceRecompile
*/
public function __construct( $templateDir, $forceRecompile = false ) {
$this->templateDir = $templateDir;
$this->forceRecompile = $forceRecompile;
}
/**
* Constructs the location of the the source handlebars template
* and the compiled php code that goes with it.
*
* @param string $templateName
*
* @return string[]
* @throws FlowException Disallows upwards directory traversal via $templateName
*/
public function getTemplateFilenames( $templateName ) {
// Prevent upwards directory traversal using same methods as Title::secureAndSplit,
// which is implemented in MediaWikiTitleCodec::splitTitleString.
if (
strpos( $templateName, '.' ) !== false &&
(
$templateName === '.' || $templateName === '..' ||
strpos( $templateName, './' ) === 0 ||
strpos( $templateName, '../' ) === 0 ||
strpos( $templateName, '/./' ) !== false ||
strpos( $templateName, '/../' ) !== false ||
substr( $templateName, -2 ) === '/.' ||
substr( $templateName, -3 ) === '/..'
)
) {
throw new FlowException( "Malformed \$templateName: $templateName" );
}
return array(
'template' => "{$this->templateDir}/{$templateName}.handlebars",
'compiled' => "{$this->templateDir}/compiled/{$templateName}.handlebars.php",
);
}
/**
* Returns a given template function if found, otherwise throws an exception.
*
* @param string $templateName
*
* @return Closure
* @throws FlowException
* @throws \Exception
*/
public function getTemplate( $templateName ) {
if ( isset( $this->renderers[$templateName] ) ) {
return $this->renderers[$templateName];
}
$filenames = $this->getTemplateFilenames( $templateName );
if ( $this->forceRecompile ) {
if ( !file_exists( $filenames['template'] ) ) {
throw new Exception( "Could not locate template: {$filenames['template']}" );
}
$code = self::compile( file_get_contents( $filenames['template'] ), $this->templateDir );
if ( !$code ) {
throw new Exception( "Failed to compile template '$templateName'." );
}
$success = file_put_contents( $filenames['compiled'], $code );
// failed to recompile template (OS permissions?); unless the
// content hasn't changes, throw an exception!
if ( !$success && file_get_contents( $filenames['compiled'] ) !== $code ) {
throw new Exception( "Failed to save updated compiled template '$templateName'" );
}
}
/** @var callable $renderer */
$renderer = require $filenames['compiled'];
return $this->renderers[$templateName] = function( $args, array $scopes = array() ) use ( $templateName, $renderer ) {
return $renderer( $args, $scopes );
};
}
/**
* @param string $code Handlebars code
* @param string $templateDir Directory templates are stored in
*
* @return string PHP code
*/
static public function compile( $code, $templateDir ) {
return LightnCandy::compile(
$code,
array(
'flags' => LightnCandy::FLAG_ERROR_EXCEPTION
| LightnCandy::FLAG_MUSTACHE,
'basedir' => array( $templateDir ),
'fileext' => array( '.partial.handlebars' ),
)
);
}
/**
* Returns HTML for a given template by calling the template function with the given args.
*
* @param string $templateName
* @param array $args
* @param array $scopes
*
* @return string
*/
public function processTemplate( $templateName, $args, array $scopes = array() ) {
$template = $this->getTemplate( $templateName );
return call_user_func( $template, $args, $scopes );
}
}
@phuedx
Copy link

phuedx commented Jun 18, 2015

Also:

actually you guys arn't even using partials, can just remove basedir and fileext options from the compile() method so compile() does that same as you were doing before

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment