2. Let's do it with Drupal 8
Rubén Teijeiro
Was earlier today :)
Migrate in core
Christian López Espínola
Saturday 1pm
El universo javascript en Drupal 8
Ramón Vilar
Saturday 5pm
Modes and formatters
Jesús Sánchez Balsera
Sunday 10am
Related sessions
4. Amazing changes
• More power for site builders
• Fields & instances moved to config entities
• Formatters, Widgets and Field types are plugins
• Formatters & Widgets work on all fields
• Moved from field to entity storage
Field & Entity API are now one happy big family
11. New field types
• More power for site builders out of the box
• Not always full ports of the corresponding D7 modules
• Sometimes they are not even modules anymore (email, number, more to
come)
18. Form modes
• Similar to "view modes", on the form side
• Build several form variants for your entities:
• User registration / user edit
• Creation / edit forms
• Fields can now be hidden in forms
Beware of required fields with no default values...
21. Fields are tied to an entity type
A field cannot be "shared" across entity types,
only across bundles of a given entity type
Consequences:
• No need to clutter the field name ('comment_body')
node 'body' != comment 'body'
• A $field_name alone is not enough:
$field = FieldConfig::loadByName($entity_type, $field_name);
<div class="field-name-body field-node--body">
28. D8 Entity translation
• Entity level, not field level
$entity->getTranslation($langcode)
• Implements EntityInterface:
$entity->getTranslation($langcode)->field_foo
• Facets of the same entity
$entityis always loaded/saved as a whole
41. Everything in a ContentEntity is a field
• $node->title FieldItemListInterface
• $node->body FieldItemListInterface
• $node->field_custom FieldItemListInterface
Drawback: $node->title->value;
Mitigation: $node->getTitle();
42. Unified APIs and features
• field translation
• field access
• constraints / validation
• output in REST
• widgets / formatters
• In Place Editing
• EntityQuery (EFQ in D7)
• field cache (= entity cache!)
44. Different kinds of fields...
• Base fields (former "entity properties")
• defined in code: MyEntityType::baseFieldDefinitions()
• Bundle fields (variations of base fields per bundle)
• defined in code: MyEntityType::bundleFieldDefinitions()
• e.g. node title
• Configurable fields (former "fields") - field.module
• defined in config through an admin UI
Properties: what you find inside a FieldItem ('value', 'format', 'target_id'...)
47. Unified FieldStorageDefinitionInterface
Implementations:
• configurable fields: FieldConfig, FieldInstanceConfig
• base fields: FieldDefinition
interface FieldStorageDefinitionInterface {
public function getName();
public function getType();
public function getSettings();
public function getSetting($setting_name);
public function isTranslatable();
public function getDescription();
public function getCardinality();
public function isMultiple();
// Some others...
49. Field storage
• D7: pluggable "field storage engines", field per field
• D8: job of the EntityStorageController
• Entities are stored as a whole
• Easier to swap an alternate storage (Mongo...)
• Base class for "generic SQL field storage"
• Per-field tables (same as D7)
• Handles revisions, translations, multi values, multi properties
• ... only for configurable fields
50. Field storage (@todo, fingers crossed)
Problem:
• Supporting translatable base fields is hard
• 3rd party code can only add fields through config
Plan:
• Let base fields control how they are stored:
• Optimized storage in the entity base tables
• Generic storage, free translation support
• Custom storage somewhere else...
52. CMI
• Configuration in YML files
• Deployable between environments
• Can be shipped in modules
• ConfigEntities
53. Field definition structures
• $field: "a data bucket"
(name, type, cardinality, entity type, ...)
• $instance: "a field attached to a specific [entity_type, bundle]"
(label, description, required, ...)
D7:
• deep arrays of hell
• {field_config}, {field_config_instance}db tables
61. Display settings in D7
Scattered around:
• $instance['display'][$view_mode]
• 'field_bundle_settings_[entity_type]_[bundle]' variable (ew...)
• 3rd party (Display suite, Field groups): in their own tables...
Each with separate "alter" hooks
Loads needless stuff in memory
62. EntityViewDisplay (ConfigEntity)
• "Full recipe" for displaying an entity in a given view mode
• Lists "components", with order and settings
entity_view($entity, $view_mode) :
• Loads the relevant display
• Alters it as a whole
• Injects it into all the callstack
hook_entity_view_display_alter(EntityViewDisplay $display);
EntityViewBuilder::buildContent(array $entities, array $displays);
hook_entity_view(EntityInterface $entity, EntityViewDisplay $display);
67. D7: field type "hooks"
function hook_field_info() { }
function hook_field_schema($field) { }
function hook_field_settings_form($field, $instnce, $has_data) { }
function hook_field_instance_settings_form($field, $instance) { }
function hook_field_load($entity_type, $entities, $field, $instances, $langcode
function hook_field_validate($entity_type, $entity, $field, $instance, $langcode
function hook_field_presave($entity_type, $entity, $field, $instance, $langcode
function hook_field_insert($entity_type, $entity, $field, $instance, $langcode
function hook_field_update($entity_type, $entity, $field, $instance, $langcode
function hook_field_delete($entity_type, $entity, $field, $instance, $langcode
function hook_field_delete_revision($entity_type, $entity, $field, $instance,
function hook_field_is_empty($item, $field) { }
function hook_field_prepare_view($entity_type, $entities, $field, $instances,
function hook_field_prepare_translation($entity_type, $entity, $field, $instance
69. FieldItemInterface Now in 8.x !
interface FieldItemInterface {
public static function schema(FieldDefinitionInterface $field_definition);
public static function propertyDefinitions();
public function getConstraints();
public function isEmpty();
public static function defaultSettings();
public static function defaultInstanceSettings();
public function settingsForm(array $form, array &$form_state, $has_data);
public function instanceSettingsForm(array $form, array &$form_state);
public function prepareCache();
public function preSave();
public function insert();
public function update();
public function delete();
70. /core/modules/link/lib/Drupal/link/Plugin/Field/FieldType/LinkItem.php
namespace DrupallinkPluginFieldFieldType;
use DrupalCoreFieldFieldItemBase;
use DrupalCoreFieldFieldStorageDefinitionInterface;
use DrupalCoreTypedDataDataDefinition;
use DrupalCoreTypedDataMapDataDefinition;
use DrupallinkLinkItemInterface;
/**
* Plugin implementation of the 'link' field type.
*
* @FieldType(
* id = "link",
* label = @Translation("Link"),
* description = @Translation("Stores a URL string, optional varchar link text, and optional bl
* default_widget = "link_default",
* default_formatter = "link",
* constraints = {"LinkType" = {}}
* )
*/
class LinkItem extends FieldItemBase implements LinkItemInterface {
/**
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
72. D7: "hooks" (well, magic callbacks)
• Lost within the 50 other functions in your file
• switchdance when you implement several formatters
function mymodule_field_formatter_info() { }
function mymodule_field_formatter_settings_form($field, $instance, $view_mode,
function mymodule_field_formatter_settings_summary($field, $instance, $view_mode
function mymodule_field_formatter_prepare_view($entity_type, $entities, $field
function mymodule_field_formatter_view($entity_type, $entity, $field, $instance
73. D8: FieldFormatter plugins
• All logic nicely self contained.
• OO! Classes! ( = Inheritance!)
• FormatterBase class provides stubs and helpers
namespace DrupalCoreField;
interface FormatterInterface extends PluginSettingsInterface {
public static function defaultSettings()
public function settingsForm(array $form, array &$form_state);
public function settingsSummary();
public function prepareView(array $entities_items);
public function view(FieldItemListInterface $items);
public function viewElements(FieldItemListInterface $items);
}
74. D8: FieldFormatter plugin type
• No more _info() hook
• Expose your class as a "Field formatter" plugin
• Discovery folder: Plugin/Field/FieldFormatter
• Annotation: FieldFormatter
76. Working in formatters
• Access the configuration of the formatter:
$this->getSetting('foo'), $this->getSettings()
• Access the definition of the field:
$this->fieldDefinition->getType()
$this->getFieldSetting('foo'), $this->getFieldSettings()
• Manipulate the FieldItemList and FieldItem objects:
$items->getEntity(), $items->getLangcode()
You really want to extend FormatterBase...
78. FieldWidget plugin type
• Discovery folder: Plugin/Field/FieldWidget
• Annotation: FieldWidget
• WidgetBase class
interface WidgetInterface extends WidgetBaseInterface {
public static function defaultSettings()
public function settingsForm(array $form, array &$form_state);
public function settingsSummary();
public function formElement(FieldItemListInterface $items, $delta, array $element
public function errorElement(array $element, ConstraintViolationInterface $violation
public function massageFormValues(array $values, array $form, array &$form_state
}
79. Working in widgets
• Same as formatters...
• New in D8: massageFormValues()
Values produced by the FAPI structure → proper field values
• FAPI / render #callbacks:
$form['#process'] = '_my_process_helper';
$form['#process'] = array($this, 'myProcessHelper');
Please use static methods instead, (avoids serializing $this):
$form['#process'] = array(get_class($this), 'myProcessHelper');
80. Widgets / formatters on base fields
• Powerful flexibility
• Free support for "In Place Editing"
• Hey, EntityDisplays let us store the settings!
82. API changes / beta targets coming up
• Content translation sync settings to own storage
• A unified repository of field definitions
• Remove field_info_*() (Patch submitted)
• Apply formatters and widgets to * fields (Partially)
• Make delete fields work with config synchronization
83. Get involved
• [META] Complete the Entity Field API
http://drupal.org/node/2095603
• http://entity.worldempire.ch/
• Weekly IRC meetings: #drupal-entity - Thursday, 18:00 CET