Issues (75)

src/ProxyClient/HttpProxyClient.php (1 issue)

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 Http\Discovery\MessageFactoryDiscovery;
15
use Http\Message\RequestFactory;
16
use Psr\Http\Message\StreamInterface;
17
use Psr\Http\Message\UriInterface;
18
use Symfony\Component\OptionsResolver\OptionsResolver;
19
20
/**
21
 * Base class for HTTP based caching proxy client.
22
 *
23
 * @author David de Boer <[email protected]>
24
 */
25
abstract class HttpProxyClient implements ProxyClient
26
{
27
    /**
28
     * Dispatcher for invalidation HTTP requests.
29
     *
30
     * @var HttpDispatcher
31
     */
32
    private $httpDispatcher;
33
34
    /**
35
     * @var RequestFactory
36
     */
37
    private $requestFactory;
38
39
    /**
40
     * The options configured in the constructor argument or default values.
41
     *
42
     * @var array The resolved options
43
     */
44
    protected $options;
45
46
    /**
47
     * Constructor.
48
     *
49
     * The base class has no options.
50
     *
51
     * @param Dispatcher          $httpDispatcher Helper to send HTTP requests to caching proxy
52
     * @param array               $options        Options for this client
53
     * @param RequestFactory|null $messageFactory Factory for PSR-7 messages. If none supplied,
54
     *                                            a default one is created
55
     */
56 45
    public function __construct(
57
        Dispatcher $httpDispatcher,
58
        array $options = [],
59
        RequestFactory $messageFactory = null
60
    ) {
61 45
        $this->httpDispatcher = $httpDispatcher;
0 ignored issues
show
Documentation Bug introduced by
$httpDispatcher is of type FOS\HttpCache\ProxyClient\Dispatcher, but the property $httpDispatcher was declared to be of type FOS\HttpCache\ProxyClient\HttpDispatcher. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
62 45
        $this->options = $this->configureOptions()->resolve($options);
63 45
        $this->requestFactory = $messageFactory ?: MessageFactoryDiscovery::find();
64 45
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 22
    public function flush()
70
    {
71 22
        return $this->httpDispatcher->flush();
72
    }
73
74
    /**
75
     * Get options resolver with default settings.
76
     *
77
     * @return OptionsResolver
78
     */
79 45
    protected function configureOptions()
80
    {
81 45
        return new OptionsResolver();
82
    }
83
84
    /**
85
     * Create a request and queue it with the HTTP dispatcher.
86
     *
87
     * @param string                               $method
88
     * @param string|UriInterface                  $url
89
     * @param bool                                 $validateHost see Dispatcher::invalidate
90
     * @param resource|string|StreamInterface|null $body
91
     */
92 43
    protected function queueRequest($method, $url, array $headers, $validateHost = true, $body = null)
93
    {
94 43
        $this->httpDispatcher->invalidate(
95 43
            $this->requestFactory->createRequest($method, $url, $headers, $body),
96
            $validateHost
97
        );
98 43
    }
99
100
    /**
101
     * Make sure that the tags are valid.
102
     *
103
     * Reusable function for proxy clients.
104
     * Escapes `,` and `\n` (newline) characters.
105
     *
106
     * Note: This is not a safe escaping function, it can lead to collisions,
107
     * e.g. between "foo,bar" and "foo_bar". But from the nature of the data,
108
     * such collisions are unlikely, and from the function of cache tagging,
109
     * collisions would in the worst case lead to unintended invalidations,
110
     * which is not a bug.
111
     *
112
     * @param array $tags The tags to escape
113
     *
114
     * @return array Sane tags
115
     */
116 5
    protected function escapeTags(array $tags)
117
    {
118
        array_walk($tags, function (&$tag) {
119
            // WARNING: changing the list of characters that are escaped is a BC break for existing installations,
120
            // as existing tags on the cache would not be invalidated anymore if they contain a character that is
121
            // newly escaped
122 5
            $tag = str_replace([',', "\n"], '_', $tag);
123 5
        });
124
125 5
        return $tags;
126
    }
127
128
    /**
129
     * Calculate how many tags fit into the header.
130
     *
131
     * This assumes that the tags are separated by one character.
132
     *
133
     * @param string[] $escapedTags
134
     * @param string   $glue        The concatenation string to use
135
     *
136
     * @return int Number of tags per tag invalidation request
137
     */
138 8
    protected function determineTagsPerHeader($escapedTags, $glue)
139
    {
140 8
        if (mb_strlen(implode($glue, $escapedTags)) < $this->options['header_length']) {
141 6
            return count($escapedTags);
142
        }
143
144
        /*
145
         * estimate the amount of tags to invalidate by dividing the max
146
         * header length by the largest tag (minus the glue length)
147
         */
148 2
        $tagsize = max(array_map('mb_strlen', $escapedTags));
149
150 2
        return floor($this->options['header_length'] / ($tagsize + strlen($glue))) ?: 1;
151
    }
152
}
153