d922db59a3d98c7f36d58772c8fc9f97be3cb593
[yaffs-website] / vendor / grasmash / yaml-expander / src / Expander.php
1 <?php
2
3 namespace Grasmash\YamlExpander;
4
5 use Dflydev\DotAccessData\Data;
6 use Symfony\Component\Yaml\Yaml;
7
8 /**
9  * Class Expander
10  * @package Grasmash\YamlExpander
11  */
12 class Expander
13 {
14
15     /**
16      * Parses a YAML string and expands property placeholders.
17      *
18      * Placeholders should formatted as ${parent.child}.
19      *
20      * @param string $yaml_string
21      *   A string of YAML.
22      * @param array $reference_array
23      *   Optional. An array of reference values. This is not operated upon but is used as a
24      *   reference to provide supplemental values for property expansion.
25      *
26      * @return array
27      *   The modified array in which placeholders have been replaced with
28      *   values.
29      */
30     public static function parse($yaml_string, $reference_array = [])
31     {
32         $array = Yaml::parse($yaml_string);
33         return self::expandArrayProperties($array, $reference_array);
34     }
35
36
37     /**
38      * Expands property placeholders in an array.
39      *
40      * Placeholders should formatted as ${parent.child}.
41      *
42      * @param array $array
43      *   An array containing properties to expand.
44      *
45      * @return array
46      *   The modified array in which placeholders have been replaced with
47      *   values.
48      */
49     public static function expandArrayProperties($array, $reference_array = [])
50     {
51         $data = new Data($array);
52         if ($reference_array) {
53             $reference_data = new Data($reference_array);
54             self::doExpandArrayProperties($data, $array, '', $reference_data);
55         } else {
56             self::doExpandArrayProperties($data, $array);
57         }
58
59         return $data->export();
60     }
61
62     /**
63      * Performs the actual property expansion.
64      *
65      * @param Data $data
66      *   A data object, containing the $array.
67      * @param array $array
68      *   The original, unmodified array.
69      * @param string $parent_keys
70      *   The parent keys of the current key in dot notation. This is used to
71      *   track the absolute path to the current key in recursive cases.
72      * @param Data|null $reference_data
73      *   A reference data object. This is not operated upon but is used as a
74      *   reference to provide supplemental values for property expansion.
75      */
76     protected static function doExpandArrayProperties(
77         $data,
78         $array,
79         $parent_keys = '',
80         $reference_data = null
81     ) {
82         foreach ($array as $key => $value) {
83             // Boundary condition(s).
84             if (is_null($value) || is_bool($value)) {
85                 continue;
86             }
87             // Recursive case.
88             if (is_array($value)) {
89                 self::doExpandArrayProperties($data, $value, $parent_keys . "$key.", $reference_data);
90             } // Base case.
91             else {
92                 self::expandStringProperties($data, $parent_keys, $reference_data, $value, $key);
93             }
94         }
95     }
96
97     /**
98      * Expand a single property.
99      *
100      * @param Data $data
101      *   A data object, containing the $array.
102      * @param string $parent_keys
103      *   The parent keys of the current key in dot notation. This is used to
104      *   track the absolute path to the current key in recursive cases.
105      * @param Data|null $reference_data
106      *   A reference data object. This is not operated upon but is used as a
107      *   reference to provide supplemental values for property expansion.
108      * @param string $value
109      *   The unexpanded property value.
110      * @param string $key
111      *   The immediate key of the property.
112      *
113      * @return mixed
114      */
115     protected static function expandStringProperties(
116         $data,
117         $parent_keys,
118         $reference_data,
119         $value,
120         $key
121     ) {
122         // We loop through all placeholders in a given string.
123         // E.g., '${placeholder1} ${placeholder2}' requires two replacements.
124         while (strpos($value, '${') !== false) {
125             $original_value = $value;
126             $value = preg_replace_callback(
127                 '/\$\{([^\$}]+)\}/',
128                 function ($matches) use ($data, $reference_data) {
129                     return self::expandStringPropertiesCallback(
130                         $matches,
131                         $data,
132                         $reference_data
133                     );
134                 },
135                 $value
136             );
137
138             // If no replacement occurred at all, break to prevent
139             // infinite loop.
140             if ($original_value == $value) {
141                 break;
142             }
143
144             // Set value on $data object.
145             if ($parent_keys) {
146                 $full_key = $parent_keys . "$key";
147             } else {
148                 $full_key = $key;
149             }
150             $data->set($full_key, $value);
151         }
152         return $value;
153     }
154
155     /**
156      * Expansion callback used by preg_replace_callback() in expandProperty().
157      *
158      * @param array $matches
159      *   An array of matches created by preg_replace_callback().
160      * @param Data $data
161      *   A data object containing the complete array being operated upon.
162      * @param Data|null $reference_data
163      *   A reference data object. This is not operated upon but is used as a
164      *   reference to provide supplemental values for property expansion.
165      *
166      * @return mixed
167      */
168     public static function expandStringPropertiesCallback(
169         $matches,
170         $data,
171         $reference_data = null
172     ) {
173         $property_name = $matches[1];
174         $unexpanded_value = $matches[0];
175
176         // Use only values within the subject array's data.
177         if (!$reference_data) {
178             return self::expandProperty($property_name, $unexpanded_value, $data);
179         } // Search both the subject array's data and the reference data for a value.
180         else {
181             return self::expandPropertyWithReferenceData(
182                 $property_name,
183                 $unexpanded_value,
184                 $data,
185                 $reference_data
186             );
187         }
188     }
189
190     /**
191      * Searches both the subject data and the reference data for value.
192      *
193      * @param string $property_name
194      *   The name of the value for which to search.
195      * @param string $unexpanded_value
196      *   The original, unexpanded value, containing the placeholder.
197      * @param Data $data
198      *   A data object containing the complete array being operated upon.
199      * @param Data|null $reference_data
200      *   A reference data object. This is not operated upon but is used as a
201      *   reference to provide supplemental values for property expansion.
202      *
203      * @return string
204      *   The expanded string.
205      */
206     public static function expandPropertyWithReferenceData(
207         $property_name,
208         $unexpanded_value,
209         $data,
210         $reference_data
211     ) {
212         $expanded_value = self::expandProperty(
213             $property_name,
214             $unexpanded_value,
215             $data
216         );
217         // If the string was not changed using the subject data, try using
218         // the reference data.
219         if ($expanded_value == $unexpanded_value) {
220             $expanded_value = self::expandProperty(
221                 $property_name,
222                 $unexpanded_value,
223                 $reference_data
224             );
225         }
226
227         return $expanded_value;
228     }
229
230     /**
231      * Searches a data object for a value.
232      *
233      * @param string $property_name
234      *   The name of the value for which to search.
235      * @param string $unexpanded_value
236      *   The original, unexpanded value, containing the placeholder.
237      * @param Data $data
238      *   A data object containing possible replacement values.
239      *
240      * @return mixed
241      */
242     public static function expandProperty($property_name, $unexpanded_value, $data)
243     {
244         if (strpos($property_name, "env.") === 0 &&
245           !$data->has($property_name)) {
246             $env_key = substr($property_name, 4);
247             if (getenv($env_key)) {
248                 $data->set($property_name, getenv($env_key));
249             }
250         }
251
252         if (!$data->has($property_name)) {
253             self::log("Property \${'$property_name'} could not be expanded.");
254             return $unexpanded_value;
255         } else {
256             $expanded_value = $data->get($property_name);
257             if (is_array($expanded_value)) {
258                 $expanded_value = Yaml::dump($expanded_value, 0);
259                 return $expanded_value;
260             }
261             self::log("Expanding property \${'$property_name'} => $expanded_value.");
262             return $expanded_value;
263         }
264     }
265
266     /**
267      * @param $message
268      */
269     public static function log($message)
270     {
271         // print "$message\n";
272     }
273 }