Jan 06 2020
Jan 06

The templating engine of Drupal 8 has seen a massive turnaround. Unlike Drupal 7, there’s Twig in Drupal 8 instead of PHPTemplate. Twig is basically a templating language for PHP i.e a tool used to output variables inside HTML. Fabien Potencier, the creator of the Symfony framework, gave life to Twig. Contrary to Drupal 7, you cannot call the regular PHP functions in your templates in Drupal 8. he way forward, in Drupal 8, is to create filters and functions.

Icon resembling human wearing blue shirt standing in front of a white board explaining Twig Extension in Symfony and Drupal


Twig extension gives more flexibility to process nearly anything inside the twig. Twig can be extended in many ways such as tags, filters, operators, global variables, and functions.

One of the major plus points of creating a twig extension in Drupal 8 is in the view.

Drupal 8 views can often be more challenging in the case where you want to perform operations on the value or need to process the content in the field. When you need to write code often, try to reuse it rather than writing it from scratch every time.

You must use a filter when you want to transform the data you want to display. Imagine you have a title that you always want to be capitalized. For example, twig has the capitalize filter that allows you to transform any text into its equivalent in uppercase.

I came across Twig Extension during one of my E-commerce projects where I had to print dynamic currency name. Drupal Commerce allows only 3 characters long currency code and they have also implemented their own Twig Extension to convert Price object into equivalent price format. So to handle this case where I have to show currency name with more number of characters, I had implemented my own Twig Extension. Similarly, there are several other cases where these Twig Extension can be very handful.

Let’s see an example where we will create a filter that will allow us to count the number of words in the article. The process of creating filters and functions is exactly the same as normal Twig. Also, you can use word count to display the reading time of the article or any other use case as per the requirement.

The main difference between regular Twig and Drupal 8 Twig is that, in Drupal 8, you must create a service definition of the class you are creating and the class must also belong to a namespace, otherwise it will not be registered as a Twig filter in the Drupal environment.

This example assumes you have a module called:

twig_word_count_extension


This will be the basic definition of the inn service.

twig_word_count_extension.services.yml
services:
  twig_word_count_extension.twig_extension:
    class: Drupal\twig_word_count_extension\TwigExtension\TwigWordCountExtension
    tags:
      - { name: twig.extension }


The key tags are also absolutely necessary and that is what Drupal tells you what this class is supposed to do (that is, register it as an extension of Twig).

And now the source code that should be placed in the path defined in the class service definition key.

<?php

namespace Drupal\twig_word_count_extension\TwigExtension;

use Twig_Extension;
use Twig_SimpleFilter;

class TwigWordCountExtension extends \Twig_Extension  {
  /**
   * This is the same name we used on the services.yml file
   */
  public function getName() {
    return 'twig_word_count_extension.twig_extension';
  }

  // Basic definition of the filter. You can have multiple filters of course.
  public function getFilters() {
    return [
      new Twig_SimpleFilter('word_count', [$this, 'wordCountFilter']),
    ];
  }
  // The actual implementation of the filter.
  public function wordCountFilter($context) {
    if(is_string($context)) {
      $context = str_word_count($context);
    }
    return $context;
  }
}


Clear your caches and now, if everything goes according to plan, you can use the filter in your templates.

{{ "shuffle me!" | word_count }} {# Return 2. #}


Note: If these twig extensions don’t have other service dependencies (i.e. if you don't inject services in them), the performance is not affected. However, if these extensions have lots of complex dependencies, for example, say those making database connections or perform heavy operations, the performance loss can be significant.

To avail help from our experts for your Drupal projects, you can check out our suite of services. You can also talk to us at [email protected].

Dec 16 2018
Dec 16

As the world gets more connected, web technologies too, need to get connected. RESTful web services can be used as an application program interface to connect various service.

This can be made possible by using HTTP requests to GET, PUT, POST and DELETE data. It is based on representational state transfer (REST) technology, an architectural style, and approach to communications often used in web services development. 

With decoupled development getting the ground, it has become important for the developers to understand teh REST technology better. Drupal provides its developers an in-house build method to use this REST technology. RESTful Web Services module, which is now a part of Drupal core, provides REST services to its developers. 

It allows users to read or update data on the site. 

Different verbs or request methods that are used for the approach are:

GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT and PATCH

The GET method allows the user to access various entities like Node, User, Taxonomy, Comments and even watchdog database log entries. GET method is a SAFE method as there is no database manipulation operation, it is a read-only request.

Unlike GET, in the POST method, database manipulation takes place. The user can update the database and create a node if need be. 

Creating REST Resource Plugins

REST resource plugins are important to expose additional resources over REST. In the steps below we will create a basic example for understanding the fundamental functionality of developing REST resource endpoint which takes a content type as argument and returns title and node ids of all nodes of that particular content-type.

  • Create the staging code for REST resource with the following Drupal console command:
drupal generate:plugin:rest:resource

You can also generate the staging code manually by creating a plugin file under src in the custom module > Plugin > Rest > Resource > {ResourceClassName}.php

Next, define the namespace, dependencies, and the plugin class as given in the example below.

  • Next, you need to create the @RestResource annotation. It helps you indicate the dependencies, and status of the class. Another important point to consider is that the URL mapping is case-sensitive.

    We must also be careful with the  @RestResource  annotation's urli_paths  which take link relation types as keys, and partial URIs as values. If you don't specify any, Drupal will automatically generate URI paths (and hence URLs) based on the plugin ID. 

    If your plugin ID is rest_example, you'll end up with/rest_example/{id}  for GET|PATCH|DELETE and /rest_example for POST . But, often, you'll want to specify your own paths: a canonical URI path (for example /todo/{todo_id}). For example:

* uri_paths = {
 *     "canonical" = "/rest_example/{id}",
 *   }

Here’s how to get the complete REST resource GET request

<?php

namespace Drupal\rest_example\Plugin\rest\resource;

use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * Provides a resource to get view modes by entity and bundle.
 *
 * @RestResource(
 *   id = "rest_example",
 *   label = @Translation("Rest example"),
 *   uri_paths = {
 *     "canonical" = "/rest/api/get/node/{type}"
 *   }
 * )
 */
class RestExample extends ResourceBase {

  /**
   * Responds to GET requests.
   *
   * @return \Drupal\rest\ResourceResponse
   *   The HTTP response object.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   *   Throws exception expected.
   */
  public function get($type = NULL) {

    // You must to implement the logic of your REST Resource here.
    // Use current user after pass authentication to validate access.
    if (!(\Drupal::currentUser)->hasPermission('access content')) {
       throw new AccessDeniedHttpException();
     }
    if($type) {
      $nids = \Drupal::entityQuery('node')->condition('type',$type)->execute();
      if($nids){
        $nodes =  \Drupal\node\Entity\Node::loadMultiple($nids);
        foreach ($nodes as $key => $value) {
          $data[] = ['id' => $value->id(),'title' => $value->getTitle()];
        }
      }
    }
    $response = new ResourceResponse($data);
    // In order to generate fresh result every time (without clearing 
    // the cache), you need to invalidate the cache.
    $response->addCacheableDependency($data);
    return $response;
  }

}

Output 

[
  {
    "id": "67",
    "title": "Consectetuer Sits"
  },
  {
    "id": "69",
    "title": "Eum Paulatim"
  },
  {
    "id": "70",
    "title": "Tation"
  }
]


Configuring the REST Resources

In the config file, we define which HTTP method, serialization format, and an authentication mechanism is supported by the plugin. 

This config file is necessary to use the REST resource plugin. There are two ways to configure the REST resource @RestResource plugin:

  1. REST UI Module
     
    • The REST UI module is not part of the core. So you have to download it and install it like any other module in your Drupal site.admin interface of rest UI
    • Once installed, go to  /admin/config/services/rest and enable your REST Resource.enabling the rest module
    • Select your desired settings. To have hal_json format, you can enable Drupal Core’s HAL module.admin interface to restrict HTTP
  2. Manually
    • Go to the config directory and create a config file with name as rest.resource.{resource id}.yml.
    • Add the following content.
langcode: en
status: true
dependencies:
  module:
    - rest_example
    - serialization
    - user
id: rest_example
plugin_id: rest_example
granularity: resource
configuration:
  methods:
    - GET
  formats:
    - json
  authentication:
    - cookie
  • Save this file as rest.resource.plugin_id.yml (rest.resource.rest_example.yml in this case) in your config directory and run config sync.

Defining your resource config:

Status: true/false ( enable or disable)
Id: unique id
Plugin_id: unique id
configuration=>methods: Name all request method you want to use in this plugin
configuration=>formats: Define all supported serialized format
configuration=>authentication: Name all supported authentication method.
By default, the REST module supports json and xml

Key Point: Each REST resource must be annotated with  @RestResource  annotation so they can be discovered by RESTful Web Services module.

Custom REST API is useful in sending data to third-party applications and for headless architecture. As of today, there is hardly any project or application that doesn't have a REST API. Connect with us at [email protected] to help you create

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web