Field Type storage¶
If you want to store Field values in regular Ibexa DXP database tables,
FieldValue must be converted to the storage-specific format used by the Persistence SPI:
After restoring a Field of the Field Type, you must reverse the conversion.
The following methods of the Field Type are responsible for that:
|This method receives the value of a Field of the Field Type and returns an SPI
FieldValue, which can be stored.
|This method receives an SPI
FieldValue and reconstructs the original value of the Field from it.
FieldValue struct has properties which the Field Type can use:
|The data to be stored in the database. This may be a scalar value, an associative array or a simple, serializable object.
|The arbitrary data stored in this field will not be touched by any of the Ibexa DXP components directly, but will be available for Storing data externally.
|A value which can be used to sort content by this Field.
Legacy storage engine¶
The Legacy storage engine uses the
ezcontentobject_attribute table to store Field values,
ezcontentclass_attribute to store Field definition values.
They are both based on the same principle.
Each row represents a Field or a Field definition, and offers several free fields of different types, where the type can store its data e.g.
Each type is free to use those fields in any way it requires.
The default Legacy storage engine cannot store arbitrary value information as provided by a Field Type. This means that using this storage engine requires a conversion. Converters will map a Field's semantic values to the fields described above, for both settings (validation and configuration) and value.
The conversion takes place through the
which you must implement in your Field Type. The interface contains the following methods:
|Converts a Persistence
Value into a Legacy storage specific value.
|Converts the other way around.
|Converts a Persistence
FieldDefinition to a storage specific one.
|Converts the other way around.
|Returns the storage column which is used for indexing either
Just like a Type, a Legacy Converter needs to be registered and tagged in the service container.
Registering a converter¶
The registration of a
Converter currently works through the
$config parameter of
Those converters also need to be correctly exposed as services and tagged with
1 2 3 4
The tag has the following attribute:
fieldTypeIdentifier (just like for the Field Type service).
Converter configuration for built-in Field Types is located in
Storing data externally¶
A Field Type may store arbitrary data in external data sources. External storage can be e.g. a web service, a file in the file system, another database or even the Ibexa DXP database itself (in form of a non-standard table).
In order to store data in external storage, the Field Type will interact with the Persistence SPI
Accessing the internal storage of a Content item that includes a Field of the Field Type calls one of the following methods to also access the external data:
|Returns whether the Field Type stores external data at all.
|Called right before a Field of the Field Type is stored. The method stores
$externalData. It returns
true if the call manipulated internal data of the given Field, so that it is updated in the internal database.
|Called after a Field has been restored from the database in order to restore
|Must delete external data for the given Field, if exists.
|Returns the actual index data for the provided
Ibexa\Contracts\Core\Persistence\Content\Field. For more information, see search service.
Each of the above methods (except
hasFieldData) receives a
$context array with information on the underlying storage and the environment.
To retrieve and store data in the Ibexa DXP data storage,
but outside of the normal structures (e.g. a custom table in an SQL database),
use Gateway-based storage with properly injected Doctrine Connection.
Note that the Field Type must take care on its own for being compliant with different data sources and that third parties can extend the data source support easily.
In order to allow the usage of a Field Type that uses external data with different data storages, it is recommended to implement a gateway infrastructure and a registry for the gateways. To make this easier, the Core implementation of Field Types provides corresponding interfaces and base classes. They can also be used for custom Field Types.
Ibexa\Contracts\Core\FieldType\StorageGateway is implemented by gateways, in order to be handled correctly by the registry. It has one method:
|The registry mechanism uses this method to set the SPI storage connection (e.g. the database connection to the Legacy Storage database) into the gateway, which might be used to store external data. The connection is retrieved from the
$context array automatically by the registry.
Note that the Gateway implementation itself must take care of validating that it received a usable connection. If it does not, it should throw a
The registry mechanism is realized as a base class for
Ibexa\Core\FieldType\GatewayBasedStorage. For managing
StorageGateways, the following methods are already implemented in the base class:
|Allows the registration of additional
StorageGateways from the outside. Furthermore, an associative array of
StorageGateways can be given to the constructor for basic initialization. This array should originate from the dependency injection mechanism.
|This protected method is used by the implementation to retrieve the correct
StorageGateway for the current context.
Refer to the built-in Keyword, URL and User Field Types for usages of such infrastructure.
Registering external storage¶
To use external storage, you need to define a service implementing the
and tag it as
ibexa.field_type.storage.external.handler to be recognized by the Repository.
Here is an example for the
myfield Field Type:
1 2 3 4 5 6 7 8 9
The configuration requires providing the
ibexa.field_type.storage.external.handler tag, with the
alias attribute being the fieldTypeIdentifier. You also have to inject the gateway in
arguments, see Gateway-based storage.
External storage configuration for basic Field Types is located in
Using gateway-based storage requires another service implementing
Ibexa\Core\FieldType\StorageGateway to be injected into the external storage handler).
1 2 3 4 5 6 7
ibexa.api.storage_engine.legacy.connection is of type
Doctrine\DBAL\Connection. If your gateway still uses an implementation of
eZ\Publish\Core\Persistence\Doctrine\ConnectionHandler), instead of the
ibexa.api.storage_engine.legacy.connection, you can pass the
Also note that there can be several gateways per Field Type (one per storage engine). In this case it's recommended to either create base implementation which each gateway can inherit or create interface which each gateway must implement and reference it instead of specific implementation when type-hinting method arguments.
Gateway configuration for built-in Field Types is located in
Storing Field Type settings externally¶
Just like in the case of data, storing Field Type settings in Content Item tables may prove insufficient. It is not a problem if your setting specifies, for example, just the allowed number of characters in a text field. However, the Field Type may represent a more complex object, for example, it may consist of two or more other fields, such as the name, SKU and price, and there can be a set of default values instead of just one. Once you add validation rules for these field values, then it becomes an issue.
You can overcome this obstacle: When you create a new Field Type, you can move Field Type settings to external storage.
Another benefit of an external storage is that there can be database relations to other objects/entities, and the database itself can maintain the integrity of data.
First, create a class that implements the
Then, register the External Storage as a service and tag it with
Make sure that the alias you use matches the identifier of the new Field Type:
1 2 3 4