summaryrefslogtreecommitdiffstats
path: root/vendor/ipl/html/src/TemplateString.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ipl/html/src/TemplateString.php')
-rw-r--r--vendor/ipl/html/src/TemplateString.php175
1 files changed, 175 insertions, 0 deletions
diff --git a/vendor/ipl/html/src/TemplateString.php b/vendor/ipl/html/src/TemplateString.php
new file mode 100644
index 0000000..611ea12
--- /dev/null
+++ b/vendor/ipl/html/src/TemplateString.php
@@ -0,0 +1,175 @@
+<?php
+
+namespace ipl\Html;
+
+use Exception;
+
+/**
+ * Render {{#mustache}}Mustache{{/mustache}}-like string from {@link ValidHtml} element arguments
+ *
+ * # Example Usage
+ * ```
+ * $info = TemplateString::create(
+ * 'Follow the {{#doc}}HTML documentation{{/doc}} for more information on {{#strong}}HTML elements{{/strong}}',
+ * [
+ * 'doc' => new Link(null, 'doc/html'),
+ * 'strong' => Html::tag('strong')
+ * ]
+ * );
+ * ```
+ */
+class TemplateString extends FormattedString
+{
+ /** @var array */
+ protected $templateArgs = [];
+
+ /** @var int */
+ protected $pos = 0;
+
+ /** @var string */
+ protected $string;
+
+ /** @var int */
+ protected $length;
+
+ public function __construct($format, $args = null)
+ {
+ $parentArgs = [];
+ foreach ($args ?: [] as $val) {
+ if (is_array($val) && is_string(key($val))) {
+ $this->templateArgs += $val;
+ } else {
+ $parentArgs[] = $val;
+ }
+ }
+
+ parent::__construct($format, $parentArgs);
+ }
+
+ /**
+ * Parse template strings
+ *
+ * @param null $for template name
+ * @return HtmlDocument
+ * @throws Exception in case of missing template argument or unbounded open or close templates
+ */
+ protected function parseTemplates($for = null)
+ {
+ $buffer = '';
+
+ while (($char = $this->readChar()) !== false) {
+ if ($char !== '{') {
+ $buffer .= $char;
+ continue;
+ }
+
+ $nextChar = $this->readChar();
+ if ($nextChar !== '{') {
+ $buffer .= $char . $nextChar;
+ continue;
+ }
+
+ $templateHandle = $this->readChar();
+ $start = $templateHandle === '#';
+ $end = $templateHandle === '/';
+
+ $templateKey = $this->readUntil('}');
+ // if the string following '{{#' is read up to the last character or (length - 1)th character
+ // then it is not a template
+ if ($this->pos >= $this->length - 1) {
+ $buffer .= $char . $nextChar . $templateHandle . $templateKey;
+ continue;
+ }
+
+ $this->pos++;
+ $closeChar = $this->readChar();
+
+ if ($closeChar !== '}') {
+ $buffer .= $char . $nextChar . $templateHandle . $templateKey . '}' . $closeChar;
+ continue;
+ }
+
+ if ($start) {
+ if (isset($this->templateArgs[$templateKey])) {
+ $wrapper = $this->templateArgs[$templateKey];
+
+ $buffer .= $this->parseTemplates($templateKey)->prependWrapper($wrapper);
+ } else {
+ throw new Exception(sprintf(
+ 'Missing template argument: %s ',
+ $templateKey
+ ));
+ }
+ } elseif ($for === $templateKey && $end) {
+ // close the template
+ $for = null;
+ break;
+ } else {
+ // throw exception for unbounded closing of templates
+ throw new Exception(sprintf(
+ 'Unbound closing of template: %s',
+ $templateKey
+ ));
+ }
+ }
+
+ if ($this->pos === $this->length && $for !== null) {
+ throw new Exception(sprintf(
+ 'Unbound opening of template: %s',
+ $for
+ ));
+ }
+
+ return (new HtmlDocument())->addHtml(HtmlString::create($buffer));
+ }
+
+ /**
+ * Read until any of the given chars appears
+ *
+ * @param string ...$chars
+ *
+ * @return string
+ */
+ protected function readUntil(...$chars)
+ {
+ $buffer = '';
+ while (($c = $this->readChar()) !== false) {
+ if (in_array($c, $chars, true)) {
+ $this->pos--;
+ break;
+ }
+
+ $buffer .= $c;
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Read a single character
+ *
+ * @return false|string false if there is no character left
+ */
+ protected function readChar()
+ {
+ if ($this->length > $this->pos) {
+ return $this->string[$this->pos++];
+ }
+
+ return false;
+ }
+
+ public function render()
+ {
+ $formattedstring = parent::render();
+ if (empty($this->templateArgs)) {
+ return $formattedstring;
+ }
+
+ $this->string = $formattedstring;
+
+ $this->length = strlen($formattedstring);
+
+ return $this->parseTemplates()->render();
+ }
+}