Skip to content

Commit

Permalink
Merge branch '5.4' into 6.0
Browse files Browse the repository at this point in the history
* 5.4:
  Don't rely on session service in tests
  [Mime] Fix encoding filenames in multipart/form-data
  Properly warn about deprecation of IS_AUTHENTICATED_ANONYMOUSLY
  [Lock] Create tables in transaction only if supported by driver
  [Validator] Improve French translation
  [HttpFoundation] Take php session.cookie settings into account
  [Translations] Add missing translations for Galician (gl)
  [ErrorHandler] fix on patching return types on Windows
  [DependencyInjection] fix linting callable classes
  alias `cache.app.taggable` to `cache.app` if using `cache.adapter.redis_tag_aware`
  restore the overriden locale on tearDown - avoid interfering with any configured value
  [Serializer] Improve UidNormalizer denormalize error message
  [DependencyInjection] Cast tag value to string
  • Loading branch information
derrabus committed Dec 21, 2021
2 parents 4d164da + bfbc5a6 commit 57d644d
Show file tree
Hide file tree
Showing 27 changed files with 449 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2125,7 +2125,9 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con
$pool['reset'] = 'reset';
}

if ($isRedisTagAware) {
if ($isRedisTagAware && 'cache.app' === $name) {
$container->setAlias('cache.app.taggable', $name);
} elseif ($isRedisTagAware) {
$tagAwareId = $name;
$container->setAlias('.'.$name.'.inner', $name);
} elseif ($pool['tags']) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

$container->loadFromExtension('framework', [
'cache' => [
'app' => 'cache.adapter.redis_tag_aware',
],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

$container->loadFromExtension('framework', [
'cache' => [
'app' => 'cache.redis_tag_aware.bar',
'pools' => [
'cache.redis_tag_aware.foo' => [
'adapter' => 'cache.adapter.redis_tag_aware',
],
'cache.redis_tag_aware.bar' => [
'adapter' => 'cache.redis_tag_aware.foo',
],
],
],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config>
<framework:cache>
<framework:app>cache.adapter.redis_tag_aware</framework:app>
</framework:cache>
</framework:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config>
<framework:cache>
<framework:app>cache.redis_tag_aware.bar</framework:app>
<framework:pool name="cache.redis_tag_aware.foo" adapter="cache.adapter.redis_tag_aware" />
<framework:pool name="cache.redis_tag_aware.bar" adapter="cache.redis_tag_aware.foo" />
</framework:cache>
</framework:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
framework:
cache:
app: cache.adapter.redis_tag_aware
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
framework:
cache:
app: cache.redis_tag_aware.bar
pools:
cache.redis_tag_aware.foo:
adapter: cache.adapter.redis_tag_aware
cache.redis_tag_aware.bar:
adapter: cache.redis_tag_aware.foo
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,32 @@ public function testRedisTagAwareAdapter()
}
}

/**
* @dataProvider testAppRedisTagAwareConfigProvider
*/
public function testAppRedisTagAwareAdapter()
{
$container = $this->createContainerFromFile('cache_app_redis_tag_aware');

foreach ([TagAwareCacheInterface::class, CacheInterface::class, CacheItemPoolInterface::class] as $alias) {
$def = $container->findDefinition($alias);

while ($def instanceof ChildDefinition) {
$def = $container->getDefinition($def->getParent());
}

$this->assertSame(RedisTagAwareAdapter::class, $def->getClass());
}
}

public function testAppRedisTagAwareConfigProvider(): array
{
return [
['cache_app_redis_tag_aware'],
['cache_app_redis_tag_aware_pool'],
];
}

public function testRemovesResourceCheckerConfigCacheFactoryArgumentOnlyIfNoDebug()
{
$container = $this->createContainer(['kernel.debug' => true]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ protected function getReflectionMethod(Definition $definition, string $method):
}

if (!$r->hasMethod($method)) {
if ($r->hasMethod('__call') && ($r = $r->getMethod('__call')) && $r->isPublic()) {
return new \ReflectionMethod(static function (...$arguments) {}, '__invoke');
}

throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private function addService(Definition $definition, ?string $id, \DOMElement $pa
$tag->appendChild($this->document->createTextNode($name));
}
foreach ($attributes as $key => $value) {
$tag->setAttribute($key, $value);
$tag->setAttribute($key, $value ?? '');
}
$service->appendChild($tag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -961,4 +961,22 @@ public function testIntersectionTypeFailsWithReference()

(new CheckTypeDeclarationsPass(true))->process($container);
}

public function testCallableClass()
{
$container = new ContainerBuilder();
$definition = $container->register('foo', CallableClass::class);
$definition->addMethodCall('callMethod', [123]);

(new CheckTypeDeclarationsPass())->process($container);

$this->addToAssertionCount(1);
}
}

class CallableClass
{
public function __call($name, $arguments)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
->register('foo', FooClass::class)
->addTag('foo', ['foo' => 'foo'])
->addTag('foo', ['bar' => 'bar', 'baz' => 'baz'])
->addTag('nullable', ['bar' => 'bar', 'baz' => null])
->addTag('foo', ['name' => 'bar', 'baz' => 'baz'])
->setFactory(['Bar\\FooClass', 'getInstance'])
->setArguments(['foo', new Reference('foo.baz'), ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%'], true, new Reference('service_container')])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<tag name="foo" foo="foo"/>
<tag name="foo" bar="bar" baz="baz"/>
<tag name="bar" baz="baz">foo</tag>
<tag name="nullable" bar="bar" baz=""/>
<argument>foo</argument>
<argument type="service" id="foo.baz"/>
<argument type="collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:
- foo: { foo: foo }
- foo: { bar: bar, baz: baz }
- foo: { name: bar, baz: baz }
- nullable: { bar: bar, baz: ~ }
arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', foobar: '%foo%' }, true, '@service_container']
properties: { foo: bar, moo: '@foo.baz', qux: { '%foo%': 'foo is %foo%', foobar: '%foo%' } }
calls:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class TentativeTypes
'format' => 'string',
'getTimezone' => 'DateTimeZone|false',
'getOffset' => 'int',
'getTimestamp' => 'int|false',
'getTimestamp' => 'int',
'diff' => 'DateInterval',
'__wakeup' => 'void',
],
Expand Down Expand Up @@ -254,6 +254,7 @@ class TentativeTypes
'isEquivalentTo' => 'bool',
'isLenient' => 'bool',
'isWeekend' => 'bool',
'roll' => 'bool',
'isSet' => 'bool',
'setTime' => 'bool',
'setTimeZone' => 'bool',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$dep

$exclude = getenv('SYMFONY_PATCH_TYPE_EXCLUDE') ?: null;
foreach ($loader->getClassMap() as $class => $file) {
if (false !== strpos($file = realpath($file), '/vendor/')) {
if (false !== strpos($file = realpath($file), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,12 @@ public function onKernelResponse(ResponseEvent $event)
*/
$sessionName = $session->getName();
$sessionId = $session->getId();
$sessionCookiePath = $this->sessionOptions['cookie_path'] ?? '/';
$sessionCookieDomain = $this->sessionOptions['cookie_domain'] ?? null;
$sessionCookieSecure = $this->sessionOptions['cookie_secure'] ?? false;
$sessionCookieHttpOnly = $this->sessionOptions['cookie_httponly'] ?? true;
$sessionCookieSameSite = $this->sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;
$sessionOptions = $this->getSessionOptions($this->sessionOptions);
$sessionCookiePath = $sessionOptions['cookie_path'] ?? '/';
$sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null;
$sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false;
$sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true;
$sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX;

SessionUtils::popSessionCookie($sessionName, $sessionId);

Expand All @@ -157,7 +158,7 @@ public function onKernelResponse(ResponseEvent $event)
);
} elseif ($sessionId !== $requestSessionCookieId) {
$expire = 0;
$lifetime = $this->sessionOptions['cookie_lifetime'] ?? null;
$lifetime = $sessionOptions['cookie_lifetime'] ?? null;
if ($lifetime) {
$expire = time() + $lifetime;
}
Expand Down Expand Up @@ -265,4 +266,23 @@ public function reset(): void
* Gets the session object.
*/
abstract protected function getSession(): ?SessionInterface;

private function getSessionOptions(array $sessionOptions): array
{
$mergedSessionOptions = [];

foreach (session_get_cookie_params() as $key => $value) {
$mergedSessionOptions['cookie_'.$key] = $value;
}

foreach ($sessionOptions as $key => $value) {
// do the same logic as in the NativeSessionStorage
if ('cookie_secure' === $key && 'auto' === $value) {
continue;
}
$mergedSessionOptions[$key] = $value;
}

return $mergedSessionOptions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -31,6 +32,97 @@

class SessionListenerTest extends TestCase
{
/**
* @dataProvider provideSessionOptions
* @runInSeparateProcess
*/
public function testSessionCookieOptions(array $phpSessionOptions, array $sessionOptions, array $expectedSessionOptions)
{
$session = $this->createMock(Session::class);
$session->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1));
$session->method('getId')->willReturn('123456');
$session->method('getName')->willReturn('PHPSESSID');
$session->method('save');
$session->method('isStarted')->willReturn(true);

if (isset($phpSessionOptions['samesite'])) {
ini_set('session.cookie_samesite', $phpSessionOptions['samesite']);
}
session_set_cookie_params(0, $phpSessionOptions['path'] ?? null, $phpSessionOptions['domain'] ?? null, $phpSessionOptions['secure'] ?? null, $phpSessionOptions['httponly'] ?? null);

$listener = new SessionListener(new Container(), false, $sessionOptions);
$kernel = $this->createMock(HttpKernelInterface::class);

$request = new Request();
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));

$request->setSession($session);
$response = new Response();
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $response));

$cookies = $response->headers->getCookies();
$this->assertSame('PHPSESSID', $cookies[0]->getName());
$this->assertSame('123456', $cookies[0]->getValue());
$this->assertSame($expectedSessionOptions['cookie_path'], $cookies[0]->getPath());
$this->assertSame($expectedSessionOptions['cookie_domain'], $cookies[0]->getDomain());
$this->assertSame($expectedSessionOptions['cookie_secure'], $cookies[0]->isSecure());
$this->assertSame($expectedSessionOptions['cookie_httponly'], $cookies[0]->isHttpOnly());
$this->assertSame($expectedSessionOptions['cookie_samesite'], $cookies[0]->getSameSite());
}

public function provideSessionOptions(): \Generator
{
if (\PHP_VERSION_ID > 70300) {
yield 'set_samesite_by_php' => [
'phpSessionOptions' => ['samesite' => Cookie::SAMESITE_STRICT],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_STRICT],
];
}

yield 'set_cookie_path_by_php' => [
'phpSessionOptions' => ['path' => '/prod/'],
'sessionOptions' => ['cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/prod/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];

yield 'set_cookie_secure_by_php' => [
'phpSessionOptions' => ['secure' => true],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];

yield 'set_cookiesecure_auto_by_symfony_false_by_php' => [
'phpSessionOptions' => ['secure' => false],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => 'auto', 'cookie_secure' => 'auto', 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => false, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];

yield 'set_cookiesecure_auto_by_symfony_true_by_php' => [
'phpSessionOptions' => ['secure' => true],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => 'auto', 'cookie_secure' => 'auto', 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];

yield 'set_cookie_httponly_by_php' => [
'phpSessionOptions' => ['httponly' => true],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];

yield 'set_cookie_domain_by_php' => [
'phpSessionOptions' => ['domain' => 'test.symfony'],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => 'test.symfony', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];

yield 'set_samesite_by_symfony' => [
'phpSessionOptions' => ['samesite' => Cookie::SAMESITE_STRICT],
'sessionOptions' => ['cookie_path' => '/test/', 'cookie_httponly' => true, 'cookie_secure' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
'expectedSessionOptions' => ['cookie_path' => '/test/', 'cookie_domain' => '', 'cookie_secure' => true, 'cookie_httponly' => true, 'cookie_samesite' => Cookie::SAMESITE_LAX],
];
}

public function testOnlyTriggeredOnMainRequest()
{
$listener = $this->getMockForAbstractClass(AbstractSessionListener::class);
Expand Down
Loading

0 comments on commit 57d644d

Please sign in to comment.