Completed
Push — master ( f1fa2a...b378f9 )
by Michael
02:57
created

CommonEveApiTrait::startEveApi()   C

Complexity

Conditions 12
Paths 114

Size

Total Lines 55
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 3
Bugs 0 Features 1
Metric Value
dl 0
loc 55
ccs 0
cts 48
cp 0
rs 6.2882
c 3
b 0
f 1
cc 12
eloc 36
nc 114
nop 3
crap 156

How to fix   Long Method    Complexity   

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 CommonEveApiTrait trait.
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) 2015-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
 * @copyright 2015-2016 Michael Cummings
32
 * @license   http://www.gnu.org/copyleft/lesser.html GNU LGPL
33
 * @author    Michael Cummings <[email protected]>
34
 */
35
namespace Yapeal\EveApi;
36
37
use Monolog\Logger;
38
use Yapeal\CommonToolsTrait;
39
use Yapeal\Event\EveApiEventEmitterTrait;
40
use Yapeal\Event\EveApiEventInterface;
41
use Yapeal\Event\MediatorInterface;
42
use Yapeal\Xml\EveApiReadWriteInterface;
43
44
/**
45
 * Trait CommonEveApiTrait
46
 */
47
trait CommonEveApiTrait
48
{
49
    use CommonToolsTrait, EveApiEventEmitterTrait;
50
    /**
51
     * @param EveApiReadWriteInterface $data
52
     *
53
     * @return bool
54
     * @throws \DomainException
55
     * @throws \InvalidArgumentException
56
     * @throws \LogicException
57
     * @throws \Yapeal\Exception\YapealDatabaseException
58
     */
59
    public function oneShot(EveApiReadWriteInterface $data): bool
60
    {
61
        if (!$this->gotApiLock($data)) {
62
            return false;
63
        }
64
        $result = $this->processEvents($data);
65
        if ($result) {
66
            $this->updateCachedUntil($data);
67
            $this->emitEvents($data, 'end');
68
        }
69
        $this->releaseApiLock($data);
70
        return $result;
71
    }
72
    /**
73
     * @param EveApiEventInterface $event
74
     * @param string               $eventName
75
     * @param MediatorInterface    $yem
76
     *
77
     * @return EveApiEventInterface
78
     * @throws \DomainException
79
     * @throws \InvalidArgumentException
80
     * @throws \LogicException
81
     * @throws \Yapeal\Exception\YapealDatabaseException
82
     */
83
    public function startEveApi(EveApiEventInterface $event, string $eventName, MediatorInterface $yem)
84
    {
85
        if (!$this->hasYem()) {
86
            $this->setYem($yem);
87
        }
88
        $data = $event->getData();
89
        $yem->triggerLogEvent('Yapeal.Log.log',
90
            Logger::DEBUG,
91
            $this->getReceivedEventMessage($data, $eventName, __CLASS__));
92
        // If method doesn't exist still needs array with member for count but return '0' from extractOwnerID().
93
        if (method_exists($this, 'getActive')) {
94
            $active = $this->getActive($data);
1 ignored issue
show
Bug introduced by
It seems like getActive() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
95
            if (0 === count($active)) {
96
                $mess = 'No active owners found for';
97
                $yem->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $this->createEveApiMessage($mess, $data));
98
                $this->emitEvents($data, 'end');
99
                return $event->setHandledSufficiently();
100
            }
101
        }
102
        $active = method_exists($this, 'getActive') ? $this->getActive($data) : [false];
103
        if (0 === count($active)) {
104
            $mess = 'No active owners found for';
105
            $yem->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $this->createEveApiMessage($mess, $data));
106
            $this->emitEvents($data, 'end');
107
            return $event->setHandledSufficiently();
108
        }
109
        $untilInterval = $data->getCacheInterval();
110
        foreach ($active as $arguments) {
111
            if (false !== $arguments) {
112
                $data->setEveApiArguments($arguments);
113
            }
114
            // Reset interval, and clear xml data.
115
            /** @noinspection DisconnectedForeachInstructionInspection */
116
            $data->setCacheInterval($untilInterval)
117
                ->setEveApiXml();
118
            /** @noinspection DisconnectedForeachInstructionInspection */
119
            foreach ($this->accountKeys as $accountKey) {
120
                $data->addEveApiArgument('accountKey', $accountKey);
121
                /** @noinspection DisconnectedForeachInstructionInspection */
122
                if ($this->cachedUntilIsNotExpired($data)) {
123
                    $event->setHandledSufficiently();
124
                    continue;
125
                }
126
                /** @noinspection DisconnectedForeachInstructionInspection */
127
                if (0 === strpos(strtolower($data->getEveApiName()), 'wallet')) {
128
                    $data->addEveApiArgument('rowCount', '2560');
129
                }
130
                /** @noinspection DisconnectedForeachInstructionInspection */
131
                if ($this->oneShot($data)) {
132
                    $event->setHandledSufficiently();
133
                }
134
            }
135
        }
