Friday, 11 June 2021

Explained Services in Drupal 8

Drupal 8 services are just a object which is managed by the container. The purpose of managing it via a container is to make the object alterable and plugable.  In simple words, Drupal 8 services are those objects which are registered with the service container in order to decouple reusable functionality. Of course services are registered with the service container for any specific purpose.  It could be used for sending an email to customer, or to generate links or to do checkout using any specific payment gateway plugin. In simple words, it can be used to server anywhere in the Drupal 8 code base.

In order to learn Drupal 8 services, we must first get familiar of some one or two most used Drupal services created in its core itself.

  1. config.factory: In Drupal 8 we now use the Configuration system which provides a central place for modules to store configuration data. This services will allow us to store the configurations or retrieve them wherever we need them. This information is generally created during site development and it is not generally effected by regular users.
  2. current_user:  This service is very useful in order to get some basic information about the current user on site. Note, current_user is not giving you user entity, it is just user proxy which will give certain details to you about the current user like if the username is anonymous or not, or its 'id' using method \Drupal::currentUser()->id(). To load the user entity you must load the user entity manually using User class or using user storage.

So, here we got to know the few details of the few services. Now, time to learn to create new service. But let's do it with the example. 

Creating a Drupal 8 service require two steps
         1.  First it has to be defined in the services.yml of module to register with the service container
         2.  Second the PHP object to perform any specific tasks.

Step 1: Let's define our service in services.yml

    class: Drupal\custom_media\PdfImageManager
    arguments: ['@entity_type.manager', '@file_system', '@config.factory']

Now, let's understand the above code snippet quickly. Let's do it for line by line.

services: This line just tells that all the services of current modules are listed

custom_media.pdf_image_manager: This is the id of the newly created service. This id will be used to fetch the service from the service container anywhere.

class: Here we will write the path of the service i.e the object we are going to write.

arguments: This line contains arguments. This is optional, Here we can send the other services as arguments to this service.

Step 2: Now let's go through the next step i.e creating the object.


namespace Drupal\custom_media;
use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\File\FileSystem; use Drupal\Core\State\State; use Drupal\Core\Logger\LoggerChannel; use Drupal\Core\StreamWrapper\StreamWrapperInterface; use Drupal\Core\Url; use \Imagick; /** * Class PdfImageManager. * * @package Drupal\custom_media */ class PdfImageManager { const IMAGE_EXTENSION = 'jpeg'; /** * EntityTypeManager. * * @var \Drupal\Core\Entity\EntityTypeManager */ protected $entityTypeManager; /** * FileSystem. * * @var \Drupal\Core\File\FileSystem */ protected $fileSystem; /** * @var \Drupal\Core\Config\ConfigFactory */ protected $configFactory; /** * MediaPdfThumbnailImagickManager constructor. * * @param \Drupal\Core\Logger\LoggerChannel $loggerChannel */ protected $logger; /** * MediaPdfThumbnailManager constructor. * * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager * EntityTypeManager. * @param \Drupal\Core\File\FileSystem $fileSystem * FileSystem. * @param \Drupal\Core\Config\ConfigFactory $configFactory */ public function __construct(EntityTypeManager $entityTypeManager, FileSystem $fileSystem, ConfigFactory $configFactory) { $this->entityTypeManager = $entityTypeManager; $this->fileSystem = $fileSystem; $this->configFactory = $configFactory; $this->logger = $loggerChannel; } /** * Create pdf thumbnail. * * @param $entity * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * @throws \Drupal\Core\Entity\EntityStorageException */ public function createThumbnail($fileEntity) { if ($fileEntity && $fileEntity->getMimeType() == 'application/pdf') { $file_id = $this->generatePdfImage($fileEntity); return $file_id; } return false; } /** * @param $fileEntity * * @return bool|string */ protected function generatePdfImage($fileEntity) { $fileInfos = $this->getFileInfos($fileEntity); if (!empty($fileInfos['source']) && !empty($fileInfos['filename'])) { return $this->generateImageFromPDF($fileInfos['source'], $fileInfos['filename']); } return NULL; } /** * @param $fileEntity * * @return array */ protected function getFileInfos($fileEntity) { $filename = $fileEntity->filename->value; $fileUri = $fileEntity->getFileUri(); $sourcePath = file_create_url($fileUri); $destinationPath = $sourcePath .'.jpeg'; return ['source' => $sourcePath, 'filename' => $filename]; } /** * Generate image from PDF file. * * @param string $source * File source. * @param string $filename * File filename. * */ public function generateImageFromPDF($source, $filename) { try { $im = new imagick(); $im->readimage($source); $im->setIteratorIndex(0); $im->setImageFormat(self::IMAGE_EXTENSION); $target_filename = $filename . '.' . self::IMAGE_EXTENSION; $file_data = file_put_contents("public://pdf_to_image/$target_filename", $im); $file_data = file_get_contents("public://pdf_to_image/$target_filename"); $file = file_save_data($file_data, "public://pdf_to_image/$target_filename"); return $file->id(); } catch (\Exception $e) { \Drupal::logger('ch_media')->error($e->getMessage()); return FALSE; } return TRUE; } }

Here we have created a service which will take the pdf as file and will generate the screenshot of its first page using Imagick library. So, we now created a service successfully. In order to use it anywhere you must first register it with the service container, So do the cache rebuild and this Drupal 8 service itself will be registered with the service container. 

Now come to the use case where u need to use this service i.e you wanted to get the screenshot of the first page of the pdf. What you have to do is fetch this service from the service container using \Drupal::service("custom_media.pdf_image_manager") and call generatePdfImage($fileEntity) method. Services can also have other properties such as tags which will categorise them into different categories.

This Is The Newest Post