PHP

Drupal

What is Drupal

Drupal is a free and open-source content management system (CMS) written in PHP and distributed under the GNU General Public License. It is used as a back-end system for at least 2.3% of all websites worldwide ranging from personal blogs to corporate, political, and government sites including whitehouse.gov and data.gov.uk.

Drupal

Installation

Composer

> composer create-project drupal/recommended-project drupal

With a specific version

$ composer create-project drupal/recommended-project:9.3.12 my_site_name

Settings

Redis

Install drupal/redis

$ composer require drupal/redis

Edit sites/default/settings.php

/**
 * Redis configuration.
 */
$settings['cache']['default'] = 'cache.backend.redis';
$settings['redis.connection']['interface'] = 'PhpRedis'; // or 'Predis'.
$settings['redis.connection']['host'] = '127.0.0.1';
$settings['redis.connection']['port'] = '6379';
$settings['redis.connection']['base'] = 0;
$settings['container_yamls'][] = 'modules/contrib/redis/example.services.yml';
$settings['container_yamls'][] = 'modules/contrib/redis/redis.services.yml';
$settings['cache_prefix'] = 'tonylabs';

// Bypass the cache bootstrap for anonymous users (optional).
$settings['cache']['bins']['bootstrap'] = 'cache.backend.chainedfast';
$settings['cache']['bins']['discovery'] = 'cache.backend.chainedfast';

// Use Redis for specific cache bins if needed.
$settings['cache']['bins']['render'] = 'cache.backend.redis';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.redis';

// Use Redis for Session Storage
$settings['redis.session']['client'] = 'PhpRedis'; // Or 'Predis'.
$settings['redis.session']['host'] = '127.0.0.1';
$settings['redis.session']['port'] = 6379;
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379');

// Disable Drupal’s Default Internal Page Cache
$settings['cache']['bins']['page'] = 'cache.backend.redis';

PhpRedis 和 Predis 的区别

语言与实现

  • PhpRedis:
    • 它是用 C 语言编写的 PHP 扩展
    • 作为一个本地扩展,它直接与 Redis 进行低级别的交互,因此性能更快、效率更高
  • Predis:
    • 它是用 PHP 编写的 PHP 库
    • 因为是纯 PHP 实现,安装更简单(通过 Composer 即可),但性能不如 PhpRedis,因为它是在较高级别的 PHP 中运行。

性能

  • PhpRedis:
    • 通常比 Predis 更快,因为它是编译的 PHP 扩展,能够直接在系统级别运行
    • 适合高性能应用或大型系统
  • Predis:
    • 由于是用 PHP 实现的,通常比 PhpRedis 慢。但对于不需要极高性能的应用,仍然适用

安装

  • PhpRedis:
    • 作为本地 PHP 扩展,必须通过包管理器(如 apt、yum 或 brew)安装,或者手动编译
    • 需要服务器级别的访问权限,因此在共享主机环境中可能无法使用
  • Predis:
    • 只需要通过 Composer 安装,使用非常方便,不需要服务器级权限或额外的系统库

兼容性

  • PhpRedis:
    • 作为 C 扩展,在不同平台上的安装会有一些限制,比如 Windows、macOS 和 Linux 的安装步骤可能不同
    • 由 Redis 官方维护,确保与 Redis 的功能和改进保持同步
  • Predis:
    • 由于完全是用 PHP 编写的,具有跨平台兼容性,适用于任何支持 PHP 的环境,兼容性更强
    • 作为第三方库,可能对最新的 Redis 功能支持较慢

持久性与维护

  • PhpRedis:
    • 作为 Redis 项目的一部分,官方支持和定期更新
    • 由 Redis 官方维护,适合长期使用的生产环境
  • Predis:
    • 虽然 Predis 曾是 PHP 开发者中的热门选择,但其 维护速度曾有所减慢。不过,最近推出了 Predis v2 版本,提高了对 Redis 6+ 的支持,但 PhpRedis 依然是现代应用的首选。

功能支持

  • PhpRedis:
    • 支持 所有 Redis 的功能,包括发布/订阅、Lua 脚本等高级功能
  • Predis:
    • Predis 支持大多数 Redis 功能,但由于依赖 PHP,有时对最新功能的支持可能滞后

使用场景

  • PhpRedis:
    • 适用于高性能应用、企业级项目或大量使用 Redis 的生产环境,因为它提供更好的速度和资源管理
    • 需要对托管环境有更多控制,因此更常见于开发者拥有 root 权限或控制服务器配置的环境中
  • Predis:
    • 更适合 小型应用,共享主机环境或需要简化安装和跨平台兼容性的场景
    • 适合托管环境受限,或无法安装扩展的项目

集群支持

  • PhpRedis:
    • 原生支持 Redis 集群,是分布式数据系统中 Redis 集群的最佳选择
  • Predis:
    • Predis 也支持集群,但由于是 PHP 实现,处理大规模集群时性能不如 PhpRedis

