diff options
Diffstat (limited to 'library/Graphite/Util/MacroTemplate.php')
-rw-r--r-- | library/Graphite/Util/MacroTemplate.php | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/library/Graphite/Util/MacroTemplate.php b/library/Graphite/Util/MacroTemplate.php new file mode 100644 index 0000000..23a171a --- /dev/null +++ b/library/Graphite/Util/MacroTemplate.php @@ -0,0 +1,239 @@ +<?php + +namespace Icinga\Module\Graphite\Util; + +use InvalidArgumentException; + +/** + * A macro-based template for strings + */ +class MacroTemplate +{ + /** + * Macros' start and end character + * + * @var string + */ + protected $macroCharacter; + + /** + * The parsed template + * + * @var string[] + */ + protected $template; + + /** + * Regex for reverse resolving patterns + * + * @var string + */ + protected $reverseResolvePattern; + + /** + * Wildcards + * + * @var string[] + */ + protected $wildCards; + + /** + * The original raw template + * + * @var string + */ + protected $orgTemplate; + + /** + * Constructor + * + * @param string $template The raw template + * @param string $macroCharacter Macros' start and end character + */ + public function __construct($template, $macroCharacter = '$') + { + $this->orgTemplate = $template; + $this->macroCharacter = $macroCharacter; + $this->template = explode($macroCharacter, $template); + foreach ($this->template as $key => $value) { + if (preg_match('/([^:]+):(.+)/', $value, $match)) { + $wildCardKey = $match[1]; + $this->template[$key] = $wildCardKey; + $this->wildCards[$wildCardKey] = $match[2]; + } + } + + if (! (count($this->template) % 2)) { + throw new InvalidArgumentException( + 'template contains odd number of ' . var_export($macroCharacter, true) + . 's: ' . var_export($template, true) + ); + } + } + + /** + * Return a string based on this template with the macros resolved from the given variables + * + * @param string[] $variables + * @param string $default The default value for missing variables. + * By default the macro just isn't replaced. + * + * @return string + */ + public function resolve(array $variables, $default = null) + { + $macro = false; + $result = []; // kind of string builder + + foreach ($this->template as $part) { + if ($macro) { + if (isset($variables[$part])) { + $result[] = $variables[$part]; + } elseif ($part === '') { + $result[] = $this->macroCharacter; + } elseif ($default === null) { + $result[] = $this->macroCharacter; + $result[] = $part; + // add wildcards to result before they are + // overwritten from Template::getFullCurves() + if (isset($this->wildCards[$part])) { + $result[] = ':' . $this->wildCards[$part]; + } + + $result[] = $this->macroCharacter; + } else { + if (isset($this->wildCards[$part])) { + $result[] = $this->wildCards[$part]; + } else { + $result[] = $default; + } + } + } else { + $result[] = $part; + } + + $macro = ! $macro; + } + + return implode($result); + } + + /** + * Try to reverse-resolve the given string + * + * @param string $resolved A result of {@link resolve()} + * + * @return string[]|false Variables as passed to {@link resolve()} if successful + */ + public function reverseResolve($resolved) + { + $matches = []; + if (! preg_match($this->getReverseResolvePattern(), $resolved, $matches)) { + return false; + } + + $macro = false; + $macros = []; + $currentCapturedSubPatternIndex = 0; + + foreach ($this->template as $part) { + if ($macro && ! isset($macros[$part])) { + $macros[$part] = ++$currentCapturedSubPatternIndex; + } + + $macro = ! $macro; + } + + $macros = array_flip($macros); + + $result = []; + foreach ($matches as $index => $match) { + if ($index > 0) { + $result[$macros[$index]] = $match; + } + } + + return $result; + } + + /** + * Return the raw template string this instance was constructed from + * + * @return string + */ + public function __toString() + { + return $this->orgTemplate; + } + + /** + * Return the macros of this template + * + * @return string[] + */ + public function getMacros() + { + $macro = false; + $macros = []; + + foreach ($this->template as $part) { + if ($macro) { + $macros[$part] = null; + } + + $macro = ! $macro; + } + + unset($macros['']); + + return array_keys($macros); + } + + /** + * Get macros' start and end character + * + * @return string + */ + public function getMacroCharacter() + { + return $this->macroCharacter; + } + + /** + * Get {@link reverseResolvePattern} + * + * @return string + */ + protected function getReverseResolvePattern() + { + if ($this->reverseResolvePattern === null) { + $result = ['/\A']; // kind of string builder + $macro = false; + $macros = []; + $currentCapturedSubPatternIndex = 0; + + foreach ($this->template as $part) { + if ($macro) { + if (isset($macros[$part])) { + $result[] = '\g{'; + $result[] = $macros[$part]; + $result[] = '}'; + } else { + $macros[$part] = ++$currentCapturedSubPatternIndex; + $result[] = '(.*)'; + } + } else { + $result[] = preg_quote($part, '/'); + } + + $macro = ! $macro; + } + + $result[] = '\z/s'; + + $this->reverseResolvePattern = implode($result); + } + + return $this->reverseResolvePattern; + } +} |