Completed
Push — master ( 2b818c...df4948 )
by Michael
04:25
created

Wiring::doSubs()   C

Complexity

Conditions 7
Paths 4

Size

Total Lines 39
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 10
Bugs 2 Features 0
Metric Value
c 10
b 2
f 0
dl 0
loc 39
rs 6.7272
cc 7
eloc 30
nc 4
nop 1
1
<?php
2
/**
3
 * Contains Wiring class.
4
 *
5
 * PHP version 5.5
6
 *
7
 * LICENSE:
8
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
9
 * which can be used to access the Eve Online API data and place it into a
10
 * database.
11
 * Copyright (C) 2014-2016 Michael Cummings
12
 *
13
 * This program is free software: you can redistribute it and/or modify it
14
 * under the terms of the GNU Lesser General Public License as published by the
15
 * Free Software Foundation, either version 3 of the License, or (at your
16
 * option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful, but WITHOUT
19
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
21
 * for more details.
22
 *
23
 * You should have received a copy of the GNU Lesser General Public License
24
 * along with this program. If not, see
25
 * <http://www.gnu.org/licenses/>.
26
 *
27
 * You should be able to find a copy of this license in the LICENSE.md file. A
28
 * copy of the GNU GPL should also be available in the GNU-GPL.md file.
29
 *
30
 * @copyright 2014-2016 Michael Cummings
31
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
32
 * @author    Michael Cummings <[email protected]>
33
 */
34
namespace Yapeal\Configuration;
35
36
use FilePathNormalizer\FilePathNormalizerTrait;
37
use RecursiveIteratorIterator;
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
    public function __construct(ContainerInterface $dic)
53
    {
54
        $this->dic = $dic;
55
    }
56
    /**
57
     * @param string $configFile
58
     * @param array  $settings
59
     *
60
     * @return array
61
     * @throws \DomainException
62
     * @throws \Yapeal\Exception\YapealException
63
     */
64
    public function parserConfigFile($configFile, array $settings = [])
65
    {
66
        if (!is_readable($configFile) || !is_file($configFile)) {
67
            return $settings;
68
        }
69
        try {
70
            /**
71
             * @var \RecursiveIteratorIterator|\Traversable $rItIt
72
             */
73
            $rItIt = new \RecursiveIteratorIterator(
74
                new \RecursiveArrayIterator(
75
                    (new Parser())->parse(file_get_contents($configFile), true, false)
76
                )
77
            );
78
        } catch (ParseException $exc) {
79
            $mess = sprintf(
80
                'Unable to parse the YAML configuration file %2$s.' . ' The error message was %1$s',
81
                $exc->getMessage(),
82
                $configFile
83
            );
84
            throw new YapealException($mess, 0, $exc);
85
        }
86
        foreach ($rItIt as $leafValue) {
87
            $keys = [];
88
            /** @noinspection DisconnectedForeachInstructionInspection */
89
            /**
90
             * @var array $depths
91
             */
92
            $depths = range(0, $rItIt->getDepth());
93
            foreach ($depths as $depth) {
94
                $keys[] = $rItIt->getSubIterator($depth)
95
                                ->key();
96
            }
97
            $settings[implode('.', $keys)] = $leafValue;
98
        }
99
        return $this->doSubs($settings);
100
    }
101
    /**
102
     * @return self Fluent interface.
103
     * @throws \LogicException
104
     */
105
    public function wireAll()
106
    {
107
        $names = ['Config', 'Error', 'Event', 'Log', 'Sql', 'Xml', 'Xsd', 'Xsl', 'Cache', 'Network', 'EveApi'];
108
        foreach ($names as $name) {
109
            $className = __NAMESPACE__ . '\\' . $name . 'Wiring';
110
            if (class_exists($className, true)) {
111
                /**
112
                 * @var WiringInterface $class
113
                 */
114
                $class = new $className();
115
                $class->wire($this->dic);
116
                continue;
117
            }
118
            $methodName = 'wire' . $name;
119
            if (method_exists($this, $methodName)) {
120
                $this->$methodName();
121
            } else {
122
                $mess = 'Could NOT find class or method for ' . $name;
123
                throw new \LogicException($mess);
124
            }
125
        }
126
        return $this;
127
    }
