Completed
Push — master ( b378f9...f97949 )
by Michael
03:14
created

ConfigFileProcessingTrait::doSubstitutions()   C

Complexity

Conditions 7
Paths 4

Size

Total Lines 36
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 36
ccs 0
cts 26
cp 0
rs 6.7272
cc 7
eloc 28
nc 4
nop 2
crap 56
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains trait ConfigFileProcessingTrait.
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) 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
 * @author    Michael Cummings <[email protected]>
32
 * @copyright 2016 Michael Cummings
33
 * @license   LGPL-3.0+
34
 */
35
namespace Yapeal\Configuration;
36
37
use Symfony\Component\Yaml\Exception\ParseException;
38
use Symfony\Component\Yaml\Parser;
39
use Yapeal\Container\ContainerInterface;
40
use Yapeal\Exception\YapealException;
41
use Yapeal\FileSystem\SafeFileHandlingTrait;
42
43
/**
44
 * Trait ConfigFileProcessingTrait.
45
 */
46
trait ConfigFileProcessingTrait
47
{
48
    use SafeFileHandlingTrait;
49
    /**
50
     * Looks for and replaces any {Yapeal.*} it finds in values with the corresponding other setting value.
51
     *
52
     * This will replace full value or part of the value. Examples:
53
     *
54
     *     $settings = [
55
     *         'Yapeal.baseDir' => '/my/junk/path/Yapeal/',
56
     *         'Yapeal.libDir' => '{Yapeal.baseDir}lib/'
57
     *         'Yapeal.Sql.dir' => '{Yapeal.libDir}Sql/'
58
     *     ];
59
     *
60
     * After doSubstitutions would be:
61
     *
62
     *     $settings = [
63
     *         'Yapeal.baseDir' => '/my/junk/path/Yapeal/',
64
     *         'Yapeal.libDir' => '/my/junk/path/Yapeal/lib/'
65
     *         'Yapeal.Sql.dir' => '/my/junk/path/Yapeal/lib/Sql/'
66
     *     ];
67
     *
68
     * Note that order in which subs are done is undefined so it could have
69
     * done libDir first and then baseDir into both or done baseDir into libDir
70
     * then libDir into Sql.dir.
71
     *
72
     * Subs from within $settings itself are used first with $dic used to
73
     * fill-in as needed for any unknown ones.
74
     *
75
     * Subs are tried up to 10 times as long as any {Yapeal.*} are found before
76
     * giving up to prevent infinite loop.
77
     *
78
     * @param array              $settings
79
     * @param ContainerInterface $dic
80
     *
81
     * @return array
82
     * @throws \DomainException
83
     */
84
    protected function doSubstitutions(array $settings, ContainerInterface $dic): array
85
    {
86
        if (0 === count($settings)) {
87
            return [];
88
        }
89
        $depth = 0;
90
        $maxDepth = 10;
91
        $regEx = '%(?<all>\{(?<name>Yapeal(?:\.\w+)+)\})%';
92
        do {
93
            $settings = preg_replace_callback($regEx,
94
                function ($match) use ($settings, $dic) {
95
                    if (array_key_exists($match['name'], $settings)) {
96
                        return $settings[$match['name']];
97
                    }
98
                    if (!empty($dic[$match['name']])) {
99
                        return $dic[$match['name']];
100
                    }
101
                    return $match['all'];
102
                },
103
                $settings,
104
                -1,
105
                $count);
106
            if (++$depth > $maxDepth) {
107
                $mess = 'Exceeded maximum depth, check for possible circular reference(s)';
108
                throw new \DomainException($mess);
109
            }
110
            $lastError = preg_last_error();
111
            if (PREG_NO_ERROR !== $lastError) {
112
                $constants = array_flip(get_defined_constants(true)['pcre']);
113
                $lastError = $constants[$lastError];
114
                $mess = 'Received preg error ' . $lastError;
115
                throw new \DomainException($mess);
116
            }
117
        } while ($count > 0);
118
        return $settings;
119
    }
120
    /**
121
     * Converts any depth Yaml config file into a flattened array with '.' separators and values.
122
     *
123
     * @param string $configFile
124
     * @param array  $existing
125
     *
126
     * @return array
127
     * @throws \DomainException
128
     * @throws \Yapeal\Exception\YapealException
129
     */
130
    protected function parserConfigFile(string $configFile, array $existing = []): array
131
    {
132
        $yaml = $this->safeFileRead($configFile);
133
        if (false === $yaml) {
134
            return $existing;
135
        }
136
        try {
137
            /**
138
             * @var \RecursiveIteratorIterator|\Traversable $rItIt
139
             */
140
            $rItIt = new \RecursiveIteratorIterator(new \RecursiveArrayIterator((new Parser())->parse($yaml,
141
                true,
142
                false)));
143
        } catch (ParseException $exc) {
144
            $mess = sprintf('Unable to parse the YAML configuration file %2$s. The error message was %1$s',
145
                $exc->getMessage(),
146
                $configFile);
147
            throw new YapealException($mess, 0, $exc);
148
        }
149
        $settings = [];
150
        foreach ($rItIt as $leafValue) {
151
            $keys = [];
152
            foreach (range(0, $rItIt->getDepth()) as $depth) {
153
                $keys[] = $rItIt->getSubIterator($depth)
154
                    ->key();
155
            }
156
            $settings[implode('.', $keys)] = $leafValue;
157
        }
158
        return array_replace($existing, $settings);
159
    }
160
}
161