From f91ea165a6f6724ed5e2412da53ad91475dcaf39 Mon Sep 17 00:00:00 2001 From: Alex Prokopenko Date: Wed, 18 Jul 2018 19:21:09 +0300 Subject: [PATCH] Fixed merge script for specs with dots in paths --- src/Helpers/Arr.php | 14 ++++++++------ src/Helpers/Str.php | 10 ++++++---- src/YamlReader.php | 24 ++++++++++++++++-------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/Helpers/Arr.php b/src/Helpers/Arr.php index c405223..7d28a96 100644 --- a/src/Helpers/Arr.php +++ b/src/Helpers/Arr.php @@ -39,10 +39,11 @@ class Arr * `function($array, $defaultValue)`. * @param null|mixed $default the default value to be returned if the specified array key does not exist. Not used when * getting value from an object. + * @param string $key_separator nested key parts separator * * @return mixed the value of the element if found, default value otherwise */ - public static function get($array, $key, $default = null) + public static function get($array, $key, $default = null, $key_separator = '.') { if ($key instanceof \Closure) { return $key($array, $default); @@ -52,9 +53,9 @@ public static function get($array, $key, $default = null) return $array[$key]; } - if (($pos = strrpos($key, '.')) !== false) { - $array = Arr::get($array, substr($key, 0, $pos), $default); - $key = substr($key, $pos + 1); + if (($pos = strrpos($key, $key_separator)) !== false) { + $array = Arr::get($array, substr($key, 0, $pos), $default, $key_separator); + $key = substr($key, $pos + strlen($key_separator)); } if (is_object($array)) { @@ -118,8 +119,9 @@ public static function get($array, $key, $default = null) * you can also describe the path as an array of keys * if the path is null then `$array` will be assigned the `$value` * @param mixed $value the value to be written + * @param string $key_separator nested key parts separator */ - public static function set(&$array, $path, $value) + public static function set(&$array, $path, $value, $key_separator = '.') { if ($path === null) { $array = $value; @@ -127,7 +129,7 @@ public static function set(&$array, $path, $value) return; } - $keys = is_array($path) ? $path : explode('.', $path); + $keys = is_array($path) ? $path : explode($key_separator, $path); while (count($keys) > 1) { $key = array_shift($keys); diff --git a/src/Helpers/Str.php b/src/Helpers/Str.php index 67a0708..97db2ef 100644 --- a/src/Helpers/Str.php +++ b/src/Helpers/Str.php @@ -17,14 +17,15 @@ class Str * user.profile.name > user/profile/name * * @param string $key + * @param string $separator array nested parts separator * * @return string */ - public static function dotkey2path($key) + public static function arrkey2path($key, $separator = '.') { return strtr($key, [ '/' => '/', - '.' => '/', + $separator => '/', ]); } @@ -35,13 +36,14 @@ public static function dotkey2path($key) * /user/profile/name/ > user.profile.name * * @param string $path + * @param string $separator array nested parts separator * * @return string */ - public static function path2dotkey($path) + public static function path2arrkey($path, $separator = '.') { return strtr(trim($path, '/'), [ - '/' => '.', + '/' => $separator, ]); } } diff --git a/src/YamlReader.php b/src/YamlReader.php index 5083524..3266f76 100644 --- a/src/YamlReader.php +++ b/src/YamlReader.php @@ -15,6 +15,13 @@ */ class YamlReader { + /** + * Special symbol for building array nested keys + * + * URLs can contain usual cars like dots or lines, so to a safe key we will use rarely used ASCII symbol + */ + const ARR_KEY_SEP = 'ยป'; + /** * Parse multi-document yaml file. * @@ -51,9 +58,10 @@ public function parseMultiFile($filename) */ public function mergeByReferences($yaml, $basedir, $index = '') { - $branch = $index ? Arr::get($yaml, $index) : $yaml; + $ks = static::ARR_KEY_SEP; // Safe nested array key separator. + $branch = $index ? Arr::get($yaml, $index, null, $ks) : $yaml; foreach ($branch as $key => $value) { - $branch_key = trim("$index.$key", '.'); + $branch_key = trim("{$index}{$ks}{$key}", $ks); if (is_array($value)) { $yaml = $this->mergeByReferences($yaml, $basedir, $branch_key); } elseif ('$ref' === $key && is_string($value) && 0 !== strpos($value, '#')) { @@ -81,19 +89,19 @@ public function mergeByReferences($yaml, $basedir, $index = '') $ref_yaml = $this->parse($ref_yaml_content); // get referenced yaml part. - $ref_branch = Arr::get($ref_yaml, Str::path2dotkey($path)); + $ref_branch = Arr::get($ref_yaml, Str::path2arrkey($path, $ks), null, $ks); - $branch_parent_path = dirname(Str::dotkey2path($index)); - $ref_parent_path = dirname(Str::dotkey2path(Str::path2dotkey($path))); + $branch_parent_path = dirname(Str::arrkey2path($index, $ks)); + $ref_parent_path = dirname(Str::arrkey2path(Str::path2arrkey($path, $ks), $ks)); if ($branch_parent_path !== $ref_parent_path) { - Arr::set($yaml, $branch_key, "#$path"); - $branch_key = Str::path2dotkey($path); + Arr::set($yaml, $branch_key, "#$path", $ks); + $branch_key = Str::path2arrkey($path, $ks); } else { $branch_key = $index; } - Arr::set($yaml, $branch_key, $ref_branch); + Arr::set($yaml, $branch_key, $ref_branch, $ks); // check refs in replaced fragment. $yaml = $this->mergeByReferences($yaml, $basedir, $branch_key);