diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 99ba8e0021..216a2ba4e5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,19 @@ | Q | A | ------------- | --- -| Branch? | "master" for new features / 2.7, 2.8 or 3.1 for fixes +| Branch? | master / 2.7, 2.8, 3.1 or 3.2 | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | yes/no | Deprecations? | yes/no | Tests pass? | yes/no -| Fixed tickets | comma-separated list of tickets fixed by the PR, if any +| Fixed tickets | #... | License | MIT -| Doc PR | reference to the documentation PR, if any +| Doc PR | symfony/symfony-docs#... + + diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 9f846a3ecb..a832b68b48 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -37,7 +37,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ 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')) { + if (extension_loaded('openssl') && ini_get('allow_url_fopen') && !isset($_SERVER['http_proxy']) && !isset($_SERVER['https_proxy'])) { 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"); diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index d5c08038ec..81a8683c35 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -31,7 +31,7 @@ class FormExtension extends \Twig_Extension implements \Twig_Extension_InitRunti public function __construct($renderer = null) { - if ($this->renderer instanceof TwigRendererInterface) { + if ($renderer instanceof TwigRendererInterface) { @trigger_error(sprintf('Passing a Twig Form Renderer to the "%s" constructor is deprecated since version 3.2 and won\'t be possible in 4.0. Pass the Twig_Environment to the TwigRendererEngine constructor instead.', static::class), E_USER_DEPRECATED); } elseif (null !== $renderer && !(is_array($renderer) && isset($renderer[0], $renderer[1]) && $renderer[0] instanceof ContainerInterface)) { throw new \InvalidArgumentException(sprintf('Passing any arguments the constructor of %s is reserved for internal use.', __CLASS__)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php index 17571fb48a..33073b0a91 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php @@ -105,7 +105,7 @@ EOF $io->title(sprintf('Current configuration for "%s.%s"', $extensionAlias, $path)); - $io->writeln(Yaml::dump($config, 10)); + $io->writeln(Yaml::dump($container->getParameterBag()->resolveValue($config), 10)); } private function compileContainer() diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php index 40604e3d80..0287f42a8e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @@ -17,7 +17,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Workflow\Dumper\GraphvizDumper; use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper; use Symfony\Component\Workflow\Marking; -use Symfony\Component\Workflow\Workflow; /** * @author Grégoire Pineau diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php index 1dbf54b5ad..90daa3eead 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php @@ -137,7 +137,7 @@ abstract class Controller implements ContainerAwareInterface protected function file($file, $fileName = null, $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT) { $response = new BinaryFileResponse($file); - $response->setContentDisposition($disposition, $fileName === null ? $response->getFile()->getFileName() : $fileName); + $response->setContentDisposition($disposition, $fileName === null ? $response->getFile()->getFilename() : $fileName); return $response; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 940f546518..4388b70afe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -20,7 +20,6 @@ use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\ProxyAdapter; use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception.html.twig index f405f6473e..b017420dd5 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception.html.twig @@ -9,9 +9,7 @@
-

- {{ exception.message|nl2br|format_file_from_text }} -

+

{{ exception.message|nl2br|format_file_from_text }}

{{ status_code }} {{ status_text }} - {{ exception.class|abbr_class }} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig index 3b79db20a6..628e87dec1 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig @@ -457,7 +457,7 @@ {% import _self as tree %}

- {{ name|default('(no name)') }} ({{ profiler_dump(data.type_class) }}) + {{ name|default('(no name)') }} {% if data.type_class is defined %}({{ profiler_dump(data.type_class) }}){% endif %}

