Drupal, a powerful and flexible content management system (CMS), employs several design patterns to maintain robust and scalable code. Understanding these design patterns can help you develop and extend Drupal more effectively.
The Hook System in Drupal allows modules to alter or add to the behavior of core or other modules without modifying their code.
// Example: Implementing hook_menu() in a custom module.
function mymodule_menu() {
$items = array();
$items['custom-page'] = array(
'title' => 'Custom Page',
'page callback' => 'mymodule_custom_page',
'access callback' => TRUE,
);
return $items;
}
function mymodule_custom_page() {
return 'This is a custom page.';
}
Drupal uses Dependency Injection to manage dependencies, improving code testability and flexibility.
// Example: Injecting a service into a class.
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
class MyService {
protected $logger;
public function __construct(LoggerChannelFactoryInterface $logger_factory) {
$this->logger = $logger_factory->get('my_service');
}
public function logMessage($message) {
$this->logger->info($message);
}
}
The Plugin System in Drupal provides a way to swap out functionality based on certain criteria.
// Example: Defining a custom block plugin.
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides a 'Custom' Block.
*
* @Block(
* id = "custom_block",
* admin_label = @Translation("Custom Block"),
* )
*/
class CustomBlock extends BlockBase {
public function build() {
return [
'#markup' => $this->t('This is a custom block.'),
];
}
}
The Entity API in Drupal follows the Active Record pattern, where entities represent rows in a database table and have methods to manage their own persistence.
// Example: Loading and saving a node entity.
$node = \Drupal\node\Entity\Node::load(1);
$node->setTitle('Updated Title');
$node->save();
Drupal uses the Factory pattern to create instances of classes, particularly in the service container.
// Example: Using a factory to create a service instance.
$service = \Drupal::service('mymodule.my_service');
$service->doSomething();
Some components in Drupal use the Singleton pattern to ensure a single instance is used throughout the application.
// Example: Accessing the database service using the Singleton pattern.
$database = \Drupal::database();
$database->select('node', 'n');
The Iterator pattern is used to traverse collections of items, such as entities or configuration objects.
// Example: Iterating over nodes with EntityFieldQuery.
$query = new \Drupal\EntityFieldQuery();
$query->entityCondition('entity_type', 'node');
$result = $query->execute();
foreach ($result['node'] as $nid => $node) {
$node = \Drupal\node\Entity\Node::load($nid);
// Process node.
}
The Decorator pattern is used in Drupal to extend or alter the behavior of services without modifying their core logic.
// Example: Decorating a service.
services:
mymodule.my_service:
class: Drupal\mymodule\MyServiceDecorator
decorates: my_service
arguments: ['@mymodule.my_service.inner']
The Adapter pattern is used to integrate different interfaces, allowing incompatible interfaces to work together.
// Example: Adapting an external library to Drupal's logger interface.
class ExternalLibraryLoggerAdapter implements LoggerInterface {
protected $externalLogger;
public function __construct(ExternalLogger $externalLogger) {
$this->externalLogger = $externalLogger;
}
public function log($level, $message, array $context = []) {
$this->externalLogger->logMessage($level, $message);
}
}
The Proxy pattern is used to control access to objects, often to lazy-load them or add additional behavior.
// Example: Lazy-loading a service.
class MyServiceProxy {
protected $realService;
public function __construct() {
// Real service is not instantiated until needed.
$this->realService = NULL;
}
public function doSomething() {
if ($this->realService === NULL) {
$this->realService = new RealService();
}
return $this->realService->doSomething();
}
}
Published By: Krishanu Jadiya
Updated at: 2024-07-31 15:29:36