Skip to content

Object-Oriented Programming (OOP)

Goal: Demonstrate ability to write code using core and object-oriented PHP.

You need a basic understanding of OOP concepts prior to attempting the certification exam. There are many tutorials available to learn those. This documentation covers some of the essential Drupal-related topics that fall under the scope of the Drupal certification exam.

OOP File Structure

All classes, interfaces and traits should live in their own files, where the name of the file matches the name of the class. Additionally, the files should be located at src/{objecttype}/{classname}.php

For example:

php
<?php
class HelloController extends ControllerBase {
  // ...
}

This class should be located at src/Controller/HelloController.php inside your module.

Factory Pattern

The Factory Pattern is a common OOP design pattern that creates an object of the class you want to use. By using factories instead of directly instantiating objects, you can reduce complexity around the actual creation of objects, especially when multiple steps are required.

Example Factory

Consider this example from PHP The Right Way - Design Patterns:

php
<?php
class Automobile
{
    private $vehicleMake;
    private $vehicleModel;

    public function __construct($make, $model)
    {
        $this->vehicleMake = $make;
        $this->vehicleModel = $model;
    }

    public function getMakeAndModel()
    {
        return $this->vehicleMake . ' ' . $this->vehicleModel;
    }
}
php
<?php
class AutomobileFactory
{
    public static function create($make, $model)
    {
        return new Automobile($make, $model);
    }
}
php
<?php
// have the factory create the Automobile object
$veyron = AutomobileFactory::create('Bugatti', 'Veyron');

print_r($veyron->getMakeAndModel()); // outputs "Bugatti Veyron"

The AutomobileFactory class will create a new automobile object for you as needed.

Drupal Config Factory

Drupal makes use of factories in several places. One such example is \Drupal::configFactory() in Drupal.php:

php
<?php
public static function configFactory() {
  return static::getContainer()->get('config.factory');
}

Then you can just use \Drupal::configFactory() to retrieve a new config object.

For example, have a look at system_update_8200():

php
<?php
function system_update_8200(&$sandbox) {
  $config_factory = \Drupal::configFactory();
  if (!array_key_exists('config_names', $sandbox)) {
    $sandbox['config_names'] = $config_factory->listAll();
    $sandbox['max'] = count($sandbox['config_names']);
  }

  // Get a list of 50 to work on at a time.
  $config_names_to_process = array_slice($sandbox['config_names'], 0, 50);
  // Preload in a single query.
  $config_factory->loadMultiple($config_names_to_process);
  foreach ($config_names_to_process as $config_name) {
    $config_factory->getEditable($config_name)->save();
  }

  // Update the list of names to process.
  $sandbox['config_names'] = array_diff($sandbox['config_names'], $config_names_to_process);
  $sandbox['#finished'] = empty($sandbox['config_names']) ? 1 : ($sandbox['max'] - count($sandbox['config_names'])) / $sandbox['max'];
}

Other Drupal Factories

To research into specific instances, check out the Drupal core factories in web/core/lib.Drupal/Component and web/core/lib/Drupal/Core for many examples of factories in use. e.g. web/core/lib/Drupal/Component/FileCache/FileCacheFactory.php, web/core/lib/Drupal/Core/Cache/CacheFactory.php and web/core/lib/Drupal/Core/Image/ImageFactory.php.

PHP Namespaces

Drupal projects should be properly namespaced to prevent potential overlap with other modules. This is done through PHP namespacing. The recommended namespace for any given module is namespace Drupal\{modulename}.

For example, the namespace for the block module is:

namespace Drupal\block;

For example, if two modules had a poorly named ModuleController.php that contained a ModuleController class with a description() method, by using namespaces we can distinguish between those two methods:

php
\Drupal\module1\Controller\ModuleController::description()
\Drupal\module2\Controller\ModuleController::description()

As mentioned in Drupal coding standards - updated Oct 2023 you need to include use statements however, you can use class aliasing to distinguish between these two classes:

use \Drupal\module1\Controller\ModuleController as Module1ModuleController;
use \Drupal\module2\Controller\ModuleController as Module2ModuleController;

Module1ModuleController::description();
Module2ModuleController::description();

Namespace Resolution

From PSR-4 namespaces and autoloading in Drupal 8 - updated Dec 2022:

ComponentBase namespaceBase directoryContains
Drupal coreDrupal\Component\core/lib/Drupal/Component/Components that are reusable outside of Drupal.
--Drupal\Core\core/lib/Drupal/Core/Components that are specific to Drupal.
--Drupal\Tests\core/tests/Drupal/Tests/PHPUnit tests of core components.
ModulesDrupal\$modulename\modules/$modulename/src/Main integration files.
--Drupal\$modulename\Tests\modules/$modulename/src/Tests/Simpletest tests of the module.
--Drupal\Tests\$modulename\modules/$modulename/tests/src/PHPUnit tests of the module.

Views and Controllers

Symfony (version 6), the underlying PHP framework Drupal 8 is built upon, is not officially a MVC (Model/View/Controller) framework, but does make heavy use of views and controllers. Drupal is an extension of that. Views are handled almost exclusively through Twig and controllers are managed via the Routing System.

By keeping the controller and views separate, it allows for a better separation of concerns. This helps keep a system flexible moving forward.

Resources

Questions

What is Object-Oriented Programming (OOP) in Drupal, and how does it help developers manage complex functionality in custom modules?

Object-Oriented Programming (OOP) in Drupal is a programming paradigm that organizes code into objects and classes, which allows for more structured, maintainable, and reusable code. OOP in Drupal enables developers to manage complex functionality in custom modules, and By using OOP principles, developers can create modular and reusable code for custom modules, improving maintainability, scalability, and the ability to extend Drupal’s functionality.

What is OOP file structure, factory pattern and Namespaces

All classes, interfaces and traits should live in their own files, where the name of the file matches the name of the class. Additionally, the files should be located at src/{objecttype}/{classname}.php. The Factory Pattern is a common OOP design pattern that creates an object of the class you want to use. By using factories instead of directly instantiating objects, you can reduce complexity around the actual creation of objects, especially when multiple steps are required. A namespace is a way to encapsulate and organize code in OOP to prevent naming conflicts between classes, functions, or constants that may have the same name, Drupal projects should be properly namespaced to prevent potential overlap with other modules. This is done through PHP namespacing. The recommended namespace for any given module is namespace Drupal\{modulename}.