From a6510f7c79e68dbafb4278dbb134d16760769d14 Mon Sep 17 00:00:00 2001 From: Awilum Date: Wed, 22 Jul 2020 09:29:40 +0300 Subject: [PATCH] feat(support): Simplify parsers and serializers #438 --- src/flextype/Support/Parsers/Markdown.php | 70 ++++++++++ src/flextype/Support/Parsers/Shortcode.php | 81 ++++++++++++ .../Shortcodes/EntriesShortcodeExtension.php | 15 +++ .../RegistryShortcodeExtension.php | 4 +- .../Shortcodes}/UrlShortcodeExtension.php | 4 +- .../Support/Serializers/Frontmatter.php | 111 ++++++++++++++++ src/flextype/Support/Serializers/Json.php | 122 ++++++++++++++++++ .../Serializers/Yaml.php | 97 ++++++++------ 8 files changed, 461 insertions(+), 43 deletions(-) create mode 100644 src/flextype/Support/Parsers/Markdown.php create mode 100644 src/flextype/Support/Parsers/Shortcode.php create mode 100644 src/flextype/Support/Parsers/Shortcodes/EntriesShortcodeExtension.php rename src/flextype/{Foundation/Parsers/shortcodes => Support/Parsers/Shortcodes}/RegistryShortcodeExtension.php (73%) rename src/flextype/{Foundation/Parsers/shortcodes => Support/Parsers/Shortcodes}/UrlShortcodeExtension.php (83%) create mode 100644 src/flextype/Support/Serializers/Frontmatter.php create mode 100644 src/flextype/Support/Serializers/Json.php rename src/flextype/{Foundation => Support}/Serializers/Yaml.php (56%) diff --git a/src/flextype/Support/Parsers/Markdown.php b/src/flextype/Support/Parsers/Markdown.php new file mode 100644 index 00000000..0133af80 --- /dev/null +++ b/src/flextype/Support/Parsers/Markdown.php @@ -0,0 +1,70 @@ +flextype = $flextype; + $this->markdown = $markdown; + } + + /** + * Takes a MARKDOWN encoded string and converts it into a PHP variable. + * + * @param string $input A string containing MARKDOWN + * @param bool $cache Cache result data or no. Default is true + * + * @return mixed The MARKDOWN converted to a PHP value + */ + public function parse(string $input, bool $cache = true) : string + { + if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) { + $key = md5($input); + + if ($data_from_cache = $this->flextype['cache']->fetch($key)) { + return $data_from_cache; + } + + $data = $this->_parse($input); + $this->flextype['cache']->save($key, $data); + + return $data; + } + + return $this->_parse($input); + } + + /** + * @see parse() + */ + protected function _parse(string $input) : string + { + return $this->markdown->text($input); + } +} diff --git a/src/flextype/Support/Parsers/Shortcode.php b/src/flextype/Support/Parsers/Shortcode.php new file mode 100644 index 00000000..d1ad4963 --- /dev/null +++ b/src/flextype/Support/Parsers/Shortcode.php @@ -0,0 +1,81 @@ +flextype = $flextype; + $this->shortcode = $shortcode; + } + + /** + * Add shortcode handler + * + * @param string $name Shortcode name + * @param $handler Handler + */ + public function add(string $name, $handler) + { + return $this->shortcode->addHandler($name, $handler); + } + + /** + * Takes a SHORTCODE encoded string and converts it into a PHP variable. + * + * @param string $input A string containing SHORTCODE + * @param bool $cache Cache result data or no. Default is true + * + * @return mixed The SHORTCODE converted to a PHP value + */ + public function parse(string $input, bool $cache = true) : string + { + if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) { + $key = md5($input); + + if ($data_from_cache = $this->flextype['cache']->fetch($key)) { + return $data_from_cache; + } + + $data = $this->_parse($input); + $this->flextype['cache']->save($key, $data); + + return $data; + } + + return $this->_parse($input); + } + + /** + * @see parse() + */ + protected function _parse(string $input) : string + { + return $this->shortcode->process($input); + } +} diff --git a/src/flextype/Support/Parsers/Shortcodes/EntriesShortcodeExtension.php b/src/flextype/Support/Parsers/Shortcodes/EntriesShortcodeExtension.php new file mode 100644 index 00000000..b5cf387d --- /dev/null +++ b/src/flextype/Support/Parsers/Shortcodes/EntriesShortcodeExtension.php @@ -0,0 +1,15 @@ +add('entries_fetch', function (ShortcodeInterface $s) use ($flextype) { + return array_get($flextype['entries']->fetch($s->getParameter('id')), $s->getParameter('field'), $s->getParameter('default')); +}); diff --git a/src/flextype/Foundation/Parsers/shortcodes/RegistryShortcodeExtension.php b/src/flextype/Support/Parsers/Shortcodes/RegistryShortcodeExtension.php similarity index 73% rename from src/flextype/Foundation/Parsers/shortcodes/RegistryShortcodeExtension.php rename to src/flextype/Support/Parsers/Shortcodes/RegistryShortcodeExtension.php index e604e549..e5176cda 100644 --- a/src/flextype/Foundation/Parsers/shortcodes/RegistryShortcodeExtension.php +++ b/src/flextype/Support/Parsers/Shortcodes/RegistryShortcodeExtension.php @@ -7,11 +7,9 @@ declare(strict_types=1); * Founded by Sergey Romanenko and maintained by Flextype Community. */ -namespace Flextype; - use Thunder\Shortcode\Shortcode\ShortcodeInterface; // Shortcode: [registry_get name="item-name" default="default-value"] -$flextype['shortcodes']->addHandler('registry_get', static function (ShortcodeInterface $s) use ($flextype) { +$flextype['shortcode']->add('registry_get', function (ShortcodeInterface $s) use ($flextype) { return $flextype['registry']->get($s->getParameter('name'), $s->getParameter('default')); }); diff --git a/src/flextype/Foundation/Parsers/shortcodes/UrlShortcodeExtension.php b/src/flextype/Support/Parsers/Shortcodes/UrlShortcodeExtension.php similarity index 83% rename from src/flextype/Foundation/Parsers/shortcodes/UrlShortcodeExtension.php rename to src/flextype/Support/Parsers/Shortcodes/UrlShortcodeExtension.php index 983d20c4..0aaf62f5 100644 --- a/src/flextype/Foundation/Parsers/shortcodes/UrlShortcodeExtension.php +++ b/src/flextype/Support/Parsers/Shortcodes/UrlShortcodeExtension.php @@ -7,13 +7,11 @@ declare(strict_types=1); * Founded by Sergey Romanenko and maintained by Flextype Community. */ -namespace Flextype; - use Slim\Http\Environment; use Slim\Http\Uri; // Shortcode: [url] -$flextype['shortcodes']->addHandler('url', static function () use ($flextype) { +$flextype['shortcode']->add('url', function () use ($flextype) { if ($flextype['registry']->has('flextype.settings.url') && $flextype['registry']->get('flextype.settings.url') !== '') { return $flextype['registry']->get('flextype.settings.url'); } diff --git a/src/flextype/Support/Serializers/Frontmatter.php b/src/flextype/Support/Serializers/Frontmatter.php new file mode 100644 index 00000000..e405fc83 --- /dev/null +++ b/src/flextype/Support/Serializers/Frontmatter.php @@ -0,0 +1,111 @@ +flextype = $flextype; + } + + /** + * Returns the FRONTMATTER representation of a value + * + * @param mixed $input The PHP value + * + * @return string A FRONTMATTER string representing the original PHP value + */ + public function encode($input) : string + { + return $this->_encode($input); + } + + /** + * Takes a FRONTMATTER encoded string and converts it into a PHP variable. + * + * @param string $input A string containing FRONTMATTER + * @param bool $cache Cache result data or no. Default is true + * + * @return mixed The FRONTMATTER converted to a PHP value + */ + public function decode(string $input, bool $cache = true) + { + if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) { + $key = md5($input); + + if ($data_from_cache = $this->flextype['cache']->fetch($key)) { + return $data_from_cache; + } + + $data = $this->_decode($input); + $this->flextype['cache']->save($key, $data); + + return $data; + } + + return $this->_decode($input); + } + + /** + * @see encode() + */ + protected function _encode($input) : string + { + if (isset($input['content'])) { + $content = $input['content']; + array_delete($input, 'content'); + $matter = Yaml::encode($input); + } else { + $content = ''; + $matter = Yaml::encode($input); + } + + $encoded = '---' . "\n" . + $matter . + '---' . "\n" . + $content; + + return $encoded; + } + + /** + * @see decode() + */ + protected function _decode(string $input) + { + $parts = preg_split('/^[\s\r\n]?---[\s\r\n]?$/sm', PHP_EOL . ltrim($input)); + if (count($parts) < 3) { + return ['content' => trim($input)]; + } + + return Yaml::decode(trim($parts[1]), false) + ['content' => trim(implode(PHP_EOL . '---' . PHP_EOL, array_slice($parts, 2)))]; + } +} diff --git a/src/flextype/Support/Serializers/Json.php b/src/flextype/Support/Serializers/Json.php new file mode 100644 index 00000000..907e7027 --- /dev/null +++ b/src/flextype/Support/Serializers/Json.php @@ -0,0 +1,122 @@ +flextype = $flextype; + } + + /** + * Returns the JSON representation of a value + * + * @param mixed $input The PHP value + * @param int $options Bitmask consisting of encode options + * @param int $depth Encode Depth. Set the maximum depth. Must be greater than zero. + * + * @return mixed A JSON string representing the original PHP value + */ + public function encode($input, int $options = 0, int $depth = 512) : string + { + return $this->_encode($input, $options, $depth); + } + + /** + * Takes a JSON encoded string and converts it into a PHP variable. + * + * @param string $input A string containing JSON + * @param bool $cache Cache result data or no. Default is true + * @param bool $assoc Decode assoc. When TRUE, returned objects will be converted into associative arrays. + * @param int $depth Decode Depth. Set the maximum depth. Must be greater than zero. + * @param int $flags Bitmask consisting of decode options + * + * @return mixed The JSON converted to a PHP value + * + * @throws ParseException If the JSON is not valid + */ + public function decode(string $input, bool $cache = true, bool $assoc = true, int $depth = 512, int $flags = 0) + { + if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) { + $key = md5($input); + + if ($data_from_cache = $this->flextype['cache']->fetch($key)) { + return $data_from_cache; + } + + $data = $this->_decode($input); + $this->flextype['cache']->save($key, $data); + + return $data; + } + + return $this->_decode($input); + } + + /** + * @see Json::encode() + */ + public function _encode($input, $options = 0, int $depth = 512) : string + { + $options = ($options & $this->ESCAPE_UNICODE ? 0 : JSON_UNESCAPED_UNICODE) + | JSON_UNESCAPED_SLASHES + | ($options & $this->PRETTY ? JSON_PRETTY_PRINT : 0) + | (defined('JSON_PRESERVE_ZERO_FRACTION') ? JSON_PRESERVE_ZERO_FRACTION : 0); + + $json = json_encode($value, $options, $depth); + + if ($error = json_last_error()) { + throw new RuntimeException(json_last_error_msg(), $error); + } + + return $json; + } + + /** + * @see decode() + */ + protected function _decode(string $input, bool $assoc = true, int $depth = 512, int $flags = 0) + { + $value = json_decode($json, $assoc, $depth, $flags); + + if ($error = json_last_error()) { + throw new RuntimeException(json_last_error_msg(), $error); + } + + return $value; + } +} diff --git a/src/flextype/Foundation/Serializers/Yaml.php b/src/flextype/Support/Serializers/Yaml.php similarity index 56% rename from src/flextype/Foundation/Serializers/Yaml.php rename to src/flextype/Support/Serializers/Yaml.php index c90e7b48..c074888a 100644 --- a/src/flextype/Foundation/Serializers/Yaml.php +++ b/src/flextype/Support/Serializers/Yaml.php @@ -7,7 +7,7 @@ declare(strict_types=1); * Founded by Sergey Romanenko and maintained by Flextype Community. */ -namespace Flextype; +namespace Flextype\Support\Serializers; use RuntimeException; use Symfony\Component\Yaml\Exception\DumpException as SymfonyYamlDumpException; @@ -16,6 +16,7 @@ use Symfony\Component\Yaml\Yaml as SymfonyYaml; use function function_exists; use function ini_get; use function ini_set; +use function md5; class Yaml { @@ -32,23 +33,20 @@ class Yaml public const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024; /** - * Inline - * - * The level where you switch to inline YAML - * - * @var int + * Flextype Dependency Container */ - public static $inline = 5; + private $flextype; /** - * Ident + * Constructor * - * The amount of spaces to use for indentation of nested nodes - * - * @var int + * @access public */ - public static $indent = 2; - + public function __construct($flextype) + { + $this->flextype = $flextype; + } + /** * Native * @@ -58,33 +56,64 @@ class Yaml */ public static $native = true; - /** - * Flags - * - * A bit field of PARSE_* constants to customize the YAML parser behavior - * - * @var int - */ - public static $flags = 16; - /** * Dumps a PHP value to a YAML string. * * The dump method, when supplied with an array, will do its best * to convert the array into friendly YAML. * - * @param mixed $input The PHP value + * @param mixed $input The PHP value + * @param int $inline The level where you switch to inline YAML + * @param int $indent The amount of spaces to use for indentation of nested nodes + * @param int $flags A bit field of DUMP_* constants to customize the dumped YAML string * * @return string A YAML string representing the original PHP value */ - public static function encode($input) : string + public function encode($input, int $inline = 2, int $indent = 4, int $flags = 0) : string + { + return $this->_encode($input, $inline, $indent, $flags); + } + + /** + * Parses YAML into a PHP value. + * + * @param string $input A string containing YAML + * @param bool $cache Cache result data or no. Default is true + * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior + * + * @return mixed The YAML converted to a PHP value + * + * @throws ParseException If the YAML is not valid + */ + public function decode(string $input, bool $cache = true, int $flags = 0) : array + { + if ($cache === true && $this->flextype['registry']->get('flextype.settings.cache.enabled') === true) { + $key = md5($input); + + if ($data_from_cache = $this->flextype['cache']->fetch($key)) { + return $data_from_cache; + } + + $data = $this->_decode($input, $flags); + $this->flextype['cache']->save($key, $data); + + return $data; + } + + return $this->_decode($input, $flags); + } + + /** + * @see encode() + */ + protected function _encode($input, int $inline = 2, int $indent = 4, int $flags = 0) : string { try { return SymfonyYaml::dump( $input, - self::$inline, - self::$indent, - self::$flags + $inline, + $indent, + $flags ); } catch (SymfonyYamlDumpException $e) { throw new RuntimeException('Encoding YAML failed: ' . $e->getMessage(), 0, $e); @@ -92,18 +121,12 @@ class Yaml } /** - * Parses YAML into a PHP value. - * - * @param string $input A string containing YAML - * - * @return array The YAML converted to a PHP value - * - * @throws ParseException If the YAML is not valid + * @see decode() */ - public static function decode(string $input) : array + protected function _decode(string $input, int $flags = 0) : array { // Try native PECL YAML PHP extension first if available. - if (function_exists('yaml_parse') && self::$native) { + if (function_exists('yaml_parse') && $this->$native) { // Safely decode YAML. $saved = @ini_get('yaml.decode_php'); @ini_set('yaml.decode_php', '0'); @@ -116,7 +139,7 @@ class Yaml } try { - return SymfonyYaml::parse($input, self::$flags); + return SymfonyYaml::parse($input, $flags); } catch (SymfonyYamlParseException $e) { throw new RuntimeException('Decoding YAML failed: ' . $e->getMessage(), 0, $e); }