5.0 迁移指南

CakePHP 5.0 包含重大变更,与 4.x 版本不向后兼容。在尝试升级到 5.0 之前,请先升级到 4.5 并解决所有弃用警告。

请参阅 5.0 升级指南,了解有关如何升级到 5.0 的分步说明。

已弃用功能已移除

自 4.5 版本以来,发出弃用警告的所有方法、属性和功能均已移除。

重大变更

除了移除已弃用功能外,还进行了重大变更

全局

  • 在所有可能的地方,函数参数和返回值都添加了类型声明。这些类型声明旨在与文档注释相匹配,但也包含对不正确注释的修复。

  • 在所有可能的地方,类属性都添加了类型声明。这些类型声明还包含对不正确注释的一些修复。

  • 已移除 SECONDMINUTEHOURDAYWEEKMONTHYEAR 常量。

  • 已移除所有地方使用 #[\AllowDynamicProperties]。它用于以下类:
    • Command/Command

    • Console/Shell

    • Controller/Component

    • Controller/Controller

    • Mailer/Mailer

    • View/Cell

    • View/Helper

    • View/View

  • 已更新支持的数据库引擎版本:
    • MySQL (5.7 或更高版本)

    • MariaDB (10.1 或更高版本)

    • PostgreSQL (9.6 或更高版本)

    • Microsoft SQL Server (2012 或更高版本)

    • SQLite 3 (3.16 或更高版本)

Auth

缓存

  • 已移除 Wincache 引擎。PHP 8 不支持 wincache 扩展。

集合

  • combine() 现在会在键路径或分组路径不存在或包含空值时抛出异常。这与 indexBy()groupBy() 的行为一致。

控制台

  • 已移除 BaseCommand::__construct()

  • 已移除 ConsoleIntegrationTestTrait::useCommandRunner(),因为它不再需要。

  • 已移除 Shell,应替换为 Command

  • 已移除 ConsoleOptionParser::addSubcommand(),与移除 Shell 一致。子命令应替换为实现 Command::defaultName() 以定义必要命令名的 Command 类。

  • BaseCommand 现在会在框架调用命令的 execute() 方法前后发出 Command.beforeExecuteCommand.afterExecute 事件。

连接

  • 已移除 Connection::prepare()。您可以改用 Connection::execute() 在单个调用中通过指定 SQL 字符串、参数和类型来执行 SQL 查询。

  • 已移除 Connection::enableQueryLogging()。如果您尚未通过连接配置启用日志记录,则可以稍后为驱动程序设置记录器实例以启用查询日志记录 $connection->getDriver()->setLogger()

控制器

  • Controller::__construct() 的方法签名已更改。因此,如果您要覆盖构造函数,则需要相应地调整代码。

  • 加载后,组件不再被设置为动态属性。相反,Controller 使用 __get() 为组件提供属性访问。此更改可能会影响使用 property_exists() 的应用程序。

  • 组件的 Controller.shutdown 事件回调已从 shutdown 重命名为 afterFilter,以匹配控制器回调。这使回调更加一致。

  • PaginatorComponent 已移除,应替换为在控制器中调用 $this->paginate() 或直接使用 Cake\Datasource\Paging\NumericPaginator

  • RequestHandlerComponent 已移除。请参阅 4.4 迁移 指南,了解如何升级

  • SecurityComponent 已移除。请改用 FormProtectionComponent 进行表单篡改保护或使用 HttpsEnforcerMiddleware 来强制请求使用 HTTPS。

  • Controller::paginate() 不再接受其 $settings 参数的查询选项,如 contain。相反,您应该使用 finder 选项 $this->paginate($this->Articles, ['finder' => 'published'])。或者,您可以在预先创建所需的 select 查询,然后将其传递给 paginate() $query = $this->Articles->find()->where(['is_published' => true]); $this->paginate($query);

