Your SlideShare is downloading. ×
0
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
Drupal 8: Fields reborn
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
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Drupal 8: Fields reborn

1,371

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,371
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. D8: Fields reborn Pablo López - @plopesc DrupalCamp Spain Valencia, May 2014
  • 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. Credits: @yched & @swentel Broken record
  • 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. ... for the 3rd time
  • 6. yched, amateescu, swentel fago, Berdir, plach, effulgentsia, andypost...
  • 7. Site building features
  • 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. Entity reference Fairly complete port of D7 entity_reference.module Taxonomy, file, image fields: still separate field types
  • 10. Date / Datetime The "repeat" features from D7 stays in contrib
  • 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. Email • Input validation • No anti-spam support out of the box Phone • HTML5 "tel" input • Basic display (optional "tel:" link)
  • 13. In Place Editing
  • 14. Fieldable blocks aka Beans in core
  • 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. Form modes UI
  • 17. Field Overview UI
  • 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. There will be code APIs !!!
  • 20. Disclaimer: still in flux... Data structures
  • 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. Data model - D7
  • 23. Data model - D7
  • 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. Data model - D8
  • 26. Data model - D8
  • 27. Data model - D8
  • 28. Data model - D8
  • 29. Data model - D8
  • 30. Data model - D8
  • 31. Data model - D8
  • 32. Data model - D8
  • 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. 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. Everything is a field
  • 36. Everything
  • 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. 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. Naming is hard...
  • 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. 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. 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. 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. 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. 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. 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. CMI
  • 48. CMI • Configuration in YML files • Deployable between environments • Can be shipped in modules • ConfigEntities
  • 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. 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. 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. 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. CRUD API - D7 Dedicated functions: + associated hooks... field_create_field(array()); field_update_field(array()); field_delete_field($field_name); ............_instance(array()); D7
  • 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. EntityDisplay
  • 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. 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. 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. 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. EntityFormDisplay • Same thing for forms :-) • Allows "form modes"
  • 61. Field types
  • 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. FieldType plugin type • Discovery folder: Plugin/Field/FieldType • Annotation: FieldType • Interface: FieldItemInterface
  • 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. /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. Formatters
  • 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. 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. D8: FieldFormatter plugin type • No more _info() hook • Expose your class as a "Field formatter" plugin • Discovery folder: Plugin/Field/FieldFormatter • Annotation: FieldFormatter
  • 70. Inheritance example
  • 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. Widgets
  • 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. 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. Widgets / formatters on base fields • Powerful flexibility • Free support for "In Place Editing" • Hey, EntityDisplays let us store the settings!
  • 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. 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. 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. Thanks!
  • 80. Questions?

×