2017-12-28 10 views
0

Mit symfony/serializer Version 4. Die Daten, die ich JSON von einer API bin immer wieder, die wie diesesSymfony Serializer: denormalize (Deserialize) umständlich Arraydaten

{ 
    "name": "Steves Book Shop", 
    "book_1": "Lord of the Rings", 
    "book_2": "The Hobbit", 
    "book_[n]": "there can be any number of books" 
} 

ich in folgende Modelle deserialisieren möchten sieht

class BookShop 
{ 
    protected $name; 

    /** @var Book[] */ 
    protected $books; 

    public function getBooks(): array 
    { 
     return $this->books; 
    } 

    public function setBooks(array $books) 
    { 
     $this->books = $books; 
    } 

    public function addBook(Book $book) 
    { 
     $this->books[] = $book; 
    } 
    // ... other code removed to save space 
} 

class Book 
{ 
    protected $title; 
    // ... other code removed to save space 
} 

Bei der Verwendung von "cleaner" JSON unten funktioniert alles wie erwartet und ich bekomme BookShop mit und Array von Book s zurückgegeben.

{ 
    "name": "Steves Book Shop", 
    "books": [ 
     { "title": "Lord of the Rings" }, 
     { "title": "The Hobbit" } 
    ] 
} 

Was für eine saubere Art und Weise die ursprüngliche JSON denormalize die stattdessen das lästige book_1 hat wäre, book_2 usw.

Ich habe mit einem benutzerdefinierten Denormalisierer (DenormalizerInterface) und meine Lösung sucht viel mehr experimentieren schwieriger als Sie erwarten würden.

+0

'BookShop' und' Book' Klassen sind nicht unbedingt Doctrine Entitäten und möglicherweise nicht einmal in der Datenbank gespeichert werden. Sie sind auch vereinfachte Beispielklassen, um mein Problem zu demonstrieren, die realen Klassen und JSON, mit denen ich arbeite, sind komplexer. – Sam

Antwort

0

Dies ist die Lösung, die ich mit endete, ich bin nicht völlig überzeugt, dass dies der beste Weg ist, aber seine Arbeit für der Moment. Irgendwelche Feedback willkommen:

class StrangeDataDenormalizer extends Symfony\Component\Serializer\Normalizer\ObjectNormalizer 
{ 
    protected function isStrangeDataInterface(string $type): bool 
    { 
     try { 
      $reflection = new \ReflectionClass($type); 

      return $reflection->implementsInterface(StrangeDataInterface::class); 
     } catch (\ReflectionException $e) { // $type is not always a valid class name, might have extract junk like `[]` 
      return false; 
     } 
    } 

    public function denormalize($data, $class, $format = null, array $context = array()) 
    { 
     $normalizedData = $this->prepareForDenormalization($data); 

     $normalizedData = $class::prepareStrangeData($normalizedData); 

     return parent::denormalize($normalizedData, $class, $format, $context); 
    } 

    public function supportsDenormalization($data, $type, $format = null) 
    { 
     return $this->isStrangeDataInterface($type); 
    } 
} 

interface StrangeDataInterface 
{ 
    public static function prepareStrangeData($data): array; 
} 

class BookShop implements StrangeDataInterface 
{ 
    public static function prepareStrangeData($data): array 
    { 
     $preparedData = []; 

     foreach ($data as $key => $value) { 
      if (preg_match('~^book_[0-9]+$~', $key)) { 
       $preparedData['books'][] = ['title' => $value]; 
      } else { 
       $preparedData[$key] = $value; 
      } 
     } 

     return $preparedData; 
    } 

    // .... other code hidden 
} 

function makeSerializer(): Symfony\Component\Serializer\Serializer 
{ 
    $extractor = new ReflectionExtractor(); 

    $nameConverter = new CamelCaseToSnakeCaseNameConverter(); 

    $arrayDenormalizer = new ArrayDenormalizer(); // seems to help respect the 'adder' typehints in the model. eg `addEmployee(Employee $employee)` 

    $strangeDataDenormalizer = new StrangeDataDenormalizer(
     null, 
     $nameConverter, 
     null, 
     $extractor 
    ); 

    $objectNormalizer = new ObjectNormalizer(
     null, 
     $nameConverter, 
     null, 
     $extractor 
    ); 

    $encoder = new JsonEncoder(); 

    $serializer = new Symfony\Component\Serializer\Serializer(
     [ 
      $strangeDataDenormalizer, 
      $objectNormalizer, 
      $arrayDenormalizer, 
     ], 
     [$encoder] 
    ); 

    return $serializer; 
} 
0

Sie sollten für diese Bücher verwenden Arraycollection - vorausgesetzt, das ist nur ein anderes Unternehmen in Ihrer Anwendung

+0

Bietet dies eine Antwort auf die Frage? – svgrafov

Verwandte Themen