Merge branch '2.7' into 2.8

* 2.7:
  [FrameworkBundle] Fix Incorrect line break in exception message (500 debug page)
  Minor cleanups and improvements
  [form] lazy trans `post_max_size_message`.
  [DI] Fix setting synthetic services on ContainerBuilder
  [ClassLoader] Fix ClassCollectionLoader inlining with declare(strict_types=1)
This commit is contained in:
Fabien Potencier 2016-09-06 16:19:39 -07:00
commit 9e9b41d0ea
19 changed files with 114 additions and 67 deletions

View File

@ -39,7 +39,7 @@ build: 56
font-family: Georgia, "Times New Roman", Times, serif; font-family: Georgia, "Times New Roman", Times, serif;
font-size: 20px; font-size: 20px;
color: #313131; color: #313131;
word-break: break-all; word-wrap: break-word;
} }
.sf-reset li { .sf-reset li {
padding-bottom: 10px; padding-bottom: 10px;

View File

@ -58,7 +58,12 @@ class ClassCollectionLoader
$classes = array_unique($classes); $classes = array_unique($classes);
$cache = $cacheDir.'/'.$name.$extension; // cache the core classes
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
$cacheDir = rtrim(realpath($cacheDir), '/'.DIRECTORY_SEPARATOR);
$cache = $cacheDir.DIRECTORY_SEPARATOR.$name.$extension;
// auto-reload // auto-reload
$reload = false; $reload = false;
@ -99,6 +104,10 @@ class ClassCollectionLoader
} }
} }
$c = '(?:\s*+(?:(?:#|//)[^\n]*+\n|/\*(?:(?<!\*/).)++)?+)*+';
$strictTypesRegex = str_replace('.', $c, "'^<\?php\s.declare.\(.strict_types.=.1.\).;'is");
$cacheDir = explode(DIRECTORY_SEPARATOR, $cacheDir);
$files = array(); $files = array();
$content = ''; $content = '';
foreach (self::getOrderedClasses($classes) as $class) { foreach (self::getOrderedClasses($classes) as $class) {
@ -106,25 +115,40 @@ class ClassCollectionLoader
continue; continue;
} }
$files[] = $class->getFileName(); $files[] = $file = $class->getFileName();
$c = file_get_contents($file);
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName())); if (preg_match($strictTypesRegex, $c)) {
$file = explode(DIRECTORY_SEPARATOR, $file);
// fakes namespace declaration for global code for ($i = 0; isset($file[$i], $cacheDir[$i]); ++$i) {
if (!$class->inNamespace()) { if ($file[$i] !== $cacheDir[$i]) {
$c = "\nnamespace\n{\n".$c."\n}\n"; break;
}
}
if (1 >= $i) {
$file = var_export(implode(DIRECTORY_SEPARATOR, $file), true);
} else {
$file = array_slice($file, $i);
$file = str_repeat('..'.DIRECTORY_SEPARATOR, count($cacheDir) - $i).implode(DIRECTORY_SEPARATOR, $file);
$file = '__DIR__.'.var_export(DIRECTORY_SEPARATOR.$file, true);
}
$c = "\nnamespace {require $file;}";
} else {
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', $c);
// fakes namespace declaration for global code
if (!$class->inNamespace()) {
$c = "\nnamespace\n{\n".$c."\n}\n";
}
$c = self::fixNamespaceDeclarations('<?php '.$c);
$c = preg_replace('/^\s*<\?php/', '', $c);
} }
$c = self::fixNamespaceDeclarations('<?php '.$c);
$c = preg_replace('/^\s*<\?php/', '', $c);
$content .= $c; $content .= $c;
} }
// cache the core classes
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
self::writeCacheFile($cache, '<?php '.$content); self::writeCacheFile($cache, '<?php '.$content);
if ($autoReload) { if ($autoReload) {

View File

@ -223,18 +223,20 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
public function testCommentStripping() public function testCommentStripping()
{ {
if (is_file($file = sys_get_temp_dir().'/bar.php')) { if (is_file($file = __DIR__.'/bar.php')) {
unlink($file); unlink($file);
} }
spl_autoload_register($r = function ($class) { spl_autoload_register($r = function ($class) {
if (0 === strpos($class, 'Namespaced') || 0 === strpos($class, 'Pearlike_')) { if (0 === strpos($class, 'Namespaced') || 0 === strpos($class, 'Pearlike_')) {
require_once __DIR__.'/Fixtures/'.str_replace(array('\\', '_'), '/', $class).'.php'; @require_once __DIR__.'/Fixtures/'.str_replace(array('\\', '_'), '/', $class).'.php';
} }
}); });
$strictTypes = defined('HHVM_VERSION') ? '' : "\nnamespace {require __DIR__.'/Fixtures/Namespaced/WithStrictTypes.php';}";
ClassCollectionLoader::load( ClassCollectionLoader::load(
array('Namespaced\\WithComments', 'Pearlike_WithComments'), array('Namespaced\\WithComments', 'Pearlike_WithComments', $strictTypes ? 'Namespaced\\WithStrictTypes' : 'Namespaced\\WithComments'),
sys_get_temp_dir(), __DIR__,
'bar', 'bar',
false false
); );
@ -274,7 +276,9 @@ public static $loaded = true;
} }
} }
EOF EOF
, str_replace("<?php \n", '', file_get_contents($file))); .$strictTypes,
str_replace(array("<?php \n", '\\\\'), array('', '/'), file_get_contents($file))
);
unlink($file); unlink($file);
} }

