diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
index 0dec79debc..abb2fed46d 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
@@ -49,7 +49,7 @@ class ExtensionPass implements CompilerPassInterface
if ($container->has('form.extension')) {
$container->getDefinition('twig.extension.form')->addTag('twig.extension');
$reflClass = new \ReflectionClass('Symfony\Bridge\Twig\Extension\FormExtension');
- $container->getDefinition('twig.loader.filesystem')->addMethodCall('addPath', array(dirname(dirname($reflClass->getFileName())).'/Resources/views/Form'));
+ $container->getDefinition('twig.loader.native_filesystem')->addMethodCall('addPath', array(dirname(dirname($reflClass->getFileName())).'/Resources/views/Form'));
}
if ($container->has('translator')) {
@@ -85,15 +85,15 @@ class ExtensionPass implements CompilerPassInterface
}
$composerRootDir = $this->getComposerRootDir($container->getParameter('kernel.root_dir'));
- $loader = $container->getDefinition('twig.loader.filesystem');
- $loader->replaceArgument(2, $composerRootDir);
-
- if (!$container->has('templating')) {
- $loader = $container->getDefinition('twig.loader.native_filesystem');
- $loader->replaceArgument(1, $composerRootDir);
- $loader->addTag('twig.loader');
- $loader->setMethodCalls($container->getDefinition('twig.loader.filesystem')->getMethodCalls());
+ $twigLoader = $container->getDefinition('twig.loader.native_filesystem');
+ if ($container->has('templating')) {
+ $loader = $container->getDefinition('twig.loader.filesystem');
+ $loader->setMethodCalls($twigLoader->getMethodCalls());
+ $loader->replaceArgument(2, $composerRootDir);
+ $twigLoader->clearTag('twig.loader');
+ } else {
+ $twigLoader->replaceArgument(1, $composerRootDir);
$container->setAlias('twig.loader.filesystem', new Alias('twig.loader.native_filesystem', false));
}
diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
index 2b4fa48028..a994ce6e67 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
@@ -78,7 +78,7 @@ class TwigExtension extends Extension
$envConfiguratorDefinition->replaceArgument(4, $config['number_format']['decimal_point']);
$envConfiguratorDefinition->replaceArgument(5, $config['number_format']['thousands_separator']);
- $twigFilesystemLoaderDefinition = $container->getDefinition('twig.loader.filesystem');
+ $twigFilesystemLoaderDefinition = $container->getDefinition('twig.loader.native_filesystem');
// register user-configured paths
foreach ($config['paths'] as $path => $namespace) {
diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/templating.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/templating.xml
index abfe1b47b1..fae523eb6f 100644
--- a/src/Symfony/Bundle/TwigBundle/Resources/config/templating.xml
+++ b/src/Symfony/Bundle/TwigBundle/Resources/config/templating.xml
@@ -11,8 +11,6 @@
-
-
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
index 8bcea690ae..1b6f783fc6 100644
--- a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
+++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
@@ -153,7 +153,7 @@ class TwigExtensionTest extends TestCase
$this->loadFromFile($container, 'extra', $format);
$this->compileContainer($container);
- $def = $container->getDefinition('twig.loader.filesystem');
+ $def = $container->getDefinition('twig.loader.native_filesystem');
$paths = array();
foreach ($def->getMethodCalls() as $call) {
if ('addPath' === $call[0] && false === strpos($call[1][0], 'Form')) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
index 4386b8d06e..d2db7b700d 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
@@ -172,11 +172,10 @@
font-size: 11px;
padding: 4px 8px 4px 0;
}
-.sf-toolbar-block .sf-toolbar-info-piece span {
-
+.sf-toolbar-block:not(.sf-toolbar-block-dump) .sf-toolbar-info-piece span {
+ color: #F5F5F5;
}
.sf-toolbar-block .sf-toolbar-info-piece span {
- color: #F5F5F5;
font-size: 12px;
}
diff --git a/src/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php b/src/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php
index 1afbbb6e6c..b3808c07cf 100644
--- a/src/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php
+++ b/src/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\Console\Tests\Output;
+use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\Output;
@@ -22,4 +23,19 @@ class ConsoleOutputTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument');
$this->assertSame($output->getFormatter(), $output->getErrorOutput()->getFormatter(), '__construct() takes a formatter or null as the third argument');
}
+
+ public function testSetFormatter()
+ {
+ $output = new ConsoleOutput();
+ $outputFormatter = new OutputFormatter();
+ $output->setFormatter($outputFormatter);
+ $this->assertSame($outputFormatter, $output->getFormatter());
+ }
+
+ public function testSetVerbosity()
+ {
+ $output = new ConsoleOutput();
+ $output->setVerbosity(Output::VERBOSITY_VERBOSE);
+ $this->assertSame(Output::VERBOSITY_VERBOSE, $output->getVerbosity());
+ }
}
diff --git a/src/Symfony/Component/Console/Tests/Output/NullOutputTest.php b/src/Symfony/Component/Console/Tests/Output/NullOutputTest.php
index b20ae4e8d0..f09573f04d 100644
--- a/src/Symfony/Component/Console/Tests/Output/NullOutputTest.php
+++ b/src/Symfony/Component/Console/Tests/Output/NullOutputTest.php
@@ -11,7 +11,9 @@
namespace Symfony\Component\Console\Tests\Output;
+use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Output\NullOutput;
+use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Output\OutputInterface;
class NullOutputTest extends \PHPUnit_Framework_TestCase
@@ -36,4 +38,50 @@ class NullOutputTest extends \PHPUnit_Framework_TestCase
$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
$this->assertSame(OutputInterface::VERBOSITY_QUIET, $output->getVerbosity(), '->getVerbosity() always returns VERBOSITY_QUIET for NullOutput');
}
+
+ public function testSetFormatter()
+ {
+ $output = new NullOutput();
+ $outputFormatter = new OutputFormatter();
+ $output->setFormatter($outputFormatter);
+ $this->assertNotSame($outputFormatter, $output->getFormatter());
+ }
+
+ public function testSetVerbosity()
+ {
+ $output = new NullOutput();
+ $output->setVerbosity(Output::VERBOSITY_NORMAL);
+ $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity());
+ }
+
+ public function testSetDecorated()
+ {
+ $output = new NullOutput();
+ $output->setDecorated(true);
+ $this->assertFalse($output->isDecorated());
+ }
+
+ public function testIsQuiet()
+ {
+ $output = new NullOutput();
+ $this->assertTrue($output->isQuiet());
+ }
+
+ public function testIsVerbose()
+ {
+ $output = new NullOutput();
+ $this->assertFalse($output->isVerbose());
+ }
+
+ public function testIsVeryVerbose()
+ {
+ $output = new NullOutput();
+ $this->assertFalse($output->isVeryVerbose());
+ }
+
+ public function testIsDebug()
+ {
+ $output = new NullOutput();
+ $this->assertFalse($output->isDebug());
+ }
}
diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php
index b24caa07a8..51795944dc 100644
--- a/src/Symfony/Component/Filesystem/Filesystem.php
+++ b/src/Symfony/Component/Filesystem/Filesystem.php
@@ -632,7 +632,9 @@ class Filesystem
if (!is_dir($dir)) {
$this->mkdir($dir);
- } elseif (!is_writable($dir)) {
+ }
+
+ if (!is_writable($dir)) {
throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
index 1101b6ac26..12da3879e0 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php
@@ -124,11 +124,11 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
$bag = new ResponseHeaderBag(array());
$bag->setCookie(new Cookie('foo', 'bar'));
- $this->assertContains('Set-Cookie: foo=bar; path=/; httponly', explode("\r\n", $bag->__toString()));
+ $this->assertSetCookieHeader('foo=bar; path=/; httponly', $bag);
$bag->clearCookie('foo');
- $this->assertRegExp('#^Set-Cookie: foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; httponly#m', $bag->__toString());
+ $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; httponly', $bag);
}
public function testClearCookieSecureNotHttpOnly()
@@ -137,7 +137,7 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
$bag->clearCookie('foo', '/', null, true, false);
- $this->assertRegExp('#^Set-Cookie: foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; secure#m', $bag->__toString());
+ $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; secure', $bag);
}
public function testReplace()
@@ -173,11 +173,10 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
$this->assertCount(4, $bag->getCookies());
- $headers = explode("\r\n", $bag->__toString());
- $this->assertContains('Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly', $headers);
- $this->assertContains('Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly', $headers);
- $this->assertContains('Set-Cookie: foo=bar; path=/path/bar; domain=bar.foo; httponly', $headers);
- $this->assertContains('Set-Cookie: foo=bar; path=/; httponly', $headers);
+ $this->assertSetCookieHeader('foo=bar; path=/path/foo; domain=foo.bar; httponly', $bag);
+ $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=foo.bar; httponly', $bag);
+ $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=bar.foo; httponly', $bag);
+ $this->assertSetCookieHeader('foo=bar; path=/; httponly', $bag);
$cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
$this->assertTrue(isset($cookies['foo.bar']['/path/foo']['foo']));
@@ -231,7 +230,7 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
{
$bag = new ResponseHeaderBag();
- $cookies = $bag->getCookies('invalid_argument');
+ $bag->getCookies('invalid_argument');
}
/**
@@ -302,4 +301,9 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
array('attachment', 'föö.html'),
);
}
+
+ private function assertSetCookieHeader($expected, ResponseHeaderBag $actual)
+ {
+ $this->assertRegExp('#^Set-Cookie:\s+'.preg_quote($expected, '#').'$#m', str_replace("\r\n", "\n", (string) $actual));
+ }
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/BasicTypesController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/BasicTypesController.php
index 1a603c2c08..e8e0b60346 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/BasicTypesController.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/BasicTypesController.php
@@ -1,5 +1,14 @@
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
class BasicTypesController
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ExtendingRequest.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ExtendingRequest.php
index e90e87c700..9b4754b46f 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ExtendingRequest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ExtendingRequest.php
@@ -1,5 +1,14 @@
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
use Symfony\Component\HttpFoundation\Request;
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/VariadicController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/VariadicController.php
index a540f9d1e1..c39812453b 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/VariadicController.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/VariadicController.php
@@ -1,5 +1,14 @@
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
class VariadicController
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
index e891bb5171..2b3433c567 100644
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Serializer\Normalizer;
use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException;
+use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
@@ -260,6 +261,16 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
}
}
+ // JSON only has a Number type corresponding to both int and float PHP types.
+ // PHP's json_encode, JavaScript's JSON.stringify, Go's json.Marshal as well as most other JSON encoders convert
+ // floating-point numbers like 12.0 to 12 (the decimal part is dropped when possible).
+ // PHP's json_decode automatically converts Numbers without a decimal part to integers.
+ // To circumvent this behavior, integers are converted to floats when denormalizing JSON based formats and when
+ // a float is expected.
+ if (Type::BUILTIN_TYPE_FLOAT === $builtinType && is_int($data) && false !== strpos($format, JsonEncoder::FORMAT)) {
+ return (float) $data;
+ }
+
if (call_user_func('is_'.$builtinType, $data)) {
return $data;
}
diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php
index cc25d488c6..0b016b829f 100644
--- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php
@@ -580,11 +580,21 @@ class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase
'inners' => array(array('foo' => 1), array('foo' => 2)),
), ObjectOuter::class);
- $this->assertEquals('foo', $obj->getInner()->foo);
- $this->assertEquals('bar', $obj->getInner()->bar);
- $this->assertEquals('1988-01-21', $obj->getDate()->format('Y-m-d'));
- $this->assertEquals(1, $obj->getInners()[0]->foo);
- $this->assertEquals(2, $obj->getInners()[1]->foo);
+ $this->assertSame('foo', $obj->getInner()->foo);
+ $this->assertSame('bar', $obj->getInner()->bar);
+ $this->assertSame('1988-01-21', $obj->getDate()->format('Y-m-d'));
+ $this->assertSame(1, $obj->getInners()[0]->foo);
+ $this->assertSame(2, $obj->getInners()[1]->foo);
+ }
+
+ public function testAcceptJsonNumber()
+ {
+ $extractor = new PropertyInfoExtractor(array(), array(new PhpDocExtractor(), new ReflectionExtractor()));
+ $normalizer = new ObjectNormalizer(null, null, null, $extractor);
+ $serializer = new Serializer(array(new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer));
+
+ $this->assertSame(10.0, $serializer->denormalize(array('number' => 10), JsonNumber::class, 'json')->number);
+ $this->assertSame(10.0, $serializer->denormalize(array('number' => 10), JsonNumber::class, 'jsonld')->number);
}
/**
@@ -892,3 +902,11 @@ class DummyWithConstructorInexistingObject
{
}
}
+
+class JsonNumber
+{
+ /**
+ * @var float
+ */
+ public $number;
+}
diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php
index a57a5919ba..838d12b403 100644
--- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php
+++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php
@@ -720,9 +720,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
// The $cascadedGroups property is set, if the "Default" group is
// overridden by a group sequence
// See validateClassNode()
- $cascadedGroups = count($cascadedGroups) > 0
- ? $cascadedGroups
- : $groups;
+ $cascadedGroups = null !== $cascadedGroups && count($cascadedGroups) > 0 ? $cascadedGroups : $groups;
if (is_array($value)) {
// Arrays are always traversed, independent of the specified