Completed
Branch feature/moar-test-optimizing (8cffd1)
by Lucas
19:31 queued 13:44
created

HttpLoader::load()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 6.0026
Metric Value
dl 0
loc 33
ccs 23
cts 24
cp 0.9583
rs 8.439
cc 6
eloc 20
nc 7
nop 1
crap 6.0026
1
<?php
2
/**
3
 * HttpLoader
4
 */
5
6
namespace Graviton\ProxyBundle\Definition\Loader;
7
8
use Graviton\ProxyBundle\Definition\ApiDefinition;
9
use Graviton\ProxyBundle\Definition\Loader\DispersalStrategy\DispersalStrategyInterface;
10
use Doctrine\Common\Cache\CacheProvider;
11
use Guzzle\Http\Client;
12
use Guzzle\Http\Message\RequestInterface;
13
use Psr\Log\LoggerInterface;
14
use Symfony\Component\HttpFoundation\Response;
15
use Symfony\Component\Validator\Constraints\Url;
16
use Symfony\Component\Validator\Validator\ValidatorInterface;
17
18
/**
19
 * load a file over http and process the data
20
 *
21
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
22
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
23
 * @link     http://swisscom.ch
24
 */
25
class HttpLoader implements LoaderInterface
26
{
27
    /**
28
     * @var ValidatorInterface
29
     */
30
    private $validator;
31
32
    /**
33
     * @var Client
34
     */
35
    private $client;
36
37
    /**
38
     * @var LoggerInterface
39
     */
40
    private $logger;
41
42
    /**
43
     * @var DispersalStrategyInterface
44
     */
45
    private $strategy;
46
47
    /**
48
     * doctrine cache
49
     *
50
     * @var CacheProvider
51
     */
52
    private $cache;
53
54
    /**
55
     * doctrine cache lifetime
56
     *
57
     * @var int
58
     */
59
    private $cacheLifetime;
60
61
    /**
62
     * @var array curl options to apply on each request
63
     */
64
    private $curlOptions = [];
65
66
    /**
67
     * @var array
68
     */
69
    private $options = [
70
        'storeKey' => 'httpLoader',
71
    ];
72
73
    /**
74
     * constructor
75
     *
76
     * @param ValidatorInterface $validator validator
77
     * @param Client             $client    http client
78
     * @param LoggerInterface    $logger    Logger
79
     */
80 8
    public function __construct(ValidatorInterface $validator, Client $client, LoggerInterface $logger)
81
    {
82 8
        $this->validator = $validator;
83 8
        $this->client = $client;
84 8
        $this->logger = $logger;
85 8
    }
86
87
    /**
88
     * @inheritDoc
89
     *
90
     * @param DispersalStrategyInterface $strategy dispersal strategy
91
     *
92
     * @return void
93
     */
94 6
    public function setDispersalStrategy($strategy)
95
    {
96 6
        $this->strategy = $strategy;
97 6
    }
98
99
    /**
100
     * @inheritDoc
101
     *
102
     * @param CacheProvider $cache          doctrine cache provider
103
     * @param string        $cacheNamespace cache namespace
104
     * @param int           $cacheLifetime  cache lifetime
105
     *
106
     * @return void
107
     */
108 2
    public function setCache(CacheProvider $cache, $cacheNamespace, $cacheLifetime)
109
    {
110 2
        $this->cache = $cache;
111 2
        $this->cache->setNamespace($cacheNamespace);
112 2
        $this->cacheLifetime = $cacheLifetime;
113 2
    }
114
115
    /**
116
     * set curl options
117
     *
118
     * @param array $curlOptions the curl options
119
     *
120
     * @return void
121
     */
122
    public function setCurlOptions(array $curlOptions)
123
    {
124
        $this->curlOptions = $curlOptions;
125
    }
126
127
    /**
128
     * @inheritDoc
129
     *
130
     * @param array $options cache strategy
131
     *
132
     * @return void
133
     */
134 2
    public function setOptions($options)
135
    {
136 2
        if (!empty($options['prefix'])) {
137 2
            $options['storeKey'] = $options['prefix'];
138 2
            unset($options['prefix']);
139 1
        }
140
141 2
        $this->options = array_merge($this->options, $options);
142 2
    }
143
144
    /**
145
     * check if the url is valid
146
     *
147
     * @param string $url url
148
     *
149
     * @return boolean
150
     */
151 2
    public function supports($url)
152
    {
153 2
        $error = $this->validator->validate($url, [new Url()]);
154
155 2
        return 0 === count($error);
156
    }
157
158
    /**
159
     * Applies the specified curl option on a request
160
     *
161
     * @param RequestInterface $request request
162
     *
163
     * @return void
164
     */
165 6
    protected function applyCurlOptions($request)
166
    {
167 6
        $curl = $request->getCurlOptions();
168 6
        foreach ($this->curlOptions as $option => $value) {
169
            $option = 'CURLOPT_'.strtoupper($option);
170
            $curl->set(constant($option), $value);
171 3
        }
172 6
        $curl->set(constant('CURLOPT_CAINFO'), __DIR__.'/../../Resources/cert/cacert.pem');
173 6
    }
174
175
    /**
176
     * @inheritDoc
177
     *
178
     * @param string $input url
179
     *
180
     * @return ApiDefinition
0 ignored issues
show
Documentation introduced by
Should the return type not be ApiDefinition|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
181
     */
182 6
    public function load($input)
183
    {
184 6
        $retVal = null;
185 6
        if (isset($this->strategy)) {
186 6
            $request = $this->client->get($input);
187 6
            $this->applyCurlOptions($request);
188 6
            if (isset($this->cache) && $this->cache->contains($this->options['storeKey'])) {
189 2
                $content = $this->cache->fetch($this->options['storeKey']);
190
191 2
                if (empty($content)) {
192 1
                    $content = $this->fetchFile($request);
193
                }
194 1
            } else {
195 4
                $content = $this->fetchFile($request);
196
            }
197
198
            // store current host (name or ip) serving the API. This MUST be the host only and does not include the
199
            // scheme nor sub-paths. It MAY include a port. If the host is not included, the host serving the
200
            // documentation is to be used (including the port)
201 6
            $fallbackHost = array();
202 6
            $fallbackHost['host'] = sprintf(
203 6
                '%s://%s:%d',
204 6
                $request->getScheme(),
205 6
                $request->getHost(),
206 6
                $request->getPort()
207 3
            );
208 6
            if ($this->strategy->supports($content)) {
209 4
                $retVal = $this->strategy->process($content, $fallbackHost);
210 2
            }
211 3
        }
212
213 6
        return $retVal;
214
    }
215
216
    /**
217
     * fetch file from remote destination
218
     *
219
     * @param RequestInterface $request request
220
     *
221
     * @return string
222
     */
223 4
    private function fetchFile($request)
224
    {
225 4
        $content = "{}";
226
        try {
227 4
            $response = $request->send();
228 4
            $content = $response->getBody(true);
229 4
            if (isset($this->cache)) {
230 2
                $this->cache->save($this->options['storeKey'], $content, $this->cacheLifetime);
231
            }
232 2
        } catch (\Guzzle\Http\Exception\RequestException $e) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
233
234
            $this->logger->info(
235
                "Unable to fetch File!",
236
                [
237
                    "message" => $e->getMessage(),
238
                    "url" => $request->getUrl(),
239
                    "code" => (!empty($request->getResponse())? $request->getResponse()->getStatusCode() : 500)
240
                ]
241
            );
242
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
243
        }
244
245 4
        return $content;
246
    }
247
}
248