4 * This file is part of the Behat Testwork.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
11 namespace Behat\Testwork\ServiceContainer\Configuration;
13 use Behat\Testwork\ServiceContainer\Exception\ConfigurationLoadingException;
14 use Symfony\Component\Yaml\Yaml;
17 * Loads configuration from different sources.
19 * @author Konstantin Kudryashov <ever.zet@gmail.com>
21 final class ConfigurationLoader
26 private $configurationPath;
30 private $environmentVariable;
34 private $profileFound;
38 private $debugInformation = array(
39 'environment_variable_name' => 'none',
40 'environment_variable_content' => 'none',
41 'configuration_file_path' => 'none'
47 * @param string $environmentVariableName Environment variable name
48 * @param string $configurationPath Configuration file path
50 public function __construct($environmentVariableName = null, $configurationPath = null)
52 $this->environmentVariable = $environmentVariableName;
53 $this->configurationPath = $configurationPath;
57 * Sets environment variable name.
59 * @param null|string $variable
61 public function setEnvironmentVariableName($variable)
63 $this->environmentVariable = $variable;
67 * Returns environment variable name.
71 public function getEnvironmentVariableName()
73 return $this->environmentVariable;
77 * Sets configuration file path.
79 * @param null|string $path
81 public function setConfigurationFilePath($path)
83 $this->configurationPath = $path;
87 * Returns configuration file path.
91 public function getConfigurationFilePath()
93 return $this->configurationPath;
97 * Reads configuration sequence for specific profile.
99 * @param string $profile Profile name
103 * @throws ConfigurationLoadingException
105 public function loadConfiguration($profile = 'default')
108 $this->profileFound = false;
110 // first is ENV config
111 foreach ($this->loadEnvironmentConfiguration() as $config) {
112 $configs[] = $config;
115 // second is file configuration (if there is some)
116 if ($this->configurationPath) {
117 $this->debugInformation['configuration_file_path'] = $this->configurationPath;
119 foreach ($this->loadFileConfiguration($this->configurationPath, $profile) as $config) {
120 $configs[] = $config;
124 // if specific profile has not been found
125 if ('default' !== $profile && !$this->profileFound) {
126 throw new ConfigurationLoadingException(sprintf(
127 'Can not find configuration for `%s` profile.',
136 * Returns array with configuration debug information.
140 public function debugInformation()
142 return $this->debugInformation;
146 * Loads information from environment variable.
150 * @throws ConfigurationLoadingException If environment variable environment var is set to invalid JSON
152 protected function loadEnvironmentConfiguration()
156 if (!$this->environmentVariable) {
160 $this->debugInformation['environment_variable_name'] = $this->environmentVariable;
162 if ($envConfig = getenv($this->environmentVariable)) {
163 $config = @json_decode($envConfig, true);
165 $this->debugInformation['environment_variable_content'] = $envConfig;
168 throw new ConfigurationLoadingException(sprintf(
169 'Environment variable `%s` should contain a valid JSON, but it is set to `%s`.',
170 $this->environmentVariable,
175 $configs[] = $config;
182 * Loads information from YAML configuration file.
184 * @param string $configPath Config file path
185 * @param string $profile Profile name
189 * @throws ConfigurationLoadingException If config file is not found
191 protected function loadFileConfiguration($configPath, $profile)
193 if (!is_file($configPath) || !is_readable($configPath)) {
194 throw new ConfigurationLoadingException(sprintf('Configuration file `%s` not found.', $configPath));
197 $basePath = rtrim(dirname($configPath), DIRECTORY_SEPARATOR);
198 $config = (array) Yaml::parse(file_get_contents($configPath));
200 return $this->loadConfigs($basePath, $config, $profile);
204 * Loads configs for provided config and profile.
206 * @param string $basePath
207 * @param array $config
208 * @param string $profile
212 private function loadConfigs($basePath, array $config, $profile)
216 // first load default profile from current config, but only if custom profile requested
217 if ('default' !== $profile && isset($config['default'])) {
218 $configs[] = $config['default'];
221 // then recursively load profiles from imports
222 if (isset($config['imports']) && is_array($config['imports'])) {
223 $configs = array_merge($configs, $this->loadImports($basePath, $config['imports'], $profile));
226 // then load specific profile from current config
227 if (isset($config[$profile])) {
228 $configs[] = $config[$profile];
229 $this->profileFound = true;
236 * Loads all provided imports.
238 * @param string $basePath
239 * @param array $paths
240 * @param string $profile
244 private function loadImports($basePath, array $paths, $profile)
247 foreach ($paths as $path) {
248 foreach ($this->parseImport($basePath, $path, $profile) as $importConfig) {
249 $configs[] = $importConfig;
259 * @param string $basePath
260 * @param string $path
261 * @param string $profile
265 * @throws ConfigurationLoadingException If import file not found
267 private function parseImport($basePath, $path, $profile)
269 if (!file_exists($path) && file_exists($basePath . DIRECTORY_SEPARATOR . $path)) {
270 $path = $basePath . DIRECTORY_SEPARATOR . $path;
273 if (!file_exists($path)) {
274 throw new ConfigurationLoadingException(sprintf(
275 'Can not import `%s` configuration file. File not found.',
280 return $this->loadFileConfiguration($path, $profile);