Handling Relations

API Platform Admin handles to-one and to-many relations automatically.

API Platform Admin は、一対一および対多の関係を自動的に処理します。

Thanks to the Schema.org support, you can easily display the name of a related resource instead of its IRI.

Schema.org サポートのおかげで、IRI の代わりに関連リソースの名前を簡単に表示できます。

Embedded Relations

If a relation is an array of embeddeds or an embedded resource, the admin will keep them by default.

リレーションが埋め込みの配列または埋め込みリソースである場合、管理者はデフォルトでそれらを保持します。

The embedded data will be displayed as text field and editable as text input: the admin cannot determine the fields present in it. To display the fields you want, see this section.

埋め込まれたデータはテキスト フィールドとして表示され、テキスト入力として編集可能です。管理者はそこに存在するフィールドを特定できません。必要なフィールドを表示するには、このセクションを参照してください。

You can also ask the admin to automatically replace the embedded resources' data by their IRI, by setting the useEmbedded parameter of the Hydra data provider to false. Embedded data is inserted to a local cache: it will not be necessary to make more requests if you reference some fields of the embedded resource later on.

また、Hydra データ プロバイダーの useEmbedded パラメータを false に設定することにより、埋め込みリソースのデータを IRI で自動的に置き換えるように管理者に依頼することもできます。埋め込みデータはローカル キャッシュに挿入されます。後で埋め込みリソースのいくつかのフィールドを参照します。

// admin/src/App.js

import { HydraAdmin, fetchHydra, hydraDataProvider } from "@api-platform/admin";
import { parseHydraDocumentation } from "@api-platform/api-doc-parser";

const entrypoint = process.env.REACT_APP_API_ENTRYPOINT;

const dataProvider = hydraDataProvider({
    entrypoint,
    httpClient: fetchHydra,
    apiDocumentationParser: parseHydraDocumentation,
    mercure: true,
    useEmbedded: false,
});

export default () => (
  <HydraAdmin
      dataProvider={dataProvider}
      entrypoint={entrypoint}
  />
);

Display a Field of an Embedded Relation

If you have an embedded relation and need to display a nested field, the code you need to write depends of the value of useEmbedded of the Hydra data provider.

埋め込みリレーションがあり、ネストされたフィールドを表示する必要がある場合、Hydra データ プロバイダーの useEmbedded の値に応じて、記述する必要があるコードが異なります。

If true (default behavior), you need to use the dot notation to display a field:

true (デフォルトの動作) の場合、ドット表記を使用してフィールドを表示する必要があります。

import {
  HydraAdmin,
  FieldGuesser,
  ListGuesser,
  ResourceGuesser
} from "@api-platform/admin";
import { TextField } from "react-admin";

const BooksList = (props) => (
  <ListGuesser {...props}>
    <FieldGuesser source="title" />
    {/* Use react-admin components directly when you want complex fields. */}
    <TextField label="Author first name" source="author.firstName" />
  </ListGuesser>
);

export default () => (
  <HydraAdmin entrypoint={process.env.REACT_APP_API_ENTRYPOINT}>
    <ResourceGuesser
      name="books"
      list={BooksList}
    />
  </HydraAdmin>
);

If useEmbedded is explicitly set to false, make sure you write the code as if the relation needs to be fetched as a reference.

useEmbedded が明示的に false に設定されている場合は、リレーションを参照としてフェッチする必要があるかのようにコードを記述してください。

In this case, you cannot use the dot separator to do so.

この場合、ドット セパレータを使用してこれを行うことはできません。

Note that you cannot edit the embedded data directly with this behavior.

この動作では埋め込みデータを直接編集できないことに注意してください。

For instance, if your API returns:

たとえば、API が次を返す場合:

{
  "@context": "/contexts/Book",
  "@id": "/books",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/books/07b90597-542e-480b-a6bf-5db223c761aa",
      "@type": "https://schema.org/Book",
      "title": "War and Peace",
      "author": {
        "@id": "/authors/d7a133c1-689f-4083-8cfc-afa6d867f37d",
        "@type": "https://schema.org/Author",
        "firstName": "Leo",
        "lastName": "Tolstoi"
      }
    }
  ],
  "hydra:totalItems": 1
}

If you want to display the author first name in the list, you need to write the following code:

リストに著者名を表示する場合は、次のコードを記述する必要があります。

import {
  HydraAdmin,
  FieldGuesser,
  ListGuesser,
  ResourceGuesser
} from "@api-platform/admin";
import { ReferenceField, TextField } from "react-admin";

const BooksList = (props) => (
  <ListGuesser {...props}>
    <FieldGuesser source="title" />
    {/* Use react-admin components directly when you want complex fields. */}
    <ReferenceField label="Author first name" source="author" reference="authors">
      <TextField source="firstName" />
    </ReferenceField>
  </ListGuesser>
);

export default () => (
  <HydraAdmin entrypoint={process.env.REACT_APP_API_ENTRYPOINT}>
    <ResourceGuesser
      name="books"
      list={BooksList}
    />
    <ResourceGuesser name="authors" />
  </HydraAdmin>
);

Using an Autocomplete Input for Relations

Let's go one step further thanks to the customization capabilities of API Platform Admin by adding autocompletion support to form inputs for relations.

リレーションのフォーム入力にオートコンプリートのサポートを追加することで、API Platform Admin のカスタマイズ機能のおかげでさらに一歩進んでみましょう。

Let's consider an API exposing Review and Book resources linked by a many-to-one relation (through the book property).

(book プロパティを介して) 多対 1 の関係でリンクされた Review リソースと Book リソースを公開する API を考えてみましょう。

This API uses the following PHP code:

この API は、次の PHP コードを使用します。

<?php
// api/src/Entity/Review.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource]
class Review
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    public ?int $id = null;

    #[ORM\ManyToOne]
    public Book $book;
}
<?php
// api/src/Entity/Book.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource]
class Book
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    public ?int $id = null;

    #[ORM\Column] 
    #[ApiFilter(SearchFilter::class, strategy: 'ipartial')]
    public string $title;

    #[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book')] 
    public $reviews;

    public function __construct()
    {
        $this->reviews = new ArrayCollection();
    }
}

Notice the "partial search" filter on the title property of the Book resource class.

Book リソース クラスの title プロパティの "部分検索" フィルターに注目してください。

Now, let's configure API Platform Admin to enable autocompletion for the relation selector:

それでは、関係セレクターのオートコンプリートを有効にするように API Platform Admin を構成しましょう。

import {
  HydraAdmin,
  ResourceGuesser,
  CreateGuesser,
  EditGuesser,
  InputGuesser
} from "@api-platform/admin";
import { ReferenceInput, AutocompleteInput } from "react-admin";

const ReviewsCreate = props => (
  <CreateGuesser {...props}>
    <InputGuesser source="author" />
    <ReferenceInput
      source="book"
      reference="books"
    >
      <AutocompleteInput
        filterToQuery={searchText => ({ title: searchText })}
        optionText="title"
        label="Books"
      />
    </ReferenceInput>

    <InputGuesser source="rating" />
    <InputGuesser source="body" />
    <InputGuesser source="publicationDate" />
  </CreateGuesser>
);

const ReviewsEdit = props => (
  <EditGuesser {...props}>
    <InputGuesser source="author" />

    <ReferenceInput
      source="book"
      reference="books"
    >
      <AutocompleteInput
        filterToQuery={searchText => ({ title: searchText })}
        optionText="title"
        label="Books"
      />
    </ReferenceInput>

    <InputGuesser source="rating" />
    <InputGuesser source="body" />
    <InputGuesser source="publicationDate" />
  </EditGuesser>
);

export default () => (
  <HydraAdmin entrypoint={process.env.REACT_APP_API_ENTRYPOINT}>
    <ResourceGuesser
      name="reviews"
      create={ReviewsCreate}
      edit={ReviewsEdit}
    />
  </HydraAdmin>
);

If the book is embedded into a review and if the useEmbedded parameter is true (default behavior), you need to change the ReferenceInput for the edit component:

書籍がレビューに埋め込まれていて、useEmbedded パラメーターが true (デフォルトの動作) の場合、編集コンポーネントの ReferenceInput を変更する必要があります。

import {
  HydraAdmin,
  ResourceGuesser,
  CreateGuesser,
  EditGuesser,
  InputGuesser
} from "@api-platform/admin";
import { ReferenceInput, AutocompleteInput } from "react-admin";

const ReviewsCreate = props => (
  <CreateGuesser {...props}>
    <InputGuesser source="author" />
    <ReferenceInput
      source="book"
      reference="books"
    >
      <AutocompleteInput
        filterToQuery={searchText => ({ title: searchText })}
        optionText="title"
        label="Books"
      />
    </ReferenceInput>

    <InputGuesser source="rating" />
    <InputGuesser source="body" />
    <InputGuesser source="publicationDate" />
  </CreateGuesser>
);

const ReviewsEdit = props => (
  <EditGuesser {...props}>
    <InputGuesser source="author" />

    <ReferenceInput
      source="book"
      reference="books"
    >
      <AutocompleteInput
        filterToQuery={searchText => ({ title: searchText })}
        format={v => v['@id'] || v}
        optionText="title"
        label="Books"
      />
    </ReferenceInput>

    <InputGuesser source="rating" />
    <InputGuesser source="body" />
    <InputGuesser source="publicationDate" />
  </EditGuesser>
);

export default () => (
  <HydraAdmin entrypoint={process.env.REACT_APP_API_ENTRYPOINT}>
    <ResourceGuesser
      name="reviews"
      create={ReviewsCreate}
      edit={ReviewsEdit}
    />
  </HydraAdmin>
);

The autocomplete field should now work properly!

オートコンプリート フィールドが正しく機能するようになりました。