Symfony: ленивая загрузка отношения из API

Я ищу лучший способ LAZY загрузить отношение к объекту из API.

Сценарий У меня есть приложение Symfony 4, которое поддерживается базой данных с использованием Doctrine, и в этой базе данных у меня есть несколько таблиц, включая Customer.

У меня также есть доступ к API с различными данными, относящимися к этому клиенту, такими как счета, счета, продукты, счета.

Мне нужно отобразить список данных о клиенте с разбивкой на страницы, который содержит значения от Заказчика и из результатов запросов API.

Мое решение до сих пор состояло в том, чтобы создать свойство сущности Customer для каждой связанной сущности в API, а затем у меня есть класс EntityLoadListener, который прослушивает событие жизненного цикла события PostLoad. Когда это срабатывает, он проверяет, является ли объект клиентом, и если да, то загружает результаты из API и обновляет отношение:

// customer is the customer entity
// the api call here returns a collection full of invoice entities
$invoices = $this->api->getInvoicesForAccount($customer->getAccountCode());

// get the name of the property to set on the entity
$propertyName = 'apiInvoices';

// set the property on the entity
$relationProp = $em->getClassMetadata($class)
  ->reflClass->getProperty($propertyName);
$relationProp->setAccessible(true);
$relationProp->setValue($entity, $invoices);

Это работает, но при загрузке большого количества клиентов это происходит медленно. И если мне не нужно отображать данные счета, я бы не стал загружать данные из API. Есть ли лучший способ реализовать это, когда я буду запрашивать API только при вызове геттера клиента для getApiInvoices (т.е. отложенной загрузки)?


person Geoff Maddock    schedule 09.05.2019    source источник
comment
Этот вопрос довольно расплывчатый, поэтому я буду голосовать близко. Без более подробной информации найти хорошее решение — это просто догадки. Даже с дополнительной информацией это было бы очень самоуверенно. Одним из улучшений может быть наличие конечной точки API, где вы можете получать несколько счетов одновременно, поэтому вместо выдачи n запросов вы выполняете только 1, а затем объединяете оба набора результатов. Если вы хотите ограничить количество запросов, вы можете отложить загрузку данных счета, объединив их с геттером, вместо того, чтобы делать это сразу после загрузки. Возможно, загрузка этих счетов в фоновом режиме и сохранение их где-нибудь также является вариантом.   -  person dbrumann    schedule 09.05.2019


Ответы (1)


Я считаю, что APIP по умолчанию использует нетерпеливую загрузку. Вы можете использовать ленивую загрузку, настроив ее в файле yaml

# api/config/packages/api_platform.yaml
api_platform:
    eager_loading:
        force_eager: false

или на уровне ресурсов и операций:

<?php
// api/src/Entity/User.php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ApiResource(attributes={"force_eager"=false})
 * @ORM\Entity
 */
class User
{
    /**
     * @var Address
     *
     * @ORM\ManyToOne(targetEntity="Address", fetch="EAGER")
     */
    public $address;

    /**
     * @var Group[]
     *
     * @ORM\ManyToMany(targetEntity="Group", inversedBy="users")
     * @ORM\JoinTable(name="users_groups")
     */
    public $groups;

    // ...
}

https://api-platform.com/docs/core/performance/#force-eager

person Bernard Pagoaga    schedule 09.05.2019