LessThanOrEqual Date without time - symfony

I try to validate a Date (not DateTime)
in my validator, i have :
myDate:
- Date: ~
- LessThanOrEqual:
value: today
message: "myDate must be less or equal than today."
Before submitting my form, i send this date to my API (i use symfony as an API with FOSRestBundle):
myDate:"2017-06-09T00:00:00.000Z"
But when i look Symfony\Component\Validator\Constraints\LessThanOrEqualValidator in this method :
protected function compareValues($value1, $value2)
{
return $value1 <= $value2;
}
i have these values:
$value1
DateTime::__set_state(array(
'date' => '2017-06-09 02:00:00.000000',
'timezone_type' => 3,
'timezone' => 'Europe/Paris',
))
$value2
DateTime::__set_state(array(
'date' => '2017-06-09 00:00:00.000000',
'timezone_type' => 3,
'timezone' => 'Europe/Paris',
))
And my validation fails.
Can you help me to solve this problem. I don't need time, i just want to validate the Date. How can i remove the 2 hours ?
Thanks
EDIT :
In my php.ini, i have :
date.timezone ="Europe/Paris"
I solved the problem by sending the right time

First of all LessThanOrEqual do just what its names stands for. It compares if left operand is less or equal to the right operand. No matter if it's a \DateTime or int or something else.
Since you validating \DeteTime i'd suggest you to use Callback Constraint or Expression Constraint so you can define how to validate those. My personal choice for this usecase would be the validation via POST_SUBMIT event in you FormType. See - How to add validators on the fly in Symfony2?

Related

Does Symfony DateTime validator support Y-m-dTH:i:s?

