Completed
Pull Request — develop (#273)
by Samuel
23:34 queued 09:33
created

HttpLoader   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 56.34%

Importance

Changes 6
Bugs 1 Features 1
Metric Value
wmc 18
lcom 2
cbo 9
dl 0
loc 211
ccs 40
cts 71
cp 0.5634
rs 10
c 6
b 1
f 1

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setDispersalStrategy() 0 4 1
A setCache() 0 6 1
A setCurlOptions() 0 4 1
A setOptions() 0 9 2
A supports() 0 6 1
A applyCurlOptions() 0 8 2
B load() 0 33 6
A fetchFile() 0 20 3
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 Symfony\Component\HttpFoundation\Response;
14
use Symfony\Component\HttpKernel\Exception\HttpException;
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 DispersalStrategyInterface
39
     */
40
    private $strategy;
41
42
    /**
43
     * doctrine cache
44
     *
45
     * @var CacheProvider
46
     */
47
    private $cache;
48
49
    /**
50
     * doctrine cache lifetime
51
     *
52
     * @var int
53
     */
54
    private $cacheLifetime;
55
56
    /**
57
     * @var array curl options to apply on each request
58
     */
59
    private $curlOptions = [];
60
61
    /**
62
     * @var array
63
     */
64
    private $options = [
65
        'storeKey' => 'httpLoader',
66
    ];
67
68
    /**
69
     * constructor
70
     *
71
     * @param ValidatorInterface $validator validator
72
     * @param Client             $client    http client
73
     */
74 3
    public function __construct(ValidatorInterface $validator, Client $client)
75
    {
76 3
        $this->validator = $validator;
77 3
        $this->client = $client;
78 3
    }
79
80
    /**
81
     * @inheritDoc
82
     *
83
     * @param DispersalStrategyInterface $strategy dispersal strategy
84
     *
85
     * @return void
86
     */
87 2
    public function setDispersalStrategy($strategy)
88
    {
89 2
        $this->strategy = $strategy;
90 2
    }
91
92
    /**
93
     * @inheritDoc
94
     *
95
     * @param CacheProvider $cache          doctrine cache provider
96
     * @param string        $cacheNamespace cache namespace
97
     * @param int           $cacheLifetime  cache lifetime
98
     *
99
     * @return void
100
     */
101
    public function setCache(CacheProvider $cache, $cacheNamespace, $cacheLifetime)
102
    {
103
        $this->cache = $cache;
104
        $this->cache->setNamespace($cacheNamespace);
105
        $this->cacheLifetime = $cacheLifetime;
106
    }
107
108
    /**
109
     * set curl options
110
     *
111
     * @param array $curlOptions the curl options
112
     *
113
     * @return void
114
     */
115
    public function setCurlOptions(array $curlOptions)
116
    {
117
        $this->curlOptions = $curlOptions;
118
    }
119
120
    /**
121
     * @inheritDoc
122
     *
123
     * @param array $options cache strategy
124
     *
125
     * @return void
126
     */
127
    public function setOptions($options)
128
    {
129
        if (!empty($options['prefix'])) {
130
            $options['storeKey'] = $options['prefix'];
131
            unset($options['prefix']);
132
        }
133
134
        $this->options = array_merge($this->options, $options);
135
    }
136
137
    /**
138
     * check if the url is valid
139
     *
140
     * @param string $url url
141
     *
142
     * @return boolean
143
     */
144 1
    public function supports($url)
145
    {
146 1
        $error = $this->validator->validate($url, [new Url()]);
147
148 1
        return 0 === count($error);
149
    }
150
151
    /**
152
     * Applies the specified curl option on a request
153
     *
154
     * @param RequestInterface $request request
155
     *
156
     * @return void
157
     */
158 2
    protected function applyCurlOptions($request)
159
    {
160 2
        $curl = $request->getCurlOptions();
161 2
        foreach ($this->curlOptions as $option => $value) {
162
            $option = 'CURLOPT_' . strtoupper($option);
163
            $curl->set(constant($option), $value);
164 2
        }
165 2
    }
166
167
    /**
168
     * @inheritDoc
169
     *
170
     * @param string $input url
171
     *
172
     * @return ApiDefinition
173
     */
174 2
    public function load($input)
175
    {
176 2
        $retVal = null;
177 2
        if (isset($this->strategy)) {
178 2
            $request = $this->client->get($input);
179 2
            $this->applyCurlOptions($request);
180 2
            if (isset($this->cache) && $this->cache->contains($this->options['storeKey'])) {
181
                $content = $this->cache->fetch($this->options['storeKey']);
182
183
                if (empty($content)) {
184
                    $content = $this->fetchFile($request);
185
                }
186
            } else {
187 2
                $content = $this->fetchFile($request);
188
            }
189
190
            // store current host (name or ip) serving the API. This MUST be the host only and does not include the
191
            // scheme nor sub-paths. It MAY include a port. If the host is not included, the host serving the
192
            // documentation is to be used (including the port)
193 2
            $fallbackHost = array();
194 2
            $fallbackHost['host'] = sprintf(
195 2
                '%s://%s:%d',
196 2
                $request->getScheme(),
197 2
                $request->getHost(),
198 2
                $request->getPort()
199 2
            );
200 2
            if ($this->strategy->supports($content)) {
201 1
                $retVal = $this->strategy->process($content, $fallbackHost);
202 1
            }
203 2
        }
204
205 2
        return $retVal;
206
    }
207
208
    /**
209
     * fetch file from remote destination
210
     *
211
     * @param RequestInterface $request request
212
     *
213
     * @return string
214
     */
215 2
    private function fetchFile($request)
216
    {
217
        try {
218 2
            $response = $request->send();
219 2
        } catch (\Guzzle\Http\Exception\CurlException $e) {
220
            throw new HttpException(
221
                Response::HTTP_BAD_GATEWAY,
222
                $e->getError(),
223
                $e,
224
                $e->getRequest()->getHeaders()->toArray(),
225
                $e->getCode()
226
            );
227
        }
228 2
        $content = $response->getBody(true);
229 2
        if (isset($this->cache)) {
230
            $this->cache->save($this->options['storeKey'], $content, $this->cacheLifetime);
231
        }
232
233 2
        return $content;
234
    }
235
}
236