Upload
lykhuong
View
215
Download
0
Embed Size (px)
Citation preview
PRESENTATION TITLE
BADCamp 2017
Custom Compound Fields
In Drupal 8OCTOBER 21, 2017
DIRECTOR OF ENGINEERING
Tobby Hagler
Introduction
Email: [email protected]: tobby
Architect for projects such as
• NBA
• Weight Watchers
• Memorial Sloan Kettering Cancer Center
Recent DrupalCon presentations
• Building NBA.com on Drupal 8
• Dungeons & Dragons & Drupal
Previous Compound Field Blog Post
• https://www.phase2technology.com/blog/compound-fields-drupal-7
BADCamp 2017 Website
Custom Compound Fields in Drupal 8
https://2017.badcamp.net/session/coding-development
/intermediate/custom-compound-fields-drupal-8
Slides
WHAT IS A COMPOUND FIELD?
A field that is composed of two or more separate elements
•Atoms
•Molecules
•Organisms
• Templates
• Pages
ATOMIC CONTENT MODEL
Elements of Atomic Design
•Country
•Street Address
•City
• State or Province
• ZIP or Postal Code
ATOMIC CONTENT MODEL
Address Field as a Molecule
CREATING CUSTOM COMPOUND FIELDS
Examples of Compound Fields
• Recipe and Ingredients (metrics, units)
• Photo Carousel on a page
• Medical Patient Records and prescriptions
• Storing D&D characters (stats, attributes, etc.)
• Paragraphs
• Custom Field API field
• Entity Construction Kit + Inline Entity Form, Field Collections, Bricks
Options
EXAMPLE: RECIPE INGREDIENTS
RECIPES
Ingredients List
Paragraphs allow for a compound field that is made up of a collection of other Drupal fields. Anything that is already a field in Drupal can be added to a Paragraph, including another Paragraph field.
Can be thought of like a “content type” of fields; different Paragraph types that consist of fields.1
Option 1: Paragraphs
1. Admin > Structure > Paragraph types
Creating a Paragraph Type
PARAGRAPHS
PARAGRAPHS
An Example Paragraph Type
PARAGRAPHS
An Example Paragraph Type
PARAGRAPHS
An Example Paragraph Type
THEMING
Theming of a Paragraphs field is made possible using a template file in your theme:
• paragraph.html.twig
• paragraph- -quote.html.twig
The twig template contains markup to render each element.
Create a custom module to add a new field.
• Field type
• Field formatter
• Field widget 2Option 2: Custom Field API Fields
FIELD API
A Custom Ingredient Field on a Recipe Node
File Structure foo_bar_fields/
foo_bar_fields.info.yml
src/
Plugin/
Field/
FieldType/
FooItem.php
FieldFormatter/
FooBarFormatter.php
FieldWidget/
FooBarWidget.php
https://www.drupal.org/docs/8/creating-custom-modules/creating-a-custom-field
Field Plugins•Field Type - Tells Drupal that the field exists and defines the database schema for storing the data points for the field.
•Field Widget - This is the input of the field. This is essentially a form for capturing whatever data points are needed for this field.
•Field Formatter - This the output of the field. It governs how the data can be structured for output as well as setting a template for the field’s markup.
Field Plugins and What They Do
STEP 1: DEFINITION - FIELD TYPE•File location
ingredient/src/Plugin/Field/FieldType/Ingredient.php
•Namespace \Drupal\ingredient\Plugin\Field\FieldType\Ingredient
Drupal 8 plugins come from Symfony 2, and require an annotation.
This is not a comment block.
This registers the plugin with Drupal, and gives some basic context about what the plugin is and what it does.
Plugin Annotation /** * Provides a field type of Ingredient. * * @FieldType( * id = "ingredient", * label = @Translation("Ingredient"), * default_formatter = "ingredient_formatter", * default_widget = “ingredient_widget", * ) */
class Ingredient extends FieldItemBase implements FieldItemInterface { … }
Annotation For Field Types
Field Type/** * {@inheritdoc} */ public static function schema(FieldStorageDefinitionInterface $field_definition) {
return array( // columns contains the values that the field will store 'columns' => array( // List the values that the field will save. This // field will only save a single value, 'value' 'value' => array( … ), 'type' => 'text', 'size' => 'tiny', 'not null' => FALSE, ), ), ); }
Example: $field_fieldname[0][‘value’]
Define the Field Type’s Schema
Field Type/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return array(
// Columns contains the values that the field will store.
'columns' => array(
// List the values that the field will save.
'quantity' => array( … ),
'unit' => array( … ),
'name' => array( … ),
'note' => array( … ),
),
);
}
Example: $field_fieldname[0][‘name’] or [‘note’]
Define the Field Type’s Schema
Title Text
Field TypeIngredient class contains:
•schema - Defines the database schema
•propertyDefinitions - Allows for field settings; such as choosing between Imperial and Metric units (or both) for an Ingredient’s unit value.
•isEmpty - This checks if the system has any field values for this field type. This is used when trying to modify a field instance’s settings; it won’t allow it if there is already data for the field.
Other Class Methods
STEP 2: INPUT - FIELD WIDGET•File location
ingredient/src/Plugin/Field/FieldWidget/IngredientWidget.php
•Namespace \Drupal\ingredient\Plugin\Field\FieldWidget
This widget can apply to more than just the Ingredient field type.
A custom field widget plugin can be a standalone plugin that just adds new widgets to existing field types.
Plugin Annotation /** * An Ingredient field widget. * * @FieldWidget( * id = "ingredient", * label = @Translation("Ingredient widget"), * field_types = { * "ingredient", * "string" * } * ) */
class BarWidget extends WidgetBase implements WidgetInterface { … }
Annotation For Field Widgets
class IngredientWidget extends WidgetBase implements WidgetInterface {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, $element, &$form, $form_state) {
$element['quantity'] = $element + array( … );
$element['unit'] = $element + array( … );
$element['name'] = $element + array(
'#type' => 'textfield',
'#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
'#size' => $this->getSetting('size'),
);
$element['node'] = $element + array( … );
return $element;
}
Define the Field Widget Form
Field WidgetIngredientWidget class contains:
•formElement - This defines the widget similar to Form API form arrays. This is how Javascript elements can be attached to the field’s element.
•validate - Just like a Form API form, this is the form validator that is executed when the form is submitted.
•defaultSettings - Allows for default values for this widget.
•settingsForm - The form used to allow admins to change widget settings.
•settingsSummary - Block of markup describing the settings.
Other Class Methods
Field Widget Alter
hook_field_widget_form_alter
• &$element - The field widget form element as constructed by hook_field_widget_form().
• $form_state - The current state of the form.
• $context - An associative array containing the following key-value pairs
Altering Existing Widgets
STEP 3: OUTPUT - FIELD FORMATTER•File location ingredient/src/Plugin/Field/FieldFormatter/IngredientFormatter.php
•Namespace \Drupal\ingredient\Plugin\Field\FieldFormatter
This formatter can apply to more than just the Ingredient field type.
This formatter can apply to any field type, provided it is capable of accessing each of the field’s element values.
Plugin Annotation /** * Provides a field formatter for Ingredient. * * @FieldFormatter( * id = "ingredient", * label = @Translation("Ingredient Formatter"), * field_types = { * "ingredient" * } * ) */
class IngredientFormatter extends FormatterBase { … }
Annotation For Field Formatter
Field Formatter/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$element = [];
foreach ($items as $delta => $item) {
// Render each element as markup.
$element[$delta] = [
'#type' => 'markup',
'#markup' => “$item->quantity $item->unit of $item->name“,
];
}
return $element;
}
Define the Field Formatter Output
Field FormatterIngredientFormatter class contains:
•viewElements - Returns a renderable array of the field’s values.
•defaultSettings - Allows for default values for this formatter.
•settingsForm - The form used to allow admins to change widget settings.
•settingsSummary - Block of markup describing the settings.
Other Class Methods
THEMING
Theming of any field is made possible using a template file in your theme or module:
• Based on field.html.twig
• field- -ingredient.html.twig
The twig template contains markup to render each element.
#theme=>’ingredient’ in the Field Formatter tells Drupal to use the theme_ingredient, an
This creates uses the module’s implementation of hook_theme to register a new theme key called ‘ingredient’.
This will allow for a new template called ‘ingredient.html.twig’ to be used for theming Ingredient fields.
/** * Implements hook_theme(). */ function ingredient_theme($existing, $type, $theme, $path) {
$theme = [ 'ingredient' => [ 'variables' => [ 'quantity' => NULL, 'unit' => NULL, 'name' => NULL, 'note' => NULL, ], ], ]; return $theme; }
Field And hook_theme
INGREDIENT FIELD WIDGET
Ingredients Field Elements
RECIPE WITH INGREDIENTS
Full Recipe Node with Custom Ingredients Field
• Entity Construction Kit + Inline Entity Form
- This is the closest thing to Paragraphs using existing contrib modules
• Field Collections
- “Paragraphs is likely to replace field collection for Drupal 8. Field collection is on its way to being deprecated. It is recommended to use paragraphs instead of field collection for Drupal 8 projects.”
• Bricks
- Complicated to use
- More of a competitor to Panelizer
?Other Options for Compound Fields
ECK+IEFEntity Construction Kit with Inline Entity Form
•ECK+IEF site builder experience can be complicated
•Content editing is as easy Paragraphs
•ECK+IEF does not support revisions; problematic for editorial workflow
•Works well with Search
•Has less support in the Drupal community than Paragraphs
ECK+IEF Compared to Paragraphs
QUESTIONS?