Skip to content

Commit 44b2f97

Browse files
Merge branch '3.4'
* 3.4: (21 commits) fixed CS HttpCache lock update [Intl] Update ICU data to 60.1 [YAML] Allow to parse custom tags when linting yaml files [HttpKernel][Debug] Remove noise from stack frames of deprecations [WebServerBundle] prevent console.terminate from being fired after stopping server [Validator] Fix Costa Rica IBAN format [Bridge/ProxyManager] Remove direct reference to value holder property [Validator] Add Belarus IBAN format [Config] Fix cannotBeEmpty() [Debug] More aggressively aggregate silenced notices per file+line [HttpFoundation] minor session-related fix [Cache][Lock] Add RedisProxy for lazy Redis connections [TwigBridge] [Bootstrap 4] Fix validation error design for expanded choiceType [FrameworkBundle] Specifically inject the debug dispatcher in the collector [WebserverBundle] fixed the bug that caused that the webserver would … update the pull request template [Stopwatch] minor fix Add default mapping path for validator component Add default mapping path for serializer component ...
2 parents 61b7534 + f1a1181 commit 44b2f97

File tree

852 files changed

+16282
-7403
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

852 files changed

+16282
-7403
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
| Q | A
22
| ------------- | ---
3-
| Branch? | 3.4 or master / 2.7, 2.8 or 3.3 <!-- see comment below -->
3+
| Branch? | master / 2.7, 2.8, 3.3, or 3.4 <!-- see comment below -->
44
| Bug fix? | yes/no
55
| New feature? | yes/no <!-- don't forget to update src/**/CHANGELOG.md files -->
66
| BC breaks? | yes/no
@@ -13,8 +13,7 @@
1313
<!--
1414
- Bug fixes must be submitted against the lowest branch where they apply
1515
(lowest branches are regularly merged to upper ones so they get the fixes too).
16-
- Features and deprecations must be submitted against the 3.4,
17-
legacy code removals go to the master branch.
16+
- Features and deprecations must be submitted against the master branch.
1817
- Please fill in this template according to the PR you're about to submit.
1918
- Replace this comment by a description of what your PR is solving.
2019
-->

