Completed
Pull Request — master (#256)
by
unknown
01:22
created

SymfonyCache::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 1
nc 1
nop 9

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\CacheBundle\Adapter;
15
16
use Sonata\Cache\CacheAdapterInterface;
17
use Sonata\Cache\CacheElementInterface;
18
use Sonata\Cache\Exception\UnsupportedException;
19
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
20
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
21
use Symfony\Component\Filesystem\Filesystem;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
24
use Symfony\Component\Routing\RouterInterface;
25
26
/**
27
 * Handles Symfony cache.
28
 *
29
 * @author Vincent Composieux <[email protected]>
30
 */
31
class SymfonyCache implements CacheAdapterInterface
32
{
33
    /**
34
     * @var RouterInterface
35
     */
36
    protected $router;
37
38
    /**
39
     * @var string
40
     */
41
    protected $cacheDir;
42
43
    /**
44
     * @var string
45
     */
46
    protected $token;
47
48
    /**
49
     * @var string[]
50
     */
51
    protected $types;
52
53
    /**
54
     * @var bool
55
     */
56
    protected $phpCodeCacheEnabled;
57
58
    /**
59
     * @var array
60
     */
61
    protected $servers;
62
63
    /**
64
     * @var array
65
     */
66
    protected $timeouts;
67
68
    /**
69
     * @var Filesystem
70
     */
71
    protected $filesystem;
72
73
    /**
74
     * @var EventDispatcherInterface
75
     */
76
    protected $eventDispatcher;
77
78
    public function __construct(
79
        RouterInterface $router,
80
        Filesystem $filesystem,
81
        EventDispatcherInterface $eventDispatcher,
82
        string $cacheDir,
83
        string $token,
84
        bool $phpCodeCacheEnabled,
85
        array $types,
86
        array $servers,
87
        array $timeouts
88
    ) {
89
        $this->router = $router;
90
        $this->filesystem = $filesystem;
91
        $this->eventDispatcher = $eventDispatcher;
92
        $this->cacheDir = $cacheDir;
93
        $this->token = $token;
94
        $this->types = $types;
95
        $this->phpCodeCacheEnabled = $phpCodeCacheEnabled;
96
        $this->servers = $servers;
97
        $this->timeouts = $timeouts;
98
    }
99
100
    public function flushAll(): bool
101
    {
102
        return $this->flush(['all']);
103
    }
104
105
    /**
106
     * @throws \InvalidArgumentException
107
     * @throws \UnexpectedValueException
108
     */
109
    public function flush(array $keys = ['all']): bool
110
    {
111
        $result = true;
112
113
        foreach ($this->servers as $server) {
114
            foreach ($keys as $type) {
115
                $ip = $server['ip'];
116
117
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
118
                    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
119
                } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
120
                    $socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
121
                } else {
122
                    throw new \InvalidArgumentException(sprintf('"%s" is not a valid ip address', $ip));
123
                }
124
125
                // generate the raw http request
126
                $command = sprintf("GET %s HTTP/1.1\r\n", $this->getUrl($type));
127
                $command .= sprintf("Host: %s\r\n", $server['domain']);
128
129
                if ($server['basic']) {
130
                    $command .= sprintf("Authorization: Basic %s\r\n", $server['basic']);
131
                }
132
133
                $command .= "Connection: Close\r\n\r\n";
134
135
                // setup the default timeout (avoid max execution time)
136
                socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $this->timeouts['SND']);
137
                socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $this->timeouts['RCV']);
138
139
                socket_connect($socket, $server['ip'], $server['port']);
140
                socket_write($socket, $command);
141
142
                $content = '';
143
144
                do {
145
                    $buffer = socket_read($socket, 1024);
146
                    $content .= $buffer;
147
                } while (!empty($buffer));
148
149
                if ($result) {
150
                    $result = 'ok' === substr($content, -2);
151
                } else {
152
                    throw new \UnexpectedValueException(sprintf(
153
                        'Server answered with "%s"',
154
                        $content
155
                    ));
156
                }
157
            }
158
        }
159
160
        return $result;
161
    }
162
163
    /**
164
     * @throws AccessDeniedHttpException
165
     * @throws \RuntimeException
166
     */
167
    public function cacheAction(string $token, string $type): Response
168
    {
169
        if ($this->token !== $token) {
170
            throw new AccessDeniedHttpException('Invalid token.');
171
        }
172
173
        if (!\in_array($type, $this->types, true)) {
174
            throw new \RuntimeException(
175
                sprintf('Type "%s" is not defined, allowed types are: "%s"', $type, implode(', ', $this->types))
176
            );
177
        }
178
179
        $path = 'all' === $type ? $this->cacheDir : sprintf('%s/%s', $this->cacheDir, $type);
180
181
        // clean up event dispatcher just before clearing the cache to prevent further events execution
182
        foreach ($this->eventDispatcher->getListeners() as $eventName => $eventListenerList) {
183
            foreach ($eventListenerList as $listener) {
184
                $listener[0] instanceof EventSubscriberInterface ?
185
                    $this->eventDispatcher->removeSubscriber($listener[0]) :
186
                    $this->eventDispatcher->removeListener($eventName, [$listener[0], $listener[1]]);
187
            }
188
        }
189
190
        if ($this->filesystem->exists($path)) {
191
            $movedPath = $path.'_old_'.uniqid();
192
193
            $this->filesystem->rename($path, $movedPath);
194
            $this->filesystem->remove($movedPath);
195
196
            $this->clearPHPCodeCache();
197
        }
198
199
        return new Response('ok', 200, [
200
            'Cache-Control' => 'no-cache, must-revalidate',
201
            'Content-Length' => 2, // to prevent chunked transfer encoding
202
        ]);
203
    }
204
205
    /**
206
     * @throws UnsupportedException
207
     */
208
    public function has(array $keys): bool
209
    {
210
        throw new UnsupportedException('SymfonyCache has() method does not exist.');
211
    }
212
213
    /**
214
     * @throws UnsupportedException
215
     */
216
    public function set(array $keys, $data, int $ttl = 84600, array $contextualKeys = []): CacheElementInterface
217
    {
218
        throw new UnsupportedException('SymfonyCache set() method does not exist.');
219
    }
220
221
    /**
222
     * @throws UnsupportedException
223
     */
224
    public function get(array $keys): CacheElementInterface
225
    {
226
        throw new UnsupportedException('SymfonyCache get() method does not exist.');
227
    }
228
229
    public function isContextual(): bool
230
    {
231
        return false;
232
    }
233
234
    protected function getUrl(string $type): ?string
235
    {
236
        return $this->router->generate('sonata_cache_symfony', [
237
            'token' => $this->token,
238
            'type' => $type,
239
        ]);
240
    }
241
242
    protected function clearPHPCodeCache(): void
243
    {
244
        if (!$this->phpCodeCacheEnabled) {
245
            return;
246
        }
247
248
        if (\function_exists('opcache_reset')) {
249
            opcache_reset();
250
        }
251
    }
252
}
253