Apigility + Doctrine - ManyToMany 从任何一方获取 Eager 都不起作用 - 存在数据

Apigility + Doctrine - ManyToMany fetch Eager not working from either side - data present

我有一个包含国家和货币对象的设置。一个国家可能有 0 个或多个货币对象,反之亦然,0 个或多个国家对象可能使用货币。问题是数据没有返回到前端(api 请求)。

Country实体

/**
 * @var Collection|ArrayCollection|Currency[]
 * @ORM\ManyToMany(targetEntity="Currency", inversedBy="countries", fetch="EAGER")
 * @ORM\JoinTable(
 *     name="country_country_currencies",
 *     joinColumns={@ORM\JoinColumn(name="country_id", referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="currency_id", referencedColumnName="id")}
 * )
 */
protected $currencies;

Currency实体

/**
 * @var Collection|ArrayCollection|Currency[]
 * @ORM\ManyToMany(targetEntity="Country", mappedBy="currencies", fetch="EAGER")
 */
protected $countries;

双方都有一个__construct()函数将初始值设置为new ArrayCollection()。两者都有自己的 get*()add*()remove*() 函数。

在单个对象(例如 /currencies/45)上调试 DoctrineResource::fetch() 函数时,$entity 对象 在执行 return $entityfethc() 的最后一行),所以我知道 数据在那里。

然而,当它最终 returns 到 "front-end" 时,我丢失了 ManyToMany 关系的数据:

正如您在上面看到的:countries 是空的。

从另一端(来自Country)请求时,currencies为空。


附加信息

其他类似问题在评论或答案中有建议,我会立即放在这里,因为我已经检查过了。

Doctrine 缓存 - 我 运行 以下命令:

我已确保禁用 Zend Framework 缓存(另外,通过 composer development-enable 启用开发模式)。

生成的实体代理也已多次删除,以确保它们不是问题所在。我也尝试过不使用 fetch="EAGER"(实际上是原始的),但结果相同。

为实体使用错误的水化器:两者都配置为使用 Doctrine EntityManager(两者相同):

'zf-hal' => [
    'metadata_map' => [
        \Country::class => [
            'route_identifier_name' => 'id',
            'entity_identifier_name' => 'id',
            'route_name' => 'country.rest.doctrine.country',
            'hydrator' => 'Country\V1\Rest\Country\CountryHydrator',
            'max_depth' => 3,
        ],
        \Country\V1\Rest\Country\CountryCollection::class => [
            'entity_identifier_name' => 'id',
            'route_name' => 'country.rest.doctrine.country',
            'is_collection' => true,
        ],
        // other entity
    ],
],
// some more config
'zf-apigility' => [
    'doctrine-connected' => [
        \Country\V1\Rest\Country\CountryResource::class => [
            'object_manager' => 'doctrine.entitymanager.orm_default',
            'hydrator' => 'Country\V1\Rest\Country\CountryHydrator',
        ],
        // other entity
    ],
],
'doctrine-hydrator' => [
    'Country\V1\Rest\Country\CountryHydrator' => [
        'entity_class' => \Salesupply\Core\Country\Entity\Country::class,
        'object_manager' => 'doctrine.entitymanager.orm_default',
        'by_value' => true,
        'strategies' => [],
        'use_generated_hydrator' => true,
    ],
    // other entity
],

另一位建议 content negotiation 类型可能设置为 json 而不是 HalJson:两者(所有内容)都设置为 HalJson:

'zf-content-negotiation' => [
    'controllers' => [
        'Country\V1\Rest\Country\Controller' => 'HalJson',
        'Country\V1\Rest\Currency\Controller' => 'HalJson',
    ],
],

ApiSkeletons 供应商包设计有此功能。几个月前我打开了 an issue on Github

为确保您收到回款:

  • 创建策略 class 并扩展 Doctrine 的 AllowRemoveByValue 策略。
  • extract 函数覆盖为 return 集合,填充或空

就是这样。

完整 class:

namespace Application\Strategy;

use DoctrineModule\Stdlib\Hydrator\Strategy\AllowRemoveByValue;
use ZF\Hal\Collection;

class UniDirectionalToManyStrategy extends AllowRemoveByValue
{
    public function extract($value)
    {
        return new Collection($value ?: []);
    }
}

在需要的地方应用此策略。例如。你的 AdvertApplications 一样多,所以应该像这样修改配置:

'doctrine-hydrator' => [
    'Application\V1\Entity\ApplicationHydrator' => [
        // other config
        'strategies' => [
            'relatedToManyPropertyName' => \Application\Strategy\UniDirectionalToManyStrategy::class,
        ],
    ],
],

现在应该 return 编辑集合。


快速说明:这只会作为策略 对 *ToMany 方有效。