LUCA LUSSO
(from drupal.org documentation)
PHP is a very loosely typed language. It doesn’t have a clear definition of the different types of data it deals with.
Therefore Drupal used to be the same. For example, there was no consistent way of telling if a field value is a string, an integer or a timestamp.
Or even, to tell if something is translatable or accessible (as in permissions).
Even if you as a developer happen to know that the value of a text field happens to be a string, there’s no consistent programmatic way of fetching this information.
This expose us to (at least) two kinds of problems:
$stub_form = drupal_get_form(
$node_type . '_node_form', (object) $stub_node
);
$form_state['triggering_element'] = $stub_form['actions']['submit'];
drupal_form_submit(
$node_type . '_node_form', $form_state, (object)$stub_node
);
if ($errors = form_get_errors()) {
return services_error(
implode(" ", $errors), 406, array('form_errors' => $errors));
}
How the Services module saves a node posted to a REST endpoint.
function email_field_validate($obj_type, $object, $field, $instance, $langcode, $items, &$errors) {
foreach ($items as $delta => $item) {
if ($item['email'] != '' && !valid_email_address(trim($item['email']))) {
$message = t('"%mail" is not a valid email address', array('%mail' => $item['email']));
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => "email_invalid",
'message' => $message,
);
}
}
}
Email module hook_field_validate.
The Typed Data API was created to provide developers with a consistent way of interacting with data in different ways.
The Typed Data API provides means of fetching more information, or metadata, about the actual data.
(partial) class diagram of Typed Data API.
The Typed Data API mainly provides three different interfaces.
Implementations of this interface are used for data that is composed of named properties with more pieces of data.
Implementations of this interface are used for something that is composed of a sequential list of other things, for instance a list of other complex pieces of data. Lists are ordered and may contain duplicate items.
Implementations of this interface are used for something that represents a single piece of typed data, like a string or integer.
This is the smallest building block in the Typed Data API.
TypedDataInterface are implemented as Drupal 8 plugins (with @DataType annotation).
/**
* @DataType(
* id = "string",
* label = @Translation("String")
* )
*/
class StringData extends PrimitiveBase implements StringInterface {
TypedDataInterface implementations stores the data, the metadata are stored in other classes that implements DataDefinitionInterface.
And we can derive the DataDefinition from the TypedData and vice-versa
TypedDataInterface::getDataDefinition();
DataDefinitionInterface::getDataType();
// Create a new DataDefinition instance
// wrapping the 'string' TypedData.
$definition = DataDefinition::create('string');
// Create a new data based on the previous definition
$data = \Drupal::typedDataManager()
->create($definition, 'my string');
$defintion = ListDataDefinition::create('string');
$list = \Drupal::typedDataManager()
->create($defintion, ['my string1', 'my string2']);
$title = DataDefinition::create('string');
$title_data = \Drupal::typedDataManager()
->create($title, 'Link title');
$url = DataDefinition::create('uri');
$url_data = \Drupal::typedDataManager()
->create($url, 'http://www.drupal.org');
$link = MapDataDefinition::create();
$link_data = \Drupal::typedDataManager()
->create($link);
$link_data->set('title', $title_data);
$link_data->set('url', $url_data);
DataDefinitions can have constraints to limit the data that they accept.
Constraints are Drupal 8 plugins (with @Constraint annotation) and are build on the Symfony Validator component.
$definition = DataDefinition::create('string')
->addConstraint('Length', ['max' => 5]);
$data = \Drupal::typedDataManager()
->create($definition, 'my string');
$definition = DataDefinition::create('string')
->addConstraint('Length', ['max' => 5]);
$data = \Drupal::typedDataManager()
->create($definition, 'my string');
$validations = $data->validate();
$validations is an instance of \Symfony\Component\Validator\ConstraintViolationList
The Drupal 8 entity API is built on the Typed Data API.
An entity is a complex piece of data it is composed of other pieces of data, like fields with a list of items.
Entities are complex.
$entity instanceof ComplexDataInterface;
Properties are not complex, they’re only a list of items.
$entity->get('image') instanceof ListInterface;
Items are complex.
$entity->get('image')
->offsetGet(0) instanceof ComplexDataInterface;
Item values are primitive.
$entity->get('image')
->offsetGet(0)->get('alt') instanceof TypedDataInterface;
Get an array with named keys for all fields and their definitions.
$property_definitions = $entity->getFieldDefinitions();
Get an array with name keys for all properties and their definitions.
$property_definitions = $entity->image
->getFieldDefinition()->getPropertyDefinitions();
Get only definition for the ‘alt’ property.
$string_definition = $entity->image
->getFieldDefinition()->getPropertyDefinition('alt');
Entity API add two plugin instances to TypedData.
entity plugin
/**
* @DataType(
* id = "entity",
* label = @Translation("Entity"),
* description =
@Translation("All kind of entities, e.g. nodes, commentss"),
* deriver =
"\Drupal\Core\Entity\Plugin\DataType\Deriver\EntityDeriver",
* definition_class =
"\Drupal\Core\Entity\TypedData\EntityDataDefinition"
* )
*/
field_item plugin
/**
* @DataType(
* id = "field_item",
* label =
@Translation("Field item"),
* list_class =
"\Drupal\Core\Field\FieldItemList",
* deriver =
"Drupal\Core\Field\Plugin\DataType\Deriver\FieldItemDeriver"
* )
*/
Book you test with a tweet with #tyds hashtag
Thanks!s
Questions?