JMS десериализует коллекцию массивов в объекте


Я пытаюсь использовать сериализатор JMS в своем приложении (не Symfony) и хотел бы десериализовать объект JSON в сущность Doctrine.
Простые свойства должным образом десериализуются, но я не могу заставить коллекции ArrayCollections работать.

Это отрывок из моего продукта JSON:

{
  "id": 2,
  "name": "Shirt blue",
  "attributeValues": [
    {
      "id": 4,
      "title": "S",
      "attributeId": 2
    },
    {
      "id": 7,
      "title": "Eterna",
      "attributeId": 3
    }
  ]
}

Это моя сущность продукта:

<?php

namespace Vendor\App\Common\Entities;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="product")
 * @JMS\ExclusionPolicy("all")
 */
class Product extends AbstractEntity {

    /**
     * @var int $id
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @JMS\Groups({"search"})
     * @JMS\Expose
     * @JMS\Type("integer")
     */
    protected $id;

    /**
     * @var string $name
     * @ORM\Column(name="name", type="string", nullable=false)
     * @JMS\Expose
     * @JMS\Groups({"search"})
     * @JMS\Type("string")
     */
    protected $name;

    /**
     * @var ArrayCollection $attributeValues
     * @ORM\ManyToMany(targetEntity="Vendor\App\Common\Entities\Attribute\Value")
     * @ORM\JoinTable(name="products_values",
    *      joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")},
    *      inverseJoinColumns={@ORM\JoinColumn(name="value_id", referencedColumnName="id")}
     *      )
     * @JMS\Expose
     * @JMS\MaxDepth(2)
     * @JMS\Groups({"search"})
     * @JMS\Type("ArrayCollection<Vendor\App\Common\Entities\Attribute\Value>")
     */
    protected $attributeValues;

    public function __construct() {
        $this->attributeValues = new ArrayCollection();
    }

    /**
     * @return ArrayCollection
     */
    public function getAttributeValues() {
        return $this->attributeValues;
    }

    /**
     * @param ArrayCollection $attributeValues
     */
    public function setAttributeValues($attributeValues) {
        $this->attributeValues = $attributeValues;
    }

    /**
     * @param Value $attributeValue
     */
    public function addAttributeValue($attributeValue) {
        $this->attributeValues->add($attributeValue);
    }

    /**
     * @param Value $attributeValue
     */
    public function removeAttributeValue($attributeValue) {
        $this->attributeValues->removeElement($attributeValue);
    }

}

Это моя сущность значения, которая должна быть десериализована в коллекции ArrayCollection:

<?php

namespace Vendor\App\Common\Entities\Attribute;

use Vendor\App\Common\Entities\AbstractEntity,
    Doctrine\ORM\Mapping as ORM,
    JMS\Serializer\Annotation as JMS;

/**
 * @ORM\Entity
 * @ORM\Table(name="attribute_value")
 * @JMS\ExclusionPolicy("all")
 */
class Value extends AbstractEntity {

    /**
     * @var int $id
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @JMS\Expose
     * @JMS\Groups({"search"})
     * @JMS\Type("integer")
     */
    protected $id;

    /**
     * @var string $title
     * @ORM\Column(name="title", type="string", nullable=false)
     * @JMS\Expose
     * @JMS\Groups({"search"})
     * @JMS\Type("string")
     */
    protected $title;

    /**
     * @var int $attributeId
     * @ORM\Column(name="attribute_id", type="integer", nullable=false)
     * @JMS\Expose
     * @JMS\Groups({"search"})
     * @JMS\Type("integer")
     */
    protected $attributeId;

    /**
     * OWNING SIDE
     * @var \Vendor\App\Common\Entities\Attribute $attribute
     * @ORM\ManyToOne(targetEntity="Vendor\App\Common\Entities\Attribute", inversedBy="values")
     * @ORM\JoinColumn(name="attribute_id", referencedColumnName="id")
     * @JMS\Expose
     * @JMS\Groups({"search"})
     * @JMS\Type("Vendor\App\Common\Entities\Attribute")
     */
    protected $attribute;

    //Getters and setters ...

}

Просто пытаюсь просто десериализовать сущность:

$serializer = SerializerBuilder::create()->build();
$entity = $serializer->deserialize($sourceJson, Product::class, 'json');

Но коллекция массивов AttributeValue остается пустой. Чего мне не хватает?

Author: Hans Höchtl, 2015-05-21

1 answers

Я нашел решение. У JMS есть стратегия именования по умолчанию, которая преобразует camelcase в нотацию подчеркивания. По умолчанию стратегия именования либо ищет аннотацию @SerializedName, и если она не задана, она преобразует camelCase в подчеркивание.

Таким образом, свойство просто было проигнорировано, потому что оно не соответствовало ожидаемому имени. Конечно, было бы лучше, если бы была ошибка или уведомление, которое дает подсказку здесь о том, где искать проблему (что-то вроде неизвестно собственность была бы хороша).

$serializer = SerializerBuilder::create()->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy())->build();

Было решением.

 2
Author: Hans Höchtl, 2015-06-02 12:56:33