Skip to content

[Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds #20307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from

Conversation

LuisDeimos
Copy link
Contributor

@LuisDeimos LuisDeimos commented Oct 26, 2016

Q A
Branch? 2.7
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets 20304
License MIT
Doc PR

Fix: When using a form with an Time type with option 'widget' => 'single_text', and 0 is selected in the seconds, we obtain an TransformationFailedException "Unable to reverse value for property path "[time]": Data missing". Check ticket #20304

@@ -132,6 +132,14 @@ public function reverseTransform($value)
throw new TransformationFailedException('Expected a string.');
}

// handle seconds ignored by user's browser when seconds as single_text is 0
if ($this->parseFormat === 'H:i:s|') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also work without the pipe character set.

// handle seconds ignored by user's browser when seconds as single_text is 0
if ($this->parseFormat === 'H:i:s|') {
if (!preg_match('((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9]))', $value) &&
preg_match('((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9]))', $value)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not only the 2nd preg_match call and use ^..$? And should we consider missing hours and/or minutes as well on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the first run, and we should see only seconds, a lack of hours or minutes (without 'with_minutes' => false) itself should make a validation error it indicates an erroneous entry by the user. Here just we managed the browser omission.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here just we managed the browser omission.

So this doesnt count for minutes and hours then? Sorry no real time to test this. But i proposed are more or less generic approach for "adding sensible defaults to the value". Ie.

format="H", value="", new_value="00"
format="H:i", value="", new_value="00:00"
format="H:i", value="12", new_value="12:00"
etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is why the condition $ this-> parseFormat === 'H: i: s |'.

And, ok, these default values would apply then sent the form (within the SUBMIT events) ?, if so, would work.

The ultimate goal of this is to correct the omission of the latter by the browser when the field requires seconds ('with_seconds' => true), and the user enters 0 seconds, in this case the browser sends '02: 05', in instead of '02: 05: 00 'causing a validation error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I fix this with an new DateTimeType implementing:

    # To fix bug in Symfony. On choice 00 seconds in an DateTime with seconds,
    # is checked as invalid, because browser send the request as '01:00' instead of '01:00:00'.
    # we catch the submission data, and, where appropriate, hand add the missing zeros
    $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $e) {
        $data = $e->getData();
        if ($time = $data['time']) {
            if (!preg_match('((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9])(?::[0-5][0-9]))', $time) &&
                preg_match('((?:(?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):(?:[0-5][0-9]))', $time)) {

                $data['time'] = $time . ":00";
                $e->setData($data);
            }
        }

    });`

Copy link
Contributor

@ro0NL ro0NL Oct 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And perhaps at this point even \d{2}:\d{2}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sounds great, it would be something like:

preg_match('/\d{2}:\d{2}$/', $time)

the above was to eliminate things like '99: 78 'but still has to go through validation.

testing in TimeType...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using ^$ is key here ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, error finger, thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, he's looking good, you think?

@@ -167,6 +167,34 @@ public function testSubmitWithSeconds()
$this->assertDateTimeEquals(new \DateTime('2010-06-02 03:04:05 UTC'), $form->getData());
}

public function testSubmitWithSecondsAndBrowserOmissionSeconds()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add this to TimeTypeTest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test may be removed now imo.

Copy link
Contributor Author

@LuisDeimos LuisDeimos Oct 27, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so, is covered by Time Type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok unit test only in TimeType ;)

if ($options['with_seconds']) {
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $e) {
if ($data = $e->getData()) {
if (preg_match('/^\d{2}:\d{2}$/', $data)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a single if()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    if ($options['with_seconds']) {
        $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $e) {
            $data = $e->getData();
            if ($data && preg_match('/^\d{2}:\d{2}$/', $data)) {
                $e->setData($data.':00');
            }
        });
    }`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented suggestions, has not simplified the condition 'if ($ options [' with_seconds '])' to avoid adding an not necessary listener

@@ -49,6 +51,18 @@ public function buildForm(FormBuilderInterface $builder, array $options)

if ('single_text' === $options['widget']) {
$builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format));

// handle seconds ignored by user's browser when with_seconds enabled and seconds is 00
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add a link to some issue(s) here, ie the chromium one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can leave out and seconds is 00 (actually seconds are omitted which you already mentioned).

@LuisDeimos LuisDeimos changed the title [WIP][Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds [Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds Oct 29, 2016
@xabbuh
Copy link
Member

xabbuh commented Nov 12, 2016

👍

Status: Reviewed

@fabpot
Copy link
Member

fabpot commented Nov 12, 2016

Thank you @LuisDeimos.

fabpot added a commit that referenced this pull request Nov 12, 2016
… single_text and zero seconds (LuisDeimos)

This PR was squashed before being merged into the 2.7 branch (closes #20307).

Discussion
----------

[Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds

| Q | A |
| --- | --- |
| Branch? | 2.7 |
| Bug fix? | yes |
| New feature? | no |
| BC breaks? | no |
| Deprecations? | no |
| Tests pass? | yes |
| Fixed tickets | 20304 |
| License | MIT |
| Doc PR |  |

Fix: When using a form with an Time type with option 'widget' => 'single_text', and 0 is selected in the seconds, we obtain an TransformationFailedException "Unable to reverse value for property path "[time]": Data missing". Check ticket #20304

Commits
-------

bcb03e0 [Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds
@fabpot fabpot closed this Nov 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants