Friday, 15 August 2025

To use entityQuery via the service container in Drupal 10—rather than the global

 We should inject entity type manager service into class rather than Global \Drupal::entityQuery('').

It is recommended approach for better testability and adherence to Drupal’s dependency injection practices.

This is the way how we use entityQuery.

$query = \Drupal::entityQuery('node')

      ->condition('status', 0)

      ->condition('type', 'content_type')

      ->accessCheck(TRUE);

$nids = $query->execute();

Inject entity_type.manager Service

In your class (e.g., a custom block or controller), define a constructor and use the create() method to inject the service:

use Drupal\Core\Entity\EntityTypeManagerInterface;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;

use Symfony\Component\DependencyInjection\ContainerInterface;

class MyCustomBlock extends BlockBase implements ContainerFactoryPluginInterface {

  protected $entityTypeManager;

  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {

    parent::__construct($configuration, $plugin_id, $plugin_definition);

    $this->entityTypeManager = $entity_type_manager;

  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {

    return new static(

      $configuration,

      $plugin_id,

      $plugin_definition,

      $container->get('entity_type.manager')

    );

  }

Use getStorage() and getQuery()

public function build() { 

 $query = $this->entityTypeManager ->getStorage('node') 

 ->getQuery() 

 ->condition('type', 'article') 

 ->condition('status', 1) 

 ->accessCheck(TRUE) ->range(0, 5); 

 $nids = $query->execute(); // Load full node entities 

$nodes = $this->entityTypeManager ->getStorage('node') ->loadMultiple($nids);


\Drupal::entityQuery() : It is quick and easy but - Tightly coupled, harder to test.

Service injection : Decoupled, testable, modern and Slightly more verbose.

Use service container aligns with Drupal’s best practices for maintainable and testable code.






Thursday, 14 August 2025

Why WebP Is Ideal for Drupal 10

For performance enhancement in Drupal 10, WebP is the most recommended image format.

Google reports that WebP images are around 25–34% smaller than JPEGs and 26% smaller than PNGs, having similar visual quality.

FeatureWebPJPEGPNG
Compression        Superior        Moderate            Lossless but heavy
Transparency            Supported        Not supported            Supported
Animation        Supported        Not supported            Not supported
Browser Support        Widely supported        Universal            Universal
Performance Impact         Excellent        Moderate            Heavy


How to Use WebP in Drupal 10

Go to: Configuration → Media → Image Styles(/admin/config/media/image-styles)
Now create/edit image style
Add image style name if its new image style.
Now add effect. Select "convert" then select WebP as format.
Now this image style is ready to use.

We can use contributed module WebP. WebP module creates a WebP copy of image style derivatives to decrease loading times.

Tuesday, 27 August 2024

Drupal 8/9/10 Multisite Setup

 Create Drupal 10 fresh instance with composer command

Below composer command will download latest Drupal version.

composer create-project drupal/recommended-project d10multisite

OR

Below composer command will download Drupal specific version.

composer create-project drupal/recommended-project:10.3.2 d10multisite


Create virtual hosts in xampp

c:\xampp\apache\conf\extra\httpd-vhosts.conf

<VirtualHost *:80>

  ServerName d10multisite.localhost

  ServerAlias www.d10multisite.localhost

  DocumentRoot "C:/xampp/htdocs/d10multisite/web"

  <Directory "C:/xampp/htdocs/d10multisite/web">

    Require all granted

  </Directory>

</VirtualHost>


<VirtualHost *:80>

  ServerName d10multisite-site1.localhost

  ServerAlias www.d10multisite-site1.localhost

  DocumentRoot "C:/xampp/htdocs/d10multisite/web"

  <Directory "C:/xampp/htdocs/d10multisite/web">

    Require all granted

  </Directory>

</VirtualHost>


<VirtualHost *:80>

  ServerName d10multisite-site2.localhost

  ServerAlias www.d10multisite-site2.localhost

  DocumentRoot "C:/xampp/htdocs/d10multisite/web"

  <Directory "C:/xampp/htdocs/d10multisite/web">

    Require all granted

  </Directory>

</VirtualHost>


Add below lines in hosts file

C:\Windows\System32\drivers\etc\hosts

    127.0.0.1 d10multisite.localhost

  127.0.0.1 d10multisite-site1.localhost

  127.0.0.1 d10multisite-site2.localhost


cd sites/

ls

cp example.sites.php sites.php

sites.php :- is a file where we are going to configure how many sites are there and mapped to which domain and mapped to which folder.

edit sites.php

go to the bottom of the file

  $sites["d10multisite.localhost"] = 'default';

  $sites["d10multisite-site1.localhost"] = 'site1';

  $sites["d10multisite-site2.localhost"] = 'site2';

every site is having different settings.php

cd default

    cp example.settings.php settings.php

cd site1

    cp default/default.settings.php site1/settings.php

cd site2

    cp default/default.settings.php site2/settings.php

every site is having different services.yml

// default

    cp default/default.services.yml default/services.yml

// site1

    cp default/default.services.yml site1/services.yml

// site2

    cp default/default.services.yml site2/services.yml

Restart xampp server

check in browser with below urls

    d10multisite.localhost

    d10multisite-site1.localhost

    d10multisite-site2.localhost

Now install Drupal instances with standard profile installation.

Now I have to install module with composer, then run below command

    composer require drupal/devel

It will download module from Drupal.org

Now I have to enable this module on any specific site, run below drush command

drush en devel --uri="d10multisite.localhost"

Tuesday, 16 July 2024

Upgrade CKEditor 4 to CKEditor 5

Upgrade CKEditor 4 to CKEditor 5 

The old CKEditor module (which integrates with CKEditor 4) has been removed from core in Drupal 10 and is replaced by a new "CKEditor 5" module that integrates with CKEditor 5. The older version still appears as 'CKEditor' when displayed, such as on the extension page.


Most Drupal sites use CKEditor 4, and must do one of the following:

  1. Switch to CKEditor 5 (strongly recommended), or
  2. Install the CKEditor 4 contributed module, which will be supported until late 2023. Choose this option only if the site has additional Drupal modules installed that provide additional CKEditor 4 plugins with no CKEditor 5 equivalents yet. (Consult the Upgrade coordination for modules providing CKEditor 4 plugins wiki page for the current status.)
            #How to upgrade from CKEditor 4 to CKEditor 5

                1. Upgrade to Drupal 9.4.4 or higher

2. Update modules providing additional CKEditor 4 plugins to the latest release of the major version you're on. Modules that have added CKEditor 5 support should provide support for both CKEditor 4 and 5, and provide an automated upgrade path (for toolbar items and plugin settings) from 4 to 5.

3. Enable the CKEditor 5 module (leave "CKEditor" module enabled) 

4. Converting text formats to use CKEditor 5

1. Go to Text Formats ⮕ Editors in the Drupal Configuration user interface and click "Configure" for each text format.

2. Under Text Editor change selection to "CKEditor 5" and click "Save configuration"

3. Text formats must be updated one at a time. This will automatically migrate your text format configuration to CKEditor 5.

4. Disable (old) "CKEditor" module.

5. Note: This will change your configuration so make sure your export it.

A contributed CKEditor 4 module is available. However, CKEditor 4 is reaching its end-of-life at the end of 2023. The contributed module will receive coordinated security releases alongside Drupal 9 core, and no other maintenance or bug fixes. Once Drupal 9 is end-of-life, core maintainers will no longer provide security coverage for the module.


Therefore, sites should only use the CKEditor 4 module if they use contributed modules extending CKEditor that have not yet been updated to work with CKEditor 5.

Wednesday, 28 June 2023

Modify a field config and storage with existing data in Drupal

 As a developer, we have faced such situations where we have to change the type of field in content type. If that field is already having data against the field then this is not possible through Drupal interface. And we cannot delete and create that field again as there will be data loss.

To meet this requirement, the proper way is to write hook_update

In my one of account, I faced such scenario where anyhow initially field was created as type "List(Text)" then we have to change it to "Boolean". We have already created a lot of contents on Production site. We don't want to update the all contents again after recreating this field. So I followed the hook_update to change that field config and storage with existing data.

I have created a custom module named mymodule and write down .install file to add hook_update. Code is as per below.


<?php

/**
 * @file
 * Update function to change field with existing data.
 */

use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;

/**
 * Recreate field_content_access storage so that "drush cim" can run.
 */
function connect_access_update_9001() {
  $fields = [
    'field_content_access' => [
      'table' => 'node__field_content_access',
      'revision_table' => 'node_revision__field_content_access',
    ],
  ];

  $database = \Drupal::database();

  foreach ($fields as $field_name => $f) {
    // Table name from $fields array.
    $table = $f['table'];
    // Revision table from $field array.
    $revision_table = $f['revision_table'];
    // Entity type like node.
    $entity_type = 'node';

    // Step 1.
// Get field storage.
    $field_storage = FieldStorageConfig::loadByName($entity_type, $field_name);

    // Then check if field is not found.
    if (is_null($field_storage)) {
      continue;
    }

    // Step 2.
// Store existing data in $rows and $revision_rows variables.
    $rows = NULL;
    $revision_rows = NULL;
    if ($database->schema()->tableExists($table)) {
      // The table data will be restored from $rows and $revision_rows variable
// after the update is completed.
      $rows = $database->select($table, 'n')->fields('n')->execute()
        ->fetchAll();
      $revision_rows = $database->select($revision_table, 'n')->fields('n')->execute()
        ->fetchAll();
    }

    // Step 3.
// Save new field configs in new variable and delete existing fields.
    $new_fields = [];
    // Traverse every field to assign those values to new field.
    foreach ($field_storage->getBundles() as $bundle => $label) {
      $field = FieldConfig::loadByName($entity_type, $bundle, $field_name);
      $new_field = $field->toArray();
      $new_field['field_type'] = 'boolean';
      $new_fields[] = $new_field;
      // Delete existing field.
      $field->delete();
    }

    // Step 4.
// Create new storage configs from existing configs.
    $new_field_storage = $field_storage->toArray();
    $new_field_storage['type'] = 'boolean';
    $new_field_storage['module'] = 'core';
    $new_field_storage['settings'] = [];

    // Step 5.
// Purge deleted fields data.
// Required to create new fields.
    field_purge_batch(200);

    // Step 6.
// Create new fieldstorage.
    FieldStorageConfig::create($new_field_storage)->save();

    // Step 7.
// Now create new fields for all bundles.
    foreach ($new_fields as $new_field) {
      $new_field = FieldConfig::create($new_field);
      $new_field->save();
    }

    // Step 8.
// Restore existing data in created fields & revision tables.
    if (!is_null($rows)) {
      foreach ($rows as $row) {
        $row = (array) $row;
        $database->insert($table)->fields($row)->execute();
      }
    }
    if (!is_null($revision_rows)) {
      foreach ($revision_rows as $row) {
        $row = (array) $row;
        $database->insert($revision_table)->fields($row)->execute();
      }
    }
  }
}

Follow below steps. 1. Machine name of the field must be same to new field. 2. On `admin/reports/fields` and search field to be changed. List down all the content types using this field. 3. Check table in the DB related with this field and check revision tables also. List down all the records here. Check with below queries either run by drush or from phpmyadmin. drush sql:query "SELECT * FROM node__field_content_access;" drush sql:query "SELECT * FROM node_revision__field_content_access;" 4. Add the above code in mymodule.install. 5. Replace the $entityType and $fieldName variables according to the entity and field have to change. 6. Take DB backup. 7. Run update either by drush updb or by /update.php on your browser. 8. Check if the update was successfully performed. 9. Check field in all content type. 10. Check data in existing content type.

Tuesday, 22 November 2022

Install Drush Globally

 To install Drush globally follow below steps.

1. Run below command, To install Drush 8.x required for Drupal 8+.

    composer global require drush/drush:dev-master

2. Now run below command to add Drush to your system path.

         export PATH="$HOME/.composer/vendor/bin:$PATH"

3. Run below command to update to a newer version.

         composer global update

To install specific version of Drush, run below command.

        composer global require drush/drush:6.1.0

Some of the below common used Drush commands.

drush cc or cache:clear => To clear cache. When we run this command, will give some options to execute as below

          [0] Cancel

    [1] drush

    [2] theme-registry

    [3] router

    [4] css-js

    [5] render

    [6] plugin

    [7] bin

    [8] views

drush cr or cache:rebuild => Rebuild a Drupal 8 site.
drush updb or updatedb => Apply any database updates required (as with running update.php)
drush updbst or updatedb:status => List any pending database updates.
drush uli or user:login => Display a one time login link for user ID 1, or another user.
drush pml => To list modules
drush en module_name => To enable module
drush pmu => To uninstall module
drush site:install => To install Drupal site with Drush command.
drush sqlc or sql:cli => Open a SQL command-line interface using Drupal's credentials.
drush sql:dump => Exports the Drupal DB as SQL using mysqldump or equivalent.
drush sqlq or sql:query => Execute a query against a database.


Create Drupal 9 Project with Composer

 For Drupal 9, We should use "drupal/recommended-project" composer template. This will ensure that Drupal core dependencies are same as the official Drupal release.

Composer command is as below to create Drupal 9 project

composer create-project drupal/recommended-project first_drupal9_site

This command will create a project in "first_drupal9_site" and automatically will execute composer install to download latest stable version of Drupal and all its dependencies.

Now first_drupal9_site directory will have files as below.

1. composer.json (file)

2. composer.lock (file)

3. vendor (Directory)

4. web (Directory)

The web root will be "web" directory. Except "web" directory, all other files "composer.json, composer.lock, vendor" will not accessible to the web server. 


To install Drupal 9 site, now access your localhost and access web directory. Follow the steps as per installation asks. Once these steps will finish, your first Drupal 9 site will ready.


To install specific version, run below composer command.

composer create-project drupal/recommended-project:9.4.8 first_drupal9_site


To do modified installation

Before composer install execution, if I need to modify some of the properties of the downloaded composer.json then we have to use --no-install flag while running composer create-project

Example, if I want to rename the subdirectory "web" to something else. Follow below steps

  • Run command composer create-project --no-install drupal/recommended-project first_drupal_site 
  • Change directories to first_drupal_site and edit the composer.json file to suit your needs.

    For example, to change the sub-directory from 'web' to something else, the keys to modify are the 'extra' sub-keys 'web-root' (under 'drupal-scaffold') and 'installer-paths'.

  • Run composer install to download Drupal and all its dependencies. 
To download contributed module and contributed theme with composer follow below steps.
  • Run composer require drupal/module_name. eg. composer require drupal/token
  • This needs to be executed at the root of your Drupal install but not at the same level as the core directory.
Composer will then automatically update your composer.json, adding the module to all the other requirements in the list, like this:

{
    "require": {
        "drupal/token": "^1.5"
    }
}
Composer will download the module and all the possible dependencies it may have.

Specifying a version
You can specify the version of the module / theme you want to download as follows:

composer require 'drupal/module_name:version'
(...where version is replaced with a Composer version or version constraint.)

For example:
composer require 'drupal/token:^1.5' 
composer require 'drupal/simple_fb_connect:~3.0' 
composer require 'drupal/ctools:3.0.0-alpha26' 
composer require 'drupal/token:1.x-dev' 

To avoid problems on different terminals/shells, surround the version in quotes as in the examples above.

Note!: On Windows, single quotes actually might break the version specification and lead to failure to install with 'Could not parse version constraint .....': Invalid version string "....'".

Without the quotes, e.g.:
composer require drupal/ctools:^3.7 or with double quotes instead of single quotes, e.g.:
composer require "drupal/ctools:^3.7" works well.

Reference link Drupal.org

Monday, 21 November 2022

Enable PHP OPCache in Xampp

To install Drupal 8 and upper version, PHP OPCache extension is required. Untill we will not enable this, Drupal 8+ versions can not be installed.

To enable this extension, Please follow below steps.

1. Open php.ini file which is configuration file for PHP.

2. Search for "Dynamic Extensions" keyword.

3. Under this heading, Either search for ";zend_extension=opcache" and uncomment this line by removing ";" or add new line by adding below code

   zend_extension="C:\xampp\php\ext\php_opcache.dll"

4. Make sure the "zend_extension" should have the exact path to the opcache.dll file.

5. opcache.dll file exists in xampp > php > ext directory.

6. Save the php.ini file.

7. Restart the apache service.

8. Now try to install Drupal 8+, issue of PHP OPCache fixed.


To get good performance, following settings for PHP OPCache are recommended.

opcache.memory_consumption=128

opcache.interned_strings_buffer=8

opcache.max_accelerated_files=4000

opcache.revalidate_freq=60

opcache.fast_shutdown=1

opcache.enable_cli=1


Sunday, 3 May 2020

Services injection in custom Controller

In custom controller, if it is extending ControllerBase class then no need to inject (with service container) some of the services explained in this post. ControllerBase already having some of the services which we can directly access in the custom controller without injecting it.

Below example will show how to use those services.

Custom Controller Class code

<?php

namespace Drupal\custom_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;

/**
 * Class ControllerServicesInjectionController.
 *
 * @package Drupal\custom_module\Controller
 */
class ControllerServicesInjectionController extends ControllerBase {

  // Below trait is used to make translatable string in controller class.
  use StringTranslationTrait;

  /**
   * Function having information about services which need not to inject.
   */
  public function useServicesWithoutInjecting() {

// Get current user object without injecting user service.
// Returns the current user.
       $user_object = $this->currentUser();

// Get entityTypeManager service without injecting entityTypeManager service.
// Retrieves the entity type manager.
$entity_type_manager = $this->entityTypeManager();

// Get moduleHandler service without injecting moduleHandler service.
// Returns the module handler.
$module_handler = $this->moduleHandler();

// Get languageManager service without injecting languageManager service.
// Returns the language manager service.
$language_manager = $this->languageManager();

// Get entityFormBuilder service without injecting entityFormBuilder service.
// Retrieves the entity form builder.
$entity_form_builder = $this->entityFormBuilder();

// Get formBuilder service without injecting formBuilder service.
// Returns the form builder service.
$form_builder = $this->formBuilder();

// Get state service without injecting state service.
// Returns the state storage service.
$state_object = $this->state();

// Get keyValue service without injecting keyValue service.
// Returns a key/value storage collection.
$keyvalue_object = $this->keyValue('config_key');

        // Translate string in controller class with StringTranslationTrait.
$this->t('This is translatable string.');

        // To only check the above services output.
        print_r($user_object);
        print_r($entity_type_manager);
        print_r($module_handler);
        print_r($language_manager);
        print_r($entity_form_builder);
        print_r($form_builder);
        print_r($state_object);
        print_r($keyvalue_object);
  }
}

Sunday, 26 April 2020

Import Field Configurations Programmatically in Drupal 8

Import Field Configurations Programmatically in Drupal 8


In one of my project, feature module was used to move configurations from one environment to another environment.
With the help of feature module it is easy to move configurations and sync of configurations is easy but when we are moving these configs to production environment we are not having access of it to revert feature changes.

So I decided to write hook_update_n in install file of the module to import configurations of any field. With the help of below code, configurations can be imported to create field.


Create a custom module having below directory structure or place config file in already created custom module in config/install directory and create a modulename.install file

config_import
  config_import.info.yml
  config_import.module
  config_import.install
  config
    install
       // Place all config files here as below
       field.storage.node.field_second_field.yml
       field.field.node.home_stage.field_second_field.yml
       core.entity_form_display.node.home_stage.default.yml
       core.entity_view_display.node.home_stage.default.yml

Code which should available in config_import.install file as below
<?


<?php

/**
 * @file
 * Add search placeholder field.
 */

use Drupal\Core\Config\FileStorage;

/**
 * Add configurations to configs.
 */
function import_config_update_8002() {
  // Get config storage.
  $config_storage = \Drupal::service('config.storage');

  $module = 'import_config';
  // Get config files path.
  $config_path = drupal_get_path('module', 'import_config') . '/config/install';
  // Get file storage for config files.
  $source = new FileStorage($config_path);

  // Create field storage for second field.
  try {
    \Drupal::entityTypeManager()->getStorage('field_storage_config')
      ->create($source->read('field.storage.node.field_second_field'))
      ->save();
  } catch (\Exception $e) {
    Drupal::logger($module)
      ->error('Storage for field field_second_field could not be created. ' . $e->getMessage());
  }

  try {
    // Create field
    \Drupal::entityTypeManager()->getStorage('field_config')
      ->create($source->read('field.field.node.home_stage.field_second_field'))
      ->save();
  } catch (\Exception $e) {
    Drupal::logger($module)
      ->error('Field field_second_field for entity home_stage could not be created. ' . $e->getMessage());
  }

  // Add termscondition field in recipe configurations config pages.
  $config_storage->write('core.entity_form_display.node.home_stage.default', $source->read('core.entity_form_display.node.home_stage.default'));
  $config_storage->write('core.entity_view_display.node.home_stage.default', $source->read('core.entity_view_display.node.home_stage.default'));


}

With above code when you will run drush updb then field "field_second_field" will be created.

For reference :

Saturday, 13 April 2019

Alter Path/Route in Drupal 8

In Drupal 7, path can be altered with the help of hook "hook_menu_alter()" but in Drupal 8 hook_menu is no longer exists so to alter the path in Drupal 8, we have to write a route subscriber.

To change the route behaviour, we need to use a service called RouteSubscriber.

  1. We need to tell Drupal that we have this service,
  2. Need to create the right class
Alter the path user/login, user/password handled by user module and remove /search handled by the Search module.
Create a custom module with custom service an RouteSubscriber.

Custom module: route_alter
create a route_alter.services.yml with custom service.

route_alter.info.yml
name: Alter Route
description: 'Alter custom or contributed Route'
type: module
core: 8.x

package: custom

route_alter.services.yml
services:
  route_alter.route_subscriber:
    class: Drupal\route_alter\Routing\AlterCustomRouteSubscriber
    tags:
      - { name: event_subscriber }

To implement RouteSubscriber, create file AlterCustomRouteSubscriber.php in directory src > Routing create class AlterCustomRouteSubscriber within this file.
Copy and paste below code in the above mentioned file.

<?php

/**
 * @file
 * Contains \Drupal\route_alter\Routing\AlterCustomRouteSubscriber.

 */

namespace Drupal\route_alter\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class AlterCustomRouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
    // Change path '/user/login' to '/login'.
    if ($route = $collection->get('user.login')) {
      $route->setPath('/login');
    }
    // Always deny access to '/user/logout'.
    // Note that the second parameter of setRequirement() is a string.
    if ($route = $collection->get('user.logout')) {
      $route->setRequirement('_access', 'FALSE');
    }
    // Remove the /search route.
    $collection->remove('search.view');
  }
}

Explanation for above code
\Drupal\route_alter\Routing\RouteSubscriber::alterRoutes method is an event subscriber because it extends RouteSubscriberBase. That's why class AlterCustomRouteSubscriber must be registered as an event subscriber service as in file route_alter.services.yml
  • With the help of alterRoutes method, dynamic routes can also added. 
  • If dynamic routes are standalone, use simpler route_callbacks solution and do not implement this class and event subscriber. 
  • If dynamic routes are dependent on other dynamic routes, then need to implement a class extending from RouteSubscriberBase

Thursday, 11 April 2019

Function Overriding and Function Overloading in PHP

Function Overriding

What is method overriding in PHP?
Two methods with same name and parameter is called overriding. In Function overriding, both parent class and child class having method with same name and arguments. Purpose of method overriding is to change the behaviour of parent class method.

How to implement overriding in PHP?

Example of overriding in PHP:

<?php
  class parent_class {
    public function text() { //text() is a parent class method
      echo "Hello!! everyone I am parent class text method"."</br>";
    }
    public function test() {
      echo "Hello!! I am second method of parent class"."</br>";
    }
  }

  class child extends parent_class {
    public function text() {  // Text() parent class method which is override by child class
      echo "Hello!! Everyone i am child class";
    }
  }

  $obj = new parent_class();
  echo $obj->text(); // display the parent class method

  $obj= new parent_class();
  echo $obj->test();

  $obj= new child();
  echo $obj->text(); // display the child class method

?>
Output: 

Hello!! Everyone I am parent class text method

Hello!! I am second method of parent class

Hello!! everyone i am child class


As from the above example we can see how text() method of parent class is overridden by child class.

Function Overloading

Function overloading allows to create method with same name but different input parameter.
Method overloading means to assign extra work to same method.

How to implement overloading in PHP?

<?php
  class text {
    public function display($parameter1) {
      echo "Hello world!!";
    }
    public function display($parameter1,$parameter2) {
      echo "Hello India!!”;
    }
  }

  $obj = new text;
  echo $obj->display('Hello'); // It will show fatal error

?>

Output: 

Fatal error: Cannot redeclare text::display() 

Above code will give fatal error. With the above code output, overloading with the same name function cannot be possible. With the help of magic function(__call()) overloading is done. __call() function takes function and arguments.

Example, find the area of certain shapes where radius are given then it should return area of circle if height and width are given then it should give area of rectangle and others.

<?php
  class Shape {
    const Pi = 3.142 ;  // constant value
    
    // __call is magic function which accepts  
    // function name and arguments
    function __call($func_name, $argument) {
      // It will match the function name
      if ($func_name == 'area') {
        switch (count($argument)) {
          // If there is no argument 
  // return 0
  // If there is only one argument 
          // area of circle 
  // If there is two arguments 
          // area of rectangle 
          case 0 : return 0 ;
          case 1 : return self::Pi * $argument[0] ; // 3.14 * 5
          case 2 : return $argument[0] * $argument[1]; // 5 * 10
        }
      }
    }
  }
  $circle = new Shape();
  echo "Area of circle:".$circle->area(5)."</br>"; // display the area of circle
  $rect = new Shape();
  echo "Area of rectangle:".$rect->area(5,10); // display area of rectangle
?>

__call() method automatically called behind the scene.

Friday, 5 April 2019

Polymorphism in PHP

Polymorphism

 This means many forms.

According to the Polymorphism, methods in different classes that do similar things should have the same name.

Example: write a classes that represent geometric shapes (such as rectangles, circles and octagons) that are different from each other in the number of sides and in the formula that calculates their area, but they all have in common an area that can be calculated by a method.

The polymorphism principle says that, in this case, all the methods that calculate the area (and it doesn't matter for which shape or class) would have the same name.

Example, Call method that calculates the area calcArea() and put in each class that represents a shape.
Now, whenever we would want to calculate the area for the different shapes, we would call a method with the name of calcArea() without having to know about the area calculation logic for different shape.
The only thing that we would need to know is the name of the method that calculates the area.

Implement the polymorphism principle?
To implement the polymorphism, choose between abstract classes and interfaces.

Choose either abstract classes or interfaces to implement polymorphism.
Example: Create an interface named shape with calcArea() method in it.

interface Shape {
  public function calcArea();
}

Circle class implements the interface Shape by putting the formula of area calculation of circle in method calcArea().

class Circle implements Shape {
  private $radius;
   
  public function __construct($radius) {
    $this -> radius = $radius;
  }
  
  // calcArea calculates the area of circles 
  public function calcArea() {
    return $this -> radius * $this -> radius * pi();
  }
}

The rectangle class also implements the interface Shape but defines the method calcArea() with formula of area calculation for rectangles:

class Rectangle implements Shape {
  private $width;
  private $height;
   
  public function __construct($width, $height) {
    $this -> width = $width;
    $this -> height = $height;
  }
  
  // calcArea calculates the area of rectangles   
  public function calcArea() {
    return $this -> width * $this -> height;
  }
}
Now, create objects from the concrete classes:

$circ = new Circle(3);
$rect = new Rectangle(3,4);

All the above objects calculate area with the calcArea(), whether for rectangle object or circle object.

Use the calcArea() methods to calculate the area of the shapes:

echo $circ -> calcArea();
echo $rect -> calcArea();

Result:
28.274333882308
12