カスタム汎用フィールドタイプの作成
汎用フィールドタイプは、住所などの構造化データを保持するフィールドタイプを抽象的に実装したものです。これをベースにして、カスタムフィールドタイプを作成することができます。汎用フィールドタイプには、基本的なメソッドが実装されており、作成しなければならないクラスの数を減らし、タグ付けのプロセスを簡略化することができます。
ヒント
非常に特殊な実装や、データの保存方法を完全に制御する必要がある場合は、汎用フィールドタイプを使うべきではありません。
Value オブジェクトの定義
まず、 src/FieldType/HelloWorld
ディレクトリに Value.php
を作成します。フィールドタイプの Value クラスには、フィールドタイプの基本的なロジックのみが含まれており、それ以外は Type クラスで処理されます。フィールドタイプの Value の詳細については、 Value の取り扱いを参照してください。
HelloWorld
の Value クラスには、以下のものが含まれているはずです。
-
name
を取得するパブリックプロパティ -
toString()
メソッドの実装
<?php
namespace App\FieldType\HelloWorld;
use Ibexa\Contracts\Core\FieldType\Value as ValueInterface;
use Symfony\Component\Validator\Constraints as Assert;
final class Value implements ValueInterface
{
/**
* @Assert\NotBlank()
*/
private $name;
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function __toString()
{
return "Hello {$this->name}!";
}
}
フィールドと設定の定義
次に、汎用フィールドタイプを拡張したフィールドタイプの定義を src/FieldType/HelloWorld/Type.php
クラスで実装します。このクラスは、フィールドタイプの設定と Ibexa\Contracts\Core\FieldType\FieldType
抽象クラスの実装を提供します。
<?php
namespace App\FieldType\HelloWorld;
use App\Form\Type\HelloWorldType;
use Ibexa\Contracts\Core\FieldType\Generic\Type as GenericType;
final class Type extends GenericType implements FieldValueFormMapperInterface
{
public function getFieldTypeIdentifier(): string
{
return 'hello_world';
}
}
チップ
フィールドタイプの Type クラスの詳細については、「Type クラス」を参照してください。
次に、フィールドタイプをサービスとして登録し、 ibexa.field_type
でタグ付けします。
services:
App\FieldType\HelloWorld\Type:
public: true
tags:
- { name: ibexa.field_type, alias: hello_world }
Value オブジェクトのためのフォームの定義
src/Form/Type/HelloWorldType.php
のフォームを作成します。これにより、新しいフィールドタイプを編集することができます。
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\FieldType\HelloWorld\Value;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class HelloWorldType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('name', TextType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Value::class
]);
}
}
これで、FormMapper を使って Symfony のフォームにフィールドの定義をマッピングすることができるようになりました。 FieldValueFormMapperInterface
が要求する mapFieldValueForm()
メソッドと、必要な use
文を src/FieldType/HelloWorld/Type.php
に追加してください。
<?php
namespace App\FieldType\HelloWorld;
use App\Form\Type\HelloWorldType;
use Ibexa\Contracts\Core\FieldType\Generic\Type as GenericType;
use Ibexa\Contracts\ContentForms\Data\Content\FieldData;
use Ibexa\Contracts\ContentForms\FieldType\FieldValueFormMapperInterface;
use Symfony\Component\Form\FormInterface;
final class Type extends GenericType implements FieldValueFormMapperInterface
{
public function getFieldTypeIdentifier(): string
{
return 'hello_world';
}
public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data): void
{
$definition = $data->fieldDefinition;
$fieldForm->add('value', HelloWorldType::class, [
'required' => $definition->isRequired,
'label' => $definition->getName()
]);
}
}
チップ
フォームマッパーの詳細については、「フィールドタイプのフォームとテンプレート」を参照してください。
次に、 ibexa.admin_ui.field_type.form.mapper.value
タグをサービス定義に追加してください。
services:
App\FieldType\HelloWorld\Type:
public: true
tags:
- { name: ibexa.field_type, alias: hello_world }
- { name: ibexa.admin_ui.field_type.form.mapper.value, fieldType: hello_world }
フィールドのレンダリング
テンプレートの作成
新しいフィールドタイプ用のテンプレートを作成します。これは、 HelloWorld
フィールドのデフォルトレンダリングを定義します。templates
ディレクトリに field_type.html.twig
ファイルを作成します。
{% block hello_world_field %}
Hello <b>{{ field.value.getName() }}!</b>
{% endblock %}
テンプレートマッピング
config/packages/ibexa.yaml
にテンプレートのマッピングを指定します。
ibexa:
system:
default:
field_templates:
- { template: 'field_type.html.twig', priority: 0 }
最終結果
最後に、管理画面で新しいコンテンツタイプを追加することができるはずです。[コンテンツタイプ]タブに移動し、[コンテンツ]カテゴリで新しいコンテンツタイプを作成します。
次に、 Hello World フィールドを定義します。
保存すると、サイドバーメニューの「コンテンツ」に Hello World コンテンツタイプが表示されるようになります。
汎用フィールドタイプの詳細については、次の「Point 2D フィールドタイプ型の作成」をご覧ください。
Point 2D フィールドタイプ型の作成
このチュートリアルでは、Ibexa DXP のカスタムフィールドタイプの作成と開発について説明します。Generic Field Type は、非常に強力な拡張ポイントです。すぐに使えるフィールドタイプのテンプレートを使って、複雑なソリューションを簡単に構築することができます。
フィールドタイプは以下を担当します:
- データの保存(ネイティブストレージエンジンメカニズムまたは特定の手段)
- 入力データの検証(バリデーション)
- データを検索可能にする(該当する場合)
- フィールドの表示
詳細については、フィールドタイプのドキュメントを参照してください。フィールドタイプの各コンポーネントがシステムのさまざまなレイヤーとどのように相互作用するか、およびそれらを実装する方法について説明します。
対象者
このチュートリアルは、Ibexa DXP に慣れて親しんでおり、PHP と Symfony での操作を容易にこなせる開発者を対象としています。
チュートリアルの内容
このチュートリアルでは、カスタムフィールドタイプのテンプレートとして Generic フィールドタイプを使用する方法を説明します。このチュートリアルでは:
- 2つの座標を入力として、カスタム Point 2D フィールドタイプを作成する(例:(4,5)
- 新しいフィールドタイプをサービスとして登録し、そのテンプレートを定義する
- Point 2D に基本的なバリデーションを追加する
- フィールドタイプにデータ移行を追加することで、簡単に出力を変更できるようにする
ステップ
このチュートリアルでは、次の手順を実行します。
- Point 2D Value クラスの実装
- Point 2D フィールドタイプの定義
- フィールドタイプを編集するためのフォームの作成
- テンプレートの導入
- 新しい Point 2D フィールドの追加
- Point 2D の設定の実装
- 基本的なバリデーションの追加
- フィールドタイプのバージョン間のデータ移行
ステップ1 - Point 2D Value クラスの実装
プロジェクトのインストール
チュートリアルを始めるには、Ibexa DXP をクリーンインストールする必要があります。お使いのシステムのガイドに従って、Ibexa DXP をインストールし、サーバーを設定し、Web サーバーを起動します。dev 環境を使用してインストールすることを忘れないでください。
クリーンインストールしたプロジェクトを開き、 src/FieldType/Point2D
に新しい Point 2D Field Type 用のベースディレクトリを作成します。
Value クラス
フィールドタイプの Value クラスは、設計上非常にシンプルです。これは、コンテンツアイテムの中でフィールドタイプのインスタンスを表現するために使用されます。各フィールドは、そのタイプの Value クラスのインスタンスを使用してデータを表示します。フィールドタイプの Value の詳細については、Value handling を参照してください。
ヒント
慣習に従って、フィールドタイプ Value を表すクラスは Value と名付けられ、タイプ定義と同じネームスペースに配置されるべきです。
Point 2D Value クラスには、以下のものが含まれます。
- 実際のデータを格納するために使用されるプライベートプロパティ
- Value インタフェースで必要とされる
__toString()
メソッドの実装
デフォルトでは、FieldType\Value
のコンストラクターが使用されます。
Point 2D には、2つの要素(2Dの座標)が格納される予定です。
-
x
値 -
y
値
この時点では、それらがどこに格納されているかは重要ではありません。フィールドタイプが API として何を公開しているかに注目しましょう。
src/FieldType/Point2D/Value.php
は以下のプロパティを持っているはずです。
/** @var float|null */
private $x;
/** @var float|null */
private $y;
Value クラスは、 Ibexa\Contracts\Core\FieldType\Value
インターフェイスも実装する必要があります。 FieldType\Value
インターフェイスに合わせるために、 __toString()
メソッドを実装する必要があります。また、 x
と y
のプロパティのゲッターとセッターを追加する必要があります。このクラスは、2D座標を表現します。
最終的にはこのようなコードになります。
<?php
declare(strict_types=1);
namespace App\FieldType\Point2D;
use Ibexa\Contracts\Core\FieldType\Value as ValueInterface;
final class Value implements ValueInterface
{
/** @var float|null */
private $x;
/** @var float|null */
private $y;
public function __construct(?float $x = null, ?float $y = null)
{
$this->x = $x;
$this->y = $y;
}
public function getX(): ?float
{
return $this->x;
}
public function setX(?float $x): void
{
$this->x = $x;
}
public function getY(): ?float
{
return $this->y;
}
public function setY(?float $y): void
{
$this->y = $y;
}
public function __toString()
{
return "({$this->x}, {$this->y})";
}
}
ステップ2 - Point 2D フィールドタイプの定義
Type クラス
Type には、データの検証、様々なフォーマットからの変換、バリデータの記述など、フィールドタイプのロジックが含まれます。この例では、Point 2D フィールドタイプは Ibexa\Contracts\Core\FieldType\Generic\Type
クラスを継承しています。フィールドタイプの Type クラスの詳細については、Type クラスを参照してください。
フィールドタイプ識別子
まず、 src/FieldType/Point2D/Type.php
を作成します。そこに getFieldTypeIdentifier()
メソッドを追加してください。この新しいメソッドは、あなたのフィールドタイプ(ここでは point2d
)を一意に識別する文字列を返します。
<?php
declare(strict_types=1);
namespace App\FieldType\Point2D;
use Ibexa\Contracts\Core\FieldType\Generic\Type as GenericType;
final class Type extends GenericType
{
public function getFieldTypeIdentifier(): string
{
return 'point2d';
}
}
新しいサービスの定義の追加
次に、 config/services.yaml
に ibexa.field_type
タグを追加してください。
services:
App\FieldType\Point2D\Type:
tags:
- { name: ibexa.field_type, alias: point2d }
ステップ3 - フィールドタイプを編集するためのフォームの作成
フォームの作成
新しいフィールドタイプを編集するには、Point2DType.php
フォームを src/Form/Type
ディレクトリに作成します。次に、 AbstractType
を継承し、 buildForm()
メソッドを実装した Point2DType
クラスを追加します。このメソッドは、x
と y
の座標のフィールドを追加します。
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\FieldType\Point2D\Value;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class Point2DType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('x', NumberType::class);
$builder->add('y', NumberType::class);
}
}
フォームマッパーのインターフェイスの追加
FormMapper は add()
メソッドを使って Symfony フォームにフィールドの定義を追加します。FieldValueFormMapperInterface
は管理インターフェイスでフィールドタイプの編集フォームを提供します。FormMapper の詳細については、フィールドタイプのフォームとテンプレートを参照してください。
まず、 src/FieldType/Point2D/Type.php
のフィールドタイプ定義に FieldValueFormMapperInterface インターフェース(Ibexa\Contracts\ContentForms\FieldType\FieldValueFormMapperInterface
)を実装します。
次に、 mapFieldValueForm()
メソッドを実装し、FormInterface::add
メソッドを以下の引数(ハイライト行)で呼び出します。
- フィールドの値がマッピングされるプロパティの名前:
value
- フィールドのタイプ。フィールドのタイプ:
Point2DType::class
- カスタムオプション:
required
とlabel
最終版の Type クラスは、以下のステートメントと関数を持つ必要があります。
<?php
declare(strict_types=1);
namespace App\FieldType\Point2D;
use App\Form\Type\Point2DType;
+use Ibexa\Contracts\Core\FieldType\Generic\Type as GenericType;
use Ibexa\Contracts\ContentForms\Data\Content\FieldData;
use Ibexa\Contracts\ContentForms\FieldType\FieldValueFormMapperInterface;
+use Symfony\Component\Form\FormInterface;
final class Type extends GenericType implements FieldValueFormMapperInterface
{
public function getFieldTypeIdentifier(): string
{
return 'point2d';
}
+ public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data)
+ {
+ $definition = $data->fieldDefinition;
+ $fieldForm->add('value', Point2DType::class, [
+ 'required' => $definition->isRequired,
+ 'label' => $definition->getName()
+ ]);
+ }
}
最後に、src/Form/Type/Point2DType.php
に configureOptions
メソッドを追加し、 data_class
のデフォルト値を Value::class
に設定します。これで、あなたのフォームがこのオブジェクトで動作するようになります。
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\FieldType\Point2D\Value;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class Point2DType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('x', NumberType::class);
$builder->add('y', NumberType::class);
}
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults([
+ 'data_class' => Value::class
+ ]);
+ }
}
新しいタグの追加
次に、 config/services.yaml
に ibexa.admin_ui.field_type.form.mapper.value
のタグを追加します。
App\FieldType\Point2D\Type:
tags:
- { name: ibexa.field_type, alias: point2d }
+ - { name: ibexa.admin_ui.field_type.form.mapper.value, fieldType: point2d }
ステップ4 - テンプレートの導入
Point 2D テンプレート
フィールドタイプのデータを表示するためには、そのためのテンプレートを作成し登録する必要があります。各フィールドタイプテンプレートは、目的のゴールを達成するために使用できる一連の変数を受け取ります。この場合、最も重要な変数はフィールドで、Ibexa\Contracts\Core\Repository\Values\Content\Field
のインスタンスです。自身のメタデータ(id
、fieldDefIdentifier
など)に加え、value
プロパティを通じてフィールド値を公開します。
何がどのように表示されるかを微調整するために、フィールドタイプテンプレートをオーバーライドできることを忘れないでください。詳細は、フィールドタイプテンプレートのドキュメントを参照してください。
まず、 templates
ディレクトリに point2d_field.html.twig
というテンプレートを作成します。これは、Point 2D のデフォルト表示を定義するものです。Point 2D の基本テンプレートは、次のようになります。
{% block point2d_field %}
({{ field.value.getX() }}, {{ field.value.getY() }})
{% endblock %}
テンプレートマッピング
次に、 config/packages/ibexa.yaml
にテンプレートのマッピングを指定します。
ibexa:
system:
default:
field_templates:
- { template: 'point2d_field.html.twig', priority: 0 }
ステップ5 - 新しい Point 2D フィールドの追加
このステップのすべてのアクションは管理画面で実行されます。管理画面(<yourdomain>/admin
)に移動し、デフォルトのユーザー名: admin
およびパスワード: Publish
でログインします。
新しいコンテンツタイプの追加
管理画面の左側のメニューで、[コンテンツ タイプ]ページに移動します。[コンテンツカテゴリ]で、新しいコンテンツタイプを作成します。
新しいコンテンツタイプには次の設定が必要です。
- 名前: Point 2D
- 識別子: point_2d
- フィールド: point2d.name
次に、以下のフィールドで point2d を定義します。
フィールドタイプ | 名前 | 識別子 | 必須 | 翻訳可能 |
---|---|---|---|---|
point2d | Point 2D | point_2d | はい | いいえ |
すべてを保存して、 [コンテンツ/コンテンツ構造] タブに戻ります。
コンテンツの作成
[コンテンツ構造] で、 [コンテンツの作成] を選択します。 Content の下に、追加したばかりの Point 2D Content Type が表示されます。クリックして新しいコンテンツを作成します。
ここで、ポイントの座標 (例: 3、5) を入力できます。指定された座標は、新しいポイントのタイトルとして使用されます。
[公開] をクリックします。これで、コンテンツ ツリーに新しい(3,5)ポイントが表示されます。
ヒント
結果が表示されない場合やエラーが発生した場合は、キャッシュをクリアしてアプリケーションをリロードしてください。
ステップ6 - Point 2D 設定の実装
設定を実装することで、フィールドをページ上に表示するためのフォーマットを定義することができます。そのために、Point 2D の座標の表示方法を変更することができる format
フィールドを作成することになります。
フィールドタイプのフォーマットの定義
このステップでは、Point 2D 座標の format
フィールドを作成します。そのためには、SettingsSchema
定義を定義する必要があります。また、座標をプレースホルダー値 %x%
と %y%
として指定します。
src/FieldType/Point2D/Type.php
を開き、以下のコードブロックに従って getSettingsSchema
メソッドを追加してください。
<?php
declare(strict_types=1);
namespace App\FieldType\Point2D;
use App\Form\Type\Point2DSettingsType;
use App\Form\Type\Point2DType;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Contracts\Core\FieldType\Generic\Type as GenericType;
use Ibexa\Contracts\Core\FieldType\Value;
use Ibexa\Contracts\ContentForms\Data\Content\FieldData;
use Ibexa\AdminUi\Form\Data\FieldDefinitionData;
use Ibexa\Contracts\ContentForms\FieldType\FieldValueFormMapperInterface;
use Symfony\Component\Form\FormInterface;
final class Type extends GenericType
{
public function getFieldTypeIdentifier(): string
{
return 'point2d';
}
public function getSettingsSchema(): array
{
return [
'format' => [
'type' => 'string',
'default' => '(%x%, %y%)',
],
];
}
public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data)
{
$definition = $data->fieldDefinition;
$fieldForm->add('value', Point2DType::class, [
'required' => $definition->isRequired,
'label' => $definition->getName()
]);
}
}
format フィールドの追加
このパートでは、フィールドタイプの編集フォームを定義して実装します。
src/Form/Type/Point2DSettingsType.php
で Point2DSettingsType
クラスを定義し、format
フィールドを追加します。
<?php
declare(strict_types=1);
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
final class Point2DSettingsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('format', TextType::class);
}
}
FieldDefinitionFormMapper インターフェイス
さて、ユーザーが検証される座標を追加できるようにします。 src/FieldType/Point2D/Type.php
で、以下のようになります。
-
FieldDefinitionFormMapperInterface
インターフェイスを実装する。 - フィールドの設定を定義する
mapFieldDefinitionForm
メソッドを最後に追加する。
<?php
declare(strict_types=1);
namespace App\FieldType\Point2D;
use Ibexa\AdminUi\FieldType\FieldDefinitionFormMapperInterface;
// ...
final class Type extends GenericType implements FieldValueFormMapperInterface, FieldDefinitionFormMapperInterface
// ...
public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data): void
{
$fieldDefinitionForm->add('fieldSettings', Point2DSettingsType::class, [
'label' => false
]);
}
完成した Type.php のコード
<?php
declare(strict_types=1);
namespace App\FieldType\Point2D;
use App\Form\Type\Point2DSettingsType;
use App\Form\Type\Point2DType;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Contracts\Core\FieldType\Generic\Type as GenericType;
use Ibexa\Contracts\Core\FieldType\Value;
use Ibexa\Contracts\ContentForms\Data\Content\FieldData;
use Ibexa\AdminUi\Form\Data\FieldDefinitionData;
use Symfony\Component\Form\FormInterface;
use Ibexa\Contracts\ContentForms\FieldType\FieldValueFormMapperInterface;
use Ibexa\AdminUi\FieldType\FieldDefinitionFormMapperInterface;
final class Type extends GenericType implements FieldValueFormMapperInterface, FieldDefinitionFormMapperInterface
{
public function getFieldTypeIdentifier(): string
{
return 'point2d';
}
public function getSettingsSchema(): array
{
return [
'format' => [
'type' => 'string',
'default' => '(%x%, %y%)',
],
];
}
public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data)
{
$definition = $data->fieldDefinition;
$fieldForm->add('value', Point2DType::class, [
'required' => $definition->isRequired,
'label' => $definition->getName()
]);
}
public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data): void
{
$fieldDefinitionForm->add('fieldSettings', Point2DSettingsType::class, [
'label' => false
]);
}
}
新しいタグの追加
次に、 FieldDefinitionFormMapper
を config/services.yaml
の AppttpFieldType
の追加タグ定義として追加する。
App\FieldType\Point2D\Type:
tags:
- { name: ibexa.field_type, alias: point2d }
- { name: ibexa.admin_ui.field_type.form.mapper.value, fieldType: point2d }
- { name: ibexa.admin_ui.field_type.form.mapper.definition, fieldType: point2d }
フィールドタイプの定義
新しい format
フィールドを表示できるようにするために、そのためのテンプレートを追加する必要があります。templates/point2d_field_type_definition.html.twig
を作成します。
{% block point2d_field_definition_edit %}
<div class="{% if group_class is not empty %}{{ group_class }}{% endif %}">
{{- form_label(form.fieldSettings.format) -}}
{{- form_errors(form.fieldSettings.format) -}}
{{- form_widget(form.fieldSettings.format) -}}
</div>
{% endblock %}
format フィールドの設定の追加
次に、 config/packages/ezplatform.yaml
にテンプレートのマッピングを指定します。
ibexa:
system:
default:
field_templates:
- { template: 'point2d_field.html.twig', priority: 0 }
fielddefinition_edit_templates:
- { template: 'point2d_field_type_definition.html.twig', priority: 0 }
テンプレートの再定義
最後に、Point 2D テンプレートを再定義し、新しい書式フィールドに対応させます。
templates/point2d_field.html.twig
で、内容を以下のように置き換えます。
{% block point2d_field %}
{{ fieldSettings.format|replace({
'%x%': field.value.x,
'%y%': field.value.y
}) }}
{% endblock %}
コンテンツタイプの編集
これで、管理画面の Admin から、Point 2D コンテンツタイプを編集して、作業結果を確認することができます。
ヒント
結果が表示されない場合やエラーが発生した場合は、キャッシュをクリアしてアプリケーションを再読み込みしてください。
下の画面のように、Format フィールドに新しいフォーマット(%x%
, %y%
)を追加します。
ステップ7 - 基本的なバリデーションの追加
両方の座標が提供されていることを確認する基本的な検証を行うには、 src/FieldType/Point2D/Value.php
にアサーションを追加してください。
use Symfony\Component\Validator\Constraints as Assert;
final class Value implements ValueInterface
{
/**
* @var float|null
*
* @Assert\NotBlank()
*/
private $x;
/**
* @var float|null
*
* @Assert\NotBlank()
*/
private $y;
// ...
その結果、ユーザーが1つの値だけを指定してPoint 2Dを公開しようとすると、エラーメッセージが表示されます。
ステップ8 - フィールドタイプのバージョン間のデータ移行
データ移行を追加することで、現在のニーズに合わせてフィールドタイプの出力を簡単に変更することができる。このプロセスは、フィールドタイプがソートや検索の目的で比較される必要がある場合に重要である。シリアライゼーションでは、オブジェクトを正規化することで配列に変更し、エンコードすることで選択されたフォーマットに変更することができる。逆に、デシリアライゼーションでは、異なるフォーマットをデコードして配列に変更し、それをオブジェクトにデノーマライズする。
シリアライザーコンポーネントの詳細な情報は、Symfony のドキュメントを参照してください。
正規化
まず、 src/Serializer/Point2D/ValueNormalizer.php
に正規化のサポートを追加する必要があります。
<?php
declare(strict_types=1);
namespace App\Serializer\Point2D;
use App\FieldType\Point2D\Value;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final class ValueNormalizer implements NormalizerInterface
{
public function normalize($object, string $format = null, array $context = [])
{
return [
$object->getX(),
$object->getY()
];
}
public function supportsNormalization($data, string $format = null)
{
return $data instanceof Value;
}
}
ノーマライザーの定義の追加
次に、 config/services.yaml
に serializer.normalizer
タグを付けて ValueNormalizer
のサービス定義を追加します。
services:
App\Serializer\Point2D\ValueNormalizer:
tags:
- { name: serializer.normalizer }
後方互換性
古いバージョンのフィールドタイプを受け入れるには、 src/Serializer/Point2D/ValueDenormalizer.php
で非正規化のサポートを追加する必要があります。
<?php
declare(strict_types=1);
namespace App\Serializer\Point2D;
use App\FieldType\Point2D\Value;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
final class ValueDenormalizer implements DenormalizerInterface
{
public function denormalize($data, string $class, string $format = null, array $context = [])
{
if (isset($data['x']) && isset($data['y'])) {
// Support for old format
$data = [$data['x'], $data['y']];
}
return new $class($data);
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return $type === Value::class;
}
}
Denormalizer の定義の追加
次に、 ValueDenormalizer
のサービス定義を config/services.yaml
に serializer.denormalizer
タグを付けて追加します。
services:
App\Serializer\Point2D\ValueDenormalizer:
tags:
- { name: serializer.denormalizer }
その場での書式変更
その場でフォーマットを変更するには、 src/FieldType/Point2D/Value.php
のコンストラクタを置き換える必要がある。
public function __construct(array $coords = [])
{
if (!empty($coords)) {
$this->x = $coords[0];
$this->y = $coords[1];
}
}
Point 2D フィールドタイプの内部表現形式を簡単に変更できるようになりました。