Completed
Push — master ( 598fe1...4a905b )
by Michael
03:41
created

Creator::createXsd()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 54
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 54
ccs 0
cts 52
cp 0
rs 7.8331
cc 7
eloc 44
nc 6
nop 3
crap 56

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains Creator 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 which can be used to access the Eve Online
10
 * API data and place it into a database.
11
 * Copyright (C) 2015-2016 Michael Cummings
12
 *
13
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
14
 * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
15
 * any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
18
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public License along with this program. If not, see
22
 * <http://spdx.org/licenses/LGPL-3.0.html>.
23
 *
24
 * You should be able to find a copy of this license in the LICENSE.md file. A copy of the GNU GPL should also be
25
 * available in the GNU-GPL.md file.
26
 *
27
 * @copyright 2015-2016 Michael Cummings
28
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
29
 * @author    Michael Cummings <[email protected]>
30
 */
31
namespace Yapeal\Xsd;
32
33
use Yapeal\Console\Command\EveApiCreatorTrait;
34
use Yapeal\Event\EveApiEventInterface;
35
use Yapeal\Event\MediatorInterface;
36
use Yapeal\FileSystem\RelativeFileSearchTrait;
37
use Yapeal\Log\Logger;
38
39
/**
40
 * Class Creator
41
 */
