Completed
Push — master ( 31b5db...524ecf )
by Michael
03:26
created

CommonEveApiTrait::processEvents()   C

Complexity

Conditions 7
Paths 5

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

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