136
        return $event;
137
    }
138
    /**
139
     * @param EveApiReadWriteInterface $data
140
     *
141
     * @return bool
142
     * @throws \DomainException
143
     * @throws \InvalidArgumentException
144
     * @throws \LogicException
145
     * @throws \Yapeal\Exception\YapealDatabaseException
146
     */
147
    protected function cachedUntilIsNotExpired(EveApiReadWriteInterface $data): bool
148
    {
149
        $columns = [
150
            'accountKey' => $data->hasEveApiArgument('accountKey') ? $data->getEveApiArgument('accountKey') : '0',
151
            'apiName' => $data->getEveApiName(),
152
            'ownerID' => $this->extractOwnerID($data->getEveApiArguments()),
153
            'sectionName' => $data->getEveApiSectionName()
154
        ];
155
        $sql = $this->getCsq()
156
            ->getUtilCachedUntilExpires($columns);
157
        $this->getYem()
158
            ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $sql);
159
        try {
160
            $expires = $this->getPdo()
161
                ->query($sql)
162
                ->fetchAll(\PDO::FETCH_ASSOC);
163
        } catch (\PDOException $exc) {
164
            $mess = 'Could NOT get cache expired for';
165
            $this->getYem()
166
                ->triggerLogEvent('Yapeal.Log.log',
167
                    Logger::WARNING,
168
                    $this->createEveApiMessage($mess, $data),
169
                    ['exception' => $exc]);
170
            return false;
171
        }
172
        if (0 === count($expires)) {
173
            $mess = 'No UtilCachedUntil record found for';
174
            $this->getYem()
175
                ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $this->createEveApiMessage($mess, $data));
176
            return false;
177
        }
178
        if (1 < count($expires)) {
179
            $mess = 'Multiple UtilCachedUntil records found for';
180
            $this->getYem()
181
                ->triggerLogEvent('Yapeal.Log.log', Logger::WARNING, $this->createEveApiMessage($mess, $data));
182
            return false;
183
        }
184
        if (strtotime($expires[0]['expires'] . '+00:00') < time()) {
185
            $mess = 'Expired UtilCachedUntil record found for';
186
            $this->getYem()
187
                ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $this->createEveApiMessage($mess, $data));
188
            return false;
189
        }
190
        return true;
191
    }
192
    /**
193
     * @param string[] $candidates
194
     *
195
     * @return string
196
     */
197
    protected function extractOwnerID(array $candidates): string
198
    {
199
        foreach (['corporationID', 'characterID', 'keyID'] as $item) {
200
            if (array_key_exists($item, $candidates)) {
201
                return (string)$candidates[$item];
202
            }
203
        }
204
        return '0';
205
    }
206
    /**
207
     * @return int
208
     */
209
    protected function getMask(): int
210
    {
211
        return $this->mask;
212
    }
213
    /**
214
     * @param EveApiReadWriteInterface $data
215
     *
216
     * @return bool
217
     * @throws \DomainException
218
     * @throws \InvalidArgumentException
219
     * @throws \LogicException
220
     * @throws \Yapeal\Exception\YapealDatabaseException
221
     */
222
    protected function gotApiLock(EveApiReadWriteInterface $data): bool
223
    {
224
        $sql = $this->getCsq()
225
            ->getApiLock(crc32($data->getHash()));
226
        $this->getYem()
227
            ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $sql);
228
        $context = [];
229
        $success = false;
230
        try {
231
            $success = (bool)$this->getPdo()
232
                ->query($sql)
233
                ->fetchColumn();
234
        } catch (\PDOException $exc) {
235
            $context = ['exception' => $exc];
236
        }
237
        $mess = $success ? 'Got lock for' : 'Could NOT get lock for';
238
        $this->getYem()
239
            ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $this->createEveApiMessage($mess, $data), $context);
240
        return $success;
241
    }
242
    /**
243
     * @param EveApiReadWriteInterface $data
244
     *
245
     * @return bool
246
     * @throws \DomainException
247
     * @throws \InvalidArgumentException
248
     * @throws \LogicException
249
     * @throws \Yapeal\Exception\YapealDatabaseException
250
     */
