Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active November 6, 2019 10:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Potherca/94c0ba1449a2ee57aafddf961f3ebe5d to your computer and use it in GitHub Desktop.
Save Potherca/94c0ba1449a2ee57aafddf961f3ebe5d to your computer and use it in GitHub Desktop.
A minimal implementation of Mustache in PHP. Supports escaped and HTML Variables, Comments, Sections and Inverted Section. Does not support Lists, Callbacks, Partials or Delimiter setting.
<?php
/**
* In Mustache syntax, values are represented by "tags".
*
* Tags are indicated by double braces (a.k.a. curly brackets): {{name}}
*
* To check if a value is available use a "section". A section is a tag that is
* prefixed with a pound `#` character. The closing tag is prefixed with a
* slash `/`. For example, to only show "name" when it is available:
*
* {{#name}}
* <p>{{name}}</p>
* {{/name}}
*
* To show content when a value is NOT available, use an inverted section. An
* inverted section is a tag prefixed with a caret `^`. The closing tag is
* prefixed with a slash `/`. For example, to show content when "name" is not
* available:
*
* {{^name}}
* <p>No name available!</p>
* {{/name}}
*
* All values are HTML escaped by default. To have unescaped HTML, use triple
* braces: {{{name}}}
*
* To add comments, prefix a tag with an exclamation mark `!` (comments may
* contain newlines): {{! this is a comment }}
*
* @author Potherca <potherca@gmail.com>
* @copyright 2016 Potherca
* @license GPLv3+
* @version 0.4.0
*
* @see https://gist.github.com/Potherca/94c0ba1449a2ee57aafddf961f3ebe5d/
*/
/**
* A minimal implementation of Mustache in PHP.
*
* Supports escaped and HTML Variables, Comments, Sections and Inverted Section.
* Does not support Lists, Callbacks, Partials or Delimiter setting.
*
* @param string $template
* @param array $context
*
* @return string
*/
function mini_mustache($template, array $context = [])
{
$pattern = '@({{)(?<SECTION_TYPE>#|\^)(?P<SECTION_NAME>[a-zA-Z\-\_\.]+)(}})(?P<SECTION_CONTENT>.*?)({{/\3}})@sm';
$template = preg_replace_callback($pattern, function (array $matches) use ($context) {
$result = '';
$key = $matches['SECTION_NAME'];
if ($matches['SECTION_TYPE'] === '^') {
// Inverted Section, will be rendered if the key doesn't exist, is false, or is an empty list
if (!array_key_exists($key, $context) || empty($context[$key])) {
$result = $matches['SECTION_CONTENT'];
}
} elseif ($matches['SECTION_TYPE'] === '#') {
// Section, will be rendered if the key exists and has a value of true or is an non-empty list
if (array_key_exists($key, $context) && !empty($context[$key])) {
$result = $matches['SECTION_CONTENT'];
}
} else {
throw new \UnexpectedValueException('Unknown section type in template.');
}
return $result;
}, $template);
$pattern = '/{{\!\s?(?P<COMMENT>.+)\s?}}|{{{\s?(?P<HTML_RAW>[a-zA-Z\-\_\.]+)\s?}}}|{{\s?(?P<HTML_ENCODE>[a-zA-Z\-\_\.]+)\s?}}/m';
return preg_replace_callback($pattern, function (array $matches) use ($context) {
if ($matches['COMMENT'] !== '') {
$result = '';
} elseif ($matches['HTML_RAW'] !== '') {
$encode = false;
$key = $matches['HTML_RAW'];
} elseif ($matches['HTML_ENCODE'] !== '') {
$encode = true;
$key = $matches['HTML_ENCODE'];
} else {
throw new \UnexpectedValueException('Unknown tag type in template.');
}
if (!isset($result) && isset($key)) {
$result = $key;
if (array_key_exists($key, $context)) {
$result = $context[$key];
if (isset($encode) && (bool) $encode === true) {
$result = htmlentities($result, ENT_HTML5 | ENT_QUOTES);
}
}
}
return $result;
}, $template);
}
/*EOF*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment