{"id":54924,"date":"2022-04-20T12:59:43","date_gmt":"2022-04-20T07:29:43","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=54924"},"modified":"2022-05-18T13:04:34","modified_gmt":"2022-05-18T07:34:34","slug":"how-to-use-singleton-design-pattern-with-elasticsearch-in-drupal-9","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/how-to-use-singleton-design-pattern-with-elasticsearch-in-drupal-9\/","title":{"rendered":"How to use singleton design pattern with Elasticsearch in Drupal 9"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Singleton design pattern is really useful to use the same object over multiple calls. For third party softwares for examples like Apache Solr, elastic search, Redis, etc. it is not good practice to create the connection object again and again, rather a single object can be used multiple times. In such cases singleton design patterns can be used.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Drupal is flexible enough to integrate with lots of libraries, we are going to pick <\/span><b>elasticsearch connector<\/b><span style=\"font-weight: 400;\"> module integration with Drupal 9 as an example.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We will create a simple class which will connect with the elasticsearch server and will return the elasticsearch client object.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For elasticsearch, <\/span><a href=\"https:\/\/www.drupal.org\/project\/elasticsearch_connector\"><span style=\"font-weight: 400;\">ElasticSearch Connector<\/span><\/a><span style=\"font-weight: 400;\"> module is used.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We will create services for achieving the singleton object of elasticsearch. There are two services which we will use to get the objects, one will be a direct method and other will be an indirect method.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">As per guidelines a custom module should be created. The files which are mentioned below should be created.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">File name: module_name.services.yml<\/span><\/p>\n<p><span style=\"font-weight: 400;\">services<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">elastic_singleton.indirect_object<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">class<\/span><span style=\"font-weight: 400;\">: Drupal\\elastic_singleton\\ElasticInitiate<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">elastic_singleton.direct_object<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">class<\/span><span style=\"font-weight: 400;\">: Drupal\\elastic_singleton\\ElasticSingleton<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">We will create the first service which supplies direct objects as per demand.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">File name: src\/ElasticSingleton.php<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">&lt;?php<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\/**<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0* @file<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0* Contains ElasticSingleton singleton.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">namespace Drupal\\module_name;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">use Elasticsearch\\ClientBuilder;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class ElasticSingleton {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0private static $instance = NULL;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\/**<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0* Checks connectivity with ElasticSearch.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0private static function getClient() {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0try {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$elastic_host = \u2018127.0.0.1\u2019; \/\/ Elasticsearch server.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$client = ClientBuilder::create()<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-&gt;setHosts([$elastic_host])<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0-&gt;build();<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$health = $client-&gt;cluster()-&gt;health();<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (empty($health)) {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return FALSE;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return $client;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0catch (\\Exception $e) {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return FALSE;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\/**ElasticSingleton.phpElasticSingleton.php<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0* Check connectivity getInstance.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0public static function getInstance() {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0if(self::$instance === NULL) {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self::$instance = self::getClient();<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0return self::$instance;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Now we will create a second service which will supply the same object but indirectly or using without static property\/without using scope resolution operator.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">&lt;?php<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\/**<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0* @file<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0* Provides indirect object of elasticsearch.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">namespace<\/span><span style=\"font-weight: 400;\"> Drupal\\elastic_singleton;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">use<\/span><span style=\"font-weight: 400;\"> Drupal\\elastic_singleton\\ElasticSingleton;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class<\/span><span style=\"font-weight: 400;\"> ElasticInitiate {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">\/**<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0* Checks connectivity with ElasticSearch.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">function<\/span><span style=\"font-weight: 400;\"> getInstance() {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">return<\/span><span style=\"font-weight: 400;\"> ElasticSingleton::getInstance();<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">For testing we can create an entry in the routing.yml file.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">File: modulename.routing.yml<\/span><\/p>\n<p><span style=\"font-weight: 400;\">elastic.test_singleton<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">path<\/span><span style=\"font-weight: 400;\">: <\/span><span style=\"font-weight: 400;\">&#8216;\/test\/elastic\/singleton&#8217;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">defaults<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">_controller<\/span><span style=\"font-weight: 400;\">: <\/span><span style=\"font-weight: 400;\">&#8216;\\Drupal\\elastic_singleton\\Controller\\ElasticController::test&#8217;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">requirements<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">_permission<\/span><span style=\"font-weight: 400;\">: <\/span><span style=\"font-weight: 400;\">&#8216;access content&#8217;<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Let&#8217;s create a controller in the src\/Controller folder.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">File Name: ElasticController.php<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;?php<\/span><\/p>\n<p><span style=\"font-weight: 400;\">namespace<\/span><span style=\"font-weight: 400;\"> Drupal\\elastic_singleton\\Controller;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">use<\/span><span style=\"font-weight: 400;\"> Drupal\\Core\\Controller\\ControllerBase;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\/**<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0* An Elasticsearch singleton testing controller.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class<\/span><span style=\"font-weight: 400;\"> ElasticController <\/span><span style=\"font-weight: 400;\">extends<\/span><span style=\"font-weight: 400;\"> ControllerBase {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">\/**<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0* Returns a render-able array for a test page.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0*\/<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">function<\/span><span style=\"font-weight: 400;\"> test() {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0$client = \\Drupal::service(<\/span><span style=\"font-weight: 400;\">&#8216;elastic_singleton.direct_object&#8217;<\/span><span style=\"font-weight: 400;\">)::getInstance();<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0var_dump($client);<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0$client1 = \\Drupal::service(<\/span><span style=\"font-weight: 400;\">&#8216;elastic_singleton.indirect_object&#8217;<\/span><span style=\"font-weight: 400;\">)-&gt;getInstance();<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0var_dump($client);<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">\/\/ exit(); \/\/ Uncomment this line to check both the client objects.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0$build = [<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">&#8216;#markup&#8217;<\/span><span style=\"font-weight: 400;\"> =&gt; <\/span><span style=\"font-weight: 400;\">$this<\/span><span style=\"font-weight: 400;\">-&gt;t(<\/span><span style=\"font-weight: 400;\">&#8216;Elasticsearch Singleton example.&#8217;<\/span><span style=\"font-weight: 400;\">),<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0];<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">return<\/span><span style=\"font-weight: 400;\"> $build;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">We can call the service at desired places and we can notice that the same object is returned multiple times.<\/span><\/p>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>Singleton design pattern is really useful to use the same object over multiple calls. For third party softwares for examples like Apache Solr, elastic search, Redis, etc. it is not good practice to create the connection object again and again, rather a single object can be used multiple times. In such cases singleton design patterns [&hellip;]<\/p>\n","protected":false},"author":1430,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":22},"categories":[3602],"tags":[4964],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/54924"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1430"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=54924"}],"version-history":[{"count":2,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/54924\/revisions"}],"predecessor-version":[{"id":54989,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/54924\/revisions\/54989"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=54924"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=54924"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=54924"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}