From c86f6ecbed237e16645a264f68f5a92b94d88406 Mon Sep 17 00:00:00 2001 From: jurgenhaas <juergen.haas@lakedrops.com> Date: Fri, 25 Dec 2020 20:52:06 +0100 Subject: [PATCH] docker/l3d#58 Move project settings out of composer.json --- BaseHandler.php | 3 +- Config.php | 3 +- Dotenv.php | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ composer.json | 2 +- 4 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 Dotenv.php diff --git a/BaseHandler.php b/BaseHandler.php index 89cce82..102aa60 100644 --- a/BaseHandler.php +++ b/BaseHandler.php @@ -6,7 +6,6 @@ use Composer\Composer; use Composer\IO\IOInterface; use Composer\Package\PackageInterface; use Composer\Script\Event; -use LakeDrops\Component\Dotenv\Dotenv; use Symfony\Component\Console\Input\InputInterface; /** @@ -57,7 +56,7 @@ abstract class BaseHandler implements BaseHandlerInterface { protected $drupalCorePackage; /** - * @var \LakeDrops\Component\Dotenv\Dotenv + * @var \LakeDrops\Component\Composer\Dotenv */ protected $env; diff --git a/Config.php b/Config.php index 66c8627..a3978e6 100644 --- a/Config.php +++ b/Config.php @@ -2,7 +2,6 @@ namespace LakeDrops\Component\Composer; -use LakeDrops\Component\Dotenv\Dotenv; use Symfony\Component\Yaml\Yaml; use Twig\Error\LoaderError; use Twig\Error\RuntimeError; @@ -37,7 +36,7 @@ final class Config { * * @param string $component * @param array $default_values - * @param \LakeDrops\Component\Dotenv\Dotenv $env + * @param \LakeDrops\Component\Composer\Dotenv $env */ public function __construct(string $component, array $default_values, Dotenv $env) { $this->component = $component; diff --git a/Dotenv.php b/Dotenv.php new file mode 100644 index 0000000..a1a364c --- /dev/null +++ b/Dotenv.php @@ -0,0 +1,213 @@ +<?php + +namespace LakeDrops\Component\Composer; + +use Composer\IO\IOInterface; +use Exception; +use Symfony\Component\Dotenv\Dotenv as SymfonyDotenv; + +/** + * Manages .env files. + */ +final class Dotenv { + + /** + * Name of the plugin "owning" this instance, used as a prefix. + * + * @var string + */ + private $name; + + /** + * The input-output object of the composer session. + * + * @var \Composer\IO\IOInterface + */ + private $io; + + /** + * The Symfony Dotenv object. + * + * @var \Symfony\Component\Dotenv\Dotenv + */ + private $dotenv; + + /** + * Dotenv constructor. + * + * @param string $name + * Name of the plugin "owning" this instance, used as a prefix. + * @param \Composer\IO\IOInterface $io + * The input-output object of the composer session. + */ + public function __construct(string $name, IOInterface $io) { + $this->name = strtoupper($name); + $this->io = $io; + $this->dotenv = new SymfonyDotenv(); + $this->load(); + } + + /** + * Receive a value from the environment with the project name as prefix. + * + * First of all, it prefixes the key with the plugin name and converts the + * result into upper case. Then looking for the value with PHP's getenv and if + * nothing found, it prompts the user for input if the session is interactive. + * Finally, if the value is still not available, the default value is being + * used. + * + * @param string $key + * The key of the environment variable. + * @param string $prompt + * The text being displayed when prompting the user. + * @param string $default + * The default value. + * + * @return string + * The value. + */ + public function receive(string $key, string $prompt, $default = ''): string { + return $this->receiveGlobal($this->name . '_' . $key, $prompt, $default); + } + + /** + * Receive a value from the environment. + * + * @param string $key + * The key of the environment variable. + * @param string $prompt + * The text being displayed when prompting the user. + * @param string $default + * The default value. + * + * @return string + * The value. + */ + public function receiveGlobal(string $key, string $prompt, $default = ''): string { + $key = strtoupper($key); + $value = $_ENV[$key] ?? NULL; + if ($value === NULL) { + if ($this->io->isInteractive()) { + $value = $this->io->ask($prompt . ': '); + } + if ($value === NULL) { + $value = $default; + } + $this->put($key, $value, TRUE); + } + else { + $this->put($key, $value); + } + + return $value; + } + + /** + * Set an environment variable. + * + * Sets the environment variable into a .env file only if there isn't an + * environment variable present yet. The .env file will also be added to the + * .gitignore file. + * + * @param string $key + * The name of the environment variable. + * @param string $value + * The value of the environment variable. + * @param bool $overwrite + */ + public function put(string $key, string $value, $overwrite = FALSE): void { + $data = $this->parse(); + $key = strtoupper($key); + if (!$overwrite && isset($data[$key])) { + return; + } + $data[$key] = $value; + $envContent = ''; + foreach ($data as $k => $v) { + $envContent .= $k . '=' . $v . PHP_EOL; + } + file_put_contents('.env', $envContent); + $this->load(); + Utils::gitIgnore('.env'); + } + + /** + * Replace environment variables in keys and values of a given array. + * + * Credit: https://github.com/composer/composer/pull/5837 + * + * @param mixed $data + * The keyed array in which to replace environment variables. + * + * @return array + * The same data with environment variables being replaced. + */ + public function replaceEnvironmentVariables($data): array { + array_walk_recursive($data, array($this, 'findEnvironmentVariables')); + return $data; + } + + /** + * Identify and replace environment variables in a key pair + * + * @param string $item + * @param string $key + */ + private function findEnvironmentVariables(string &$item, string &$key): void { + $pattern = '@\{\$env:(\w)\}@i'; + preg_match_all($pattern, $item, $item_matches); + preg_match_all($pattern, $key, $key_matches); + + if (!empty($item_matches[1])) { + $item = $this->replaceItemEnvironmentVariables($item, $item_matches[1]); + } + if (!empty($key_matches[1])) { + $key = $this->replaceItemEnvironmentVariables($key, $key_matches[1]); + } + } + + /** + * Replace environment variables in a string + * + * @param string $item + * @param array $matches + * + * @return string + */ + private function replaceItemEnvironmentVariables(string $item, array $matches): string { + foreach ($matches as $var) { + $value = $_ENV[$var] ?? NULL; + if ($value === NULL) { + $value = ''; + } + $item = str_replace( '{$env:' . $var . '}', $value, $item ); + } + return $item; + } + + /** + * Parse the local .env file and return the content as an array. + * + * @return array + */ + private function parse(): array { + $envContent = file_exists('.env') ? file_get_contents('.env') : ''; + return $this->dotenv->parse($envContent); + } + + /** + * Load the local .env file. + */ + private function load(): void { + try { + foreach ($this->parse() as $key => $value) { + unset($_SERVER[$key]); + } + $this->dotenv->load('.env'); + } + catch (Exception $ex) { + // Ignore. + } + } + +} diff --git a/composer.json b/composer.json index 93ef369..3b4ab1c 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "require": { "php": ">=7.2", "ext-json": "*", - "lakedrops/dotenv": "^1.5||dev-master", + "symfony/dotenv": "^3.4||^4.4||^5.0", "symfony/yaml": "^3.4||^4.4||^5.0", "twig/twig": "^1.44" }, -- GitLab