Completed
Push — master ( 7c429e...75748b )
by Michael
03:23
created

Wiring   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 304
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 29
Bugs 3 Features 3
Metric Value
wmc 39
c 29
b 3
f 3
lcom 1
cbo 11
dl 0
loc 304
rs 8.2857

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B wireAll() 0 23 4
C doSubs() 0 39 7
B getFilteredEveApiSubscriberList() 0 31 5
B parserConfigFile() 0 41 6
D wireConfig() 0 44 9
C wireEveApi() 0 75 7
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 FilesystemIterator;
38
use RecursiveArrayIterator;
39
use RecursiveIteratorIterator;
40
use Symfony\Component\Yaml\Exception\ParseException;
41
use Symfony\Component\Yaml\Parser;
42
use Traversable;
43
use Twig_Environment;
44
use Twig_Loader_Filesystem;
45
use Twig_SimpleFilter;
46
use Yapeal\Container\ContainerInterface;
47
use Yapeal\Exception\YapealDatabaseException;
48
use Yapeal\Exception\YapealException;
49
50
/**
51
 * Class Wiring
52
 */
53
class Wiring
54
{
55
    use FilePathNormalizerTrait;
56
    /**
57
     * @param ContainerInterface $dic
58
     */
59
    public function __construct(ContainerInterface $dic)
60
    {
61
        $this->dic = $dic;
62
    }
63
    /**
64
     * @return self Fluent interface.
65
     * @throws \LogicException
66
     * @throws \DomainException
67
     * @throws \InvalidArgumentException
68
     * @throws YapealException
69
     * @throws YapealDatabaseException
70
     */
71
    public function wireAll()
72
    {
73
        $names = ['Config', 'Error', 'Event', 'Log', 'Sql', 'Xml', 'Xsd', 'Xsl', 'Cache', 'Network', 'EveApi'];
74
        foreach ($names as $name) {
75
            $className = __NAMESPACE__ . '\\' . $name . 'Wiring';
76
            if (class_exists($className, true)) {
77
                /**
78
                 * @var WiringInterface $class
79
                 */
80
                $class = new $className();
81
                $class->wire($this->dic);
82
                continue;
83
            }
84
            $methodName = 'wire' . $name;
85
            if (method_exists($this, $methodName)) {
86
                $this->$methodName();
87
            } else {
88
                $mess = 'Could NOT find class or method for ' . $name;
89
                throw new \LogicException($mess);
90
            }
91
        }
92
        return $this;
93
    }
94
    /**
95
     * @param array $settings
96
     *
97
     * @return array
98
     * @throws \DomainException
99
     * @throws \InvalidArgumentException
100
     */
101
    protected function doSubs(array $settings)
102
    {
103
        if (0 === count($settings)) {
104
            return [];
105
        }
106
        $depth = 0;
107
        $maxDepth = 10;
108
        $regEx = '/(?<all>\{(?<name>Yapeal(?:\.\w+)+)\})/';
109
        $dic = $this->dic;
110
        do {
111
            $settings = preg_replace_callback(
112
                $regEx,
113
                function ($match) use ($settings, $dic) {
114
                    if (!empty($settings[$match['name']])) {
115
                        return $settings[$match['name']];
116
                    }
117
                    if (!empty($dic[$match['name']])) {
118
                        return $dic[$match['name']];
119
                    }
120
                    return $match['all'];
121
                },
122
                $settings,
123
                -1,
124
                $count
125
            );
126
            if (++$depth > $maxDepth) {
127
                $mess = 'Exceeded maximum depth, check for possible circular reference(s)';
128
                throw new \DomainException($mess);
129
            }
130
            $lastError = preg_last_error();
131
            if (PREG_NO_ERROR !== $lastError) {
132
                $constants = array_flip(get_defined_constants(true)['pcre']);
133
                $lastError = $constants[$lastError];
134
                $mess = 'Received preg error ' . $lastError;
135
                throw new \DomainException($mess);
136
            }
137
        } while ($count > 0);
138
        return $settings;
139
    }
140
    /**
141
     * @return array
142
     */
143
    protected function getFilteredEveApiSubscriberList()
144
    {
145
        $flags = FilesystemIterator::CURRENT_AS_FILEINFO
146
            | FilesystemIterator::KEY_AS_PATHNAME
147
            | FilesystemIterator::SKIP_DOTS
148
            | FilesystemIterator::UNIX_PATHS;
149
        $rdi = new \RecursiveDirectoryIterator($this->dic['Yapeal.EveApi.dir']);
150
        $rdi->setFlags($flags);
151
        /** @noinspection SpellCheckingInspection */
152
        $rcfi = new \RecursiveCallbackFilterIterator(
153
            $rdi, function (\SplFileInfo $current, $key, \RecursiveDirectoryIterator $rdi) {
154
            if ($rdi->hasChildren()) {
155
                return true;
156
            }
157
            $dirs = ['Account', 'Api', 'Char', 'Corp', 'Eve', 'Map', 'Server'];
158
            $dirExists = in_array(basename(dirname($key)), $dirs, true);
159
            return ($dirExists && $current->isFile() && 'php' === $current->getExtension());
160
        }
161
        );
162
        /** @noinspection SpellCheckingInspection */
163
        $rii = new RecursiveIteratorIterator(
164
            $rcfi, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD
165
        );
166
        $rii->setMaxDepth(3);
167
        $fpn = $this->getFpn();
168
        $files = [];
169
        foreach ($rii as $file) {
170
            $files[] = $fpn->normalizeFile($file->getPathname());
171
        }
172
        return $files;
173
    }
174
    /**
175
     * @param string $configFile
176
     * @param array  $settings
177
     *
178
     * @return array|string
179
     * @throws \DomainException
180
     * @throws \InvalidArgumentException
181
     * @throws YapealException
182
     */
183
    protected function parserConfigFile($configFile, $settings)
184
    {
185
        if (!is_readable($configFile) || !is_file($configFile)) {
186
            return $settings;
187
        }
188
        try {
189
            /**
190
             * @var RecursiveIteratorIterator|Traversable $rItIt
191
             */
192
            $rItIt = new RecursiveIteratorIterator(
193
                new RecursiveArrayIterator(
194
                    (new Parser())->parse(
195
                        file_get_contents($configFile),
196
                        true,
197
                        false
198
                    )
199
                )
200
            );
201
        } catch (ParseException $exc) {
202
            $mess = sprintf(
203
                'Unable to parse the YAML configuration file %2$s.' . ' The error message was %1$s',
204
                $exc->getMessage(),
205
                $configFile
206
            );
207
            throw new YapealException($mess, 0, $exc);
208
        }
209
        foreach ($rItIt as $leafValue) {
210
            $keys = [];
211
            /** @noinspection DisconnectedForeachInstructionInspection */
212
            /**
213
             * @var array $depths
214
             */
215
            $depths = range(0, $rItIt->getDepth());
216
            foreach ($depths as $depth) {
217
                $keys[] = $rItIt->getSubIterator($depth)
218
                                ->key();
219
            }
220
            $settings[implode('.', $keys)] = $leafValue;
221
        }
222
        return $this->doSubs($settings);
223
    }
224
    /**
225
     * @return self Fluent interface.
226
     * @throws \DomainException
227
     * @throws \InvalidArgumentException
228
     * @throws YapealException
229
     */
230
    protected function wireConfig()
231
    {
232
        $dic = $this->dic;
233
        $fpn = $this->getFpn();
234
        $path = $fpn->normalizePath(dirname(dirname(__DIR__)));
235
        if (empty($dic['Yapeal.baseDir'])) {
236
            $dic['Yapeal.baseDir'] = $path;
237
        }
238
        if (empty($dic['Yapeal.libDir'])) {
239
            $dic['Yapeal.libDir'] = $path . 'lib/';
240
        }
241
        $configFiles = [
242
            $fpn->normalizeFile(__DIR__ . '/yapeal_defaults.yaml'),
243
            $fpn->normalizeFile($dic['Yapeal.baseDir'] . 'config/yapeal.yaml')
244
        ];
245
        if (empty($dic['Yapeal.vendorParentDir'])) {
246
            $vendorPos = strpos(
247
                $path,
248
                'vendor/'
249
            );
250
            if (false !== $vendorPos) {
251
                $dic['Yapeal.vendorParentDir'] = substr($path, 0, $vendorPos);
252
                $configFiles[] = $fpn->normalizeFile($dic['Yapeal.vendorParentDir'] . 'config/yapeal.yaml');
253
            }
254
        } else {
255
            $configFiles[] = $fpn->normalizeFile($dic['Yapeal.vendorParentDir'] . 'config/yapeal.yaml');
256
        }
257
        $settings = [];
258
        // Process each file in turn so any substitutions are done in a more
259
        // consistent way.
260
        foreach ($configFiles as $configFile) {
261
            $settings = $this->parserConfigFile(
262
                $configFile,
263
                $settings
264
            );
265
        }
266
        if (0 !== count($settings)) {
267
            // Assure NOT overwriting already existing settings.
268
            foreach ($settings as $key => $value) {
269
                $dic[$key] = empty($dic[$key]) ? $value : $dic[$key];
270
            }
271
        }
272
        return $this;
273
    }
274
    /**
275
     * @return self Fluent interface.
276
     */
277
    protected function wireEveApi()
278
    {
279
        /**
280
         * @var ContainerInterface $dic
281
         */
282
        $dic = $this->dic;
283
        /**
284
         * @var \Yapeal\Event\MediatorInterface $mediator
285
         */
286
        $mediator = $dic['Yapeal.Event.Mediator'];
287
        $internal = $this->getFilteredEveApiSubscriberList();
288
        if (0 !== count($internal)) {
289
            $base = 'Yapeal.EveApi';
290
            /**
291
             * @var \SplFileInfo $subscriber
292
             */
293
            foreach ($internal as $subscriber) {
294
                $service = sprintf(
295
                    '%1$s.%2$s.%3$s',
296
                    $base,
297
                    basename(dirname($subscriber)),
298
                    basename($subscriber, '.php')
299
                );
300
                if (!isset($dic[$service])) {
301
                    $dic[$service] = function () use ($dic, $service) {
302
                        $class = '\\' . str_replace('.', '\\', $service);
303
                        /**
304
                         * @var \Yapeal\EveApi\EveApiToolsTrait $callable
305
                         */
306
                        $callable = new $class();
307
                        return $callable->setCsq($dic['Yapeal.Sql.CommonQueries'])
308
                                        ->setPdo($dic['Yapeal.Sql.Connection']);
309
                    };
310
                }
311
                $events = [$service . '.start' => ['startEveApi', 'last']];
312
                if (false === strpos($subscriber, 'Section')) {
313
                    $events[$service . '.preserve'] = ['preserveEveApi', 'last'];
314
                }
315
                $mediator->addServiceSubscriberByEventList($service, $events);
316
            }
317
        }
318
        if (empty($dic['Yapeal.EveApi.Creator'])) {
319
            $dic['Yapeal.EveApi.Creator'] = function () use ($dic) {
320
                $loader = new Twig_Loader_Filesystem($dic['Yapeal.EveApi.dir']);
321
                $twig = new Twig_Environment(
322
                    $loader, ['debug' => true, 'strict_variables' => true, 'autoescape' => false]
323
                );
324
                $filter = new Twig_SimpleFilter(
325
                    'ucFirst', function ($value) {
326
                    return ucfirst($value);
327
                }
328
                );
329
                $twig->addFilter($filter);
330
                $filter = new Twig_SimpleFilter(
331
                    'lcFirst', function ($value) {
332
                    return lcfirst($value);
333
                }
334
                );
335
                $twig->addFilter($filter);
336
                /**
337
                 * @var \Yapeal\EveApi\Creator $create
338
                 */
339
                $create = new $dic['Yapeal.EveApi.create']($twig, $dic['Yapeal.EveApi.dir']);
340
                if (!empty($dic['Yapeal.Create.overwrite'])) {
341
                    $create->setOverwrite($dic['Yapeal.Create.overwrite']);
342
                }
343
                return $create;
344
            };
345
            $mediator->addServiceSubscriberByEventList(
346
                'Yapeal.EveApi.Creator',
347
                ['Yapeal.EveApi.create' => ['createEveApi', 'last']]
348
            );
349
        }
350
        return $this;
351
    }
352
    /**
353
     * @var ContainerInterface $dic
354
     */
355
    protected $dic;
356
}
357