8000 [Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds by LuisDeimos · Pull Request #20307 · symfony/symfony · GitHub
[go: up one dir, main page]

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
Closed
Next Next commit
[Form] fixed Date\TimeType marked as invalid on request with single_t…
…ext and zero seconds (LuisDeimos)
  • Loading branch information
LuisDeimos committed Oct 27, 2016
commit bf6979b2b26c623edbc0d20c52fd6b1e3b72ef57
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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?

$value = $value . ":00";
}
}

$outputTz = new \DateTimeZone($this->outputTimezone);
$dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;)

{
$form = $this->factory->create('datetime', null, array(
'model_timezone' => 'UTC',
'view_timezone' => 'UTC',
'date_widget' => 'choice',
'years' => array(2010),
'time_widget' => 'single_text',
'input' => 'datetime',
'with_seconds' => true,
));

$form->setData(new \DateTime());

$input = array(
'date' => array(
'day' => '2',
'month' => '6',
'year' => '2010',
),
'time' => '03:04'
);

$form->submit($input);

$this->assertDateTimeEquals(new \DateTime('2010-06-02 03:04:00 UTC'), $form->getData());
}

public function testSubmitDifferentTimezones()
{
$form = $this->factory->create('datetime', null, array(
Expand Down
0