Newer
Older
<?php
namespace LakeDrops\Component\Composer;
use Composer\Json\JsonFile;
use Symfony\Component\Yaml\Yaml;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;

jurgenhaas
committed
use Twig\Loader\ArrayLoader;
/**
* Manages project config.
*/
final class Config {

jurgenhaas
committed
/**

jurgenhaas
committed
* @var array
*/

jurgenhaas
committed
* @var array
*/
* The component for which this config object holds the values.
*
* @var string
*/

jurgenhaas
committed
* @var \Twig\Loader\ArrayLoader

jurgenhaas
committed
* @var \Twig\Environment
* @var \LakeDrops\Component\Composer\Dotenv
*/
* @var string
*/
* @var string
*/
/**
* Config constructor.
*
* @param string $component
* The component for which this config object holds the values.
* @param array $default_values
* @param \LakeDrops\Component\Composer\Dotenv $env
public function __construct(string $component, array $default_values, Dotenv $env) {
$this->component = $component;
$this->env = $env;
$this->twigLoader = new ArrayLoader([]);
$this->twig = new Environment($this->twigLoader);
$this->configFile = getcwd() . '/.lakedrops.yml';
$this->userConfigFile = getcwd() . '/.lakedrops.user.yml';
$this->merge($default_values, self::$customValues[$this->component] ?? []);

jurgenhaas
committed
$this->merge([], self::$overwriteValues[$this->component] ?? [], FALSE);
$this->merge([], self::$userValues[$this->component] ?? [], FALSE);
}
/**
* Read project configuration if not already happened.
*/
private function init(): void {
self::$values = [];

jurgenhaas
committed
self::$overwriteValues = [];
if (!file_exists($this->configFile)) {
self::$customValues = [];
$this->save();
}
else {
self::$customValues = Yaml::parseFile($this->configFile);
// Apply overwrite by stage declarations.
$stage = getenv('PROJECT_BRANCH');
if (isset(self::$customValues['stage_overwrites'][$stage])) {

jurgenhaas
committed
self::$overwriteValues = self::$customValues['stage_overwrites'][$stage];
if (!file_exists($this->userConfigFile)) {
self::$userValues = [];
}
else {
self::$userValues = Yaml::parseFile($this->userConfigFile);
}
/**
* Migrate custom settings from composer.json if required.
*/
private function migrateFromComposerJson(): void {
$filename = getcwd() . '/composer.json';
$jsonFile = new JsonFile($filename);
try {
$content = $jsonFile->read();
}
catch (ParsingException $e) {
$content = [];
}
if (isset($content['extra'][$this->component])) {
$this->merge([], $content['extra'][$this->component]);
$this->save();
unset($content['extra'][$this->component]);
try {
$jsonFile->write($content);
}
catch (\Exception $ex) {
// Ignored, if composer.json is read-only there is a general problem.
* Helper function to merge and optionally store config values.
*
* @param array $defaultValues
* @param array $customValues
* Array with custom value to be merged on top of default.

jurgenhaas
committed
* @param bool $store
* TRUE, if the resulting array should be stored back to the config file.
private function merge(array $defaultValues, array $customValues, bool $store = TRUE): void {
$default = self::$values[$this->component] ?? [];
$custom = self::$customValues[$this->component] ?? [];
if (!empty($defaultValues)) {
$default = NestedArray::mergeDeep($default, $defaultValues);
}
if (!empty($customValues)) {
$default = NestedArray::mergeDeep($default, $customValues);

jurgenhaas
committed
if ($store) {
$custom = NestedArray::mergeDeep($custom, $customValues);
}
}
self::$values[$this->component] = $this->env->replaceEnvironmentVariables($default);
self::$customValues[$this->component] = $custom;
}
/**
* Save the current settings.
*/
private function save(): void {
file_put_contents($this->configFile, Yaml::dump(self::$customValues, 9, 2));
* @param array $values
* @param array $keys
* List of keys of how we should dive deep into the value array.
*
* @return mixed|null
private function readValueFromArray(array $values, array $keys) {
$key = array_shift($keys);
if (!isset($values[$key])) {
return NULL;
}
if (empty($keys)) {
return $values[$key];
}
return $this->readValueFromArray($values[$key], $keys);
}
/**
* @param string|array $keys
* List of keys of how we should dive deep into the value array. If a top
* level value should be read, the key can be provided as a string instead
* of an array.
*
* @return mixed|null
public function readValue($keys) {
if (is_string($keys)) {
$keys = [$keys];
}
return $this->readValueFromArray(self::$values[$this->component], $keys);
* @param string $key
* @param mixed $value

jurgenhaas
committed
* @param bool $store
* Whether the new value should be stored in the config file.
public function setValue(string $key, $value, bool $store = TRUE): void {

jurgenhaas
committed
$this->merge([], [$key => $value], $store);
$this->save();
}
* @param string $filename
* @param string $content
*
* @return string
*/
public function render(string $filename, string $content): string {
try {
return $this->twig->render($filename, self::$values[$this->component]);
}
}
return '';
}