Completed
Push — master ( 2cff5f...81de03 )
by Michael
03:19
created

CacheRetriever::setRetrieve()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
/**
3
 * Contains CacheRetriever 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\FileSystem;
35
36
use FilePathNormalizer\FilePathNormalizerTrait;
37
use InvalidArgumentException;
38
use LogicException;
39
use SimpleXMLElement;
40
use Yapeal\Event\EveApiEventEmitterTrait;
41
use Yapeal\Event\EveApiEventInterface;
42
use Yapeal\Event\MediatorInterface;
43
use Yapeal\Log\Logger;
44
use Yapeal\Xml\EveApiRetrieverInterface;
45
46
/**
47
 * Class CacheRetriever
48
 */
49
class CacheRetriever implements EveApiRetrieverInterface
50
{
51
    use CommonFileHandlingTrait, EveApiEventEmitterTrait, FilePathNormalizerTrait;
52
    /**
53
     * @param string|null $cachePath
54
     *
55
     * @throws InvalidArgumentException
56
     */
57
    public function __construct($cachePath = null)
58
    {
59
        $this->setCachePath($cachePath);
60
    }
61
    /**
62
     * @return boolean
63
     */
64
    public function shouldRetrieve()
65
    {
66
        return $this->retrieve;
67
    }
68
    /**
69
     * @param EveApiEventInterface $event
70
     * @param string               $eventName
71
     * @param MediatorInterface    $yem
72
     *
73
     * @return EveApiEventInterface
74
     * @throws LogicException
75
     */
76
    public function retrieveEveApi(EveApiEventInterface $event, $eventName, MediatorInterface $yem)
77
    {
78
        if (!$this->shouldRetrieve()) {
79
            return $event;
80
        }
81
        $this->setYem($yem);
82
        $data = $event->getData();
83
        $yem->triggerLogEvent(
84
            'Yapeal.Log.log',
85
            Logger::DEBUG,
86
            $this->getReceivedEventMessage($data, $eventName, __CLASS__)
87
        );
88
        // BaseSection/ApiHash.xml
89
        $cacheFile = sprintf(
90
            '%1$s%2$s/%3$s%4$s.xml',
91
            $this->getCachePath(),
92
            ucfirst($data->getEveApiSectionName()),
93
            ucfirst($data->getEveApiName()),
94
            $data->getHash()
95
        );
96
        $result = $this->safeFileRead($cacheFile, $yem);
97
        if (false === $result) {
98
            return $event;
99
        }
100
        if ($this->isExpired($result)) {
101
            $this->deleteWithRetry($cacheFile, $yem);
102
            return $event;
103
        }
104
        $mess = sprintf('Found usable cache file %1$s', $cacheFile);
105
        $yem->triggerLogEvent('Yapeal.Log.log', Logger::DEBUG, $this->createEventMessage($mess, $data, $eventName));
106
        return $event->setData($data->setEveApiXml($result))
107
            ->eventHandled();
108
    }
109
    /**
110
     * @param string|null $value
111
     *
112
     * @return self
113
     * @throws \InvalidArgumentException
114
     */
115
    public function setCachePath($value = null)
116
    {
117
        if ($value === null) {
118
            $value = dirname(dirname(__DIR__)) . '/cache/';
119
        }
120
        if (!is_string($value)) {
121
            $mess = 'Cache path MUST be string, but given ' . gettype($value);
122
            throw new InvalidArgumentException($mess);
123
        }
124
        $this->cachePath = $this->getFpn()
125
            ->normalizePath($value);
126
        return $this;
127
    }
128
    /**
129
     * @param boolean $value
130
     *
131
     * @return $this Fluent interface
132
     */
133
    public function setRetrieve($value)
134
    {
135
        $this->retrieve = (boolean)$value;
136
        return $this;
137
    }
138
    /**
139
     * @return string
140
     * @throws LogicException
141
     */
142
    protected function getCachePath()
143
    {
144
        if ('' === $this->cachePath) {
145
            $mess = 'Tried to access $cachePath before it was set';
146
            throw new LogicException($mess);
147
        }
148
        return $this->getFpn()
149
            ->normalizePath($this->cachePath);
150
    }
151
    /**
152
     * @param string $xml
153
     *
154
     * @return bool
155
     * @throws \DomainException
156
     * @throws \LogicException
157
     * @throws \InvalidArgumentException
158
     */
159
    protected function isExpired($xml)
160
    {
161
        $simple = new SimpleXMLElement($xml);
162
        /** @noinspection PhpUndefinedFieldInspection */
163
        if (null === $simple->currentTime[0]) {
164
            $mess = 'Xml file missing required currentTime element';
165
            $this->getYem()
166
                ->triggerLogEvent('Yapeal.Log.log', Logger::NOTICE, $mess);
167
            return true;
168
        }
169
        /** @noinspection PhpUndefinedFieldInspection */
170
        if (null === $simple->cachedUntil[0]) {
171
            $mess = 'Xml file missing required cachedUntil element';
172
            $this->getYem()
173
                ->triggerLogEvent('Yapeal.Log.log', Logger::NOTICE, $mess);
174
            return true;
175
        }
176
        $now = time();
177
        /** @noinspection PhpUndefinedFieldInspection */
178
        $current = strtotime($simple->currentTime[0] . '+00:00');
179
        /** @noinspection PhpUndefinedFieldInspection */
180
        $until = strtotime($simple->cachedUntil[0] . '+00:00');
181
        // At minimum use cached XML for 5 minutes (300 secs).
182
        if (($now - $current) <= 300) {
183
            return false;
184
        }
185
        // Catch and log APIs with bad CachedUntil times so CCP can be told and get them fixed.
186
        if ($until <= $current) {
187
            $mess = sprintf('CachedUntil is invalid was given %1$s and currentTime is %2$s', $until, $current);
188
            $this->getYem()
189
                ->triggerLogEvent('Yapeal.Log.log', Logger::WARNING, $mess);
190
            return true;
191
        }
192
        // Now plus a day.
193
        if ($until > ($now + 86400)) {
194
            $mess = sprintf('CachedUntil is excessively long was given %1$s and currentTime is %2$s', $until, $current);
195
            $this->getYem()
196
                ->triggerLogEvent('Yapeal.Log.log', Logger::NOTICE, $mess);
197
            return true;
198
        }
199
        return ($until <= $now);
200
    }
201
    /**
202
     * @var string $cachePath
203
     */
204
    protected $cachePath;
205
    /**
206
     * @var bool $retrieve
207
     */
208
    private $retrieve = false;
209
}
210