1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the FOSHttpCacheBundle 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\HttpCacheBundle\EventListener; |
13
|
|
|
|
14
|
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
15
|
|
|
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; |
16
|
|
|
use Symfony\Component\HttpKernel\Event\FinishRequestEvent; |
17
|
|
|
use Symfony\Component\HttpKernel\Event\GetResponseEvent; |
18
|
|
|
use Symfony\Component\HttpKernel\Event\RequestEvent; |
19
|
|
|
use Symfony\Component\HttpKernel\Event\ResponseEvent; |
20
|
|
|
use Symfony\Component\HttpKernel\EventListener\SessionListener as BaseSessionListener; |
21
|
|
|
use Symfony\Component\HttpKernel\Kernel; |
22
|
|
|
|
23
|
1 |
View Code Duplication |
if (Kernel::MAJOR_VERSION >= 5) { |
|
|
|
|
24
|
1 |
|
class_alias(RequestEvent::class, 'FOS\HttpCacheBundle\EventListener\SessionRequestEvent'); |
25
|
1 |
|
class_alias(ResponseEvent::class, 'FOS\HttpCacheBundle\EventListener\SessionResponseEvent'); |
26
|
|
|
} else { |
27
|
|
|
class_alias(GetResponseEvent::class, 'FOS\HttpCacheBundle\EventListener\SessionRequestEvent'); |
28
|
|
|
class_alias(FilterResponseEvent::class, 'FOS\HttpCacheBundle\EventListener\SessionResponseEvent'); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Decorates the default Symfony session listener. |
33
|
|
|
* |
34
|
|
|
* Since Symfony 3.4, the default Symfony session listener automatically |
35
|
|
|
* overwrites the Cache-Control headers to `private` in case the session has |
36
|
|
|
* been started. This destroys the user context feature of FOSHttpCache. |
37
|
|
|
* Since Symfony 4.1, there is a header we can set to skip this behaviour. We |
38
|
|
|
* set that header in UserContextListener. |
39
|
|
|
* For Symfony 3.4 and 4.0, we decorate the listener to only call the default |
40
|
|
|
* behaviour if `Vary` contains neither the context hash header nor any of the |
41
|
|
|
* user identifier headers, to avoid impacts on other parts of your application. |
42
|
|
|
* |
43
|
|
|
* @author Yanick Witschi <[email protected]> |
44
|
|
|
*/ |
45
|
|
|
final class SessionListener implements EventSubscriberInterface |
46
|
|
|
{ |
47
|
|
|
/** |
48
|
|
|
* @var BaseSessionListener |
49
|
|
|
*/ |
50
|
|
|
private $inner; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
private $userHashHeader; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var array |
59
|
|
|
*/ |
60
|
|
|
private $userIdentifierHeaders; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @param string $userHashHeader Must be lower-cased |
64
|
|
|
* @param array $userIdentifierHeaders Must be lower-cased |
65
|
|
|
*/ |
66
|
|
|
public function __construct(BaseSessionListener $inner, string $userHashHeader, array $userIdentifierHeaders) |
67
|
7 |
|
{ |
68
|
|
|
$this->inner = $inner; |
69
|
7 |
|
$this->userHashHeader = $userHashHeader; |
70
|
7 |
|
$this->userIdentifierHeaders = $userIdentifierHeaders; |
71
|
7 |
|
} |
72
|
7 |
|
|
73
|
|
|
public function onKernelRequest(SessionRequestEvent $event) |
74
|
1 |
|
{ |
75
|
|
|
return $this->inner->onKernelRequest($event); |
76
|
1 |
|
} |
77
|
|
|
|
78
|
|
|
public function onKernelResponse(SessionResponseEvent $event) |
79
|
5 |
|
{ |
80
|
|
|
if (!$event->isMasterRequest()) { |
81
|
5 |
|
return; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
$varyHeaders = array_map('strtolower', $event->getResponse()->getVary()); |
85
|
5 |
|
$relevantHeaders = array_merge($this->userIdentifierHeaders, [$this->userHashHeader]); |
86
|
5 |
|
|
87
|
|
|
// Call default behaviour if it's an irrelevant request for the user context |
88
|
|
|
if (0 === count(array_intersect($varyHeaders, $relevantHeaders))) { |
89
|
5 |
|
$this->inner->onKernelResponse($event); |
90
|
2 |
|
} |
91
|
|
|
|
92
|
|
|
// noop, see class description |
93
|
|
|
} |
94
|
5 |
|
|
95
|
|
|
public function onFinishRequest(FinishRequestEvent $event) |
96
|
1 |
|
{ |
97
|
|
|
// this hook has been added in symfony 3.4.12 - older versions of the listener do not register for it |
98
|
|
|
$this->inner->onFinishRequest($event); |
99
|
1 |
|
} |
100
|
1 |
|
|
101
|
|
|
public static function getSubscribedEvents(): array |
102
|
|
|
{ |
103
|
|
|
return BaseSessionListener::getSubscribedEvents(); |
104
|
|
|
} |
105
|
|
|
} |
106
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.