251
    protected function releaseApiLock(EveApiReadWriteInterface $data): bool
252
    {
253
        $sql = $this->getCsq()
254
            ->getApiLockRelease(crc32($data->getHash()));
255
        $this->getYem()
256
            ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $sql);
257
        $context = [];
258
        $success = false;
259
        try {
260
            $success = (bool)$this->getPdo()
261
                ->query($sql)
262
                ->fetchColumn();
263
        } catch (\PDOException $exc) {
264
            $context = ['exception' => $exc];
265
        }
266
        $mess = $success ? 'Released lock for' : 'Could NOT release lock for';
267
        $this->getYem()
268
            ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $this->createEveApiMessage($mess, $data), $context);
269
        return $success;
270
    }
271
    /**
272
     * @param EveApiReadWriteInterface $data
273
     *
274
     * @return self Fluent interface.
275
     * @throws \DomainException
276
     * @throws \InvalidArgumentException
277
     * @throws \LogicException
278
     * @throws \Yapeal\Exception\YapealDatabaseException
279
     */
280
    protected function updateCachedUntil(EveApiReadWriteInterface $data)
281
    {
282
        if (false === $data->getEveApiXml()) {
283
            return $this;
284
        }
285
        /** @noinspection PhpUndefinedFieldInspection */
286
        /** @noinspection UnnecessaryParenthesesInspection */
287
        $currentTime = (string)(new \SimpleXMLElement($data->getEveApiXml()))->currentTime[0];
288
        if ('' === $currentTime) {
289
            return $this;
290
        }
291
        $dateTime = gmdate('Y-m-d H:i:s', strtotime($currentTime . '+00:00') + $data->getCacheInterval());
292
        $row = [
293
            'accountKey' => $data->hasEveApiArgument('accountKey') ? $data->getEveApiArgument('accountKey') : '0',
294
            'apiName' => $data->getEveApiName(),
295
            'expires' => $dateTime,
296
            'ownerID' => $this->extractOwnerID($data->getEveApiArguments()),
297
            'sectionName' => $data->getEveApiSectionName()
298
        ];
299
        $sql = $this->getCsq()
300
            ->getUpsert('utilCachedUntil', array_keys($row), 1);
301
        $this->getYem()
302
            ->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $sql);
303
        $pdo = $this->getPdo();
304
        $pdo->beginTransaction();
305
        $context = [];
306
        $success = false;
307
        try {
308
            $pdo->prepare($sql)
309
                ->execute(array_values($row));
310
            $pdo->commit();
311
            $success = true;
312
        } catch (\PDOException $exc) {
313
            $pdo->rollBack();
314
            $context = ['exception' => $exc];
315
        }
316
        $mess = $success ? 'Updated cached until date/time of' : 'Could NOT update cached until date/time of';
317
        $this->getYem()
318
            ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $this->createEveApiMessage($mess, $data), $context);
319
        return $this;
320
    }
321
    /**
322
     * @var int[] $accountKey
323
     */
324
    protected $accountKeys = [0];
325
    /**
326
     * @var int $mask
327
     */
328
    protected $mask;
329
    /**
330
     * @param EveApiReadWriteInterface $data
331
     *
332
     * @return bool
333
     * @throws \DomainException
334
     * @throws \InvalidArgumentException
335
     * @throws \LogicException
336
     */
337
    private function processEvents(EveApiReadWriteInterface $data): bool
338
    {
339
        $eventSuffixes = ['retrieve', 'transform', 'validate', 'preserve'];
340
        foreach ($eventSuffixes as $eventSuffix) {
341
            if (false === $this->emitEvents($data, $eventSuffix)) {
342
                return false;
343
            }
344
            if (false === $data->getEveApiXml()) {
345
                if ($data->hasEveApiArgument('accountKey') && '10000' === $data->getEveApiArgument('accountKey')
346
                    && 'corp' === strtolower($data->getEveApiSectionName())
347
                ) {
348
                    $mess = 'No faction warfare account data in';
349
                    $this->getYem()
350
                        ->triggerLogEvent('Yapeal.Log.log', Logger::INFO, $this->createEveApiMessage($mess, $data));
351
                    return false;
352
                }
353
                $this->getYem()
354
                    ->triggerLogEvent('Yapeal.Log.log',
355
                        Logger::INFO,
356
                        $this->getEmptyXmlDataMessage($data, $eventSuffix));
357
                return false;
358
            }
359
        }
360
        return true;
361
    }
362
}
363