Merge branch '2.7'
* 2.7: [FrameworkBundle|TwigBundle] update functional tests configuration files to not use deprecated config keys anymore. added a relative_path Twig function added an absolute_url() Twig function
This commit is contained in:
commit
3176b0951d
@ -1,6 +1,11 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
||||
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
|
109
src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php
Normal file
109
src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bridge\Twig\Extension;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Twig extension for the Symfony HttpFoundation component.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class HttpFoundationExtension extends \Twig_Extension
|
||||
{
|
||||
private $requestStack;
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
return array(
|
||||
new \Twig_SimpleFunction('absolute_url', array($this, 'generateAbsoluteUrl')),
|
||||
new \Twig_SimpleFunction('relative_path', array($this, 'generateRelativePath')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL for the given absolute or relative path.
|
||||
*
|
||||
* This method returns the path unchanged if no request is available.
|
||||
*
|
||||
* @param string $path The path
|
||||
*
|
||||
* @return string The absolute URL
|
||||
*
|
||||
* @see Request::getUriForPath()
|
||||
*/
|
||||
public function generateAbsoluteUrl($path)
|
||||
{
|
||||
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if (!$request = $this->requestStack->getMasterRequest()) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if (!$path || '/' !== $path[0]) {
|
||||
$prefix = $request->getPathInfo();
|
||||
$last = strlen($prefix) - 1;
|
||||
if ($last !== $pos = strrpos($prefix, '/')) {
|
||||
$prefix = substr($prefix, 0, $pos).'/';
|
||||
}
|
||||
|
||||
$path = $prefix.$path;
|
||||
}
|
||||
|
||||
return $request->getUriForPath($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a relative path based on the current Request.
|
||||
*
|
||||
* This method returns the path unchanged if no request is available.
|
||||
*
|
||||
* @param string $path The path
|
||||
*
|
||||
* @return string The relative path
|
||||
*
|
||||
* @see Request::getRelativeUriForPath()
|
||||
*/
|
||||
public function generateRelativePath($path)
|
||||
{
|
||||
if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if (!$request = $this->requestStack->getMasterRequest()) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return $request->getRelativeUriForPath($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the extension.
|
||||
*
|
||||
* @return string The extension name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'request';
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bridge\Twig\Tests\Extension;
|
||||
|
||||
use Symfony\Bridge\Twig\Extension\HttpFoundationExtension;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class HttpFoundationExtensionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getGenerateAbsoluteUrlData()
|
||||
*/
|
||||
public function testGenerateAbsoluteUrl($expected, $path, $pathinfo)
|
||||
{
|
||||
$stack = new RequestStack();
|
||||
$stack->push(Request::create($pathinfo));
|
||||
$extension = new HttpFoundationExtension($stack);
|
||||
|
||||
$this->assertEquals($expected, $extension->generateAbsoluteUrl($path));
|
||||
}
|
||||
|
||||
public function getGenerateAbsoluteUrlData()
|
||||
{
|
||||
return array(
|
||||
array('http://localhost/foo.png', '/foo.png', '/foo/bar.html'),
|
||||
array('http://localhost/foo/foo.png', 'foo.png', '/foo/bar.html'),
|
||||
array('http://localhost/foo/foo.png', 'foo.png', '/foo/bar'),
|
||||
array('http://localhost/foo/bar/foo.png', 'foo.png', '/foo/bar/'),
|
||||
|
||||
array('http://example.com/baz', 'http://example.com/baz', '/'),
|
||||
array('https://example.com/baz', 'https://example.com/baz', '/'),
|
||||
array('//example.com/baz', '//example.com/baz', '/'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getGenerateRelativePathData()
|
||||
*/
|
||||
public function testGenerateRelativePath($expected, $path, $pathinfo)
|
||||
{
|
||||
if (!method_exists('Symfony\Component\HttpFoundation\Request', 'getRelativeUriForPath')) {
|
||||
$this->markTestSkipped('Your version of Symfony HttpFoundation is too old.');
|
||||
}
|
||||
|
||||
$stack = new RequestStack();
|
||||
$stack->push(Request::create($pathinfo));
|
||||
$extension = new HttpFoundationExtension($stack);
|
||||
|
||||
$this->assertEquals($expected, $extension->generateRelativePath($path));
|
||||
}
|
||||
|
||||
public function getGenerateRelativePathData()
|
||||
{
|
||||
return array(
|
||||
array('../foo.png', '/foo.png', '/foo/bar.html'),
|
||||
array('../baz/foo.png', '/baz/foo.png', '/foo/bar.html'),
|
||||
array('baz/foo.png', 'baz/foo.png', '/foo/bar.html'),
|
||||
|
||||
array('http://example.com/baz', 'http://example.com/baz', '/'),
|
||||
array('https://example.com/baz', 'https://example.com/baz', '/'),
|
||||
array('//example.com/baz', '//example.com/baz', '/'),
|
||||
);
|
||||
}
|
||||
}
|
@ -43,6 +43,16 @@ class Configuration implements ConfigurationInterface
|
||||
$rootNode = $treeBuilder->root('framework');
|
||||
|
||||
$rootNode
|
||||
// Check deprecations before the config is processed to ensure
|
||||
// the setting has been explicitly defined in a configuration file.
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return isset($v['csrf_protection']['field_name']); })
|
||||
->then(function ($v) {
|
||||
trigger_error('The framework.csrf_protection.field_name configuration key is deprecated since version 2.4 and will be removed in 3.0. Use the framework.form.csrf_protection.field_name configuration key instead', E_USER_DEPRECATED);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('secret')->end()
|
||||
->scalarNode('http_method_override')
|
||||
|
@ -205,7 +205,6 @@ class FrameworkExtension extends Extension
|
||||
if (null !== $config['form']['csrf_protection']['field_name']) {
|
||||
$container->setParameter('form.type_extension.csrf.field_name', $config['form']['csrf_protection']['field_name']);
|
||||
} else {
|
||||
trigger_error('The framework.csrf_protection.field_name configuration key is deprecated since version 2.4 and will be removed in 3.0. Use the framework.form.csrf_protection.field_name configuration key instead', E_USER_DEPRECATED);
|
||||
$container->setParameter('form.type_extension.csrf.field_name', $config['csrf_protection']['field_name']);
|
||||
}
|
||||
} else {
|
||||
|
@ -1,14 +1,10 @@
|
||||
<?php
|
||||
|
||||
$container->loadFromExtension('framework', array(
|
||||
'csrf_protection' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'csrf_protection' => true,
|
||||
'form' => array(
|
||||
'enabled' => true,
|
||||
'csrf_protection' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
'csrf_protection' => true,
|
||||
),
|
||||
'session' => array(
|
||||
'handler_id' => null,
|
||||
|
@ -467,7 +467,7 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
$this->assertEquals('_custom', $container->getParameter('form.type_extension.csrf.field_name'));
|
||||
}
|
||||
|
||||
public function testFormCsrfFieldNameUnderFormSettingsTakesPrecedence()
|
||||
public function testLegacyFormCsrfFieldNameUnderFormSettingsTakesPrecedence()
|
||||
{
|
||||
$container = $this->createContainerFromFile('form_csrf_under_form_sets_field_name');
|
||||
|
||||
|
@ -42,5 +42,9 @@ class ExtensionPass implements CompilerPassInterface
|
||||
if ($container->has('fragment.handler')) {
|
||||
$container->getDefinition('twig.extension.httpkernel')->addTag('twig.extension');
|
||||
}
|
||||
|
||||
if ($container->has('request_stack')) {
|
||||
$container->getDefinition('twig.extension.httpfoundation')->addTag('twig.extension');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,13 +49,21 @@ class Configuration implements ConfigurationInterface
|
||||
private function addFormSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
// Check deprecation before the config is processed to ensure
|
||||
// the setting has been explicitly defined in a configuration file.
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return isset($v['form']['resources']); })
|
||||
->then(function ($v) {
|
||||
trigger_error('The twig.form.resources configuration key is deprecated since version 2.6 and will be removed in 3.0. Use the twig.form_themes configuration key instead.', E_USER_DEPRECATED);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return count($v['form']['resources']) > 0;
|
||||
})
|
||||
->then(function ($v) {
|
||||
trigger_error('The twig.form.resources configuration key is deprecated since version 2.6 and will be removed in 3.0. Use the twig.form_themes configuration key instead.', E_USER_DEPRECATED);
|
||||
|
||||
$v['form_themes'] = array_values(array_unique(array_merge($v['form']['resources'], $v['form_themes'])));
|
||||
|
||||
return $v;
|
||||
|
@ -103,6 +103,9 @@
|
||||
<argument type="service" id="fragment.handler" />
|
||||
</service>
|
||||
|
||||
<service id="twig.extension.httpfoundation" class="Symfony\Bridge\Twig\Extension\HttpFoundationExtension" public="false">
|
||||
<argument type="service" id="request_stack" />
|
||||
</service>
|
||||
|
||||
<service id="twig.extension.form" class="%twig.extension.form.class%" public="false">
|
||||
<argument type="service" id="twig.form.renderer" />
|
||||
|
@ -1137,6 +1137,61 @@ class Request
|
||||
return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path as relative reference from the current Request path.
|
||||
*
|
||||
* Only the URIs path component (no schema, host etc.) is relevant and must be given.
|
||||
* Both paths must be absolute and not contain relative parts.
|
||||
* Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
|
||||
* Furthermore, they can be used to reduce the link size in documents.
|
||||
*
|
||||
* Example target paths, given a base path of "/a/b/c/d":
|
||||
* - "/a/b/c/d" -> ""
|
||||
* - "/a/b/c/" -> "./"
|
||||
* - "/a/b/" -> "../"
|
||||
* - "/a/b/c/other" -> "other"
|
||||
* - "/a/x/y" -> "../../x/y"
|
||||
*
|
||||
* @param string $path The target path
|
||||
*
|
||||
* @return string The relative target path
|
||||
*/
|
||||
public function getRelativeUriForPath($path)
|
||||
{
|
||||
// be sure that we are dealing with an absolute path
|
||||
if (!isset($path[0]) || '/' !== $path[0]) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if ($path === $basePath = $this->getPathInfo()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
|
||||
$targetDirs = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
|
||||
array_pop($sourceDirs);
|
||||
$targetFile = array_pop($targetDirs);
|
||||
|
||||
foreach ($sourceDirs as $i => $dir) {
|
||||
if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
|
||||
unset($sourceDirs[$i], $targetDirs[$i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$targetDirs[] = $targetFile;
|
||||
$path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
|
||||
|
||||
// A reference to the same base directory or an empty subdirectory must be prefixed with "./".
|
||||
// This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
|
||||
// as the first segment of a relative-path reference, as it would be mistaken for a scheme name
|
||||
// (see http://tools.ietf.org/html/rfc3986#section-4.2).
|
||||
return !isset($path[0]) || '/' === $path[0]
|
||||
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
|
||||
? "./$path" : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the normalized query string for the Request.
|
||||
*
|
||||
|
@ -575,6 +575,26 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getRelativeUriForPathData()
|
||||
*/
|
||||
public function testGetRelativeUriForPath($expected, $pathinfo, $path)
|
||||
{
|
||||
$this->assertEquals($expected, Request::create($pathinfo)->getRelativeUriForPath($path));
|
||||
}
|
||||
|
||||
public function getRelativeUriForPathData()
|
||||
{
|
||||
return array(
|
||||
array('me.png', '/foo', '/me.png'),
|
||||
array('../me.png', '/foo/bar', '/me.png'),
|
||||
array('me.png', '/foo/bar', '/foo/me.png'),
|
||||
array('../baz/me.png', '/foo/bar/b', '/foo/baz/me.png'),
|
||||
array('../../fooz/baz/me.png', '/foo/bar/b', '/fooz/baz/me.png'),
|
||||
array('baz/me.png', '/foo/bar/b', 'baz/me.png'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\HttpFoundation\Request::getUserInfo
|
||||
*/
|
||||
|
Reference in New Issue
Block a user