Merge branch '2.5' into 2.6

* 2.5:
  [HttpFoundation] [Request] fix baseUrl parsing to fix wrong path_info
  [Twig][Bridge][TranslationDefaultDomain] add support of named arguments.
  [Form] Improved exception message if the data class is not found
  Fixes ArgvInput's argument getter with empty tokens
  execute cheaper checks before more expensive ones
  [FrameworkBundle] FormDataCollector should be loaded only if form config is enabled

Conflicts:
	src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml
This commit is contained in:
Fabien Potencier 2015-01-20 02:40:20 +01:00
commit 7a3332b798
13 changed files with 122 additions and 38 deletions

View File

@ -62,14 +62,20 @@ class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
}
if ($node instanceof \Twig_Node_Expression_Filter && in_array($node->getNode('filter')->getAttribute('value'), array('trans', 'transchoice'))) {
$ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2;
$arguments = $node->getNode('arguments');
if (!$arguments->hasNode($ind)) {
if (!$arguments->hasNode($ind - 1)) {
$arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine()));
$ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2;
if ($this->isNamedArguments($arguments)) {
if (!$arguments->hasNode('domain') && !$arguments->hasNode($ind)) {
$arguments->setNode('domain', $this->scope->get('domain'));
}
} else {
if (!$arguments->hasNode($ind)) {
if (!$arguments->hasNode($ind - 1)) {
$arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine()));
}
$arguments->setNode($ind, $this->scope->get('domain'));
$arguments->setNode($ind, $this->scope->get('domain'));
}
}
} elseif ($node instanceof TransNode) {
if (null === $node->getNode('domain')) {
@ -103,4 +109,18 @@ class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface
{
return -10;
}
/**
* @return bool
*/
private function isNamedArguments($arguments)
{
foreach ($arguments as $name => $node) {
if (!is_int($name)) {
return true;
}
}
return false;
}
}

View File

@ -147,6 +147,40 @@ class TranslationExtensionTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array())));
}
public function testDefaultTranslationDomainWithNamedArguments()
{
$templates = array(
'index' => '
{%- trans_default_domain "foo" %}
{%- block content %}
{{- "foo"|trans(arguments = {}, domain = "custom") }}
{{- "foo"|transchoice(count = 1) }}
{{- "foo"|transchoice(count = 1, arguments = {}, domain = "custom") }}
{{- "foo"|trans({}, domain = "custom") }}
{{- "foo"|trans({}, "custom", locale = "fr") }}
{{- "foo"|transchoice(1, arguments = {}, domain = "custom") }}
{{- "foo"|transchoice(1, {}, "custom", locale = "fr") }}
{% endblock %}
',
'base' => '
{%- block content "" %}
',
);
$translator = new Translator('en', new MessageSelector());
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', array('foo' => 'foo (messages)'), 'en');
$translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom');
$translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo');
$translator->addResource('array', array('foo' => 'foo (fr)'), 'fr', 'custom');
$template = $this->getTemplate($templates, $translator);
$this->assertEquals('foo (custom)foo (foo)foo (custom)foo (custom)foo (fr)foo (custom)foo (fr)', trim($template->render(array())));
}
protected function getTemplate($template, $translator = null)
{
if (null === $translator) {

View File

@ -77,6 +77,13 @@ class TranslationDefaultDomainNodeVisitorTest extends \PHPUnit_Framework_TestCas
array(TwigNodeProvider::getTransFilter(self::$message)),
array(TwigNodeProvider::getTransChoiceFilter(self::$message)),
array(TwigNodeProvider::getTransTag(self::$message)),
// with named arguments
array(TwigNodeProvider::getTransFilter(self::$message, null, array(
'arguments' => new \Twig_Node_Expression_Array(array(), 0),
))),
array(TwigNodeProvider::getTransChoiceFilter(self::$message), null, array(
'arguments' => new \Twig_Node_Expression_Array(array(), 0),
)),
);
}
}

View File

