0

Ich arbeite an der Deserialisierung einer XML-Datei. Es ist möglich, dass einige Elemente keine Daten enthalten, so versuche ich, das folgende XML-Element (OfferDate) in ein null Objekt anstelle ein \DateTime Objekt deserialisieren:JMSSerializer: Deserialisieren leeres DateTime-XML-Element in PHP "Null" -Objekt

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

... aber ich bin immer der folgende Fehler:

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 

Wenn die XML-Datei zum Beispiel 2016-09-25T18:58:55 in OfferDate enthalten würde es funktionieren würde, da einige Daten gibt es ... da es aber auch möglich, dass es Elemente ohne Daten sein, ich muß involviere diesen Fall auch.

Mein YML Mapping der XML in ein Objekt deserialisieren:

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

Meine Product Klasse:

Und schließlich meine Deserialisierung:

$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 wie oben gesehen in Der Fehler entspricht der Zeile $productCollection = $serializer->deserialize($xml, ProductCollection::class, 'xml');.

To clarify why I deserialize into a ProductCollection : The product.xml contains a <Products> element in which <Product> elements are. The ProductCollection then contains a method called getProducts() which returns an array containing the deserialized Product objects.

Gibt es eine Möglichkeit, das OfferDate Element deserialisiert, ohne Daten in ein null Objekt? Und wenn ja, wie?

Antwort

0

Ich habe eine Handler für die Deserialisierung von DateTime-Objekten erstellt.

Hier ist meine Lösung. Mein DateTimeHandler Überschreiben des Standard DateHandler s Klasse und Methode deserializeDateTimeFromXml vom JMSSerializer bereitgestellt:

<?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); 
    } 
} 

Da ist in meiner Deserialisierung: (man beachte die configureHandlers Methode)

$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'); 

Dies funktioniert nun völlig in Ordnung!