Get on with Field API

Drupalcamp Spain - Cáceres 27/10/2013

Get on with Field API

Drupalcamp Spain - Cáceres 27/10/2013

What is Field API

Terminology

Structure

Semaphore bundle Mug bundle
Entity
Instance Semaphore color Mug color
Field Type Color

Field API components

Field API components

Field Types API

Field Type

Widget

Formatter

... and all for what??

To make our life easier!!

Our boss need...

Show the sum of all field items

The easy way...

			function my_module_node_view($node, $view_mode, $langcode) {
  if ($node->type == 'page') {
    if (isset($node->content['field_integer'][0])) {
      $items = $node->field_integer['und'];
      $result = 0;
      foreach ($items as $item) {
        $result += $item['value'];
      }
      $node->content['field_integer'] =
        array(array('#markup' => $result));
    }
  }
}
		

It works but...

Yes, you can


use Field API!!

hook_field_formatter_info()

			function addition_formatter_field_formatter_info() {
  return array(
    'addition_formatter_basic' => array(
      'label' => t('Basic Addition Formatter'),
      'description' => t('Sums all the field items'),
      'field types' => array('number_integer', 'number_decimal', 'number_float'),
      'settings' => array(),
    ),
  );
}
		

hook_field_formatter_view()

			function addition_formatter_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  if ($items) {
    $addition = 0;
    foreach ($items as $delta => $item) {
      $addition += $item['value'];
    }
    $element[0] = array('#markup' => $addition);
  }
  return $element;
}
		

But now, what I need...

...is represent basic arithmetic
operations and store its results

How would I write it...

http://www.flickr.com/photos/jasonmirandes/

It's so easy


using Field API...

Field Language API

How to access to our fields

$values = $entity->my_field['und'][0]

$language = field_language('node', $node, 'my_field'); $values = $node->my_field[$language][0];

How to access to our fields using Field API

field_get_items
($entity_type, $entity, $field_name, $langcode = NULL)

field_view_field
($entity_type, $entity, $field_name, $display = array(), $langcode = NULL)

field_view_value
($entity_type, $entity, $field_name, $item, $display = array(), $langcode = NULL)

http://www.flickr.com/photos/jasonmirandes/

Field API


do it for us...

...and Drupal 8??

Field API in D8

Field types are now plugins: https://drupal.org/node/2064123

Entity based storage: https://drupal.org/node/2078765

Form modes: https://drupal.org/node/2014821

Some others...

Goodbye hooks and procedural code!

Drupal 7: 85 hooks

Drupal 8: 21 hooks and counting down...

still under


construction

...but show me

the code!

Addition formatter

modules/addition_formatter/lib/Drupal/addition_formatter/Plugin/Field/FieldFormatter/NumberFullAdditionFormatter.php

			namespace Drupal\addition_formatter\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\number\Plugin\Field\FieldFormatter\NumberDecimalFormatter;

/**
 * Plugin implementation of the 'number_full_addition' formatter.
 *
 * @FieldFormatter(
 *   id = "number_full_addition",
 *   label = @Translation("Number Full Addition"),
 *   field_types = {
 *     "number_integer",
 *     "number_decimal",
 *     "number_float"
 *   },
 *   settings = {
 *     "thousand_separator" = "",
 *     "decimal_separator" = ".",
 *     "scale" = "2",
 *     "prefix_suffix" = "TRUE"
 *   }
 * )
 */
class NumberFullAdditionFormatter extends NumberDecimalFormatter {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items) {
    foreach ($items as $delta => $item) {
      if ($delta != 0) {
        $items[0]->value += $item->value;
        unset($items[$delta]);
      }
    }

    return parent::viewElements($items);
  }

}
		

https://github.com/plopesc/drupalCampES2013/tree/8.x/addition_formatter

Arithmetic field type

modules/arithmetic_field/lib/Drupal/arithmetic_field/Plugin/Field/FieldType/ArithmeticItem.php

			namespace Drupal\arithmetic_field\Plugin\Field\FieldType;

use Drupal\Core\Field\ConfigFieldItemBase;
use Drupal\field\FieldInterface;

  /**
   * Plugin implementation of the 'arithmetic' field type.
   *
   * @FieldType(
   *   id = "arithmetic",
   *   label = @Translation("Arithmetic"),
   *   description = @Translation("Field that represents arithmetic operations."),
   *   default_widget = "arithmetic",
   *   default_formatter = "arithmetic"
   * )
   */
class ArithmeticItem extends ConfigFieldItemBase {

  /**
   * Definitions of the contained properties.
   *
   * @var array
   */
  static $propertyDefinitions;

  const ADDITION = '+';
  const SUBTRACTION = '-';
  const MULTIPLICATION = 'X';
  const DIVISION = '/';

