home
Hero image for: How to create a Field Formatter in Drupal 8

How to create a Field Formatter in Drupal 8

By Eduardo García ● CTO | December 9th, 2014

One of the most significant changes in Drupal 8 is his integration with RESTful.

Because now Views lives in Core you can create a view with JSON response in few minutes; you just need to enable modules Views, Views UI, and RESTful Web Services

The problem I found with the image is the formatter for images is not compatible with RESTful responses due the output of Image formatter is HTML.

Create a View

Let me explain the situation if you create a view with a Rest Export display you can select what fields of your entity you want to render.

Now if you choose an image field, the default format is Image as you can see in the following snapshot.

image field formatter

Even if you don’t set the option to link to the original image you will get the image in HTML format as you see in the following sample of JSON response.

[
  {
    title: "Image sample # 3",
    field_image: " <img 
  src="http://example.com/sites/enzo/files/styles/thumbnail/public/
  field/image/globe.jpg?itok=wmu3VCr6" width="100" height="75" 
  alt="" typeof="foaf:Image" class="image-style-thumbnail" /> "
  },
  {
    title: "Image sample # 2",
    field_image: " <img 
  src="http://example.com/sites/enzo/files/styles/thumbnail/public/
  field/image/sample_08.jpg?itok=X9N005N1" width="100" height="75" 
  alt="" typeof="foaf:Image" class="image-style-thumbnail" /> "
  },
  {
    title: "Image sample # 1",
    field_image: " <img 
  src="http://d$/sites/enzo/files/styles/thumbnail/public/
  field/image/sample_01.jpg?itok=UD1-QXTj" width="100" height="75" 
  alt="" typeof="foaf:Image" class="image-style-thumbnail" /> "
  }
]

The previous output was generated by a view selecting articles with images, if you want to import this view in your system download the file views_list.yml and import using the Configuration Management of Drupal accessing the URL http://example.com/admin/config/development/configuration/single/import in your Drupal install as you can see in the following image.

configuration management view import

If you want to read more about Configuration Management in Drupal 8, you can read the post entry Understanding Configuration Management in Drupal 8

To resolve this problem, I will show you how to create your Field Formatter to meet your needs.

Create a Module

I will skip the explanation about how to create a Module in Drupal 8 because could be generated using the project Drupal Console executing the following command.

$ php console.phar generate:module

Create a new Field Formatter

If you want to create a new custom Field Formatter is required to add a new class file located inside your module in the following path

YOUR_MODULE/src/Plugin/Field/FieldFormatter/

Inside this folder, you must create a class file per each Field Formatter do you want to create.

I will create a new file named ImageRawFormatter.php; I will explain each part of this file

Field Formatter Metadata

Before to start to the code we must define some stuff required for a proper function.

Namespace

We have to define what will be Namespace for your Field Formatter

namespace Drupal\image_raw_formatter\Plugin\Field\FieldFormatter;

Drupal 8 implement PSR-4 from PHP Framework Interop Group

This specification follows the following pattern

\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>

In our case, the division will be

  • NamespaceName: Drupal
  • SubNamespaceNames: image_raw_formatter\Plugin\Field\FieldFormatter
  • ClassName: ImageRawFormatter

Libraries required

In this specific case, we have to define where are classes we require to create our Field Formatter.

Drupal 8 use Autoloader class, but we need to inform where they are using the instruction use.

use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatterBase;
use Drupal\image\Entity\ImageStyle;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Field\FieldItemListInterface;
use \InvalidArgumentException;

Annotations

Drupal 8 have several discovers to detect specific implementation, for instance, we have a Discover to detect all Field Formatter declared in our application and the way to declare a new Field Formatter is using Annotations.

Below you can find an annotation example for Field Formatter

/**
 * Plugin implementation of the 'image_raw_formatter' formatter.
 *
 * @FieldFormatter(
 *   id = "image_raw_formatter",
 *   label = @Translation("Image Raw"),
 *   field_types = {
 *     "image"
 *   }
 * )
 */

As you can see, we must define a unique id with a label with translation and we must define for which field types this Field Formatter will be available.

Implement Class

Now we have to create a class extending from ImageFormatterBase as you can see in the following snippet

class ImageRawFormatter extends ImageFormatterBase
{
}

Settings Form

Now we have to add a method settingsForm to define the Setting options for our Formatter. check the following implementation.

/**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, 
  FormStateInterface $form_state) {
    $image_styles = image_style_options(FALSE);
    $element['image_style'] = array(
      '#title' => t('Image style'),
      '#type' => 'select',
      '#default_value' => $this->getSetting('image_style'),
      '#empty_option' => t('None (original image)'),
      '#options' => $image_styles,
    );
    return $element;
  }

The implementation above allows the user to select a specific image style to be returned or just return the original image.

Summary Report

Is important to inform to end users current setting of formatter, to enable that we have to implement the method settingsSummary

/**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = array();
    $image_styles = image_style_options(FALSE);
    // Unset possible 'No defined styles' option.
    unset($image_styles['']);
    // Styles could be lost because of enabled/disabled modules that 
    // defines their styles in code.
    $image_style_setting = $this->getSetting('image_style');
    if (isset($image_styles[$image_style_setting])) {
      $summary[] = t('Image style: @style', 
  array('@style' => $image_styles[$image_style_setting]));
    }
    else {
      $summary[] = t('Original image');
    }
    return $summary;
  }

As you can see the method above, just read the current settings and render an output.

Render Field Formatter

At the end we need to define the how we want to render the field based in current Field Formatter settings, we have to implement the method viewElements as you can see in the following snippet.

/**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items) {
    $elements = array();
    $image_style_setting = $this->getSetting('image_style');

    // Determine if Image style is required.
    $image_style = NULL;
    if (!empty($image_style_setting)) {
      $image_style = entity_load('image_style', $image_style_setting);
    }
    foreach ($items as $delta => $item) {
      if ($item->entity) {
        $image_uri = $item->entity->getFileUri();
        // Get image style URL
        if ($image_style) {
          $image_uri = ImageStyle::load(
  $image_style->getName())->buildUrl($image_uri
  );
        } else {
          // Get absolute path for original image
          $image_uri = $item->entity->url();
        }
        $elements[$delta] = array(
          '#markup' => $image_uri,
        );
      }
    }
    return $elements;
  }

If you read the logic only determine if the configuration requires use any image style or if is only required the original image, in both sceneries the proper path URL is returned.

We don’t need any transformation to JSON because that is handled by view Display selected.

Module usage

After enabling our custom module, we need to edit our view and edit the field to use new Raw Formatter as you can see in the following image.

image field raw formatter

After saving the view and run again the output will be different and perfect to use in RESTful services to avoid HTML parsing to extract the image path. Check the output example below.

[
  {
    title: "Image sample # 3",
    field_image: "http://drupal8b3.dev/sites/enzo/files/styles/
  thumbnail/public/field/image/globe.jpg?itok=wmu3VCr6"
  },
  {
    title: "Image sample # 2",
    field_image: "http://drupal8b3.dev/sites/enzo/files/styles/
  thumbnail/public/field/image/sample_08.jpg?itok=X9N005N1"
  },
  {
    title: "Image sample # 1",
    field_image: "http://drupal8b3.dev/sites/enzo/files/styles/
  thumbnail/public/field/image/sample_01.jpg?itok=UD1-QXTj"
  }
]

You can download a full implementation of this custom Image Raw Field Formatter at https://github.com/enzolutions/image_raw_formatter.

I expect you found this blog entry useful.