8000 Merge branch '4.1' · symfony/symfony@b1ae305 · GitHub
[go: up one dir, main page]

Skip to content

Commit b1ae305

Browse files
Merge branch '4.1'
* 4.1: [TwigBridge] fix lowest version of symfony/form Think positive KernelInterface can return null container [DI] Detect circular references with ChildDefinition parent [VarDumper] Fix global dump function return value for PHP7 [Ldap] Use shut up operator on connection errors at ldap_start_tls Implement startTest rather than startTestSuite [OptionsResolver] remove dead code and useless else [HttpFoundation] don't override StreamedResponse::setNotModified() Added relevent links for parsing to the phpdoc Add stricter checking for valid date time string Fix symfony/console (optional) dependency for MonologBridge fix not displaying labels when value is false [Form] Fix DateTimeType html5 input format
2 parents 440944f + 1b19d80 commit b1ae305

File tree

21 files changed

+369
-76
lines changed

21 files changed

+369
-76
lines changed

src/Symfony/Bridge/Monolog/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@
2828
"symfony/var-dumper": "~3.4|~4.0"
2929
},
3030
"conflict": {
31+
"symfony/console": "<3.4",
3132
"symfony/http-foundation": "<3.4"
3233
},
3334
"suggest": {
3435
"symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.",
35-
"symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings. You need version ~2.3 of the console for it.",
36+
"symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.",
3637
"symfony/event-dispatcher": "Needed when using log messages in console commands.",
3738
"symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler."
3839
},

src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerForV5.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
namespace Symfony\Bridge\PhpUnit\Legacy;
1313

