Операция PUT создает новый встроенный документ вместо его обновления на платформе Api

Я застрял в проблеме, которую не могу решить уже несколько дней. Как сказано в названии, операция PUT платформы Api на основе аннотаций не работает должным образом в отношении частичного обновления встроенного документа с помощью MongoDB ODM.

Действительно, несмотря на все разные конфигурации, которые я пробовал, мне не удалось обновить встроенный документ, уже установленный в родительском документе.

Я попытался изменить аннотации в соответствующих документах, например, изменив группы нормализации и денормализации, попробовав различные стратегии встроенных документов, установив определенные itemOperations для метода PUT и т.д. операции с использованием Doctrine ORM.

Самая "интересная" информация, которую я нашел, взята из этой главы документации по платформе Api: https://api-platform.com/docs/core/serialization/#denormalization

Как написано: «Если ключ @id присутствует во встроенном ресурсе, то объект, соответствующий данному URI, будет извлечен через поставщик данных. Любые изменения во встроенном отношении также будут применены к этому объекту.», Что соответствует этому объекту. документ должен быть получен, но этого не происходит.

У меня есть родительский документ Page со встроенным документом Basic во взаимосвязи embedOne.

/**
 * @ApiFilter(SearchFilter::class, properties={"basic.name": "ipartial", "basic.title": "exact"})
 * 
 * @ApiResource(
 *  normalizationContext={"groups"={"read"}},
 *  denormalizationContext={"groups"={"write"}}
 * )
 *
 * @ODM\Document
 */
class Page
{
    /**
     * @ODM\Id(strategy="increment", type="integer")
     */
    private $id;

    /**
     * Embedded document with data shared by all Pages and Modules such as name, title, etc.
     * 
     * @Assert\Valid
     * @Groups({"read", "write"})
     * @ODM\EmbedOne(targetDocument=Basic::class, strategy="set")
     */
    private $basic;
}

С другой стороны, у меня есть встроенный документ Basic:

/**
 * @ApiResource()
 * 
 * @ODM\EmbeddedDocument
 */
class Basic
{
    /**
     * @ApiProperty(identifier=true)
     * @Groups({"read", "write"})
     * @ODM\Id(strategy="INCREMENT", type="integer")
     */
    public $id;

    /**
     * @Groups({"read", "write"})
     * @ODM\Field(type="string")
     */
    private $title;

    /**
     * @Groups({"read", "write"})
     * @ODM\Field(type="string")
     */
    private $name;

    /**
     * @Groups({"read", "write"})
     * @ODM\Field(type="string")
     */
    private $category;
}

Итак, когда я делаю запрос «POST» на / api / страницах, таких как этот:

{
    "basic": {
        "title": "Master",
        "name": "Peter Jackson",
        "category": "Director"
    }
}

Я получаю 201 ответ:

{
    "@context": "\/api\/contexts\/Page",
    "@id": "\/api\/pages\/11",
    "@type": "Page",
    "basic": {
        "@id": "\/api\/basics\/21",
        "@type": "Basic",
        "id": 21,
        "title": "Master",
        "name": "Peter Jackson",
        "category": "Director"
    }
}

Но я делаю запрос «PUT» на этом ресурсе через api / pages / 11 с такими параметрами:

{
  "basic": {
    "title": "Master",
    "name": "Steven Spielberg",
    "category": "Director"
  }
}

Я получаю ответ 200:

{
    "@context": "\/api\/contexts\/Page",
    "@id": "\/api\/pages\/11",
    "@type": "Page",
    "basic": {
        "@id": "\/api\/basics\/22",
        "@type": "Basic",
        "id": 22,
        "title": "Master",
        "name": "Steven Spielberg",
        "category": "Director"
    }
}

Как видите, для операции PUT создается новый встроенный документ Basic, в котором используются значения, заданные в запросе. Но я не хочу, чтобы это происходило, я хочу систематически обновлять созданный внедренный документ, поскольку он был создан. Большое спасибо, если вы знаете, как с этим справиться. Ваше здоровье!


person Domopus    schedule 04.08.2019    source источник


Ответы (1)


Думаю, это твоя проблема. Вам необходимо установить идентификатор для встроенных отношений, иначе они будут созданы.

{
  "basic": {
    "@id": "\/api\/basics\/21",
    "title": "Master",
    "name": "Steven Spielberg",
    "category": "Director"
  }
}

Из документов:

If an @id key is present in the embedded resource, then the object corresponding to the given URI will be retrieved through the data provider. Any changes in the embedded relation will also be applied to that object.

If no @id key exists, a new object will be created containing data provided in the embedded JSON document.
person Mario 2002    schedule 06.08.2019
comment
Привет ! Спасибо за Ваш ответ. На самом деле я пробовал это решение, и оно не сработало. Причина в том, что \ / api \ / basics \ / 21 нельзя запрашивать отдельно, без встраиваемого родителя. Таким образом, он выдает сообщение об ошибке, в котором говорится, что я не могу получить доступ к этому ресурсу (я точно не помню, какой именно). Наконец, попробовав разные решения, я пришел к выводу, что лучше следовать логике SQL API-платформы и избегать встроенных документов. Определенно не лучшее решение, но, по крайней мере, оно работает, и я могу сохранить его СУХИМ с чертами. - person Domopus; 13.08.2019
comment
Привет @Domopus, вы должны включить операцию получения элемента для базовой сущности, чтобы ссылаться на нее с помощью IRI в другом документе - person Adee; 26.03.2021