src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ public function getProxyFactoryCode(Definition $definition, $id, $factoryCode =
8888
*/
8989
public function getProxyCode(Definition $definition)
9090
{
91-
return $this->classGenerator->generate($this->generateProxyClass($definition));
91+
return preg_replace(
92+
'/(\$this->initializer[0-9a-f]++) && \1->__invoke\(\$this->(valueHolder[0-9a-f]++), (.*?), \1\);/',
93+
'$1 && ($1->__invoke(\$$2, $3, $1) || 1) && $this->$2 = \$$2;',
94+
$this->classGenerator->generate($this->generateProxyClass($definition))
95+
);
9296
}
9397

9498
/**

src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
{{- form_widget(child, {
112112
parent_label_class: label_attr.class|default(''),
113113
translation_domain: choice_translation_domain,
114-
valid: valid,
114+
valid: true,
115115
}) -}}
116116
{% endfor -%}
117117
</div>

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public static function getServiceProvider(ContainerBuilder $container, $name)
134134
$definition = new Definition(AbstractAdapter::class);
135135
$definition->setPublic(false);
136136
$definition->setFactory(array(AbstractAdapter::class, 'createConnection'));
137-
$definition->setArguments(array($dsn));
137+
$definition->setArguments(array($dsn, array('lazy' => true)));
138138
$container->setDefinition($name, $definition);
139139
}
140140
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,11 @@ private function registerValidatorMapping(ContainerBuilder $container, array $co
10211021
}
10221022
}
10231023

1024+
$projectDir = $container->getParameter('kernel.project_dir');
1025+
if ($container->fileExists($dir = $projectDir.'/config/validator', '/^$/')) {
1026+
$this->registerMappingFilesFromDir($dir, $fileRecorder);
1027+
}
1028+
10241029
$this->registerMappingFilesFromConfig($container, $config, $fileRecorder);
10251030
}
10261031

@@ -1188,6 +1193,11 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
11881193
}
11891194
}
11901195

1196+
$projectDir = $container->getParameter('kernel.project_dir');
1197+
if ($container->fileExists($dir = $projectDir.'/config/serializer', '/^$/')) {
1198+
$this->registerMappingFilesFromDir($dir, $fileRecorder);
1199+
}
1200+
11911201
$this->registerMappingFilesFromConfig($container, $config, $fileRecorder);
11921202

11931203
$chainLoader->replaceArgument(0, $serializerLoaders);
@@ -1253,7 +1263,7 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
12531263
$connectionDefinition = new Definition(\stdClass::class);
12541264
$connectionDefinition->setPublic(false);
12551265
$connectionDefinition->setFactory(array(AbstractAdapter::class, 'createConnection'));
1256-
$connectionDefinition->setArguments(array($storeDsn));
1266+
$connectionDefinition->setArguments(array($storeDsn, array('lazy' => true)));
12571267
$container->setDefinition($connectionDefinitionId, $connectionDefinition);
12581268
}
12591269

src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
<service id="data_collector.events" class="Symfony\Component\HttpKernel\DataCollector\EventDataCollector">
2929
<tag name="data_collector" template="@WebProfiler/Collector/events.html.twig" id="events" priority="290" />
30-
<argument type="service" id="event_dispatcher" on-invalid="ignore" />
30+
<argument type="service" id="debug.event_dispatcher" on-invalid="ignore" />
3131
</service>
3232

3333
<service id="data_collector.logger" class="Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector">

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,13 @@ public function testTemplatingRequiresAtLeastOneEngine()
536536
public function testValidation()
537537
{
538538
$container = $this->createContainerFromFile('full');
539+
$projectDir = $container->getParameter('kernel.project_dir');
539540

540541
$ref = new \ReflectionClass('Symfony\Component\Form\Form');
541-
$xmlMappings = array(dirname($ref->getFileName()).'/Resources/config/validation.xml');
542+
$xmlMappings = array(
543+
dirname($ref->getFileName()).'/Resources/config/validation.xml',
544+
strtr($projectDir.'/config/validator/foo.xml', '/', DIRECTORY_SEPARATOR),
545+
);
542546

543547
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
544548

@@ -626,7 +630,7 @@ public function testValidationPaths()
626630
$this->assertEquals(array(new Reference('validator.mapping.cache.symfony')), $calls[7][1]);
627631

628632
$xmlMappings = $calls[3][1][0];
629-
$this->assertCount(2, $xmlMappings);
633+
$this->assertCount(3, $xmlMappings);
630634
try {
631635
// Testing symfony/symfony
632636
$this->assertStringEndsWith('Component'.DIRECTORY_SEPARATOR.'Form/Resources/config/validation.xml', $xmlMappings[0]);
@@ -652,7 +656,7 @@ public function testValidationPathsUsingCustomBundlePath()
652656

653657
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
654658
$xmlMappings = $calls[3][1][0];
655-
$this->assertCount(2, $xmlMappings);
659+
$this->assertCount(3, $xmlMappings);
656660

657661
try {
658662
// Testing symfony/symfony
@@ -694,7 +698,7 @@ public function testValidationMapping()
694698
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
695699

696700
$this->assertSame('addXmlMappings', $calls[3][0]);
697-
$this->assertCount(2, $calls[3][1][0]);
701+
$this->assertCount(3, $calls[3][1][0]);
698702

699703
$this->assertSame('addYamlMappings', $calls[4][0]);
700704
$this->assertCount(3, $calls[4][1][0]);
@@ -742,7 +746,7 @@ public function testSerializerEnabled()
742746

743747
$argument = $container->getDefinition('serializer.mapping.chain_loader')->getArgument(0);
744748

745-
$this->assertCount(1, $argument);
749+
$this->assertCount(2, $argument);
746750
$this->assertEquals('Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader', $argument[0]->getClass());
747751
$this->assertNull($container->getDefinition('serializer.mapping.class_metadata_factory')->getArgument(1));
748752
$this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.normalizer.object')->getArgument(1));
@@ -839,23 +843,33 @@ public function testSerializerCacheDisabled()
839843
public function testSerializerMapping()
840844
{
841845
$container = $this->createContainerFromFile('serializer_mapping', array('kernel.bundles_metadata' => array('TestBundle' => array('namespace' => 'Symfony\\Bundle\\FrameworkBundle\\Tests', 'path' => __DIR__.'/Fixtures/TestBundle'))));
846+
$projectDir = $container->getParameter('kernel.project_dir');
842847
$configDir = __DIR__.'/Fixtures/TestBundle/Resources/config';
843848
$expectedLoaders = array(
844849
new Definition(AnnotationLoader::class, array(new Reference('annotation_reader'))),
845850
new Definition(XmlFileLoader::class, array($configDir.'/serialization.xml')),
846851
new Definition(YamlFileLoader::class, array($configDir.'/serialization.yml')),
852+
new Definition(YamlFileLoader::class, array($projectDir.'/config/serializer/foo.yml')),
847853
new Definition(XmlFileLoader::class, array($configDir.'/serializer_mapping/files/foo.xml')),
848854
new Definition(YamlFileLoader::class, array($configDir.'/serializer_mapping/files/foo.yml')),
849855
new Definition(YamlFileLoader::class, array($configDir.'/serializer_mapping/serialization.yml')),
850856
new Definition(YamlFileLoader::class, array($configDir.'/serializer_mapping/serialization.yaml')),
851857
);
852858

853859
foreach ($expectedLoaders as $definition) {
860+
if (is_file($arg = $definition->getArgument(0))) {
861+
$definition->replaceArgument(0, strtr($arg, '/', DIRECTORY_SEPARATOR));
862+
}
854863
$definition->setPublic(false);
855864
}
856865

857866
$loaders = $container->getDefinition('serializer.mapping.chain_loader')->getArgument(0);
858-
$this->assertEquals(sort($expectedLoaders), sort($loaders));
867+
foreach ($loaders as $loader) {
868+
if (is_file($arg = $loader->getArgument(0))) {
869+
$loader->replaceArgument(0, strtr($arg, '/', DIRECTORY_SEPARATOR));
870+
}
871+
}
872+
$this->assertEquals($expectedLoaders, $loaders);
859873
}
860874

861875
public function testAssetHelperWhenAssetsAreEnabled()

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/config/serializer/foo.yml

Whitespace-only changes.

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/config/validator/foo.xml

Whitespace-only changes.

src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public function load(array $configs, ContainerBuilder $container)
8080
$container->setParameter('twig.exception_listener.controller', $config['exception_controller']);
8181

8282
$container->setParameter('twig.form.resources', $config['form_themes']);
83+
$container->setParameter('twig.default_path', $config['default_path']);
8384

8485
$envConfiguratorDefinition = $container->getDefinition('twig.configurator.environment');
8586
$envConfiguratorDefinition->replaceArgument(0, $config['date']['format']);

src/Symfony/Bundle/WebServerBundle/Command/ServerStartCommand.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Console\Output\OutputInterface;
2121
use Symfony\Component\Console\Output\ConsoleOutputInterface;
2222
use Symfony\Component\Console\Style\SymfonyStyle;
23+
use Symfony\Component\EventDispatcher\EventDispatcher;
2324

2425
/**
2526
* Runs a local web server in a background process.
@@ -127,6 +128,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
127128
$io->error('Running this server in production environment is NOT recommended!');
128129
}
129130

131+
// replace event dispatcher with an empty one to prevent console.terminate from firing
132+
// as container could have changed between start and stop
133+
$this->getApplication()->setDispatcher(new EventDispatcher());
134+
130135
try {
131136
$server = new WebServer();
132137
if ($server->isRunning($input->getOption('pidfile'))) {

src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function testCreateConnection()
4444
'persistent_id' => null,
4545
'read_timeout' => 0,
4646
'retry_interval' => 0,
47+
'lazy' => false,
4748
'database' => '1',
4849
'password' => null,
4950
);

src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,22 @@
1313

1414
use Symfony\Component\Cache\Adapter\AbstractAdapter;
1515
use Symfony\Component\Cache\Adapter\RedisAdapter;
16+
use Symfony\Component\Cache\Traits\RedisProxy;
1617

1718
class RedisAdapterTest extends AbstractRedisAdapterTest
1819
{
1920
public static function setupBeforeClass()
2021
{
2122
parent::setupBeforeClass();
22-
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
23+
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), array('lazy' => true));
24+
}
25+
26+
public function createCachePool($defaultLifetime = 0)
27+
{
28+
$adapter = parent::createCachePool($defaultLifetime);
29+
$this->assertInstanceOf(RedisProxy::class, self::$redis);
30+
31+
return $adapter;
2332
}
2433

2534
public function testCreateConnection()
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.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 Symfony\Component\Cache\Traits;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*
17+
* @internal
18+
*/
19+
class RedisProxy
20+
{
21+
private $redis;
22+
private $initializer;
23+
private $ready = false;
24+
25+
public function __construct(\Redis $redis, \Closure $initializer)
26+
{
27+
$this->redis = $redis;
28+
$this->initializer = $initializer;
29+
}
30+
31+
public function __call($method, array $args)
32+
{
33+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
34+
35+
return \call_user_func_array(array($this->redis, $method), $args);
36+
}
37+
38+
public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
39+
{
40+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
41+
42+
return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount);
43+
}
44+
45+
public function scan(&$iIterator, $strPattern = null, $iCount = null)
46+
{
47+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
48+
49+
return $this->redis->scan($iIterator, $strPattern, $iCount);
50+
}
51+
52+
public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
53+
{
54+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
55+
56+
return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount);
57+
}
58+
59+
public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
60+
{
61+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
62+
63+
return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount);
64+
}
65+
}