核心

  • 已移除函数 getTypeName()。请改用 PHP 的 get_debug_type()

  • 已将 league/container 的依赖项更新为 4.x。这将要求您在 ServiceProvider 实现中添加类型提示。

  • deprecationWarning() 现在有一个 $version 参数。

  • 已移除配置选项 App.uploadedFilesAsObjects,以及整个框架对 PHP 文件上传形状数组的支持。

  • 已移除 ClassLoader。请改用 composer 生成自动加载文件。

数据库

  • DateTimeTypeDateType 现在始终返回不可变对象。此外,Date 对象的接口反映了 ChronosDate 接口,该接口缺少 CakePHP 4.x 中存在的所有与时间相关的方法。

  • DateType::setLocaleFormat() 不再接受数组。

  • Query 现在只接受 \Closure 参数,而不是 callable。可调用对象可以使用 PHP 8.1 中新的头等数组语法转换为闭包。

  • Query::execute() 不再运行结果装饰器回调。 您必须使用 Query::all() 代替。

  • TableSchemaAwareInterface 已被移除。

  • Driver::quote() 已被移除。 请改用预处理语句。

  • Query::orderBy() 已被添加以替换 Query::order()

  • Query::groupBy() 已被添加以替换 Query::group()

  • SqlDialectTrait 已被移除,其所有功能已移至 Driver 类本身。

  • CaseExpression 已被移除,应替换为 QueryExpression::case()CaseStatementExpression

  • Connection::connect() 已被移除。 请改用 $connection->getDriver()->connect()

  • Connection::disconnect() 已被移除。 请改用 $connection->getDriver()->disconnect()

  • cake.database.queries 已被添加作为 queriesLog 范围的替代方案。

  • 启用/禁用结果集缓冲的功能已被移除。 结果始终被缓冲。

数据源

  • getAccessible() 方法已添加到 EntityInterface。 非 ORM 实现现在需要实现此方法。

  • aliasField() 方法已添加到 RepositoryInterface。 非 ORM 实现现在需要实现此方法。

事件

  • 事件有效载荷必须是数组。 其他对象(如 ArrayAccess)不再转换为数组,现在将引发 TypeError

  • 建议调整事件处理程序以成为 void 方法,并使用 $event->setResult() 而不是返回结果。

错误

  • ErrorHandlerConsoleErrorHandler 已被移除。 有关如何升级,请参阅 4.4 迁移 指南。

  • ExceptionRenderer 已被移除,应替换为 WebExceptionRenderer

  • ErrorLoggerInterface::log() 已被移除,应替换为 ErrorLoggerInterface::logException()

  • ErrorLoggerInterface::logMessage() 已被移除,应替换为 ErrorLoggerInterface::logError()

文件系统

  • Filesystem 包已被移除,Filesystem 类已移至 Utility 包。

HTTP

  • ServerRequest 不再与 files 作为数组兼容。 此行为自 4.1.0 起默认情况下已被禁用。 files 数据现在将始终包含 UploadedFileInterfaces 对象。

国际化

  • FrozenDate 已重命名为 DateFrozenTime 已重命名为 DateTime

  • Time 现在扩展了 Cake\Chronos\ChronosTime,因此是不可变的。

  • Date 对象不再扩展 DateTimeInterface - 因此您无法将它们与 DateTime 对象进行比较。 有关更多信息,请参阅 cakephp/chronos 版本发布文档

  • Date::parseDateTime() 已被移除。

  • Date::parseTime() 已被移除。

  • Date::setToStringFormat()Date::setJsonEncodeFormat() 不再接受数组。

  • Date::i18nFormat()Date::nice() 不再接受时区参数。

  • 具有供应商前缀名称 (FooBar/Awesome) 的插件的翻译文件现在将在文件名中包含该前缀,例如 foo_bar_awesome.po,以避免与来自相应插件 (Awesome) 的 awesome.po 文件冲突。

日志

  • 日志引擎配置现在使用 null 而不是 false 来禁用范围。 因此,在您的日志配置中,您需要使用 'scopes' => null 而不是 'scopes' => false

邮件

  • Email 已被移除。 请改用 Mailer

  • cake.mailer 已被添加作为 email 范围的替代方案。

