代码模块
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');