  /**
   * {@inheritdoc}
  */
  public function getPropertyDefinitions() {
    if (!isset(static::$propertyDefinitions)) {
      static::$propertyDefinitions['operand1'] = array(
        'type' => 'float',
        'label' => t('First value'),
      );
      static::$propertyDefinitions['operand2'] = array(
        'type' => 'float',
        'label' => t('Second value'),
      );
      static::$propertyDefinitions['operation'] = array(
        'type' => 'string',
        'label' => t('operation'),
      );
      static::$propertyDefinitions['value'] = array(
        'type' => 'float',
        'label' => t('Operation result'),
      );
    }
    return static::$propertyDefinitions;
  }

  /**
   * {@inheritdoc}
  */
  public static function schema(FieldInterface $field) {
    return array(
      'columns' => array(
        'operand1' => array(
          'type' => 'float',
          'not null' => FALSE,
        ),
        'operand2' => array(
          'type' => 'float',
          'not null' => FALSE,
        ),
        'operation' => array(
          'type' => 'varchar',
          'length' => 1,
          'not null' => FALSE
        ),
        'value' => array(
          'type' => 'float',
          'not null' => FALSE,
        ),
      ),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function isEmpty() {
    if ((empty($this->operand1) && (string) $this->operand1 !== '0') || (empty($this->operand2) && (string) $this->operand2 !== '0')) {
      return TRUE;
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function preSave() {
    switch($this->operation) {
      case ArithmeticItem::SUBTRACTION:
        $this->value = $this->operand1 - $this->operand2;
        break;
      case ArithmeticItem::MULTIPLICATION:
        $this->value = $this->operand1 * $this->operand2;
        break;
      case ArithmeticItem::DIVISION:
        $this->value = $this->operand1 / $this->operand2;
        break;
      case ArithmeticItem::ADDITION:
      default:
        $this->value = $this->operand1 + $this->operand2;
    }
  }

}
		

https://github.com/plopesc/drupalCampES2013/tree/8.x/arithmetic_field

Arithmetic widget

modules/arithmetic_field/lib/Drupal/arithmetic_field/Plugin/Field/fieldWidget/ArithmeticWidget.php

			namespace Drupal\arithmetic_field\Plugin\Field\fieldWidget;

use Drupal\arithmetic_field\Plugin\Field\FieldType\ArithmeticItem;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;

/**
 * Plugin implementation of the 'arithmetic' widget.
 *
 * @FieldWidget(
 *   id = "arithmetic",
 *   label = @Translation("Arithmetic"),
 *   field_types = {
 *     "arithmetic"
 *   },
 *   settings = {
 *     "placeholder" = ""
 *   }
 * )
 */
class ArithmeticWidget extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, array &$form_state) {
    $element['placeholder'] = array(
      '#type' => 'textfield',
      '#title' => t('Placeholder'),
      '#default_value' => $this->getSetting('placeholder'),
      '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
    );
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = array();

    $placeholder = $this->getSetting('placeholder');
    if (!empty($placeholder)) {
      $summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
    }
    else {
      $summary[] = t('No placeholder');
    }

    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
    $operand1 = isset($items[$delta]->operand1) ? $items[$delta]->operand1 : NULL;
    $operand2 = isset($items[$delta]->operand2) ? $items[$delta]->operand2 : NULL;
    $operation = isset($items[$delta]->operation) ? $items[$delta]->operation : NULL;

    $element += array(
      '#type' => 'fieldset',
    );

    $element['operand1'] = array(
      '#type' => 'number',
      '#default_value' => $operand1,
      '#placeholder' => $this->getSetting('placeholder'),
      '#step' => 'any',
      '#weight' => 0,
    );

    $element['operation'] = array(
      '#type' => 'select',
      '#options' => array(
        ArithmeticItem::ADDITION => ArithmeticItem::ADDITION,
        ArithmeticItem::SUBTRACTION => ArithmeticItem::SUBTRACTION,
        ArithmeticItem::MULTIPLICATION => ArithmeticItem::MULTIPLICATION,
        ArithmeticItem::DIVISION => ArithmeticItem::DIVISION
      ),
      '#default_value' => $operation,
      '#weight' => 1,
    );

    $element['operand2'] = array(
      '#type' => 'number',
      '#default_value' => $operand2,
      '#placeholder' => $this->getSetting('placeholder'),
      '#step' => 'any',
      '#weight' => 2,
    );

    return $element;
  }

}
		

https://github.com/plopesc/drupalCampES2013/tree/8.x/arithmetic_field

Code comparison

Addition formatter Files Folders Lines of code
Drupal 7 2 1 98
Drupal 8 4 7 61
Arithmetic field Files Folders Lines of code
Drupal 7 3 1 128
Drupal 8 5 9 187

It’s good to have code organized.

Don't stop me now


using Field API

Thank you!

Drupal.org: plopesc

Twitter: @plopesc

Fork me on Github