ORM

  • EntityTrait::has() 现在在属性存在且设置为 null 时返回 true。 在之前的 CakePHP 版本中,这将返回 false。 有关如何在 4.x 中采用此行为,请参阅 4.5.0 的版本发布说明。

  • EntityTrait::extractOriginal() 现在仅返回存在的字段,类似于 extractOriginalChanged()

  • 查找器参数现在要求是关联数组,因为它们始终被预期为关联数组。

  • TranslateBehavior 现在默认为 ShadowTable 策略。 如果您正在使用 Eav 策略,您需要更新您的行为配置以保留以前的行为。

  • allowMultipleNulls 选项用于 isUnique 规则现在默认为 true,匹配原始 3.x 行为。

  • Table::query() 已被移除,有利于特定于查询类型的函数。

  • Table::updateQuery()Table::selectQuery()Table::insertQuery()Table::deleteQuery())已被添加,并返回以下新的特定于类型的查询对象。

  • SelectQueryInsertQueryUpdateQueryDeleteQuery 已被添加,它们仅代表一种类型的查询,不允许在查询类型之间切换,也不允许调用与特定查询类型无关的函数。

  • Table::_initializeSchema() 已被移除,应替换为在 initialize() 方法中调用 $this->getSchema()

  • SaveOptionsBuilder 已被移除。 请改用普通数组作为选项。

路由

  • Router 的静态方法 connect()prefix()scope()plugin() 已被移除,应替换为通过 RouteBuilder 实例调用其非静态方法变体。

  • RedirectException 已被移除。 请改用 \Cake\Http\Exception\RedirectException

测试套件

  • TestSuite 已被移除。 用户应该使用环境变量来自定义单元测试设置。

  • TestListenerTrait 已被移除。 PHPUnit 放弃了对这些侦听器的支持。 请参阅 PHPUnit 10 升级

  • IntegrationTestTrait::configRequest() 现在在多次调用时合并配置,而不是替换当前存在的配置。

