symfony — JMSSerializer: десериализация пустого XML-элемента DateTime в PHP & quot; null & quot; объект

Я работаю над десериализацией файла XML. Возможно, что некоторые элементы не будут содержать никаких данных, поэтому я пытаюсь десериализовать следующий элемент XML (OfferDate) в null объект вместо \DateTime объект:

<Product>
<OfferDate></OfferDate>
</Product>

… но я получаю следующую ошибку:

JMS\Serializer\Exception\RuntimeException: Invalid datetime "", expected format Y-m-d\TH:i:s.

./vendor/jms/serializer/src/JMS/Serializer/Handler/DateHandler.php:117
./vendor/jms/serializer/src/JMS/Serializer/Handler/DateHandler.php:99
./vendor/jms/serializer/src/JMS/Serializer/GraphNavigator.php:180
./vendor/jms/serializer/src/JMS/Serializer/XmlDeserializationVisitor.php:280
./vendor/jms/serializer/src/JMS/Serializer/GraphNavigator.php:236
./vendor/jms/serializer/src/JMS/Serializer/XmlDeserializationVisitor.php:175
./vendor/jms/serializer/src/JMS/Serializer/GraphNavigator.php:130
./vendor/jms/serializer/src/JMS/Serializer/XmlDeserializationVisitor.php:251
./vendor/jms/serializer/src/JMS/Serializer/GraphNavigator.php:236
./vendor/jms/serializer/src/JMS/Serializer/Serializer.php:182
./vendor/jms/serializer/src/JMS/Serializer/Serializer.php:116
./vendor/phpoption/phpoption/src/PhpOption/Some.php:89
./vendor/jms/serializer/src/JMS/Serializer/Serializer.php:119
./tests/AppBundle/Domain/Model/ProductTest.php:35
./tests/AppBundle/Domain/Model/ProductTest.php:44

Если файл XML будет содержать, например, 2016-09-25T18:58:55 в OfferDate это сработало бы, так как есть некоторые данные … Но так как также возможно, что могут быть элементы без каких-либо данных, я должен также включить этот случай.

Мое сопоставление YML для десериализации XML в объект:

AppBundle\Domain\Model\Product:
xml_root_name: Product
properties:
offerDate:
serialized_name: OfferDate
type: DateTime<'Y-m-d\TH:i:s'>

мой Product учебный класс:

<?php
declare(strict_types = 1);

namespace AppBundle\Domain\Model;

/**
* @author ...
*/
class Product
{

/**
* @var \DateTime
*/
private $offerDate;

/**
* @return \DateTime
*/
public function getOfferDate(): \DateTime
{
return $this->offerDate;
}

}

И наконец моя десериализация:

$xml = file_get_contents(__DIR__.'/product.xml');

$serializer = SerializerBuilder::create()
->addMetadataDir(__DIR__.'/../../../../app/config/serializer')
->build();

/** @var ProductCollection $productCollection */
$productCollection  = $serializer->deserialize($xml, ProductCollection::class, 'xml');
$firstProduct = $productCollection->getProducts()[0];

var_dump($firstProduct->getOfferDate());

./tests/AppBundle/Domain/Model/ProductTest.php:35 как видно выше, ошибка равна линии $productCollection = $serializer->deserialize($xml, ProductCollection::class, 'xml');,

Чтобы выяснить, почему я десериализую в ProductCollection:
product.xml содержит <Products> элемент, в котором <Product> элементы есть. ProductCollection затем содержит метод с именем getProducts() который возвращает массив, содержащий десериализованный Product объекты.

Есть ли способ десериализации OfferDate элемент, без каких-либо данных, в null объект? И если да, то как?

0

Решение

Я придумал создать укротитель для процесса десериализации объектов DateTime.

Вот мое решение. мой DateTimeHandler переопределение по умолчанию DateHandlerс класс и метод deserializeDateTimeFromXml предоставляемый JMSSerializer:

<?php
declare(strict_types = 1);

namespace AppBundle\Serializer\Handler;

use JMS\Serializer\Handler\DateHandler;
use JMS\Serializer\XmlDeserializationVisitor;

/**
* @author ...
*/
class DateTimeHandler extends DateHandler
{
/**
* @param XmlDeserializationVisitor $visitor
* @param $data
* @param array $type
*
* @return \DateTime|null
*/
public function deserializeDateTimeFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
{
// Casting the data to a string will return the value of the
// current xml element. So if it's empty there is no data.
if ((string)$data === '') {
return null;
}

return parent::deserializeDateTimeFromXml($visitor, $data, $type);
}
}

Тогда в моей десериализации: (обратите внимание на configureHandlers метод)

$xml = file_get_contents(__DIR__.'/product.xml');

$serializer = SerializerBuilder::create()
->addMetadataDir(__DIR__.'/../../../../app/config/serializer')
->configureHandlers(
function (HandlerRegistry $registry) {
$registry->registerSubscribingHandler(new DateTimeHandler());
}
)
->build();

/** @var ProductCollection $productCollection */
$productCollection = $serializer->deserialize($xml, ProductCollection::class, 'xml');

Теперь это работает отлично!

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]