持久性

  • PhpRedis:
    • 作为 Redis 的官方维护项目,拥有更高的持久性和更强的支持
  • Predis:
    • 虽然它曾被广泛使用和支持,但其更新依赖于外部开发者

How to make a custom module

File Structure

module_name.info.yml

创建扩展模块首先创建 info.yml 文件,用来声明该模块的基本信息

name: 'Module Name'
type: module
description: 'A custom module for Drupal'
core_version_requirement: ^10 || ^11
package: 'Custom'
version: '1.0'
dependencies:
  - drupal:node

module_name.module

包含模块的函数方法和功能实现

'Stores athletics events.',
        'fields' => [
            'event_id' => [
                'type' => 'serial',
                'unsigned' => TRUE,
                'not null' => TRUE,
                'description' => '',
            ],

        ],
        'primary key' => ['event_id'],
    ];

    $schema['athletics_teams'] = [
        'description' => 'Stores athletics teams.',
        'fields' => [
            'team_id' => [
                'type' => 'serial',
                'unsigned' => TRUE,
                'not null' => TRUE,
                'description' => '',
            ],
            'name' => [
                'type' => 'varchar',
                'length' => 255,
                'not null' => TRUE,
                'description' => '',
            ],
            'description' => [
                'type' => 'text',
                'size' => 'medium',
                'not null' => false,
                'description' => '',
            ]
        ],
        'primary key' => ['team_id'],
    ];

    $database = \Drupal::database();
    $schema_manager = $database->schema();
    foreach ($schema as $table_name => $definition) {
        if (!$schema_manager->tableExists($table_name)) {
            $schema_manager->createTable($table_name, $definition);
        }
    }
}


/**
 * Implements hook_uninstall().
 */
function athletics_uninstall()
{
    $database = \Drupal::database();
    $schema_manager = $database->schema();

    if ($schema_manager->tableExists('athletics_events')) {
        $schema_manager->dropTable('athletics_events');
    }

    if ($schema_manager->tableExists('athletics_teams')) {
        $schema_manager->dropTable('athletics_teams');
    }
}

/**
 * Implements hook_theme().
 *
 * Register a module or theme's theme implementations.
 * The implementations declared by this hook specify how a
 * particular render array is to be rendered as HTML.
 *
 * See: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21theme.api.php/function/hook_theme
 *
 * If you change this method, clear theme registry and routing
 * table 'drush cc theme-registry' and 'drush cc router'.
 */

function athletics_theme($existing, $type, $theme, $path)
{
    return [
        // Name of the theme hook. This is used in the controller to trigger the hook.
        'event_index' => [
            'render element' => 'children',
            // If no template name is defined here,
            // it defaults to the name of the theme hook
            'template' => 'event/index',
            // Optionally define path to Twig template files.
            // Defaults to the module's ./templates/ directory.
            'path' => $path . '/templates',
            // Optionally define variables that will be passed to the Twig
            // template and set default values for them.
            'variables' => [
                'variable1' => 'Yet another default text.',
                'variable2' => 0,
                'variable3' => [0, 0, 0],
            ],
        ],
    ];
}

module_name.routing.yml

定义模块的路由

hello_world.content:
  path: '/hello'
  defaults:
    _controller: '\Drupal\hello_world\Controller\HelloController::content'
    _title: 'Hello World'
  requirements:
    _permission: 'access content'

module_name.settings.yml

定义模块的配置, settings.yml 文件通常存储在模块工程文件夹下的 config/install/module_name.settings.yml

# Configuration settings for the Hello World module.
# This file is used to store the module's configuration settings.
# The settings are stored in the 'config' table and can be overridden
# by settings in the 'config_override' table.
# The settings are exported to the 'config/install' directory when the
# module is installed and can be imported from there.

# An example configuration setting.
# This setting is a simple text field.
# The key is the name of the setting.
# The value is the default value of the setting.
# The 'type' key is the data type of the setting.
# The 'label' key is the human-readable name of the setting.
# The 'description' key is a description of the setting.
# The 'required' key is a boolean value that determines if the setting is required.
# The 'default_value' key is the default value of the setting.
# The 'dependencies' key is an array of module dependencies.
# The 'module' key is the name of the module that provides the setting.
# The 'locked' key is a boolean value that determines if the setting is locked.
# The 'schema' key is an array of schema information for the setting.
hello_world.admin:
  title: 'Hello module settings'
  description: 'example of how to make an admin settings page link'
  parent: system.admin_config_development
  route_name: hello_world.content
  weight: 100

node.type.example_type.yml

Reference URL to an external site.

如果开发的新模块中需要用到一种新的内容类型,类似 Structure 中的 Article, Post 等等,在目录 module_name/config/install 目录下放置 node.type.example_type.yml文件,可以在 node.type.example_type.yml 中定义其属性:

type: example_mytype
name: Example
description: 'Use example content to get to Drupal 8 development better.'
help: ''
new_revision: false
display_submitted: true
preview_mode: 1
status: true
langcode: en
dependencies:
  module:
    - example
  enforced:
    module:
      - example
Previous
Deployer