128
    /**
129
     * @param array $settings
130
     *
131
     * @return array
132
     * @throws \DomainException
133
     */
134
    protected function doSubs(array $settings)
135
    {
136
        if (0 === count($settings)) {
137
            return [];
138
        }
139
        $depth = 0;
140
        $maxDepth = 10;
141
        $regEx = '/(?<all>\{(?<name>Yapeal(?:\.\w+)+)\})/';
142
        $dic = $this->dic;
143
        do {
144
            $settings = preg_replace_callback(
145
                $regEx,
146
                function ($match) use ($settings, $dic) {
147
                    if (!empty($settings[$match['name']])) {
148
                        return $settings[$match['name']];
149
                    }
150
                    if (!empty($dic[$match['name']])) {
151
                        return $dic[$match['name']];
152
                    }
153
                    return $match['all'];
154
                },
155
                $settings,
156
                -1,
157
                $count
158
            );
159
            if (++$depth > $maxDepth) {
160
                $mess = 'Exceeded maximum depth, check for possible circular reference(s)';
161
                throw new \DomainException($mess);
162
            }
163
            $lastError = preg_last_error();
164
            if (PREG_NO_ERROR !== $lastError) {
165
                $constants = array_flip(get_defined_constants(true)['pcre']);
166
                $lastError = $constants[$lastError];
167
                $mess = 'Received preg error ' . $lastError;
168
                throw new \DomainException($mess);
169
            }
170
        } while ($count > 0);
171
        return $settings;
172
    }
173
    /**
174
     * @return array
175
     */
176
    protected function getFilteredEveApiSubscriberList()
177
    {
178
        $flags = \FilesystemIterator::CURRENT_AS_FILEINFO
179
            | \FilesystemIterator::KEY_AS_PATHNAME
180
            | \FilesystemIterator::SKIP_DOTS
181
            | \FilesystemIterator::UNIX_PATHS;
182
        $rdi = new \RecursiveDirectoryIterator($this->dic['Yapeal.EveApi.dir']);
183
        $rdi->setFlags($flags);
184
        /** @noinspection SpellCheckingInspection */
185
        $rcfi = new \RecursiveCallbackFilterIterator(
186
            $rdi, function (\SplFileInfo $current, $key, \RecursiveDirectoryIterator $rdi) {
187
            if ($rdi->hasChildren()) {
188
                return true;
189
            }
190
            $dirs = ['Account', 'Api', 'Char', 'Corp', 'Eve', 'Map', 'Server'];
191
            $dirExists = in_array(basename(dirname($key)), $dirs, true);
192
            return ($dirExists && $current->isFile() && 'php' === $current->getExtension());
193
        }
194
        );
195
        /** @noinspection SpellCheckingInspection */
196
        $rii = new RecursiveIteratorIterator(
197
            $rcfi, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD
198
        );
199
        $rii->setMaxDepth(3);
200
        $fpn = $this->getFpn();
201
        $files = [];
202
        foreach ($rii as $file) {
203
            $files[] = $fpn->normalizeFile($file->getPathname());
204
        }
205
        return $files;
206
    }
207
    /**
208
     * @return self Fluent interface.
209
     * @throws \DomainException
210
     * @throws \Yapeal\Exception\YapealException
211
     */
212
    protected function wireConfig()