src/Symfony/Component/Cache/Traits/RedisTrait.php

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ trait RedisTrait
3434
'timeout' => 30,
3535
'read_timeout' => 0,
3636
'retry_interval' => 0,
37+
'lazy' => false,
3738
);
3839
private $redis;
3940

@@ -49,7 +50,7 @@ public function init($redisClient, $namespace = '', $defaultLifetime = 0)
4950
}
5051
if ($redisClient instanceof \RedisCluster) {
5152
$this->enableVersioning();
52-
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client) {
53+
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
5354
throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($redisClient) ? get_class($redisClient) : gettype($redisClient)));
5455
}
5556
$this->redis = $redisClient;
@@ -117,19 +118,30 @@ public static function createConnection($dsn, array $options = array())
117118
if (is_a($class, \Redis::class, true)) {
118119
$connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect';
119120
$redis = new $class();
120-
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']);
121121

122-
if (@!$redis->isConnected()) {
123-
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
124-
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
125-
}
122+
$initializer = function ($redis) use ($connect, $params, $dsn, $auth) {
123+
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']);
124+
125+
if (@!$redis->isConnected()) {
126+
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
127+
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
128+
}
129+
130+
if ((null !== $auth && !$redis->auth($auth))
131+
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
132+
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
133+
) {
134+
$e = preg_replace('/^ERR /', '', $redis->getLastError());
135+
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
136+
}
137+
138+
return true;
139+
};
126140

127-
if ((null !== $auth && !$redis->auth($auth))
128-
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
129-
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
130-
) {
131-
$e = preg_replace('/^ERR /', '', $redis->getLastError());
132-
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
141+
if ($params['lazy']) {
142+
$redis = new RedisProxy($redis, $initializer);
143+
} else {
144+
$initializer($redis);
133145
}
134146
} elseif (is_a($class, \Predis\Client::class, true)) {
135147
$params['scheme'] = $scheme;

src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,11 @@ protected function createNode()
424424
$node->setKeyAttribute($this->key, $this->removeKeyItem);
425425
}
426426

427-
if (true === $this->atLeastOne || false === $this->allowEmptyValue) {
427+
if (false === $this->allowEmptyValue) {
428+
@trigger_error(sprintf('Using %s::cannotBeEmpty() at path "%s" has no effect, consider requiresAtLeastOneElement() instead. In 4.0 both methods will behave the same.', __CLASS__, $node->getPath()), E_USER_DEPRECATED);
429+
}
430+
431+
if (true === $this->atLeastOne) {
428432
$node->setMinNumberOfElements(1);
429433
}
430434

@@ -486,9 +490,7 @@ protected function validateConcreteNode(ArrayNode $node)
486490
}
487491

488492
if (false === $this->allowEmptyValue) {
489-
throw new InvalidDefinitionException(
490-
sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s"', $path)
491-
);
493+
@trigger_error(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s". In 4.0 it will throw an exception.', $path), E_USER_DEPRECATED);
492494
}
493495

494496
if (true === $this->atLeastOne) {

0 commit comments

Comments
 (0)