Completed
Pull Request — develop (#273)
by Samuel
25:26 queued 13:47
created

HttpLoader::load()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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