From 647b3d2f54f6ae2ac7f61d3597e9661755937413 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 5 Sep 2016 14:06:16 +0200 Subject: [PATCH 01/18] [ClassLoader] Fix ClassCollectionLoader inlining with declare(strict_types=1) --- .../ClassLoader/ClassCollectionLoader.php | 52 ++++++++++++++----- .../Tests/ClassCollectionLoaderTest.php | 14 +++-- .../Tests/ClassMapGeneratorTest.php | 1 + .../Fixtures/Namespaced/WithStrictTypes.php | 13 +++++ 4 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php index b695b9272f..18e22a5bca 100644 --- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php +++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php @@ -58,7 +58,12 @@ class ClassCollectionLoader $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 $reload = false; @@ -99,6 +104,10 @@ class ClassCollectionLoader } } + $c = '(?:\s*+(?:(?:#|//)[^\n]*+\n|/\*(?:(?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 - if (!$class->inNamespace()) { - $c = "\nnamespace\n{\n".$c."\n}\n"; + for ($i = 0; isset($file[$i], $cacheDir[$i]); ++$i) { + if ($file[$i] !== $cacheDir[$i]) { + 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(' realpath(__DIR__).'/Fixtures/Namespaced/Foo.php', 'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php', 'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php', + 'Namespaced\WithStrictTypes' => realpath(__DIR__).'/Fixtures/Namespaced/WithStrictTypes.php', ), ), array(__DIR__.'/Fixtures/beta/NamespaceCollision', array( diff --git a/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php b/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php new file mode 100644 index 0000000000..3c7870592b --- /dev/null +++ b/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php @@ -0,0 +1,13 @@ + Date: Tue, 6 Sep 2016 15:11:47 +0200 Subject: [PATCH 02/18] [DI] Fix setting synthetic services on ContainerBuilder --- .../DependencyInjection/ContainerBuilder.php | 15 ++++----------- .../Tests/ContainerBuilderTest.php | 6 ++---- .../DependencyInjection/Tests/ContainerTest.php | 2 +- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 0813110ded..6814d28e73 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -362,21 +362,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface public function set($id, $service, $scope = self::SCOPE_CONTAINER) { $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 - if ( - (!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)); - } + 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]; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 7870c40ea9..6b49b1e34f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -637,14 +637,12 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase $container->set('a', new \stdClass()); } - /** - * @expectedException \BadMethodCallException - */ public function testThrowsExceptionWhenAddServiceOnAFrozenContainer() { $container = new ContainerBuilder(); $container->compile(); - $container->set('a', new \stdClass()); + $container->set('a', $foo = new \stdClass()); + $this->assertSame($foo, $container->get('a')); } public function testNoExceptionWhenSetSyntheticServiceOnAFrozenContainer() diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php index e451806bb7..b4eba04f97 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php @@ -258,7 +258,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase /** * @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() { From c03164e4f95eeef83421933dbd90ed900918f786 Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Wed, 10 Aug 2016 18:14:01 +0100 Subject: [PATCH 03/18] [form] lazy trans `post_max_size_message`. --- .../Component/Form/Extension/Core/Type/FormType.php | 9 +++++++++ .../HttpFoundation/HttpFoundationRequestHandler.php | 2 +- .../Validator/Type/UploadValidatorExtension.php | 7 ++++--- src/Symfony/Component/Form/NativeRequestHandler.php | 2 +- .../Validator/Type/UploadValidatorExtensionTest.php | 8 +++++++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 8590796bfa..1a1a3175e6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -146,6 +146,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, // errors should bubble up by default $errorBubbling = function (Options $options) { @@ -207,9 +214,11 @@ class FormType extends BaseType 'action' => '', 'attr' => $defaultAttr, 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', + 'upload_max_size_message' => $uploadMaxSizeMessage, // internal )); $resolver->setAllowedTypes('label_attr', 'array'); + $resolver->setAllowedTypes('upload_max_size_message', array('callable')); } /** diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index d1e5eece7b..004f4778f9 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -78,7 +78,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface $form->submit(null, false); $form->addError(new FormError( - $form->getConfig()->getOption('post_max_size_message'), + call_user_func($form->getConfig()->getOption('upload_max_size_message')), null, array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) )); diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php index 6f0fa60afd..efbfda93d4 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php +++ b/src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php @@ -42,9 +42,10 @@ class UploadValidatorExtension extends AbstractTypeExtension { $translator = $this->translator; $translationDomain = $this->translationDomain; - - $resolver->setNormalizer('post_max_size_message', function (Options $options, $errorMessage) use ($translator, $translationDomain) { - return $translator->trans($errorMessage, array(), $translationDomain); + $resolver->setNormalizer('upload_max_size_message', function (Options $options, $message) use ($translator, $translationDomain) { + return function () use ($translator, $translationDomain, $message) { + return $translator->trans(call_user_func($message), array(), $translationDomain); + }; }); } diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index 5541e96ad5..3607feb99c 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -86,7 +86,7 @@ class NativeRequestHandler implements RequestHandlerInterface $form->submit(null, false); $form->addError(new FormError( - $form->getConfig()->getOption('post_max_size_message'), + call_user_func($form->getConfig()->getOption('upload_max_size_message')), null, array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) )); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php index 95a11a78c7..dbe13a2745 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Type; use Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\OptionsResolver\Options; class UploadValidatorExtensionTest extends TypeTestCase { @@ -29,10 +30,15 @@ class UploadValidatorExtensionTest extends TypeTestCase $resolver = new OptionsResolver(); $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); $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'])); } } From e4193c746c11c44a6ee83f1a098a16b575a26bf5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 6 Sep 2016 11:23:48 +0200 Subject: [PATCH 04/18] Minor cleanups and improvements --- .../Compiler/RepeatedPass.php | 14 ++++++-------- .../Dumper/GraphvizDumper.php | 6 +++--- .../DependencyInjection/Dumper/PhpDumper.php | 16 ++++++++-------- .../DependencyInjection/Dumper/XmlDumper.php | 4 ++-- .../DependencyInjection/Dumper/YamlDumper.php | 4 ++-- .../Loader/YamlFileLoader.php | 4 ++-- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php index 508a8978ea..59d4e0a767 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php @@ -56,14 +56,12 @@ class RepeatedPass implements CompilerPassInterface */ public function process(ContainerBuilder $container) { - $this->repeat = false; - foreach ($this->passes as $pass) { - $pass->process($container); - } - - if ($this->repeat) { - $this->process($container); - } + do { + $this->repeat = false; + foreach ($this->passes as $pass) { + $pass->process($container); + } + } while ($this->repeat); } /** diff --git a/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php index f69d1e9066..c8edea28db 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php @@ -130,7 +130,7 @@ class GraphvizDumper extends Dumper * * @return array An array of edges */ - private function findEdges($id, $arguments, $required, $name) + private function findEdges($id, array $arguments, $required, $name) { $edges = array(); foreach ($arguments as $argument) { @@ -246,7 +246,7 @@ class GraphvizDumper extends Dumper * * @return string A comma separated list of attributes */ - private function addAttributes($attributes) + private function addAttributes(array $attributes) { $code = array(); foreach ($attributes as $k => $v) { @@ -263,7 +263,7 @@ class GraphvizDumper extends Dumper * * @return string A space separated list of options */ - private function addOptions($options) + private function addOptions(array $options) { $code = array(); foreach ($options as $k => $v) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 0c3705647d..37c3275444 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -375,7 +375,7 @@ class PhpDumper extends Dumper * @throws InvalidArgumentException * @throws RuntimeException */ - private function addServiceInstance($id, $definition) + private function addServiceInstance($id, Definition $definition) { $class = $definition->getClass(); @@ -425,7 +425,7 @@ class PhpDumper extends Dumper * * @return bool */ - private function isSimpleInstance($id, $definition) + private function isSimpleInstance($id, Definition $definition) { foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) { if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) { @@ -449,7 +449,7 @@ class PhpDumper extends Dumper * * @return string */ - private function addServiceMethodCalls($id, $definition, $variableName = 'instance') + private function addServiceMethodCalls($id, Definition $definition, $variableName = 'instance') { $calls = ''; foreach ($definition->getMethodCalls() as $call) { @@ -464,7 +464,7 @@ class PhpDumper extends Dumper return $calls; } - private function addServiceProperties($id, $definition, $variableName = 'instance') + private function addServiceProperties($id, Definition $definition, $variableName = 'instance') { $code = ''; foreach ($definition->getProperties() as $name => $value) { @@ -484,7 +484,7 @@ class PhpDumper extends Dumper * * @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'); @@ -528,7 +528,7 @@ class PhpDumper extends Dumper * * @return string */ - private function addServiceConfigurator($id, $definition, $variableName = 'instance') + private function addServiceConfigurator($id, Definition $definition, $variableName = 'instance') { if (!$callable = $definition->getConfigurator()) { return ''; @@ -560,7 +560,7 @@ class PhpDumper extends Dumper * * @return string */ - private function addService($id, $definition) + private function addService($id, Definition $definition) { $this->definitionVariables = new \SplObjectStorage(); $this->referenceVariables = array(); @@ -1124,7 +1124,7 @@ EOF; * * @throws InvalidArgumentException */ - private function exportParameters($parameters, $path = '', $indent = 12) + private function exportParameters(array $parameters, $path = '', $indent = 12) { $php = array(); foreach ($parameters as $key => $value) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index bd8e20071e..3306c4b1a6 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -262,7 +262,7 @@ class XmlDumper extends Dumper * @param \DOMElement $parent * @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); foreach ($parameters as $key => $value) { @@ -311,7 +311,7 @@ class XmlDumper extends Dumper * * @return array */ - private function escape($arguments) + private function escape(array $arguments) { $args = array(); foreach ($arguments as $k => $v) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index 3acac1c9ad..955cb7c14e 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -304,7 +304,7 @@ class YamlDumper extends Dumper * * @return array */ - private function prepareParameters($parameters, $escape = true) + private function prepareParameters(array $parameters, $escape = true) { $filtered = array(); foreach ($parameters as $key => $value) { @@ -327,7 +327,7 @@ class YamlDumper extends Dumper * * @return array */ - private function escape($arguments) + private function escape(array $arguments) { $args = array(); foreach ($arguments as $k => $v) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index f57ba587c8..52cc53946b 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -386,9 +386,9 @@ class YamlFileLoader extends FileLoader { if (is_array($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)); - } elseif (is_string($value) && 0 === strpos($value, '@')) { + } elseif (is_string($value) && 0 === strpos($value, '@')) { if (0 === strpos($value, '@@')) { $value = substr($value, 1); $invalidBehavior = null; From c49e46259c081a1d0a3fbfadbe118d5e2d07cf6b Mon Sep 17 00:00:00 2001 From: Konstantin Myakshin Date: Mon, 29 Aug 2016 14:19:30 +0300 Subject: [PATCH 05/18] [Security] Added note inside phpdoc. --- .../Component/Security/Core/Authorization/Voter/Voter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php index 8d36fd8f8c..2396b1e678 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php @@ -74,6 +74,7 @@ abstract class Voter implements VoterInterface /** * Perform a single access check operation on a given attribute, subject and token. + * It is safe to assume that $attribute and $subject already passed the "supports()" method check. * * @param string $attribute * @param mixed $subject From 1393e3e91326036e5d09679c4a72af3dd233cd2d Mon Sep 17 00:00:00 2001 From: Pedro Resende Date: Mon, 29 Aug 2016 21:43:12 +0100 Subject: [PATCH 06/18] [FrameworkBundle] Fix Incorrect line break in exception message (500 debug page) --- .../Bundle/FrameworkBundle/Resources/public/css/body.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css b/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css index c50c1a54c7..9a1cbb8cc2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/public/css/body.css @@ -39,7 +39,7 @@ build: 56 font-family: Georgia, "Times New Roman", Times, serif; font-size: 20px; color: #313131; - word-break: break-all; + word-wrap: break-word; } .sf-reset li { padding-bottom: 10px; From c3b68b0d28790c85bab190b030d132f2ddc73438 Mon Sep 17 00:00:00 2001 From: Enleur Date: Tue, 6 Sep 2016 13:52:05 +0300 Subject: [PATCH 07/18] [Security] Optimize RoleHierarchy's buildRoleMap method --- .../Component/Security/Core/Role/RoleHierarchy.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php index 793007e7f5..95e76ee279 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php @@ -65,9 +65,17 @@ class RoleHierarchy implements RoleHierarchyInterface } $visited[] = $role; - $this->map[$main] = array_unique(array_merge($this->map[$main], $this->hierarchy[$role])); - $additionalRoles = array_merge($additionalRoles, array_diff($this->hierarchy[$role], $visited)); + + foreach ($this->hierarchy[$role] as $roleToAdd) { + $this->map[$main][] = $roleToAdd; + } + + foreach (array_diff($this->hierarchy[$role], $visited) as $additionalRole) { + $additionalRoles[] = $additionalRole; + } } + + $this->map[$main] = array_unique($this->map[$main]); } } } From 7735b4eac9e9a4fdd208a8cd1ff26bfc73dc7af4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 17:54:08 -0700 Subject: [PATCH 08/18] updated CHANGELOG for 2.7.18 --- CHANGELOG-2.7.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index 0f7fa8210c..c5f93200d0 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,16 @@ in 2.7 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.7.0...v2.7.1 +* 2.7.18 (2016-09-07) + + * bug #19859 [ClassLoader] Fix ClassCollectionLoader inlining with declare(strict_types=1) (nicolas-grekas) + * bug #19780 [FrameworkBundle] Incorrect line break in exception message (500 debug page) (pedroresende) + * bug #19595 [form] lazy trans `post_max_size_message`. (aitboudad) + * bug #19870 [DI] Fix setting synthetic services on ContainerBuilder (nicolas-grekas) + * bug #19848 Revert "minor #19689 [DI] Cleanup array_key_exists (ro0NL)" (nicolas-grekas) + * bug #19842 [FrameworkBundle] Check for class existence before is_subclass_of (chalasr) + * bug #19827 [BrowserKit] Fix cookie expiration on 32 bit systems (jameshalsall) + * 2.7.17 (2016-09-02) * bug #19794 [VarDumper] Various minor fixes & cleanups (nicolas-grekas) From dbc2ad230cb3ee2f822c1f00360816b64775d011 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 17:54:14 -0700 Subject: [PATCH 09/18] update CONTRIBUTORS for 2.7.18 --- CONTRIBUTORS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e10ae01026..7cbed979c4 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -16,8 +16,8 @@ Symfony is the result of the work of many people who made the code better - Kris Wallsmith (kriswallsmith) - Jakub Zalas (jakubzalas) - Ryan Weaver (weaverryan) - - Kévin Dunglas (dunglas) - Javier Eguiluz (javier.eguiluz) + - Kévin Dunglas (dunglas) - Hugo Hamon (hhamon) - Abdellatif Ait boudad (aitboudad) - Pascal Borreli (pborreli) @@ -52,8 +52,8 @@ Symfony is the result of the work of many people who made the code better - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - Florin Patan (florinpatan) - - Peter Rehm (rpet) - Ener-Getick (energetick) + - Peter Rehm (rpet) - Iltar van der Berg (kjarli) - Kevin Bond (kbond) - Andrej Hudec (pulzarraider) @@ -315,6 +315,7 @@ Symfony is the result of the work of many people who made the code better - JhonnyL - hossein zolfi (ocean) - Clément Gautier (clementgautier) + - James Halsall (jaitsu) - Eduardo Gulias (egulias) - giulio de donato (liuggio) - Stéphane PY (steph_py) @@ -396,7 +397,6 @@ Symfony is the result of the work of many people who made the code better - Christian Wahler - Mathieu Lemoine - Gintautas Miselis - - James Halsall (jaitsu) - David Badura (davidbadura) - Zander Baldwin - Adam Harvey @@ -1302,6 +1302,7 @@ Symfony is the result of the work of many people who made the code better - Muriel (metalmumu) - Michael Pohlers (mick_the_big) - Cayetano Soriano Gallego (neoshadybeat) + - Ondrej Machulda (ondram) - Patrick McDougle (patrick-mcdougle) - Pablo Monterde Perez (plebs) - Jimmy Leger (redpanda) From 59985613b286b031241628e1470c5f1bd012570f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 17:54:19 -0700 Subject: [PATCH 10/18] updated VERSION for 2.7.18 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 4215ea070d..e0e7954519 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.18-DEV'; + const VERSION = '2.7.18'; const VERSION_ID = 20718; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; const RELEASE_VERSION = 18; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From be2a6d129131d33e5504091cd540ddb0a82cd6b4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 19:01:26 -0700 Subject: [PATCH 11/18] bumped Symfony version to 2.7.19 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index e0e7954519..c6586c0231 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.18'; - const VERSION_ID = 20718; + const VERSION = '2.7.19-DEV'; + const VERSION_ID = 20719; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 18; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 19; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From c9ea677719594c02345aef2edc56f2706f086d8a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 19:02:53 -0700 Subject: [PATCH 12/18] updated CHANGELOG for 2.8.11 --- CHANGELOG-2.8.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 1de96a66a9..482e20e17c 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,16 @@ in 2.8 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.8.0...v2.8.1 +* 2.8.11 (2016-09-07) + + * bug #19859 [ClassLoader] Fix ClassCollectionLoader inlining with declare(strict_types=1) (nicolas-grekas) + * bug #19780 [FrameworkBundle] Incorrect line break in exception message (500 debug page) (pedroresende) + * bug #19595 [form] lazy trans `post_max_size_message`. (aitboudad) + * bug #19870 [DI] Fix setting synthetic services on ContainerBuilder (nicolas-grekas) + * bug #19848 Revert "minor #19689 [DI] Cleanup array_key_exists (ro0NL)" (nicolas-grekas) + * bug #19842 [FrameworkBundle] Check for class existence before is_subclass_of (chalasr) + * bug #19827 [BrowserKit] Fix cookie expiration on 32 bit systems (jameshalsall) + * 2.8.10 (2016-09-02) * bug #19786 Update profiler's layout to use flexbox (javiereguiluz) From af440e3f9249e774987886d937a74b430fa45ea5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 19:02:58 -0700 Subject: [PATCH 13/18] updated VERSION for 2.8.11 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 1e62cf1266..7b78f1bf21 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.11-DEV'; + const VERSION = '2.8.11'; const VERSION_ID = 20811; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 11; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 69afe99f45650afe77f0048b08bedbf75be888e1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 19:58:32 -0700 Subject: [PATCH 14/18] bumped Symfony version to 2.8.12 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7b78f1bf21..150d65e7cf 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.11'; - const VERSION_ID = 20811; + const VERSION = '2.8.12-DEV'; + const VERSION_ID = 20812; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 11; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 12; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From ffdd15ee064affe08b27a79df40ee7e49943f38e Mon Sep 17 00:00:00 2001 From: Titouan Galopin Date: Wed, 7 Sep 2016 10:32:40 +0200 Subject: [PATCH 15/18] Fix translation:update command count --- .../Command/TranslationUpdateCommand.php | 14 ++++++++------ .../Tests/Command/TranslationUpdateCommandTest.php | 9 +++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index a9a004735b..72298480b4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -160,11 +160,8 @@ EOF foreach ($operation->getDomains() as $domain) { $newKeys = array_keys($operation->getNewMessages($domain)); $allKeys = array_keys($operation->getMessages($domain)); - $domainMessagesCount = count($newKeys) + count($allKeys); - $io->section(sprintf('Messages extracted for domain "%s" (%d messages)', $domain, $domainMessagesCount)); - - $io->listing(array_merge( + $list = array_merge( array_diff($allKeys, $newKeys), array_map(function ($id) { return sprintf('%s', $id); @@ -172,7 +169,12 @@ EOF array_map(function ($id) { return sprintf('%s', $id); }, array_keys($operation->getObsoleteMessages($domain))) - )); + ); + + $domainMessagesCount = count($list); + + $io->section(sprintf('Messages extracted for domain "%s" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : '')); + $io->listing($list); $extractedMessagesCount += $domainMessagesCount; } @@ -181,7 +183,7 @@ EOF $io->comment('Xliff output version is 1.2'); } - $resultMessage = sprintf('%d messages were successfully extracted', $extractedMessagesCount); + $resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was'); } if ($input->getOption('no-backup') === true) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php index f7eca9d366..40eab748c6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php @@ -28,6 +28,15 @@ class TranslationUpdateCommandTest extends \PHPUnit_Framework_TestCase $tester = $this->createCommandTester($this->getContainer(array('foo' => 'foo'))); $tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true)); $this->assertRegExp('/foo/', $tester->getDisplay()); + $this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay()); + } + + public function testDumpTwoMessagesAndClean() + { + $tester = $this->createCommandTester($this->getContainer(array('foo' => 'foo', 'bar' => 'bar'))); + $tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true)); + $this->assertRegExp('/foo/', $tester->getDisplay()); + $this->assertRegExp('/bar/', $tester->getDisplay()); $this->assertRegExp('/2 messages were successfully extracted/', $tester->getDisplay()); } From bf6691ca4617b8b6da22fc7b19801f82009bae13 Mon Sep 17 00:00:00 2001 From: Matteo Beccati Date: Wed, 7 Sep 2016 13:06:20 +0200 Subject: [PATCH 16/18] Fix #19721 Issue was introduced in #19541 --- .../DateTimeToLocalizedStringTransformer.php | 5 ++++- ...DateTimeToLocalizedStringTransformerTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index 51f692755e..d2e5ddba5c 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -134,7 +134,10 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer } // read timestamp into DateTime object - the formatter delivers a timestamp - $dateTime = new \DateTime(sprintf('@%s', $timestamp), new \DateTimeZone($this->outputTimezone)); + $dateTime = new \DateTime(sprintf('@%s', $timestamp)); + // set timezone separately, as it would be ignored if set via the constructor, + // see http://php.net/manual/en/datetime.construct.php + $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 444cdd4582..d5abfe7047 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -134,6 +134,23 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase $this->assertEquals($dateTime->format('d.m.Y, H:i'), $transformer->transform($input)); } + public function testReverseTransformWithNoConstructorParameters() + { + $tz = date_default_timezone_get(); + date_default_timezone_set('Europe/Rome'); + + $transformer = new DateTimeToLocalizedStringTransformer(); + + $dateTime = new \DateTime('2010-02-03 04:05'); + + $this->assertEquals( + $dateTime->format('c'), + $transformer->reverseTransform('03.02.2010, 04:05')->format('c') + ); + + date_default_timezone_set($tz); + } + public function testTransformWithDifferentPatterns() { $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss'); From d3c613be367c5d3b28de03ef669f3ea0354a37c1 Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Wed, 7 Sep 2016 12:59:03 +0100 Subject: [PATCH 17/18] [Console] fixed PHP7 Errors are now handled and converted to Exceptions --- src/Symfony/Component/Console/Application.php | 15 ++++- .../Console/Tests/ApplicationTest.php | 56 +++++++++++++++++++ src/Symfony/Component/Console/composer.json | 3 +- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 590460ca0d..c2c13b8aed 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -38,6 +38,7 @@ use Symfony\Component\Console\Helper\TableHelper; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -849,17 +850,25 @@ class Application if ($event->commandShouldRun()) { try { + $e = null; $exitCode = $command->run($input, $output); - } catch (\Exception $e) { + } catch (\Exception $x) { + $e = $x; + } catch (\Throwable $x) { + $e = new FatalThrowableError($x); + } + if (null !== $e) { $event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode()); $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event); - $e = $event->getException(); + if ($e !== $event->getException()) { + $x = $e = $event->getException(); + } $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode()); $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); - throw $e; + throw $x; } } else { $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 918200d53c..eb04e8a0ad 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -949,6 +949,62 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertContains('before.foo.caught.after.', $tester->getDisplay()); } + /** + * @expectedException \LogicException + * @expectedExceptionMessage caught + */ + public function testRunWithErrorAndDispatcher() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dym')); + $this->assertContains('before.dym.caught.after.', $tester->getDisplay(), 'The PHP Error did not dispached events'); + } + + public function testRunDispatchesAllEventsWithError() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dym')); + $this->assertContains('before.dym.caught.after.', $tester->getDisplay(), 'The PHP Error did not dispached events'); + } + + public function testRunWithErrorFailingStatusCode() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('dus')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dus.'); + + throw new \Error('duserr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dus')); + $this->assertSame(1, $tester->getStatusCode(), 'Status code should be 1'); + } + public function testRunWithDispatcherSkippingCommand() { $application = new Application(); diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index b68129ddfc..1bd4af63cb 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/debug": "~2.7,>=2.7.2" }, "require-dev": { "symfony/event-dispatcher": "~2.1", From 9eb8524d184d575a052d4850db61e59125cc2b59 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 12 Sep 2016 12:06:58 +0200 Subject: [PATCH 18/18] [travis/appveyor] Wire simple-phpunit --- .github/build-packages.php | 74 +++++++++++++ .github/travis.php | 54 ---------- .travis.yml | 17 +-- appveyor.yml | 10 +- composer.json | 6 +- phpunit | 213 +------------------------------------ 6 files changed, 97 insertions(+), 277 deletions(-) create mode 100644 .github/build-packages.php delete mode 100644 .github/travis.php diff --git a/.github/build-packages.php b/.github/build-packages.php new file mode 100644 index 0000000000..2a2b4a396c --- /dev/null +++ b/.github/build-packages.php @@ -0,0 +1,74 @@ + $_SERVER['argc']) { + echo "Usage: branch version dir1 dir2 ... dirN\n"; + exit(1); +} +chdir(dirname(__DIR__)); + +$dirs = $_SERVER['argv']; +array_shift($dirs); +$mergeBase = trim(shell_exec(sprintf('git merge-base %s HEAD', array_shift($dirs)))); +$version = array_shift($dirs); + +$packages = array(); +$flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; + +foreach ($dirs as $k => $dir) { + if (!system("git diff --name-only $mergeBase -- $dir", $exitStatus)) { + if ($exitStatus) { + exit($exitStatus); + } + unset($dirs[$k]); + continue; + } + echo "$dir\n"; + + $json = ltrim(file_get_contents($dir.'/composer.json')); + if (null === $package = json_decode($json)) { + passthru("composer validate $dir/composer.json"); + exit(1); + } + + $package->repositories = array(array( + 'type' => 'composer', + 'url' => 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__)).'/', + )); + if (false === strpos($json, "\n \"repositories\": [\n")) { + $json = rtrim(json_encode(array('repositories' => $package->repositories), $flags), "\n}").','.substr($json, 1); + file_put_contents($dir.'/composer.json', $json); + } + passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); + + $package->version = $version.'.999'; + $package->dist['type'] = 'tar'; + $package->dist['url'] = 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__))."/$dir/package.tar"; + + $packages[$package->name][$package->version] = $package; + + $versions = file_get_contents('https://packagist.org/packages/'.$package->name.'.json'); + $versions = json_decode($versions); + + foreach ($versions->package->versions as $v => $package) { + $packages[$package->name] += array($v => $package); + } +} + +file_put_contents('packages.json', json_encode(compact('packages'), $flags)); + +if ($dirs) { + $json = ltrim(file_get_contents('composer.json')); + if (null === $package = json_decode($json)) { + passthru("composer validate $dir/composer.json"); + exit(1); + } + + $package->repositories = array(array( + 'type' => 'composer', + 'url' => 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__)).'/', + )); + if (false === strpos($json, "\n \"repositories\": [\n")) { + $json = rtrim(json_encode(array('repositories' => $package->repositories), $flags), "\n}").','.substr($json, 1); + file_put_contents('composer.json', $json); + } +} diff --git a/.github/travis.php b/.github/travis.php deleted file mode 100644 index 695c69604f..0000000000 --- a/.github/travis.php +++ /dev/null @@ -1,54 +0,0 @@ - $_SERVER['argc']) { - echo "Usage: branch version dir1 dir2 ... dirN\n"; - exit(1); -} -chdir(dirname(__DIR__)); - -$dirs = $_SERVER['argv']; -array_shift($dirs); -$branch = array_shift($dirs); -$version = array_shift($dirs); - -$packages = array(); -$flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; - -foreach ($dirs as $dir) { - if (!system("git diff --name-only $branch...HEAD -- $dir", $exitStatus)) { - if ($exitStatus) { - exit($exitStatus); - } - continue; - } - echo "$dir\n"; - - $json = ltrim(file_get_contents($dir.'/composer.json')); - if (null === $package = json_decode($json)) { - passthru("composer validate $dir/composer.json"); - exit(1); - } - - $package->repositories = array(array( - 'type' => 'composer', - 'url' => 'file://'.dirname(__DIR__).'/', - )); - $json = rtrim(json_encode(array('repositories' => $package->repositories), $flags), "\n}").','.substr($json, 1); - file_put_contents($dir.'/composer.json', $json); - passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); - - $package->version = $version.'.999'; - $package->dist['type'] = 'tar'; - $package->dist['url'] = 'file://'.dirname(__DIR__)."/$dir/package.tar"; - - $packages[$package->name][$package->version] = $package; - - $versions = file_get_contents('https://packagist.org/packages/'.$package->name.'.json'); - $versions = json_decode($versions); - - foreach ($versions->package->versions as $v => $package) { - $packages[$package->name] += array($v => $package); - } -} - -file_put_contents('packages.json', json_encode(compact('packages'), $flags)); diff --git a/.travis.yml b/.travis.yml index f7fbaa300c..57e639da85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,22 +58,27 @@ before_install: - if [[ ! $skip && ! $PHP = hhvm* ]]; then echo extension = ldap.so >> $INI_FILE; fi - if [[ ! $skip && ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi - if [[ ! $skip ]]; then [ -d ~/.composer ] || mkdir ~/.composer; cp .composer/* ~/.composer/; fi - - if [[ ! $skip ]]; then ./phpunit install; fi - if [[ ! $skip ]]; then export PHPUNIT=$(readlink -f ./phpunit); fi install: + - if [[ ! $skip && $deps ]]; then cp composer.json composer.json.orig; fi + - if [[ ! $skip && $deps ]]; then echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json; fi - if [[ ! $skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - - if [[ ! $skip && $deps ]]; then git fetch origin $TRAVIS_BRANCH && php .github/travis.php FETCH_HEAD $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then php .github/build-packages.php HEAD^ $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then mv composer.json composer.json.phpunit; mv composer.json.orig composer.json; fi + - if [[ ! $skip && ! $deps ]]; then php .github/build-packages.php HEAD^ $TRAVIS_BRANCH src/Symfony/Bridge/PhpUnit; fi # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi - - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi + - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev - - if [[ ! $deps ]]; then composer update; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi - - if [[ $TRAVIS_BRANCH = master ]]; then export SYMFONY_PHPUNIT_OVERLOAD=1; fi - - if [[ ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi + - if [[ ! $skip && $deps ]]; then export SYMFONY_DEPRECATIONS_HELPER=weak; fi + - if [[ ! $skip && $deps ]]; then mv composer.json.phpunit composer.json; fi + - if [[ ! $skip ]]; then composer update; fi + - if [[ ! $skip ]]; then COMPOSER_ROOT_VERSION= ./phpunit install; fi + - if [[ ! $skip && ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi script: - if [[ $skip ]]; then echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"; fi diff --git a/appveyor.yml b/appveyor.yml index 6e143bf4ab..768c52416d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -48,18 +48,20 @@ install: - echo curl.cainfo=c:\php\cacert.pem >> php.ini-max - copy /Y php.ini-max php.ini - cd c:\projects\symfony - - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.2.0/composer.phar) + - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.2.1/composer.phar) - php composer.phar self-update - copy /Y .composer\* %APPDATA%\Composer\ - - php phpunit install + - php .github/build-packages.php "HEAD^" %APPVEYOR_REPO_BRANCH% src\Symfony\Bridge\PhpUnit - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - php composer.phar update --no-progress --ansi + - SET COMPOSER_ROOT_VERSION= + - php phpunit install test_script: - cd c:\projects\symfony - SET X=0 - copy /Y c:\php\php.ini-min c:\php\php.ini - - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! + - php phpunit src\Symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! - copy /Y c:\php\php.ini-max c:\php\php.ini - - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! + - php phpunit src\Symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! - exit %X% diff --git a/composer.json b/composer.json index 613e53f5aa..05e9d158ae 100644 --- a/composer.json +++ b/composer.json @@ -78,6 +78,7 @@ "monolog/monolog": "~1.11", "ircmaxell/password-compat": "~1.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", + "symfony/phpunit-bridge": "~3.2", "egulias/email-validator": "~1.2,>=1.2.1" }, "autoload": { @@ -99,11 +100,6 @@ "**/Tests/" ] }, - "autoload-dev": { - "psr-4": { - "Symfony\\Bridge\\PhpUnit\\": "src/Symfony/Bridge/PhpUnit/" - } - }, "minimum-stability": "dev", "extra": { "branch-alias": { diff --git a/phpunit b/phpunit index 22432a093c..f9243bcbf9 100755 --- a/phpunit +++ b/phpunit @@ -1,212 +1,9 @@ #!/usr/bin/env php - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -// Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id-Version: 2016-06-29 13:45 UTC - -use Symfony\Component\Process\ProcessUtils; - -error_reporting(-1); -require __DIR__.'/src/Symfony/Component/Process/ProcessUtils.php'; - -// PHPUnit 4.8 does not support PHP 7, while 5.1 requires PHP 5.6+ -$PHPUNIT_VERSION = PHP_VERSION_ID >= 50600 ? '5.1' : '4.8'; -$PHPUNIT_DIR = __DIR__.'/.phpunit'; -$PHP = defined('PHP_BINARY') ? PHP_BINARY : 'php'; -$PHP = ProcessUtils::escapeArgument($PHP); -if ('phpdbg' === PHP_SAPI) { - $PHP .= ' -qrr'; +if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) { + echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n"; + exit(1); } - -$COMPOSER = file_exists($COMPOSER = __DIR__.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar`)) - ? $PHP.' '.ProcessUtils::escapeArgument($COMPOSER) - : 'composer'; - -if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__FILE__) !== @file_get_contents("$PHPUNIT_DIR/.$PHPUNIT_VERSION.md5")) { - // Build a standalone phpunit without symfony/yaml - - $oldPwd = getcwd(); - @mkdir($PHPUNIT_DIR); - chdir($PHPUNIT_DIR); - if (file_exists("phpunit-$PHPUNIT_VERSION")) { - passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? '(del /S /F /Q %s & rmdir %1$s) >nul': 'rm -rf %s', "phpunit-$PHPUNIT_VERSION")); - } - if (extension_loaded('openssl') && ini_get('allow_url_fopen')) { - stream_copy_to_stream(fopen("https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip", 'rb'), fopen("$PHPUNIT_VERSION.zip", 'wb')); - } else { - @unlink("$PHPUNIT_VERSION.zip"); - passthru("wget https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip"); - } - $zip = new ZipArchive(); - $zip->open("$PHPUNIT_VERSION.zip"); - $zip->extractTo(getcwd()); - $zip->close(); - chdir("phpunit-$PHPUNIT_VERSION"); - passthru("$COMPOSER remove --no-update phpspec/prophecy"); - passthru("$COMPOSER remove --no-update symfony/yaml"); - if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { - passthru("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); - } - passthru("$COMPOSER require --dev --no-update symfony/phpunit-bridge \">=3.2@dev\""); - passthru("$COMPOSER install --prefer-dist --no-progress --ansi", $exit); - if ($exit) { - exit($exit); - } - file_put_contents('phpunit', <<<'EOPHP' -addPsr4('Symfony\\Bridge\\PhpUnit\\', array('src/Symfony/Bridge/PhpUnit'), true); -} -unset($loader); -Symfony\Bridge\PhpUnit\TextUI\Command::main(); - -EOPHP - ); - chdir('..'); - file_put_contents(".$PHPUNIT_VERSION.md5", md5_file(__FILE__)); - chdir($oldPwd); - -} - -$cmd = array_map('Symfony\Component\Process\ProcessUtils::escapeArgument', $argv); -$exit = 0; - -if (isset($argv[1]) && 'symfony' === $argv[1]) { - array_shift($cmd); -} - -$cmd[0] = sprintf('%s %s --colors=always', $PHP, ProcessUtils::escapeArgument("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit")); -$cmd = str_replace('%', '%%', implode(' ', $cmd)).' %1$s'; - -if ('\\' === DIRECTORY_SEPARATOR) { - $cmd = 'cmd /v:on /d /c "('.$cmd.')%2$s"'; -} else { - $cmd .= '%2$s'; -} - -if (isset($argv[1]) && 'symfony' === $argv[1]) { - // Find Symfony components in plain php for Windows portability - - $oldPwd = getcwd(); - chdir(__DIR__); - $finder = new RecursiveDirectoryIterator('src/Symfony', FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::UNIX_PATHS); - $finder = new RecursiveIteratorIterator($finder); - $finder->setMaxDepth(3); - - $skippedTests = isset($_SERVER['SYMFONY_PHPUNIT_SKIPPED_TESTS']) ? $_SERVER['SYMFONY_PHPUNIT_SKIPPED_TESTS'] : false; - $runningProcs = array(); - - foreach ($finder as $file => $fileInfo) { - if ('phpunit.xml.dist' === $file) { - $component = dirname($fileInfo->getPathname()); - - // Run phpunit tests in parallel - - if ($skippedTests) { - putenv("SYMFONY_PHPUNIT_SKIPPED_TESTS=$component/$skippedTests"); - } - - $c = ProcessUtils::escapeArgument($component); - - if ($proc = proc_open(sprintf($cmd, $c, " > $c/phpunit.stdout 2> $c/phpunit.stderr"), array(), $pipes)) { - $runningProcs[$component] = $proc; - } else { - $exit = 1; - echo "\033[41mKO\033[0m $component\n\n"; - } - } - } - chdir($oldPwd); - - // Fixes for colors support on appveyor - // See https://github.com/appveyor/ci/issues/373 - $colorFixes = array( - array("S\033[0m\033[0m\033[36m\033[1mS", "E\033[0m\033[0m\033[31m\033[1mE", "I\033[0m\033[0m\033[33m\033[1mI", "F\033[0m\033[0m\033[41m\033[37mF"), - array("SS", "EE", "II", "FF"), - ); - $colorFixes[0] = array_merge($colorFixes[0], $colorFixes[0]); - $colorFixes[1] = array_merge($colorFixes[1], $colorFixes[1]); - - while ($runningProcs) { - usleep(300000); - $terminatedProcs = array(); - foreach ($runningProcs as $component => $proc) { - $procStatus = proc_get_status($proc); - if (!$procStatus['running']) { - $terminatedProcs[$component] = $procStatus['exitcode']; - unset($runningProcs[$component]); - proc_close($proc); - } - } - - foreach ($terminatedProcs as $component => $procStatus) { - foreach (array('out', 'err') as $file) { - $file = "$component/phpunit.std$file"; - - if ('\\' === DIRECTORY_SEPARATOR) { - $h = fopen($file, 'rb'); - while (false !== $line = fgets($h)) { - echo str_replace($colorFixes[0], $colorFixes[1], preg_replace( - '/(\033\[[0-9]++);([0-9]++m)(?:(.)(\033\[0m))?/', - "$1m\033[$2$3$4$4", - $line - )); - } - fclose($h); - } else { - readfile($file); - } - unlink($file); - } - - // Fail on any individual component failures but ignore some error codes on Windows when APCu is enabled: - // STATUS_STACK_BUFFER_OVERRUN (-1073740791/0xC0000409) - // STATUS_ACCESS_VIOLATION (-1073741819/0xC0000005) - // STATUS_HEAP_CORRUPTION (-1073740940/0xC0000374) - if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || !in_array($procStatus, array(-1073740791, -1073741819, -1073740940)))) { - $exit = $procStatus; - echo "\033[41mKO\033[0m $component\n\n"; - } else { - echo "\033[32mOK\033[0m $component\n\n"; - } - } - } -} elseif (!isset($argv[1]) || 'install' !== $argv[1]) { - // Run regular phpunit in a subprocess - - $errFile = tempnam(sys_get_temp_dir(), 'phpunit.stderr.'); - if ($proc = proc_open(sprintf($cmd, '', ' 2> '.ProcessUtils::escapeArgument($errFile)), array(1 => array('pipe', 'w')), $pipes)) { - stream_copy_to_stream($pipes[1], STDOUT); - fclose($pipes[1]); - $exit = proc_close($proc); - - readfile($errFile); - unlink($errFile); - } - - if (!file_exists($component = array_pop($argv))) { - $component = basename(getcwd()); - } - - if ($exit) { - echo "\033[41mKO\033[0m $component\n\n"; - } else { - echo "\033[32mOK\033[0m $component\n\n"; - } -} - -exit($exit); +putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); +require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit';