Eduardo Garcia bio photo

enzo

Eduardo Garcia

Knowmad by definition

Location: Costa Rica

Twitter Facebook  QQ交谈 Google+ Github LinkedIn Feed

One of the biggest 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 enable modules Views, Views UI and RESTful Web Services

The problem I found with image is the formatter for image 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.

Even if you don't set the option to link to 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/default/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/default/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/default/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 import this view in your system just 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.

If you want 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 own 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 require 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 code we must to 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 follow 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 intruction 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 an 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 allow user 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 require use any image style or if is only required the original image, in both sceneries the proper path url is return.

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

Module usage

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

After save the view and run again the output will be totally 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/default/files/styles/thumbnail/public/field/image/globe.jpg?itok=wmu3VCr6"
  },
  {
    title: "Image sample # 2",
    field_image: "http://drupal8b3.dev/sites/default/files/styles/thumbnail/public/field/image/sample_08.jpg?itok=X9N005N1"
  },
  {
    title: "Image sample # 1",
    field_image: "http://drupal8b3.dev/sites/default/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.


Comments

comments powered by Disqus