验证

  • Validation::isEmpty() 不再与文件上传形状数组兼容。 对 PHP 文件上传数组的支持已从 ServerRequest 中移除,因此您在测试之外不应该看到这是一个问题。

  • 以前,大多数数据验证错误消息只是 The provided value is invalid。 现在,数据验证错误消息的措辞更加准确。 例如,The provided value must be greater than or equal to \`5\`

视图

  • ViewBuilder 选项现在确实是关联的(字符串键)。

  • NumberHelperTextHelper 不再接受 engine 配置。

  • ViewBuilder::setHelpers() 参数 $merge 已被移除。 请改用 ViewBuilder::addHelpers()

  • View::initialize() 内部,优先使用 addHelper() 而不是 loadHelper()。无论如何,所有配置的助手将在之后加载。

  • View\Widget\FileWidget 现在不再与 PHP 文件上传形状数组兼容。这与 ServerRequestValidation 的更改保持一致。

  • FormHelper 不再在 CSRF 令牌字段上设置 autocomplete=off。这是一个针对 Safari 漏洞的解决方法,现在不再相关。

弃用

以下是已弃用的方法、属性和行为的列表。这些功能将在 5.x 中继续发挥作用,并在 6.0 中被移除。

数据库

  • Query::order() 已被弃用。现在 Connection 方法不再被代理,请使用 Query::orderBy() 代替。这使函数名称与 SQL 语句保持一致。

  • Query::group() 已被弃用。现在 Connection 方法不再被代理,请使用 Query::groupBy() 代替。这使函数名称与 SQL 语句保持一致。

ORM

  • 使用选项数组调用 Table::find() 已被弃用。请使用 命名参数 代替。例如,不要使用 find('all', ['conditions' => $array]),请使用 find('all', conditions: $array)。同样,对于自定义查找器选项,不要使用 find('list', ['valueField' => 'name']),请使用 find('list', valueField: 'name') 或多个命名参数,如 find(type: 'list', valueField: 'name', conditions: $array)

新功能

改进的类型检查

CakePHP 5 利用了 PHP 8.1+ 中可用的扩展类型系统功能。CakePHP 还使用 assert() 来提供改进的错误消息和额外的类型安全性。在生产模式下,您可以配置 PHP 不为 assert() 生成代码,从而提高应用程序性能。有关如何执行此操作,请参阅 提高应用程序性能

集合

  • 添加了 unique(),它根据提供的回调过滤掉重复的值。

  • reject() 现在支持默认回调,该回调过滤掉真值,这与 filter() 的默认行为相反。

核心

  • services() 方法添加到 PluginInterface 中。

  • PluginCollection::addFromConfig() 已添加到 简化插件加载 中。

数据库

  • ConnectionManager 现在支持读写连接角色。角色可以通过连接配置中的 readwrite 键进行配置,这些键会覆盖共享配置。

  • 添加了 Query::all(),它运行结果修饰器回调并返回选择查询的结果集。

  • 添加了 Query::comment(),用于将 SQL 注释添加到执行的查询中。这使得调试查询变得更加容易。

  • 添加了 EnumType,允许在 PHP 支持的枚举和字符串或整数列之间进行映射。

  • getMaxAliasLength()getConnectionRetries() 添加到 DriverInterface 中。

  • 现在,支持的驱动程序会自动将自增仅添加到名为“id”的整数主键,而不是所有整数主键。将 ‘autoIncrement’ 设置为 false 将始终在所有支持的驱动程序上禁用。

Http

  • 添加了对 PSR-17 工厂接口的支持。这使得 cakephp/http 能够为允许自动接口解析的库(如 php-http)提供客户端实现。

  • 添加了 CookieCollection::__get()CookieCollection::__isset(),以提供符合人体工程学的方式访问 cookie,而无需出现异常。

ORM

必需实体字段

实体具有一个新的选择性功能,允许实体更严格地处理属性。这种新行为称为“必需字段”。启用后,访问实体中未定义的属性将引发异常。这会影响以下用法

$entity->get();
$entity->has();
$entity->getOriginal();
isset($entity->attribute);
$entity->attribute;

如果字段通过 array_key_exists,则认为字段已定义。这包括空值。由于这可能是一个繁琐的启用功能,因此它被推迟到 5.0。我们希望您能对这个功能提供任何反馈,因为我们正在考虑在将来将其设为默认行为。

类型化查找器参数

表查找器现在可以具有类型化参数作为必需参数,而不是选项数组。例如,用于按类别或用户获取帖子的查找器

public function findByCategoryOrUser(SelectQuery $query, array $options)
{
    if (isset($options['categoryId'])) {
        $query->where(['category_id' => $options['categoryId']]);
    }
    if (isset($options['userId'])) {
        $query->where(['user_id' => $options['userId']]);
    }

    return $query;
}

现在可以写成

public function findByCategoryOrUser(SelectQuery $query, ?int $categoryId = null, ?int $userId = null)
{
    if ($categoryId) {
        $query->where(['category_id' => $categoryId]);
    }
    if ($userId) {
        $query->where(['user_id' => $userId]);
    }

    return $query;
}

然后可以像 find('byCategoryOrUser', userId: $somevar) 那样调用查找器。您甚至可以包含用于设置查询子句的特殊命名参数。 find('byCategoryOrUser', userId: $somevar, conditions: ['enabled' => true])

RepositoryInterface::get() 方法也进行了类似的更改

public function view(int $id)
{
    $author = $this->Authors->get($id, [
        'contain' => ['Books'],
        'finder' => 'latest',
    ]);
}

现在可以写成

public function view(int $id)
{
    $author = $this->Authors->get($id, contain: ['Books'], finder: 'latest');
}

测试套件

  • 添加了 IntegrationTestTrait::requestAsJson(),用于为下一个请求设置 JSON 标头。

插件安装程序

  • 插件安装程序已更新,可以自动处理您的应用程序插件的类自动加载。因此,您可以从 composer.json 中删除插件的命名空间到路径映射,只需运行 composer dumpautoload