Passed
Push — trunk ( c83b87...a87e38 )
by Christian
22:40 queued 02:13
created

VarnishReverseProxyGateway   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 92
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 34
dl 0
loc 92
rs 10
c 0
b 0
f 0
wmc 13

6 Methods

Rating   Name   Duplication   Size   Complexity  
A ban() 0 22 4
A invalidate() 0 20 3
A __construct() 0 5 1
A getDecorated() 0 3 1
A tag() 0 10 3
A banAll() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Storefront\Framework\Cache\ReverseProxy;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Exception\ServerException;
7
use GuzzleHttp\Exception\TransferException;
8
use GuzzleHttp\Pool;
9
use GuzzleHttp\Psr7\Request;
10
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
11
use Symfony\Component\HttpFoundation\Response;
12
13
/**
14
 * @package storefront
15
 *
16
 * @see https://github.com/varnish/varnish-modules/blob/master/src/vmod_xkey.vcc
17
 */
18
class VarnishReverseProxyGateway extends AbstractReverseProxyGateway
19
{
20
    /**
21
     * @var array<string>
22
     */
23
    private array $hosts;
24
25
    private Client $client;
26
27
    private int $concurrency;
28
29
    /**
30
     * @internal
31
     *
32
     * @param string[] $hosts
33
     */
34
    public function __construct(array $hosts, int $concurrency, Client $client)
35
    {
36
        $this->hosts = $hosts;
37
        $this->concurrency = $concurrency;
38
        $this->client = $client;
39
    }
40
41
    public function getDecorated(): AbstractReverseProxyGateway
42
    {
43
        throw new DecorationPatternException(self::class);
44
    }
45
46
    /**
47
     * @param string[] $tags
48
     */
49
    public function tag(array $tags, string $url, Response $response): void
50
    {
51
        /** @var Response|null $response */
52
        $response = \func_num_args() === 3 ? func_get_arg(2) : null;
53
54
        if ($response === null) {
55
            throw new \InvalidArgumentException('Parameter $response is required for VarnishReverseProxyGateway');
56
        }
57
58
        $response->headers->set('xkey', implode(' ', $tags));
59
    }
60
61
    public function invalidate(array $tags): void
62
    {
63
        $list = [];
64
65
        foreach ($this->hosts as $host) {
66
            $list[] = new Request('PURGE', $host, ['xkey' => implode(' ', $tags)]);
67
        }
68
69
        $pool = new Pool($this->client, $list, [
70
            'concurrency' => $this->concurrency,
71
            'rejected' => function (TransferException $reason): void {
72
                if ($reason instanceof ServerException) {
73
                    throw new \RuntimeException(sprintf('BAN request failed to %s failed with error: %s', $reason->getRequest()->getUri()->__toString(), $reason->getMessage()), 0, $reason);
74
                }
75
76
                throw $reason;
77
            },
78
        ]);
79
80
        $pool->promise()->wait();
81
    }
82
83
    public function ban(array $urls): void
84
    {
85
        $list = [];
86
87
        foreach ($urls as $url) {
88
            foreach ($this->hosts as $host) {
89
                $list[] = new Request('PURGE', $host . $url);
90
            }
91
        }
92
93
        $pool = new Pool($this->client, $list, [
94
            'concurrency' => $this->concurrency,
95
            'rejected' => function (TransferException $reason): void {
96
                if ($reason instanceof ServerException) {
97
                    throw new \RuntimeException(sprintf('BAN request failed to %s failed with error: %s', $reason->getRequest()->getUri()->__toString(), $reason->getMessage()), 0, $reason);
98
                }
99
100
                throw $reason;
101
            },
102
        ]);
103
104
        $pool->promise()->wait();
105
    }
106
107
    public function banAll(): void
108
    {
109
        $this->ban(['/']);
110
    }
111
}
112