213
    {
214
        $dic = $this->dic;
215
        $fpn = $this->getFpn();
216
        $path = $fpn->normalizePath(dirname(dirname(__DIR__)));
217
        if (empty($dic['Yapeal.baseDir'])) {
218
            $dic['Yapeal.baseDir'] = $path;
219
        }
220
        if (empty($dic['Yapeal.libDir'])) {
221
            $dic['Yapeal.libDir'] = $path . 'lib/';
222
        }
223
        $configFiles = [
224
            $fpn->normalizeFile(__DIR__ . '/yapeal_defaults.yaml'),
225
            $fpn->normalizeFile($dic['Yapeal.baseDir'] . 'config/yapeal.yaml')
226
        ];
227
        $vendorPos = strpos($path, 'vendor/');
228
        if (false !== $vendorPos) {
229
            $dic['Yapeal.vendorParentDir'] = substr($path, 0, $vendorPos);
230
            $configFiles[] = $fpn->normalizeFile($dic['Yapeal.vendorParentDir'] . 'config/yapeal.yaml');
231
        }
232
        $settings = [];
233
        // Process each file in turn so any substitutions are done in a more
234
        // consistent way.
235
        foreach ($configFiles as $configFile) {
236
            $settings = $this->parserConfigFile($configFile, $settings);
237
        }
238
        if (0 !== count($settings)) {
239
            // Assure NOT overwriting already existing settings from previously processed CLI or application settings.
240
            foreach ($settings as $key => $value) {
241
                $dic[$key] = empty($dic[$key]) ? $value : $dic[$key];
242
            }
243
        }
244
        return $this;
245
    }
246
    /**
247
     * @return self Fluent interface.
248
     */
249
    protected function wireEveApi()
250
    {
251
        /**
252
         * @var ContainerInterface $dic
253
         */
254
        $dic = $this->dic;
255
        /**
256
         * @var \Yapeal\Event\MediatorInterface $mediator
257
         */
258
        $mediator = $dic['Yapeal.Event.Mediator'];
259
        $internal = $this->getFilteredEveApiSubscriberList();
260
        if (0 !== count($internal)) {
261
            $base = 'Yapeal.EveApi';
262
            /**
263
             * @var \SplFileInfo $subscriber
264
             */
265
            foreach ($internal as $subscriber) {
266
                $service = sprintf(
267
                    '%1$s.%2$s.%3$s',
268
                    $base,
269
                    basename(dirname($subscriber)),
270
                    basename($subscriber, '.php')
271
                );
272
                if (!isset($dic[$service])) {
273
                    $dic[$service] = function () use ($dic, $service) {
274
                        $class = '\\' . str_replace('.', '\\', $service);
275
                        /**
276
                         * @var \Yapeal\CommonToolsTrait $callable
277
                         */
278
                        $callable = new $class();
279
                        return $callable->setCsq($dic['Yapeal.Sql.CommonQueries'])
280
                                        ->setPdo($dic['Yapeal.Sql.Connection']);
281
                    };
282
                }
283
                $events = [$service . '.start' => ['startEveApi', 'last']];
284
                if (false === strpos($subscriber, 'Section')) {
285
                    $events[$service . '.preserve'] = ['preserveEveApi', 'last'];
286
                }
287
                $mediator->addServiceSubscriberByEventList($service, $events);
288
            }
289
        }
290
        if (empty($dic['Yapeal.EveApi.Creator'])) {
291
            $dic['Yapeal.EveApi.Creator'] = function () use ($dic) {
292
                $loader = new \Twig_Loader_Filesystem($dic['Yapeal.EveApi.dir']);
293
                $twig = new \Twig_Environment(
294
                    $loader, ['debug' => true, 'strict_variables' => true, 'autoescape' => false]
295
                );
296
                $filter = new \Twig_SimpleFilter(
297
                    'ucFirst', function ($value) {
298
                    return ucfirst($value);
299
                }
300
                );
301
                $twig->addFilter($filter);
302
                $filter = new \Twig_SimpleFilter(
303
                    'lcFirst', function ($value) {
304
                    return lcfirst($value);
305
                }
306
                );
307
                $twig->addFilter($filter);
308
                /**
309
                 * @var \Yapeal\EveApi\Creator $create
310
                 */
311
                $create = new $dic['Yapeal.EveApi.create']($twig, $dic['Yapeal.EveApi.dir']);
312
                if (!empty($dic['Yapeal.Create.overwrite'])) {
313
                    $create->setOverwrite($dic['Yapeal.Create.overwrite']);
314
                }
315
                return $create;
316
            };
317
            $mediator->addServiceSubscriberByEventList(
318
                'Yapeal.EveApi.Creator',
319
                ['Yapeal.EveApi.create' => ['createEveApi', 'last']]
320
            );
321
        }
322
        return $this;
323
    }
324
    /**
325
     * @var ContainerInterface $dic
326
     */
327
    protected $dic;
328
}
329