View File

@ -76,6 +76,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php', 'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php',
'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php', 'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php',
'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php', 'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php',
'Namespaced\WithStrictTypes' => realpath(__DIR__).'/Fixtures/Namespaced/WithStrictTypes.php',
), ),
), ),
array(__DIR__.'/Fixtures/beta/NamespaceCollision', array( array(__DIR__.'/Fixtures/beta/NamespaceCollision', array(

View File

@ -0,0 +1,13 @@
<?php
/*
* foo
*/
declare (strict_types = 1);
namespace Namespaced;
class WithStrictTypes
{
}

View File

@ -56,14 +56,12 @@ class RepeatedPass implements CompilerPassInterface
*/ */
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)
{ {
$this->repeat = false; do {
foreach ($this->passes as $pass) { $this->repeat = false;
$pass->process($container); foreach ($this->passes as $pass) {
} $pass->process($container);
}
if ($this->repeat) { } while ($this->repeat);
$this->process($container);
}
} }
/** /**

View File

@ -381,21 +381,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
public function set($id, $service, $scope = self::SCOPE_CONTAINER) public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{ {
$id = strtolower($id); $id = strtolower($id);
$set = isset($this->definitions[$id]);
if ($this->isFrozen()) { if ($this->isFrozen() && ($set || isset($this->obsoleteDefinitions[$id])) && !$this->{$set ? 'definitions' : 'obsoleteDefinitions'}[$id]->isSynthetic()) {
// setting a synthetic service on a frozen container is alright // setting a synthetic service on a frozen container is alright
if ( throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
(!isset($this->definitions[$id]) && !isset($this->obsoleteDefinitions[$id]))
||
(isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())
||
(isset($this->obsoleteDefinitions[$id]) && !$this->obsoleteDefinitions[$id]->isSynthetic())
) {
throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
}
} }
if (isset($this->definitions[$id])) { if ($set) {
$this->obsoleteDefinitions[$id] = $this->definitions[$id]; $this->obsoleteDefinitions[$id] = $this->definitions[$id];
} }

View File

@ -130,7 +130,7 @@ class GraphvizDumper extends Dumper
* *
* @return array An array of edges * @return array An array of edges
*/ */
private function findEdges($id, $arguments, $required, $name) private function findEdges($id, array $arguments, $required, $name)
{ {
$edges = array(); $edges = array();
foreach ($arguments as $argument) { foreach ($arguments as $argument) {
@ -246,7 +246,7 @@ class GraphvizDumper extends Dumper
* *
* @return string A comma separated list of attributes * @return string A comma separated list of attributes
*/ */
private function addAttributes($attributes) private function addAttributes(array $attributes)
{ {
$code = array(); $code = array();
foreach ($attributes as $k => $v) { foreach ($attributes as $k => $v) {
@ -263,7 +263,7 @@ class GraphvizDumper extends Dumper
* *
* @return string A space separated list of options * @return string A space separated list of options
*/ */
private function addOptions($options) private function addOptions(array $options)
{ {
$code = array(); $code = array();
foreach ($options as $k => $v) { foreach ($options as $k => $v) {

View File

@ -375,7 +375,7 @@ class PhpDumper extends Dumper
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @throws RuntimeException * @throws RuntimeException
*/ */
private function addServiceInstance($id, $definition) private function addServiceInstance($id, Definition $definition)
{ {
$class = $definition->getClass(); $class = $definition->getClass();
@ -425,7 +425,7 @@ class PhpDumper extends Dumper
* *
* @return bool * @return bool
*/ */
private function isSimpleInstance($id, $definition) private function isSimpleInstance($id, Definition $definition)
{ {
foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) { foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) { if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
@ -449,7 +449,7 @@ class PhpDumper extends Dumper
* *
* @return string * @return string
*/ */
private function addServiceMethodCalls($id, $definition, $variableName = 'instance') private function addServiceMethodCalls($id, Definition $definition, $variableName = 'instance')
{ {
$calls = ''; $calls = '';
foreach ($definition->getMethodCalls() as $call) { foreach ($definition->getMethodCalls() as $call) {
@ -464,7 +464,7 @@ class PhpDumper extends Dumper
return $calls; return $calls;
} }
private function addServiceProperties($id, $definition, $variableName = 'instance') private function addServiceProperties($id, Definition $definition, $variableName = 'instance')
{ {
$code = ''; $code = '';
foreach ($definition->getProperties() as $name => $value) { foreach ($definition->getProperties() as $name => $value) {
@ -484,7 +484,7 @@ class PhpDumper extends Dumper
* *
* @throws ServiceCircularReferenceException when the container contains a circular reference * @throws ServiceCircularReferenceException when the container contains a circular reference
*/ */
private function addServiceInlinedDefinitionsSetup($id, $definition) private function addServiceInlinedDefinitionsSetup($id, Definition $definition)
{ {
$this->referenceVariables[$id] = new Variable('instance'); $this->referenceVariables[$id] = new Variable('instance');
@ -528,7 +528,7 @@ class PhpDumper extends Dumper
* *
* @return string * @return string
*/ */
private function addServiceConfigurator($id, $definition, $variableName = 'instance') private function addServiceConfigurator($id, Definition $definition, $variableName = 'instance')
{ {
if (!$callable = $definition->getConfigurator()) { if (!$callable = $definition->getConfigurator()) {
return ''; return '';
@ -560,7 +560,7 @@ class PhpDumper extends Dumper
* *
* @return string * @return string
*/ */
private function addService($id, $definition) private function addService($id, Definition $definition)
{ {
$this->definitionVariables = new \SplObjectStorage(); $this->definitionVariables = new \SplObjectStorage();
$this->referenceVariables = array(); $this->referenceVariables = array();
@ -1144,7 +1144,7 @@ EOF;
* *
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
private function exportParameters($parameters, $path = '', $indent = 12) private function exportParameters(array $parameters, $path = '', $indent = 12)
{ {
$php = array(); $php = array();
foreach ($parameters as $key => $value) { foreach ($parameters as $key => $value) {

View File

@ -286,7 +286,7 @@ class XmlDumper extends Dumper
* @param \DOMElement $parent * @param \DOMElement $parent
* @param string $keyAttribute * @param string $keyAttribute
*/ */
private function convertParameters($parameters, $type, \DOMElement $parent, $keyAttribute = 'key') private function convertParameters(array $parameters, $type, \DOMElement $parent, $keyAttribute = 'key')
{ {
$withKeys = array_keys($parameters) !== range(0, count($parameters) - 1); $withKeys = array_keys($parameters) !== range(0, count($parameters) - 1);
foreach ($parameters as $key => $value) { foreach ($parameters as $key => $value) {
@ -335,7 +335,7 @@ class XmlDumper extends Dumper
* *
* @return array * @return array
*/ */
private function escape($arguments) private function escape(array $arguments)
{ {
$args = array(); $args = array();
foreach ($arguments as $k => $v) { foreach ($arguments as $k => $v) {

View File

@ -327,7 +327,7 @@ class YamlDumper extends Dumper
* *
* @return array * @return array
*/ */
private function prepareParameters($parameters, $escape = true) private function prepareParameters(array $parameters, $escape = true)
{ {
$filtered = array(); $filtered = array();
foreach ($parameters as $key => $value) { foreach ($parameters as $key => $value) {
@ -350,7 +350,7 @@ class YamlDumper extends Dumper
* *
* @return array * @return array
*/ */
private function escape($arguments) private function escape(array $arguments)
{ {
$args = array(); $args = array();
foreach ($arguments as $k => $v) { foreach ($arguments as $k => $v) {

View File

@ -420,9 +420,9 @@ class YamlFileLoader extends FileLoader
{ {
if (is_array($value)) { if (is_array($value)) {
$value = array_map(array($this, 'resolveServices'), $value); $value = array_map(array($this, 'resolveServices'), $value);
} elseif (is_string($value) && 0 === strpos($value, '@=')) { } elseif (is_string($value) && 0 === strpos($value, '@=')) {
return new Expression(substr($value, 2)); return new Expression(substr($value, 2));
} elseif (is_string($value) && 0 === strpos($value, '@')) { } elseif (is_string($value) && 0 === strpos($value, '@')) {
if (0 === strpos($value, '@@')) { if (0 === strpos($value, '@@')) {
$value = substr($value, 1); $value = substr($value, 1);
$invalidBehavior = null; $invalidBehavior = null;

View File

@ -677,14 +677,12 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
$container->set('a', new \stdClass()); $container->set('a', new \stdClass());
} }
/**
* @expectedException \BadMethodCallException
*/
public function testThrowsExceptionWhenAddServiceOnAFrozenContainer() public function testThrowsExceptionWhenAddServiceOnAFrozenContainer()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->compile(); $container->compile();
$container->set('a', new \stdClass()); $container->set('a', $foo = new \stdClass());
$this->assertSame($foo, $container->get('a'));
} }
public function testNoExceptionWhenSetSyntheticServiceOnAFrozenContainer() public function testNoExceptionWhenSetSyntheticServiceOnAFrozenContainer()

View File

@ -269,7 +269,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExcepionMessage You have requested a synthetic service ("request"). The DIC does not know how to construct this service. * @expectedExceptionMessage You have requested a synthetic service ("request"). The DIC does not know how to construct this service.
*/ */
public function testGetSyntheticServiceAlwaysThrows() public function testGetSyntheticServiceAlwaysThrows()
{ {

View File

@ -145,6 +145,13 @@ class FormType extends BaseType
}; };
}; };
// Wrap "post_max_size_message" in a closure to translate it lazily
$uploadMaxSizeMessage = function (Options $options) {
return function () use ($options) {
return $options['post_max_size_message'];
};
};
// For any form that is not represented by a single HTML control, // For any form that is not represented by a single HTML control,
// errors should bubble up by default // errors should bubble up by default
$errorBubbling = function (Options $options) { $errorBubbling = function (Options $options) {
@ -225,12 +232,14 @@ class FormType extends BaseType
'action' => '', 'action' => '',
'attr' => $defaultAttr, 'attr' => $defaultAttr,
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
'upload_max_size_message' => $uploadMaxSizeMessage, // internal
)); ));
$resolver->setNormalizer('attr', $attrNormalizer); $resolver->setNormalizer('attr', $attrNormalizer);
$resolver->setNormalizer('read_only', $readOnlyNormalizer); $resolver->setNormalizer('read_only', $readOnlyNormalizer);
$resolver->setAllowedTypes('label_attr', 'array'); $resolver->setAllowedTypes('label_attr', 'array');
$resolver->setAllowedTypes('upload_max_size_message', array('callable'));
} }
/** /**

View File

@ -78,7 +78,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface
$form->submit(null, false); $form->submit(null, false);
$form->addError(new FormError( $form->addError(new FormError(
$form->getConfig()->getOption('post_max_size_message'), call_user_func($form->getConfig()->getOption('upload_max_size_message')),
null, null,
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
)); ));

View File

@ -42,9 +42,10 @@ class UploadValidatorExtension extends AbstractTypeExtension
{ {
$translator = $this->translator; $translator = $this->translator;
$translationDomain = $this->translationDomain; $translationDomain = $this->translationDomain;
$resolver->setNormalizer('upload_max_size_message', function (Options $options, $message) use ($translator, $translationDomain) {
$resolver->setNormalizer('post_max_size_message', function (Options $options, $errorMessage) use ($translator, $translationDomain) { return function () use ($translator, $translationDomain, $message) {
return $translator->trans($errorMessage, array(), $translationDomain); return $translator->trans(call_user_func($message), array(), $translationDomain);
};
}); });
} }

View File

@ -86,7 +86,7 @@ class NativeRequestHandler implements RequestHandlerInterface
$form->submit(null, false); $form->submit(null, false);
$form->addError(new FormError( $form->addError(new FormError(
$form->getConfig()->getOption('post_max_size_message'), call_user_func($form->getConfig()->getOption('upload_max_size_message')),
null, null,
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
)); ));

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
use Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension; use Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\OptionsResolver\Options;
class UploadValidatorExtensionTest extends TypeTestCase class UploadValidatorExtensionTest extends TypeTestCase
{ {
@ -29,10 +30,15 @@ class UploadValidatorExtensionTest extends TypeTestCase
$resolver = new OptionsResolver(); $resolver = new OptionsResolver();
$resolver->setDefault('post_max_size_message', 'old max {{ max }}!'); $resolver->setDefault('post_max_size_message', 'old max {{ max }}!');
$resolver->setDefault('upload_max_size_message', function (Options $options, $message) {
return function () use ($options) {
return $options['post_max_size_message'];
};
});
$extension->configureOptions($resolver); $extension->configureOptions($resolver);
$options = $resolver->resolve(); $options = $resolver->resolve();
$this->assertEquals('translated max {{ max }}!', $options['post_max_size_message']); $this->assertEquals('translated max {{ max }}!', call_user_func($options['upload_max_size_message']));
} }
} }