Completed
Pull Request — master (#266)
by David de
03:58
created

AbstractProxyClient::flush()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 7.0036

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 39
ccs 23
cts 24
cp 0.9583
rs 6.7273
cc 7
eloc 20
nc 9
nop 0
crap 7.0036
1
<?php
2
3
/*
4
 * This file is part of the FOSHttpCache package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\HttpCache\ProxyClient;
13
14
use FOS\HttpCache\Exception\ExceptionCollection;
15
use FOS\HttpCache\Exception\ProxyResponseException;
16
use FOS\HttpCache\Exception\ProxyUnreachableException;
17
use FOS\HttpCache\ProxyClient\Request\InvalidationRequest;
18
use FOS\HttpCache\ProxyClient\Request\RequestQueue;
19
use Http\Adapter\Exception\MultiHttpAdapterException;
20
use Http\Adapter\HttpAdapter;
21
use Http\Discovery\HttpAdapterDiscovery;
22
use Psr\Http\Message\ResponseInterface;
23
24
/**
25
 * Abstract caching proxy client
26
 *
27
 * @author David de Boer <[email protected]>
28
 */
29
abstract class AbstractProxyClient implements ProxyClientInterface
30
{
31
    /**
32
     * HTTP client
33
     *
34
     * @var HttpAdapter
35
     */
36
    private $httpAdapter;
37
38
    /**
39
     * Request queue
40
     *
41
     * @var RequestQueue
42
     */
43
    protected $queue;
44
45
    /**
46
     * Constructor
47
     *
48
     * @param array $servers           Caching proxy server hostnames or IP
49
     *                                 addresses, including port if not port 80.
50
     *                                 E.g. ['127.0.0.1:6081']
51
     * @param string      $baseUri     Default application hostname, optionally
52
     *                                 including base URL, for purge and refresh
53
     *                                 requests (optional). This is required if
54
     *                                 you purge and refresh paths instead of
55
     *                                 absolute URLs.
56
     * @param HttpAdapter $httpAdapter If no HTTP adapter is supplied, a default
57
     *                                 one will be created.
58
     */
59 46
    public function __construct(
60
        array $servers,
61
        $baseUri = null,
62
        HttpAdapter $httpAdapter = null
63
    ) {
64 46
        $this->httpAdapter = $httpAdapter ?: HttpAdapterDiscovery::find();
65 46
        $this->initQueue($servers, $baseUri);
66 43
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 39
    public function flush()
72
    {
73 39
        if (0 === $this->queue->count()) {
74 1
            return 0;
75
        }
76
77 38
        $queue = clone $this->queue;
78 38
        $this->queue->clear();
79
80 1
        try {
81 38
            $responses = $this->httpAdapter->sendRequests($queue->all());
82 38
        } catch (MultiHttpAdapterException $e) {
83
            // Handle all networking errors: php-http only throws an exception
84
            // if no response is available.
85 1
            $collection = new ExceptionCollection();
86 1
            foreach ($e->getExceptions() as $exception) {
87
                // php-http only throws an exception if no response is available
88 1
                if (!$exception->getResponse()) {
89
                    // Assume networking error if no response was returned.
90 1
                    $collection->add(
91 1
                        ProxyUnreachableException::proxyUnreachable($exception)
92 1
                    );
93 1
                }
94 1
            }
95
96 1
            foreach ($this->handleErrorResponses($e->getResponses()) as $exception) {
97
                $collection->add($exception);
98 1
            }
99
100 1
            throw $collection;
101
        }
102
103 38
        $exceptions = $this->handleErrorResponses($responses);
104 38
        if (count($exceptions) > 0) {
105 1
            throw new ExceptionCollection($exceptions);
106
        }
107
108 37
        return count($queue);
109
    }
110
111
    /**
112
     * Add invalidation reqest to the queue
113
     *
114
     * @param string $method  HTTP method
115
     * @param string $url     HTTP URL
116
     * @param array  $headers HTTP headers
117
     */
118 38
    protected function queueRequest($method, $url, array $headers = [])
119
    {
120 38
        $this->queue->add(new InvalidationRequest($method, $url, $headers));
121 38
    }
122
123
    /**
124
     * Initialize the request queue
125
     *
126
     * @param array  $servers
127
     * @param string $baseUri
128
     */
129 46
    protected function initQueue(array $servers, $baseUri)
130
    {
131 46
        $this->queue = new RequestQueue($servers, $baseUri);
132 43
    }
133
134
    /**
135
     * @param ResponseInterface[] $responses
136
     *
137
     * @return ProxyResponseException[]
138
     */
139 38
    private function handleErrorResponses(array $responses)
140
    {
141 38
        $exceptions = [];
142
143 38
        foreach ($responses as $response) {
144 36
            if ($response->getStatusCode() >= 400
145 36
                && $response->getStatusCode() < 600
146 36
            ) {
147 1
                $exceptions[] = ProxyResponseException::proxyResponse($response);
148 1
            }
149 38
        }
150
151 38
        return $exceptions;
152
    }
153
154
    /**
155
     * Make sure that the tags are valid.
156
     *
157
     * Reusable function for proxy clients.
158
     * Escapes `,` and `\n` (newline) characters.
159
     *
160
     * @param array $tags The tags to escape.
161
     *
162
     * @return array Sane tags.
163
     */
164
    protected function escapeTags(array $tags)
165
    {
166 3
        array_walk($tags, function (&$tag) {
167 3
            $tag = str_replace([',', "\n"], ['_', '_'], $tag);
168 3
        });
169
170 3
        return $tags;
171
    }
172
}
173