aboutsummaryrefslogtreecommitdiffstats
path: root/core/namespace/Parsers/FunctionParser.php
diff options
context:
space:
mode:
authorThomas Lange <code@nerdmind.de>2021-07-20 18:39:34 +0200
committerThomas Lange <code@nerdmind.de>2021-07-20 18:39:34 +0200
commite6103791f528357197f8afb9ed222a9469cbd177 (patch)
tree2eeb9ac567532c6dbe646dc44c9f9bca4eb8936f /core/namespace/Parsers/FunctionParser.php
parent01d4727f939c0b9530fe5fc976b7accb9e078db1 (diff)
downloadblog-e6103791f528357197f8afb9ed222a9469cbd177.tar.gz
blog-e6103791f528357197f8afb9ed222a9469cbd177.tar.xz
blog-e6103791f528357197f8afb9ed222a9469cbd177.zip
Implement new *content functions* feature (readme)
This commit implements a new feature called *content functions* that is similar but much more powerful than the already existing *content tags* which you may have already used (`{POST[1]}`, for example). You now can also add your own *content functions* to do some interesting things like embedding a YouTube video or other things to prevent typing repetitive lines of text or code in your entities content. Read the corresponding wiki page to learn more about this: https://github.com/Nerdmind/Blog/wiki/Content-functions
Diffstat (limited to 'core/namespace/Parsers/FunctionParser.php')
-rw-r--r--core/namespace/Parsers/FunctionParser.php84
1 files changed, 84 insertions, 0 deletions
diff --git a/core/namespace/Parsers/FunctionParser.php b/core/namespace/Parsers/FunctionParser.php
new file mode 100644
index 0000000..9f2f72e
--- /dev/null
+++ b/core/namespace/Parsers/FunctionParser.php
@@ -0,0 +1,84 @@
+<?php
+namespace Parsers;
+use ReflectionFunction;
+
+class FunctionParser implements ParserInterface {
+ private static $functions = [];
+
+ #===============================================================================
+ # Regular expressions
+ #===============================================================================
+ private const FUNCTION_SHELL_REGEX = '#\{\s?(%s)%s\s?\}#';
+ private const ARGUMENT_PARTS_REGEX = '(?:\:( (?:(?:"[^"]*"|[0-9]+)(?:,[\s]*)?)+))?';
+ private const ARGUMENT_SPLIT_REGEX = '#("[^"]*"|[0-9]+)(?:,[\s]*)?#';
+
+ #===============================================================================
+ # Register function
+ #===============================================================================
+ public static function register(string $name, callable $callback): void {
+ $Function = new ReflectionFunction($callback);
+ self::$functions[$name] = [
+ 'callback' => $callback,
+ 'required' => $Function->getNumberOfRequiredParameters()
+ ];
+ }
+
+ #===============================================================================
+ # Parse functions
+ #===============================================================================
+ public function parse(string $text): array {
+ $functionNames = array_keys(self::$functions);
+ $functionNames = implode('|', $functionNames);
+
+ $pattern = self::FUNCTION_SHELL_REGEX;
+ $options = self::ARGUMENT_PARTS_REGEX;
+
+ preg_match_all(sprintf($pattern, $functionNames, $options), $text, $matches);
+
+ foreach(array_map(function($name, $parameters) {
+ return [$name , $this->parseParameterString($parameters)];
+ }, $matches[1], $matches[2]) as $match) {
+ $functions[$match[0]][] = $match[1];
+ }
+
+ return $functions ?? [];
+ }
+
+ #===============================================================================
+ # Transform functions
+ #===============================================================================
+ public function transform(string $text): string {
+ $functionData = self::$functions;
+ $functionNames = array_keys($functionData);
+ $functionNames = implode('|', $functionNames);
+
+ $pattern = self::FUNCTION_SHELL_REGEX;
+ $options = self::ARGUMENT_PARTS_REGEX;
+
+ return preg_replace_callback(sprintf($pattern, $functionNames, $options),
+ function($matches) use($functionData) {
+ $function = $matches[1];
+ $callback = $functionData[$function]['callback'];
+ $required = $functionData[$function]['required'];
+
+ $arguments = $this->parseParameterString($matches[2] ?? '');
+
+ if(count($arguments) < $required) {
+ return sprintf('`{%s: *Missing arguments*}`', $function);
+ }
+
+ return $callback(...$arguments);
+ }, $text);
+ }
+
+ #===============================================================================
+ # Parse the parameter string found within the function shell
+ #===============================================================================
+ private function parseParameterString(string $parameters): array {
+ preg_match_all(self::ARGUMENT_SPLIT_REGEX, $parameters, $matches);
+
+ return array_map(function($argument) {
+ return trim($argument, '"');
+ }, $matches[1]);
+ }
+}