Completed
Push — master ( 82ab58...9975bc )
by Mikael
03:15
created

Configuration::getConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
namespace Anax\Configure;
4
5
/**
6
 * Load configuration for a specified item, look in several places for the
7
 * configuration files or directories. Return the configuration as the value
8
 * received from the configuration file.
9
 */
10
class Configuration
11
{
12
    /**
13
     * @var array $config to save the latest loaded config to ease
14
     *                    access.
15
     */
16
    protected $config = [];
17
18
19
20
    /**
21
     * @var array $dirs where to look for configuration items.
22
     */
23
    protected $dirs = [];
24
25
26
27
    /**
28
     * @var array $mapping mapping items to specific configuration file, mainly
29
     *                     useful for testing various configuration files.
30
     */
31
    protected $mapping = [];
32
33
34
35
    /**
36
     * Set a specific configuration file to load for a particluar item.
37
     *
38
     * @param string $item the item to map.
39
     * @param string $file file to load configuration from.
40
     *
41
     * @return self to allow chaining.
42
     */
43
    public function setMapping(string $item, string $file) : object
44
    {
45
        $this->mapping[$item] = $file;
46
        return $this;
47
    }
48
49
50
51
    /**
52
     * Set the directories where to look for configuration
53
     * items (files, directories) to load.
54
     *
55
     * @throws Exception when the path to any of the directories are incorrect.
56
     *
57
     * @param array $dirs with the path to the config directories to search in.
58
     *
59
     * @return self to allow chaining.
60
     */
61
    public function setBaseDirectories(array $dirs): object
62
    {
63
        foreach ($dirs as $dir) {
64
            if (!(is_readable($dir) && is_dir($dir))) {
65
                throw new Exception("The configuration dir '$dir' is not a valid path.");
66
            }
67
        }
68
69
        $this->dirs = $dirs;
70
        return $this;
71
    }
72
73
74
75
    /**
76
     * Read configuration from file or directory, if a file, look though all
77
     * base dirs and use the first configuration that is found. A configuration
78
     * item can be combined from a file and a directory, when available in the
79
     * same base directory.
80
     *
81
     * The resulting configuration is always an array, its structure contains
82
     * values from each individual configuration file, like this.
83
     *
84
     * $config = [
85
     *      "file" => filename for file.php,
86
     *      "config" => result returned from file.php,
87
     *      "items" => [
88
     *          [
89
     *              "file" => filename for dir/file1.php,
90
     *              "config" => result returned from dir/file1.php,
91
     *          ],
92
     *          [
93
     *              "file" => filename for dir/file2.php,
94
     *              "config" => result returned from dir/file2.php,
95
     *          ],
96
     *      ].
97
     * ]
98
     *
99
     * The configuration files in the directory are loaded per alphabetical
100
     * order.
101
     *
102
     * @param string $item is a name representing the module and is used to
103
     *                     combine the path to search for.
104
     *
105
     * @throws Exception when configuration item can not be found.
106
     * @throws Exception when $dirs are empty.
107
     *
108
     * @return array with returned value from the loaded configuration.
109
     */
110
    public function load(string $item) : array
111
    {
112
        $found = false;
113
        $config = [];
114
        $this->config = $config;
115
116
        $mapping = $this->mapping[$item] ?? null;
117
        if ($mapping) {
118
            $config["file"] = $mapping;
119
            $config["config"] = require $mapping;
120
            $this->config = $config;
121
            return $config;
122
        }
123
124
        // The configuration is found by absolute path
125 View Code Duplication
        if (is_readable($item) && is_file($item)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
            $found = true;
127
            $config["file"] = $item;
128
            $config["config"] = require $item;
129
            $this->config = $config;
130
            return $config;
131
        }
132
133
        foreach ($this->dirs as $dir) {
134
            $path = "$dir/$item";
135
            $file = "$path.php";
136
137
            // The configuration is found in a file
138 View Code Duplication
            if (is_readable($file) && is_file($file)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
                $found = true;
140
                $config["file"] = $file;
141
                $config["config"] = require $file;
142
            }
143
144
            // The configuration is found in a directory
145
            if (is_readable($path) && is_dir($path)) {
146
                $found = true;
147
                $config["items"] = $this->loadFromDir($path);
148
            }
149
150
            if ($found) {
151
                break;
152
            }
153
        }
154
155
        if (!$found) {
156
            throw new Exception("Configure item '$item' can not be found.");
157
        }
158
159
        $this->config = $config;
160
        return $config;
161
    }
162
163
164
165
    /**
166
     * Read configuration a directory, loop through all files and add
167
     * them into the $config array as:
168
     * [
169
     *      [
170
     *          "file" => filename for dir/file1.php,
171
     *          "config" => result returned from dir/file1.php,
172
     *      ],
173
     *      [
174
     *          "file" => filename for dir/file2.php,
175
     *          "config" => result returned from dir/file2.php,
176
     *      ],
177
     * ].
178
     *
179
     * @param string $path is the path to the directory containing config files.
180
     *
181
     * @return array with configuration for each file.
182
     */
183
    public function loadFromDir(string $path): array
184
    {
185
        $config = [];
186
        foreach (glob("$path/*.php") as $file) {
187
            $config[] = [
188
                "file" => $file,
189
                "config" => require $file,
190
            ];
191
        }
192
193
        return $config;
194
    }
195
196
197
198
    /**
199
     * Helper function for reading values from the configuration and apply
200
     * default values where configuration item is missing. This
201
     * helper only works when there are single configuration files,
202
     * it does not work when multiple configuration files are loaded
203
     * from a directory.
204
     *
205
     * @param string $key     matching a key in the config array.
206
     * @param string $default value returned when config item is not found.
207
     *
208
     * @return mixed or null if key does not exists.
209
     */
210
    public function getConfig($key, $default = null)
211
    {
212
        return $this->config["config"][$key] ?? $default;
213
    }
214
}
215