LoginSignup
0
0

More than 1 year has passed since last update.

Ibexa DXP でのカスタムフィールドタイプの作成

Last updated at Posted at 2021-12-31

カスタム汎用フィールドタイプの作成

汎用フィールドタイプは、住所などの構造化データを保持するフィールドタイプを抽象的に実装したものです。これをベースにして、カスタムフィールドタイプを作成することができます。汎用フィールドタイプには、基本的なメソッドが実装されており、作成しなければならないクラスの数を減らし、タグ付けのプロセスを簡略化することができます。

ヒント
非常に特殊な実装や、データの保存方法を完全に制御する必要がある場合は、汎用フィールドタイプを使うべきではありません。

Value オブジェクトの定義

まず、 src/FieldType/HelloWorld ディレクトリに Value.php を作成します。フィールドタイプの Value クラスには、フィールドタイプの基本的なロジックのみが含まれており、それ以外は Type クラスで処理されます。フィールドタイプの Value の詳細については、 Value の取り扱いを参照してください。

HelloWorld の Value クラスには、以下のものが含まれているはずです。

  • name を取得するパブリックプロパティ
  • toString() メソッドの実装
src/FieldType/HelloWorld/Value.php
<?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 抽象クラスの実装を提供します。

src/FieldType/HelloWorld/Type.php
<?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 のフォームを作成します。これにより、新しいフィールドタイプを編集することができます。

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 に追加してください。

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 ファイルを作成します。

templates/field_type.html.twig
{% block hello_world_field %}
    Hello <b>{{ field.value.getName() }}!</b>
{% endblock %}

テンプレートマッピング

config/packages/ibexa.yaml にテンプレートのマッピングを指定します。

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 に基本的なバリデーションを追加する
  • フィールドタイプにデータ移行を追加することで、簡単に出力を変更できるようにする

ステップ

このチュートリアルでは、次の手順を実行します。

  1. Point 2D Value クラスの実装
  2. Point 2D フィ​​ールドタイプの定義
  3. フィールドタイプを編集するためのフォームの作成
  4. テンプレートの導入
  5. 新しい Point 2D フィールドの追加
  6. Point 2D の設定の実装
  7. 基本的なバリデーションの追加
  8. フィールドタイプのバージョン間のデータ移行

ステップ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() メソッドを実装する必要があります。また、 xy のプロパティのゲッターとセッターを追加する必要があります。このクラスは、2D座標を表現します。

最終的にはこのようなコードになります。

src/FieldType/Point2D/Value.php
<?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)を一意に識別する文字列を返します。

src/FieldType/Point2D/Type.php
<?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.yamlibexa.field_type タグを追加してください。

config/services.yaml
services:
    App\FieldType\Point2D\Type:
        tags:
            - { name: ibexa.field_type, alias: point2d }

ステップ3 - フィールドタイプを編集するためのフォームの作成

フォームの作成

新しいフィールドタイプを編集するには、Point2DType.php フォームを src/Form/Type ディレクトリに作成します。次に、 AbstractType を継承し、 buildForm() メソッドを実装した Point2DType クラスを追加します。このメソッドは、xy の座標のフィールドを追加します。

src/Form/Type/Point2DType.php
<?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
  • カスタムオプション: requiredlabel

最終版の Type クラスは、以下のステートメントと関数を持つ必要があります。

src/FieldType/Point2D/Type.php
 <?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.phpconfigureOptions メソッドを追加し、 data_class のデフォルト値を Value::class に設定します。これで、あなたのフォームがこのオブジェクトで動作するようになります。

src/Form/Type/Point2DType.php
<?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.yamlibexa.admin_ui.field_type.form.mapper.value のタグを追加します。

config/services.yaml
    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 のインスタンスです。自身のメタデータ(idfieldDefIdentifierなど)に加え、value プロパティを通じてフィールド値を公開します。

何がどのように表示されるかを微調整するために、フィールドタイプテンプレートをオーバーライドできることを忘れないでください。詳細は、フィールドタイプテンプレートのドキュメントを参照してください。

まず、 templates ディレクトリに point2d_field.html.twig というテンプレートを作成します。これは、Point 2D のデフォルト表示を定義するものです。Point 2D の基本テンプレートは、次のようになります。

templates/point2d_field.html.twig
{% block point2d_field %}
    ({{ field.value.getX() }}, {{ field.value.getY() }})
{% endblock %}

テンプレートマッピング

次に、 config/packages/ibexa.yaml にテンプレートのマッピングを指定します。

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 メソッドを追加してください。

src/FieldType/Point2D/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 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.phpPoint2DSettingsType クラスを定義し、format フィールドを追加します。

src/Form/Type/Point2DSettingsType.php
<?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 メソッドを最後に追加する。
src/FieldType/Point2D/Type.php
<?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 のコード

src/FieldType/Point2D/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
        ]);
    }
}

新しいタグの追加

次に、 FieldDefinitionFormMapperconfig/services.yamlAppttpFieldType の追加タグ定義として追加する。

config/services.yaml
    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 を作成します。

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 にテンプレートのマッピングを指定します。

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 で、内容を以下のように置き換えます。

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 にアサーションを追加してください。

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 に正規化のサポートを追加する必要があります。

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.yamlserializer.normalizer タグを付けて ValueNormalizer のサービス定義を追加します。

config/services.yaml
services:
    App\Serializer\Point2D\ValueNormalizer:
        tags:
            - { name: serializer.normalizer }

後方互換性

古いバージョンのフィールドタイプを受け入れるには、 src/Serializer/Point2D/ValueDenormalizer.php で非正規化のサポートを追加する必要があります。

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.yamlserializer.denormalizer タグを付けて追加します。

config/services.yaml
services:
    App\Serializer\Point2D\ValueDenormalizer:
        tags:
            - { name: serializer.denormalizer }

その場での書式変更

その場でフォーマットを変更するには、 src/FieldType/Point2D/Value.php のコンストラクタを置き換える必要がある。

src/FieldType/Point2D/Value.php
    public function __construct(array $coords = [])
    {
        if (!empty($coords)) {
            $this->x = $coords[0];
            $this->y = $coords[1];
        }
    }

Point 2D フィールドタイプの内部表現形式を簡単に変更できるようになりました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0