@ -29,12 +29,14 @@ class TwigNodeProvider
);
}
public static function getTransFilter($message, $domain = null)
public static function getTransFilter($message, $domain = null, $arguments = null)
{
$arguments = $domain ? array(
new \Twig_Node_Expression_Array(array(), 0),
new \Twig_Node_Expression_Constant($domain, 0),
) : array();
if (!$arguments) {
$arguments = $domain ? array(
new \Twig_Node_Expression_Array(array(), 0),
new \Twig_Node_Expression_Constant($domain, 0),
) : array();
}
return new \Twig_Node_Expression_Filter(
new \Twig_Node_Expression_Constant($message, 0),
@ -44,13 +46,15 @@ class TwigNodeProvider
);
}
public static function getTransChoiceFilter($message, $domain = null)
public static function getTransChoiceFilter($message, $domain = null, $arguments = null)
{
$arguments = $domain ? array(
new \Twig_Node_Expression_Constant(0, 0),
new \Twig_Node_Expression_Array(array(), 0),
new \Twig_Node_Expression_Constant($domain, 0),
) : array();
if (!$arguments) {
$arguments = $domain ? array(
new \Twig_Node_Expression_Constant(0, 0),
new \Twig_Node_Expression_Array(array(), 0),
new \Twig_Node_Expression_Constant($domain, 0),
) : array();
}
return new \Twig_Node_Expression_Filter(
new \Twig_Node_Expression_Constant($message, 0),

View File

@ -13,8 +13,6 @@
<parameter key="data_collector.time.class">Symfony\Component\HttpKernel\DataCollector\TimeDataCollector</parameter>
<parameter key="data_collector.memory.class">Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector</parameter>
<parameter key="data_collector.router.class">Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector</parameter>
<parameter key="data_collector.form.class">Symfony\Component\Form\Extension\DataCollector\FormDataCollector</parameter>
<parameter key="data_collector.form.extractor.class">Symfony\Component\Form\Extension\DataCollector\FormDataExtractor</parameter>
</parameters>
<services>
@ -61,12 +59,5 @@
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController"/>
<tag name="data_collector" template="@WebProfiler/Collector/router.html.twig" id="router" priority="255" />
</service>
<service id="data_collector.form.extractor" class="%data_collector.form.extractor.class%" />
<service id="data_collector.form" class="%data_collector.form.class%">
<tag name="data_collector" template="@WebProfiler/Collector/form.html.twig" id="form" priority="255" />
<argument type="service" id="data_collector.form.extractor" />
</service>
</services>
</container>

View File

@ -7,6 +7,8 @@
<parameters>
<parameter key="form.resolved_type_factory.data_collector_proxy.class">Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeFactoryDataCollectorProxy</parameter>
<parameter key="form.type_extension.form.data_collector.class">Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension</parameter>
<parameter key="data_collector.form.class">Symfony\Component\Form\Extension\DataCollector\FormDataCollector</parameter>
<parameter key="data_collector.form.extractor.class">Symfony\Component\Form\Extension\DataCollector\FormDataExtractor</parameter>
</parameters>
<services>
@ -22,5 +24,13 @@
<tag name="form.type_extension" alias="form" />
<argument type="service" id="data_collector.form" />
</service>
<!-- DataCollector -->
<service id="data_collector.form.extractor" class="%data_collector.form.extractor.class%" />
<service id="data_collector.form" class="%data_collector.form.class%">
<tag name="data_collector" template="@WebProfiler/Collector/form.html.twig" id="form" priority="255" />
<argument type="service" id="data_collector.form.extractor" />
</service>
</services>
</container>

View File

@ -309,9 +309,11 @@ class ArgvInput extends Input
public function getParameterOption($values, $default = false)
{
$values = (array) $values;
$tokens = $this->tokens;
while ($token = array_shift($tokens)) {
while (0 < count($tokens)) {
$token = array_shift($tokens);
foreach ($values as $value) {
if ($token === $value || 0 === strpos($token, $value.'=')) {
if (false !== $pos = strpos($token, '=')) {

View File

@ -304,6 +304,7 @@ class ArgvInputTest extends \PHPUnit_Framework_TestCase
array(array('app/console', 'foo:bar', '-e', 'dev'), array('-e', '--env'), 'dev'),
array(array('app/console', 'foo:bar', '--env=dev'), array('-e', '--env'), 'dev'),
array(array('app/console', 'foo:bar', '--env=dev', '--en=1'), array('--en'), '1'),
array(array('app/console', 'foo:bar', '--env=dev', '', '--en=1'), array('--en'), '1'),
);
}

View File

@ -193,7 +193,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
self::validateName($name);
if (null !== $dataClass && !class_exists($dataClass) && !interface_exists($dataClass)) {
throw new InvalidArgumentException(sprintf('The data class "%s" is not a valid class.', $dataClass));
throw new InvalidArgumentException(sprintf('Class "%s" not found. Is the "data_class" form option set correctly?', $dataClass));
}
$this->name = (string) $name;

View File

@ -1760,7 +1760,7 @@ class Request
return $prefix;
}
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, dirname($baseUrl))) {
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, dirname($baseUrl).'/')) {
// directory portion of $baseUrl matches
return rtrim($prefix, '/');
}

View File

@ -223,6 +223,21 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$request = Request::create('http://test.com/?foo');
$this->assertEquals('/?foo', $request->getRequestUri());
$this->assertEquals(array('foo' => ''), $request->query->all());
## assume rewrite rule: (.*) --> app/app.php ; app/ is a symlink to a symfony web/ directory
$request = Request::create('http://test.com/apparthotel-1234', 'GET', array(), array(), array(),
array(
'DOCUMENT_ROOT' => '/var/www/www.test.com',
'SCRIPT_FILENAME' => '/var/www/www.test.com/app/app.php',
'SCRIPT_NAME' => '/app/app.php',
'PHP_SELF' => '/app/app.php/apparthotel-1234',
));
$this->assertEquals('http://test.com/apparthotel-1234', $request->getUri());
$this->assertEquals('/apparthotel-1234', $request->getPathInfo());
$this->assertEquals('', $request->getQueryString());
$this->assertEquals(80, $request->getPort());
$this->assertEquals('test.com', $request->getHttpHost());
$this->assertFalse($request->isSecure());
}
/**
@ -1327,7 +1342,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
{
return array(
array(
'/foo%20bar',
'/foo%20bar/',
array(
'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
'SCRIPT_NAME' => '/foo bar/app.php',

View File

@ -72,15 +72,15 @@ class Escaper
*/
public static function requiresSingleQuoting($value)
{
// Determines if the PHP value contains any single characters that would
// cause it to require single quoting in YAML.
if (preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value)) {
// Determines if a PHP value is entirely composed of a value that would
// require single quoting in YAML.
if (in_array(strtolower($value), array('null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'))) {
return true;
}
// Determines if a PHP value is entirely composed of a value that would
// require single quoting in YAML.
return in_array(strtolower($value), array('null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'));
// Determines if the PHP value contains any single characters that would
// cause it to require single quoting in YAML.
return preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value);
}
/**

View File

@ -144,13 +144,13 @@ class Inline
}
return $repr;
case '' == $value:
return "''";
case Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
case preg_match(self::getTimestampRegex(), $value):
return Escaper::escapeWithSingleQuotes($value);
case '' == $value:
return "''";
default:
return $value;
}