2016-11-24 17 views
5

Mam wiele klas, które chcę serializować z serializatorem Symfony. Na przykładNie wyświetlaj elementu zerowego z serializatorem Symfony

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

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

które serializacji z następującym serialize() rozmowy:

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') 
    } 
} 

Wyjście wyprodukowany daje mi:

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

Wyjście z oczekiwaniami powinny być:

<apple>1</apple> 

Spojrzałem na Symfony 2.8 doc i udało mi się znaleźć szybkie rozwiązanie za pomocą $normalizer->setIgnoredAttributes("pear").

Więc ulepszona serialize funkcja statycznego wygląda to

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') 
    } 
} 

Jednak to rozwiązanie nie spełnia mnie, ponieważ mam bardziej skomplikowanych przypadków, w których może być różny Foo własnością tej samej klasy. na przykład

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

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

Tutaj nie można użyć metody setIgnoredAttributes od $foo1 i $foo2 nie mają te same elementy null. Ponadto nie nazywam metody serialize z klasy potomnej (tj. Foo) tutaj, aby setIgnoredAttributes było puste.

Bez konieczności pisania skomplikowanego kodu introspekcji, jak mogę ukryć domyślnie element zerowy za pomocą serializera Symfony 2.8? Widziałem na przykład, że jest domyślnie włączone z JMSSerializer.

+0

Obawiam się, że nie jest to łatwy sposób (bez konieczności pisania złożonego kodu introspekcji_), dodając 'elseif (null === $ val) {return false; } 'tutaj https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php#L489 rozwiązuje twój problem, ale aby to zrobić, potrzebujesz przepisać dużo kodu, ponieważ prawie wszystkie metody są prywatne w 'XmlEncoder' :( – yceruto

+0

Nigdy go nie używam, ale może przy pomocy serializatora JMS może pomóc ten http://jmsyst.com/bundles/JMSSerializerBundle mam nadzieję, że pomoże – Thomas

+0

@Yonel, naprawdę, chciałbym uniknąć pisania w kodzie symfony Nie jestem sam! Czy nie jest możliwe, aby zastąpić XmlEncoder w sposób nie intruzujący do tego? – coincoin

Odpowiedz

8

Rozwiązaniem byłoby rozszerzyć z ObjectNormalizer klasy zastąpić metodę normalize() i usunąć wszystkie wartości null tam:

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

// ... 

Jeśli mamy szereg Person like the one of the official documentation:

// ... 

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

wynik zostanie nie być null węzłów:

<?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

To działa jak urok i jest to bardzo proste rozwiązanie.Szkoda, że ​​nie mogę głosować dwa razy! Dziękuję :) – coincoin

+2

@coincoin +1 :) –