Completed
Push — master ( f1fa2a...b378f9 )
by Michael
02:57
created

Wiring   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 2.27%

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 27
lcom 1
cbo 4
dl 0
loc 173
ccs 2
cts 88
cp 0.0227
rs 10
c 4
b 1
f 1

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getDic() 0 4 1
B wireAll() 0 27 5
C doSubs() 0 37 7
C wireConfig() 0 35 7
B parserConfigFile() 0 29 6
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains Wiring class.
5
 *
6
 * PHP version 7.0+
7
 *
8
 * LICENSE:
9
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
10
 * which can be used to access the Eve Online API data and place it into a
11
 * database.
12
 * Copyright (C) 2014-2016 Michael Cummings
13
 *
14
 * This program is free software: you can redistribute it and/or modify it
15
 * under the terms of the GNU Lesser General Public License as published by the
16
 * Free Software Foundation, either version 3 of the License, or (at your
17
 * option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful, but WITHOUT
20
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
22
 * for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public License
25
 * along with this program. If not, see
26
 * <http://spdx.org/licenses/LGPL-3.0.html>.
27
 *
28
 * You should be able to find a copy of this license in the COPYING-LESSER.md
29
 * file. A copy of the GNU GPL should also be available in the COPYING.md file.
30
 *
31
 * @copyright 2014-2016 Michael Cummings
32
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
33
 * @author    Michael Cummings <[email protected]>
34
 */
35
namespace Yapeal\Configuration;
36
37
use FilePathNormalizer\FilePathNormalizerTrait;
38
use Symfony\Component\Yaml\Exception\ParseException;
39
use Symfony\Component\Yaml\Parser;
40
use Yapeal\Container\ContainerInterface;
41
use Yapeal\Exception\YapealException;
42
43
/**
44
 * Class Wiring
45
 */
46
class Wiring
47
{
48
    use FilePathNormalizerTrait;
49
    /**
50
     * @param ContainerInterface $dic
51
     */
52 1
    public function __construct(ContainerInterface $dic)
53
    {
54 1
        $this->dic = $dic;
55
    }
56
    /**
57
     * @return ContainerInterface
58
     */
59
    public function getDic(): ContainerInterface
60
    {
61
        return $this->dic;
62
    }
63
    /**
64
     * @param string $configFile
65
     * @param array  $existing
66
     *
67
     * @return array
68
     * @throws \DomainException
69
     * @throws \Yapeal\Exception\YapealException
70
     */
71
    public function parserConfigFile(string $configFile, array $existing = []): array
72
    {
73
        if (!is_readable($configFile) || !is_file($configFile)) {
74
            return $existing;
75
        }
76
        try {
77
            /**
78
             * @var \RecursiveIteratorIterator|\Traversable $rItIt
79
             */
80
            $rItIt = new \RecursiveIteratorIterator(new \RecursiveArrayIterator((new Parser())->parse(file_get_contents($configFile),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 133 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
81
                true,
82
                false)));
83
        } catch (ParseException $exc) {
84
            $mess = sprintf('Unable to parse the YAML configuration file %2$s. The error message was %1$s',
85
                $exc->getMessage(),
86
                $configFile);
87
            throw new YapealException($mess, 0, $exc);
88
        }
89
        $settings = [];
90
        foreach ($rItIt as $leafValue) {
91
            $keys = [];
92
            foreach (range(0, $rItIt->getDepth()) as $depth) {
93
                $keys[] = $rItIt->getSubIterator($depth)
94
                    ->key();
95
            }
96
            $settings[implode('.', $keys)] = $leafValue;
97
        }
98
        return array_replace($existing, $settings);
99
    }
100
    /**
101
     * @return self Fluent interface.
102
     * @throws \LogicException
103
     */
104
    public function wireAll()
105
    {
106
        $dic = $this->dic;
107
        $base = 'Yapeal.Wiring.Handlers.';
108
        $names = ['Config', 'Error', 'Event', 'Log', 'Sql', 'Xml', 'Xsd', 'Xsl', 'FileSystem', 'Network', 'EveApi'];
109
        /**
110
         * @var WiringInterface $class
111
         */
112
        foreach ($names as $name) {
113
            $setting = $base . strtolower($name);
114
            if (!empty($dic[$setting])
115
                && is_subclass_of($dic[$setting], '\\Yapeal\\Configuration\\WiringInterface', true)
116
            ) {
117
                $class = new $dic[$setting];
118
                $class->wire($dic);
119
                continue;
120
            }
121
            $methodName = 'wire' . $name;
122
            if (method_exists($this, $methodName)) {
123
                $this->$methodName();
124
            } else {
125
                $mess = 'Could NOT find class or method for ' . $name;
126
                throw new \LogicException($mess);
127
            }
128
        }
129
        return $this;
130
    }
131
    /**
132
     * @param array $settings
133
     *
134
     * @return array
135
     * @throws \DomainException
136
     */
137
    protected function doSubs(array $settings): array
138
    {
139
        if (0 === count($settings)) {
140
            return [];
141
        }
142
        $depth = 0;
143
        $maxDepth = 10;
144
        $regEx = '%(?<all>\{(?<name>Yapeal(?:\.\w+)+)\})%';
145
        $dic = $this->dic;
146
        do {
147
            $settings = preg_replace_callback($regEx,
148
                function ($match) use ($settings, $dic) {
149
                    if (array_key_exists($match['name'], $settings)) {
150
                        return $settings[$match['name']];
151
                    }
152
                    if (!empty($dic[$match['name']])) {
153
                        return $dic[$match['name']];
154
                    }
155
                    return $match['all'];
156
                },
157
                $settings,
158
                -1,
159
                $count);
160
            if (++$depth > $maxDepth) {
161
                $mess = 'Exceeded maximum depth, check for possible circular reference(s)';
162
                throw new \DomainException($mess);
163
            }
164
            $lastError = preg_last_error();
165
            if (PREG_NO_ERROR !== $lastError) {
166
                $constants = array_flip(get_defined_constants(true)['pcre']);
167
                $lastError = $constants[$lastError];
168
                $mess = 'Received preg error ' . $lastError;
169
                throw new \DomainException($mess);
170
            }
171
        } while ($count > 0);
172
        return $settings;
173
    }
174
    /**
175
     * @return Wiring Fluent interface.
0 ignored issues
show
Documentation introduced by
Should the return type not be \self?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
176
     * @throws \DomainException
177
     * @throws \Yapeal\Exception\YapealException
178
     */
179
    protected function wireConfig(): self
180
    {
181
        $dic = $this->dic;
182
        $fpn = $this->getFpn();
183
        $path = $fpn->normalizePath(dirname(dirname(__DIR__)));
184
        if (empty($dic['Yapeal.baseDir'])) {
185
            $dic['Yapeal.baseDir'] = $path;
186
        }
187
        if (empty($dic['Yapeal.libDir'])) {
188
            $dic['Yapeal.libDir'] = $path . 'lib/';
189
        }
190
        $configFiles = [
191
            $fpn->normalizeFile(__DIR__ . '/yapeal_defaults.yaml'),
192
            $fpn->normalizeFile($dic['Yapeal.baseDir'] . 'config/yapeal.yaml')
193
        ];
194
        $vendorPos = strpos($path, 'vendor/');
195
        if (false !== $vendorPos) {
196
            $dic['Yapeal.vendorParentDir'] = substr($path, 0, $vendorPos);
197
            $configFiles[] = $fpn->normalizeFile($dic['Yapeal.vendorParentDir'] . 'config/yapeal.yaml');
198
        }
199
        $settings = [];
200
        // Process each file in turn so any substitutions are done in a more
201
        // consistent way.
202
        foreach ($configFiles as $configFile) {
203
            $settings = $this->parserConfigFile($configFile, $settings);
204
        }
205
        $settings = $this->doSubs($settings);
206
        if (0 !== count($settings)) {
207
            // Assure NOT overwriting already existing settings given by application.
208
            foreach ($settings as $key => $value) {
209
                $dic[$key] = $dic[$key] ?? $value;
210
            }
211
        }
212
        return $this;
213
    }
214
    /**
215
     * @var ContainerInterface $dic
216
     */
217
    protected $dic;
218
}
219