Your SlideShare is downloading. ×
0
D8: Fields reborn
Pablo López - @plopesc
DrupalCamp Spain
Valencia, May 2014
Let's do it with Drupal 8
Rubén Teijeiro
Was earlier today :)
Migrate in core
Christian López Espínola
Saturday 1pm
El uni...
Credits: @yched & @swentel
Broken record
Amazing changes
• More power for site builders
• Fields & instances moved to config entities
• Formatters, Widgets and Fie...
... for the 3rd time
yched, amateescu, swentel
fago, Berdir, plach,
effulgentsia, andypost...
Site building
features
New field types
• More power for site builders out of the box
• Not always full ports of the corresponding D7 modules
• So...
Entity reference
Fairly complete port of D7 entity_reference.module
Taxonomy, file, image fields: still separate field typ...
Date / Datetime
The "repeat" features from D7 stays in contrib
Link
Basic version (URL, text)
No support for internal paths (e.g. node/1)
Now supports internal paths (https://drupal.org...
Email
• Input validation
• No anti-spam support out of the box
Phone
• HTML5 "tel" input
• Basic display (optional "tel:" ...
In Place Editing
Fieldable blocks
aka Beans in core
Form modes
• Similar to "view modes", on the form side
• Build several form variants for your entities:
• User registratio...
Form modes UI
Field Overview UI
Fields are tied to an entity type
A field cannot be "shared" across entity types,
only across bundles of a given entity ty...
There will be code
APIs !!!
Disclaimer: still in flux...
Data structures
Data model recap
• Field value: list of multiple items
• Each item: list of properties depending on the field type
• Field...
Data model - D7
Data model - D7
D8 Entity translation
• Entity level, not field level
$entity->getTranslation($langcode)
• Implements EntityInterface:
$en...
Data model - D8
Data model - D8
Data model - D8
Data model - D8
Data model - D8
Data model - D8
Data model - D8
Data model - D8
In a nutshell
• $entity, $entity->getTranslation('fr') Entity
• $entity->field_foo FieldItemList
• $entity->field_foo[$del...
Navigating
Field items are "smart":
$items->getEntity() $items->getLangcode()
$items->getFieldDefinition()
$instances = fi...
Everything is a field
Everything
Everything in a ContentEntity is a field
• $node->title FieldItemListInterface
• $node->body FieldItemListInterface
• $nod...
Unified APIs and features
• field translation
• field access
• constraints / validation
• output in REST
• widgets / forma...
Naming is hard...
Different kinds of fields...
• Base fields (former "entity properties")
• defined in code: MyEntityType::baseFieldDefiniti...
Code architecture
• /core/lib/Drupal/Core/Field
The Field system, widgets, formatters...
baked in the lifecycle of (Conten...
Unified FieldStorageDefinitionInterface
Field definition: name, type, label, cardinality, settings, description...
• D7: $...
Unified FieldStorageDefinitionInterface
Implementations:
• configurable fields: FieldConfig, FieldInstanceConfig
• base fi...
Grabbing field definitions
field_info_fields()
field_info_field($field_name)
field_info_instances($entity_type, $bundle)
f...
Field storage
• D7: pluggable "field storage engines", field per field
• D8: job of the EntityStorageController
• Entities...
Field storage (@todo, fingers crossed)
Problem:
• Supporting translatable base fields is hard
• 3rd party code can only ad...
CMI
CMI
• Configuration in YML files
• Deployable between environments
• Can be shipped in modules
• ConfigEntities
Field definition structures
• $field: "a data bucket"
(name, type, cardinality, entity type, ...)
• $instance: "a field at...
D8: Field structures as ConfigEntities
• $field:
• FieldConfig(entity type: 'field_config')
• field.field.[entity_type].[f...
field.field.node.body.yml
id: node.body
uuid: d9a197db-89e1-4b8b-b50c-122083aeacb1
status: true
langcode: en
name: body
en...
field.instance.node.article.body.yml
id: node.article.body
uuid: a378b8b5-39ac-44da-bc07-7ad0a2479a6a
status: true
langcod...
CRUD API - D7
Dedicated functions:
+ associated hooks...
field_create_field(array());
field_update_field(array());
field_d...
CRUD API - D8
Regular Entity CRUD API:
+ regular hook_entity_[ENTITY_TYPE]_[OP]()hooks
$field = entity_create('field_confi...
EntityDisplay
Display settings in D7
Scattered around:
• $instance['display'][$view_mode]
• 'field_bundle_settings_[entity_type]_[bundle...
EntityViewDisplay (ConfigEntity)
• "Full recipe" for displaying an entity in a given view mode
• Lists "components", with ...
entity.display.node.article.teaser.yml
id: node.article.teaser
uuid: ad345f0f-ff44-4210-8900-b8bdfcd8e671
targetEntityType...
EntityViewDisplay API
$display = entity_get_display('node', 'article', 'teaser');
$display->setComponent('body', array(
't...
EntityFormDisplay
• Same thing for forms :-)
• Allows "form modes"
Field types
D7: field type "hooks"
function hook_field_info() { }
function hook_field_schema($field) { }
function hook_field_settings_...
FieldType plugin type
• Discovery folder: Plugin/Field/FieldType
• Annotation: FieldType
• Interface: FieldItemInterface
FieldItemInterface Now in 8.x !
interface FieldItemInterface {
public static function schema(FieldDefinitionInterface $fie...
/core/modules/link/lib/Drupal/link/Plugin/Field/FieldType/LinkItem.php
namespace DrupallinkPluginFieldFieldType;
use Drupa...
Formatters
D7: "hooks" (well, magic callbacks)
• Lost within the 50 other functions in your file
• switchdance when you implement sev...
D8: FieldFormatter plugins
• All logic nicely self contained.
• OO! Classes! ( = Inheritance!)
• FormatterBase class provi...
D8: FieldFormatter plugin type
• No more _info() hook
• Expose your class as a "Field formatter" plugin
• Discovery folder...
Inheritance example
Working in formatters
• Access the configuration of the formatter:
$this->getSetting('foo'), $this->getSettings()
• Access...
Widgets
FieldWidget plugin type
• Discovery folder: Plugin/Field/FieldWidget
• Annotation: FieldWidget
• WidgetBase class
interfac...
Working in widgets
• Same as formatters...
• New in D8: massageFormValues()
Values produced by the FAPI structure → proper...
Widgets / formatters on base fields
• Powerful flexibility
• Free support for "In Place Editing"
• Hey, EntityDisplays let...
/core/modules/node/lib/Drupal/node/Entity/Node.php
public static function baseFieldDefinitions(EntityTypeInterface $entity...
API changes / beta targets coming up
• Content translation sync settings to own storage
• A unified repository of field de...
Get involved
• [META] Complete the Entity Field API
http://drupal.org/node/2095603
• http://entity.worldempire.ch/
• Weekl...
Thanks!
Questions?
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Upcoming SlideShare
Loading in...5
×

Drupal 8: Fields reborn

1,399

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,399
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Drupal 8: Fields reborn"

  1. 1. D8: Fields reborn Pablo López - @plopesc DrupalCamp Spain Valencia, May 2014
  2. 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
  3. 3. Credits: @yched & @swentel Broken record
  4. 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
  5. 5. ... for the 3rd time
  6. 6. yched, amateescu, swentel fago, Berdir, plach, effulgentsia, andypost...
  7. 7. Site building features
  8. 8. 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)
  9. 9. Entity reference Fairly complete port of D7 entity_reference.module Taxonomy, file, image fields: still separate field types
  10. 10. Date / Datetime The "repeat" features from D7 stays in contrib
  11. 11. Link Basic version (URL, text) No support for internal paths (e.g. node/1) Now supports internal paths (https://drupal.org/node/2054011)
  12. 12. Email • Input validation • No anti-spam support out of the box Phone • HTML5 "tel" input • Basic display (optional "tel:" link)
  13. 13. In Place Editing
  14. 14. Fieldable blocks aka Beans in core
  15. 15. 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...
  16. 16. Form modes UI
  17. 17. Field Overview UI
  18. 18. 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">
  19. 19. There will be code APIs !!!
  20. 20. Disclaimer: still in flux... Data structures
  21. 21. Data model recap • Field value: list of multiple items • Each item: list of properties depending on the field type • Fields can be translatable
  22. 22. Data model - D7
  23. 23. Data model - D7
  24. 24. 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
  25. 25. Data model - D8
  26. 26. Data model - D8
  27. 27. Data model - D8
  28. 28. Data model - D8
  29. 29. Data model - D8
  30. 30. Data model - D8
  31. 31. Data model - D8
  32. 32. Data model - D8
  33. 33. In a nutshell • $entity, $entity->getTranslation('fr') Entity • $entity->field_foo FieldItemList • $entity->field_foo[$delta] FieldItem • $entity->field_foo[$delta]->property • $entity->field_foo->propertyfor delta 0
  34. 34. Navigating Field items are "smart": $items->getEntity() $items->getLangcode() $items->getFieldDefinition() $instances = field_info_instances($entity_type, $bundle); foreach ($instances as $field_name => $instance) { $items = $entity[$field_name][$langcode]; do_something($items, $entity, $langcode, $instance); } D7 foreach ($entity as $field_name => $items) { $items->doSomething(); // or $object->doSomething($items); } D8
  35. 35. Everything is a field
  36. 36. Everything
  37. 37. Everything in a ContentEntity is a field • $node->title FieldItemListInterface • $node->body FieldItemListInterface • $node->field_custom FieldItemListInterface Drawback: $node->title->value; Mitigation: $node->getTitle();
  38. 38. 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!)
  39. 39. Naming is hard...
  40. 40. 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'...)
  41. 41. Code architecture • /core/lib/Drupal/Core/Field The Field system, widgets, formatters... baked in the lifecycle of (Content)Entities • /core/modules/field.module Configurable fields
  42. 42. Unified FieldStorageDefinitionInterface Field definition: name, type, label, cardinality, settings, description... • D7: $field / $instance arrays $field['type'], $instance['settings']['max'] • D8: FieldStorageDefinitionInterface $definition->getType(), $definition->getSetting('max')... • Autocompletion, documentation... • $field / $instance are mostly abstracted away
  43. 43. 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...
  44. 44. Grabbing field definitions field_info_fields() field_info_field($field_name) field_info_instances($entity_type, $bundle) field_info_instances($entity_type, $bundle, $field_name) D7 $entity_manager->getFieldDefinitions($entity_type, $bundle) // On an entity: $entity->getFieldDefinitions() $entity->getFieldDefinition($field_name) $entity->hasField($field_name) // On items: $item->getFieldDefinition(), $items->getFieldDefinition() D8D8D8
  45. 45. 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
  46. 46. 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...
  47. 47. CMI
  48. 48. CMI • Configuration in YML files • Deployable between environments • Can be shipped in modules • ConfigEntities
  49. 49. 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
  50. 50. D8: Field structures as ConfigEntities • $field: • FieldConfig(entity type: 'field_config') • field.field.[entity_type].[field_name].yml • $instance: • FieldInstanceConfig(entity type: 'field_instance_config') • field.instance.[entity_type].[bundle].[field_name].yml
  51. 51. field.field.node.body.yml id: node.body uuid: d9a197db-89e1-4b8b-b50c-122083aeacb1 status: true langcode: en name: body entity_type: node type: text_with_summary settings: { } module: text locked: false cardinality: 1 translatable: false indexes: { } dependencies: module: - node - text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  52. 52. field.instance.node.article.body.yml id: node.article.body uuid: a378b8b5-39ac-44da-bc07-7ad0a2479a6a status: true langcode: en field_uuid: d9a197db-89e1-4b8b-b50c-122083aeacb1 field_name: body entity_type: node bundle: article label: Body description: '' required: false default_value: { } default_value_function: '' settings: display_summary: true text_processing: true dependencies: entity: - field.field.node.body - node.type.article field_type: text_with_summary 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  53. 53. CRUD API - D7 Dedicated functions: + associated hooks... field_create_field(array()); field_update_field(array()); field_delete_field($field_name); ............_instance(array()); D7
  54. 54. CRUD API - D8 Regular Entity CRUD API: + regular hook_entity_[ENTITY_TYPE]_[OP]()hooks $field = entity_create('field_config', array( 'name' => 'body', 'entity_type' => 'node', 'type' => 'text_with_summary', ); $field->save(); $field->cardinality = 2; $field->save(); $field->delete(); D8
  55. 55. EntityDisplay
  56. 56. 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
  57. 57. 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);
  58. 58. entity.display.node.article.teaser.yml id: node.article.teaser uuid: ad345f0f-ff44-4210-8900-b8bdfcd8e671 targetEntityType: node bundle: article mode: teaser content: field_image: label: hidden type: image settings: image_style: medium image_link: content weight: -1 body: label: hidden type: text_summary_or_trimmed weight: 0 settings: trim_length: 600 field_tags: type: taxonomy_term_reference_link weight: 10 label: above 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  59. 59. EntityViewDisplay API $display = entity_get_display('node', 'article', 'teaser'); $display->setComponent('body', array( 'type' => 'text_trimmed', 'settings' => array('trim_length' => '600' )) ->removeComponent('image') ->save(); $options = $display->getComponent('body'); // array( // 'type' => 'text_default' // 'weight' => 0, // 'settings' => array(), // 'label' => 'hidden', // ) // or NULL if 'body' is hidden
  60. 60. EntityFormDisplay • Same thing for forms :-) • Allows "form modes"
  61. 61. Field types
  62. 62. 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
  63. 63. FieldType plugin type • Discovery folder: Plugin/Field/FieldType • Annotation: FieldType • Interface: FieldItemInterface
  64. 64. 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();
  65. 65. /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
  66. 66. Formatters
  67. 67. 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
  68. 68. 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); }
  69. 69. D8: FieldFormatter plugin type • No more _info() hook • Expose your class as a "Field formatter" plugin • Discovery folder: Plugin/Field/FieldFormatter • Annotation: FieldFormatter
  70. 70. Inheritance example
  71. 71. 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...
  72. 72. Widgets
  73. 73. 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 }
  74. 74. 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');
  75. 75. Widgets / formatters on base fields • Powerful flexibility • Free support for "In Place Editing" • Hey, EntityDisplays let us store the settings!
  76. 76. /core/modules/node/lib/Drupal/node/Entity/Node.php public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['title'] = FieldDefinition::create('string') ->setLabel(t('Title')) ->setDescription(t('The title of this node, always treated as non-markup plain text.')) // ... ->setSettings(array( // Array settings... )) ->setDisplayOptions('view', array( // Array options... )) ->setDisplayOptions('form', array( // Array options... )) ->setDisplayConfigurable('form', TRUE); //.... } public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $node_type = node_type_load($bundle); $fields = array(); if (isset($node_type->title_label)) { $fields['title'] = clone $base_field_definitions['title']; $fields['title']->setLabel($node_type->title_label); } return $fields; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  77. 77. 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
  78. 78. 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
  79. 79. Thanks!
  80. 80. Questions?
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×