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

Creator::createSql()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 56
Code Lines 46

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 56
ccs 0
cts 54
cp 0
rs 7.7489
cc 7
eloc 46
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\Sql;
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
     * @param string            $platform
51
     */
52
    public function __construct(\Twig_Environment $twig, string $dir = __DIR__, $platform = 'MySql')
53
    {
54
        $this->setRelativeBaseDir($dir);
55
        $this->setPlatform($platform);
56
        $this->setTwig($twig);
57
        $this->twigExtension = strtolower($platform) . '.sql.twig';
58
    }
59
    /**
60
     * @param EveApiEventInterface $event
61
     * @param string               $eventName
62
     * @param MediatorInterface    $yem
63
     *
64
     * @return EveApiEventInterface
65
     * @throws \DomainException
66
     * @throws \InvalidArgumentException
67
     * @throws \LogicException
68
     */
69
    public function createSql(
70
        EveApiEventInterface $event,
71
        string $eventName,
72
        MediatorInterface $yem
73
    ): EveApiEventInterface
74
    {
75
        $this->setYem($yem);
76
        $data = $event->getData();
77
        $yem->triggerLogEvent('Yapeal.Log.log',
78
            Logger::DEBUG,
79
            $this->getReceivedEventMessage($data, $eventName, __CLASS__));
80
        // Only work with raw unaltered XML data.
81
        if (false !== strpos($data->getEveApiXml(), '<?yapeal.parameters.json')) {
82
            return $event->setHandledSufficiently();
83
        }
84
        $this->sectionName = $data->getEveApiSectionName();
85
        $this->apiName = $data->getEveApiName();
86
        $outputFile = sprintf('%1$s%2$s/Create%3$s.%4$s.sql',
87
            $this->getRelativeBaseDir(),
88
            ucfirst($this->sectionName),
89
            ucfirst($this->apiName),
90
            $this->getPlatform());
91
        // Nothing to do if NOT overwriting and file exists.
92
        if (false === $this->isOverwrite() && is_file($outputFile)) {
93
            return $event->setHandledSufficiently();
94
        }
95
        $sxi = new \SimpleXMLIterator($data->getEveApiXml());
96
        $this->tables = [];
97
        $this->processValueOnly($sxi, $this->apiName);
98
        $this->processRowset($sxi, $this->apiName);
99
        $tCount = count($this->tables);
100
        if (0 === $tCount) {
101
            $mess = 'No SQL tables to create for';
102
            $yem->triggerLogEvent('Yapeal.Log.log', Logger::NOTICE, $this->createEveApiMessage($mess, $data));
103
            return $event->setHandledSufficiently();
104
        }
105
        ksort($this->tables);
106
        list($mSec, $sec) = explode(' ', microtime());
107
        $context = [
108
            'className' => lcfirst($this->apiName),
109
            'tables' => $this->tables,
110
            'sectionName' => lcfirst($this->sectionName),
111
            'version' => gmdate('YmdHis', $sec) . substr($mSec, 1, 4)
112
        ];
113
        $contents = $this->getContentsFromTwig($eventName, $data, $context);
114
        if (false === $contents) {
115
            return $event;
116
        }
117
        if (false === $this->safeFileWrite($contents, $outputFile)) {
118
            $yem->triggerLogEvent($eventName,
119
                Logger::WARNING,
120
                $this->getFailedToWriteFileMessage($data, $eventName, $outputFile));
121
            return $event;
122
        }
123
        return $event->setHandledSufficiently();
124
    }
125
    /**
126
     * @param string $platform
127
     *
128
     * @return self Fluent interface.
129
     */
130
    public function setPlatform(string $platform)
131
    {
132
        $this->platform = $platform;
133
        return $this;
134
    }
135
    /**
136
     * @param \SimpleXMLIterator $sxi
137
     * @param string             $apiName
138
     * @param string             $xPath
139
     */
140
    protected function processRowset(\SimpleXMLIterator $sxi, string $apiName, string $xPath = '//result/rowset')
141
    {
142
        $items = $sxi->xpath($xPath);
143
        if (0 === count($items)) {
144
            return;
145
        }
146
        foreach ($items as $ele) {
147
            $rsName = ucfirst((string)$ele['name']);
148
            $colNames = explode(',', (string)$ele['columns']);
149
            $keyNames = explode(',', (string)$ele['key']);
150
            $columns = [];
151
            foreach ($keyNames as $keyName) {
152
                $columns[$keyName] = $this->inferTypeFromName($keyName);
153
            }
154
            foreach ($colNames as $colName) {
155
                $columns[$colName] = $this->inferTypeFromName($colName);
156
            }
157
            if ($this->hasOwner()) {
158
                $columns['ownerID'] = 'BIGINT(20) UNSIGNED NOT NULL';
159
            }
160
            uksort($columns,
161
                function ($alpha, $beta) {
162
                    return strtolower($alpha) <=> strtolower($beta);
163
                });
164
            if (0 === count($this->tables)) {
165
                $this->tables[$apiName] = ['columns' => $columns, 'keys' => $this->getSqlKeys($keyNames)];
166
            } else {
167
                $this->tables[$rsName] = ['columns' => $columns, 'keys' => $this->getSqlKeys($keyNames)];
168
            }
169
        }
170
    }
