Skip to content

Create custom generic Field Type

The Generic Field Type is an abstract implementation of Field Types holding structured data for example, address. You can use it as a base for custom Field Types. The Generic Field Type comes with the implementation of basic methods, reduces the number of classes which must be created, and simplifies the tagging process.

Tip

You should not use the Generic Field Type when you need a very specific implementation or complete control over the way data is stored.

Define value object

First, create Value.php in the src/FieldType/HelloWorld directory. The Value class of a Field Type contains only the basic logic of a Field Type, the rest of it is handled by the Type class. For more information about Field Type Value see Value handling.

The HelloWorld Value class should contain:

  • public properties that retrieve name
  • an implementation of the __toString() method
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

namespace App\FieldType\HelloWorld;

use eZ\Publish\SPI\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}!";
    }
}

Define fields and configuration

Next, implement a definition of a Field Type extending the Generic Field Type in the src/FieldType/HelloWorld/Type.php class. It provides settings for the Field Type and an implementation of the eZ\Publish\SPI\FieldType\FieldType abstract class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php

namespace App\FieldType\HelloWorld;

use App\Form\Type\HelloWorldType;
use eZ\Publish\SPI\FieldType\Generic\Type as GenericType;

final class Type extends GenericType implements FieldValueFormMapperInterface
{
    public function getFieldTypeIdentifier(): string
    {
        return 'hello_world';
    }
}

Tip

For more information about the Type class of a Field Type, see Type class.

Next, register the Field Type as a service and tag it with ezplatform.field_type:

1
2
3
4
5
services:
    App\FieldType\HelloWorld\Type:
        public: true
        tags:
            - { name: ezplatform.field_type, alias: hello_world }

Define form for value object

Create a src/Form/Type/HelloWorldType.php form. It enables you to edit the new Field Type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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
        ]);
    }
}

Now you can map Field definitions into Symfony forms with FormMapper. Add the mapFieldValueForm() method required by FieldValueFormMapperInterface and the required use statements to src/FieldType/HelloWorld/Type.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App\FieldType\HelloWorld;

use App\Form\Type\HelloWorldType;
use eZ\Publish\SPI\FieldType\Generic\Type as GenericType;
use EzSystems\EzPlatformContentForms\Data\Content\FieldData;
use EzSystems\EzPlatformContentForms\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()
        ]);
    }
}

Tip

For more information about the FormMappers see Field Type form and template.

Next, add the ezplatform.field_type.form_mapper.value tag to the service definition:

1
2
3
4
5
6
services:
    App\FieldType\HelloWorld\Type:
        public: true
        tags:
            - { name: ezplatform.field_type, alias: hello_world }
            - { name: ezplatform.field_type.form_mapper.value, fieldType: hello_world }

Render fields

Create a template

Create a template for the new Field Type. It defines the default rendering of the HelloWorld field. In the templates directory create a field_type.html.twig file:

1
2
3
{% block hello_world_field %}
    Hello <b>{{ field.value.getName() }}!</b>
{% endblock %}

Template mapping

Provide the template mapping in config/packages/ezplatform.yaml:

1
2
3
4
5
ezplatform:
    system:
        default:
            field_templates:
                - { template: 'field_type.html.twig', priority: 0 }

Final results

Finally, you should be able to add a new Content Type in the Back Office interface. Navigate to Content Types tab and under Content category create a new Content Type:

Creating new Content Type

Next, define a Hello World field:

Defining Hello World

After saving, your Hello World Content Type should be available under Content in the sidebar menu.

Creating Hello World

For more detailed tutorial on Generic Field Type follow Creating a Point 2D Field Type .