2016-11-24 3 views
5

So habe ich viele Klassen, die ich mit Symfony Serializer serialisieren möchte. Zum BeispielNULL Element nicht mit Symfony Serializer anzeigen

class Foo 
{ 
    public $apple = 1; 
    public $pear = null; 

    public function serialize() { 
    Utils::serialize($this); 
    } 
} 

, die ich mit dem folgenden serialize() Aufruf serialisiert:

class Utils { 
    public static function serialize($object) { 
     $encoder = new XmlEncoder(); 
     $normalizer = new ObjectNormalizer(); 
     $serializer = new Serializer(array($normalizer), array($encoder)); 
     $str = $serializer->serialize($object, 'xml') 
    } 
} 

Die erzeugte Ausgabe gibt mir:

<apple>1</apple><pear/> 

Die Ausgabe sollte erwartet:

<apple>1</apple> 

Ich habe mir die Symfony 2.8 doc angesehen und mit $normalizer->setIgnoredAttributes("pear") eine schnelle Lösung gefunden.

So ist die verbesserte serialize statische Funktion sieht wie folgt aus

class Utils { 
    public static function ignoreNullAttributes($object) { 
    $ignored_attributes = array(); 
    foreach($object as $member => $value) { 
     if (is_null($object->$member)) { 
     array_push($ignored_attributes, $member); 
     } 
    } 
    return $ignored_attributes; 
    } 

    public static function serialize($object) { 
     $encoder = new XmlEncoder(); 
     $normalizer = new ObjectNormalizer(); 
     $normalizer->setIgnoredAttributes(Utils::ignoreNullAttributes($object)); 
     $serializer = new Serializer(array($normalizer), array($encoder)); 
     $str = $serializer->serialize($object, 'xml') 
    } 
} 

Diese Lösung ist jedoch befriedigt mich nicht, da ich komplizierteren Fällen, wo verschiedene Foo kann durch eine derselben Klasse gehören. z.B.

class Bar 
{ 
    public $foo1; // (apple=null; pear=2) 
    public $foo2; // (apple=2; pear=null) 

    public function serialize() { 
    Utils::serialize($this); 
    } 
} 

Hier kann ich nicht verwenden, um die setIgnoredAttributes Methode, da $foo1 und $foo2 nicht die gleichen Null-Elemente hat. Außerdem rufe ich die serialize-Methode von der Kindklasse (d. H. Foo) hier nicht auf, so dass die setIgnoredAttributes leer ist.

Ohne komplexe Introspection-Code zu schreiben, wie kann ich standardmäßig Null-Element mit Symfony 2.8 Serializer ausblenden? Ich habe zum Beispiel gesehen, dass es standardmäßig mit JMSSerializer aktiviert ist.

+0

Ich befürchte, dass es keinen einfachen Weg gibt, es zu tun (_ohne den komplexen Introspektionscode schreiben zu müssen_), indem ich 'elseif (null === $ val) {return false; } 'hier https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php#L489 löst Ihr Problem, aber dafür müssen Sie eine Menge Code neu schreiben, weil fast alle Methoden sind privat in 'XmlEncoder' :( – yceruto

+0

Niemals verwendet, aber vielleicht mit JMS Serializer könnte dazu beitragen, dass http://jmyst.com/bundles/JMSSerializerBundle hoffe, es hilft – Thomas

+0

@Yonel danke, ich möchte vermeiden zu schreiben Ich bin nicht allein! Ist es nicht möglich, den XmlEncoder in einer nicht intruisive Weise für das zu überschreiben? – coincoin

Antwort

8

würde eine Lösung aus ObjectNormalizer Klasse, überschreiben die normalize() Methode und entfernen Sie alle null Werte dort zu erweitern sein:

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; 
use Symfony\Component\Serializer\Serializer; 
use Symfony\Component\Serializer\Encoder\XmlEncoder; 

class CustomObjectNormalizer extends ObjectNormalizer 
{ 
    public function normalize($object, $format = null, array $context = []) 
    { 
     $data = parent::normalize($object, $format, $context); 

     return array_filter($data, function ($value) { 
      return null !== $value; 
     }); 
    } 
} 

$encoders = array(new XmlEncoder()); 
$normalizers = array(new CustomObjectNormalizer()); 
$serializer = new Serializer($normalizers, $encoders); 

// ... 

Wenn wir eine Reihe von Person like the one of the official documentation haben:

// ... 

$person1 = new Person(); 
$person1->setName('foo'); 
$person1->setAge(null); 
$person1->setSportsman(false); 

$person2 = new Person(); 
$person2->setName('bar'); 
$person2->setAge(33); 
$person2->setSportsman(null); 

$persons = array($person1, $person2); 
$xmlContent = $serializer->serialize($persons, 'xml'); 

echo $xmlContent; 

Das Ergebnis wird seien Sie jene nicht null Knoten:

<?xml version="1.0"?> 
<response> 
    <item key="0"> 
     <name>foo</name> 
     <sportsman>0</sportsman> 
    </item> 
    <item key="1"> 
     <name>bar</name> 
     <age>33</age> 
    </item> 
</response> 
+1

Dies funktioniert wie ein Charme und das ist eine sehr einfache Lösung.Schade, ich kann nicht zweimal wählen! Danke :) – coincoin

+2

@coincoin +1 :) –

Verwandte Themen