I need to validate dates in Symfony and the expected format is Y-m-dTH:i:s, for example 2019-08-02T23:09:01
This is how the DateTime object is being instantiated:
//...some code
'start_date' => new DateTime([
'format' => 'Y-m-dTH:i:s'
]),
//...some code
and even though start_date is correct (for example 2019-08-01T20:04:00), the validator still renders this invalid. If I try with 2019-08-01 20:04:00 and a format of 'Y-m-d H:i:s', then it works. Is it possible to use that T in the format?
Whats the origin of the date that you want to validate ? It's from form(user input?) ?
If yes
then you should use DateTime Assert on entity connected to form
https://symfony.com/doc/current/reference/constraints/DateTime.html
also
you can use datetime field (https://symfony.com/doc/current/reference/forms/types/datetime.html) on form to validate on data input
If no
If you have value from (for example) database, and you are not sure if is it vaild
you can use Datetime Assert ( link above) with validating "raw values" , here is example :
https://symfony.com/doc/current/validation/raw_values.html

CakePHP date parsing in patchEntity [duplicate]

I try to save data from a cakephp 3 form. All data are well saved but datetime not. I've got 2 datetime fields. Those fields are filled by jquery-ui widget.
The problem seems to happened when pacthing entity.
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
Debug of $this->request->data :
'user_id' => '1',
'description' => 'test',
'starttime' => '2015/11/15 10:00',
'endtime' => '2015/11/15 12:10'
Debug of my object $intervention after pacthEntity :
object(App\Model\Entity\Intervention)
'id' => (int) 3,
'user_id' => (int) 1,
'description' => 'test',
'starttime' => null,
'endtime' => null
...
starttime and endtime become null and I don't understand why.
Is somebody had this pb before ?
I tried (for debuging and understanding) to force fields value afer patching
and datetime fields in mysql are ok.
$intervention->starttime = date('Y-m-d H:i:s', strtotime($this->request->data['starttime']));
$intervention->endtime = date('Y-m-d H:i:s', strtotime($this->request->data['endtime']));
Thanks for help
Date/time values are being casted/parsed in a locale aware fashion
Update: this is the default behavior with the CakePHP application template versions prior to 3.2.5. As of 3.2.5 locale parsing is not enabled by default anymore, which will make the date/time marshalling logic expect a default format of Y-m-d H:i:s instead.
In the marshalling process, values are being "casted" according to the respective column types. For DATETIME columns, this is done by the \Cake\Database\Type\DateTimeType type class.
To be exact, this is done in \Cake\Database\Type\DateTimeType::marshall().
With the default app template configuration, DateTimeType is configured to use locale aware parsing, and since no default locale format is being set, \Cake\I18n\Time::parseDateTime() will parse the values according to its default "to string format" (Time::$_toStringFormat), which defaults to the locale aware [IntlDateFormatter::SHORT, IntlDateFormatter::SHORT].
So, if for example your locale is set to en_US, then the value would be parsed with an expected format of M/d/yy, h:mm a, which your value wouldn't fit, and hence you'd finally end up with null being set for the entity property.
Make the parser use the proper format
tl;dr
In case the format for the jQuery widget is not being used everywhere in your app, you could for example either temporarily set the proper locale format, or disable locale parsing, like
// for time- or date-only comlumn types you'd use 'time' or 'date' instead of 'datetime'
$dateTimeType = Type::build('datetime')->setLocaleFormat('yyyy/MM/dd HH:mm');
// ...
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
// ...
$dateTimeType->setLocaleFormat(null);
or
$dateTimeType = Type::build('datetime')->useLocaleParser(false);
// ...
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
// ...
$dateTimeType->useLocaleParser(true);
It should be noted that this will affect all date/time input, not just your starttime and endtime fields!
Should the format used by the jQuery widget on the other hand be the format that you wish to use all the way through your app, then changing the default format could do it too, like
use Cake\I18n\Time;
use Cake\I18n\FrozenTime;
// To affect date-only columns you'd configure `Date` and `FrozenDate`.
// For time-only columns, see the linked SO question below.
Time::setToStringFormat('yyyy/MM/dd HH:mm');
FrozenTime::setToStringFormat('yyyy/MM/dd HH:mm');
in your bootstrap.php. Note that there's also Time/FrozenTime::setJsonEncodeFormat() and Time/FrozenTime::$niceFormat which you may want/need to modify too.
See also
Cookbook > Internationalization & Localization > Parsing Localized Datetime Data
Cookbook > Time > Setting the Default Locale and Format String
CakePHP 3 time column gets date added
Convert the input before marshalling it
Another option would be to for example convert the data to Time instances before the marshalling process. This would avoid possible problems with the previous mentioned solution that would affect all input.
In your InterventionsTable class (could also be put in a behavior or an external listener):
use Cake\Event\Event;
use Cake\I18n\Time;
...
public function beforeMarshal(Event $event, \ArrayObject $data, \ArrayObject $options)
{
foreach (['starttime', 'endtime'] as $key) {
if (isset($data[$key]) && is_string($data[$key])) {
$data[$key] = Time::parseDateTime($data[$key], 'yyyy/MM/dd HH:mm');
}
}
}
See also
Cookbook > Database Access & ORM > Saving Data > Modifying Request Data Before Building Entities

Why are date/time values interpreted incorrectly when patching/saving?

I try to save data from a cakephp 3 form. All data are well saved but datetime not. I've got 2 datetime fields. Those fields are filled by jquery-ui widget.
The problem seems to happened when pacthing entity.
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
Debug of $this->request->data :
'user_id' => '1',
'description' => 'test',
'starttime' => '2015/11/15 10:00',
'endtime' => '2015/11/15 12:10'
Debug of my object $intervention after pacthEntity :
object(App\Model\Entity\Intervention)
'id' => (int) 3,
'user_id' => (int) 1,
'description' => 'test',
'starttime' => null,
'endtime' => null
...
starttime and endtime become null and I don't understand why.
Is somebody had this pb before ?
I tried (for debuging and understanding) to force fields value afer patching
and datetime fields in mysql are ok.
$intervention->starttime = date('Y-m-d H:i:s', strtotime($this->request->data['starttime']));
$intervention->endtime = date('Y-m-d H:i:s', strtotime($this->request->data['endtime']));
Thanks for help
Date/time values are being casted/parsed in a locale aware fashion
Update: this is the default behavior with the CakePHP application template versions prior to 3.2.5. As of 3.2.5 locale parsing is not enabled by default anymore, which will make the date/time marshalling logic expect a default format of Y-m-d H:i:s instead.
In the marshalling process, values are being "casted" according to the respective column types. For DATETIME columns, this is done by the \Cake\Database\Type\DateTimeType type class.
To be exact, this is done in \Cake\Database\Type\DateTimeType::marshall().
With the default app template configuration, DateTimeType is configured to use locale aware parsing, and since no default locale format is being set, \Cake\I18n\Time::parseDateTime() will parse the values according to its default "to string format" (Time::$_toStringFormat), which defaults to the locale aware [IntlDateFormatter::SHORT, IntlDateFormatter::SHORT].
So, if for example your locale is set to en_US, then the value would be parsed with an expected format of M/d/yy, h:mm a, which your value wouldn't fit, and hence you'd finally end up with null being set for the entity property.
Make the parser use the proper format
tl;dr
In case the format for the jQuery widget is not being used everywhere in your app, you could for example either temporarily set the proper locale format, or disable locale parsing, like
// for time- or date-only comlumn types you'd use 'time' or 'date' instead of 'datetime'
$dateTimeType = Type::build('datetime')->setLocaleFormat('yyyy/MM/dd HH:mm');
// ...
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
// ...
$dateTimeType->setLocaleFormat(null);
or
$dateTimeType = Type::build('datetime')->useLocaleParser(false);
// ...
$intervention = $this->Interventions->patchEntity($intervention, $this->request->data);
// ...
$dateTimeType->useLocaleParser(true);
It should be noted that this will affect all date/time input, not just your starttime and endtime fields!
Should the format used by the jQuery widget on the other hand be the format that you wish to use all the way through your app, then changing the default format could do it too, like
use Cake\I18n\Time;
use Cake\I18n\FrozenTime;
// To affect date-only columns you'd configure `Date` and `FrozenDate`.
// For time-only columns, see the linked SO question below.
Time::setToStringFormat('yyyy/MM/dd HH:mm');
FrozenTime::setToStringFormat('yyyy/MM/dd HH:mm');
in your bootstrap.php. Note that there's also Time/FrozenTime::setJsonEncodeFormat() and Time/FrozenTime::$niceFormat which you may want/need to modify too.
See also
Cookbook > Internationalization & Localization > Parsing Localized Datetime Data
Cookbook > Time > Setting the Default Locale and Format String
CakePHP 3 time column gets date added
Convert the input before marshalling it
Another option would be to for example convert the data to Time instances before the marshalling process. This would avoid possible problems with the previous mentioned solution that would affect all input.
In your InterventionsTable class (could also be put in a behavior or an external listener):
use Cake\Event\Event;
use Cake\I18n\Time;
...
public function beforeMarshal(Event $event, \ArrayObject $data, \ArrayObject $options)
{
foreach (['starttime', 'endtime'] as $key) {
if (isset($data[$key]) && is_string($data[$key])) {
$data[$key] = Time::parseDateTime($data[$key], 'yyyy/MM/dd HH:mm');
}
}
}
See also
Cookbook > Database Access & ORM > Saving Data > Modifying Request Data Before Building Entities

Allow multiple date formats in symfony2 form builder

A client requested this. He wants to allow multiple date formats for a birthday field. The documentation didn't give me any clues how to realize it and neither did google.
Anyone who experienced such a request before and has a lead how to achieve this?
Currently it looks like this:
$builder->add('xxx', 'birthday', array('widget' => 'single_text', 'invalid_message' => 'some message (dd-MM-yyyy)', 'format' => 'dd-MM-yyyy'))
If you want to handle different date formats in your form, you ought to look at DataTransformer
It helps you to transform data from one format to another, for example:
2013-03-26 ==transform==> 2013/03/26
2013.03.26 ==transform==> 2013/03/26
26.03.2013 ==transform==> 2013/03/26
Data transformer should NOT be used in this case.
The main point of data transformer is to convert a data back and forth between view <=> norm <=> model.
It's not your case, you don't want a bidirectional transformation.
What you want is to filter the data, and for that, you can use a form event:
$builder->add(
$builder
->create('xxx', 'birthday', [...])
->addEventListener(
FormEvents::PRE_SUBMIT,
function(FormEvent $event) {
$value = $event->getData();
// Do the filtering you want (for example replacement of special chars with a dash)
// $value = preg_replace('[^\d]', '-', $value)
$event->setData($value);
}
)
);
And you are done, the data is filtered on the PRE_SUBMIT event, before validation.
I wrote this example from memory and didn't tested it, maybe you'll should adapt it (and add your field option instead of [...].

"This value is not valid" when using "query_builder" on "entity" buildForm on symfony2.1

Here is my problem.
I use the buildForm method on symfony 2.1 in order to build my form.
With the following code everything works just fine :
$builder->add('combat','entity',array(
class' => 'KarateCompetitionBundle:CompetitionCombat',
'empty_value' => 'Sélectionner un combat'));
But I want to filter and display only some Combat. That's why I have to use the query_builder option. When i do that i get the This value is not valid error message.
Here is the code :
$builder->add('combat','entity',array(
'class' => 'KarateCompetitionBundle:CompetitionCombat',
'empty_value' => 'Sélectionner un combat',
'query_builder' => function(CombatRepository $cr) {
return $cr->getAllWithoutBilanQueryBuilder();}));
I reduce at the minimum the code (i.e. no filtering on the getAllWithoutBilanQueryBuildermethod) in order to be able to find the problem.
public function getAllWithoutBilanQueryBuilder(){
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
return $queryBuilder->select('c')->from('KarateEntrainementBundle:CompetitionCombat', 'c');
}
I've compared both html code generate on each case and they are the same.
I put a var_dump($object) on the controller after binding the form with the request $form->bind($request) and it appears that when i use the query_builder option the combatis null while it is not null if i don't use it.
I can't manage to understand why ?
I found few post on the web with the same issue but none with an answer.
Is it possible that there is a symfony issue here or am I doing something wrong ?
I had the exact same problem and - in my case - traced it back to Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader.
When the form is validated, the entities are loaded by primary key in ORMQueryBuilderLoader::getEntitiesByIds() by adding an IN() clause to the query builder. In my case, this IN() clause was ineffective and all selectable entities were returned.
This, in turn, caused Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer::reverseTransform() to throw a TransformationFailedException, because the number of loaded entities and submitted choices were not the same.
I suppose there's other possible causes for this specific error. Here's what you could try:
Look at the generated query, run it manually and make sure it returns only the selected values
In Symfony\Component\Form\Form, try outputting the caught TransformationFailedException and see where it leads you.
If none of the above seem plausible, add some debug output to Symfony\Component\Form\Extension\Validator\Constraints\FormValidator and see whether you can narrow it down somewhat.
As an addition to #mike-b answer: for me failing QueryBuilder statement was ->having('...') query part:
...
'query_builder' => function(EntityRepository $er) use ($pn) {
return $er->createQueryBuilder('p')
->select('p')
->join('p.product', 'pr')
->where('p.name = ' . $pn->getId())
->andWhere("LENGTH(p.value_en) > 1")
->andWhere("p.value_en != ''")
/* when I remove this - validation passe flawlessly */
->having('COUNT(pr.id) > 1')
->groupBy('p.value_en)
->orderBy('p.value_en', 'ASC');
...
tested with Symfony version 2.3.6
I finally managed to make this worked :-)
So here was the fix.
On the getAllWithoutBilanQueryBuilder function, I replace
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
by
$queryBuilder = $this->createQueryBuilder('c');
I don't know what is exactly the difference and why this is now working.
But this is working.
Thanks you all for your help.

Resources