ConfigStorage::__construct()   B
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 37
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 37
rs 8.439
cc 6
eloc 26
nc 7
nop 3
1
<?php
2
3
/*
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the MIT license. For more information, see
18
 * <http://www.doctrine-project.org>.
19
 */
20
21
namespace Baleen\Cli\Config;
22
23
use Baleen\Migrations\Exception\InvalidArgumentException;
24
use League\Flysystem\FilesystemInterface;
25
use Symfony\Component\Config\Definition\ConfigurationInterface;
26
use Symfony\Component\Config\Definition\Processor;
27
use Symfony\Component\Yaml\Yaml;
28
29
/**
30
 * Class ConfigStorage.
31
 *
32
 * @author Gabriel Somoza <[email protected]>
33
 */
34
class ConfigStorage
35
{
36
    /** @var FilesystemInterface */
37
    protected $projectFileSystem;
38
39
    /** @var array */
40
    protected $localConfigStack;
41
42
    /** @var Processor */
43
    protected $processor;
44
45
    /** @var string */
46
    protected $configClass;
47
48
    /** @var ConfigurationInterface */
49
    protected $definition;
50
51
    /** @var string */
52
    protected $defaultFileName;
53
54
    /**
55
     * ConfigStorage constructor.
56
     *
57
     * @param string              $configClass       The FQN of the configuration file to be loaded.
58
     * @param FilesystemInterface $projectFileSystem
59
     * @param array               $localConfigStack  Array of files that contain configuration information in PHP
60
     *                                               arrays (see ./config folder in this project)
61
     *
62
     * @throws InvalidArgumentException
63
     */
64
    public function __construct(
65
        $configClass,
66
        FilesystemInterface $projectFileSystem,
67
        array $localConfigStack = []
68
    ) {
69
        foreach ($localConfigStack as $file) {
70
            if (!is_file($file) || !is_readable($file)) {
71
                throw new InvalidArgumentException(sprintf(
72
                    'Config file "%s" must be a readable file.',
73
                    $file
74
                ));
75
            }
76
        }
77
        $this->localConfigStack = $localConfigStack;
78
79
        $configClass = (string) $configClass;
80
        if (!class_exists($configClass)) {
81
            throw new InvalidArgumentException(sprintf(
82
                'Invalid argument configClass: class "%s" does not exist.',
83
                $configClass
84
            ));
85
        }
86
        $this->configClass = $configClass;
87
        $configInstance = new $configClass();
88
        if (!$configInstance instanceof ConfigInterface) {
89
            throw new InvalidArgumentException(sprintf(
90
                'Class "%s" must be an instance of %s.',
91
                $configClass,
92
                ConfigInterface::class
93
            ));
94
        }
95
        $this->definition = $configInstance->getDefinition();
96
        $this->defaultFileName = $configInstance->getFileName();
97
98
        $this->processor = new Processor();
99
        $this->projectFileSystem = $projectFileSystem;
100
    }
101
102
    /**
103
     * @param string $configFileName The path to the consumer's config file (eg .baleen.yml) relative to the project
104
     *                               filesystem
105
     *
106
     * @return Config
107
     */
108
    public function load($configFileName = null)
109
    {
110
        $configs = [];
111
112
        // load all local configs (config files that are not user-facing)
113
        $localConfig = [];
114
        foreach ($this->localConfigStack as $file) {
115
            $config = include $file;
116
            $localConfig = array_merge_recursive($localConfig, $config);
117
        }
118
        if (!empty($localConfig)) {
119
            $configs[] = $localConfig;
120
        }
121
122
        // load the current project's config file (user-facing)
123
        if (null === $configFileName) {
124
            $configFileName = $this->defaultFileName;
125
        }
126
        if ($this->projectFileSystem->has($configFileName)) {
127
            $configs[] = Yaml::parse($this->projectFileSystem->read($configFileName));
128
        }
129
130
        // validate and merge all configs
131
        $config = $this->processor->processConfiguration(
132
            $this->definition,
133
            $configs
134
        );
135
136
        return new $this->configClass($config);
137
    }
138
139
    /**
140
     * @param ConfigInterface $config
141
     *
142
     * @return bool
143
     */
144
    public function write(ConfigInterface $config)
145
    {
146
        $fileName = $config->getFileName() ?: Config::CONFIG_FILE_NAME;
147
        $array = $config->getCleanArray();
148
        $contents = Yaml::dump($array);
149
150
        return $this->projectFileSystem->write($fileName, $contents);
151
    }
152
153
    /**
154
     * Returns whether the specified configuration has an existing user-facing config file.
155
     *
156
     * @param ConfigInterface $config
157
     *
158
     * @return bool
159
     */
160
    public function isInitialized(ConfigInterface $config)
161
    {
162
        return $this->projectFileSystem->has($config->getFileName());
163
    }
164
}
165