+ {% endif %}
{% if data.errors is defined and data.errors|length > 0 %}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
index 59d28a33c1bea..1f2f4d40acfa0 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
@@ -192,4 +192,9 @@ public function provideDsnWithOptions()
array(\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8),
);
}
+
+ public function testClear()
+ {
+ $this->assertTrue($this->createCachePool()->clear());
+ }
}
diff --git a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
index cf04f1cf85664..8160f14116162 100644
--- a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
+++ b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
@@ -260,7 +260,7 @@ protected function doDelete(array $ids)
*/
protected function doClear($namespace)
{
- return false;
+ return '' === $namespace && $this->getClient()->flush();
}
private function checkResultCode($result)
diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php
index c9fa76cfe7058..138b4d38d8fe1 100644
--- a/src/Symfony/Component/Debug/DebugClassLoader.php
+++ b/src/Symfony/Component/Debug/DebugClassLoader.php
@@ -138,14 +138,14 @@ public function loadClass($class)
try {
if ($this->isFinder && !isset($this->loaded[$class])) {
$this->loaded[$class] = true;
- if ($file = $this->classLoader[0]->findFile($class) ?: false) {
- $wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file);
-
+ if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
+ // no-op
+ } elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
require $file;
- if ($wasCached) {
- return;
- }
+ return;
+ } else {
+ require $file;
}
} else {
\call_user_func($this->classLoader, $class);
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
index 05eb72d9746f4..a229022ed8a0b 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
@@ -127,13 +127,19 @@ private function isInlineableDefinition($id, Definition $definition, ServiceRefe
}
$ids = array();
+ $isReferencedByConstructor = false;
foreach ($graph->getNode($id)->getInEdges() as $edge) {
- if ($edge->isWeak()) {
+ $isReferencedByConstructor = $isReferencedByConstructor || $edge->isReferencedByConstructor();
+ if ($edge->isWeak() || $edge->isLazy()) {
return false;
}
$ids[] = $edge->getSourceNode()->getId();
}
+ if (!$ids) {
+ return true;
+ }
+
if (\count(array_unique($ids)) > 1) {
return false;
}
@@ -142,6 +148,10 @@ private function isInlineableDefinition($id, Definition $definition, ServiceRefe
return false;
}
- return !$ids || $this->container->getDefinition($ids[0])->isShared();
+ if ($isReferencedByConstructor && $this->container->getDefinition($ids[0])->isLazy() && ($definition->getProperties() || $definition->getMethodCalls() || $definition->getConfigurator())) {
+ return false;
+ }
+
+ return $this->container->getDefinition($ids[0])->isShared();
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index fd7eec05759b7..3a3c24d0445bd 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -155,17 +155,18 @@ public function dump(array $options = array())
}
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
+ $checkedNodes = array();
$this->circularReferences = array();
- foreach (array(true, false) as $byConstructor) {
- foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
- if (!$node->getValue() instanceof Definition) {
- continue;
- }
- $currentPath = array($id => true);
- $this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
+ foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
+ if (!$node->getValue() instanceof Definition) {
+ continue;
+ }
+ if (!isset($checkedNodes[$id])) {
+ $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes);
}
}
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
+ $checkedNodes = array();
$this->docStar = $options['debug'] ? '*' : '';
@@ -301,12 +302,12 @@ private function getProxyDumper()
return $this->proxyDumper;
}
- private function analyzeCircularReferences(array $edges, &$currentPath, $sourceId, $byConstructor)
+ private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = array())
{
+ $checkedNodes[$sourceId] = true;
+ $currentPath[$sourceId] = $sourceId;
+
foreach ($edges as $edge) {
- if ($byConstructor && !$edge->isReferencedByConstructor()) {
- continue;
- }
$node = $edge->getDestNode();
$id = $node->getId();
@@ -315,20 +316,42 @@ private function analyzeCircularReferences(array $edges, &$currentPath, $sourceI
} elseif (isset($currentPath[$id])) {
$currentId = $id;
foreach (array_reverse($currentPath) as $parentId) {
- if (!isset($this->circularReferences[$parentId][$currentId])) {
- $this->circularReferences[$parentId][$currentId] = $byConstructor;
+ $this->circularReferences[$parentId][$currentId] = $currentId;
+ if ($parentId === $id) {
+ break;
}
+ $currentId = $parentId;
+ }
+ } elseif (!isset($checkedNodes[$id])) {
+ $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath);
+ } elseif (isset($this->circularReferences[$id])) {
+ $this->connectCircularReferences($id, $currentPath);
+ }
+ }
+ unset($currentPath[$sourceId]);
+ }
+
+ private function connectCircularReferences($sourceId, &$currentPath, &$subPath = array())
+ {
+ $subPath[$sourceId] = $sourceId;
+ $currentPath[$sourceId] = $sourceId;
+
+ foreach ($this->circularReferences[$sourceId] as $id) {
+ if (isset($currentPath[$id])) {
+ $currentId = $id;
+ foreach (array_reverse($currentPath) as $parentId) {
+ $this->circularReferences[$parentId][$currentId] = $currentId;
if ($parentId === $id) {
break;
}
$currentId = $parentId;
}
- } else {
- $currentPath[$id] = $id;
- $this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
- unset($currentPath[$id]);
+ } elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
+ $this->connectCircularReferences($id, $currentPath, $subPath);
}
}
+ unset($currentPath[$sourceId]);
+ unset($subPath[$sourceId]);
}
private function collectLineage($class, array &$lineage)
@@ -569,7 +592,8 @@ private function addServiceConfigurator(Definition $definition, $variableName =
if (\is_array($callable)) {
if ($callable[0] instanceof Reference
- || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
+ || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
+ ) {
return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
@@ -724,7 +748,7 @@ private function addInlineReference($id, Definition $definition, $targetId, $for
$hasSelfRef = isset($this->circularReferences[$id][$targetId]);
$forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]);
- $code = $hasSelfRef && $this->circularReferences[$id][$targetId] && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
+ $code = $hasSelfRef && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
return $code;
@@ -1798,6 +1822,7 @@ private function getServiceCall($id, Reference $reference = null)
if ($definition->isShared()) {
$code = sprintf('$this->services[\'%s\'] = %s', $id, $code);
}
+ $code = "($code)";
} elseif ($this->asFiles && $definition->isShared() && !$this->isHotPath($definition)) {
$code = sprintf("\$this->load('%s.php')", $this->generateMethodName($id));
} else {
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 51c5fd21f6e87..60fa55c3b5451 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -752,7 +752,7 @@ public function testExpressionReferencingPrivateService()
->setPublic(false);
$container->register('public_foo', 'stdClass')
->setPublic(true)
- ->addArgument(new Expression('service("private_foo")'));
+ ->addArgument(new Expression('service("private_foo").bar'));
$container->compile();
$dumper = new PhpDumper($container);
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php
index ad316b23c6ee9..fc04f5faeece0 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php
@@ -126,7 +126,7 @@ protected function getConfiguredServiceSimpleService()
{
$this->services['configured_service_simple'] = $instance = new \stdClass();
- ${($_ = isset($this->services['configurator_service_simple']) ? $this->services['configurator_service_simple'] : $this->services['configurator_service_simple'] = new \ConfClass('bar')) && false ?: '_'}->configureStdClass($instance);
+ ${($_ = isset($this->services['configurator_service_simple']) ? $this->services['configurator_service_simple'] : ($this->services['configurator_service_simple'] = new \ConfClass('bar'))) && false ?: '_'}->configureStdClass($instance);
return $instance;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt
index 4b6e2f59e65a1..fa032cbc1f94d 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt
@@ -243,7 +243,7 @@ use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->load('getFooService.php')) && false ?: '_'};
- yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : $this->services['tagged_iterator_foo'] = new \Bar()) && false ?: '_'};
+ yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : ($this->services['tagged_iterator_foo'] = new \Bar())) && false ?: '_'};
}, 2));
[Container%s/getTaggedIteratorFooService.php] => services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'};
- yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : $this->services['tagged_iterator_foo'] = new \Bar()) && false ?: '_'};
+ yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : ($this->services['tagged_iterator_foo'] = new \Bar())) && false ?: '_'};
}, 2));
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
index 9c54acc6bea3b..8aa4a2c406b6f 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
@@ -331,7 +331,7 @@ protected function getManager2Service()
*/
protected function getRootService()
{
- return $this->services['root'] = new \stdClass(${($_ = isset($this->services['level2']) ? $this->services['level2'] : $this->getLevel2Service()) && false ?: '_'}, ${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : $this->services['multiuse1'] = new \stdClass()) && false ?: '_'});
+ return $this->services['root'] = new \stdClass(${($_ = isset($this->services['level2']) ? $this->services['level2'] : $this->getLevel2Service()) && false ?: '_'}, ${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'});
}
/**
@@ -397,7 +397,7 @@ protected function getLevel3Service()
*/
protected function getLevel4Service()
{
- return $this->services['level4'] = new \stdClass(${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : $this->services['multiuse1'] = new \stdClass()) && false ?: '_'}, ${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'});
+ return $this->services['level4'] = new \stdClass(${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'}, ${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'});
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
index bd08c4d15f67b..a5de37f12c931 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
@@ -126,7 +126,7 @@ protected function getBar3Service()
{
$this->services['bar3'] = $instance = new \BarCircular();
- $a = ${($_ = isset($this->services['foobar3']) ? $this->services['foobar3'] : $this->services['foobar3'] = new \FoobarCircular()) && false ?: '_'};
+ $a = ${($_ = isset($this->services['foobar3']) ? $this->services['foobar3'] : ($this->services['foobar3'] = new \FoobarCircular())) && false ?: '_'};
$instance->addFoobar($a, $a);
@@ -431,7 +431,7 @@ protected function getManager2Service()
*/
protected function getRootService()
{
- return $this->services['root'] = new \stdClass(${($_ = isset($this->services['level2']) ? $this->services['level2'] : $this->getLevel2Service()) && false ?: '_'}, ${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : $this->services['multiuse1'] = new \stdClass()) && false ?: '_'});
+ return $this->services['root'] = new \stdClass(${($_ = isset($this->services['level2']) ? $this->services['level2'] : $this->getLevel2Service()) && false ?: '_'}, ${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'});
}
/**
@@ -497,7 +497,7 @@ protected function getLevel3Service()
*/
protected function getLevel4Service()
{
- return $this->services['level4'] = new \stdClass(${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : $this->services['multiuse1'] = new \stdClass()) && false ?: '_'}, ${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'});
+ return $this->services['level4'] = new \stdClass(${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'}, ${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'});
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php
index 91114fd9788e6..dab23e1dbcc12 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_env_in_id.php
@@ -73,7 +73,7 @@ public function isFrozen()
*/
protected function getBarService()
{
- return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : $this->services['bar_%env(BAR)%'] = new \stdClass()) && false ?: '_'});
+ return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : ($this->services['bar_%env(BAR)%'] = new \stdClass())) && false ?: '_'});
}
/**
@@ -83,7 +83,7 @@ protected function getBarService()
*/
protected function getFooService()
{
- return $this->services['foo'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : $this->services['bar_%env(BAR)%'] = new \stdClass()) && false ?: '_'}, array('baz_'.$this->getEnv('string:BAR') => new \stdClass()));
+ return $this->services['foo'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : ($this->services['bar_%env(BAR)%'] = new \stdClass())) && false ?: '_'}, array('baz_'.$this->getEnv('string:BAR') => new \stdClass()));
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php
index 08a474eea33d8..c6927eb95d653 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php
@@ -110,7 +110,7 @@ protected function getC2Service()
include_once $this->targetDirs[1].'/includes/HotPath/C2.php';
include_once $this->targetDirs[1].'/includes/HotPath/C3.php';
- return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3'] : $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3()) && false ?: '_'});
+ return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3'] : ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3())) && false ?: '_'});
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_legacy_privates.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_legacy_privates.php
index 7aa1bff87069a..d720ae396f890 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_legacy_privates.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_legacy_privates.php
@@ -98,7 +98,7 @@ public function isFrozen()
*/
protected function getBarService()
{
- return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['private_not_inlined']) ? $this->services['private_not_inlined'] : $this->services['private_not_inlined'] = new \stdClass()) && false ?: '_'});
+ return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['private_not_inlined']) ? $this->services['private_not_inlined'] : ($this->services['private_not_inlined'] = new \stdClass())) && false ?: '_'});
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_locator.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_locator.php
index 496f6aa77d306..c436aea407c83 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_locator.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_locator.php
@@ -76,7 +76,7 @@ public function isFrozen()
*/
protected function getBarServiceService()
{
- return $this->services['bar_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : $this->services['baz_service'] = new \stdClass()) && false ?: '_'});
+ return $this->services['bar_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'});
}
/**
@@ -89,7 +89,7 @@ protected function getFooServiceService()
return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\ServiceLocator(array('bar' => function () {
return ${($_ = isset($this->services['bar_service']) ? $this->services['bar_service'] : $this->getBarServiceService()) && false ?: '_'};
}, 'baz' => function () {
- $f = function (\stdClass $v) { return $v; }; return $f(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : $this->services['baz_service'] = new \stdClass()) && false ?: '_'});
+ $f = function (\stdClass $v) { return $v; }; return $f(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'});
}, 'nil' => function () {
return NULL;
}));
@@ -133,7 +133,7 @@ protected function getTranslator_Loader3Service()
protected function getTranslator1Service()
{
return $this->services['translator_1'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator(new \Symfony\Component\DependencyInjection\ServiceLocator(array('translator.loader_1' => function () {
- return ${($_ = isset($this->services['translator.loader_1']) ? $this->services['translator.loader_1'] : $this->services['translator.loader_1'] = new \stdClass()) && false ?: '_'};
+ return ${($_ = isset($this->services['translator.loader_1']) ? $this->services['translator.loader_1'] : ($this->services['translator.loader_1'] = new \stdClass())) && false ?: '_'};
})));
}
@@ -145,10 +145,10 @@ protected function getTranslator1Service()
protected function getTranslator2Service()
{
$this->services['translator_2'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator(new \Symfony\Component\DependencyInjection\ServiceLocator(array('translator.loader_2' => function () {
- return ${($_ = isset($this->services['translator.loader_2']) ? $this->services['translator.loader_2'] : $this->services['translator.loader_2'] = new \stdClass()) && false ?: '_'};
+ return ${($_ = isset($this->services['translator.loader_2']) ? $this->services['translator.loader_2'] : ($this->services['translator.loader_2'] = new \stdClass())) && false ?: '_'};
})));
- $instance->addResource('db', ${($_ = isset($this->services['translator.loader_2']) ? $this->services['translator.loader_2'] : $this->services['translator.loader_2'] = new \stdClass()) && false ?: '_'}, 'nl');
+ $instance->addResource('db', ${($_ = isset($this->services['translator.loader_2']) ? $this->services['translator.loader_2'] : ($this->services['translator.loader_2'] = new \stdClass())) && false ?: '_'}, 'nl');
return $instance;
}
@@ -161,10 +161,10 @@ protected function getTranslator2Service()
protected function getTranslator3Service()
{
$this->services['translator_3'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator(new \Symfony\Component\DependencyInjection\ServiceLocator(array('translator.loader_3' => function () {
- return ${($_ = isset($this->services['translator.loader_3']) ? $this->services['translator.loader_3'] : $this->services['translator.loader_3'] = new \stdClass()) && false ?: '_'};
+ return ${($_ = isset($this->services['translator.loader_3']) ? $this->services['translator.loader_3'] : ($this->services['translator.loader_3'] = new \stdClass())) && false ?: '_'};
})));
- $a = ${($_ = isset($this->services['translator.loader_3']) ? $this->services['translator.loader_3'] : $this->services['translator.loader_3'] = new \stdClass()) && false ?: '_'};
+ $a = ${($_ = isset($this->services['translator.loader_3']) ? $this->services['translator.loader_3'] : ($this->services['translator.loader_3'] = new \stdClass())) && false ?: '_'};
$instance->addResource('db', $a, 'nl');
$instance->addResource('db', $a, 'en');
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_frozen.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_frozen.php
index 1275e9f2642a3..8ef589c127c54 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_frozen.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_frozen.php
@@ -67,7 +67,7 @@ public function isFrozen()
*/
protected function getBarServiceService()
{
- return $this->services['bar_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : $this->services['baz_service'] = new \stdClass()) && false ?: '_'});
+ return $this->services['bar_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'});
}
/**
@@ -77,7 +77,7 @@ protected function getBarServiceService()
*/
protected function getFooServiceService()
{
- return $this->services['foo_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : $this->services['baz_service'] = new \stdClass()) && false ?: '_'});
+ return $this->services['foo_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'});
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_in_expression.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_in_expression.php
index fe84f49753c52..75cbc2730b056 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_in_expression.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_private_in_expression.php
@@ -67,7 +67,7 @@ public function isFrozen()
*/
protected function getPublicFooService()
{
- return $this->services['public_foo'] = new \stdClass(${($_ = isset($this->services['private_foo']) ? $this->services['private_foo'] : $this->services['private_foo'] = new \stdClass()) && false ?: '_'});
+ return $this->services['public_foo'] = new \stdClass(${($_ = isset($this->services['private_foo']) ? $this->services['private_foo'] : ($this->services['private_foo'] = new \stdClass())) && false ?: '_'}->bar);
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php
index 90836aa90debd..efbb0023164b1 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php
@@ -78,7 +78,7 @@ protected function getRot13EnvVarProcessorService()
protected function getContainer_EnvVarProcessorsLocatorService()
{
return $this->services['container.env_var_processors_locator'] = new \Symfony\Component\DependencyInjection\ServiceLocator(array('rot13' => function () {
- return ${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor'] : $this->services['Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor()) && false ?: '_'};
+ return ${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor'] : ($this->services['Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor())) && false ?: '_'};
}));
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php
index 9475c923068f2..8f198f0ba8355 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php
@@ -84,13 +84,13 @@ protected function getTestServiceSubscriberService()
protected function getFooServiceService()
{
return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber((new \Symfony\Component\DependencyInjection\ServiceLocator(array('Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => function () {
- $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition()) && false ?: '_'});
+ $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition())) && false ?: '_'});
}, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => function () {
- $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber()) && false ?: '_'});
+ $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber())) && false ?: '_'});
}, 'bar' => function () {
- $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber()) && false ?: '_'});
+ $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber())) && false ?: '_'});
}, 'baz' => function () {
- $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition()) && false ?: '_'});
+ $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : ($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition())) && false ?: '_'});
})))->withContext('foo_service', $this));
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_uninitialized_ref.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_uninitialized_ref.php
index 4d0c00b289138..c53e336d278bd 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_uninitialized_ref.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_uninitialized_ref.php
@@ -107,7 +107,7 @@ protected function getBazService()
{
$this->services['baz'] = $instance = new \stdClass();
- $instance->foo3 = ${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : $this->services['foo3'] = new \stdClass()) && false ?: '_'};
+ $instance->foo3 = ${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : ($this->services['foo3'] = new \stdClass())) && false ?: '_'};
return $instance;
}
diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
index 7577b85a12136..967bb9fba10ee 100644
--- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
@@ -132,19 +132,24 @@ public function dispatch($eventName, Event $event = null)
}
$this->preProcess($eventName);
- $this->preDispatch($eventName, $event);
-
- $e = $this->stopwatch->start($eventName, 'section');
-
- $this->dispatcher->dispatch($eventName, $event);
-
- if ($e->isStarted()) {
- $e->stop();
+ try {
+ $this->preDispatch($eventName, $event);
+ try {
+ $e = $this->stopwatch->start($eventName, 'section');
+ try {
+ $this->dispatcher->dispatch($eventName, $event);
+ } finally {
+ if ($e->isStarted()) {
+ $e->stop();
+ }
+ }
+ } finally {
+ $this->postDispatch($eventName, $event);
+ }
+ } finally {
+ $this->postProcess($eventName);
}
- $this->postDispatch($eventName, $event);
- $this->postProcess($eventName);
-
return $event;
}
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
index 9e03606a3ec70..3e125bc82be36 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
@@ -146,7 +146,7 @@ public function reverseTransform($value)
return;
}
- if ('NaN' === $value) {
+ if (\in_array($value, array('NaN', 'NAN', 'nan'), true)) {
throw new TransformationFailedException('"NaN" is not a valid number');
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
index 1b699d51e84ab..56fcfe17e9bf7 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php
@@ -105,6 +105,7 @@ public function configureOptions(OptionsResolver $resolver)
'data_class' => $dataClass,
'empty_data' => $emptyData,
'multiple' => false,
+ 'allow_file_upload' => true,
));
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 363fd46590271..89b9dd8ff5335 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -178,6 +178,7 @@ public function configureOptions(OptionsResolver $resolver)
'attr' => array(),
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
'upload_max_size_message' => $uploadMaxSizeMessage, // internal
+ 'allow_file_upload' => false,
));
$resolver->setAllowedTypes('label_attr', 'array');
diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php
index 8b15447d1b27a..f3cfc7212ac17 100644
--- a/src/Symfony/Component/Form/Form.php
+++ b/src/Symfony/Component/Form/Form.php
@@ -532,6 +532,11 @@ public function submit($submittedData, $clearMissing = true)
$submittedData = null;
} elseif (is_scalar($submittedData)) {
$submittedData = (string) $submittedData;
+ } elseif ($this->config->getOption('allow_file_upload')) {
+ // no-op
+ } elseif ($this->config->getRequestHandler()->isFileUpload($submittedData)) {
+ $submittedData = null;
+ $this->transformationFailure = new TransformationFailedException('Submitted data was expected to be text or number, file upload given.');
}
$dispatcher = $this->config->getEventDispatcher();
@@ -541,6 +546,10 @@ public function submit($submittedData, $clearMissing = true)
$viewData = null;
try {
+ if (null !== $this->transformationFailure) {
+ throw $this->transformationFailure;
+ }
+
// Hook to change content of the data submitted by the browser
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
$event = new FormEvent($this, $submittedData);
diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php
index 336593f7f7639..4a6590ded5af3 100644
--- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php
+++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php
@@ -707,7 +707,7 @@ public function testSubmitPostOrPutRequestWithSingleChildForm($method)
'REQUEST_METHOD' => $method,
));
- $form = $this->getBuilder('image')
+ $form = $this->getBuilder('image', null, null, array('allow_file_upload' => true))
->setMethod($method)
->setRequestHandler(new HttpFoundationRequestHandler())
->getForm();
@@ -1036,6 +1036,21 @@ public function testDisabledButtonIsNotSubmitted()
$this->assertFalse($submit->isSubmitted());
}
+ public function testFileUpload()
+ {
+ $reqHandler = new HttpFoundationRequestHandler();
+ $this->form->add($this->getBuilder('foo')->setRequestHandler($reqHandler)->getForm());
+ $this->form->add($this->getBuilder('bar')->setRequestHandler($reqHandler)->getForm());
+
+ $this->form->submit(array(
+ 'foo' => 'Foo',
+ 'bar' => new UploadedFile(__FILE__, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK),
+ ));
+
+ $this->assertSame('Submitted data was expected to be text or number, file upload given.', $this->form->get('bar')->getTransformationFailure()->getMessage());
+ $this->assertNull($this->form->get('bar')->getData());
+ }
+
protected function createForm()
{
return $this->getBuilder()
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php
index d6a4662102232..176d3a9a58f9e 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php
@@ -514,24 +514,24 @@ public function testReverseTransformExpectsValidNumber()
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
+ * @dataProvider nanRepresentationProvider
*
* @see https://github.com/symfony/symfony/issues/3161
*/
- public function testReverseTransformDisallowsNaN()
+ public function testReverseTransformDisallowsNaN($nan)
{
$transformer = new NumberToLocalizedStringTransformer();
- $transformer->reverseTransform('NaN');
+ $transformer->reverseTransform($nan);
}
- /**
- * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
- */
- public function testReverseTransformDisallowsNaN2()
+ public function nanRepresentationProvider()
{
- $transformer = new NumberToLocalizedStringTransformer();
-
- $transformer->reverseTransform('nan');
+ return array(
+ array('nan'),
+ array('NaN'), // see https://github.com/symfony/symfony/issues/3161
+ array('NAN'),
+ );
}
/**
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json
index 6aba3b60ecb12..e9c1a0f4963e8 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json
@@ -29,6 +29,7 @@
"parent": {
"Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType": [
"action",
+ "allow_file_upload",
"attr",
"auto_initialize",
"block_name",
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt
index 874dede77f7f5..92759b1b0b467 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt
@@ -8,16 +8,17 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
choice_attr FormType FormType FormTypeCsrfExtension
choice_label -------------------- ------------------------- -----------------------
choice_loader compound action csrf_field_name
- choice_name data_class attr csrf_message
- choice_translation_domain empty_data auto_initialize csrf_protection
- choice_value error_bubbling block_name csrf_token_id
- choices trim by_reference csrf_token_manager
- choices_as_values data
- expanded disabled
- group_by inherit_data
- multiple label
- placeholder label_attr
- preferred_choices label_format
+ choice_name data_class allow_file_upload csrf_message
+ choice_translation_domain empty_data attr csrf_protection
+ choice_value error_bubbling auto_initialize csrf_token_id
+ choices trim block_name csrf_token_manager
+ choices_as_values by_reference
+ expanded data
+ group_by disabled
+ multiple inherit_data
+ placeholder label
+ preferred_choices label_attr
+ label_format
mapped
method
post_max_size_message
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json
index bdefb5c946626..6c18e7169f394 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json
@@ -4,6 +4,7 @@
"options": {
"own": [
"action",
+ "allow_file_upload",
"attr",
"auto_initialize",
"block_name",
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt
index 72b13dfef75aa..24dfb07e074d5 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt
@@ -6,6 +6,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
Options
-------------------------
action
+ allow_file_upload
attr
auto_initialize
block_name
diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php
index 36c673093bcc8..f34d9b32251b3 100644
--- a/src/Symfony/Component/HttpKernel/HttpKernel.php
+++ b/src/Symfony/Component/HttpKernel/HttpKernel.php
@@ -263,6 +263,9 @@ private function handleException(\Exception $e, $request, $type)
}
}
+ /**
+ * Returns a human-readable string for the specified variable.
+ */
private function varToString($var)
{
if (\is_object($var)) {
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index bfc961f50511f..faea3086e5420 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -67,11 +67,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private $requestStackSize = 0;
private $resetServices = false;
- const VERSION = '3.4.19';
- const VERSION_ID = 30419;
+ const VERSION = '3.4.20';
+ const VERSION_ID = 30420;
const MAJOR_VERSION = 3;
const MINOR_VERSION = 4;
- const RELEASE_VERSION = 19;
+ const RELEASE_VERSION = 20;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '11/2020';
diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
index b598d49d3e83f..0d7c3df0decfb 100644
--- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
+++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
@@ -638,8 +638,8 @@ public function setSymbol($attr, $value)
/**
* Not supported. Set a text attribute.
*
- * @param int $attr An attribute specifier, one of the text attribute constants
- * @param int $value The attribute value
+ * @param int $attr An attribute specifier, one of the text attribute constants
+ * @param string $value The attribute value
*
* @return bool true on success or false on failure
*
diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
index 90e4c234fb1dd..2e358f458600b 100644
--- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
+++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
@@ -687,7 +687,8 @@ private function writeCollection($zval, $property, $collection, $addMethod, $rem
*/
private function getWriteAccessInfo($class, $property, $value)
{
- $key = str_replace('\\', '.', $class).'..'.$property;
+ $useAdderAndRemover = \is_array($value) || $value instanceof \Traversable;
+ $key = str_replace('\\', '.', $class).'..'.$property.'..'.(int) $useAdderAndRemover;
if (isset($this->writePropertyCache[$key])) {
return $this->writePropertyCache[$key];
@@ -707,6 +708,16 @@ private function getWriteAccessInfo($class, $property, $value)
$camelized = $this->camelize($property);
$singulars = (array) Inflector::singularize($camelized);
+ if ($useAdderAndRemover) {
+ $methods = $this->findAdderAndRemover($reflClass, $singulars);
+
+ if (null !== $methods) {
+ $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER;
+ $access[self::ACCESS_ADDER] = $methods[0];
+ $access[self::ACCESS_REMOVER] = $methods[1];
+ }
+ }
+
if (!isset($access[self::ACCESS_TYPE])) {
$setter = 'set'.$camelized;
$getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item)
@@ -728,22 +739,16 @@ private function getWriteAccessInfo($class, $property, $value)
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC;
$access[self::ACCESS_NAME] = $setter;
} elseif (null !== $methods = $this->findAdderAndRemover($reflClass, $singulars)) {
- if (\is_array($value) || $value instanceof \Traversable) {
- $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER;
- $access[self::ACCESS_ADDER] = $methods[0];
- $access[self::ACCESS_REMOVER] = $methods[1];
- } else {
- $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
- $access[self::ACCESS_NAME] = sprintf(
- 'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
- 'the new value must be an array or an instance of \Traversable, '.
- '"%s" given.',
- $property,
- $reflClass->name,
- implode('()", "', $methods),
- \is_object($value) ? \get_class($value) : \gettype($value)
- );
- }
+ $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
+ $access[self::ACCESS_NAME] = sprintf(
+ 'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
+ 'the new value must be an array or an instance of \Traversable, '.
+ '"%s" given.',
+ $property,
+ $reflClass->name,
+ implode('()", "', $methods),
+ \is_object($value) ? \get_class($value) : \gettype($value)
+ );
} else {
$access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND;
$access[self::ACCESS_NAME] = sprintf(
@@ -783,6 +788,18 @@ private function isPropertyWritable($object, $property)
$access = $this->getWriteAccessInfo(\get_class($object), $property, array());
+ $isWritable = self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE]
+ || self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE]
+ || self::ACCESS_TYPE_ADDER_AND_REMOVER === $access[self::ACCESS_TYPE]
+ || (!$access[self::ACCESS_HAS_PROPERTY] && property_exists($object, $property))
+ || self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE];
+
+ if ($isWritable) {
+ return true;
+ }
+
+ $access = $this->getWriteAccessInfo(\get_class($object), $property, '');
+
return self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE]
|| self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE]
|| self::ACCESS_TYPE_ADDER_AND_REMOVER === $access[self::ACCESS_TYPE]
diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php
index cf6152380d1f2..894fbd5c0df0e 100644
--- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php
+++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php
@@ -719,7 +719,27 @@ public function testWriteToPluralPropertyWhileSingularOneExists()
$this->propertyAccessor->isWritable($object, 'emails'); //cache access info
$this->propertyAccessor->setValue($object, 'emails', array('test@email.com'));
- self::assertEquals(array('test@email.com'), $object->getEmails());
- self::assertNull($object->getEmail());
+ $this->assertEquals(array('test@email.com'), $object->getEmails());
+ $this->assertNull($object->getEmail());
+ }
+
+ public function testAdderAndRemoverArePreferredOverSetter()
+ {
+ $object = new TestPluralAdderRemoverAndSetter();
+
+ $this->propertyAccessor->isWritable($object, 'emails'); //cache access info
+ $this->propertyAccessor->setValue($object, 'emails', array('test@email.com'));
+
+ $this->assertEquals(array('test@email.com'), $object->getEmails());
+ }
+
+ public function testAdderAndRemoverArePreferredOverSetterForSameSingularAndPlural()
+ {
+ $object = new TestPluralAdderRemoverAndSetterSameSingularAndPlural();
+
+ $this->propertyAccessor->isWritable($object, 'aircraft'); //cache access info
+ $this->propertyAccessor->setValue($object, 'aircraft', array('aeroplane'));
+
+ $this->assertEquals(array('aeroplane'), $object->getAircraft());
}
}
diff --git a/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php
new file mode 100644
index 0000000000000..ecb3f9b4a9d32
--- /dev/null
+++ b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\PropertyAccess\Tests;
+
+class TestPluralAdderRemoverAndSetter
+{
+ private $emails = array();
+
+ public function getEmails()
+ {
+ return $this->emails;
+ }
+
+ public function setEmails(array $emails)
+ {
+ $this->emails = array('foo@email.com');
+ }
+
+ public function addEmail($email)
+ {
+ $this->emails[] = $email;
+ }
+
+ public function removeEmail($email)
+ {
+ $this->emails = array_diff($this->emails, array($email));
+ }
+}
diff --git a/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php
new file mode 100644
index 0000000000000..bb3b4f4688dc5
--- /dev/null
+++ b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php
@@ -0,0 +1,28 @@
+aircraft;
+ }
+
+ public function setAircraft(array $aircraft)
+ {
+ $this->aircraft = array('plane');
+ }
+
+ public function addAircraft($aircraft)
+ {
+ $this->aircraft[] = $aircraft;
+ }
+
+ public function removeAircraft($aircraft)
+ {
+ $this->aircraft = array_diff($this->aircraft, array($aircraft));
+ }
+}
diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
index 69d73906fe4ef..4b6494288ec6e 100644
--- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
+++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php
@@ -118,19 +118,24 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac
*/
protected function matchCollection($pathinfo, RouteCollection $routes)
{
+ // HEAD and GET are equivalent as per RFC
+ if ('HEAD' === $method = $this->context->getMethod()) {
+ $method = 'GET';
+ }
$supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;
foreach ($routes as $name => $route) {
$compiledRoute = $route->compile();
$staticPrefix = $compiledRoute->getStaticPrefix();
+ $requiredMethods = $route->getMethods();
// check the static prefix of the URL first. Only use the more expensive preg_match when it matches
if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
// no-op
- } elseif (!$supportsTrailingSlash) {
+ } elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods)) || 'GET' !== $method) {
continue;
} elseif ('/' === substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) {
- return;
+ return $this->allow = array();
} else {
continue;
}
@@ -148,7 +153,10 @@ protected function matchCollection($pathinfo, RouteCollection $routes)
}
if ($hasTrailingSlash && '/' !== substr($pathinfo, -1)) {
- return;
+ if ((!$requiredMethods || \in_array('GET', $requiredMethods)) && 'GET' === $method) {
+ return $this->allow = array();
+ }
+ continue;
}
$hostMatches = array();
@@ -163,12 +171,7 @@ protected function matchCollection($pathinfo, RouteCollection $routes)
}
// check HTTP method requirement
- if ($requiredMethods = $route->getMethods()) {
- // HEAD and GET are equivalent as per RFC
- if ('HEAD' === $method = $this->context->getMethod()) {
- $method = 'GET';
- }
-
+ if ($requiredMethods) {
if (!\in_array($method, $requiredMethods)) {
if (self::REQUIREMENT_MATCH === $status[0]) {
$this->allow = array_merge($this->allow, $requiredMethods);
@@ -180,6 +183,8 @@ protected function matchCollection($pathinfo, RouteCollection $routes)
return $this->getAttributes($route, $name, array_replace($matches, $hostMatches, isset($status[1]) ? $status[1] : array()));
}
+
+ return array();
}
/**
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
index a7aea0ec071d2..9857f05024d72 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
@@ -128,6 +128,23 @@ public function testFallbackPage()
$this->assertSame(array('_route' => 'foo'), $matcher->match('/foo'));
}
+ public function testSlashAndVerbPrecedenceWithRedirection()
+ {
+ $coll = new RouteCollection();
+ $coll->add('a', new Route('/api/customers/{customerId}/contactpersons', array(), array(), array(), '', array(), array('post')));
+ $coll->add('b', new Route('/api/customers/{customerId}/contactpersons/', array(), array(), array(), '', array(), array('get')));
+
+ $matcher = $this->getUrlMatcher($coll);
+ $expected = array(
+ '_route' => 'b',
+ 'customerId' => '123',
+ );
+ $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons/'));
+
+ $matcher->expects($this->once())->method('redirect')->with('/api/customers/123/contactpersons/')->willReturn(array());
+ $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons'));
+ }
+
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($routes, $context ?: new RequestContext()));
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
index 0d4b44b090704..85647f0bead22 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
@@ -502,6 +502,31 @@ public function testSchemeAndMethodMismatch()
$matcher->match('/');
}
+ public function testSlashAndVerbPrecedence()
+ {
+ $coll = new RouteCollection();
+ $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', array(), array(), array(), '', array(), array('post')));
+ $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', array(), array(), array(), '', array(), array('get')));
+
+ $matcher = $this->getUrlMatcher($coll);
+ $expected = array(
+ '_route' => 'b',
+ 'customerId' => '123',
+ );
+ $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons'));
+
+ $coll = new RouteCollection();
+ $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', array(), array(), array(), '', array(), array('get')));
+ $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', array(), array(), array(), '', array(), array('post')));
+
+ $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'POST'));
+ $expected = array(
+ '_route' => 'b',
+ 'customerId' => '123',
+ );
+ $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons'));
+ }
+
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return new UrlMatcher($routes, $context ?: new RequestContext());
diff --git a/src/Symfony/Component/Security/Http/HttpUtils.php b/src/Symfony/Component/Security/Http/HttpUtils.php
index a6bcffe4852dc..49ccc723b451f 100644
--- a/src/Symfony/Component/Security/Http/HttpUtils.php
+++ b/src/Symfony/Component/Security/Http/HttpUtils.php
@@ -59,7 +59,7 @@ public function __construct(UrlGeneratorInterface $urlGenerator = null, $urlMatc
*/
public function createRedirectResponse(Request $request, $path, $status = 302)
{
- if (null !== $this->domainRegexp && preg_match('#^https?://[^/]++#i', $path, $host) && !preg_match(sprintf($this->domainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
+ if (null !== $this->domainRegexp && preg_match('#^https?:[/\\\\]{2,}+[^/]++#i', $path, $host) && !preg_match(sprintf($this->domainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
$path = '/';
}
diff --git a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php
index 28b242995d4bf..a0d6f79714414 100644
--- a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php
@@ -54,14 +54,28 @@ public function testCreateRedirectResponseWithRequestsDomain()
$this->assertTrue($response->isRedirect('http://localhost/blog'));
}
- public function testCreateRedirectResponseWithBadRequestsDomain()
+ /**
+ * @dataProvider badRequestDomainUrls
+ */
+ public function testCreateRedirectResponseWithBadRequestsDomain($url)
{
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');
- $response = $utils->createRedirectResponse($this->getRequest(), 'http://pirate.net/foo');
+ $response = $utils->createRedirectResponse($this->getRequest(), $url);
$this->assertTrue($response->isRedirect('http://localhost/'));
}
+ public function badRequestDomainUrls()
+ {
+ return array(
+ array('http://pirate.net/foo'),
+ array('http:\\\\pirate.net/foo'),
+ array('http:/\\pirate.net/foo'),
+ array('http:\\/pirate.net/foo'),
+ array('http://////pirate.net/foo'),
+ );
+ }
+
public function testCreateRedirectResponseWithProtocolRelativeTarget()
{
$utils = new HttpUtils($this->getUrlGenerator(), null, '#^https?://%s$#i');
diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
index be469a4d53c5f..aaa4e8b940a91 100644
--- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
@@ -59,7 +59,8 @@ public function normalize($object, $format = null, array $context = array())
$timezone = $this->getTimezone($context);
if (null !== $timezone) {
- $object = (new \DateTimeImmutable('@'.$object->getTimestamp()))->setTimezone($timezone);
+ $object = clone $object;
+ $object = $object->setTimezone($timezone);
}
return $object->format($format);
diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
index 178519b30e687..99b224996cb1b 100644
--- a/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
@@ -78,6 +78,82 @@ public function normalizeUsingTimeZonePassedInContextProvider()
yield array('2016-12-01T09:00:00+09:00', new \DateTimeImmutable('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan'));
}
+ /**
+ * @dataProvider normalizeUsingTimeZonePassedInContextAndExpectedFormatWithMicrosecondsProvider
+ */
+ public function testNormalizeUsingTimeZonePassedInContextAndFormattedWithMicroseconds($expected, $expectedFormat, $input, $timezone)
+ {
+ $this->assertSame(
+ $expected,
+ $this->normalizer->normalize(
+ $input,
+ null,
+ array(
+ DateTimeNormalizer::TIMEZONE_KEY => $timezone,
+ DateTimeNormalizer::FORMAT_KEY => $expectedFormat,
+ )
+ )
+ );
+ }
+
+ public function normalizeUsingTimeZonePassedInContextAndExpectedFormatWithMicrosecondsProvider()
+ {
+ yield array(
+ '2018-12-01T18:03:06.067634',
+ 'Y-m-d\TH:i:s.u',
+ \DateTime::createFromFormat(
+ 'Y-m-d\TH:i:s.u',
+ '2018-12-01T18:03:06.067634',
+ new \DateTimeZone('UTC')
+ ),
+ null,
+ );
+
+ yield array(
+ '2018-12-01T18:03:06.067634',
+ 'Y-m-d\TH:i:s.u',
+ \DateTime::createFromFormat(
+ 'Y-m-d\TH:i:s.u',
+ '2018-12-01T18:03:06.067634',
+ new \DateTimeZone('UTC')
+ ),
+ new \DateTimeZone('UTC'),
+ );
+
+ yield array(
+ '2018-12-01T19:03:06.067634+01:00',
+ 'Y-m-d\TH:i:s.uP',
+ \DateTimeImmutable::createFromFormat(
+ 'Y-m-d\TH:i:s.u',
+ '2018-12-01T18:03:06.067634',
+ new \DateTimeZone('UTC')
+ ),
+ new \DateTimeZone('Europe/Rome'),
+ );
+
+ yield array(
+ '2018-12-01T20:03:06.067634+02:00',
+ 'Y-m-d\TH:i:s.uP',
+ \DateTime::createFromFormat(
+ 'Y-m-d\TH:i:s.u',
+ '2018-12-01T18:03:06.067634',
+ new \DateTimeZone('UTC')
+ ),
+ new \DateTimeZone('Europe/Kiev'),
+ );
+
+ yield array(
+ '2018-12-01T21:03:06.067634',
+ 'Y-m-d\TH:i:s.u',
+ \DateTime::createFromFormat(
+ 'Y-m-d\TH:i:s.u',
+ '2018-12-01T18:03:06.067634',
+ new \DateTimeZone('UTC')
+ ),
+ new \DateTimeZone('Europe/Moscow'),
+ );
+ }
+
/**
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
* @expectedExceptionMessage The object must implement the "\DateTimeInterface".
diff --git a/src/Symfony/Component/Validator/ConstraintViolation.php b/src/Symfony/Component/Validator/ConstraintViolation.php
index 848c77611776b..ae9ff89eb54cf 100644
--- a/src/Symfony/Component/Validator/ConstraintViolation.php
+++ b/src/Symfony/Component/Validator/ConstraintViolation.php
@@ -79,13 +79,13 @@ public function __toString()
}
$propertyPath = (string) $this->propertyPath;
- $code = $this->code;
+ $code = (string) $this->code;
if ('' !== $propertyPath && '[' !== $propertyPath[0] && '' !== $class) {
$class .= '.';
}
- if (!empty($code)) {
+ if ('' !== $code) {
$code = ' (code '.$code.')';
}
diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php
index 544c82f6c074b..e4f7df1757da6 100644
--- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php
+++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php
@@ -112,7 +112,7 @@ public function getValidator();
* Returns the currently validated object.
*
* If the validator is currently validating a class constraint, the
- * object of that class is returned. If it is a validating a property or
+ * object of that class is returned. If it is validating a property or
* getter constraint, the object that the property/getter belongs to is
* returned.
*
diff --git a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php
index cef4782e0f82d..edaa7fa50d6b0 100644
--- a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php
+++ b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php
@@ -53,4 +53,59 @@ public function testToStringHandlesArrayRoots()
$this->assertSame($expected, (string) $violation);
}
+
+ public function testToStringHandlesCodes()
+ {
+ $violation = new ConstraintViolation(
+ '42 cannot be used here',
+ 'this is the message template',
+ array(),
+ array('some_value' => 42),
+ 'some_value',
+ null,
+ null,
+ 0
+ );
+
+ $expected = <<<'EOF'
+Array.some_value:
+ 42 cannot be used here (code 0)
+EOF;
+
+ $this->assertSame($expected, (string) $violation);
+ }
+
+ public function testToStringOmitsEmptyCodes()
+ {
+ $expected = <<<'EOF'
+Array.some_value:
+ 42 cannot be used here
+EOF;
+
+ $violation = new ConstraintViolation(
+ '42 cannot be used here',
+ 'this is the message template',
+ array(),
+ array('some_value' => 42),
+ 'some_value',
+ null,
+ null,
+ null
+ );
+
+ $this->assertSame($expected, (string) $violation);
+
+ $violation = new ConstraintViolation(
+ '42 cannot be used here',
+ 'this is the message template',
+ array(),
+ array('some_value' => 42),
+ 'some_value',
+ null,
+ null,
+ ''
+ );
+
+ $this->assertSame($expected, (string) $violation);
+ }
}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy