api-platform / api-platform/core

Make identifier resolution resource aware in the Doctrine and Eloquent links handlers

オープン
#8,494 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
PHP
スター
2.6k
フォーク
980
平均マージ
2日 4時間
マージ済み PR(30日)
49

説明

**Follow-up to #8491.**

#8491 lets a uri variable's parameter provider transform the value used to query the resource, and lets `ReadLinkParameterProvider` opt into writing the *resolved resource* into the uri variables (constructor flag, or the `write_uri_variable` extra property per link). Working on the resource rather than the identifier is usually easier when writing a custom provider.

That opt-in currently only works for resources whose provider does not query a persistence layer. On a Doctrine-backed link it fails with:

```
Object of class App\Entity\Company could not be converted to string
```

because the links handler compares the identifier column and binds the value with an explicit Doctrine type:

```php
// src/Doctrine/Orm/State/LinksHandlerTrait.php
$queryBuilder->andWhere("$joinAlias.$identifierProperty = :$placeholder");
$queryBuilder->setParameter(
$placeholder,
$this->getIdentifierValue($identifiers, $hasCompositeIdentifiers ? $identifierProperty : null),
$fromClassMetadata->getTypeOfField($identifierProperty)
);
```

## Proposal

Make identifier resolution accept a resolved resource and read the link's identifier off it, keeping the query shape unchanged. Reading the *link's* identifier (e.g. a `name` slug) rather than assuming the Doctrine primary key avoids the identifier-divergence problem.

Both backends funnel through a single method, so this is two small changes rather than three parallel ones:

| Backend | Method | Call sites covered |
| --- | --- | --- |
| Doctrine | `getIdentifierValue()` in `src/Doctrine/Common/State/LinksHandlerTrait.php` | ORM (4), ODM (2), `PersistProcessor` (4) — all share it |
| Eloquent | `buildQuery()` in `src/Laravel/Eloquent/State/LinksHandler.php` | all 5 entry points funnel through it |

`symfony/property-access` is already a dependency.

## Wrinkle

`getIdentifierValue(array &$identifiers, ?string $name = null)` only receives the property name when the link has composite identifiers; otherwise it is `null` and the method does `array_shift($identifiers)`. Reading a property off an object requires knowing which property, and only the caller has it — so `$identifierProperty` needs to be passed unconditionally at the 6 Doctrine call sites. It is a private method on an `@internal` trait, so there is no BC surface.

## Risk

`PersistProcessor` shares `getIdentifierValue()` and uses it to build references on write. It needs verifying that a resolved resource cannot reach it, or an explicit guard.

## Suggested sequence

1. Pass `$identifierProperty` unconditionally at the Doctrine call sites.
2. Make `getIdentifierValue()` resource aware.
3. Audit `PersistProcessor`.
4. Gate: `LinkProviderParameterTest::testLinkSecurityWithSlug` green with `write_uri_variable` enabled on a Doctrine-backed link.
5. Eloquent `buildQuery()`.
6. ODM.

The bulk of the effort is verification across the three backends (the Laravel suite runs under testbench, ODM needs the mongodb environment), not the code itself.

## Beyond this

Once identifier resolution is resource aware, flipping the *default* so `ReadLinkParameterProvider` always writes the resource becomes a separate, explicit BC decision. It is a real break for consumers independent of Doctrine: plain-`ApiResource` providers that read uri variables assume scalars — the `Issue7939BazResource` fixture does `(string) ($uriVariables['barId'] ?? '')` — so it would need an upgrade note. `PreservesUriVariableInterface` stays meaningful either way, since consumers still need resources kept out of the uri variables.

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

Start with getIdentifierValue() and its six Doctrine call sites in src/Doctrine/Common/State/LinksHandlerTrait.php, then audit PersistProcessor and the Eloquent buildQuery() path in src/Laravel/Eloquent/State/LinksHandler.php. Run LinkProviderParameterTest::testLinkSecurityWithSlug and verify the resource-aware identifier behavior across Doctrine ORM, ODM, and Laravel without changing the query shape.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
laravel, php, symfony
領域
api, backend, databases
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
明確に書かれている
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。