Closed Padam87 closed 6 years ago
Can you post the full code of your entity please?
It is just a test project, so sure: https://gist.github.com/Padam87/25a331c348f5fe5f3b9ec21d4ffa55fe
I'm using "api-platform/core": "2.1.x-dev"
, because I needed the oauth support.
Hello guys,
I have exactly the same error describe by @Padam87 . You can find the full code of my entity:
<?php
namespace AppBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Post
*
* @ORM\Table(name="post")
* @ORM\Entity(repositoryClass="AppBundle\Repository\PostRepository")
* @ApiResource()
*/
class Post
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=255)
* @Assert\NotBlank()
*/
private $title;
/**
* @var \DateTime
*
* @ORM\Column(name="date", type="datetimetz")
* @Assert\NotBlank()
* @Assert\Date()
*/
private $date;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* @param string $title
*
* @return Post
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set date
*
* @param \DateTime $date
*
* @return Post
*/
public function setDate(\DateTime $date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* @return \DateTime
*/
public function getDate()
{
return $this->date;
}
}
Thanks
To prevent today's date from being used when a null
is posted for a \DateTime type add a datetime_format
to your denormalization context.
<?php
namespace AppBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table
* @ORM\Entity
* @ApiResource(
* itemOperations={
* "put"={"denormalization_context"={"datetime_format"="Y-m-d\TH:i:sP"}
* },
* collectionOperations={
* "post"={"denormalization_context"={"datetime_format"="Y-m-d\TH:i:sP"}
* }
* )
*/
class dummyObject
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(type="datetime")
*/
private $dummyDate;
}
The format Y-m-d\TH:i:sP
is ISO8601 - for some reason c
will not work here - this is a limitation of the underlying \DateTime::createFromFormat
method. I also couldn't find a way to make the \DateTime::ATOM
constants work. ISO8601 is the format that \DateTime
is serialized to, if you are serialising dates or accepting them back in a different format you should match that format here.
This won't give you a nice friendly validation failure message, but it will at least stop nulls from being interpreted as now
. This works by telling the DateTimeNormalizer which format to use instead of letting it accept anything that \DateTime::_construct
will accept as valid, which includes null
and any of the valid Date and Time Formats.
For a more complete fix there is some more thought required. All \DateTime types appear to be automatically denormalized from a string to a \DateTime
type by the DateTimeNormalizer long before the validators get a look at the data. This makes any @Assert\Date()
or @Assert\NotBlank
on a \DateTime
field useless.
maybe better idea is to decorate DateTimeNomalizer
class DateTimeNullNormalizer implements NormalizerInterface, DenormalizerInterface
{
private $dateTimeNormalizer;
public function __construct(DateTimeNormalizer $dateTimeNormalizer)
{
$this->dateTimeNormalizer = $dateTimeNormalizer;
}
public function supportsDenormalization($data, $type, $format = null)
{
return $this->dateTimeNormalizer->supportsDenormalization($data, $type, $format);
}
public function supportsNormalization($data, $format = null)
{
return $this->dateTimeNormalizer->supportsNormalization($data, $format);
}
public function denormalize($data, $class, $format = null, array $context = array())
{
if ($data == null) {
return $data;
}
return $this->dateTimeNormalizer->denormalize($data, $class, $format, $context);
}
public function normalize($object, $format = null, array $context = array())
{
return $this->dateTimeNormalizer->normalize($object, $format, $context);
}
}
AppBundle\Serializer\DateTimeNullNormalizer:
class: AppBundle\Serializer\DateTimeNullNormalizer
decorates: serializer.normalizer.datetime
arguments: ['@AppBundle\Serializer\DateTimeNullNormalizer.inner']
This way we have nice errors from the validator
Bonjour,
Nous avons eu le même problème merci @piotrbrzezina pour ta solution.
Ne pas oublier non plus de modifier le setter:
public function setDate(\DateTime $date)
en
public function setDate(\DateTime $date = null)
Pour que le code aille jusqu'aux validateurs.
Similar issue here (after 3 years),
/**
* @ORM\Column(type="datetime", nullable=false)
* @Groups({"schedule.read","schedule.list"})
* @Assert\NotBlank(message="field.not_blank")
* @Assert\DateTime(message="field.invalid_date")
*/
I submit empty date (empty string or null) even after implementing answer from @piotrbrzezina it throws: Failed to denormalize attribute "date" value for class "App\Entity\Schedule": Expected argument of type "DateTimeInterface", "string" given at property path "date".
For anyone who ends up here here's a shortcut to a groundwork change in the Symfony Serializer component which will be released with 5.4/6.0:
https://github.com/symfony/symfony/pull/42502
Until then an interim fix is making the property nullable, thus e.g. ?\DateTimeImmutable
instead of \DateTimeImmutable
.
This works fine together with nullable=false
(which is the default anyways) of @ORM\Column
but still allows empty/null
values at runtime to let the NotBlank
assertion to do its work.
When posting null: NotBlank is ignored, actual date is used. I presume it is interpreted as
new \DateTime(null)
When posting a non-datetime string:
DateTime::__construct(): Failed to parse time string (test) at position 0 (t): The timezone could not be found in the database