171
    /**
172
     * @param \SimpleXMLIterator $sxi
173
     * @param string             $tableName
174
     * @param string             $xpath
175
     */
176
    protected function processValueOnly(
177
        \SimpleXMLIterator $sxi,
178
        string $tableName,
179
        string $xpath = '//result/child::*[not(*|@*|self::dataTime)]'
180
    ) {
181
        $items = $sxi->xpath($xpath);
182
        if (0 === count($items)) {
183
            return;
184
        }
185
        $columns = [];
186
        foreach ($items as $ele) {
187
            $name = (string)$ele->getName();
188
            $columns[$name] = $this->inferTypeFromName($name, true);
189
        }
190
        if ($this->hasOwner()) {
191
            $columns['ownerID'] = 'BIGINT(20) UNSIGNED NOT NULL';
192
        }
193
        uksort($columns,
194
            function ($alpha, $beta) {
195
                return strtolower($alpha) <=> strtolower($beta);
196
            });
197
        $keys = $this->getSqlKeys();
198
        if (0 !== count($keys)) {
199
            $this->tables[$tableName] = ['columns' => $columns, 'keys' => $keys];
200
        } else {
201
            $this->tables[$tableName] = ['columns' => $columns];
202
        }
203
    }
204
    /**
205
     * @var string $twigExtension
206
     */
207
    protected $twigExtension = 'sql.twig';
208
    /**
209
     * @return string
210
     */
211
    private function getPlatform(): string
212
    {
213
        return $this->platform;
214
    }
215
    /**
216
     * @param string[] $keyNames
217
     *
218
     * @return string[]
219
     */
220
    private function getSqlKeys(array $keyNames = []): array
221
    {
222
        if ($this->hasOwner()) {
223
            array_unshift($keyNames, 'ownerID');
224
        }
225
        return array_unique($keyNames);
226
    }
227
    /**
228
     * Used to determine if API is in section that has an owner.
229
     *
230
     * @return bool
231
     */
232
    private function hasOwner(): bool
233
    {
234
        return in_array(strtolower($this->sectionName), ['account', 'char', 'corp'], true);
235
    }
236
    /**
237
     * Used to infer(choose) type from element or attribute's name.
238
     *
239
     * @param string $name     Name of the element or attribute.
240
     * @param bool   $forValue Determines if returned type is going to be used for element or an attribute.
241
     *
242
     * @return string Returns the inferred type from the name.
243
     */
244
    private function inferTypeFromName(string $name, bool $forValue = false): string
245
    {
246
        if ('ID' === substr($name, -2)) {
247
            return 'BIGINT(20) UNSIGNED NOT NULL';
248
        }
249
        $name = strtolower($name);
250
        foreach ([
251
                     'descr' => 'TEXT NOT NULL',
252
                     'name' => 'CHAR(100) NOT NULL',
253
                     'balance' => 'DECIMAL(17, 2) NOT NULL',
254
                     'isk' => 'DECIMAL(17, 2) NOT NULL',
255
                     'tax' => 'DECIMAL(17, 2) NOT NULL',
256
                     'timeefficiency' => 'TINYINT(3) UNSIGNED NOT NULL',
257
                     'date' => 'DATETIME NOT NULL DEFAULT \'1970-01-01 00:00:01\'',
258
                     'time' => 'DATETIME NOT NULL DEFAULT \'1970-01-01 00:00:01\'',
259
                     'until' => 'DATETIME NOT NULL DEFAULT \'1970-01-01 00:00:01\'',
260
                     'errorcode' => 'SMALLINT(4) UNSIGNED NOT NULL',
261
                     'level' => 'SMALLINT(4) UNSIGNED NOT NULL',
262
                     'logoncount' => 'BIGINT(20) UNSIGNED NOT NULL',
263
                     'logonminutes' => 'BIGINT(20) UNSIGNED NOT NULL',
264
                     'trainingend' => 'DATETIME NOT NULL DEFAULT \'1970-01-01 00:00:01\'',
265
                     'skillintraining' => 'BIGINT(20) UNSIGNED NOT NULL',
266
                     'trainingdestinationsp' => 'BIGINT(20) UNSIGNED NOT NULL',
267
                     'trainingstartsp' => 'BIGINT(20) UNSIGNED NOT NULL'
268
                 ] as $search => $replace) {
269
            if (false !== strpos($name, $search)) {
270
                return $replace;
271
            }
272
        }
273
        return $forValue ? 'TEXT NOT NULL' : 'VARCHAR(255) DEFAULT \'\'';
274
    }
275
    /**
276
     * @var string $apiName
277
     */
278
    private $apiName;
279
    /**
280
     * @var string $platform Sql connection platform being used.
281
     */
282
    private $platform;
283
    /**
284
     * @var string $sectionName
285
     */
286
    private $sectionName;
287
    /**
288
     * @var array $tables
289
     */
290
    private $tables;
291
}
292