Completed
Pull Request — develop (#273)
by Samuel
19:01 queued 08:39
created

HttpLoader::supports()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4286
c 1
b 0
f 1
cc 1
eloc 3
nc 1
nop 1
crap 1
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 4
    public function __construct(ValidatorInterface $validator, Client $client)
75
    {
76 4
        $this->validator = $validator;
77 4
        $this->client = $client;
78 4
    }
79
80
    /**
81
     * @inheritDoc
82
     *
83
     * @param DispersalStrategyInterface $strategy dispersal strategy
84
     *
85
     * @return void
86
     */
87 3
    public function setDispersalStrategy($strategy)
88
    {
89 3
        $this->strategy = $strategy;
90 3
    }
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 1
    public function setCache(CacheProvider $cache, $cacheNamespace, $cacheLifetime)
102
    {
103 1
        $this->cache = $cache;
104 1
        $this->cache->setNamespace($cacheNamespace);
105 1
        $this->cacheLifetime = $cacheLifetime;
106 1
    }
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 1
    public function setOptions($options)
128
    {
129 1
        if (!empty($options['prefix'])) {
130 1
            $options['storeKey'] = $options['prefix'];
131 1
            unset($options['prefix']);
132 1
        }
133
134 1
        $this->options = array_merge($this->options, $options);
135 1
    }
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 3
    protected function applyCurlOptions($request)
159
    {
160 3
        $curl = $request->getCurlOptions();
161 3
        foreach ($this->curlOptions as $option => $value) {
162
            $option = 'CURLOPT_'.strtoupper($option);
163
            $curl->set(constant($option), $value);
164 3
        }
165 3
        $curl->set(constant('CURLOPT_CAINFO'), __DIR__.'/../../Resources/cert/cacert.pem');
166 3
    }
167
168
    /**
169
     * @inheritDoc
170
     *
171
     * @param string $input url
172
     *
173
     * @return ApiDefinition
174
     */
175 3
    public function load($input)
176
    {
177 3
        $retVal = null;
178 3
        if (isset($this->strategy)) {
179 3
            $request = $this->client->get($input);
180 3
            $this->applyCurlOptions($request);
181 3
            if (isset($this->cache) && $this->cache->contains($this->options['storeKey'])) {
182 1
                $content = $this->cache->fetch($this->options['storeKey']);
183
184 1
                if (empty($content)) {
185
                    $content = $this->fetchFile($request);
186
                }
187 1
            } else {
188 2
                $content = $this->fetchFile($request);
189
            }
190
191
            // store current host (name or ip) serving the API. This MUST be the host only and does not include the
192
            // scheme nor sub-paths. It MAY include a port. If the host is not included, the host serving the
193
            // documentation is to be used (including the port)
194 3
            $fallbackHost = array();
195 3
            $fallbackHost['host'] = sprintf(
196 3
                '%s://%s:%d',
197 3
                $request->getScheme(),
198 3
                $request->getHost(),
199 3
                $request->getPort()
200 3
            );
201 3
            if ($this->strategy->supports($content)) {
202 2
                $retVal = $this->strategy->process($content, $fallbackHost);
203 2
            }
204 3
        }
205
206 3
        return $retVal;
207
    }
208
209
    /**
210
     * fetch file from remote destination
211
     *
212
     * @param RequestInterface $request request
213
     *
214
     * @return string
215
     */
216 2
    private function fetchFile($request)
217
    {
218
        try {
219 2
            $response = $request->send();
220 2
        } catch (\Guzzle\Http\Exception\CurlException $e) {
221
            throw new HttpException(
222
                Response::HTTP_BAD_GATEWAY,
223
                $e->getError(),
224
                $e,
225
                $e->getRequest()->getHeaders()->toArray(),
226
                $e->getCode()
227
            );
228
        }
229 2
        $content = $response->getBody(true);
230 2
        if (isset($this->cache)) {
231
            $this->cache->save($this->options['storeKey'], $content, $this->cacheLifetime);
232
        }
233
234 2
        return $content;
235
    }
236
}
237