1414
/**
15-
* CoverageListener adds `@covers <className>` on each test suite when possible
16-
* to make the code coverage more accurate.
15+
* CoverageListener adds `@covers <className>` on each test when possible to
16+
* make the code coverage more accurate.
1717
*
1818
* @author Grégoire Pineau <lyrixx@lyrixx.info>
1919
*

src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerForV6.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
use PHPUnit\Framework\Test;
1616

1717
/**
18-
* CoverageListener adds `@covers <className>` on each test suite when possible
19-
* to make the code coverage more accurate.
18+
* CoverageListener adds `@covers <className>` on each test when possible to
19+
* make the code coverage more accurate.
2020
*
2121
* @author Grégoire Pineau <lyrixx@lyrixx.info>
2222
*

src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerForV7.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111

1212
namespace Symfony\Bridge\PhpUnit\Legacy;
1313

14+
use PHPUnit\Framework\Test;
1415
use PHPUnit\Framework\TestListener;
1516
use PHPUnit\Framework\TestListenerDefaultImplementation;
16-
use PHPUnit\Framework\TestSuite;
1717

1818
/**
19-
* CoverageListener adds `@covers <className>` on each test suite when possible
20-
* to make the code coverage more accurate.
19+
* CoverageListener adds `@covers <className>` on each test when possible to
20+
* make the code coverage more accurate.
2121
*
2222
* @author Grégoire Pineau <lyrixx@lyrixx.info>
2323
*
@@ -34,8 +34,8 @@ public function __construct(callable $sutFqcnResolver = null, $warningOnSutNotFo
3434
$this->trait = new CoverageListenerTrait($sutFqcnResolver, $warningOnSutNotFound);
3535
}
3636

37-
public function startTestSuite(TestSuite $suite): void
37+
public function startTest(Test $test): void
3838
{
39-
$this->trait->startTest($suite);
39+
$this->trait->startTest($test);
4040
}
4141
}

src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_base_layout.html.twig

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,13 @@
6464
{%- if datetime is not defined or not datetime -%}
6565
<div {{ block('widget_container_attributes') -}}>
6666
{%- endif %}
67+
{%- if label is not same as(false) -%}
6768
<div class="sr-only">
6869
{{ form_label(form.year) }}
6970
{{ form_label(form.month) }}
7071
{{ form_label(form.day) }}
7172
</div>
73+
{%- endif -%}
7274

7375
{{- date_pattern|replace({
7476
'{{ year }}': form_widget(form.year),
@@ -89,10 +91,10 @@
8991
{%- if datetime is not defined or false == datetime -%}
9092
<div {{ block('widget_container_attributes') -}}>
9193
{%- endif -%}
92-
<div class="sr-only">{{ form_label(form.hour) }}</div>
94+
{%- if label is not same as(false) -%}<div class="sr-only">{{ form_label(form.hour) }}</div>{%- endif -%}
9395
{{- form_widget(form.hour) -}}
94-
{%- if with_minutes -%}:<div class="sr-only">{{ form_label(form.minute) }}</div>{{ form_widget(form.minute) }}{%- endif -%}
95-
{%- if with_seconds -%}:<div class="sr-only">{{ form_label(form.second) }}</div>{{ form_widget(form.second) }}{%- endif -%}
96+
{%- if with_minutes -%}:{%- if label is not same as(false) -%}<div class="sr-only">{{ form_label(form.minute) }}</div>{%- endif -%}{{ form_widget(form.minute) }}{%- endif -%}
97+
{%- if with_seconds -%}:{%- if label is not same as(false) -%}<div class="sr-only">{{ form_label(form.second) }}</div>{%- endif -%}{{ form_widget(form.second) }}{%- endif -%}
9698
{%- if datetime is not defined or false == datetime -%}
9799
</div>
98100
{%- endif -%}

src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,7 @@ public function testDateTimeWithWidgetSingleText()
15771577
[@type="datetime-local"]
15781578
[@name="name"]
15791579
[@class="my&class form-control"]
1580-
[@value="2011-02-03T04:05:06Z"]
1580+
[@value="2011-02-03T04:05:06"]
15811581
'
15821582
);
15831583
}
@@ -1598,7 +1598,7 @@ public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
15981598
[@type="datetime-local"]
15991599
[@name="name"]
16001600
[@class="my&class form-control"]
1601-
[@value="2011-02-03T04:05:06Z"]
1601+
[@value="2011-02-03T04:05:06"]
16021602
'
16031603
);
16041604
}

src/Symfony/Bridge/Twig/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"symfony/asset": "~3.4|~4.0",
2424
"symfony/dependency-injection": "~3.4|~4.0",
2525
"symfony/finder": "~3.4|~4.0",
26-
"symfony/form": "^4.1.2",
26+
"symfony/form": "^4.1.5",
2727
"symfony/http-foundation": "~3.4|~4.0",
2828
"symfony/http-kernel": "~3.4|~4.0",
2929
"symfony/polyfill-intl-icu": "~1.0",

src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\Definition;
1616
use Symfony\Component\DependencyInjection\Exception\ExceptionInterface;
1717
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18+
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1819

1920
/**
2021
* This replaces all ChildDefinition instances with their equivalent fully
@@ -25,6 +26,8 @@
2526
*/
2627
class ResolveChildDefinitionsPass extends AbstractRecursivePass
2728
{
29+
private $currentPath;
30+
2831
protected function processValue($value, $isRoot = false)
2932
{
3033
if (!$value instanceof Definition) {
@@ -36,6 +39,7 @@ protected function processValue($value, $isRoot = false)
3639
$value = $this->container->getDefinition($this->currentId);
3740
}
3841
if ($value instanceof ChildDefinition) {
42+
$this->currentPath = array();
3943
$value = $this->resolveDefinition($value);
4044
if ($isRoot) {
4145
$this->container->setDefinition($this->currentId, $value);
@@ -56,6 +60,8 @@ private function resolveDefinition(ChildDefinition $definition)
5660
{
5761
try {
5862
return $this->doResolveDefinition($definition);
63+
} catch (ServiceCircularReferenceException $e) {
64+
throw $e;
5965
} catch (ExceptionInterface $e) {
6066
$r = new \ReflectionProperty($e, 'message');
6167
$r->setAccessible(true);
@@ -71,6 +77,13 @@ private function doResolveDefinition(ChildDefinition $definition)
7177
throw new RuntimeException(sprintf('Parent definition "%s" does not exist.', $parent));
7278
}
7379

80+
$searchKey = array_search($parent, $this->currentPath);
81+
$this->currentPath[] = $parent;
82+
83+
if (false !== $searchKey) {
84+
throw new ServiceCircularReferenceException($parent, \array_slice($this->currentPath, $searchKey));
85+
}
86+
7487
$parentDef = $this->container->findDefinition($parent);
7588
if ($parentDef instanceof ChildDefinition) {
7689
$id = $this->currentId;

src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveChildDefinitionsPassTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,4 +396,21 @@ protected function process(ContainerBuilder $container)
396396
$pass = new ResolveChildDefinitionsPass();
397397
$pass->process($container);
398398
}
399+
400+
/**
401+
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
402+
* @expectedExceptionMessageRegExp /^Circular reference detected for service "c", path: "c -> b -> a -> c"./
403+
*/
404+
public function testProcessDetectsChildDefinitionIndirectCircularReference()
405+
{
406+
$container = new ContainerBuilder();
407+
408+
$container->register('a');
409+
410+
$container->setDefinition('b', new ChildDefinition('a'));
411+
$container->setDefinition('c', new ChildDefinition('b'));
412+
$container->setDefinition('a', new ChildDefinition('c'));
413+
414+
$this->process($container);
415+
}
399416
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13+
14+
use Symfony\Component\Form\Exception\TransformationFailedException;
15+
16+
/**
17+
* @author Franz Wilding <franz.wilding@me.com>
18+
* @author Bernhard Schussek <bschussek@gmail.com>
19+
* @author Fred Cox <mcfedr@gmail.com>
20+
*/
21+
class DateTimeToHtml5LocalDateTimeTransformer extends BaseDateTimeTransformer
22+
{
23+
const HTML5_FORMAT = 'Y-m-d\\TH:i:s';
24+
25+
/**
26+
* Transforms a \DateTime into a local date and time string.
27+
*
28+
* According to the HTML standard, the input string of a datetime-local
29+
* input is a RFC3339 date followed by 'T', followed by a RFC3339 time.
30+
* https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-local-date-and-time-string
31+
*
32+
* @param \DateTime|\DateTimeInterface $dateTime A DateTime object
33+
*
34+
* @return string The formatted date
35+
*
36+
* @throws TransformationFailedException If the given value is not an
37+
* instance of \DateTime or \DateTimeInterface
38+
*/
39+
public function transform($dateTime)
40+
{
41+
if (null === $dateTime) {
42+
return '';
43+
}
44+
45+
if (!$dateTime instanceof \DateTime && !$dateTime instanceof \DateTimeInterface) {
46+
throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
47+
}
48+
49+
if ($this->inputTimezone !== $this->outputTimezone) {
50+
if (!$dateTime instanceof \DateTimeImmutable) {
51+
$dateTime = clone $dateTime;
52+
}
53+
54+
$dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
55+
}
56+
57+
return $dateTime->format(self::HTML5_FORMAT);
58+
}
59+
60+
/**
61+
* Transforms a local date and time string into a \DateTime.
62+
*
63+
* When transforming back to DateTime the regex is slightly laxer, taking into
64+
* account rules for parsing a local date and time string
65+
* https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-local-date-and-time-string
66+
*
67+
* @param string $dateTimeLocal Formatted string
68+
*
69+
* @return \DateTime Normalized date
70+
*
71+
* @throws TransformationFailedException If the given value is not a string,
72+
* if the value could not be transformed
73+
*/
74+
public function reverseTransform($dateTimeLocal)
75+
{
76+
if (!\is_string($dateTimeLocal)) {
77+
throw new TransformationFailedException('Expected a string.');
78+
}
79+
80+
if ('' === $dateTimeLocal) {
81+
return;
82+
}
83+
84+
if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})[T ]\d{2}:\d{2}(?::\d{2})?$/', $dateTimeLocal, $matches)) {
85+
throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $dateTimeLocal));
86+
}
87+
88+
try {
89+
$dateTime = new \DateTime($dateTimeLocal, new \DateTimeZone($this->outputTimezone));
90+
} catch (\Exception $e) {
91+
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
92+
}
93+
94+
if ($this->inputTimezone !== $dateTime->getTimezone()->getName()) {
95+
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
96+
}
97+
98+
if (!checkdate($matches[2], $matches[3], $matches[1])) {
99+
throw new TransformationFailedException(sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3]));
100+
}
101+
102+
return $dateTime;
103+
}
104+
}

