代码模块

CodeIgniter 支持一种代码模块化形式,以帮助您创建可重用的代码。模块通常围绕特定主题,可以被认为是您更大应用程序中的小型应用程序。

框架中的任何标准文件类型都受支持,例如控制器、模型、视图、配置文件、助手、语言文件等。模块可以包含您喜欢的任意数量的这些文件。

如果您想将模块作为 Composer 包创建,请参阅 创建 Composer 包

命名空间

模块功能的核心元素来自 CodeIgniter 使用的 与 PSR-4 兼容的自动加载。虽然任何代码都可以使用 PSR-4 自动加载器和命名空间,但充分利用模块的主要方法是为您的代码命名空间,并将其添加到 app/Config/Autoload.php 中的 $psr4 属性中。

例如,假设我们想保留一个简单的博客模块,以便在应用程序之间重复使用。我们可能会创建一个包含我们公司名称 Acme 的文件夹,以存储我们所有的模块。我们将把它放在主项目根目录中的 app 目录旁边。

acme/        // New modules directory
app/
public/
system/
tests/
writable/

打开 app/Config/Autoload.php 并将 Acme\Blog 命名空间添加到 $psr4 数组属性中。

<?php

namespace Config;

use CodeIgniter\Config\AutoloadConfig;

class Autoload extends AutoloadConfig
{
    public $psr4 = [
        APP_NAMESPACE => APPPATH, // For custom namespace
        'Config'      => APPPATH . 'Config',
        'Acme\Blog'   => ROOTPATH . 'acme/Blog',
    ];

    // ...
}

现在,我们已经设置了这个,我们可以通过 Acme\Blog 命名空间访问 acme/Blog 文件夹中的任何文件。这本身就解决了模块工作所需的 80%,因此您应该确保熟悉命名空间并习惯使用它们。几种文件类型将通过所有定义的命名空间自动扫描 - 这是使用模块的关键要素。

模块中的常见目录结构将模仿主应用程序文件夹。

acme/
    Blog/
        Config/
        Controllers/
        Database/
            Migrations/
            Seeds/
        Helpers/
        Language/
            en/
        Libraries/
        Models/
        Views/

当然,没有什么强迫您使用这种确切的结构,您应该以最适合您的模块的方式进行组织,省略不需要的目录,为实体、接口或存储库等创建新目录。

自动加载非类文件

通常,您的模块不仅包含 PHP 类,还包含其他文件,例如过程函数、引导文件、模块常量文件等,这些文件通常不会像类那样加载。一种方法是在使用该文件的开始使用 require 加载该文件。

CodeIgniter 提供的另一种方法是像自动加载类一样自动加载这些非类文件。我们只需要提供这些文件的路径列表,并将它们包含在 app/Config/Autoload.php 文件的 $files 属性中。

<?php

namespace Config;

use CodeIgniter\Config\AutoloadConfig;

class Autoload extends AutoloadConfig
{
    // ...

    public $files = [
        'path/to/my/functions.php',
        'path/to/my/constants.php',
        'path/to/my/bootstrap.php',
    ];

    // ...
}

自动发现

很多时候,您需要指定要包含的文件的完整命名空间,但 CodeIgniter 可以配置为通过自动发现许多不同的文件类型(包括)来简化将模块集成到您的应用程序中。

这在文件 **app/Config/Modules.php** 中配置。

自动发现系统通过扫描 **Config/Autoload.php** 和 Composer 包中定义的 psr4 命名空间内的特定目录和文件来工作。

发现过程将在该路径上查找可发现的项目,例如,应该在 **acme/Blog/Config/Routes.php** 中找到路由文件。

启用/禁用发现

您可以使用 $enabled 类变量在系统中打开或关闭所有自动发现。False 将禁用所有发现,优化性能,但会抵消模块和 Composer 包的特殊功能。

指定发现项目

使用 $aliases 选项,您可以指定哪些项目会被自动发现。如果项目不存在,则不会对该项目进行自动发现,但数组中的其他项目仍将被发现。

发现和 Composer

使用 PSR-4 命名空间通过 Composer 安装的包默认也会被发现。PSR-0 命名空间的包将不会被检测到。

指定 Composer 包

版本 4.3.0 中的新功能。

为了避免浪费时间扫描不相关的 Composer 包,您可以通过编辑 **app/Config/Modules.php** 中的 $composerPackages 变量来手动指定要发现的包。

<?php

namespace Config;

use CodeIgniter\Modules\Modules as BaseModules;

class Modules extends BaseModules
{
    // ...

    public $composerPackages = [
        'only' => [
            // List up all packages to auto-discover
            'codeigniter4/shield',
        ],
    ];

    // ...
}

或者,您可以指定要从发现中排除的包。

<?php

namespace Config;

use CodeIgniter\Modules\Modules as BaseModules;

class Modules extends BaseModules
{
    // ...

    public $composerPackages = [
        'exclude' => [
            // List up packages to exclude.
            'pestphp/pest',
        ],
    ];

    // ...
}