42
class Creator
43
{
44
    use EveApiCreatorTrait, RelativeFileSearchTrait;
45
    /**
46
     * Creator constructor.
47
     *
48
     * @param \Twig_Environment $twig
49
     * @param string            $dir
50
     */
51
    public function __construct(\Twig_Environment $twig, string $dir = __DIR__)
52
    {
53
        $this->setRelativeBaseDir($dir);
54
        $this->setTwig($twig);
55
    }
56
    /**
57
     * @param EveApiEventInterface $event
58
     * @param string               $eventName
59
     * @param MediatorInterface    $yem
60
     *
61
     * @return EveApiEventInterface
62
     * @throws \DomainException
63
     * @throws \InvalidArgumentException
64
     * @throws \LogicException
65
     */
66
    public function createXsd(
67
        EveApiEventInterface $event,
68
        string $eventName,
69
        MediatorInterface $yem
70
    ): EveApiEventInterface
71
    {
72
        $this->setYem($yem);
73
        $data = $event->getData();
74
        $yem->triggerLogEvent('Yapeal.Log.log',
75
            Logger::DEBUG,
76
            $this->getReceivedEventMessage($data, $eventName, __CLASS__));
77
        // Only work with raw unaltered XML data.
78
        if (false !== strpos($data->getEveApiXml(), '<?yapeal.parameters.json')) {
79
            return $event->setHandledSufficiently();
80
        }
81
        $this->sectionName = $data->getEveApiSectionName();
82
        $this->apiName = $data->getEveApiName();
83
        $outputFile = sprintf('%1$s%2$s/%3$s.xsd',
84
            $this->getRelativeBaseDir(),
85
            ucfirst($this->sectionName),
86
            ucfirst($this->apiName));
87
        // Nothing to do if NOT overwriting and file exists.
88
        if (false === $this->isOverwrite() && is_file($outputFile)) {
89
            return $event;
90
        }
91
        $xml = $data->getEveApiXml();
92
        if (false === $xml) {
93
            return $event->setHandledSufficiently();
94
        }
95
        $sxi = new \SimpleXMLIterator($xml);
96
        $this->tables = [];
97
        $this->processValueOnly($sxi, lcfirst($this->apiName));
98
        $this->processRowset($sxi);
99
        list($mSec, $sec) = explode(' ', microtime());
100
        $context = [
101
            'className' => lcfirst($this->apiName),
102
            'tables' => $this->tables,
103
            'sectionName' => lcfirst($this->sectionName),
104
            'version' => gmdate('YmdHis', $sec) . sprintf('.%0-3s', floor($mSec * 1000))
105
        ];
106
        $contents = $this->getContentsFromTwig($eventName, $data, $context);
107
        if (false === $contents) {
108
            return $event;
109
        }
110
        $contents = $this->getTidy()
111
            ->repairString($contents);
112
        if (false === $this->safeFileWrite($contents, $outputFile)) {
113
            $yem->triggerLogEvent($eventName,
114
                Logger::WARNING,
115
                $this->getFailedToWriteFileMessage($data, $eventName, $outputFile));
116
            return $event;
117
        }
118
        return $event->setHandledSufficiently();
119
    }
120
    /**
121
     * @param \SimpleXMLIterator $sxi
122
     * @param string             $xpath
123
     */
124
    protected function processRowset(\SimpleXMLIterator $sxi, string $xpath = '//result/rowset')
125
    {
126
        $items = $sxi->xpath($xpath);
127
        if (0 === count($items)) {
128
            return;
129
        }
130
        $tables = [];
131
        foreach ($items as $ele) {
132
            $tableName = (string)$ele['name'];
133
            /**
134
             * @var string[] $colNames
135
             */
136
            $colNames = explode(',', (string)$ele['columns']);
137
            /**
138
             * @var string[] $keyNames
139
             */
140
            $keyNames = explode(',', (string)$ele['key']);
141
            $columns = [];
142
            foreach ($keyNames as $keyName) {
143
                $columns[$keyName] = $this->inferTypeFromName($keyName);
144
            }
145
            foreach ($colNames as $colName) {
146
                $columns[$colName] = $this->inferTypeFromName($colName);
147
            }
148
            uksort($columns,
149
                function ($alpha, $beta) {
150
                    return strtolower($alpha) <=> strtolower($beta);
151
                });
152
            $tables[$tableName] = ['attributes' => $columns];
153
        }
154
        uksort($tables,
155
            function ($alpha, $beta) {
156
                return strtolower($alpha) <=> strtolower($beta);
157
            });
158
        $this->tables = array_merge($this->tables, $tables);
159
    }
160
    /**
161
     * @param \SimpleXMLIterator $sxi
162
     *
163
     * @param string             $tableName
164
     * @param string             $xpath
165
     */
166
    protected function processValueOnly(
167
        \SimpleXMLIterator $sxi,
168
        string $tableName,
169
        string $xpath = '//result/child::*[not(*|@*|self::dataTime)]'
170
    ) {
171
        $items = $sxi->xpath($xpath);
172
        if (0 === count($items)) {
173
            return;
174
        }
175
        $columns = [];
176
        /**
177
         * @var \SimpleXMLElement $ele
178
         */
179
        foreach ($items as $ele) {
180
            $name = (string)$ele->getName();
181
            $columns[$name] = $this->inferTypeFromName($name, true);
182
        }
183
        uksort($columns,
184
            function ($alpha, $beta) {
185
                return strtolower($alpha) <=> strtolower($beta);
186
            });
187
        $this->tables[$tableName] = ['values' => $columns];
188
    }
189
    /**
190
     * @var string $twigExtension
191
     */
192
    protected $twigExtension = 'xsd.twig';
193
    /**
194
     * @return \tidy
195
     */
196
    private function getTidy(): \tidy
197
    {
198
        if (null === $this->tidy) {
199
            $tidyConfig = [
200
                'indent' => true,
201
                'indent-spaces' => 4,
202
                'input-xml' => true,
203
                'newline' => 'LF',
204
                'output-xml' => true,
205
                'wrap' => '120'
206
            ];
207
            $this->tidy = new \tidy(null, $tidyConfig, 'utf8');
208
        }
209
        return $this->tidy;
210
    }
211
    /**
212
     * Used to infer(choose) type from element or attribute's name.
213
     *
214
     * @param string $name     Name of the element or attribute.
215
     * @param bool   $forValue Determines if returned type is going to be used for element or an attribute.
216
     *
217
     * @return string Returns the inferred type from the name.
218
     */
219
    private function inferTypeFromName(string $name, bool $forValue = false): string
220
    {
221
        if ('ID' === substr($name, -2)) {
222
            return 'eveIDType';
223
        }
224
        $name = strtolower($name);
225
        foreach ([
226
                     'descr' => 'xs:string',
227
                     'name' => 'eveNameType',
228
                     'balance' => 'eveISKType',
229
                     'isk' => 'eveISKType',
230
                     'tax' => 'eveISKType',
231
                     'timeefficiency' => 'xs:unsignedByte',
232
                     'date' => 'eveNEDTType',
233
                     'time' => 'eveNEDTType',
234
                     'until' => 'eveNEDTType',
235
                     'errorcode' => 'xs:unsignedShort',
236
                     'level' => 'xs:unsignedShort'
237
                 ] as $search => $replace) {
238
            if (false !== strpos($name, $search)) {
239
                return $replace;
240
            }
241
        }
242
        return $forValue ? 'xs:string' : 'xs:token';
243
    }
244
    /**
245
     * @var string $apiName
246
     */
247
    private $apiName;
248
    /**
249
     * @var string $sectionName
250
     */
251
    private $sectionName;
252
    /**
253
     * @var array $tables
254
     */
255
    private $tables;
256
    /**
257
     * @var \tidy $tidy
258
     */
259
    private $tidy;
260
}
261