src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
1717
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
1818
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
19+
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToHtml5LocalDateTimeTransformer;
1920
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
20-
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
2121
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
2222
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
2323
use Symfony\Component\Form\FormBuilderInterface;
@@ -34,21 +34,8 @@ class DateTimeType extends AbstractType
3434
const DEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM;
3535

3636
/**
37-
* This is not quite the HTML5 format yet, because ICU lacks the
38-
* capability of parsing and generating RFC 3339 dates.
39-
*
40-
* For more information see:
41-
*
42-
* http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
43-
* https://www.w3.org/TR/html5/sec-forms.html#local-date-and-time-state-typedatetimelocal
44-
* http://tools.ietf.org/html/rfc3339
45-
*
46-
* An ICU ticket was created:
47-
* http://icu-project.org/trac/ticket/9421
48-
*
49-
* It was supposedly fixed, but is not available in all PHP installations
50-
* yet. To temporarily circumvent this issue, DateTimeToRfc3339Transformer
51-
* is used when the format matches this constant.
37+
* The HTML5 datetime-local format as defined in
38+
* http://w3c.github.io/html-reference/datatypes.html#form.data.datetime-local.
5239
*/
5340
const HTML5_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
5441

@@ -89,7 +76,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8976

9077
if ('single_text' === $options['widget']) {
9178
if (self::HTML5_FORMAT === $pattern) {
92-
$builder->addViewTransformer(new DateTimeToRfc3339Transformer(
79+
$builder->addViewTransformer(new DateTimeToHtml5LocalDateTimeTransformer(
9380
$options['model_timezone'],
9481
$options['view_timezone']
9582
));
@@ -133,6 +120,11 @@ public function buildForm(FormBuilderInterface $builder, array $options)
133120
'invalid_message_parameters',
134121
)));
135122

123+
if (false === $options['label']) {
124+
$dateOptions['label'] = false;
125+
$timeOptions['label'] = false;
126+
}
127+
136128
if (null !== $options['date_widget']) {
137129
$dateOptions['widget'] = $options['date_widget'];
138130
}

src/Symfony/Component/Form/Tests/AbstractLayoutTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ public function testDateTimeWithWidgetSingleText()
15011501
'/input
15021502
[@type="datetime-local"]
15031503
[@name="name"]
1504-
[@value="2011-02-03T04:05:06Z"]
1504+
[@value="2011-02-03T04:05:06"]
15051505
'
15061506
);
15071507
}
@@ -1521,7 +1521,7 @@ public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
15211521
'/input
15221522
[@type="datetime-local"]
15231523
[@name="name"]
1524-
[@value="2011-02-03T04:05:06Z"]
1524+
[@value="2011-02-03T04:05:06"]
15251525
'
15261526
);
15271527
}

0 commit comments

Comments
 (0)
0