diff --git a/CHANGELOG-3.3.md b/CHANGELOG-3.3.md
index 17b9ed1ed3..8a6626da32 100644
--- a/CHANGELOG-3.3.md
+++ b/CHANGELOG-3.3.md
@@ -7,6 +7,36 @@ in 3.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.3.0...v3.3.1
+* 3.3.1 (2017-06-05)
+
+ * bug #23067 [HttpFoundation][FrameworkBundle] Revert "trusted proxies" BC break (nicolas-grekas)
+ * bug #23065 [Cache] Fallback to positional when keyed results are broken (nicolas-grekas)
+ * bug #22981 [DependencyInjection] Fix named args support in ChildDefinition (dunglas)
+ * bug #23050 [Form][Profiler] Fixes form collector triggering deprecations (ogizanagi)
+ * bug #22971 [Profiler] Fix code excerpt wrapping (ogizanagi)
+ * bug #23049 [FrameworkBundle] mitigate BC break with empty trusted_proxies (xabbuh)
+ * bug #23045 [Cache] fix Redis scheme detection (xabbuh)
+ * bug #23013 Parse the _controller format in sub-requests (weaverryan)
+ * bug #23015 [PhpUnitBridge] Fix detection of PHPUnit 5 (enumag)
+ * bug #23041 [Config] Always protected ClassExistenceResource against bad parents (nicolas-grekas)
+ * bug #22988 [PropertyInfo][DoctrineBridge] The bigint Doctrine's type must be converted to string (dunglas)
+ * bug #23014 Fix optional cache warmers are always instantiated whereas they should be lazy-loaded (romainneutron)
+ * feature #23022 [Di] Remove closure-proxy arguments (nicolas-grekas)
+ * bug #23024 [EventDispatcher] Fix ContainerAwareEventDispatcher::hasListeners(null) (nicolas-grekas)
+ * bug #23008 [EventDispatcher] Handle laziness internally instead of relying on ClosureProxyArgument (nicolas-grekas)
+ * bug #23018 [FrameworkBundle] Fix CacheCollectorPass priority (chalasr)
+ * bug #23009 [Routing] Allow GET requests to be redirected. Fixes #23004 (frankdejonge)
+ * bug #22996 [Form] Fix \IntlDateFormatter timezone parameter usage to bypass PHP bug #66323 (romainneutron)
+ * bug #22965 [Cache] Ignore missing annotations.php (ro0NL)
+ * bug #22993 [DI] Autowiring exception thrown when inlined service is removed (weaverryan)
+ * bug #22999 Better DI type deprecation message (weaverryan)
+ * bug #22985 [Config] Allow empty globs (nicolas-grekas)
+ * bug #22961 [HttpKernel] Support unknown format in LoggerDataCollector (iltar)
+ * bug #22991 [DI] Don't throw Autowire exception for removed service with private __construct (weaverryan)
+ * bug #22968 [Profiler] Fix text selection & click on file links on exception pages (ogizanagi)
+ * bug #22994 Harden the debugging of Twig filters and functions (stof)
+ * bug #22960 [Cache] Fix decoration of TagAware adapters in dev (chalasr)
+
* 3.3.0 (2017-05-29)
* bug #22940 [Config] Fallback to regular import when glob fails (nicolas-grekas)
diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
index c69ca843e8..b3c89d18eb 100644
--- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
+++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
@@ -14,6 +14,7 @@ namespace Symfony\Bridge\Twig\NodeVisitor;
use Symfony\Bridge\Twig\Node\TransNode;
use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
use Twig\Environment;
+use Twig\Node\BlockNode;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\Expression\ConstantExpression;
@@ -21,6 +22,7 @@ use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
+use Twig\Node\SetNode;
use Twig\NodeVisitor\AbstractNodeVisitor;
/**
@@ -48,7 +50,7 @@ class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor
*/
protected function doEnterNode(Node $node, Environment $env)
{
- if ($node instanceof Node_Block || $node instanceof ModuleNode) {
+ if ($node instanceof BlockNode || $node instanceof ModuleNode) {
$this->scope = $this->scope->enter();
}
@@ -62,7 +64,7 @@ class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor
$name = new AssignNameExpression($var, $node->getTemplateLine());
$this->scope->set('domain', new NameExpression($var, $node->getTemplateLine()));
- return new Node_Set(false, new Node(array($name)), new Node(array($node->getNode('expr'))), $node->getTemplateLine());
+ return new SetNode(false, new Node(array($name)), new Node(array($node->getNode('expr'))), $node->getTemplateLine());
}
}
@@ -104,7 +106,7 @@ class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor
return false;
}
- if ($node instanceof Node_Block || $node instanceof ModuleNode) {
+ if ($node instanceof BlockNode || $node instanceof ModuleNode) {
$this->scope = $this->scope->leave();
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index d25f4547d3..b760d28997 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -7,7 +7,7 @@ CHANGELOG
* Not defining the `type` option of the `framework.workflows.*` configuration entries is deprecated.
The default value will be `state_machine` in Symfony 4.0.
* Deprecated the `CompilerDebugDumpPass` class
- * [BC BREAK] Removed the "framework.trusted_proxies" configuration option and the corresponding "kernel.trusted_proxies" parameter
+ * Deprecated the "framework.trusted_proxies" configuration option and the corresponding "kernel.trusted_proxies" parameter
* Added a new new version strategy option called json_manifest_path
that allows you to use the `JsonManifestVersionStrategy`.
* Added `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`. It provides
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
index acaec0bf5d..206b01e4f0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
@@ -307,11 +307,4 @@ abstract class Descriptor implements DescriptorInterface
return $serviceIds;
}
-
- protected function formatClosure(\Closure $closure)
- {
- $r = new \ReflectionFunction($closure);
-
- return 'closure';
- }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
index 31ca3a9aaf..8d76bdc3ad 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
@@ -373,7 +373,7 @@ class JsonDescriptor extends Descriptor
}
if ($callable instanceof \Closure) {
- $data['type'] = $this->formatClosure($callable);
+ $data['type'] = 'closure';
return $data;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
index 5703c108bc..73df205d6d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
@@ -352,8 +352,7 @@ class MarkdownDescriptor extends Descriptor
}
if ($callable instanceof \Closure) {
- $formatted = $this->formatClosure($callable);
- $string .= "\n- Type: `$formatted`";
+ $string .= "\n- Type: `closure`";
return $this->write($string."\n");
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
index 63ce6accb2..409d81221a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
@@ -475,13 +475,7 @@ class TextDescriptor extends Descriptor
}
if ($callable instanceof \Closure) {
- $formatted = $this->formatClosure($callable);
-
- if ('closure' === $formatted) {
- return '\Closure()';
- }
-
- return $formatted.'()';
+ return '\Closure()';
}
if (method_exists($callable, '__invoke')) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
index f1770d8c3c..5baa8de11c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
@@ -593,7 +593,7 @@ class XmlDescriptor extends Descriptor
}
if ($callable instanceof \Closure) {
- $callableXML->setAttribute('type', $this->formatClosure($callable));
+ $callableXML->setAttribute('type', 'closure');
return $dom;
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 87d722b91e..611bfad97d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -65,10 +65,38 @@ class Configuration implements ConfigurationInterface
->info("Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. Note: When using the HttpCache, you need to call the method in your front controller instead")
->defaultTrue()
->end()
- ->arrayNode('trusted_proxies') // @deprecated in version 3.3, to be removed in 4.0
+ ->arrayNode('trusted_proxies')
->beforeNormalization()
- ->always()
- ->thenInvalid('The "framework.trusted_proxies" configuration key has been removed in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.')
+ ->ifTrue(function ($v) {
+ @trigger_error('The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.', E_USER_DEPRECATED);
+
+ return !is_array($v) && null !== $v;
+ })
+ ->then(function ($v) { return is_bool($v) ? array() : preg_split('/\s*,\s*/', $v); })
+ ->end()
+ ->prototype('scalar')
+ ->validate()
+ ->ifTrue(function ($v) {
+ if (empty($v)) {
+ return false;
+ }
+
+ if (false !== strpos($v, '/')) {
+ if ('0.0.0.0/0' === $v) {
+ return false;
+ }
+
+ list($v, $mask) = explode('/', $v, 2);
+
+ if (strcmp($mask, (int) $mask) || $mask < 1 || $mask > (false !== strpos($v, ':') ? 128 : 32)) {
+ return true;
+ }
+ }
+
+ return !filter_var($v, FILTER_VALIDATE_IP);
+ })
+ ->thenInvalid('Invalid proxy IP "%s"')
+ ->end()
->end()
->end()
->scalarNode('ide')->defaultNull()->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 1fda255004..06ae921dd2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -155,6 +155,9 @@ class FrameworkExtension extends Extension
$container->setParameter('kernel.http_method_override', $config['http_method_override']);
$container->setParameter('kernel.trusted_hosts', $config['trusted_hosts']);
+ if ($config['trusted_proxies']) {
+ $container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
+ }
$container->setParameter('kernel.default_locale', $config['default_locale']);
if (!$container->hasParameter('debug.file_link_format')) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_debug.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_debug.xml
index d7e4803f5c..8990f7c6cd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_debug.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_debug.xml
@@ -26,7 +26,6 @@
- false
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
index 353e959c68..0d2578db04 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
@@ -43,6 +43,103 @@ class ConfigurationTest extends TestCase
$this->assertEquals(array('FrameworkBundle:Form'), $config['templating']['form']['resources']);
}
+ /**
+ * @group legacy
+ * @expectedDeprecation The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
+ */
+ public function testTrustedProxiesSetToNullIsDeprecated()
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+ $processor->processConfiguration($configuration, array(array('trusted_proxies' => null)));
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
+ */
+ public function testTrustedProxiesSetToEmptyArrayIsDeprecated()
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+ $processor->processConfiguration($configuration, array(array('trusted_proxies' => array())));
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation The "framework.trusted_proxies" configuration key has been deprecated in Symfony 3.3. Use the Request::setTrustedProxies() method in your front controller instead.
+ */
+ public function testTrustedProxiesSetToNonEmptyArrayIsInvalid()
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+ $processor->processConfiguration($configuration, array(array('trusted_proxies' => array('127.0.0.1'))));
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider getTestValidTrustedProxiesData
+ */
+ public function testValidTrustedProxies($trustedProxies, $processedProxies)
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+ $config = $processor->processConfiguration($configuration, array(array(
+ 'secret' => 's3cr3t',
+ 'trusted_proxies' => $trustedProxies,
+ )));
+
+ $this->assertEquals($processedProxies, $config['trusted_proxies']);
+ }
+
+ public function getTestValidTrustedProxiesData()
+ {
+ return array(
+ array(array('127.0.0.1'), array('127.0.0.1')),
+ array(array('::1'), array('::1')),
+ array(array('127.0.0.1', '::1'), array('127.0.0.1', '::1')),
+ array(null, array()),
+ array(false, array()),
+ array(array(), array()),
+ array(array('10.0.0.0/8'), array('10.0.0.0/8')),
+ array(array('::ffff:0:0/96'), array('::ffff:0:0/96')),
+ array(array('0.0.0.0/0'), array('0.0.0.0/0')),
+ );
+ }
+
+ /**
+ * @group legacy
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ */
+ public function testInvalidTypeTrustedProxies()
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+ $processor->processConfiguration($configuration, array(
+ array(
+ 'secret' => 's3cr3t',
+ 'trusted_proxies' => 'Not an IP address',
+ ),
+ ));
+ }
+
+ /**
+ * @group legacy
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ */
+ public function testInvalidValueTrustedProxies()
+ {
+ $processor = new Processor();
+ $configuration = new Configuration(true);
+
+ $processor->processConfiguration($configuration, array(
+ array(
+ 'secret' => 's3cr3t',
+ 'trusted_proxies' => array('Not an IP address'),
+ ),
+ ));
+ }
+
public function testAssetsCanBeEnabled()
{
$processor = new Processor();
@@ -124,6 +221,7 @@ class ConfigurationTest extends TestCase
{
return array(
'http_method_override' => true,
+ 'trusted_proxies' => array(),
'ide' => null,
'default_locale' => 'en',
'csrf_protection' => array(
diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig
index 1c8c76e78d..cb455274ee 100644
--- a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig
+++ b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig
@@ -95,7 +95,7 @@ header .container { display: flex; justify-content: space-between; }
.trace-head .icon svg { height: 24px; width: 24px; }
.trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; }
-
+.trace-details { table-layout: fixed; }
.trace-line { position: relative; padding-left: 36px; }
.trace-line.sf-toggle:hover { background: #F5F5F5; }
.trace-line a { color: #222; }
@@ -108,12 +108,12 @@ header .container { display: flex; justify-content: space-between; }
.trace-method { color: #B0413E; color: #222; font-weight: bold; color: #B0413E; }
.trace-arguments { color: #222; color: #999; font-weight: normal; color: #795da3; color: #777; padding-left: 2px; }
-.trace-code { background: #FFF; font-size: 12px; margin: 10px 0 2px; padding: 10px; }
-.trace-code ol { margin: 0; }
-.trace-code li { color: #969896; margin: 0; padding-left: 10px; }
-.trace-code li + li { margin-top: 10px; }
-.trace-code li.selected { background: #F8EEC7; padding: 3px 0 3px 10px; }
-.trace-code li code { color: #222; }
+.trace-code { background: #FFF; font-size: 12px; margin: 10px 0 2px; padding: 10px; overflow-x: auto; }
+.trace-code ol { margin: 0; float: left; }
+.trace-code li { color: #969896; margin: 0; padding-left: 10px; float: left; width: 100%; }
+.trace-code li + li { margin-top: 5px; }
+.trace-code li.selected { background: #F8EEC7; padding: 3px 0 3px 10px; margin-top: 2px; }
+.trace-code li code { color: #222; white-space: nowrap; }
.trace-as-text .stacktrace { line-height: 1.8; margin: 0 0 15px; white-space: pre-wrap; }
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
index 2f8b83049d..02b77319ac 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
@@ -525,7 +525,7 @@
Model Format |
{% if data.default_data.model is defined %}
- {{ profiler_dump(data.default_data.model) }}
+ {{ profiler_dump(data.default_data.seek('model')) }}
{% else %}
same as normalized format
{% endif %}
@@ -533,13 +533,13 @@
|
Normalized Format |
- {{ profiler_dump(data.default_data.norm) }} |
+ {{ profiler_dump(data.default_data.seek('norm')) }} |
View Format |
{% if data.default_data.view is defined %}
- {{ profiler_dump(data.default_data.view) }}
+ {{ profiler_dump(data.default_data.seek('view')) }}
{% else %}
same as normalized format
{% endif %}
@@ -571,7 +571,7 @@
| View Format |
{% if data.submitted_data.view is defined %}
- {{ profiler_dump(data.submitted_data.view) }}
+ {{ profiler_dump(data.submitted_data.seek('view')) }}
{% else %}
same as normalized format
{% endif %}
@@ -579,13 +579,13 @@
|
Normalized Format |
- {{ profiler_dump(data.submitted_data.norm) }} |
+ {{ profiler_dump(data.submitted_data.seek('norm')) }} |
Model Format |
{% if data.submitted_data.model is defined %}
- {{ profiler_dump(data.submitted_data.model) }}
+ {{ profiler_dump(data.submitted_data.seek('model')) }}
{% else %}
same as normalized format
{% endif %}
@@ -630,7 +630,7 @@
{% if resolved_option_value == option_value %}
same as passed value
{% else %}
- {{ profiler_dump(data.resolved_options[option]) }}
+ {{ profiler_dump(data.resolved_options.seek(option)) }}
{% endif %}
|
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
index c761b9a201..e4fa4c97b7 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
@@ -266,6 +266,9 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
try {
foreach ($items as $id => $value) {
+ if (!isset($keys[$id])) {
+ $id = key($keys);
+ }
$key = $keys[$id];
unset($keys[$id]);
yield $key => $f($key, $value, true);
diff --git a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
index 5c8784e69c..3acf8bdb86 100644
--- a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
@@ -19,6 +19,18 @@ class MemcachedAdapter extends AbstractAdapter
protected $maxIdLength = 250;
+ /**
+ * Constructor.
+ *
+ * Using a MemcachedAdapter with a TagAwareAdapter for storing tags is discouraged.
+ * Using a RedisAdapter is recommended instead. If you cannot do otherwise, be aware that:
+ * - the Memcached::OPT_BINARY_PROTOCOL must be enabled
+ * (that's the default when using MemcachedAdapter::createConnection());
+ * - tags eviction by Memcached's LRU algorithm will break by-tags invalidation;
+ * your Memcached memory should be large enough to never trigger LRU.
+ *
+ * Using a MemcachedAdapter as a pure items store is fine.
+ */
public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0)
{
$this->init($client, $namespace, $defaultLifetime);
diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
index 1d9dc7ce57..1e0617ebe2 100644
--- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
@@ -281,7 +281,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface
foreach ($items as $key => $item) {
if (!$tagKeys) {
- yield $key => $f($item, self::TAGS_PREFIX.$key, $itemTags);
+ yield $key => $f($item, static::TAGS_PREFIX.$key, $itemTags);
continue;
}
if (!isset($tagKeys[$key])) {
@@ -306,7 +306,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface
$tagVersions = $tagKeys = null;
foreach ($bufferedItems as $key => $item) {
- yield $key => $f($item, self::TAGS_PREFIX.$key, $itemTags);
+ yield $key => $f($item, static::TAGS_PREFIX.$key, $itemTags);
}
$bufferedItems = null;
}
diff --git a/src/Symfony/Component/Cache/Simple/AbstractCache.php b/src/Symfony/Component/Cache/Simple/AbstractCache.php
index 4c44b9b323..bbd35780fd 100644
--- a/src/Symfony/Component/Cache/Simple/AbstractCache.php
+++ b/src/Symfony/Component/Cache/Simple/AbstractCache.php
@@ -162,6 +162,9 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface
{
try {
foreach ($values as $id => $value) {
+ if (!isset($keys[$id])) {
+ $id = key($keys);
+ }
$key = $keys[$id];
unset($keys[$id]);
yield $key => $value;
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TraceableTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TraceableTagAwareAdapterTest.php
index 38f3c6c087..9b50bfabe6 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/TraceableTagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/TraceableTagAwareAdapterTest.php
@@ -15,6 +15,9 @@ use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
+/**
+ * @group time-sensitive
+ */
class TraceableTagAwareAdapterTest extends TraceableAdapterTest
{
public function testInvalidateTags()
diff --git a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
index 81d412bd66..b3799ebcda 100644
--- a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
@@ -15,6 +15,15 @@ use Cache\IntegrationTests\SimpleCacheTest;
abstract class CacheTestCase extends SimpleCacheTest
{
+ public static function validKeys()
+ {
+ if (defined('HHVM_VERSION')) {
+ return parent::validKeys();
+ }
+
+ return array_merge(parent::validKeys(), array(array("a\0b")));
+ }
+
public function testDefaultLifeTime()
{
if (isset($this->skippedTests[__FUNCTION__])) {
diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php
index 8877b0911a..f28da39346 100644
--- a/src/Symfony/Component/Cache/Traits/RedisTrait.php
+++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php
@@ -90,6 +90,11 @@ trait RedisTrait
$params['dbindex'] = $m[1];
$params['path'] = substr($params['path'], 0, -strlen($m[0]));
}
+ if (isset($params['host'])) {
+ $scheme = 'tcp';
+ } else {
+ $scheme = 'unix';
+ }
$params += array(
'host' => isset($params['host']) ? $params['host'] : $params['path'],
'port' => isset($params['host']) ? 6379 : null,
@@ -120,7 +125,7 @@ trait RedisTrait
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
}
} elseif (is_a($class, \Predis\Client::class, true)) {
- $params['scheme'] = isset($params['host']) ? 'tcp' : 'unix';
+ $params['scheme'] = $scheme;
$params['database'] = $params['dbindex'] ?: null;
$params['password'] = $auth;
$redis = new $class((new Factory())->create($params));
diff --git a/src/Symfony/Component/DependencyInjection/ChildDefinition.php b/src/Symfony/Component/DependencyInjection/ChildDefinition.php
index dd02f86067..5701caa474 100644
--- a/src/Symfony/Component/DependencyInjection/ChildDefinition.php
+++ b/src/Symfony/Component/DependencyInjection/ChildDefinition.php
@@ -62,7 +62,7 @@ class ChildDefinition extends Definition
* If replaceArgument() has been used to replace an argument, this method
* will return the replacement value.
*
- * @param int $index
+ * @param int|string $index
*
* @return mixed The argument value
*
@@ -74,13 +74,7 @@ class ChildDefinition extends Definition
return $this->arguments['index_'.$index];
}
- $lastIndex = count(array_filter(array_keys($this->arguments), 'is_int')) - 1;
-
- if ($index < 0 || $index > $lastIndex) {
- throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, $lastIndex));
- }
-
- return $this->arguments[$index];
+ return parent::getArgument($index);
}
/**
@@ -91,8 +85,8 @@ class ChildDefinition extends Definition
* certain conventions when you want to overwrite the arguments of the
* parent definition, otherwise your arguments will only be appended.
*
- * @param int $index
- * @param mixed $value
+ * @param int|string $index
+ * @param mixed $value
*
* @return self the current instance
*
@@ -105,7 +99,7 @@ class ChildDefinition extends Definition
} elseif (0 === strpos($index, '$')) {
$this->arguments[$index] = $value;
} else {
- throw new InvalidArgumentException('$index must be an integer.');
+ throw new InvalidArgumentException('The argument must be an existing index or the name of a constructor\'s parameter.');
}
return $this;
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index 840b670f16..6c2f1bf6e8 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -175,7 +175,7 @@ class PhpDumper extends Dumper
}
}
if ($unusedEnvs) {
- throw new EnvParameterException($unusedEnvs);
+ throw new EnvParameterException($unusedEnvs, null, 'Environment variables "%s" are never used. Please, check your container\'s configuration.');
}
return $code;
diff --git a/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php b/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php
index 44dbab45b6..3839a4633b 100644
--- a/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php
+++ b/src/Symfony/Component/DependencyInjection/Exception/EnvParameterException.php
@@ -18,8 +18,8 @@ namespace Symfony\Component\DependencyInjection\Exception;
*/
class EnvParameterException extends InvalidArgumentException
{
- public function __construct(array $usedEnvs, \Exception $previous = null)
+ public function __construct(array $envs, \Exception $previous = null, $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.')
{
- parent::__construct(sprintf('Incompatible use of dynamic environment variables "%s" found in parameters.', implode('", "', $usedEnvs)), 0, $previous);
+ parent::__construct(sprintf($message, implode('", "', $envs)), 0, $previous);
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/ChildDefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/ChildDefinitionTest.php
index a367a8b2c4..a941b96074 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/ChildDefinitionTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/ChildDefinitionTest.php
@@ -113,6 +113,10 @@ class ChildDefinitionTest extends TestCase
$this->assertSame('baz', $def->getArgument(1));
$this->assertSame(array(0 => 'foo', 1 => 'bar', 'index_1' => 'baz'), $def->getArguments());
+
+ $this->assertSame($def, $def->replaceArgument('$bar', 'val'));
+ $this->assertSame('val', $def->getArgument('$bar'));
+ $this->assertSame(array(0 => 'foo', 1 => 'bar', 'index_1' => 'baz', '$bar' => 'val'), $def->getArguments());
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index fe53b94100..bd8a95bab9 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -336,7 +336,7 @@ class PhpDumperTest extends TestCase
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\EnvParameterException
- * @expectedExceptionMessage Incompatible use of dynamic environment variables "FOO" found in parameters.
+ * @expectedExceptionMessage Environment variables "FOO" are never used. Please, check your container's configuration.
*/
public function testUnusedEnvParameter()
{
diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php
index a57dd86eaf..fc7b30f9cc 100644
--- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php
@@ -21,7 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* @author Bernhard Schussek
* @author Jordan Alliot
*
- * @deprecated since 3.3, to be removed in 4.0. Use EventDispatcher with closure-proxy injection instead.
+ * @deprecated since 3.3, to be removed in 4.0. Use EventDispatcher with closure factories instead.
*/
class ContainerAwareEventDispatcher extends EventDispatcher
{
@@ -60,7 +60,7 @@ class ContainerAwareEventDispatcher extends EventDispatcher
$class = get_parent_class($class);
}
if (__CLASS__ !== $class) {
- @trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use EventDispatcher with closure-proxy injection instead.', __CLASS__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED);
}
}
@@ -78,7 +78,7 @@ class ContainerAwareEventDispatcher extends EventDispatcher
*/
public function addListenerService($eventName, $callback, $priority = 0)
{
- @trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use EventDispatcher with closure-proxy injection instead.', __CLASS__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED);
if (!is_array($callback) || 2 !== count($callback)) {
throw new \InvalidArgumentException('Expected an array("service", "method") argument');
diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php
index 4360a62567..886cdee630 100644
--- a/src/Symfony/Component/Form/FormFactory.php
+++ b/src/Symfony/Component/Form/FormFactory.php
@@ -115,7 +115,13 @@ class FormFactory implements FormFactoryInterface
// user options may override guessed options
if ($typeGuess) {
- $options = array_merge($typeGuess->getOptions(), $options);
+ $attrs = array();
+ $typeGuessOptions = $typeGuess->getOptions();
+ if (isset($typeGuessOptions['attr']) && isset($options['attr'])) {
+ $attrs = array('attr' => array_merge($typeGuessOptions['attr'], $options['attr']));
+ }
+
+ $options = array_merge($typeGuessOptions, $options, $attrs);
}
return $this->createNamedBuilder($property, $type, $data, $options);
diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php
index 30aea951fb..6029f34a8c 100644
--- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php
+++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php
@@ -310,7 +310,7 @@ class FormFactoryTest extends TestCase
->with('Application\Author', 'firstName')
->will($this->returnValue(new TypeGuess(
'Symfony\Component\Form\Extension\Core\Type\TextType',
- array('attr' => array('maxlength' => 10)),
+ array('attr' => array('class' => 'foo', 'maxlength' => 10)),
Guess::MEDIUM_CONFIDENCE
)));
@@ -318,7 +318,7 @@ class FormFactoryTest extends TestCase
$factory->expects($this->once())
->method('createNamedBuilder')
- ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array('attr' => array('maxlength' => 11)))
+ ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array('attr' => array('class' => 'foo', 'maxlength' => 11)))
->will($this->returnValue('builderInstance'));
$this->builder = $factory->createBuilderForProperty(
diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md
index ac812fe152..e1fdf77b9b 100644
--- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md
+++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md
@@ -4,7 +4,7 @@ CHANGELOG
3.3.0
-----
- * [BC BREAK] the `Request::setTrustedProxies()` method takes a new `$trustedHeaderSet` argument,
+ * the `Request::setTrustedProxies()` method takes a new `$trustedHeaderSet` argument,
see http://symfony.com/doc/current/components/http_foundation/trusting_proxies.html for more info,
* deprecated the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` methods,
* added `File\Stream`, to be passed to `BinaryFileResponse` when the size of the served file is unknown,
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index 75d15df312..13ff1e0552 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -581,7 +581,7 @@ class Request
* You should only list the reverse proxies that you manage directly.
*
* @param array $proxies A list of trusted proxies
- * @param int $trustedHeaderSet A bit field of Request::HEADER_*, usually either Request::HEADER_FORWARDED or Request::HEADER_X_FORWARDED_ALL, to set which headers to trust from your proxies
+ * @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies
*
* @throws \InvalidArgumentException When $trustedHeaderSet is invalid
*/
@@ -590,10 +590,11 @@ class Request
self::$trustedProxies = $proxies;
if (2 > func_num_args()) {
- // @deprecated code path in 3.3, to be replaced by mandatory argument in 4.0.
- throw new \InvalidArgumentException(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument. Defining it is required since version 3.3. See http://symfony.com/doc/current/components/http_foundation/trusting_proxies.html for more info.', __METHOD__));
+ @trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since version 3.3. Defining it will be required in 4.0. ', __METHOD__), E_USER_DEPRECATED);
+
+ return;
}
- $trustedHeaderSet = func_get_arg(1);
+ $trustedHeaderSet = (int) func_get_arg(1);
foreach (self::$trustedHeaderNames as $header => $name) {
self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null;
@@ -665,11 +666,11 @@ class Request
*
* @throws \InvalidArgumentException
*
- * @deprecated since version 3.3, to be removed in 4.0. Use "X-Forwarded-*" headers or the "Forwarded" header defined in RFC7239, and the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
+ * @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
*/
public static function setTrustedHeaderName($key, $value)
{
- @trigger_error(sprintf('The "%s()" method is deprecated since version 3.3 and will be removed in 4.0. Use "X-Forwarded-*" headers or the "Forwarded" header defined in RFC7239, and the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since version 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED);
if (!array_key_exists($key, self::$trustedHeaders)) {
throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
@@ -679,6 +680,9 @@ class Request
if (null !== $value) {
self::$trustedHeaderNames[$key] = $value;
+ self::$trustedHeaderSet |= $key;
+ } else {
+ self::$trustedHeaderSet &= ~$key;
}
}
@@ -886,8 +890,8 @@ class Request
* adding the IP address where it received the request from.
*
* If your reverse proxy uses a different header name than "X-Forwarded-For",
- * ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with
- * the "client-ip" key.
+ * ("Client-Ip" for instance), configure it via the $trustedHeaderSet
+ * argument of the Request::setTrustedProxies() method instead.
*
* @return string|null The client IP address
*
@@ -993,7 +997,8 @@ class Request
* The "X-Forwarded-Port" header must contain the client port.
*
* If your reverse proxy uses a different header name than "X-Forwarded-Port",
- * configure it via "setTrustedHeaderName()" with the "client-port" key.
+ * configure it via via the $trustedHeaderSet argument of the
+ * Request::setTrustedProxies() method instead.
*
* @return int|string can be a string if fetched from the server bag
*/
@@ -1210,8 +1215,8 @@ class Request
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
*
* If your reverse proxy uses a different header name than "X-Forwarded-Proto"
- * ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
- * the "client-proto" key.
+ * ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet
+ * argument of the Request::setTrustedProxies() method instead.
*
* @return bool
*/
@@ -1235,7 +1240,8 @@ class Request
* The "X-Forwarded-Host" header must contain the client host name.
*
* If your reverse proxy uses a different header name than "X-Forwarded-Host",
- * configure it via "setTrustedHeaderName()" with the "client-host" key.
+ * configure it via the $trustedHeaderSet argument of the
+ * Request::setTrustedProxies() method instead.
*
* @return string
*
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
index 9042fc49ba..b36fbb7e96 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
@@ -1729,7 +1729,7 @@ class RequestTest extends TestCase
/**
* @group legacy
- * @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since version 3.3 and will be removed in 4.0. Use "X-Forwarded-*" headers or the "Forwarded" header defined in RFC7239, and the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
+ * @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since version 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.
*/
public function testLegacyTrustedProxies()
{
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
index 0eee6d94a4..82e7fa672f 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
@@ -43,7 +43,7 @@ abstract class AbstractToken implements TokenInterface
if (is_string($role)) {
$role = new Role($role);
} elseif (!$role instanceof RoleInterface) {
- throw new \InvalidArgumentException(sprintf('$roles must be an array of strings, or RoleInterface instances, but got %s.', gettype($role)));
+ throw new \InvalidArgumentException(sprintf('$roles must be an array of strings, Role instances or RoleInterface instances, but got %s.', gettype($role)));
}
$this->roles[] = $role;