Согласно документация, API-платформа по умолчанию будет с готовностью загружать связанные ресурсы.
Но в конфигурации по умолчанию все мои запросы к ресурсам с отношениями (в основном с типичными отношениями Many2One) заполняют эти свойства объектным IRI вместо сериализованного объекта.
Например, для этого объекта:
/**
* @ORM\Entity(repositoryClass = "App\Repository\BoostLeadContactActionRepository")
* @ORM\Table(name = "BoostLeadContactActions")
*/
class BoostLeadContactAction {
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type = "integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity = "App\Entity\BoostLead", inversedBy = "contacts")
* @ORM\JoinColumn(nullable=false)
*/
private $boostLead;
/**
* @ORM\ManyToOne(targetEntity = "App\Entity\ContactChannel", fetch = "EAGER")
* @ORM\JoinColumn(nullable=false, referencedColumnName = "Id")
*/
private $channel;
// getters/setters/extra properties removed for brevity
}
Тогда у нас есть соответствующие ContactChannel:
/**
* ContactChannel
*
* @ORM\Table(name = "ContactChannels")
* @ORM\Entity
*/
class ContactChannel {
/**
* @var int
*
* @ORM\Column(name = "Id", type = "smallint", nullable=false, options = {"unsigned"=true})
* @ORM\Id
* @ORM\GeneratedValue(strategy = "IDENTITY")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name = "Name", type = "string", length=64, nullable=false)
*/
private $name = '';
}
Я поставил fetch = "EAGER" на отношения, даже если в теории это не нужно. Моя конфигурация по умолчанию, но на всякий случай я написал это в своем api_platform.yaml:
eager_loading:
# To enable or disable eager loading.
enabled: true
# Fetch only partial data according to serialization groups.
# If enabled, Doctrine ORM entities will not work as expected if any of the other fields are used.
fetch_partial: false
# Max number of joined relations before EagerLoading throws a RuntimeException.
max_joins: 30
# Force join on every relation.
# If disabled, it will only join relations having the EAGER fetch mode.
force_eager: true
Результат debug:config api_platform подтверждает, что применяется правильная конфигурация:
Current configuration for extension with alias "api_platform"
=============================================================
api_platform:
title: FooBar API
description: 'FooBar API, only for authenticated use'
version: 0.8.0
name_converter: null
path_segment_name_generator: api_platform.path_segment_name_generator.underscore
eager_loading:
enabled: true
fetch_partial: false
max_joins: 30
force_eager: true
И все же результаты будут примерно такими:
{
"@context": "/api/contexts/BoostLeadContactAction",
"@id": "/api/boost_lead_contact_actions/9",
"@type": "BoostLeadContactAction",
"id": 9,
"boostLead": "/api/boost_leads/30",
"channel": "/api/contact_channels/1",
"direction": "outgoing",
"successful": true,
"type": "/api/lead_contact_attempt_reasons/1",
"notes": "2",
"createdAt": "2019-05-16T10:27:33+00:00",
"updatedAt": "2019-05-16T10:27:33+00:00"
}
"boostLead", "channel" и "type" должны быть реальными сущностями, загружаемыми с нетерпением, но вместо этого возвращаются только IRI. Я подтвердил, что выполненный SQL-запрос не содержит никаких join.
Как ни странно, это проблема, противоположная у этого другого пользователя есть. Хотел бы я иметь их проблемы.
Что может помешать жадной загрузке этих отношений? Отношения работают иначе (я могу выполнять другие запросы с помощью Doctrine или создавать пользовательские группы сериализации, и соответствующие свойства будут включены).
Вы пытались добавить @ApiProperty(attributes = {"fetchEager": true}) строку выше private $channel; ?
Вы пытались добавить * @ApiResource(attributes = {"force_eager"=true}) строки над каждым объявлением класса?
Пробовал оба. Не работает. Но, как вы видите, force_eager включен на глобальном уровне, его повторное включение на уровне ресурса или свойства не должно иметь значения. Тем не менее пробовал, безрезультатно.
Как говорится в вопросе, вам не нужно ничего делать по умолчанию для быстрой загрузки. Это всего лишь чистое предположение, но попробуйте закомментировать enable,fetch_partial и max_joins в разделе await_loading, чтобы ваша конфигурация соответствовала документам. В частности, fetch_partial может вызывать проблемы. Также может помочь начать новый проект, возможно, с двумя объединенными объектами и ничем другим.
Я попробую, @Cerad. Но тем не менее это настройки по умолчанию. Я просто включил их в свою конфигурацию из-за растущего отчаяния.
Вы очищаете и прогреваете свой кеш каждый раз?






По умолчанию разыменуемые IRI используются для отображения связанных ассоциаций.
Глядя на выполненные операторы, вы должны увидеть не явный запрос JOIN, а скорее дополнительные операторы SELECT для связанных ассоциаций.
Если вам требуется JSON-представление связанного объекта.
Вам нужно указать Serialization@Groups для желаемых свойств в соответствующей ассоциации.
Это приведет к тому, что оператор SELECT добавит оператор JOIN для извлечения связанных данных для сериализации.
Подробнее см. https://api-platform.com/docs/core/serialization/#embedding-relations
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ApiResource(normalizationContext = { "groups": {"boost"} })
* @ORM\Entity()
* @ORM\Table(name = "BoostLeadContactActions")
*/
class BoostLeadContactAction {
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type = "integer")
* @Groups({"boost"})
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity = "App\Entity\BoostLead", inversedBy = "contacts")
* @ORM\JoinColumn(nullable=false)
* @Groups({"boost"})
*/
private $boostLead;
/**
* @ORM\ManyToOne(targetEntity = "App\Entity\ContactChannel", fetch = "EAGER")
* @ORM\JoinColumn(nullable=false, referencedColumnName = "Id")
* @Groups({"boost"})
*/
private $channel;
// getters/setters/extra properties removed for brevity
}
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ApiResource()
* @ORM\Table(name = "ContactChannels")
* @ORM\Entity
*/
class ContactChannel {
/**
* @var int
* @ORM\Column(name = "Id", type = "smallint", nullable=false, options = {"unsigned"=true})
* @ORM\Id
* @ORM\GeneratedValue(strategy = "IDENTITY")
* @Groups({"boost"})
*/
private $id;
/**
* @var string
* @ORM\Column(name = "Name", type = "string", length=64, nullable=false)
* @Groups({"boost"})
*/
private $name = '';
}
Что должно привести к получению нормализованных значений
{
"@context": "/api/contexts/BoostLeadContactAction",
"@id": "/api/boost_lead_contact_actions/9",
"@type": "BoostLeadContactAction",
"id": 9,
"boostLead": "/api/boost_leads/30",
"channel": {
"@id": "/api/contact_channels/1",
"@type": "ContactChannel",
"id": "1",
"name": "Test"
},
"direction": "outgoing",
"successful": true,
"type": "/api/lead_contact_attempt_reasons/1",
"notes": "2",
"createdAt": "2019-05-16T10:27:33+00:00",
"updatedAt": "2019-05-16T10:27:33+00:00"
}
Мммм. Я неправильно прочитал документацию. Я интерпретировал «EAGER по умолчанию» как то, что отношения были встроены автоматически. Эта другая часть документации делает очевидным, что это не так. Я предполагаю, что невозможно пометить весь объект как принадлежащий группе сериализации?
Не к знанию, поскольку контекст может быть изменен, и это может привести к другим последствиям.
Не каждый день я встречаю разработчика, который просит решить проблему другого. (Я ищу решение и возвращаюсь)