diff --git a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php index 98b98f1983..69d6d326f4 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php @@ -12,6 +12,8 @@ namespace Symfony\Bridge\Twig\Extension; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\RequestContext; /** * Twig extension for the Symfony HttpFoundation component. @@ -21,10 +23,12 @@ use Symfony\Component\HttpFoundation\RequestStack; class HttpFoundationExtension extends \Twig_Extension { private $requestStack; + private $requestContext; - public function __construct(RequestStack $requestStack) + public function __construct(RequestStack $requestStack, RequestContext $requestContext = null) { $this->requestStack = $requestStack; + $this->requestContext = $requestContext; } /** @@ -56,6 +60,23 @@ class HttpFoundationExtension extends \Twig_Extension } if (!$request = $this->requestStack->getMasterRequest()) { + if (null !== $this->requestContext && '' !== $host = $this->requestContext->getHost()) { + $scheme = $this->requestContext->getScheme(); + $port = ''; + + if ('http' === $scheme && 80 != $this->requestContext->getHttpPort()) { + $port = ':'.$this->requestContext->getHttpPort(); + } elseif ('https' === $scheme && 443 != $this->requestContext->getHttpsPort()) { + $port = ':'.$this->requestContext->getHttpsPort(); + } + + if ('/' !== $path[0]) { + $path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path; + } + + return $scheme.'://'.$host.$port.$path; + } + return $path; } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php index 91f978a909..339d43d7c6 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php @@ -14,6 +14,7 @@ namespace Symfony\Bridge\Twig\Tests\Extension; use Symfony\Bridge\Twig\Extension\HttpFoundationExtension; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\RequestContext; class HttpFoundationExtensionTest extends \PHPUnit_Framework_TestCase { @@ -43,6 +44,49 @@ class HttpFoundationExtensionTest extends \PHPUnit_Framework_TestCase ); } + /** + * @dataProvider getGenerateAbsoluteUrlRequestContextData + */ + public function testGenerateAbsoluteUrlWithRequestContext($path, $baseUrl, $host, $scheme, $httpPort, $httpsPort, $expected) + { + if (!class_exists('Symfony\Component\Routing\RequestContext')) { + $this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.'); + } + + $requestContext = new RequestContext($baseUrl, 'GET', $host, $scheme, $httpPort, $httpsPort, $path); + $extension = new HttpFoundationExtension(new RequestStack(), $requestContext); + + $this->assertEquals($expected, $extension->generateAbsoluteUrl($path)); + } + + /** + * @dataProvider getGenerateAbsoluteUrlRequestContextData + */ + public function testGenerateAbsoluteUrlWithoutRequestAndRequestContext($path) + { + if (!class_exists('Symfony\Component\Routing\RequestContext')) { + $this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.'); + } + + $extension = new HttpFoundationExtension(new RequestStack()); + + $this->assertEquals($path, $extension->generateAbsoluteUrl($path)); + } + + public function getGenerateAbsoluteUrlRequestContextData() + { + return array( + array('/foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo.png'), + array('foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo/foo.png'), + array('foo.png', '/foo/bar/', 'localhost', 'http', 80, 443, 'http://localhost/foo/bar/foo.png'), + array('/foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo.png'), + array('foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo/foo.png'), + array('foo.png', '/foo/bar/', 'localhost', 'https', 80, 443, 'https://localhost/foo/bar/foo.png'), + array('/foo.png', '/foo', 'localhost', 'http', 443, 80, 'http://localhost:443/foo.png'), + array('/foo.png', '/foo', 'localhost', 'https', 443, 80, 'https://localhost:80/foo.png'), + ); + } + public function testGenerateAbsoluteUrlWithScriptFileName() { $request = Request::create('http://localhost/app/web/app_dev.php'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php index 23a4460179..d8c60bcb9b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php @@ -29,7 +29,13 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand { $headers = array('Bundle name', 'Extension alias'); $rows = array(); - foreach ($this->getContainer()->get('kernel')->getBundles() as $bundle) { + + $bundles = $this->getContainer()->get('kernel')->getBundles(); + usort($bundles, function($bundleA, $bundleB) { + return strcmp($bundleA->getName(), $bundleB->getName()); + }); + + foreach ($bundles as $bundle) { $extension = $bundle->getContainerExtension(); $rows[] = array($bundle->getName(), $extension ? $extension->getAlias() : ''); } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index a638daeb8a..b2df7917a9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -383,7 +383,12 @@ class Configuration implements ConfigurationInterface ->prototype('array') ->fixXmlConfig('base_url') ->children() - ->scalarNode('version')->defaultNull()->end() + ->scalarNode('version') + ->beforeNormalization() + ->ifTrue(function ($v) { return '' === $v; }) + ->then(function ($v) { return; }) + ->end() + ->end() ->scalarNode('version_format')->defaultNull()->end() ->scalarNode('base_path')->defaultValue('')->end() ->arrayNode('base_urls') diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 7d8afee62b..d05f122794 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -568,7 +568,7 @@ class FrameworkExtension extends Extension $namedPackages = array(); foreach ($config['packages'] as $name => $package) { - if (null === $package['version']) { + if (!array_key_exists('version', $package)) { $version = $defaultVersion; } else { $format = $package['version_format'] ?: $config['version_format']; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php index e3532a7747..1055251004 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php @@ -20,6 +20,10 @@ $container->loadFromExtension('framework', array( 'bar' => array( 'base_urls' => array('https://bar2.example.com'), ), + 'bar_null_version' => array( + 'version' => null, + 'base_urls' => array('https://bar3.example.com'), + ), ), ), )); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml index e39e15f900..3e057d5b90 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml @@ -18,6 +18,9 @@ https://bar2.example.com + + https://bar3.example.com + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml index 193dc59dfb..d3285ff581 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml @@ -14,3 +14,6 @@ framework: version_format: %%s-%%s bar: base_urls: ["https://bar2.example.com"] + bar_null_version: + version: null + base_urls: "https://bar3.example.com" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index f6be36dae8..9c66a6761a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -209,7 +209,7 @@ abstract class FrameworkExtensionTest extends TestCase // packages $packages = $packages->getArgument(1); - $this->assertCount(4, $packages); + $this->assertCount(5, $packages); $package = $container->getDefinition($packages['images_path']); $this->assertPathPackage($container, $package, '/foo', 'SomeVersionScheme', '%%s?version=%%s'); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index c6aef2b99c..af293a7b63 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -18,6 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase { + private static $containerCache = array(); + abstract protected function loadFromFile(ContainerBuilder $container, $file); public function testRolesHierarchy() @@ -255,6 +257,9 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase protected function getContainer($file) { + if (isset(self::$containerCache[$file])) { + return self::$containerCache[$file]; + } $container = new ContainerBuilder(); $security = new SecurityExtension(); $container->registerExtension($security); @@ -267,6 +272,6 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase $container->getCompilerPassConfig()->setRemovingPasses(array()); $container->compile(); - return $container; + return self::$containerCache[$file] = $container; } } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index bd1635ed87..55182c083a 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -112,6 +112,7 @@ + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index 84476a1977..66055a4eca 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -101,7 +101,7 @@ var request = requestStack[i]; var row = document.createElement('tr'); - rows.appendChild(row); + rows.insertBefore(row, rows.firstChild); var methodCell = document.createElement('td'); if (request.error) { diff --git a/src/Symfony/Component/HttpFoundation/ServerBag.php b/src/Symfony/Component/HttpFoundation/ServerBag.php index fa1cb2fc9f..0d38c08ac0 100644 --- a/src/Symfony/Component/HttpFoundation/ServerBag.php +++ b/src/Symfony/Component/HttpFoundation/ServerBag.php @@ -86,6 +86,10 @@ class ServerBag extends ParameterBag } } + if (isset($headers['AUTHORIZATION'])) { + return $headers; + } + // PHP_AUTH_USER/PHP_AUTH_PW if (isset($headers['PHP_AUTH_USER'])) { $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']); diff --git a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php index 20773c4d7a..41e44e1005 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ServerBagTest.php @@ -151,4 +151,19 @@ class ServerBagTest extends \PHPUnit_Framework_TestCase 'AUTHORIZATION' => $headerContent, ), $bag->getHeaders()); } + + /** + * @see https://github.com/symfony/symfony/issues/17345 + */ + public function testItDoesNotOverwriteTheAuthorizationHeaderIfItIsAlreadySet() + { + $headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo'; + $bag = new ServerBag(array('PHP_AUTH_USER' => 'foo', 'HTTP_AUTHORIZATION' => $headerContent)); + + $this->assertEquals(array( + 'AUTHORIZATION' => $headerContent, + 'PHP_AUTH_USER' => 'foo', + 'PHP_AUTH_PW' => '', + ), $bag->getHeaders()); + } } diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index a08a37ec98..0e0b4ee01e 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -105,7 +105,7 @@ class Inline return 'null'; case is_object($value): if ($objectSupport) { - return '!!php/object:'.serialize($value); + return '!php/object:'.serialize($value); } if ($exceptionOnInvalidType) { @@ -476,6 +476,16 @@ class Inline return (string) substr($scalar, 5); case 0 === strpos($scalar, '! '): return (int) self::parseScalar(substr($scalar, 2)); + case 0 === strpos($scalar, '!php/object:'): + if (self::$objectSupport) { + return unserialize(substr($scalar, 12)); + } + + if (self::$exceptionOnInvalidType) { + throw new ParseException('Object support when parsing a YAML file has been disabled.'); + } + + return; case 0 === strpos($scalar, '!!php/object:'): if (self::$objectSupport) { return unserialize(substr($scalar, 13)); diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 5b9cb25017..2a0df692b3 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -180,7 +180,7 @@ EOF; { $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, false, true); - $this->assertEquals('{ foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects'); + $this->assertEquals('{ foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects'); } public function testObjectSupportDisabledButNoExceptions() diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index f032d1ff97..81f97916a8 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -426,15 +426,19 @@ foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} bar: 1 EOF; $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects'); - } - public function testObjectSupportDisabledButNoExceptions() - { $input = <<assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects'); + } + /** + * @dataProvider invalidDumpedObjectProvider + */ + public function testObjectSupportDisabledButNoExceptions($input) + { $this->assertEquals(array('foo' => null, 'bar' => 1), $this->parser->parse($input), '->parse() does not parse objects'); } @@ -470,11 +474,29 @@ EOF; } /** + * @dataProvider invalidDumpedObjectProvider * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ - public function testObjectsSupportDisabledWithExceptions() + public function testObjectsSupportDisabledWithExceptions($yaml) { - $this->parser->parse('foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";}', true, false); + $this->parser->parse($yaml, true, false); + } + + public function invalidDumpedObjectProvider() + { + $yamlTag = << array($yamlTag), + 'local-tag' => array($localTag), + ); } /**