禁用 Composer 包发现

如果您不希望在查找文件时扫描 Composer 的所有已知目录,您可以通过编辑 **app/Config/Modules.php** 中的 $discoverInComposer 变量来关闭此功能。

<?php

namespace Config;

use CodeIgniter\Modules\Modules as BaseModules;

class Modules extends BaseModules
{
    public $discoverInComposer = false;

    // ...
}

使用文件

本节将介绍每种文件类型(控制器、视图、语言文件等)以及它们如何在模块中使用。用户指南中相关位置对其中一些信息进行了更详细的描述,但这里也进行了复述,以便更容易理解所有部分如何协同工作。

路由

默认情况下,路由 会在模块中自动扫描。可以在上面描述的 **Modules** 配置文件中将其关闭。

注意

由于文件被包含到当前作用域中,因此 $routes 实例已经为您定义。如果您尝试重新定义该类,将会导致错误。

在使用模块时,如果应用程序中的路由包含通配符,可能会出现问题。在这种情况下,请参见 路由优先级

过滤器

自版本 4.4.2 起已弃用。

注意

此功能已弃用。请使用 注册器 代替,例如:

<?php

namespace CodeIgniter\Shield\Config;

use CodeIgniter\Shield\Filters\SessionAuth;
use CodeIgniter\Shield\Filters\TokenAuth;

class Registrar
{
    /**
     * Registers the Shield filters.
     */
    public static function Filters(): array
    {
        return [
            'aliases' => [
                'session' => SessionAuth::class,
                'tokens'  => TokenAuth::class,
            ],
        ];
    }
}

默认情况下,过滤器 会在模块中自动扫描。可以在上面描述的 **Modules** 配置文件中将其关闭。

注意

由于文件被包含到当前作用域中,因此 $filters 实例已经为您定义。如果您尝试重新定义该类,将会导致错误。

在模块的 **Config/Filters.php** 文件中,您需要定义所用过滤器的别名

<?php

$filters->aliases['menus'] = \App\Filters\MenusFilter::class;

控制器

位于主 **app/Controllers** 目录之外的控制器无法通过 URI 检测自动路由,而必须在 Routes 文件本身中指定

<?php

// Routes.php
$routes->get('blog', '\Acme\Blog\Controllers\Blog::index');

为了减少这里所需的输入量,分组路由功能非常有用

<?php

$routes->group('blog', ['namespace' => 'Acme\Blog\Controllers'], static function ($routes) {
    $routes->get('/', 'Blog::index');
});

配置文件

在处理配置文件时,无需进行任何特殊更改。这些仍然是命名空间类,并使用 new 命令加载

<?php

$config = new \Acme\Blog\Config\Blog();

每次使用始终可用的 config() 函数并向其传递一个简短的类名时,都会自动发现配置文件。

注意

我们不建议您在模块中使用相同的简短类名。需要覆盖或添加到 **app/Config/** 中已知配置的模块应使用 隐式注册器

注意

在 v4.4.0 之前,config() 在存在具有相同简短名称的类时,会在 **app/Config/** 中找到该文件,即使您指定了完全限定的类名,例如 config(\Acme\Blog\Config\Blog::class)。此行为已在 v4.4.0 中修复,并返回指定的实例。

迁移

迁移文件将在定义的命名空间内自动发现。每次都会运行所有命名空间中找到的所有迁移。

种子

种子文件既可以从 CLI 使用,也可以从其他种子文件内部调用,只要提供了完整的命名空间。如果在 CLI 上调用,则需要提供双反斜杠

对于 Unix

php spark db:seed Acme\\Blog\\Database\\Seeds\\TestPostSeeder

对于 Windows

php spark db:seed Acme\Blog\Database\Seeds\TestPostSeeder

助手

当使用 helper() 函数时,助手将在定义的命名空间内自动发现,只要它位于命名空间 **Helpers** 目录中

<?php

helper('blog');

您可以指定命名空间。有关详细信息,请参阅 从指定命名空间加载

语言文件

当使用 lang() 方法时,语言文件会从定义的命名空间中自动定位,只要该文件遵循与主应用程序目录相同的目录结构。

库始终通过其完全限定的类名实例化,因此不提供特殊访问权限

<?php

$lib = new \Acme\Blog\Libraries\BlogLib();

模型

如果您使用完全限定的类名通过 new 关键字实例化模型,则不提供特殊访问权限

<?php

$model = new \Acme\Blog\Models\PostModel();

只要使用始终可用的 model() 函数,模型文件就会自动被发现。

注意

我们不建议您在模块中使用相同的简短类名。

注意

model() 在存在具有相同简短名称的类时,会在 app/Models/ 中查找文件,即使您指定了完全限定的类名,例如 model(\Acme\Blog\Model\PostModel::class)。这是因为 model()Factories 类的包装器,默认情况下使用 preferApp。有关更多信息,请参阅 加载类

视图

视图可以使用类命名空间加载,如 视图 文档中所述

<?php

echo view('Acme\Blog\Views\index');