Step 3 - Implement the Tweet\Type class¶
You can find all files used and modified in this step on GitHub.
The Type class¶
The Type contains the logic of the Field Type: validating data, transforming from various formats, describing the validators, etc.
A Type class must implement
eZ\Publish\SPI\FieldType\FieldType ("Field Type interface").
All native Field Types also extend the
eZ\Publish\Core\FieldType\FieldType abstract class that implements this interface and provides implementation facilities through a set of abstract methods of its own. In this case, Type classes implement a mix of methods from the Field Type interface and from the abstract Field Type.
The recommended way to allow the Field Type to be able to generate content name is through implementing the
Let's go over those methods and their implementation.
This method must return the string that uniquely identifies the Field Type, in this case "
1 2 3 4
Value handling methods¶
Both methods are used by the abstract Field Type implementation of
This Field Type interface method checks and transforms various input values into the Type's own Value class:
This method must:
- either return the value object it was able to create out of the input value,
- or return this value untouched. The API will detect this and inform that the input value was not accepted.
The only acceptable value for the type is the URL of a tweet:
1 2 3 4 5 6 7 8
Use this method to provide convenient ways to set an attribute's value using the API. This can be anything from primitives to complex business objects.
checkValueStructure(). It is called by the abstract Field Type to ensure that the Value fed to the Type is acceptable. In this case, you need to ensure that
Tweet\Value::$url is a string:
1 2 3 4 5 6 7 8 9 10
The difference between this method and
createValueFromInput() is that
createValueFromInput() will, if given something else than a value of its type, try to convert it to one.
checkValueStructure() will always be used, even if the Field Type is directly fed a value object, and not a string.
This method provides what is considered an empty value of this type, depending on the business requirements. No extra initialization is required in this case.
1 2 3 4
The Type class is also responsible for validating input data (to a
Field), as well as configuration input data (to a
In this tutorial, you will validate submitted URLs, ensuring they actually reference a Twitter status.
validate() is the method that runs the validation on data, when a Content item is created with a Field of this type:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
You validate the URL with a regular expression. If it doesn't match, you add an instance of
ValidationError to the return array.
Note that the tested value isn't directly embedded in the message but passed as an argument.
This ensures that the variable is properly encoded in order to prevent attacks, and allows for singular/plural phrases using the second parameter.
You will create more advanced custom validation later in the tutorial.
Metadata handling methods¶
Field Types require two methods related to Field metadata:
getFieldName()is used to generate a name out of a Field value, either to name a Content item or to generate a part for a URL alias.
getSortInfo()is used by the persistence layer to obtain the value it can use to sort and filter on a Field of this Field Type.
A tweet's full URL isn't suitable as a name. Instead use subset of it:
<username>-<tweetId> is suitable for both sorting and naming.
You can assume that this method will not be called if the Field is empty, and that the URL is a valid Twitter URL:
1 2 3 4 5 6 7 8 9 10 11 12 13
getFieldName() you run a regular expression replace operation on the URL to extract the part you're interested in.
This name is a perfect match for
getSortInfo() as it allows you to sort by the tweet's author and by the tweet's ID.
eZ\Publish\SPI\FieldType\FieldType interface there is also
getName() method that is currently deprecated and replaced by
You can throw an exception in its body to make sure it isn't called anywhere:
1 2 3 4 5 6
Field Type serialization methods¶
Both methods defined in the Field Type interface are core to the REST API. They are used to export values to serializable hashes:
toHash()builds a hash with every property from
Tweet\Valuewith the hash it receives.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Storage of Field Type data is done through the persistence layer (SPI).
Field Types use their own value objects to expose their contents using their own domain language.
However, to store those objects, the Type needs to map this custom object
to a structure understood by the persistence layer:
PersistenceValue is a simple value object that has three properties:
data- standard data, stored using the storage engine's native features
externalData- external data, stored using a custom storage handler
sortKey- sort value used for sorting
The role of those mapping methods is to convert a
Value of the Field Type into a
PersistenceValue and the other way around.
About external storage¶
Whatever is stored in
externalData requires an external storage handler to be written. Read more about external storage in Field Type API.
External storage is beyond the scope of this tutorial, but many examples can be found in existing Field Types.
You will follow a simple implementation here: the
Tweet\Value object will be serialized as an array to the
code property using
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
Fetching data from the Twitter API¶
As explained in the tutorial's introduction, you will enrich the tweet's URL with the embed version, fetched using the Twitter API. To do so, you will fill in the value's contents property from the
toPersistenceValue() when it is called, before creating the
First, you need a Twitter client in
Tweet\Type. For convenience, one is provided in this tutorial's bundle.
Copy the following files to your bundle's directory:
The interface has one method:
getEmbed( $statusUrl ) that returns the embed code as a string when given a tweet's URL.
Next, add the
ezsystems.tweetbundle.twitter.client service that uses the class above to
1 2 3
Injecting the Twitter client into
The Field Type doesn't have a constructor yet.
You will create one, with an instance of
Twitter\TwitterClientInterface as the argument, and store it in a new protected property:
1 2 3 4 5 6 7 8 9 10 11
Completing the value using the Twitter client¶
As described above, before creating the
PersistenceValue object in
you will fetch the tweet's embed contents using the client, and assign it to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
When the persistence layer stores content from your type, the value will be completed with what the Twitter API returns.
In the end the Type class should have the following
1 2 3 4 5 6 7 8 9 10 11