SsiCache   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 9
dl 0
loc 116
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A flushAll() 0 4 1
A flush() 0 4 1
A has() 0 4 1
A get() 0 14 3
A set() 0 8 1
A cacheAction() 0 19 2
A isContextual() 0 4 1
A getUrl() 0 9 1
A computeHash() 0 6 1
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\CacheElement;
18
use Sonata\Cache\CacheElementInterface;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
22
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
23
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
24
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
25
use Symfony\Component\Routing\RouterInterface;
26
27
/**
28
 * Not really a cache as it, depends on the reverse proxy feature.
29
 */
30
class SsiCache implements CacheAdapterInterface
31
{
32
    protected $router;
33
34
    protected $servers;
35
36
    protected $resolver;
37
38
    protected $token;
39
40
    /**
41
     * @var ArgumentResolverInterface
42
     */
43
    private $argumentResolver;
44
45
    public function __construct(
46
        string $token,
47
        RouterInterface $router,
48
        ControllerResolverInterface $resolver,
49
        ArgumentResolverInterface $argumentResolver
50
    ) {
51
        $this->token = $token;
52
        $this->router = $router;
53
        $this->resolver = $resolver;
54
        $this->argumentResolver = $argumentResolver;
55
    }
56
57
    public function flushAll(): bool
58
    {
59
        return true; // nothing to flush
60
    }
61
62
    public function flush(array $keys = []): bool
63
    {
64
        return true; // still nothing to flush ...
65
    }
66
67
    public function has(array $keys): bool
68
    {
69
        return true;
70
    }
71
72
    /**
73
     * @throws \RuntimeException
74
     */
75
    public function get(array $keys): CacheElementInterface
76
    {
77
        if (!isset($keys['controller'])) {
78
            throw new \RuntimeException('Please define a controller key');
79
        }
80
81
        if (!isset($keys['parameters'])) {
82
            throw new \RuntimeException('Please define a parameters key');
83
        }
84
85
        $content = sprintf('<!--# include virtual="%s" -->', $this->getUrl($keys));
86
87
        return new CacheElement($keys, new Response($content));
88
    }
89
90
    public function set(
91
        array $keys,
92
        $data,
93
        int $ttl = CacheElement::DAY,
94
        array $contextualKeys = []
95
    ): CacheElementInterface {
96
        return new CacheElement($keys, $data, $ttl, $contextualKeys);
97
    }
98
99
    /**
100
     * @throws AccessDeniedHttpException
101
     *
102
     * @return mixed
103
     */
104
    public function cacheAction(Request $request)
105
    {
106
        $parameters = $request->get('parameters', []);
107
108
        if ($request->get('token') !== $this->computeHash($parameters)) {
109
            throw new AccessDeniedHttpException('Invalid token');
110
        }
111
112
        $subRequest = Request::create('', 'get', $parameters, $request->cookies->all(), [], $request->server->all());
113
114
        $controller = $this->resolver->getController($subRequest);
115
116
        $subRequest->attributes->add(['_controller' => $parameters['controller']]);
117
        $subRequest->attributes->add($parameters['parameters']);
118
119
        $arguments = $this->argumentResolver->getArguments($subRequest, $controller);
0 ignored issues
show
Security Bug introduced by
It seems like $controller defined by $this->resolver->getController($subRequest) on line 114 can also be of type false; however, Symfony\Component\HttpKe...terface::getArguments() does only seem to accept callable, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
120
121
        return \call_user_func_array($controller, $arguments);
122
    }
123
124
    public function isContextual(): bool
125
    {
126
        return true;
127
    }
128
129
    protected function getUrl(array $keys): ?string
130
    {
131
        $parameters = [
132
            'token' => $this->computeHash($keys),
133
            'parameters' => $keys,
134
        ];
135
136
        return $this->router->generate('sonata_cache_ssi', $parameters, UrlGeneratorInterface::ABSOLUTE_PATH);
137
    }
138
139
    protected function computeHash(array $keys): string
140
    {
141
        ksort($keys);
142
143
        return hash('sha256', $this->token.serialize($keys));
144
    }
145
}
146