export(); } /** * Performs the actual property expansion. * * @param Data $data * A data object, containing the $array. * @param array $array * The original, unmodified array. * @param string $parent_keys * The parent keys of the current key in dot notation. This is used to * track the absolute path to the current key in recursive cases. * @param Data|null $reference_data * A reference data object. This is not operated upon but is used as a * reference to provide supplemental values for property expansion. */ protected static function doExpandArrayProperties( $data, $array, $parent_keys = '', $reference_data = null ) { foreach ($array as $key => $value) { // Boundary condition(s). if (is_null($value) || is_bool($value)) { continue; } // Recursive case. if (is_array($value)) { self::doExpandArrayProperties($data, $value, $parent_keys . "$key.", $reference_data); } // Base case. else { self::expandStringProperties($data, $parent_keys, $reference_data, $value, $key); } } } /** * Expand a single property. * * @param Data $data * A data object, containing the $array. * @param string $parent_keys * The parent keys of the current key in dot notation. This is used to * track the absolute path to the current key in recursive cases. * @param Data|null $reference_data * A reference data object. This is not operated upon but is used as a * reference to provide supplemental values for property expansion. * @param string $value * The unexpanded property value. * @param string $key * The immediate key of the property. * * @return mixed */ protected static function expandStringProperties( $data, $parent_keys, $reference_data, $value, $key ) { // We loop through all placeholders in a given string. // E.g., '${placeholder1} ${placeholder2}' requires two replacements. while (strpos($value, '${') !== false) { $original_value = $value; $value = preg_replace_callback( '/\$\{([^\$}]+)\}/', function ($matches) use ($data, $reference_data) { return self::expandStringPropertiesCallback( $matches, $data, $reference_data ); }, $value ); // If no replacement occurred at all, break to prevent // infinite loop. if ($original_value == $value) { break; } // Set value on $data object. if ($parent_keys) { $full_key = $parent_keys . "$key"; } else { $full_key = $key; } $data->set($full_key, $value); } return $value; } /** * Expansion callback used by preg_replace_callback() in expandProperty(). * * @param array $matches * An array of matches created by preg_replace_callback(). * @param Data $data * A data object containing the complete array being operated upon. * @param Data|null $reference_data * A reference data object. This is not operated upon but is used as a * reference to provide supplemental values for property expansion. * * @return mixed */ public static function expandStringPropertiesCallback( $matches, $data, $reference_data = null ) { $property_name = $matches[1]; $unexpanded_value = $matches[0]; // Use only values within the subject array's data. if (!$reference_data) { return self::expandProperty($property_name, $unexpanded_value, $data); } // Search both the subject array's data and the reference data for a value. else { return self::expandPropertyWithReferenceData( $property_name, $unexpanded_value, $data, $reference_data ); } } /** * Searches both the subject data and the reference data for value. * * @param string $property_name * The name of the value for which to search. * @param string $unexpanded_value * The original, unexpanded value, containing the placeholder. * @param Data $data * A data object containing the complete array being operated upon. * @param Data|null $reference_data * A reference data object. This is not operated upon but is used as a * reference to provide supplemental values for property expansion. * * @return string * The expanded string. */ public static function expandPropertyWithReferenceData( $property_name, $unexpanded_value, $data, $reference_data ) { $expanded_value = self::expandProperty( $property_name, $unexpanded_value, $data ); // If the string was not changed using the subject data, try using // the reference data. if ($expanded_value == $unexpanded_value) { $expanded_value = self::expandProperty( $property_name, $unexpanded_value, $reference_data ); } return $expanded_value; } /** * Searches a data object for a value. * * @param string $property_name * The name of the value for which to search. * @param string $unexpanded_value * The original, unexpanded value, containing the placeholder. * @param Data $data * A data object containing possible replacement values. * * @return mixed */ public static function expandProperty($property_name, $unexpanded_value, $data) { if (strpos($property_name, "env.") === 0 && !$data->has($property_name)) { $env_key = substr($property_name, 4); if (getenv($env_key)) { $data->set($property_name, getenv($env_key)); } } if (!$data->has($property_name)) { self::log("Property \${'$property_name'} could not be expanded."); return $unexpanded_value; } else { $expanded_value = $data->get($property_name); if (is_array($expanded_value)) { $expanded_value = Yaml::dump($expanded_value, 0); return $expanded_value; } self::log("Expanding property \${'$property_name'} => $expanded_value."); return $expanded_value; } } /** * @param $message */ public static function log($message) { // print "$message\n"; } }