{% if data.errors is defined and data.errors|length > 0 %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index eee7ffc759..ca69e371df 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -234,15 +234,28 @@ var oldFetch = window.fetch; window.fetch = function () { var promise = oldFetch.apply(this, arguments); - if (!arguments[0].match(new RegExp({{ excluded_ajax_paths|json_encode|raw }}))) { + var url = arguments[0]; + var params = arguments[1]; + var paramType = Object.prototype.toString.call(arguments[0]); + if (paramType === '[object Request]') { + url = arguments[0].url; + params = { + method: arguments[0].method, + credentials: arguments[0].credentials, + headers: arguments[0].headers, + mode: arguments[0].mode, + redirect: arguments[0].redirect + }; + } + if (!url.match(new RegExp({{ excluded_ajax_paths|json_encode|raw }}))) { var method = 'GET'; - if (arguments[1] && arguments[1].method !== undefined) { - method = arguments[1].method; + if (params && params.method !== undefined) { + method = params.method; } var stackElement = { error: false, - url: arguments[0], + url: url, method: method, type: 'fetch', start: new Date() diff --git a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php index d2591c1fb0..8e09280ca4 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php @@ -93,7 +93,7 @@ class PhpFilesAdapter extends AbstractAdapter $ok = true; $data = array($lifetime ? time() + $lifetime : PHP_INT_MAX, ''); - foreach ($values as $id => $value) { + foreach ($values as $key => $value) { if (null === $value || is_object($value)) { $value = serialize($value); } elseif (is_array($value)) { @@ -109,13 +109,16 @@ class PhpFilesAdapter extends AbstractAdapter $value = serialize($value); } } elseif (!is_scalar($value)) { - throw new InvalidArgumentException(sprintf('Value of type "%s" is not serializable', $key, gettype($value))); + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, gettype($value))); } $data[1] = $value; - $file = $this->getFile($id, true); + $file = $this->getFile($key, true); $ok = $this->write($file, 'depth('> 1') // the Finder will start matching at level 1. * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point. * - * @param int $level The depth level expression + * @param string|int $level The depth level expression * * @return Finder|SplFileInfo[] The current Finder instance * @@ -283,7 +283,7 @@ class Finder implements \IteratorAggregate, \Countable * $finder->size('<= 1Ki'); * $finder->size(4); * - * @param string $size A size range string + * @param string|int $size A size range string or an integer * * @return Finder|SplFileInfo[] The current Finder instance * diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php index fb2b7d7ff3..6e8139f502 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php @@ -102,14 +102,12 @@ class DateIntervalType extends AbstractType $childOptions[$part] = array(); $childOptions[$part]['error_bubbling'] = true; if ('choice' === $options['widget']) { + $childOptions[$part]['choice_translation_domain'] = false; $childOptions[$part]['choices'] = $options[$part]; $childOptions[$part]['placeholder'] = $options['placeholder'][$part]; } } } - $invertOptions = array( - 'error_bubbling' => true, - ); // Append generic carry-along options foreach (array('required', 'translation_domain') as $passOpt) { foreach ($this->timeParts as $part) { @@ -117,9 +115,6 @@ class DateIntervalType extends AbstractType $childOptions[$part][$passOpt] = $options[$passOpt]; } } - if ($options['with_invert']) { - $invertOptions[$passOpt] = $options[$passOpt]; - } } foreach ($this->timeParts as $part) { if ($options['with_'.$part]) { @@ -135,7 +130,11 @@ class DateIntervalType extends AbstractType } } if ($options['with_invert']) { - $builder->add('invert', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType', $invertOptions); + $builder->add('invert', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType', array( + 'error_bubbling' => true, + 'required' => false, + 'translation_domain' => $options['translation_domain'], + )); } $builder->addViewTransformer(new DateIntervalToArrayTransformer($parts, 'text' === $options['widget'])); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php index e40c0949f6..8d44e3c934 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\DateIntervalType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\Test\TypeTestCase as TestCase; @@ -364,4 +365,38 @@ class DateIntervalTypeTest extends TestCase $this->assertSame(array(), iterator_to_array($form['years']->getErrors())); $this->assertSame(array($error), iterator_to_array($form->getErrors())); } + + public function testTranslationsAreDisabledForChoiceWidget() + { + $form = $this->factory->create( + DateIntervalType::class, + null, + array( + 'widget' => 'choice', + 'with_hours' => true, + 'with_minutes' => true, + 'with_seconds' => true, + ) + ); + $this->assertFalse($form->get('years')->getConfig()->getOption('choice_translation_domain')); + $this->assertFalse($form->get('months')->getConfig()->getOption('choice_translation_domain')); + $this->assertFalse($form->get('days')->getConfig()->getOption('choice_translation_domain')); + $this->assertFalse($form->get('hours')->getConfig()->getOption('choice_translation_domain')); + $this->assertFalse($form->get('minutes')->getConfig()->getOption('choice_translation_domain')); + $this->assertFalse($form->get('seconds')->getConfig()->getOption('choice_translation_domain')); + } + + public function testInvertDoesNotInheritRequiredOption() + { + $form = $this->factory->create( + 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType', + null, + array( + 'input' => 'dateinterval', + 'with_invert' => true, + 'required' => true, + ) + ); + $this->assertFalse($form->get('invert')->getConfig()->getOption('required')); + } } diff --git a/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php b/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php index 4ba7640044..41ac04f209 100644 --- a/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php @@ -13,7 +13,6 @@ namespace Symfony\Component\Serializer\Encoder; use Symfony\Component\Yaml\Dumper; use Symfony\Component\Yaml\Parser; -use Symfony\Component\Yaml\Yaml; /** * Encodes YAML data. diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index bcec4d7fcb..01c5adf996 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -18,6 +18,7 @@ use Symfony\Component\Serializer\Exception\LogicException; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; @@ -68,9 +69,10 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer $stack = array(); $attributes = $this->getAttributes($object, $format, $context); $class = get_class($object); + $attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null; foreach ($attributes as $attribute) { - if ($this->isMaxDepthReached($class, $attribute, $context)) { + if (null !== $attributesMetadata && $this->isMaxDepthReached($attributesMetadata, $class, $attribute, $context)) { continue; } @@ -300,42 +302,35 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer /** * Is the max depth reached for the given attribute? * - * @param string $class - * @param string $attribute - * @param array $context + * @param AttributeMetadataInterface[] $attributesMetadata + * @param string $class + * @param string $attribute + * @param array $context * * @return bool */ - private function isMaxDepthReached($class, $attribute, array &$context) + private function isMaxDepthReached(array $attributesMetadata, $class, $attribute, array &$context) { - if (!$this->classMetadataFactory || !isset($context[static::ENABLE_MAX_DEPTH])) { - return false; - } - - $classMetadata = $this->classMetadataFactory->getMetadataFor($class); - $attributesMetadata = $classMetadata->getAttributesMetadata(); - - if (!isset($attributesMetadata[$attribute])) { - return false; - } - - $maxDepth = $attributesMetadata[$attribute]->getMaxDepth(); - if (null === $maxDepth) { + if ( + !isset($context[static::ENABLE_MAX_DEPTH]) || + !isset($attributesMetadata[$attribute]) || + null === $maxDepth = $attributesMetadata[$attribute]->getMaxDepth() + ) { return false; } $key = sprintf(static::DEPTH_KEY_PATTERN, $class, $attribute); - $keyExist = isset($context[$key]); + if (!isset($context[$key])) { + $context[$key] = 1; - if ($keyExist && $context[$key] === $maxDepth) { + return false; + } + + if ($context[$key] === $maxDepth) { return true; } - if ($keyExist) { - ++$context[$key]; - } else { - $context[$key] = 1; - } + ++$context[$key]; return false; } diff --git a/src/Symfony/Component/VarDumper/Caster/StubCaster.php b/src/Symfony/Component/VarDumper/Caster/StubCaster.php index 5674c09ef3..f8b13afcef 100644 --- a/src/Symfony/Component/VarDumper/Caster/StubCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/StubCaster.php @@ -31,8 +31,8 @@ class StubCaster $stub->attr = $c->attr; if (Stub::TYPE_REF === $c->type && !$c->class && is_string($c->value) && !preg_match('//u', $c->value)) { - $stub->type = self::TYPE_STRING; - $stub->class = self::STRING_BINARY; + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_BINARY; } return array(); diff --git a/src/Symfony/Component/Workflow/DefinitionBuilder.php b/src/Symfony/Component/Workflow/DefinitionBuilder.php index 447d67337d..34d27aa5e9 100644 --- a/src/Symfony/Component/Workflow/DefinitionBuilder.php +++ b/src/Symfony/Component/Workflow/DefinitionBuilder.php @@ -79,6 +79,9 @@ class DefinitionBuilder } } + /** + * @param Transition[] $transitions + */ public function addTransitions(array $transitions) { foreach ($transitions as $transition) { diff --git a/src/Symfony/Component/Workflow/Registry.php b/src/Symfony/Component/Workflow/Registry.php index 619ed5f66a..53e06fbb5e 100644 --- a/src/Symfony/Component/Workflow/Registry.php +++ b/src/Symfony/Component/Workflow/Registry.php @@ -30,6 +30,12 @@ class Registry $this->workflows[] = array($workflow, $className); } + /** + * @param object $subject + * @param string|null $workflowName + * + * @return Workflow + */ public function get($subject, $workflowName = null) { $matched = null; diff --git a/src/Symfony/Component/Workflow/Tests/StateMachineTest.php b/src/Symfony/Component/Workflow/Tests/StateMachineTest.php index 7dca9a824d..7e0a656938 100644 --- a/src/Symfony/Component/Workflow/Tests/StateMachineTest.php +++ b/src/Symfony/Component/Workflow/Tests/StateMachineTest.php @@ -2,7 +2,6 @@ namespace Symfony\Component\Workflow\Tests; -use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\StateMachine; class StateMachineTest extends \PHPUnit_Framework_TestCase diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index c6e5830bd5..8ad3b1e1b2 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -463,8 +463,8 @@ class Inline break; } - if (!isset($mapping[$i + 1]) || ' ' !== $mapping[$i + 1]) { - @trigger_error('Omitting the space after the colon that follows a mapping key definition is deprecated since version 3.2 and will throw a ParseException in 4.0.', E_USER_DEPRECATED); + if (!isset($mapping[$i + 1]) || !in_array($mapping[$i + 1], array(' ', '[', ']', '{', '}'), true)) { + @trigger_error('Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0.', E_USER_DEPRECATED); } // value diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 33bda676f4..355deb454a 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -166,7 +166,7 @@ class InlineTest extends \PHPUnit_Framework_TestCase /** * @group legacy - * @expectedDeprecation Omitting the space after the colon that follows a mapping key definition is deprecated since version 3.2 and will throw a ParseException in 4.0. + * @expectedDeprecation Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0. * throws \Symfony\Component\Yaml\Exception\ParseException in 4.0 */ public function testParseMappingKeyWithColonNotFollowedBySpace() @@ -395,6 +395,8 @@ class InlineTest extends \PHPUnit_Framework_TestCase array('[foo, {bar: foo}]', array('foo', array('bar' => 'foo'))), array('{ foo: {bar: foo} }', array('foo' => array('bar' => 'foo'))), array('{ foo: [bar, foo] }', array('foo' => array('bar', 'foo'))), + array('{ foo:{bar: foo} }', array('foo' => array('bar' => 'foo'))), + array('{ foo:[bar, foo] }', array('foo' => array('bar', 'foo'))), array('[ foo, [ bar, foo ] ]', array('foo', array('bar', 'foo'))),