CakePHP

Release 3.9

Cake Software Foundation

CakePHP 概览

CakePHP 的设计是为了让共通的网络开发变得更加轻松，简单。通过提供给您一个全能工具箱来让您很好地整体或者单独地使用它。

这篇概要的目的是介绍CakePHP的一般概念，并且为您介绍这些概念是如何在CakePHP中得到实现的。如果你急于开始一个项目，你可以 开始教程, 或者 直接参考文档.

规约来替代设定

CakePHP提供的基本构造包括class名，文件名，数据库table名。尽管这些规约需要花一些时间学习，遵从这些CakePHP为您提供的规约可以让您避免不必要的设定并且拥有一个使各种项目都能简单使用的应用结构。在 规约章节 囊括了CakePHP需要的各种规约.

模型（Model）层

模型层为您的应用程序提供了实现业务逻辑的部分。他负责检索数据并且将其转换成对于应用程序有意义的形式。包括了处理、验证、表结合以及其它操作数据的任务。

拿社交网络来举例子，Model层将负责像保存用户数据、保存朋友们的关联、存储和检索用户相片、寻找关于新朋友的建议等等。这些Model对象可以被当作“朋友（Friend）”、“用户（User）”、 “评论（Comment）”、或者是“照片（Photo）”。如果你想要从我们的``users``表中读取一些数据，我们可以:

use Cake\ORM\TableRegistry;

// Prior to 3.6 use TableRegistry::get('Users')
$users = TableRegistry::getTableLocator()->get('Users');
$query = $users->find();
foreach ($query as $row) {
    echo $row->username;
}

您也许注意到了我们在使用我们的数据之前并不需要写任何代码。通过使用规约，CakePHP将会使用我们还没有定义的table和entity类（classes）的标准类。

如果我们想要造一个新的User并且将其保存（通过验证），我们可以像如下:

use Cake\ORM\TableRegistry;

// Prior to 3.6 use TableRegistry::get('Users')
$users = TableRegistry::getTableLocator()->get('Users');
$user = $users->newEntity(['email' => 'mark@example.com']);
$users->save($user);

视图（View）层

View层会渲染来自Model的数据。通过与Model对象的分离，它能够使用合适的信息来产生你的应用程序需要的表示界面。

举个例子，View（视图）可以使用model数据来渲染一个View template（视图模板）包含的HTML，或者在其它地方使用的XML形式的返回值:

// In a view template file, we'll render an 'element' for each user.
<?php foreach ($users as $user): ?>
    <li class="user">
        <?= $this->element('user', ['user' => $user]) ?>
    </li>
<?php endforeach; ?>

View层提供了很多像 section_view-templates , section_view-elements 和 View Cells 的扩展功能来让您重复利用你的表示逻辑。

View层不仅仅限制于呈现数据的HTML或者文本。它还可以用于传递像JSON、XML、以及任何可通过插件追加的你需要的结构，比方说CSV。

控制器（Controller）层

Controller层用于处理来自用户的请求。它能够在Model层和View层的帮助下渲染一个响应。

一个Controller可以被看成是一个管理者，它确保完成一个任务的所有资源被正确分配到员工手中。它等待来自客户的请求，通过身份认证和权限检查来验证它们的合法性，委托Model取得和处理数据，选择客户所接受的表示数据类型，最后委托View层来完成渲染过程。一个用户注册Controller的例子将会是:

public function add()
{
    $user = $this->Users->newEntity();
    if ($this->request->is('post')) {
        $user = $this->Users->patchEntity($user, $this->request->getData());
        if ($this->Users->save($user, ['validate' => 'registration'])) {
            $this->Flash->success(__('You are now registered.'));
        } else {
            $this->Flash->error(__('There were some problems.'));
        }
    }
    $this->set('user', $user);
}

你也许注意到了我们从来没有明示地渲染一个视图（view）。CakePHP的规约将负责选择正确的视图，并且用我们准备的``set()``方法来渲染它。

CakePHP请求周期

现在你已经对不同的层有了一定的熟悉，让我回顾一下一个请求周期是如何在CakePHP中运作的:

典型的CakePHP请求周期开始于用户请求在你应用程序中的页面或者资源。在一个很高的层级上各自的请求都经过以下的步骤:

网页服务器重写导向**webroot/index.php**请求路径的规则。

你的应用程序被加载和绑定到一个``HttpServer``。

你的应用程序的中间件被初始化。

请求和请求结果通过你的应用程序使用的PSR-7中间件进行分配。这通常包括错误捕获和路径导向（路由）。

如果中间件没有返回响应并且请求中包含路由信息，那么表明一个Controller&Action被指定。

Controller的Action被调用并且Controller与请求的Models和Components（部件）发生反应。

Controller分配给视图（view）一个创建的响应来生成Model数据输出的结果。

视图（view）使用Helpers和Cells来生成响应的头部（headers）和身体（body）内容。

响应结果通过 Middleware 被送回。

HttpServer 向网页服务器放出响应结果。

让我们开始吧

希望这个快速的概览能够激起你的兴趣。一些其它的CakePHP的显著特征是:

一个由Memcached, Redis 和其它后端所集成的 缓存 框架

强力的 代码生成工具 让你可以迅速地开始

结合测试框架 可以让你确保你的代码完美运行

下一步明显要做的是 下载 CakePHP, 阅读教程并且制作些很棒的东西.

附录

求助指南

CakePHP 约定

CakePHP 的文件夹结构

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

求助指南

官方网站

https://cakephp.org

官方网站提供各种实用的讯息，包括常用开发工具地址，教学视频，捐赠平台以及各种资讯供下载。

开发手册（Cookbook）

https://book.cakephp.org

Cookbook 是你遇到问题时，寻找答案的首选之地。CakePHP和其他的开源项目一样，每天都有很多新人加入。我们相信，最好的学习方式就是靠自己去寻找答案。也许寻找的过程比较长，但是它就让你更快成才，同时也将减轻官方的负担。Cookbook 和 API 文档都可以在网上查看。

社区（Bakery）

https://bakery.cakephp.org

Bakery 是一个信息丰富的社区。它包含了教程，实例探究以及代码示例。当你熟练了 CakePHP 以后，你也可以加入，和大家分享你的知识。说不定你还能一举成名（开玩笑的）。

API 文档

https://api.cakephp.org/

API 文档是 CakePHP 最全面的代码文档，它解释了内核运作的各种细节。如果你钟爱阅读代码，你一定会爱上它。文档出自于核心开发者之手，也是了解 CakePHP 最贴近的方法。但是我们不推荐给初学者。

测试用例

如果 API 文档提供的信息还不够的话，你还可以使用测试用例来学习 CakePHP。你可以通过调试测试用例来了解类别中的方法以及资料成员是怎样工作的。

tests/TestCase/

IRC 聊天频道

IRC 聊天频道都建立在 irc.freenode.net:

#cakephp – 关于一般讨论

#cakephp-docs – 关于文档

#cakephp-bakery – 关于 Bakery

#cakephp-fr – 法文频道.

遇到任何问题，请在 IRC 上面告诉我们。一般情况下，一些`核心开发成员 <https://github.com/cakephp?tab=members>`_ 都会在那里，特别是南北美的白天。不管是你需要帮助，想在你的地区找组织，或者要给我们捐赠跑车，都欢迎你联系我们。

官方论坛

CakePHP 官方论坛 [http://discourse.cakephp.org]

官方论坛提供了一个平台，让我们可以提问，提建议以及谈论任何有关 CakePHP 话题。加入这个论坛，你可以迅速地找到答案，也可以帮助其他人。

Stackoverflow

https://stackoverflow.com/ [https://stackoverflow.com/questions/tagged/cakephp/]

提问时，请使用 cakephp 标签，同时标明 CakePHP 版本。只有这样，stackoverflow 的用户才可以看到你的问题。

求助指南（各国）

巴西

巴西 CakePHP 社区 [http://cakephp-br.org]

丹麦

丹麦 CakePHP Slack 频道 [https://cakesf.slack.com/messages/denmark/]

法国

法国 CakePHP 社区 [http://cakephp-fr.org]

德国

德国 CakePHP Slack 频道 [https://cakesf.slack.com/messages/german/]

德国 CakePHP Facebook Group [https://www.facebook.com/groups/146324018754907/]

伊朗

伊朗 CakePHP 社区 [http://cakephp.ir]

荷兰

荷兰 CakePHP Slack 频道 [https://cakesf.slack.com/messages/netherlands/]

日本

日本 CakePHP Slack Channel [https://cakesf.slack.com/messages/japanese/]

日本 CakePHP Facebook Group [https://www.facebook.com/groups/304490963004377/]

葡萄牙语

葡萄牙 CakePHP Google Group [http://groups.google.com/group/cakephp-pt]

西班牙语

西班牙 CakePHP Slack 频道 [https://cakesf.slack.com/messages/spanish/]

西班牙 CakePHP IRC 频道

西班牙 CakePHP Google Group [http://groups.google.com/group/cakephp-esp]

中国

中国社区 [http://cakephpchina.com/]

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CakePHP 约定

我们坚信，约定优于配置(convention over configuration)。虽然学习 CakePHP 的约定需要一些时间，但从长远来看，您可以节省时间。通过遵循约定，您可以获得免费的功能，并将您从维护跟踪配置文件的噩梦中解放出来。约定也会带来非常统一的开发体验，可以允许其他开发者参与进来并提供帮助。

控制器约定

控制器的类名是复数，首字母大写, 并且以 Controller 结尾。UsersController 和 ArticleCategoriesController 都是约定的控制器类名的例子。

控制器中 public 的方法通常被暴露为可通过web浏览器访问的“操作”。例如 /users/view 映射到 UsersController 中的 view() 方法。protected 或者 private 的方法不能通过路由访问。

控制器名称的URL注意事项

正如您刚刚所见，单个单词的控制器映射到一个简单的小写URL路径。例如 UsersController （将是定义在名称为 UsersController.php 的文件中）可以从 http://example.com/users 访问。

虽然你也可以以任何你喜欢的方式来定义多个单词的控制器的路由，但约定的URL路径是小写并且用 DashedRoute 类来分割。因此，/article-categories/view-all 是访问 ArticleCategoriesController::viewAll() 方法的正确方式。

当你使用 $this->Html->link() 创建连接的时候，你可以使用以下约定的url数组:

$this->Html->link('link-title', [
    'prefix' => 'MyPrefix' // 首字母大写
    'plugin' => 'MyPlugin', // 首字母大写
    'controller' => 'ControllerName', // 首字母大写
    'action' => 'actionName' // 驼峰式
]

有关 CakePHP URL 和参数处理的更多信息，见 Connecting Routes。

文件名和类名约定

通常地，文件名匹配类名，并遵循 PSR-4 标准以便进行自动加载。下面是类名和文件名的一些示例：

控制器类 LatestArticlesController 将对应文件名 LatestArticlesController.php

组件类 MyHandyComponent 将对应文件名 MyHandyComponent.php

Table 类 OptionValuesTable 将对应文件名 OptionValuesTable.php.

Entity 类 OptionValue 将对应文件名 OptionValue.php.

Behavior 类 EspeciallyFunkableBehavior 将对应文件名 EspeciallyFunkableBehavior.php

视图类 SuperSimpleView 将对应文件名 SuperSimpleView.php

Helper 类 BestEverHelper 将对应文件名 BestEverHelper.php

每个文件将放置于你的应用程序的适当的 folder/namespace 文件夹中。

数据库约定

与 CakePHP 模型对应的表名是复数并用下划线分隔的。例如， users, article_categories, 和 user_favorite_pages 等。

带有两个单词的字段名使用下划线分隔： first_name。

hasMany， belongsTo/hasOne 关系中的外键被自动识别为关联表的表名（单数形式）后面带上``_id``。因此，假设 Users hasMany Articles，那么 articles 表将使用 user_id 字段作为外键关联到 users 表。 像 article_categories 这种表名中包含多个单词的表，外键的格式是 article_category_id。

当使用模型之间的 BelongsToMany 关系时，连接表应该以被连的表名作为表名（否则 bake 命令将无法运作），并且按字母顺序排序（使用 articles_tags 而非 tags_articles）。如果你需要在连接表上添加额外的列，您应该为该表创建一个单独的 entity/table 类。

除了使用自增长的 integer 作为主键外，你还可以使用 UUID 字段。当你使用 Table::save() 方法保存新的记录的时候，CakePHP 会自动使用 (Cake\Utility\Text::uuid()) 生成 UUID 值。

模型约定

Table 类名是复数、首字母大写、以 Table 结尾的。UsersTable、ArticleCategoriesTable、UserFavoritePagesTable 分别是对应 users、article_categories、user_favorite_pages 表的 table 类名。

Entity 类名是单数、首字母大写、无后缀的。User、ArticleCategory、UserFavoritePage 分别是对应 users、article_categories、user_favorite_pages 表的 entity 类名。

视图约定

视图模板文件使用它对应的控制器方法的名字以下划线形式命名。ArticlesController 类的 viewAll() 防范将会对应视图模板文件 src/Template/Articles/view_all.ctp。

基本模式就是：src/Template/Controller/underscored_function_name.ctp。

注解

CakePHP 默认使用英语的词形变化。如果你的数据库表名或字段名使用别的语言，你需要新增词形变化规则（从单数到复数，反之亦然）。你可以使用 Cake\Utility\Inflector 来定义你的自定义词形变化规则。更多信息见文档 Inflector。

概述

通过使用 CakePHP 约定来命名应用程序的各个部分，你无须烦恼于配置和维护的麻烦就可以轻松使用。下面是一个将约定整合在一起的例子：

数据库表：”articles”

Table 类：ArticlesTable，在文件 src/Model/Table/ArticlesTable.php 中

Entity 类：Article，在文件 src/Model/Entity/Article.php 中

控制器类：ArticlesController，在文件 src/Controller/ArticlesController.php 中

视图模板，在文件 src/Template/Articles/index.ctp 中

使用这些约定，CakePHP 知道 http://example.com/articles/ 的请求映射到 ArticlesController（Articles 模型自动可用并被绑定到数据库的 articles 表）的 index() 方法，然后呈现给一个文件。除了通过创建无论如何需要创建的类和文件之外，这些关系都不是通过任何方式配置的。

现在您已经了解了 CakePHP 的基础知识，您可以尝试运行 內容管理系統教程 来看看这些东西是如何组合在一起的。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CakePHP 的文件夹结构

CakePHP 应用程序框架提供以下几个默认顶层文件夹：

bin 文件夹包含控制台可执行文件。

config 文件夹包含少许 Configuration 内核使用的文件。比如数据库连接信息文件，引导文件，内核配置以及其他。

plugins 文件夹包含了你的应用程序所使用的 Plugins。

logs 文件夹一般包含了根据你的配置而定的日志文件。

src 文件夹将是你的应用程序的源代码的所属之地。

tests 文件夹将是你的应用程序的测试用例的所属之地。

tmp 文件夹包含 CakePHP 的零时数据。具体的数据内容取决于你的配置。但是这个文件夹一般都储存翻译信息，模型描述以及 session 信息。

vendor 文件夹包含使用 Composer [http://getcomposer.org] 安装的应用程序所依赖的扩展包。由于 Composer 会在更新时覆盖任何人为的修改，所以不建议改动此文件夹内的内容。

webroot 是你的应用程序的公共文档根目录。它包含了外界可以直接接触的所有文件。

确保 tmp 和 logs 都存在而且可被写。不然你的应用程序的性能将被严重受影响。在 debug 模式下， CakePHP 会发出警告，如果这些目录不可被写。

src 文件夹

CakePHP 的 src 文件夹是在你开发时接触得最平常的地方。让我们近看下 src 里面的结构。

Controller

包含你的应用程序的控制器以及他们的组件。

Locale

储存国际化字符串文件。

Model

包含你的应用程序的数据表，实体以及行为。

Shell

包含应用程序的终端命令以及终端任务。详情可见 Shells, Tasks & Console Tools。

View

展示类都在此，他们包括视图，元件以及助手.

Template

展示文件都在此，他们包括： 元素，错误页面，布局以及视图模版文件。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

快速入门

实战是学习以及体验 CakePHP 的最好途径。让我们以开发一个内容管理系统（CMS）为例，来学习 CakePHP。

內容管理系統教程

此教程将讲述如何建立一个简单的 CMS。 首先我们需要安装 CakePHP，然后创建数据库，最后编写一个简单的文章管理系统。

基本要求：

一个数据库服务器。此教程采用的是 MySQL 作为数据库。你需要储备基本的 SQL 知识。懂得如何使用 SQL 建立数据库以及执行教程中的各种 SQL 片段。 CakePHP 可自动构造你的应用所需的各种查询语句。 由于此教程使用的是 MySQL, 请确定 PHP 的 pdo_mysql 已经启用。

基本的 PHP 知识。

在开始之前，请确保你的 PHP 已经更新。

php -v

你至少需要安装 PHP （命令行界面）版本 5.6 以上。网路服务器的 PHP 需要和命令行界面版本一致，保证 5.6 以上。

安装 CakePHP

使用 Composer 是安装 CakePHP 最简单的方法。Composer 是通过终端或者命令行提示符安装 CakePHP 的一种简易方式。首先，你需要下载和安装 Composer。你可以通过 cURL，然后执行以下语句来安装：

curl -s https://getcomposer.org/installer | php

或者你也可以从 Composer 官网 [https://getcomposer.org/download/] 直接下载 composer.phar。

然后在同一个目录中，运行以下语句来安装 CakePHP 的应用骨架，此应用将会建立在一个 cms 的目录中：

php composer.phar create-project --prefer-dist cakephp/app:^3.8 cms

如果你是下载使用的 Composer Windows Installer [https://getcomposer.org/Composer-Setup.exe]，在同一个目录中（比如 C:\wamp\www\dev\cakephp3）终端运行以下语句：

composer self-update && composer create-project --prefer-dist cakephp/app:^3.8 cms

使用 Composer 的优势是它会自动完成一些重要的设置任务，比如建立合适的文件权限以及建立配置文件

config/app.php。

当然 CakePHP 也提供其他的安装方式。如果你不能或者不想使用 Composer 的话，请查看 安装 章节。

不管你是以何种方式下载和安装,你的目录应该都会是以下形式:

/cms
  /bin
  /config
  /logs
  /plugins
  /src
  /tests
  /tmp
  /vendor
  /webroot
  .editorconfig
  .gitignore
  .htaccess
  .travis.yml
  composer.json
  index.php
  phpunit.xml.dist
  README.md

事不宜迟，现在是学习 CakePHP 目录结构的合适时机： 请查看 CakePHP 的文件夹结构 章节。

如果你没有跟上此教程的速度，你可以参考下此教程的 成品代码 [https://github.com/cakephp/cms-tutorial].

检查安装

你可以通过访问默认的主页的来检查安装是否成功。当然首先我们需要启动开发服务器：

cd /path/to/our/app

bin/cake server

注解

Windows 用户，需使用 bin\cake server （使用反斜线）

PHP 自带的网络服务器将在 8765 端口启动。在浏览器中访问 http://localhost:8765，你应该会看到欢迎页面。除了 ”CakePHP being able to connect to your database“ 没有绿色厨师帽以后，其余的要点都应有。如果不是这样的话，你可能需要安装一些缺失的 PHP 扩展，或者是建立正确的目录权限。

接下来，我们将创立我们的 数据库以及创建第一个模型.

CMS 教程 － 创建数据库

CakePHP 已经安装好，我们可以开始为 CMS 应用建立数据库了。首先建立一个空的数据库，你可以使用任意的名字，比如 cake_cms。执行以下 SQL 语句来建立需要的数据库表:

USE cake_cms;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE articles (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(191) NOT NULL,
    body TEXT,
    published BOOLEAN DEFAULT FALSE,
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (slug),
    FOREIGN KEY user_key (user_id) REFERENCES users(id)
) CHARSET=utf8mb4;

CREATE TABLE tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(191),
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (title)
) CHARSET=utf8mb4;

CREATE TABLE articles_tags (
    article_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (article_id, tag_id),
    FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
    FOREIGN KEY article_key(article_id) REFERENCES articles(id)
);

INSERT INTO users (email, password, created, modified)
VALUES
('cakephp@example.com', 'secret', NOW(), NOW());

INSERT INTO articles (user_id, title, slug, body, published, created, modified)
VALUES
(1, 'First Post', 'first-post', 'This is the first post.', 1, now(), now());

你也许已经注意到 articles_tags 表使用了复合主键。CakePHP 几乎支持所有的复合主键，这样便于你使用比较简单的数据库结构，不用添加额外的 id 列。

以上所使用的数据表名以及列名都不是随意的。利用 CakePHP 的 命名约定，我们可以更有效的使用并且避免了配置框架的需要。虽然 CakePHP 的灵活度可以容纳几乎所有的数据库结构，但是采取约定，利用 CakePHP 提供的默认的约定可以节省你很多的开发时间，

数据库配置

接着我们需要告诉 CakePHP 我们之前创建的数据库地址以及如何连接。在 config/app.php 文件中，找到 Datasources.default 数组，更改为相对应的值。以下的例子是一个完整的配置数组:

<?php
return [
    // More configuration above.
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql',
            'persistent' => false,
            'host' => 'localhost',
            'username' => 'cakephp',
            'password' => 'AngelF00dC4k3~',
            'database' => 'cake_cms',
            'encoding' => 'utf8mb4',
            'timezone' => 'UTC',
            'cacheMetadata' => true,
        ],
    ],
    // More configuration below.
];

一旦配置好你的 config/app.php 文件以后，你应该看到 ‘CakePHP is able to connect to the database’ 的部分也出现一个绿色厨师帽。

注解

一份默认的 CakePHP 配置文件可在 config/app.default.php 找到。

创建第一个的模型

模型是一个 CakePHP 应用的核心。通过他们，我们能够读取以及修改数据。他们让我们可以将数据关联起来，验证数据以及运用各种业务逻辑。模型是建立控制器的动作 （action） 和 模块（template）的基石。

CakePHP 的模型是由 Table and Entity 两种对象组成。Table 为是一个特定的数据库表的抽象。他们储存在 src/Model/Table 目录中。在本教程中，我们将建立文件 src/Model/Table/ArticlesTable.php。 完成的文件内容如下:

<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;

use Cake\ORM\Table;

class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        $this->addBehavior('Timestamp');
    }
}

我们附属了 Timestamp 行为 （behavior）。此行为将会帮助我们自动填充被附属的数据库表的 created 列 和 modified 列。利用 CakePHP 的命名约定，我们取其名为 ArticlesTable，这样 CakePHP 便可自动找到 articles 数据库表。同样利用命名约定，CakePHP 默认 id 为主键。

注解

如果一个模型的定义文件在 src/Model/Table 目录中缺失， CakePHP 会动态的建立一个模型对象。这代表着，如果我们不小心写错文件名（比如错写成 articlestable.php 或者 ArticleTable.php）， CakePHP 将无法读取你的设置，而是使用动态生成的模型。

我们也需要为 Articles 创建一个 Entity 的类。Entity 是数据库表中单个记录的抽象，它提供数据库行层面的行为。在本教程中，我们将建立文件 src/Model/Entity/Article.php。 完成的文件内容如下:

<?php
// src/Model/Entity/Article.php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Article extends Entity
{
    protected $_accessible = [
        '*' => true,
        'id' => false,
        'slug' => false,
    ];
}

以上的 Entity 目前比较单一，我们仅仅建立了 _accessible 属性。它规定了此类的各种属性的控制规则 entities-mass-assignment。

目前为止，我们的模型都很简单，接下来我们将创建我们的第一个 控制器和模版。

CMS 教案 - 创建 Articles 控制器

在上一节，我们为 articles 数据表创建了模型，现在我们需要为它创建控制器。CakePHP 中的控制器是用来处理 HTTP 请求以及执行封装在模型中的业务逻辑。让我们建立一个叫 ArticlesController.php 的控制器文件，然后把它置于 src/Controller 目录中。一个基本的控制器代码如下:

<?php
// src/Controller/ArticlesController.php

namespace App\Controller;

class ArticlesController extends AppController
{
}

然后让我们为控制器添加一个行为（action）。行为是控制器中的方法，并且他们都与路由相连。比如当用户访问 www.example.com/articles/index （与 www.example.com/articles 是一样的效果），CakePHP 会自动调用 ArticlesController 控制器中的 index 方法。我们需要建立的这个行为应该查询模型层，接着用模版渲染一个视图作为响应。此行为的代码应该看起来如下:

<?php
// src/Controller/ArticlesController.php

namespace App\Controller;

class ArticlesController extends AppController
{
    public function index()
    {
        $this->loadComponent('Paginator');
        $articles = $this->Paginator->paginate($this->Articles->find());
        $this->set(compact('articles'));
    }
}

定义完 ArticlesController 控制器中的 index() 函数以后，用户便可以使用 www.example.com/articles/index 访问了。同理，如果我们定义一个 foobar() 的函数，用户便可以访问 www.example.com/articles/foobar。不要为了实现某些特定的 URLs 来为你的控制器和行为取名。遵循 CakePHP 约定 原则，秉持易读易懂的概念来取名。然后再使用 Routing 连接行为和你想要的 URLs。

至此，我们的控制器行为是非常简单的。它利用 Articles 模型从数据库中读取一组分页后的 articles 数据，然后使用 set() 函数将数据传入模版（将在下部分创建）。CakePHP 将会自动渲染模版。

创建 Article 列表模版

我们的控制器拉取到了数据，为视图做好了准备，让我们为 index 行为创建一个视图模版。

CakePHP 的视图模版是插入应用布局中的演示型 PHP 代码。视图不仅可以实现 HTML，也可以实现 JSON 和 CSV，甚至是二进制文件，比如说 PDF。

布局是用来包装视图的演示代码。布局文件包含常见的网站元素，比如 header, footer 以及其他导航元素。一个应用可以拥有多个布局，使用于不同场景。但是现在让我创建一个默认的布局而已。

模版文件都储存在 src/Template 目录中的一个文件夹中，此文件夹以其对应的控制器命名。所以我们需要创建一个叫做 ‘Articles’ 的文件夹。其代码如下：

<!-- File: src/Template/Articles/index.ctp -->

<h1>Articles</h1>
<table>
    <tr>
        <th>Title</th>
        <th>Created</th>
    </tr>

    <!-- Here is where we iterate through our $articles query object, printing out article info -->

    <?php foreach ($articles as $article): ?>
    <tr>
        <td>
            <?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
        </td>
        <td>
            <?= $article->created->format(DATE_RFC850) ?>
        </td>
    </tr>
    <?php endforeach; ?>
</table>

在上一个章节中，我们使用 set() 方法将 ‘articles’ 注入到了视图中。在以上的代码中，我们可以看到，被注入的变量转化为了视图模版中的本地变量。

你也许注意到我们使用了一个叫做 $this->Html 的对象。它是 CakePHP 中 HtmlHelper 的一个实例。CakePHP 自带一系列的视图助手 (view helper），它们简化了很多任务，比如创建衔接，表单以及分页。你可以在 助件 章节学到更多关于它们的内容，但是在这里，我们需要注意到的是 link() 方法会使用第一个参数作为文字和第二个参数作为 URL 来生产一个 HTML 衔接。

When specifying URLs in CakePHP, it is recommended that you use arrays or named routes. These syntaxes allow you to leverage the reverse routing features CakePHP offers.

在 CakePHP 中生成 URLs 时候，建议使用数组或者 命名路由。使用这些语法，你将可以利用到 CakePHP 的反向路由功能。

至此，在你的浏览其中访问 http://localhost:8765/articles/index，你应该可以看到一个列表视图，主题使用着正确的格式，使用着 table 来排列 articles。

创建 View 动作

如果你点击其中的一个 ‘view’ 衔接，你会看到一个报错页面，提示你 ‘action hasn’t been implemented’. 让我们修复它:

// Add to existing src/Controller/ArticlesController.php file

public function view($slug = null)
{
    $article = $this->Articles->findBySlug($slug)->firstOrFail();
    $this->set(compact('article'));
}

虽然以上是一个很简单的 action，但是我们却可以看到一些 CakePHP 强大的功能。首先我们使用了 findBySlug() 方法，它属于动态 Finder。这个方法容许我们创建一个简单的使用 slug 查询 artciles 的 query。然后我们使用 firstOrFail() 提取第一个记录，或者拋出异常 NotFoundException。

我们的 action 的第一个参数是 $slug，可这个参数的值是如何来的呢？如果一个用户访问 /articles/view/first-post，那么 ‘first-post’ 将会被 CakePHP 的路由以及调度层传入为 action 的参数。保存为文件以后，如果我们重新加载页面，我们将看到另一个新的 CakePHP 报错页面，提示我们 ‘missing a view template’。让我们修复它。

创建视图模版

让我们为 ‘view’ 创建一个视图文件 src/Template/Articles/view.ctp

<!-- File: src/Template/Articles/view.ctp -->

<h1><?= h($article->title) ?></h1>
<p><?= h($article->body) ?></p>
<p><small>Created: <?= $article->created->format(DATE_RFC850) ?></small></p>
<p><?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?></p>

你可以通过浏览 /articles/index 页面或者直接访问 /articles/view/first-post 查看一个 article 来检测视图是否成功。

添加 Artciles

我们已经创建好基本的阅读视图，下一步我们需要实现创建新 articles 的功能。首先让我们在 ArticlesController 中创建一个 action() 的动作。至此我们的控制器代码应该看起来如下:

// src/Controller/ArticlesController.php

namespace App\Controller;

use App\Controller\AppController;

class ArticlesController extends AppController
{

    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Paginator');
        $this->loadComponent('Flash'); // Include the FlashComponent
    }

    public function index()
    {
        $articles = $this->Paginator->paginate($this->Articles->find());
        $this->set(compact('articles'));
    }

    public function view($slug)
    {
        $article = $this->Articles->findBySlug($slug)->firstOrFail();
        $this->set(compact('article'));
    }

    public function add()
    {
        $article = $this->Articles->newEntity();
        if ($this->request->is('post')) {
            $article = $this->Articles->patchEntity($article, $this->request->getData());

            // Hardcoding the user_id is temporary, and will be removed later
            // when we build authentication out.
            $article->user_id = 1;

            if ($this->Articles->save($article)) {
                $this->Flash->success(__('Your article has been saved.'));
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('Unable to add your article.'));
        }
        $this->set('article', $article);
    }
}

注解

如果你需要在控制器中使用 Flash 的组件，你必须要先加载它。通常情况下我们可以在 AppController 中加载它，由于它是一个比较常用的组件。

以下是 add() 行为的功能：

如果 HTTP 请求是 POST,尝试使用 Articles 模型来保存数据。

如果由于任何原因数据没有被保存，直接渲染视图。这样子用户有机会看到验证错误或者其他的警告信息。

每一个 CakePHP 请求包含着一个 request 对象，我们可以通过 $this->request 获取到。这个 request 对象包含着当前的请求的所有信息。我们使用 Cake\Http\ServerRequest::is() 方法检测此次请求是否是一个 HTTP POST请求。

POST 数据可以通过 $this->request->getData() 获取。如果需要检查它里面的数据内容，我们可以通过方法 pr() 或者 debug()。在保存数据之前，我们首先 ‘marshal’ 数据成一个 Article Entity。然后我们使用之前创建的 ArticlesTable 来存储。

保存完以后，我们使用 FlashComponent 的 success() 方法来把提示信息传入 session 中。success 方法是通过 PHP 的 魔术方法 [http://php.net/manual/en/language.oop5.overloading.php#object.call] 实现的. 瞬间提示信息将会在页面跳转以后显示出来。在我们的布局中，我们使用了 <?= $this->Flash->render() ?>，它会将瞬间提示信息显示出来，然后删除其对应的 session 变量。保存完成以后，我们使用 Cake\Controller\Controller::redirect 将用户页面带回 artciles 列表。参数 ['action' => 'index'] 将被翻译为 /articles，也就是 ArticlesController 的 index 行为。参照 API <https://api.cakephp.org> 中的 Cake\Routing\Router::url() 文档来查看 CakePHP 中生成 URL 各种方法的格式。

创建 add 模版

以下是 add 动作对应的视图模版:

<!-- File: src/Template/Articles/add.ctp -->

<h1>Add Article</h1>
<?php
    echo $this->Form->create($article);
    // Hard code the user for now.
    echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => 1]);
    echo $this->Form->control('title');
    echo $this->Form->control('body', ['rows' => '3']);
    echo $this->Form->button(__('Save Article'));
    echo $this->Form->end();
?>

我们使用 FormHelper 来生成 HTML form 的开始标签。以下是 $this->Form->create() 生成的 HTML 代码:

<form method="post" action="/articles/add">

由于我们使用 create() 时没有使用 URL 选项，FormHelper 假设我们需要提交此 form 回当前的动作。

当需要创建同名的表单元素时，我们可以使用 $this->Form->control() 方法。第一个参数告诉 CakePHP 其对应的领域，第二个参数可以让我们指定各式各样的选项 － 在以上代码中，textarea 元素的 rows 的行数。这里有使用到一些内检功能和约定。 control() 将会根据不同的模型领域生产不同的元素，以及使用 inflection 来生成标注文字。你也可以使用选项来定制标注,输入元素以及任何其他 form 的属性。 最后 $this->Form->end() 方法关闭表单.

让我们更新一下 src/Template/Articles/index.ctp 视图，添加一个新的 “Add Article” 的衔接。在 <table> 之前，加入下行代码:

<?= $this->Html->link('Add Article', ['action' => 'add']) ?>

添加简单 slug 生成功能

如果我们现在保存一个 Article, 它将会失败，因为 slug 列应该为 NOT NULL。通常 slug 的值应该是 title 的 URL 安全版本。我们可以使用 ORM 的 beforeSave() 回调 来生成 slug:

// in src/Model/Table/ArticlesTable.php
namespace App\Model\Table;

use Cake\ORM\Table;
// the Text class
use Cake\Utility\Text;

// Add the following method.

public function beforeSave($event, $entity, $options)
{
    if ($entity->isNew() && !$entity->slug) {
        $sluggedTitle = Text::slug($entity->title);
        // trim slug to maximum length defined in schema
        $entity->slug = substr($sluggedTitle, 0, 191);
    }
}

以上的代码是很简陋的，没有考虑到 slug 的重复问题。往下我们会修复它。

添加 edit 动作

现在我们可以保存 articles，但是无法编辑他们。让我们现在完善它。加入一下的动作至 ArticlesController 中:

// in src/Controller/ArticlesController.php

// Add the following method.

public function edit($slug)
{
    $article = $this->Articles->findBySlug($slug)->firstOrFail();
    if ($this->request->is(['post', 'put'])) {
        $this->Articles->patchEntity($article, $this->request->getData());
        if ($this->Articles->save($article)) {
            $this->Flash->success(__('Your article has been updated.'));
            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('Unable to update your article.'));
    }

    $this->set('article', $article);
}

在这个动作中，我们首先保证用户要求的 article 存在。如果 $slug 是空的，或者 article 并不存在，抛出 NotFoundException 异常，然后 CakePHP 的 ErrorHandler 会渲染相对应的错误页面。

接着我们检测此请求是否为 POST 或者 PUT。如果是，我们将使用 patchEntity() 方法以及传入的数据来更新我们的 artcile 模型。最后，我们使用 save() 保存数据，成功将跳转，失败将显示验证错误信息。

创建 edit 模版

以下是 edit 模版代码：

<!-- File: src/Template/Articles/edit.ctp -->

<h1>Edit Article</h1>
<?php
    echo $this->Form->create($article);
    echo $this->Form->control('user_id', ['type' => 'hidden']);
    echo $this->Form->control('title');
    echo $this->Form->control('body', ['rows' => '3']);
    echo $this->Form->button(__('Save Article'));
    echo $this->Form->end();
?>

这个模版将展示一个编辑表单（以及表单元素值），以及必要时的错误验证信息。

现在我们可以更新 index 视图，加入 edit 的衔接。

<!-- File: src/Template/Articles/index.ctp  (edit links added) -->

<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
    <tr>
        <th>Title</th>
        <th>Created</th>
        <th>Action</th>
    </tr>

<!-- Here's where we iterate through our $articles query object, printing out article info -->

<?php foreach ($articles as $article): ?>
    <tr>
        <td>
            <?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
        </td>
        <td>
            <?= $article->created->format(DATE_RFC850) ?>
        </td>
        <td>
            <?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
        </td>
    </tr>
<?php endforeach; ?>

</table>

更新验证规则

到现在为止，我们都没有使用任何的输入验证。让我们使用 验证器 来完善:

// src/Model/Table/ArticlesTable.php

// add this use statement right below the namespace declaration to import
// the Validator class
use Cake\Validation\Validator;

// Add the following method.
public function validationDefault(Validator $validator)
{
    $validator
        ->notEmpty('title')
        ->minLength('title', 10)
        ->maxLength('title', 255)

        ->notEmpty('body')
        ->minLength('body', 10);

    return $validator;
}

当 CakePHP 调用 save() 时，validationDefault() 方法将指示如何验证数据。在以上代码中，我们规定 title 和 body 不可以为空，而且必须要达到一定的长度。

CakePHP 的验证器很强大也很灵活。它提供了一些常用的规则，比如邮箱地址，IP 地址等等。此外，你也可以灵活地加入自定的规则。参考 Validation 文档可了解如何自定义验证规则。

现在我们部署好了验证规则，你可以尝试着使用空 title 或者 body 来测试。由于我们使用了 FormHelper 的 Cake\View\Helper\FormHelper::control() 来创建表单元素，你会发现验证错误信息回自动的呈现出来。

添加 delete 行为

接下来我们要实现一个功能可以让用户删除 artciles。首先添加一个 delete() 行为到 ArticlesController 中:

// src/Controller/ArticlesController.php

public function delete($slug)
{
    $this->request->allowMethod(['post', 'delete']);

    $article = $this->Articles->findBySlug($slug)->firstOrFail();
    if ($this->Articles->delete($article)) {
        $this->Flash->success(__('The {0} article has been deleted.', $article->title));
        return $this->redirect(['action' => 'index']);
    }
}

以上的代码逻辑将会使用规定的 $slug 来删除指定 article，跳转页面至 /articles，然后使用 $this->Flash->success() 呈现一条确认信息。如果用户尝试用 GET 请求，allowMethod() 将会抛出异常。未捕获的异常将被 CakePHP 内核的异常处理器捕获，自带的错误页面将被展示出来。CakePHP 自带很多 异常 ，我们可以使用它们来响应不同的 HTTP 错误。

警告

允许 GET 请求删除内容是 很 危险的，这种做法可能导致爬虫不小心删除所有的内容。这就是我们在控制器中使用 allowMethod() 的原因。

由于我们只是运行了一段逻辑然后跳转到另一个动作，此处不需要模版。让我们更新下 index 模版，加入 delete 的衔接:

<!-- File: src/Template/Articles/index.ctp  (delete links added) -->

<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
    <tr>
        <th>Title</th>
        <th>Created</th>
        <th>Action</th>
    </tr>

<!-- Here's where we iterate through our $articles query object, printing out article info -->

<?php foreach ($articles as $article): ?>
    <tr>
        <td>
            <?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
        </td>
        <td>
            <?= $article->created->format(DATE_RFC850) ?>
        </td>
        <td>
            <?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
            <?= $this->Form->postLink(
                'Delete',
                ['action' => 'delete', $article->slug],
                ['confirm' => 'Are you sure?'])
            ?>
        </td>
    </tr>
<?php endforeach; ?>

</table>

此处我们使用了 View\Helper\FormHelper::postLink() 来创建一个衔接，此衔接将会用 JavaScript 来建立一个 POST 的请求。

注解

This view code also uses the FormHelper to prompt the user with a JavaScript confirmation dialog before they attempt to delete an article.

With a basic articles management setup, we’ll create the basic actions for our Tags and Users tables.

基于我们现在创立的 articles 管理系统，下一节我们的任务是 操作 Tags 和 Users 表单

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.0 Migration Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

教程以及范例

你可以翻阅此章节来了解典型的 CakePHP 应用是如何搭建起来的。

另外你也可以借阅非官方的 CakePHP 插件库 CakePackages [https://plugins.cakephp.org/] 和 Bakery [https://bakery.cakephp.org/]。这些站点提供成型的应用以及组件。

內容管理系統教程

CMS 教程 － 创建数据库

CMS 教案 - 创建 Articles 控制器

CMS 教程 － Tags 和 Users

CMS 教案 - 认证

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

內容管理系統教程

此教程将讲述如何建立一个简单的 CMS。 首先我们需要安装 CakePHP，然后创建数据库，最后编写一个简单的文章管理系统。

基本要求：

一个数据库服务器。此教程采用的是 MySQL 作为数据库。你需要储备基本的 SQL 知识。懂得如何使用 SQL 建立数据库以及执行教程中的各种 SQL 片段。 CakePHP 可自动构造你的应用所需的各种查询语句。 由于此教程使用的是 MySQL, 请确定 PHP 的 pdo_mysql 已经启用。

基本的 PHP 知识。

在开始之前，请确保你的 PHP 已经更新。

php -v

你至少需要安装 PHP （命令行界面）版本 5.6 以上。网路服务器的 PHP 需要和命令行界面版本一致，保证 5.6 以上。

安装 CakePHP

使用 Composer 是安装 CakePHP 最简单的方法。Composer 是通过终端或者命令行提示符安装 CakePHP 的一种简易方式。首先，你需要下载和安装 Composer。你可以通过 cURL，然后执行以下语句来安装：

curl -s https://getcomposer.org/installer | php

或者你也可以从 Composer 官网 [https://getcomposer.org/download/] 直接下载 composer.phar。

然后在同一个目录中，运行以下语句来安装 CakePHP 的应用骨架，此应用将会建立在一个 cms 的目录中：

php composer.phar create-project --prefer-dist cakephp/app:^3.8 cms

如果你是下载使用的 Composer Windows Installer [https://getcomposer.org/Composer-Setup.exe]，在同一个目录中（比如 C:\wamp\www\dev\cakephp3）终端运行以下语句：

composer self-update && composer create-project --prefer-dist cakephp/app:^3.8 cms

使用 Composer 的优势是它会自动完成一些重要的设置任务，比如建立合适的文件权限以及建立配置文件

config/app.php。

当然 CakePHP 也提供其他的安装方式。如果你不能或者不想使用 Composer 的话，请查看 安装 章节。

不管你是以何种方式下载和安装,你的目录应该都会是以下形式:

/cms
  /bin
  /config
  /logs
  /plugins
  /src
  /tests
  /tmp
  /vendor
  /webroot
  .editorconfig
  .gitignore
  .htaccess
  .travis.yml
  composer.json
  index.php
  phpunit.xml.dist
  README.md

事不宜迟，现在是学习 CakePHP 目录结构的合适时机： 请查看 CakePHP 的文件夹结构 章节。

如果你没有跟上此教程的速度，你可以参考下此教程的 成品代码 [https://github.com/cakephp/cms-tutorial].

检查安装

你可以通过访问默认的主页的来检查安装是否成功。当然首先我们需要启动开发服务器：

cd /path/to/our/app

bin/cake server

注解

Windows 用户，需使用 bin\cake server （使用反斜线）

PHP 自带的网络服务器将在 8765 端口启动。在浏览器中访问 http://localhost:8765，你应该会看到欢迎页面。除了 ”CakePHP being able to connect to your database“ 没有绿色厨师帽以后，其余的要点都应有。如果不是这样的话，你可能需要安装一些缺失的 PHP 扩展，或者是建立正确的目录权限。

接下来，我们将创立我们的 数据库以及创建第一个模型.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CMS 教程 － 创建数据库

CakePHP 已经安装好，我们可以开始为 CMS 应用建立数据库了。首先建立一个空的数据库，你可以使用任意的名字，比如 cake_cms。执行以下 SQL 语句来建立需要的数据库表:

USE cake_cms;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created DATETIME,
    modified DATETIME
);

CREATE TABLE articles (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(191) NOT NULL,
    body TEXT,
    published BOOLEAN DEFAULT FALSE,
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (slug),
    FOREIGN KEY user_key (user_id) REFERENCES users(id)
) CHARSET=utf8mb4;

CREATE TABLE tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(191),
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (title)
) CHARSET=utf8mb4;

CREATE TABLE articles_tags (
    article_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (article_id, tag_id),
    FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
    FOREIGN KEY article_key(article_id) REFERENCES articles(id)
);

INSERT INTO users (email, password, created, modified)
VALUES
('cakephp@example.com', 'secret', NOW(), NOW());

INSERT INTO articles (user_id, title, slug, body, published, created, modified)
VALUES
(1, 'First Post', 'first-post', 'This is the first post.', 1, now(), now());

你也许已经注意到 articles_tags 表使用了复合主键。CakePHP 几乎支持所有的复合主键，这样便于你使用比较简单的数据库结构，不用添加额外的 id 列。

以上所使用的数据表名以及列名都不是随意的。利用 CakePHP 的 命名约定，我们可以更有效的使用并且避免了配置框架的需要。虽然 CakePHP 的灵活度可以容纳几乎所有的数据库结构，但是采取约定，利用 CakePHP 提供的默认的约定可以节省你很多的开发时间，

数据库配置

接着我们需要告诉 CakePHP 我们之前创建的数据库地址以及如何连接。在 config/app.php 文件中，找到 Datasources.default 数组，更改为相对应的值。以下的例子是一个完整的配置数组:

<?php
return [
    // More configuration above.
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql',
            'persistent' => false,
            'host' => 'localhost',
            'username' => 'cakephp',
            'password' => 'AngelF00dC4k3~',
            'database' => 'cake_cms',
            'encoding' => 'utf8mb4',
            'timezone' => 'UTC',
            'cacheMetadata' => true,
        ],
    ],
    // More configuration below.
];

一旦配置好你的 config/app.php 文件以后，你应该看到 ‘CakePHP is able to connect to the database’ 的部分也出现一个绿色厨师帽。

注解

一份默认的 CakePHP 配置文件可在 config/app.default.php 找到。

创建第一个的模型

模型是一个 CakePHP 应用的核心。通过他们，我们能够读取以及修改数据。他们让我们可以将数据关联起来，验证数据以及运用各种业务逻辑。模型是建立控制器的动作 （action） 和 模块（template）的基石。

CakePHP 的模型是由 Table and Entity 两种对象组成。Table 为是一个特定的数据库表的抽象。他们储存在 src/Model/Table 目录中。在本教程中，我们将建立文件 src/Model/Table/ArticlesTable.php。 完成的文件内容如下:

<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;

use Cake\ORM\Table;

class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        $this->addBehavior('Timestamp');
    }
}

我们附属了 Timestamp 行为 （behavior）。此行为将会帮助我们自动填充被附属的数据库表的 created 列 和 modified 列。利用 CakePHP 的命名约定，我们取其名为 ArticlesTable，这样 CakePHP 便可自动找到 articles 数据库表。同样利用命名约定，CakePHP 默认 id 为主键。

注解

如果一个模型的定义文件在 src/Model/Table 目录中缺失， CakePHP 会动态的建立一个模型对象。这代表着，如果我们不小心写错文件名（比如错写成 articlestable.php 或者 ArticleTable.php）， CakePHP 将无法读取你的设置，而是使用动态生成的模型。

我们也需要为 Articles 创建一个 Entity 的类。Entity 是数据库表中单个记录的抽象，它提供数据库行层面的行为。在本教程中，我们将建立文件 src/Model/Entity/Article.php。 完成的文件内容如下:

<?php
// src/Model/Entity/Article.php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Article extends Entity
{
    protected $_accessible = [
        '*' => true,
        'id' => false,
        'slug' => false,
    ];
}

以上的 Entity 目前比较单一，我们仅仅建立了 _accessible 属性。它规定了此类的各种属性的控制规则 entities-mass-assignment。

目前为止，我们的模型都很简单，接下来我们将创建我们的第一个 控制器和模版。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CMS 教案 - 创建 Articles 控制器

在上一节，我们为 articles 数据表创建了模型，现在我们需要为它创建控制器。CakePHP 中的控制器是用来处理 HTTP 请求以及执行封装在模型中的业务逻辑。让我们建立一个叫 ArticlesController.php 的控制器文件，然后把它置于 src/Controller 目录中。一个基本的控制器代码如下:

<?php
// src/Controller/ArticlesController.php

namespace App\Controller;

class ArticlesController extends AppController
{
}

然后让我们为控制器添加一个行为（action）。行为是控制器中的方法，并且他们都与路由相连。比如当用户访问 www.example.com/articles/index （与 www.example.com/articles 是一样的效果），CakePHP 会自动调用 ArticlesController 控制器中的 index 方法。我们需要建立的这个行为应该查询模型层，接着用模版渲染一个视图作为响应。此行为的代码应该看起来如下:

<?php
// src/Controller/ArticlesController.php

namespace App\Controller;

class ArticlesController extends AppController
{
    public function index()
    {
        $this->loadComponent('Paginator');
        $articles = $this->Paginator->paginate($this->Articles->find());
        $this->set(compact('articles'));
    }
}

定义完 ArticlesController 控制器中的 index() 函数以后，用户便可以使用 www.example.com/articles/index 访问了。同理，如果我们定义一个 foobar() 的函数，用户便可以访问 www.example.com/articles/foobar。不要为了实现某些特定的 URLs 来为你的控制器和行为取名。遵循 CakePHP 约定 原则，秉持易读易懂的概念来取名。然后再使用 Routing 连接行为和你想要的 URLs。

至此，我们的控制器行为是非常简单的。它利用 Articles 模型从数据库中读取一组分页后的 articles 数据，然后使用 set() 函数将数据传入模版（将在下部分创建）。CakePHP 将会自动渲染模版。

创建 Article 列表模版

我们的控制器拉取到了数据，为视图做好了准备，让我们为 index 行为创建一个视图模版。

CakePHP 的视图模版是插入应用布局中的演示型 PHP 代码。视图不仅可以实现 HTML，也可以实现 JSON 和 CSV，甚至是二进制文件，比如说 PDF。

布局是用来包装视图的演示代码。布局文件包含常见的网站元素，比如 header, footer 以及其他导航元素。一个应用可以拥有多个布局，使用于不同场景。但是现在让我创建一个默认的布局而已。

模版文件都储存在 src/Template 目录中的一个文件夹中，此文件夹以其对应的控制器命名。所以我们需要创建一个叫做 ‘Articles’ 的文件夹。其代码如下：

<!-- File: src/Template/Articles/index.ctp -->

<h1>Articles</h1>
<table>
    <tr>
        <th>Title</th>
        <th>Created</th>
    </tr>

    <!-- Here is where we iterate through our $articles query object, printing out article info -->

    <?php foreach ($articles as $article): ?>
    <tr>
        <td>
            <?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
        </td>
        <td>
            <?= $article->created->format(DATE_RFC850) ?>
        </td>
    </tr>
    <?php endforeach; ?>
</table>

在上一个章节中，我们使用 set() 方法将 ‘articles’ 注入到了视图中。在以上的代码中，我们可以看到，被注入的变量转化为了视图模版中的本地变量。

你也许注意到我们使用了一个叫做 $this->Html 的对象。它是 CakePHP 中 HtmlHelper 的一个实例。CakePHP 自带一系列的视图助手 (view helper），它们简化了很多任务，比如创建衔接，表单以及分页。你可以在 助件 章节学到更多关于它们的内容，但是在这里，我们需要注意到的是 link() 方法会使用第一个参数作为文字和第二个参数作为 URL 来生产一个 HTML 衔接。

When specifying URLs in CakePHP, it is recommended that you use arrays or named routes. These syntaxes allow you to leverage the reverse routing features CakePHP offers.

在 CakePHP 中生成 URLs 时候，建议使用数组或者 命名路由。使用这些语法，你将可以利用到 CakePHP 的反向路由功能。

至此，在你的浏览其中访问 http://localhost:8765/articles/index，你应该可以看到一个列表视图，主题使用着正确的格式，使用着 table 来排列 articles。

创建 View 动作

如果你点击其中的一个 ‘view’ 衔接，你会看到一个报错页面，提示你 ‘action hasn’t been implemented’. 让我们修复它:

// Add to existing src/Controller/ArticlesController.php file

public function view($slug = null)
{
    $article = $this->Articles->findBySlug($slug)->firstOrFail();
    $this->set(compact('article'));
}

虽然以上是一个很简单的 action，但是我们却可以看到一些 CakePHP 强大的功能。首先我们使用了 findBySlug() 方法，它属于动态 Finder。这个方法容许我们创建一个简单的使用 slug 查询 artciles 的 query。然后我们使用 firstOrFail() 提取第一个记录，或者拋出异常 NotFoundException。

我们的 action 的第一个参数是 $slug，可这个参数的值是如何来的呢？如果一个用户访问 /articles/view/first-post，那么 ‘first-post’ 将会被 CakePHP 的路由以及调度层传入为 action 的参数。保存为文件以后，如果我们重新加载页面，我们将看到另一个新的 CakePHP 报错页面，提示我们 ‘missing a view template’。让我们修复它。

创建视图模版

让我们为 ‘view’ 创建一个视图文件 src/Template/Articles/view.ctp

<!-- File: src/Template/Articles/view.ctp -->

<h1><?= h($article->title) ?></h1>
<p><?= h($article->body) ?></p>
<p><small>Created: <?= $article->created->format(DATE_RFC850) ?></small></p>
<p><?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?></p>

你可以通过浏览 /articles/index 页面或者直接访问 /articles/view/first-post 查看一个 article 来检测视图是否成功。

添加 Artciles

我们已经创建好基本的阅读视图，下一步我们需要实现创建新 articles 的功能。首先让我们在 ArticlesController 中创建一个 action() 的动作。至此我们的控制器代码应该看起来如下:

// src/Controller/ArticlesController.php

namespace App\Controller;

use App\Controller\AppController;

class ArticlesController extends AppController
{

    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Paginator');
        $this->loadComponent('Flash'); // Include the FlashComponent
    }

    public function index()
    {
        $articles = $this->Paginator->paginate($this->Articles->find());
        $this->set(compact('articles'));
    }

    public function view($slug)
    {
        $article = $this->Articles->findBySlug($slug)->firstOrFail();
        $this->set(compact('article'));
    }

    public function add()
    {
        $article = $this->Articles->newEntity();
        if ($this->request->is('post')) {
            $article = $this->Articles->patchEntity($article, $this->request->getData());

            // Hardcoding the user_id is temporary, and will be removed later
            // when we build authentication out.
            $article->user_id = 1;

            if ($this->Articles->save($article)) {
                $this->Flash->success(__('Your article has been saved.'));
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('Unable to add your article.'));
        }
        $this->set('article', $article);
    }
}

注解

如果你需要在控制器中使用 Flash 的组件，你必须要先加载它。通常情况下我们可以在 AppController 中加载它，由于它是一个比较常用的组件。

以下是 add() 行为的功能：

如果 HTTP 请求是 POST,尝试使用 Articles 模型来保存数据。

如果由于任何原因数据没有被保存，直接渲染视图。这样子用户有机会看到验证错误或者其他的警告信息。

每一个 CakePHP 请求包含着一个 request 对象，我们可以通过 $this->request 获取到。这个 request 对象包含着当前的请求的所有信息。我们使用 Cake\Http\ServerRequest::is() 方法检测此次请求是否是一个 HTTP POST请求。

POST 数据可以通过 $this->request->getData() 获取。如果需要检查它里面的数据内容，我们可以通过方法 pr() 或者 debug()。在保存数据之前，我们首先 ‘marshal’ 数据成一个 Article Entity。然后我们使用之前创建的 ArticlesTable 来存储。

保存完以后，我们使用 FlashComponent 的 success() 方法来把提示信息传入 session 中。success 方法是通过 PHP 的 魔术方法 [http://php.net/manual/en/language.oop5.overloading.php#object.call] 实现的. 瞬间提示信息将会在页面跳转以后显示出来。在我们的布局中，我们使用了 <?= $this->Flash->render() ?>，它会将瞬间提示信息显示出来，然后删除其对应的 session 变量。保存完成以后，我们使用 Cake\Controller\Controller::redirect 将用户页面带回 artciles 列表。参数 ['action' => 'index'] 将被翻译为 /articles，也就是 ArticlesController 的 index 行为。参照 API <https://api.cakephp.org> 中的 Cake\Routing\Router::url() 文档来查看 CakePHP 中生成 URL 各种方法的格式。

创建 add 模版

以下是 add 动作对应的视图模版:

<!-- File: src/Template/Articles/add.ctp -->

<h1>Add Article</h1>
<?php
    echo $this->Form->create($article);
    // Hard code the user for now.
    echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => 1]);
    echo $this->Form->control('title');
    echo $this->Form->control('body', ['rows' => '3']);
    echo $this->Form->button(__('Save Article'));
    echo $this->Form->end();
?>

我们使用 FormHelper 来生成 HTML form 的开始标签。以下是 $this->Form->create() 生成的 HTML 代码:

<form method="post" action="/articles/add">

由于我们使用 create() 时没有使用 URL 选项，FormHelper 假设我们需要提交此 form 回当前的动作。

当需要创建同名的表单元素时，我们可以使用 $this->Form->control() 方法。第一个参数告诉 CakePHP 其对应的领域，第二个参数可以让我们指定各式各样的选项 － 在以上代码中，textarea 元素的 rows 的行数。这里有使用到一些内检功能和约定。 control() 将会根据不同的模型领域生产不同的元素，以及使用 inflection 来生成标注文字。你也可以使用选项来定制标注,输入元素以及任何其他 form 的属性。 最后 $this->Form->end() 方法关闭表单.

让我们更新一下 src/Template/Articles/index.ctp 视图，添加一个新的 “Add Article” 的衔接。在 <table> 之前，加入下行代码:

<?= $this->Html->link('Add Article', ['action' => 'add']) ?>

添加简单 slug 生成功能

如果我们现在保存一个 Article, 它将会失败，因为 slug 列应该为 NOT NULL。通常 slug 的值应该是 title 的 URL 安全版本。我们可以使用 ORM 的 beforeSave() 回调 来生成 slug:

// in src/Model/Table/ArticlesTable.php
namespace App\Model\Table;

use Cake\ORM\Table;
// the Text class
use Cake\Utility\Text;

// Add the following method.

public function beforeSave($event, $entity, $options)
{
    if ($entity->isNew() && !$entity->slug) {
        $sluggedTitle = Text::slug($entity->title);
        // trim slug to maximum length defined in schema
        $entity->slug = substr($sluggedTitle, 0, 191);
    }
}

以上的代码是很简陋的，没有考虑到 slug 的重复问题。往下我们会修复它。

添加 edit 动作

现在我们可以保存 articles，但是无法编辑他们。让我们现在完善它。加入一下的动作至 ArticlesController 中:

// in src/Controller/ArticlesController.php

// Add the following method.

public function edit($slug)
{
    $article = $this->Articles->findBySlug($slug)->firstOrFail();
    if ($this->request->is(['post', 'put'])) {
        $this->Articles->patchEntity($article, $this->request->getData());
        if ($this->Articles->save($article)) {
            $this->Flash->success(__('Your article has been updated.'));
            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('Unable to update your article.'));
    }

    $this->set('article', $article);
}

在这个动作中，我们首先保证用户要求的 article 存在。如果 $slug 是空的，或者 article 并不存在，抛出 NotFoundException 异常，然后 CakePHP 的 ErrorHandler 会渲染相对应的错误页面。

接着我们检测此请求是否为 POST 或者 PUT。如果是，我们将使用 patchEntity() 方法以及传入的数据来更新我们的 artcile 模型。最后，我们使用 save() 保存数据，成功将跳转，失败将显示验证错误信息。

创建 edit 模版

以下是 edit 模版代码：

<!-- File: src/Template/Articles/edit.ctp -->

<h1>Edit Article</h1>
<?php
    echo $this->Form->create($article);
    echo $this->Form->control('user_id', ['type' => 'hidden']);
    echo $this->Form->control('title');
    echo $this->Form->control('body', ['rows' => '3']);
    echo $this->Form->button(__('Save Article'));
    echo $this->Form->end();
?>

这个模版将展示一个编辑表单（以及表单元素值），以及必要时的错误验证信息。

现在我们可以更新 index 视图，加入 edit 的衔接。

<!-- File: src/Template/Articles/index.ctp  (edit links added) -->

<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
    <tr>
        <th>Title</th>
        <th>Created</th>
        <th>Action</th>
    </tr>

<!-- Here's where we iterate through our $articles query object, printing out article info -->

<?php foreach ($articles as $article): ?>
    <tr>
        <td>
            <?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
        </td>
        <td>
            <?= $article->created->format(DATE_RFC850) ?>
        </td>
        <td>
            <?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
        </td>
    </tr>
<?php endforeach; ?>

</table>

更新验证规则

到现在为止，我们都没有使用任何的输入验证。让我们使用 验证器 来完善:

// src/Model/Table/ArticlesTable.php

// add this use statement right below the namespace declaration to import
// the Validator class
use Cake\Validation\Validator;

// Add the following method.
public function validationDefault(Validator $validator)
{
    $validator
        ->notEmpty('title')
        ->minLength('title', 10)
        ->maxLength('title', 255)

        ->notEmpty('body')
        ->minLength('body', 10);

    return $validator;
}

当 CakePHP 调用 save() 时，validationDefault() 方法将指示如何验证数据。在以上代码中，我们规定 title 和 body 不可以为空，而且必须要达到一定的长度。

CakePHP 的验证器很强大也很灵活。它提供了一些常用的规则，比如邮箱地址，IP 地址等等。此外，你也可以灵活地加入自定的规则。参考 Validation 文档可了解如何自定义验证规则。

现在我们部署好了验证规则，你可以尝试着使用空 title 或者 body 来测试。由于我们使用了 FormHelper 的 Cake\View\Helper\FormHelper::control() 来创建表单元素，你会发现验证错误信息回自动的呈现出来。

添加 delete 行为

接下来我们要实现一个功能可以让用户删除 artciles。首先添加一个 delete() 行为到 ArticlesController 中:

// src/Controller/ArticlesController.php

public function delete($slug)
{
    $this->request->allowMethod(['post', 'delete']);

    $article = $this->Articles->findBySlug($slug)->firstOrFail();
    if ($this->Articles->delete($article)) {
        $this->Flash->success(__('The {0} article has been deleted.', $article->title));
        return $this->redirect(['action' => 'index']);
    }
}

以上的代码逻辑将会使用规定的 $slug 来删除指定 article，跳转页面至 /articles，然后使用 $this->Flash->success() 呈现一条确认信息。如果用户尝试用 GET 请求，allowMethod() 将会抛出异常。未捕获的异常将被 CakePHP 内核的异常处理器捕获，自带的错误页面将被展示出来。CakePHP 自带很多 异常 ，我们可以使用它们来响应不同的 HTTP 错误。

警告

允许 GET 请求删除内容是 很 危险的，这种做法可能导致爬虫不小心删除所有的内容。这就是我们在控制器中使用 allowMethod() 的原因。

由于我们只是运行了一段逻辑然后跳转到另一个动作，此处不需要模版。让我们更新下 index 模版，加入 delete 的衔接:

<!-- File: src/Template/Articles/index.ctp  (delete links added) -->

<h1>Articles</h1>
<p><?= $this->Html->link("Add Article", ['action' => 'add']) ?></p>
<table>
    <tr>
        <th>Title</th>
        <th>Created</th>
        <th>Action</th>
    </tr>

<!-- Here's where we iterate through our $articles query object, printing out article info -->

<?php foreach ($articles as $article): ?>
    <tr>
        <td>
            <?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
        </td>
        <td>
            <?= $article->created->format(DATE_RFC850) ?>
        </td>
        <td>
            <?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
            <?= $this->Form->postLink(
                'Delete',
                ['action' => 'delete', $article->slug],
                ['confirm' => 'Are you sure?'])
            ?>
        </td>
    </tr>
<?php endforeach; ?>

</table>

此处我们使用了 View\Helper\FormHelper::postLink() 来创建一个衔接，此衔接将会用 JavaScript 来建立一个 POST 的请求。

注解

This view code also uses the FormHelper to prompt the user with a JavaScript confirmation dialog before they attempt to delete an article.

With a basic articles management setup, we’ll create the basic actions for our Tags and Users tables.

基于我们现在创立的 articles 管理系统，下一节我们的任务是 操作 Tags 和 Users 表单

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CMS 教程 － Tags 和 Users

我们已经完成了管理 article 的基本功能，接下来我们将允许多位用户使用这个 CMS。在此之前我们都是手动创建的所有模型，视图以及控制器。这一次我们将使用 Bake Console 来生成骨架代码。Bake 是一个很强大的 CLI 代码生成工具，他利用 CakePHP 的约定有效地生成 CRUD 应用。在这一章节，我们将使用 bake 来为 users 创建代码：

cd /path/to/our/app

bin/cake bake model users
bin/cake bake controller users
bin/cake bake template users

以上3个命令将生成：

Table, Entity, Fixture 文件.

控制器。

CRUD 模版。

以上类的测试用例。

Bake 也会使用 CakePHP 约定来推断模型之间的关系以及模型的验证规则。

添加标签至 Articles

我们小巧的 CMS 可允许多用户，如果可以给内容分类会是一个很棒的功能。我们将使用标签来让用户创建任何的类以便标记他们的创作。我们将再一次地使用 bake 来快速的生成一些骨架代码：

# Generate all the code at once.
bin/cake bake all tags

以上脚手架代码创建以后，打开 http://localhost:8765/tags/add 添加一些简单的标签。

表单 tags 创建好了，我们可以建立 articles 和 tags 之间的关联。添加以下的代码至 ArticlesTable 的 initialize 方法中:

public function initialize(array $config)
{
    $this->addBehavior('Timestamp');
    $this->belongsToMany('Tags'); // 加入此行
}

之所以我们可以用一行代码来实现这种关联是因为我们遵守了 CakePHP 的约定来创建我们的表单。更多详情，可见 Associations - Linking Tables Together。

启用标记功能

现在我们的应用有了标签，让我们给予用户 articles 标记功能。首先，更新 add 行为如下:

// in src/Controller/ArticlesController.php

namespace App\Controller;

use App\Controller\AppController;

class ArticlesController extends AppController
{
    public function add()
    {
        $article = $this->Articles->newEntity();
        if ($this->request->is('post')) {
            $article = $this->Articles->patchEntity($article, $this->request->getData());

            // Hardcoding the user_id is temporary, and will be removed later
            // when we build authentication out.
            $article->user_id = 1;

            if ($this->Articles->save($article)) {
                $this->Flash->success(__('Your article has been saved.'));
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('Unable to add your article.'));
        }
        // Get a list of tags.
        $tags = $this->Articles->Tags->find('list');

        // Set tags to the view context
        $this->set('tags', $tags);

        $this->set('article', $article);
    }

    // Other actions
}

添加的几行代码将标签列表作为关联数组 id => title 加载。这种格式能够让我们在模板中创建一个新的标签输入。加入以下代码至 src/Template/Articles/add.ctp 来实现新的标签输入:

echo $this->Form->control('tags._ids', ['options' => $tags]);

以下代码将会渲染一个多选的 select 选择器，并使用变量 $tags 来生成其选项。现在我们可以添加一些有标签的 articles，因为往下我们将加入使用标签搜索 articles 的功能。

你也需要更新 edit，以便其可以添加和更新标签。更新后代码看起来如下:

public function edit($slug)
{
    $article = $this->Articles
        ->findBySlug($slug)
        ->contain('Tags') // load associated Tags
        ->firstOrFail();
    if ($this->request->is(['post', 'put'])) {
        $this->Articles->patchEntity($article, $this->request->getData());
        if ($this->Articles->save($article)) {
            $this->Flash->success(__('Your article has been updated.'));
            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('Unable to update your article.'));
    }

    // Get a list of tags.
    $tags = $this->Articles->Tags->find('list');

    // Set tags to the view context
    $this->set('tags', $tags);

    $this->set('article', $article);
}

记住参照 add.ctp 来添加多选的 select 选择器至 src/Template/Articles/edit.ctp 模版中。

使用标签搜寻 articles

既然用户可以将内容分类了，他们肯定会需要使用标签来搜寻内容。我们将利用路由，控制器行为以及模型的 finder 方法来实现这个功能。

我们需要实现一个 URL http://localhost:8765/articles/tagged/funny/cat/gifs, 它将搜索并展示出所有带 ‘funny’, ‘cat’ 或者 ‘gifs’ 标签的 articles。首先我们需要加入一个新的路由。更新后的 config/routes.php 文件应该如下:

<?php
use Cake\Core\Plugin;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\Router;

Router::defaultRouteClass(DashedRoute::class);

// New route we're adding for our tagged action.
// The trailing `*` tells CakePHP that this action has
// passed parameters.
Router::scope(
    '/articles',
    ['controller' => 'Articles'],
    function ($routes) {
        $routes->connect('/tagged/*', ['action' => 'tags']);
    }
);

Router::scope('/', function ($routes) {
    // Connect the default home and /pages/* routes.
    $routes->connect('/', [
        'controller' => 'Pages',
        'action' => 'display', 'home'
    ]);
    $routes->connect('/pages/*', [
        'controller' => 'Pages',
        'action' => 'display'
    ]);

    // Connect the conventions based default routes.
    $routes->fallbacks();
});

Plugin::routes();

新添加的路由将路径 /articles/tagged/ 与 ArticlesController::tags() 行为关联了起来。通过定义路由，我们可以将 URLs 的展现形式和实现方法独立开。现在访问 http://localhost:8765/articles/tagged 的话，CakePHP 将渲染一个自带的错误页面并提醒你控制器的某行为不存在。让我们现在就实现缺失的行为。在 src/Controller/ArticlesController.php 中加入以下代码:

public function tags()
{
    // The 'pass' key is provided by CakePHP and contains all
    // the passed URL path segments in the request.
    $tags = $this->request->getParam('pass');

    // Use the ArticlesTable to find tagged articles.
    $articles = $this->Articles->find('tagged', [
        'tags' => $tags
    ]);

    // Pass variables into the view template context.
    $this->set([
        'articles' => $articles,
        'tags' => $tags
    ]);
}

获取请求中的其他数据，请参考 cake-request 章节。

由于参数是通过方法参数传入，我们也可以使用 PHP 的变长参数函数:

public function tags(...$tags)
{
    // Use the ArticlesTable to find tagged articles.
    $articles = $this->Articles->find('tagged', [
        'tags' => $tags
    ]);

    // Pass variables into the view template context.
    $this->set([
        'articles' => $articles,
        'tags' => $tags
    ]);
}

创建 finder 方法

在 CakePHP 中，我们提倡胖模型，瘦控制器。现在访问 /articles/tagged 的话，你将看到一条错误信息，提示 findTagged() 方法缺失。在 src/Model/Table/ArticlesTable.php 加入以下代码:

// add this use statement right below the namespace declaration to import
// the Query class
use Cake\ORM\Query;

// The $query argument is a query builder instance.
// The $options array will contain the 'tags' option we passed
// to find('tagged') in our controller action.
public function findTagged(Query $query, array $options)
{
    $columns = [
        'Articles.id', 'Articles.user_id', 'Articles.title',
        'Articles.body', 'Articles.published', 'Articles.created',
        'Articles.slug',
    ];

    $query = $query
        ->select($columns)
        ->distinct($columns);

    if (empty($options['tags'])) {
        // If there are no tags provided, find articles that have no tags.
        $query->leftJoinWith('Tags')
            ->where(['Tags.title IS' => null]);
    } else {
        // Find articles that have one or more of the provided tags.
        $query->innerJoinWith('Tags')
            ->where(['Tags.title IN' => $options['tags']]);
    }

    return $query->group(['Articles.id']);
}

以上我们运用到了 自定义 finder 方法。这是一个很强大的 CakePHP 功能,通过它，你可以将可重复使用的查询语句打包。Finder 方法的第一个参数为 Query Builder 对象，第二个参数为一个选项数组。Finder 方法可以操作 query 并添加需要的条件或标准，最后它必须返回一个 query 对象。在我们以上的自定义 finder 中， 我们使用了 distinct() and leftJoin() 方法来搜寻标有指定标签的不同的 article。

创建视图

现在访问 /articles/tagged，你将会看到一个新的报错页面，提醒你还没有建立视图文件。让我们完成它。在 src/Template/Articles/tags.ctp 加入以下内容:

<h1>
    Articles tagged with
    <?= $this->Text->toList(h($tags), 'or') ?>
</h1>

<section>
<?php foreach ($articles as $article): ?>
    <article>
        <!-- Use the HtmlHelper to create a link -->
        <h4><?= $this->Html->link(
            $article->title,
            ['controller' => 'Articles', 'action' => 'view', $article->slug]
        ) ?></h4>
        <span><?= h($article->created) ?>
    </article>
<?php endforeach; ?>
</section>

我们使用了 Html 和 Text 来帮助生成视图内容。我们还使用了 h 来编码 HTML 内容。h() 能够帮助我们防止 HTML 注入。

以上创建的 tags.ctp 文件遵循 CakePHP 的视图约定。此约定要求视图文件名使用小写字母和下划线格式的控制器行为名。

我们可以在视图模版中使用 $tags and $articles 变量，这是因为当我们在控制器中使用了 set() 方法将变量传入视图中。视图将会把传入的变量变成局部变量。

现在访问 /articles/tagged/funny 将可以看到所有带 ‘funny’ 标签的 articles。

改善标示功能

目前添加标签有点麻烦，因为用户需要事先创建它们，然后才能使用。我们可以使用逗号分隔的文本输入元素来取代原有的 select 元素。这样可以提高用户体验并且能让我们使用更多的 ORM 功能。

添加一个虚拟属性

我们可以通过模型的虚拟属性来操作格式化的 tags。加入以下代码至 src/Model/Entity/Article.php 中:

// add this use statement right below the namespace declaration to import
// the Collection class
use Cake\Collection\Collection;

protected function _getTagString()
{
    if (isset($this->_properties['tag_string'])) {
        return $this->_properties['tag_string'];
    }
    if (empty($this->tags)) {
        return '';
    }
    $tags = new Collection($this->tags);
    $str = $tags->reduce(function ($string, $tag) {
        return $string . $tag->title . ', ';
    }, '');
    return trim($str, ', ');
}

以上的定义让我可以通过 $article->tag_string 来获取这个虚拟属性。往下我们将使用到此属性。

更新对应的视图

在更新完我们的模型以后，我们可以加入一个新的输入元素至对应的视图中。在 src/Template/Articles/add.ctp 和 src/Template/Articles/edit.ctp 中，用以下的代码替换 tags._ids:

echo $this->Form->control('tag_string', ['type' => 'text']);

保存标签内容

虽然我们可以查看标签，却没有办法保存他们。让我们实现此功能。由于我们标记了 tag_string 为虚拟属性，ORM 会自动将它从请求中复制到模型中。我们可以使用 beforeSave() 钩子来解析标签的字符串并且找到或者建立相应的模型。加入以下代码至 src/Model/Table/ArticlesTable.php 中:

public function beforeSave($event, $entity, $options)
{
    if ($entity->tag_string) {
        $entity->tags = $this->_buildTags($entity->tag_string);
    }

    // Other code
}

protected function _buildTags($tagString)
{
    // Trim tags
    $newTags = array_map('trim', explode(',', $tagString));
    // Remove all empty tags
    $newTags = array_filter($newTags);
    // Reduce duplicated tags
    $newTags = array_unique($newTags);

    $out = [];
    $query = $this->Tags->find()
        ->where(['Tags.title IN' => $newTags]);

    // Remove existing tags from the list of new tags.
    foreach ($query->extract('title') as $existing) {
        $index = array_search($existing, $newTags);
        if ($index !== false) {
            unset($newTags[$index]);
        }
    }
    // Add existing tags.
    foreach ($query as $tag) {
        $out[] = $tag;
    }
    // Add new tags.
    foreach ($newTags as $tag) {
        $out[] = $this->Tags->newEntity(['title' => $tag]);
    }
    return $out;
}

现在创建和编辑 articles 的话，我们应该可以使用逗号分隔的标签，标签字符串将会被保存，并且他们的关联会被自动的建立。

以上有点复杂的代码展示了 CakePHP ORM 的强大。你可以使用 集合 来操作查询的结果，并使用它来动态地创建模型。

下一节，我们将添加 认证。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CMS 教案 - 认证

我们现在需要加入登陆以及权限控制等到我们的 CMS 中。

添加密码哈希

现在用户的密码都是以纯文本形式保存在数据库中，我们需要修复这个安全漏洞。

在此，让我们仔细地讨论下 CakePHP 的模型层。在 CakePHP 中，我们将代表单个数据的抽象叫做 Entity 类，将操作 Entity 集合的类叫做 Table。

由于密码哈希是在单个数据上面的操作，因此我们将在 Entity 对象中实现。每一次秘密被加入时，我们都应该使用哈希，因此我们将用到 setter。根据约定，CakePHP 将会调用相应的 setter 当一个属性被附属值时。加入以下代码给密码属性加入 setter:

<?php
namespace App\Model\Entity;

use Cake\Auth\DefaultPasswordHasher; // Add this line
use Cake\ORM\Entity;

class User extends Entity
{

    // Code from bake.

    // Add this method
    protected function _setPassword($value)
    {
        if (strlen($value)) {
            $hasher = new DefaultPasswordHasher();

            return $hasher->hash($value);
        }
    }
}

现在打开 http://localhost:8765/users ，它将展示很多的 user。你可以在 安装时编辑默认用户。如果你编辑用户的密码，你应该看到在用户的密码栏看到一段哈希值。CakePHP 默认使用 bcrypt <http://codahale.com/how-to-safely-store-a-password/> 哈希方法。如果有需要，你也可以使用 SHA-1 或者 MD5，但是我们推荐 bcrypt。

添加登陆功能

在 CakePHP 中，认证是通过 组件 实现的。我们可以将组件想象成某功能或概念一段可重复使用控制器代码。组件可勾入控制器事件的生命周期并由此和应用互动。首先我们将添加 AuthComponent 组件。添加，编辑和删除动作需要认证，在 AppController 中添加以下代码:

// In src/Controller/AppController.php
namespace App\Controller;

use Cake\Controller\Controller;

class AppController extends Controller
{
    public function initialize()
    {
        // Existing code

        $this->loadComponent('Auth', [
            'authenticate' => [
                'Form' => [
                    'fields' => [
                        'username' => 'email',
                        'password' => 'password'
                    ]
                ]
            ],
            'loginAction' => [
                'controller' => 'Users',
                'action' => 'login'
            ],
             // If unauthorized, return them to page they were just on
            'unauthorizedRedirect' => $this->referer()
        ]);

        // Allow the display action so our PagesController
        // continues to work. Also enable the read only actions.
        $this->Auth->allow(['display', 'view', 'index']);
    }
}

以上代码要求 CakePHP 加载了 Auth 组件。由于我们需要使用 email 作为用户名，所以简单定义了

AuthComponent 的属性。现在如果我们浏览被保护的 URL，比如 /articles/add， 页面将会跳转至 /users/login，由于我们还没有完成此页面，因此它会报错。让我们添加登陆动作:

// In src/Controller/UsersController.php
public function login()
{
    if ($this->request->is('post')) {
        $user = $this->Auth->identify();
        if ($user) {
            $this->Auth->setUser($user);
            return $this->redirect($this->Auth->redirectUrl());
        }
        $this->Flash->error('Your username or password is incorrect.');
    }
}

在 src/Template/Users/login.ctp 视图中加入以下:

<h1>Login</h1>
<?= $this->Form->create() ?>
<?= $this->Form->control('email') ?>
<?= $this->Form->control('password') ?>
<?= $this->Form->button('Login') ?>
<?= $this->Form->end() ?>

我们完成了一个简单的登陆页面，可以使用一个用户账号尝试登陆。

注解

如果目前的数据库没有用户密码，你可以先注释掉 loadComponent('Auth') 和 $this->Auth->allow()，这样你就可以使用编辑页面来给用户添加密码。当然请记得添加完以后取消注释！

让我们测试一下！首先打开 /articles/add 页面，由于这是受保护页面，你将被重定向至登陆页面。成功登陆以后，CakePHP 将跳转至 /articles/add。

添加注销功能

现在用户虽然可以登录，但是没有办法注销，让我们添加此功能。在 UsersController 控制器中加入以下代码:

public function initialize()
{
    parent::initialize();
    $this->Auth->allow(['logout']);
}

public function logout()
{
    $this->Flash->success('You are now logged out.');
    return $this->redirect($this->Auth->logout());
}

此段代码首先将 logout 加入到了 AuthComponent `` 组件的白名单中，因此我们可以无认证地访问。然后实现了注销方法。现在我们便可以通过访问 ``/users/logout 来注销当前用户。注销以后，它将自动跳转至登陆页面。

添加注册功能

如果你在登陆前访问 /users/add 页面，它将跳转至登陆页面。我们需要添加注册功能，用户才能使用我们的应用。在 UsersController 控制器中加入以下代码:

public function initialize()
{
    parent::initialize();
    // Add the 'add' action to the allowed actions list.
    $this->Auth->allow(['logout', 'add']);
}

以上代码将 add() 行为列入了 AuthComponent 组件的白名单中，因此访问此行为将无需要认证或者授权。你应该花点时间来清理下 Users/add.ctp 视图，比如删除没必要的衔接。此教程将不会加入编辑用户，查看用户以及用户列表功能，但是你应该尝试自己将他们实现。

文章访问权限

用户登录以后，我们需要限制用户权限，每位用户应该仅能编辑自己创建的 articles 。我们可以通过使用 ‘authorization’ 适配器来实现。实现原理其实很简单，我们只需要使用 ArticlesController 控制器中的一个勾。在此之前，我们需要指导 AuthComponent 如何去授权控制器动作。在 AppController 中加入以下代码:

public function isAuthorized($user)
{
    // By default deny access.
    return false;
}

然后我们配置 AuthComponent 使用控制器的勾方法实现授权。更新后的 AppController::initialize() 方法中的代码应该是这样:

public function initialize()
{
    // Existing code

    $this->loadComponent('Flash');
    $this->loadComponent('Auth', [
        // Added this line
        'authorize'=> 'Controller',
        'authenticate' => [
            'Form' => [
                'fields' => [
                    'username' => 'email',
                    'password' => 'password'
                ]
            ]
        ],
        'loginAction' => [
            'controller' => 'Users',
            'action' => 'login'
        ],
         // If unauthorized, return them to page they were just on
        'unauthorizedRedirect' => $this->referer()
    ]);

    // Allow the display action so our pages controller
    // continues to work. Also enable the read only actions.
    $this->Auth->allow(['display', 'view', 'index']);
}

我们的实现逻辑是：默认授予访问权限为拒绝，然后根据情况授予访问权限。我们首先为 articles 加入授权代码。在 ArticlesController 加入以下代码:

public function isAuthorized($user)
{
    $action = $this->request->getParam('action');
    // The add and tags actions are always allowed to logged in users.
    if (in_array($action, ['add', 'tags'])) {
        return true;
    }

    // All other actions require a slug.
    $slug = $this->request->getParam('pass.0');
    if (!$slug) {
        return false;
    }

    // Check that the article belongs to the current user.
    $article = $this->Articles->findBySlug($slug)->first();

    return $article->user_id === $user['id'];
}

现在尝试编辑或者删除一个不属于当前用户的 article，页面将会跳转到原始页面。如果你没有看到错误信息，在布局中加入以下代码:

// In src/Template/Layout/default.ctp
<?= $this->Flash->render() ?>

接下来我们需要将 tags 行为让任何人访问，在 src/Controller/ArticlesController.php 的 initialize() 方法中加入以下代码:

$this->Auth->allow(['tags']);

以上这段相对简单的授权代码给我们以后创建复杂的授权逻辑提供了很好的基础。

修复 add 和 edit 行为

虽然我们已经给 edit 行为加入了认证，但是用户仍然可以在编辑 article 时修改它的 user_id 。我们将马上修复这个问题。我们需要从 add 行为入手。

在添加 articles，我们可以使用当前当前用户的 user_id:

// in src/Controller/ArticlesController.php

public function add()
{
    $article = $this->Articles->newEntity();
    if ($this->request->is('post')) {
        $article = $this->Articles->patchEntity($article, $this->request->getData());

        // Changed: Set the user_id from the session.
        $article->user_id = $this->Auth->user('id');

        if ($this->Articles->save($article)) {
            $this->Flash->success(__('Your article has been saved.'));
            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('Unable to add your article.'));
    }
    $this->set('article', $article);
}

接下来我们更新 edit 方法。用以下代码替换已有的 edit 方法:

// in src/Controller/ArticlesController.php

public function edit($slug)
{
    $article = $this->Articles
        ->findBySlug($slug)
        ->contain('Tags') // load associated Tags
        ->firstOrFail();

    if ($this->request->is(['post', 'put'])) {
        $this->Articles->patchEntity($article, $this->request->getData(), [
            // Added: Disable modification of user_id.
            'accessibleFields' => ['user_id' => false]
        ]);
        if ($this->Articles->save($article)) {
            $this->Flash->success(__('Your article has been updated.'));
            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('Unable to update your article.'));
    }
    $this->set('article', $article);
}

在这里我们我们使用了 patchEntity() 来成批修改属性。详情可参看 changing-accessible-fields。在这里我们也删除了 user_id 输入控制，因为我们已经不需要。

结语

我们成功了创建了一个简单的 CMS 应用。它的功能包括用户登录，发布，标示以及使用标签搜索文章。我们也通过 FormHelper 以及 ORM 提高了它的用户体验。

感谢您花时间来探索 CakePHP。接下来，你应该学习更多关于 Models 的知识，或者细读 Using CakePHP。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Bookmarker Tutorial

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Bookmarker Tutorial Part 2

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

博客教程

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

博客教程——添加一个层

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Blog Tutorial - Part 3

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Blog Tutorial - Authentication and Authorization

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

贡献

为CakePHP做贡献有多种方式。以下各节涵盖了各种可以为CakePHP做出贡献的方式：

文档

问题跟踪系统

代码

编码规范

向后兼容性指南

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

文档

给文档做贡献是很简单的。这些文件都托管在 https://github.com/cakephp/docs。请自行复制(fork)代码仓库，加入你的更改/改进/翻译，然后发出拉取请求来提交你的改动。你甚至可以在 GitHub 上在线地编辑文档，而完全不用下载文件–在任何页面上的”Improve this Doc”按键将会引导你进入该页面的 GitHub 在线编辑器。

翻译

发邮件给文档小组(docs at cakephp dot org)，或者通过 IRC(freenode上的#cakephp)，来讨论任何你想参与的翻译工作。

关于翻译的一些忠告:

用要翻译的语言来进行浏览、编辑 - 否则你将无法看到哪些已经翻译了。

如果你选择的语言在本书中已经存在，请自行加入。

请使用 Informal Form [http://en.wikipedia.org/wiki/Register_(linguistics)] 。

请将内容和标题一起翻译。

在提交一个更正之前，请先和英文版本的内容进行比较(如果你改正了一些东西，却没有整合“上游”(upstream)的改动，你提交的东西将不会被接受)。

如果你要写一个英文术语，请把它放在 <em> 标签之内。比如， “asdf asdf Controller asdf”或者”asdf asdf Kontroller (Controller) asfd”，请适为选用。

请不要提交不完整的翻译。

请不要编辑正在改动的部分。

对于标以重音符号的字符，请不要使用 html 字符实体 [http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references] (html entities) 来表示，本书使用UTF-8。

请不要显著改变标记(HTML)或增加新的内容。

如果原始的内容遗漏了某些信息，请先提交(对原始内容的)更正。

文档格式指南

这份新的 CakePHP 文档是以 ReST formatted text [http://en.wikipedia.org/wiki/ReStructuredText] 格式写的。 ReST (Re Structured Text)是与 markdown 或者 textile 类似的纯文本标记语法。在为 CakePHP 的文档做出贡献时，为了保持一致性，建议你遵循下面的准则，来你格式化和组织你的文字。

每行的长度

每行文字应在80列处折行。唯一的例外是长的网址和代码片断。

标题和小节

小节的标题要在它的下一行用至少相同长度的标点符号来标识。

# 用来标识网页标题。

= 用于标识在一个页面中的小节。

- 用于标识下一级的小节。

~ 用于标识再下一级的小节。

^ 用于标识更下一级的小节。

标题的嵌套深度不应超过5层。标题之前和之后都应留有一个空行。

段落

段落是简单的文本块，缩进在同一级别。段落之间应以一个以上的空行分隔。

内嵌(inline)标记

一个星号： 文字 为强调(斜体)

*text*

两个星号： 文字 为高度强调(粗体)

**text**

反引号： 文字 为代码样本

``text``

如果星号或反引号出现在文字中，并易与内嵌标记分隔符混淆，则必须用一个反斜杠转义。

内嵌标记有一些限制:

不可以 嵌套。

内容不可以以空格开始或结束: * 文本* 是错误的。

内容必须与周围的文字由非文字字符分隔，这可以使用反斜杠转义的空格来解决：一个长的\ *粗体*\ 词汇。

列表

列表与 markdown 非常相似。无序列表以一个星号和一个空格开始。有序列表可以数字开始，或以 # 进行自动编号:

* 这是一点
* 这也是。但这一点
  有两行。

1. 第一行
2. 第二行

#. 自动编号
#. 可以为你节省时间。

也可以创建缩进列表，只需缩进缩进列表那部分，并用一个空行分隔:

* 第一行
* 第二行

    * 缩进
    * 哇

* 回到第一层。

定义列表(Definition lists)，可以通过以下方式创建:

术语
    定义
CakePHP
    一个基于 PHP 的 MVC 框架

术语不可超过一行，但定义可以有多行并且所有行应当有同样的缩进。

链接

有几种类型的链接，每个都有自己的用途。

外部链接

链接到外部文件如下:

`外部链接 <http://example.com>`_

上面会产生一个指向 http://example.com 的链接。

链接到其他页面

:doc:

指向文档中其他网页的链接可以使用 :doc: 角色(role)。你可以使用绝对路径或者相对路径，来链接到指定的文件中。请省略 .rst 扩展名。例如，如果链接 :doc:`form` 出现在文档 core-helpers/html 中，则该链接指向 core-helpers/form 。如果链接是 :doc:`/core-helpers` ，那么不论它用在那里，总是会指向 /core-helpers 。

交叉引用链接

:ref:

你可以使用 :ref: 角色交叉引用在任何文件中的任何标题。链接标签指向的目标在整个文档必须是唯一的。当为类的方法创建标签时，最好使用 class-method 作为您的链接标签的格式。

标签最常见的用途是在标题之前。例如:

.. 标签名称:

小节标题
--------

更多内容在这里。

在其他地方你可以用 :ref:`标签名称` 引用上面的小节。链接的文字可以是标签之后的标题。你也可以使用 :ref:`链接文字 <标签名称>` 的方式来提供自定义的链接文字。

Prevent Sphinx to Output Warnings

Sphinx will output warnings if a file is not referenced in a toc-tree. It’s a great way to ensure that all files have a link directed to them, but sometimes, you don’t need to insert a link for a file, eg. for our epub-contents and pdf-contents files. In those cases, you can add :orphan: at the top of the file, to suppress warnings that the file is not in the toc-tree.

描述类和它们的内容

CakePHP 文档使用 phpdomain [http://pypi.python.org/pypi/sphinxcontrib-phpdomain] 提供自定义指令描述 PHP 对象和结构。我们必须使用这些指令和角色，才能保证正确的索引和交叉引用。

描述类及其组成

每个指令生成索引，或命名空间索引。

.. php:global:: name

这个指令声明一个新的PHP全局变量。

.. php:function:: name(signature)

定义一个新的处于类之外的函数。

.. php:const:: name

这个指令声明一个新的 PHP 常量，也可以在一个类的指令之内使用它来创建类的常量。

.. php:exception:: name

这个指令在当前命名空间内声明一个新的 PHP 异常。其签名可以包括构造函数的参数。

.. php:class:: name

描述了一个类。属于该类的方法、属性和常量应该处于这个指令之内:

.. php:class:: MyClass

    类的说明

   .. php:method:: method($argument)

   方法的说明

属性、方法和常量不需要嵌套。他们可以直接位于类的声明之后:

.. php:class:: MyClass

    关于类的文字

.. php:method:: methodName()

    关于方法的文字

参见

php:method, php:attr, php:const

.. php:method:: name(signature)

描述一个类的方法，其参数、返回值以及异常:

.. php:method:: instanceMethod($one, $two)

    :param string $one: 第一个参数.
    :param string $two: 第二个参数.
    :returns: 一个数组。
    :throws: InvalidArgumentException

   这是一个实例方法。

.. php:staticmethod:: ClassName::methodName(signature)

描述了一个静态方法，其参数、返回值以及异常，选项可参看 php:method 。

.. php:attr:: name

描述一个类的属性(property/attribute)。

Prevent Sphinx to Output Warnings

Sphinx will output warnings if a function is referenced in multiple files. It’s a great way to ensure that you did not add a function two times, but sometimes, you actually want to write a function in two or more files, eg. debug object is referenced in /development/debugging and in /core-libraries/global-constants-and-functions. In this case, you can add :noindex: under the function debug to suppress warnings. Keep only one reference without :no-index: to still have the function referenced:

.. php:function:: debug(mixed $var, boolean $showHtml = null, $showFrom = true)
    :noindex:

交叉引用

以下角色指向 PHP 对象，如果有匹配的指令，就会生成链接：

:php:func:

指向一个PHP函数。

:php:global:

指向一个名称以 $ 开始的全局变量。

:php:const:

指向一个全局常量、或类的常量。类的常量应当以所属类为前缀。

DateTime 有一个 DateTime::ATOM 常量。

:php:class:

指向一个以名称标识的类:

:php:class:`ClassName`

:php:meth:

指向一个类的方法，该角色支持两种方法:

:php:meth:`DateTime::setDate`
:php:meth:`类名::静态方法`

:php:attr:

指向一个对象的属性:

:php:attr:`ClassName::$propertyName`

:php:exc:

指向一个异常。

源代码

一个段落以 :: 结束，就可以创建代码块。该段落必须缩进，且象所有段落一样，须以单个空行分隔:

这是一个段落::

    while ($i--) {
        doStuff()
    }

这又是正常的文字了。

代码的文字不会被改动或格式化，除非取消该级别的缩进。

注释和警告

有很多时候，你会想告诉读者一个重要的提示、特别的说明或者可能的危险。sphinx 中的告诫(Admonition)正是为了这个目的。有三种类型的告诫。

.. tip:: 提示用于说明或重申有趣或者重要的信息。应当使用完整的句子以及任何适当的标点符号。

.. note:: 注释是用来说明特别重要的信息。应当使用完整的句子以及任何适当的标点符号。

.. warning:: 警告用于描述潜在的障碍，或与安全有关的信息。应当使用完整的句子以及任何适当的标点符号。

所有告诫都是相同的:

.. note::

    缩进，并且前后都应留有一个空行，就象普通段落一样。

此文字不是注释的一部分。

示例

小技巧

这是一条有用的信息，你可能忘记了。

注解

你应当注意这里。

警告

它可能有危险。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

问题跟踪系统

在 CakePHP 的开发过程中，以问题跟踪系统的形式从社区获得反馈和帮助是极为重要的一部分。所有 CakePHP 的问题跟踪都托管在 GitHub [https://github.com/cakephp/cakephp/issues] 上。

报告臭虫

写得好的问题报告都非常有用。下面的步骤可以帮助创建尽可能好的问题报告：

请搜索 [https://github.com/cakephp/cakephp/search?q=it+is+broken&ref=cmdform&type=Issues] 类似的已有问题，并保证别人没有报告你的问题，或者在源代码仓库中还没有得到修复。

请 包括 如何重现问题 的详细说明。这可以是测试用例或代码片段，来展示所报告的问题。如果没有办法重现问题，则意味着它不太容易被修复。

请 尽可能详尽地提供关于你的(运行)环境的细节(操作系统，PHP 的版本，CakePHP 的版本)。

请不要 使用问题跟踪系统来询问技术支持的问题。寻求技术支持，请使用谷歌讨论组 [http://groups.google.com/group/cake-php] 或 #cakephp 的 IRC 渠道或者 Stack Overflow <https://stackoverflow.com/questions/tagged/cakephp>。

报告安全问题

如果你发现了 CakePHP 的安全问题，请使用以下过程，而不要使用平常的错误报告系统，比如问题跟踪系统、邮件列表或 IRC。请发送电子邮件至 security [at] cakephp.org 。发送到这个邮箱的电子邮件会进入一个 CakePHP 核心团队所在的内部邮件列表中。

对于每一份报告，我们首先尝试确认该漏洞。一经确认，CakePHP 团队将采取以下措施：

向报告者确认我们已经收到了该问题报告，并正着手修复。我们请求报告者对该问题保密，直到我们对外宣布。

准备一个更正/补丁。

准备一份帖子，描述该漏洞以及可能的利用方式。

针对所有受影响的版本发布新版本。

在版本发布公告中明确地说明该问题。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

代码

补丁和拉取请求是为 CakePHP 贡献代码的一种很棒的方式。拉取请求可以在 GitHub 中创建，是比附在问题报告的评论(ticket comments)中的补丁更受青睐的方式。

初始设置

在开始为 CakePHP 制作补丁之前，最好先把你的环境设置好。你需要下列软件：

Git

PHP 5.2.8 或更高版本

PHPUnit 3.5.10 或更高版本

设置你的用户信息，包括你的名字/账号和电子邮件:

git config --global user.name 'Bob Barker'
git config --global user.email 'bob.barker@example.com'

注解

如果你对 Git 完全陌生，我们强烈建议你阅读优秀且免费的 ProGit [http://git-scm.com/book/] 这本书。

从 GitHub 获得一份 CakePHP 源程序的克隆(clone)。

如果你没有 GitHub [http://github.com] 的账号，创建一个。

点击**Fork**按键，复制(fork)一份 CakePHP repository [http://github.com/cakephp/cakephp] 的源码。

你的复制完成后，从你的复制仓库(repository)克隆(clone)到你的本地机器:

git clone git@github.com:你的账号/cakephp.git

把原始的 CakePHP 仓库添加为远程仓库(remote repository)。以后你会使用它来抓取 CakePHP 仓库的改动，保持与 CakePHP 仓库一致:

cd cakephp
git remote add upstream git://github.com/cakephp/cakephp.git

现在你已经搭建好了 CakePHP 的环境。你应该能够定义一个 $test 数据库连接，并且运行所有的测试 。

制作补丁

每次当你要修复一个臭虫(bug)、增加一个特性或做一个改进时，创建一个主题分支 (topic branch)。

你创建的分支，应根据你的修复/改进所适用的版本。例如，如果你正在修复 2.3 版本中的一个臭虫，那么你就应当以 2.3 的分支为基础来创建你的分支。如果你做的改动是对当前的稳定版本的一个臭虫的修复，你就应当使用 master 分支。这样以后合并改动时就会简单多了:

# fixing a bug on 2.3
git fetch upstream
git checkout -b ticket-1234 upstream/2.3

小技巧

作为一个良好的习惯，为你的分支起一个描述性的名称，可以引用问题跟踪报告或特性名称。例如 ticket-1234，超棒的特性

上述命令将创建基于上游(CakePHP) 2.3分支的一个本地分支。进行你的臭虫修复工作，根据你的需要做任意多次的提交(commit)。不过你要牢记以下几点:

遵循 编码规范 。

添加一个测试用例来说明错误修复好了，或者新特性能够工作。

使你的提交保持逻辑性，提交信息应当清晰、简洁。

提交拉取请求

一旦你的改动完成了，并且可以合并到 CakePHP 中去了，你就应当更新你的分支:

git checkout 2.3
git fetch upstream
git merge upstream/2.3
git checkout <branch_name>
git rebase 2.3

这将抓取+合并自从你开始之后 CakePHP 中的任何改动。然后，它将衍合(rebase) – 或者说，在当前代码的基础上重新应用你的改动。在 衍合 过程中你可能会遇到冲突。如果衍合过早退出，你可以使用 git status 命令来查看哪些文件发生冲突/没有合并。解决每个冲突，然后继续衍合:

git add <filename> # 针对每一个发生冲突的文件。
git rebase --continue

检查所有的测试仍然通过。然后把你的分支推送(push)到你的复制(fork)仓库上:

git push origin <branch-name>

一旦你的分支在 GitHub 上，你就可以在 cakephp-core [http://groups.google.com/group/cakephp-core] 邮件列表上进行讨论或在 GitHub 上提交拉取请求。

选择你的改动会被合并到哪里

当提交拉取请求时，你应该确保你选择了正确的分支作为基础，因为拉取请求一经创建就无法更改。

如果你的改动是一个 错误修正，并不引入新功能，只是纠正当前版本中现有的行为，则请选择 master 为合并目标。

如果你的改动是一个 新特性 或者为框架新增的功能，那么你应选择下一个版本号对应的分支。例如，如果目前的稳定版本是 2.2.2，则接受新特性的分支将是 2.3。

如果你的改动打破(break)了现有的功能或 API，那么你就应当选择再下一个主要版本。例如，如果当前的版本是 2.2.2，那么下一次现有的功能可以被打破(broken)就是在 3.0 版本了，所以你应该针对这一分支。

注解

请记住，所有你贡献给 CakePHP 的代码将被置于 MIT 许可之下， Cake Software Foundation [http://cakefoundation.org/pages/about] 将会成为任何贡献出去的代码的所有者。代码贡献者应当遵循 CakePHP Community Guidelines [http://community.cakephp.org/guidelines] 。

所有合并到维护分支中的臭虫修复，也将被核心团队定期地合并到即将发布的下一个版本。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

编码规范

CakePHP 开发人员将使用下面的编码规范。

我们建议其他开发Cake组成部分的人员也应当遵循同样的规范。

你可以使用 CakePHP Code Sniffer [https://github.com/cakephp/cakephp-codesniffer] 来检查你的代码是否遵循了必要的规范。

添加新特性

添加新特性，必须伴随相应的测试用例，在提交到代码仓库前，测试用例必须通过。

缩进

缩进使用一个制表符。

所以，缩进应当看起来象这样:

// 底层
    // 第1层
        // 第2层
    // 第1层
// 底层

或者:

$booleanVariable = true;
$stringVariable = 'moose';
if ($booleanVariable) {
    echo '布尔值为真';
    if ($stringVariable === '驼鹿') {
        echo '我们遇到了一只驼鹿';
    }
}

行的长度

为了使代码更好的可读性，建议每行保持在大约100个字符的长度。每行不得超过120个字符。

简而言之:

100个字符是建议性的上限。

120个字符是强制性的上限。

控制结构

控制结构是”if”、”for”、”foreach”、”while”、”switch”这些。下面是使用”if”的一个例子:

if ((expr_1) || (expr_2)) {
    // action_1;
} elseif (!(expr_3) && (expr_4)) {
    // action_2;
} else {
    // default_action;
}

在控制结构中，在第一个括号之前应该有一个空格，在最后一个括号和开始的大括号之间也应该有一个空格。

在控制结构中总是使用大括号，即使他们是不必要的。这会提高代码的可读性，也导致较少的逻辑错误。

开始的大括号应与控制结构放在同一行上。结束的大括号应该新起一行，并且与控制结构应该有相同的缩进级别。包括在大括号中的语句应该新起一行，其代码也应该再缩进一层。

在控制结构中不应该使用内嵌赋值(inline assignment)。

// 错误 = 没有大括号，语句的位置也不对
if (expr) statement;

// 错误 = 没有大括号
if (expr)
    statement;

// 正确
if (expr) {
    statement;
}

// 错误 = 内嵌赋值
if ($variable = Class::function()) {
    statement;
}

// 正确
$variable = Class::function();
if ($variable) {
    statement;
}

三元运算符

当整个三元运算可以放在一行之内时，三元运算符是允许的。更长的三元运算就应该分成 if else 语句。三元运算符绝对不允许嵌套。括号虽然不必须，但是可以用在三元运算的条件检查之外，使其更清晰:

//很好，简单，易读
$variable = isset($options['variable']) ? $options['variable'] : true;

//嵌套的三元运算不好
$variable = isset($options['variable']) ? isset($options['othervar']) ? true : false : false;

视图文件

在视图文件(.ctp files)中，开发人员使用关键词控制结构。关键词控制结构在复杂的视图文件中更容易阅读。控制结构可以放在一段大的 PHP 代码段落中，也可以放在单独的 PHP 标签中:

<?php
if ($isAdmin):
    echo '<p>You are the admin user.</p>';
endif;
?>
<p>下面也是可以接受的:</p>
<?php if ($isAdmin): ?>
    <p>You are the admin user.</p>
<?php endif; ?>

比较

总是尽可能的严格。如果特意要使用一个不严格的比较，也许应当注释说明是这样，以免混淆为错误。

要测试一个变量是否为空，建议使用严格检查:

if ($value === null) {
      // ...
}

要检查的值应该放在右边:

// 不建议使用
if (null === $this->foo()) {
    // ...
}

// 推荐使用
if ($this->foo() === null) {
    // ...
}

函数调用

在函数调用中，函数名和开始的括号之间不允许有空格，在每个参数之间应当有一个空格:

$var = foo($bar, $bar2, $bar3);

如上所示，在等号(=)的两边都应该有一个空格。

方法的定义

方法定义的例子:

function someFunction($arg1, $arg2 = '')
{
    if (expr) {
        statement;
    }
    return $var;
}

带缺省值的参数应该放在函数定义的最后。尽量让你的函数返回一些东西, 至少是 true 或者 false ，这样就可以判断函数调用是否成功:

public function connection($dns, $persistent = false)
{
    if (is_array($dns)) {
        $dnsInfo = $dns;
    } else {
        $dnsInfo = BD::parseDNS($dns);
    }

    if (!($dnsInfo) || !($dnsInfo['phpType'])) {
        return $this->addError();
    }
    return true;
}

等号两边都有空格。

类型约束

接受对象或者数组的参数可以使用类型约束:

/**
 * 方法描述。
 *
 * @param Model $Model 使用的模型。
 * @param array $array 数组值。
 * @param bool $boolean 布尔值。
 */
public function foo(Model $Model, array $array, $boolean)
{
}

这里 $Model 必须是 Model 的实例，$array 必须是数组(array)。

注意，如果你要允许 $array 也可以是 ArrayObject 的实例，你就不能用类型约束，因为 array 只接受基本类型:

/**
 * 方法描述。
 *
 * @param array|ArrayObject $array 数组值。
 */
public function foo($array)
{
}

方法链接(Method Chaining)

方法链接时, 多个方法应当在各自的行上, 并且缩进一个制表符:

$email->from('foo@example.com')
    ->to('bar@example.com')
    ->subject('A great message')
    ->send();

代码的注释

所有的注释都应该是英文, 并且应该清楚地描述被注释的代码段。

注释可以包括以下`phpDocumentor <http://phpdoc.org>`_标签:

@author [http://phpdoc.org/docs/latest/references/phpdoc/tags/author.html]

@copyright [http://phpdoc.org/docs/latest/references/phpdoc/tags/copyright.html]

@deprecated [http://phpdoc.org/docs/latest/references/phpdoc/tags/deprecated.html] 使用格式 @version <vector> <description> ，其中 version``和``description 是必须的。

@example [http://phpdoc.org/docs/latest/references/phpdoc/tags/example.html]

@ignore [http://phpdoc.org/docs/latest/references/phpdoc/tags/ignore.html]

@internal [http://phpdoc.org/docs/latest/references/phpdoc/tags/internal.html]

@link [http://phpdoc.org/docs/latest/references/phpdoc/tags/link.html]

@see [http://phpdoc.org/docs/latest/references/phpdoc/tags/see.html]

@since [http://phpdoc.org/docs/latest/references/phpdoc/tags/since.html]

@version [http://phpdoc.org/docs/latest/references/phpdoc/tags/version.html]

PhpDoc 标签非常类似于 Java 中的 JavaDoc 标签。标签只有出现在文档块(DocBlock)行的开头才会起作用, 例如:

/**
 * Tag example.
 *
 * @author 这个标签会被处理, 但这个@version会被忽略
 * @version 1.0 这个标签也会被处理
 */

/**
 * 内嵌 phpDoc 的例子。
 *
 * 这个函数致力于与 foo() 联手统治世界。
 *
 * @return void
 */
function bar()
{
}

/**
 * Foo 函数.
 *
 * @return void
 */
function foo()
{
}

所有注释段, 除了一个文件中的第一段, 之前总是应当有一个空行。

变量类型

文档块(DocBlock)中使用的变量类型:

类型

描述

mixed

有未定义(或多种)类型的变量。

int

整数类型变量(整数)。

float

浮点数类型(浮点数)。

bool

逻辑类型(true或者false)。

string

字符串类型(位于” “或’ ‘中的任何值)。

null

空类型。通常与另一种类型一起使用。

array

数组类型。

object

对象类型。 如果可能应该使用更明确的类名。

resource

资源类型(例如由mysql_connect()返回的)。记住, 如果你指定了混合类型, 则需指明是未知, 或者可以是哪些类型。

callable

可调用的函数。

你也可以用竖线(pipe char)组合多个类型:

int|bool

对两种以上的类型，通常最好使用 mixed 。

当返回对象本身时，例如为了实现链式方法，应当使用 $this

/**
 * Foo function.
 *
 * @return $this
 */
public function foo()
{
    return $this;

包括文件

include 、 require 、 include_once 和 require_once 没有括号:

// 错误 = 括号
require_once('ClassFileName.php');
require_once ($class);

// 正确 = 没有括号
require_once 'ClassFileName.php';
require_once $class;

当包括类或者库的文件时, 总是只使用 require_once [http://php.net/require_once] 函数。

PHP 标签

总是使用长标签(<?php ?>), 而不用短标签(<? ?>)。

命名规则

函数

所有函数名都应为 camelBack 形式:

function longFunctionName()
{
}

类

类名应为驼峰命名法(CamelCase), 例如:

class ExampleClass
{
}

变量

变量名应当尽可能具有描述性, 但同时越短越好。普通变量应当以小写字母开头，如果含有多个词, 则应当为 camelBack 形式。引用对象变量的变量名应当以大写字母开头，并且与对象所属的类应当以某种方式相关联。例如:

$user = 'John';
$users = array('John', 'Hans', 'Arne');

$Dispatcher = new Dispatcher();

成员的可见范围

方法和变量应当使用 PHP5 的 private 和 protected 关键字。另外，protected 的方法和变量应当以一个下划线开头(_)。例如:

class A
{
    protected $_iAmAProtectedVariable;

    protected function _iAmAProtectedMethod()
    {
       /*...*/
    }
}

私有方法和变量应当以双下划线(__)开���。例如:

class A
{
    private $__iAmAPrivateVariable;

    private function __iAmAPrivateMethod()
    {
        /*...*/
    }
}

不过，尽可能避免私有方法或者变量，而使用保护(protected)的(方法或者变量)。后者可以被子类访问或者改变，而私有的(方法或者变量)阻止了扩展或重用。私有也使测试更加困难。

示例地址

所有示例用的网址和电子邮箱地址应当使用”example.com”、”example.org”和”example.net”，例如:

电子邮箱地址: someone@example.com

网址: http://www.example.com

FTP: ftp://ftp.example.com

“example.com” 域名已为此目的而保留(参见 RFC 2606 [https://tools.ietf.org/html/rfc2606.html] )，建议在文档中或者作为例子使用。

文件

不包含类的文件，其文件名应当小写，并且以下划线分隔单词，例如:

long_file_name.php

强制转换(Casting)

做强制转换，我们使用:

类型

描述

(bool)

强制转换成布尔类型。

(int)

强制转换成整数类型。

(float)

强制转换成浮点类型。

(string)

强制转换成字符串类型。

(array)

强制转换成数组类型。

(object)

强制转换成对象类型。

在适用时，请使用 (int)$var，而不是 intval($var)，使用 (float)$var，而不是 floatval($var)。

常量

常量名称应当大写:

define('CONSTANT', 1);

如果常量名称由多个单词组成的，则应当用下划线分隔，例如:

define('LONG_NAMED_CONSTANT', 2);

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

向后兼容性指南

确保您可以轻松顺利地升级您的应用程序，这对我们是很重要的。这就是为什么我们只在主要版本里程碑才会打破兼容性。你可能熟悉 语义版本控制 [http://semver.org/] ，这就是我们在所有的 CakePHP 项目中使用的通用准则。总之，语义版本控制意味着只有主要版本(比如2.0，3.0，4.0)可以打破向后兼容性。次要版本(比如2.1，3.1，3.2)可能会引入新的功能，但不能破坏兼容性。错误修复版本(比如2.1.2，3.0.1)不增加新的功能，但仅修复漏洞或改善性能。

注解

CakePHP 从2.0.0开始遵循语义版本控制。这些规则不适用于1.x。

为了澄清在每个版本层次可以预期到哪些变化，我们为使用 CakePHP 的开发人员以及开发 CakePHP 的开发人员准备了更详细的信息，以便于建立预期在次要版本中能做什么。主要版本根据需要可以有任意多个打破兼容性的变化。

升级指南

对每个主要和次要版本，CakePHP 开发团队会提供一份升级指南。这些指南说明每一个版本中的新功能及任何打破兼容性的变化，可以在 cookbook 的 Appendices 一节中看到。

使用 CakePHP

如果你使用 CakePHP 来构建应用程序，下面的指南说明了你可以预期的稳定性。

接口

除了主要版本，CakePHP 提供的接口的任何现有的方法 不 会改变。可能会增加新的方法，但不会改变任何现有的方法。

类

CakePHP 提供的类可以实例化，并且它们的公共方法和属性，可以被应用代码使用，除了主要版本，(其他的版本)可以保证向后兼容性。

注解

一些 CakePHP 的类标有 @internal API 文档标签(API doc tag)。这些类不 稳定，不能保证向后兼容性。

在次要版本中，类可以添加新方法，已有的方法可以添加新的参数。任何新参数必须有缺省值，但如果你用不同的签名重载方法，你可能会遇到致命错误(fatal errors)。添加了新参数的方法，会在那个版本的升级指南中说明。

下面的表格列出一些用例，以及你从 CakePHP 可以期望得到的兼容性：

如果你……

向后兼容性？

使用类作为类型约束

是

创建新的实例

是

扩展类

是

访问公共属性

是

调用公共方法

是

扩展类并且……

重载公共属性

是

访问受保护的属性

否 1

重载受保护的属性

否 1

重载受保护的方法

否 1

调用受保护的方法

否 1

添加公共属性

否

添加公共方法

否

为重载的方法添加参数

否 1

为已有的方法添加缺省参数

是

开发 CakePHP

如果你帮助改进 CakePHP，在添加/修改功能时，请记住下面的指南：

在次要版本中，你可以：

在次要版本中你能……

类

删除类

否

删除接口

否

删除 trait

否

改变为 final

否

改变为 abstract

否

改变名称

是 2

属性

添加公共属性

是

删除公共属性

否

添加受保护的属性

是

删除受保护的属性

是 3

方法

添加公共方法

是

删除公共方法

否

添加受保护的方法

是

迁移到父类

是

删除受保护的方法

是 3

降低访问控制（可见性）

否

改变方法名称

是 2

添加带缺省值的参数

是

添加必需的参数

否

1(1,2,3,4,5)

你的代码*可能*会被次要版本打破(兼容性)。查看升级指南了解详情。

2(1,2)

只要原有的名称仍然可用，你可以改变类/方法的名称。通常应当避免，除非改名有明显的好处。

3(1,2)

尽可能避免。任何删除都需要在升级指南中说明。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

安装

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Configuration

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Routing

class Cake\Routing\Router

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

Connecting Routes

Creating RESTful Routes

Dispatcher Filters

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Dispatcher Filters

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Request & Response Objects

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

控制器

class Cake\Controller\Controller

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

关于控制器的更多内容

页面控制器

组件

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

页面控制器

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

组件

组件(Components)是在控制器之间共享的封装了的逻辑。CakePHP 附带一套非常棒的核心组件，可帮你完成各种常见任务。你也可以创建自己的组件。如果你发现自己要在控制器间复制粘贴代码，就应当考虑创建自己的组件，封装这些功能。创建组件可以保持控制器代码简洁，并且让你可以在不同的项目中重用代码。

每个核心组件都会在各自的章节中详细介绍，请参看。本节将描述如何配置和使用组件，以及如何创建你自己的组件。

Authentication

Cookie

Cross Site Request Forgery

Flash

Security

Pagination

Request Handling

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Authentication

class AuthComponent(ComponentCollection $collection, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Cookie

class Cake\Controller\Component\CookieComponent(ComponentRegistry $collection, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Cross Site Request Forgery

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Flash

class Cake\Controller\Component\FlashComponent(ComponentCollection $collection, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Security

class SecurityComponent(ComponentCollection $collection, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Pagination

class Cake\Controller\Component\PaginatorComponent

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Request Handling

class RequestHandlerComponent(ComponentCollection $collection, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

视图

class Cake\View\View

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

关于视图的更多内容

View Cells

主题

JSON 和 XML 视图

助件

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

View Cells

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

主题

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

JSON 和 XML 视图

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

助件

助件(Helper)对于应用程序中表现层的作用，就像组件对于控制器的作用。助件包含的表现层逻辑，在多个视图、元素或布局间共享。本章将展示如何创建你自己的助件，并概述 CakePHP 的核心助件能帮助你实现的基本任务。

CakePHP 包含了一些有助于创建视图的助件。助件帮助创建完整格式的标记代码 (markup)(包括表单)，帮助格式化文本、时间和数字，甚至加速 AJAX 功能。欲知 CakePHP 中助件的更多信息，请查看。

Breadcrumbs

Flash

Form

Html

Number

Paginator

Rss

Session

Text

Time

Url

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Breadcrumbs

class Cake\View\Helper\BreadcrumbsHelper(View $view, array $config = [])

3.3.6 新版功能.

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Flash

class Cake\View\Helper\FlashHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Form

class Cake\View\Helper\FormHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Html

class Cake\View\Helper\HtmlHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Number

class Cake\View\Helper\NumberHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Paginator

class Cake\View\Helper\PaginatorHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Rss

class Cake\View\Helper\RssHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Session

class Cake\View\Helper\SessionHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Text

class Cake\View\Helper\TextHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Time

class Cake\View\Helper\TimeHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Url

class Cake\View\Helper\UrlHelper(View $view, array $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Models

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

Database Basics

Query Builder

Table Objects

Entities

Retrieving Data & Results Sets

Validating Data

Saving Data

Deleting Data

Associations - Linking Tables Together

Behaviors

CounterCache

Timestamp

Translate

Tree

Schema System

ORM Cache Shell

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Database Basics

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Query Builder

class Cake\ORM\Query

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Table Objects

class Cake\ORM\Table

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Entities

class Cake\ORM\Entity

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Retrieving Data & Results Sets

class Cake\ORM\Table

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Validating Data

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Saving Data

class Cake\ORM\Table

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Deleting Data

class Cake\ORM\Table

Cake\ORM\Table::delete(Entity $entity, $options = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Associations - Linking Tables Together

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Behaviors

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

CounterCache

Timestamp

Translate

Tree

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CounterCache

class Cake\ORM\Behavior\CounterCacheBehavior

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Timestamp

class Cake\ORM\Behavior\TimestampBehavior

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Translate

class Cake\ORM\Behavior\TranslateBehavior

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Tree

class Cake\ORM\Behavior\TreeBehavior

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Schema System

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

ORM Cache Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Bake Console

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

Code Generation with Bake

Extending Bake

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Code Generation with Bake

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Extending Bake

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Caching

class Cake\Cache\Cache

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Shells, Tasks & Console Tools

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

Shell Helpers

Interactive Console (REPL)

Running Shells as Cron Jobs

I18N Shell

Completion Shell

Plugin Shell

Routes Shell

Upgrade Shell

Server Shell

Cache Shell

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Shell Helpers

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Interactive Console (REPL)

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Running Shells as Cron Jobs

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

I18N Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Completion Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Plugin Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Routes Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Upgrade Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Server Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Cache Shell

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can referer to the english version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Debugging

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Deployment

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Email

class Cake\Mailer\Email(mixed $profile = null)

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Error & Exception Handling

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

事件系统（Events System）

创造一个可维持得应用既是一门科学也是一门艺术。让代码变得更加有质量的方式就是让你的对象变得松耦合（loosely coupled）的同时保持强内聚（strongly cohesive）。内聚意味着一个类的所有方法和属性都和类本身强烈关联并且该类不会去做其它对象应该做的事。而相对应的松耦合是指一个类与外部对象的关联度有多低，这个类依赖于其它对象的程度。

确实有些时候你需要在没有太多的代码依赖的基础上与其它应用保持干净的交流，因此你让耦合变得疏松同时增加类的内聚。使用观察者模式，让一些对象在变化时可以通知另外一些对象和匿名的监听器，是一种达到该目的常用模式。

在观察者模式中监听器可以订阅事件并且选择在事件发生时要做出的动作。如果你已经使用过JavaScript，那么很有可能你已经接触过并且熟悉了事件驱动的程序设计。

CakePHP 模拟了类似jQuery的流行的JavaScript库中，对于事件触发和管理的几个方面。在CakePHP实装的时候，一个事件对象将会发送给所有监听者。事件对象掌握着关于事件的信息，并且可以在任意点上停止事件的传播。监听器可以注册它们自身，可以将一个任务委任给其它对象并且可以用回调函数转换状态和事件本身。

事件辅助系统是模型（Model）、行为（Behavior）、控制器（Controller）、视图（View）和助件（Helper）的回调的核心。如果你已经用过它们，那么你已经或多或少熟悉CakePHP中的事件了。

事件的使用例

让我们假设你已经建立了一个购物车插件，你希望专注于完善订单的逻辑。不希望在购物逻辑中包含物流、邮件通知、或者在库削减的逻辑。但是这些对于使用你的插件的人来说是非常重要的。如果你不使用事件，或许你会试着通过在模型中添加行为来将这些包含进来，或者给你的控制器增加部件。做这些意味着花费大量时间，因为你将要让这些加载的行为来迎合你的代码，或者来和你的插件控制器连接起来。

取而代之，你可以使用事件来干净地分离你代码的关系并且为你使用事件的插件提供附加的关联。举个例子，在你的购物车插件中你有一个处理新增订单的模型。你可能会通知其它应用一个订单已经被新增了。你可以使用这些事件来让你的模型保持干净:

// Cart/Model/Table/OrdersTable.php
namespace Cart\Model\Table;

use Cake\Event\Event;
use Cake\ORM\Table;

class OrdersTable extends Table
{

    public function place($order)
    {
        if ($this->save($order)) {
            $this->Cart->remove($order);
            $event = new Event('Model.Order.afterPlace', $this, [
                'order' => $order
            ]);
            $this->eventManager()->dispatch($event);
            return true;
        }
        return false;
    }
}

上述代码可以让你通知其它应用一个订单已经被创建。之后你可以在其它关注该事件的独立对象中执行像发送邮件通知、更新在库、日志相关统计以及其它任务。

访问事件管理器（Event Managers）

CakePHP事件会触发事件管理器。在各表、视图、控制器中使用 eventManager() 能够访问事件管理器:

$events = $this->eventManager();

各模型都拥有一个独立的事件管理器，而视图和控制器共享一个。这使得模型的事件可以容纳自身，并且能够让部件或者控制器基于视图中的事件来启动。

全局事件管理器

除了实例级别的事件管理器，CakePHP还提供一个全局的事件管理器让你可以监听应用中发生的任意事件。这在添加一个监听器到个别实例会很笨重或者困难的时候将会比较实用。全局管理器是一个 Cake\Event\EventManager 的单子实例。登录到全局发送者的监听器在同样的优先级下将会比实例监听器先发动。你可以使用静态方法进入全局管理器:

// 在事件执行前的配置文件或者代码片段中
use Cake\Event\EventManager;

EventManager::instance()->on(
    'Model.Order.afterPlace',
    $aCallback
);

一个你应该考虑的重要事情是有些拥有相同名字但是不同内容的事件被发动的情况。因此需要在事件对象中检查以防止分配到全局的任意机能中漏洞。记住使用全局管理者的柔软性，会让额外的复杂程度增加。

Cake\Event\EventManager::dispatch() 方法接受事件对象作为宣言并且通知所有的监听器，通过回填函数单独传递这个对象。监听器将会掌握围绕着 afterPlace 事件的全部逻辑，你可以通过不同的独立对象记录时间、发送邮件、更新用户统计，甚至委托线下任务如果你需要的话。

跟踪事件

保持一个由特别的 EventManager 发动的事件列表，你可以使用事件追踪。只需要简单地登录一个

Cake\Event\EventList 到管理器:

EventManager::instance()->setEventList(new EventList());

在管理器触发一个事件时，你可以从事件列表中回收掉它:

$eventsFired = EventManager::instance()->getEventList();
$firstEvent = $eventsFired[0];

追踪可以通过移除事件列表或者调用 Cake\Event\EventList::trackEvents(false) 来取消。

3.2.11 新版功能: 事件追踪和 Cake\Event\EventList 被增加。

核心事件

框架中有很多你的应用能够监听的核心事件。CakePHP的各层会发出你的应用能够监听的事件。

:section ORM/Model events <table-callbacks>

:section Controller events <controller-life-cycle>

:section View events <view-events>

注册监听器

监听器是为事件注册回调函数的好方法。它通过包含任意你想注册回调函数的类中的 Cake\Event\EventListenerInterface 接口来实现。包含它的类需要实现 implementedEvents() 方法。该方法需要返回一个该类掌握的有所有事件的名字的关联数组。

继续我们之前的例子，让我们想象我们有一个用户统计类，负责计算用户的购买记录，并且编写成全局位置的统计。这是个非常适合使用监听类的位置。这样做让你可以集中于一处的统计逻辑并且在必要情况下将其反应成事件。我们的 UserStatistics 监听器也许像下面那样开始:

use Cake\Event\EventListenerInterface;

class UserStatistic implements EventListenerInterface
{

    public function implementedEvents()
    {
        return [
            'Model.Order.afterPlace' => 'updateBuyStatistic',
        ];
    }

    public function updateBuyStatistic($event, $order)
    {
        // 更新统计的代码
    }
}

// 将用户统计对象登录到事件管理者
$statistics = new UserStatistic();
$this->Orders->eventManager()->on($statistics);

像你在上面的代码中看到的，on() 函数会接收 EventListener 接口的实例。在内部，事件管理器会使用 implementedEvents() 来登录正确的回调函数。

注册匿名监听器

事件监听器对象通常是一个实行监听器的好方法。同时你也可以捆绑任何的 callable 作为事件监听器。举例来说如果我们想要放任何订单到日志文件里面，我们可以用一个简单的匿名函数来做这些:

use Cake\Log\Log;

$this->Orders->eventManager()->on('Model.Order.afterPlace', function ($event) {
    Log::write(
        'info',
        'A new order was placed with id: ' . $event->getSubject()->id
    );
});

除了匿名函数，你也可以使用PHP支持的任何种类回调函数:

$events = [
    'email-sending' => 'EmailSender::sendBuyEmail',
    'inventory' => [$this->InventoryManager, 'decrement'],
];
foreach ($events as $callable) {
    $eventManager->on('Model.Order.afterPlace', $callable);
}

当使用不触发特殊事件的插件时，你可以触动默认事件的事件监听器。让我们举个掌管用户的反馈表单的’UserFeedback’插件的例子。从你的应用开始，你可能会知道何时一个反馈记录会被存储并且最终处理它。你可以监听全局的 Model.afterSave 事件。然而，你可以取得一个更加直接的路径并且仅仅监听你需要的事件:

// 在存储操作之前，你可以
// 创建如下, ie. config/bootstrap.php
use Cake\ORM\TableRegistry;
// 如果发送邮件
use Cake\Mailer\Email;

TableRegistry::getTableLocator()->get('ThirdPartyPlugin.Feedbacks')
    ->eventManager()
    ->on('Model.afterSave', function($event, $entity)
    {
        // 比方说我们可以给管理者发送一封邮件
        $email = new Email('default');
        $email->from('info@yoursite.com' => 'Your Site')
            ->setTo('admin@yoursite.com')
            ->setSubject('New Feedback - Your Site')
            ->send('Body of message');
    });

你可以用这个相同的路径去绑定监听器对象。

和既存监听器互相作用

假设几个事件监听器已经被登录的情况下，某个特定事件模式的有无可以当作有些动作的基础使用。:

// 登录监听器到事件管理器
$this->eventManager()->on('User.Registration', [$this, 'userRegistration']);
$this->eventManager()->on('User.Verification', [$this, 'userVerification']);
$this->eventManager()->on('User.Authorization', [$this, 'userAuthorization']);

// 应用的其它地方。
$events = $this->eventManager()->matchingListeners('Verification');
if (!empty($events)) {
    // 实行存在'Verification'事件监听器的逻辑
    // 比方说如果存在就移除该监听器
    $this->eventManager()->off('User.Verification');
} else {
    // 实行不存在'Verification'事件监听器的逻辑
}

注解

传递到 matchingListeners 方法的模式区分大小写。

3.2.3 新版功能: matchingListeners 方法返回一个与检索模式一致的数组。

优先顺序设置

在某些情况下你可能会想要控制监听器的调用顺序。比方说，如果你返回我们用户统计的例子。监听器在堆（stack）的最后被调用会比较理想。在监听器堆的最后调用它，我们可以确保事件没有被取消，以及其它监听器没有发生例外。在其它监听器修改标题或者事件对象时，我们也能得到对象的最后状态。

当增加一个监听器时，优先级被定义成了一个整数值。数值越高，方法越晚被调用。所有监听器的默认优先级都是 10。如果你想要你的方法更早调用，可以使用一个低于默认值的整数。在另一方面，如果你想要比其它方法更晚调用，可以使用一个比 10 大的数字。

两个回调函数拥有相同优先级的情况下，它们将会按照我们登录的顺序执行。你可以用 on() 方法来为回调函数设定优先级，在 implementedEvents() 函数内宣言给事件监听器设定优先级:

// 给回调函数设定优先级
$callback = [$this, 'doSomething'];
$this->eventManager()->on(
    'Model.Order.afterPlace',
    ['priority' => 2],
    $callback
);

// 给监听器设定优先级
class UserStatistic implements EventListenerInterface
{
    public function implementedEvents()
    {
        return [
            'Model.Order.afterPlace' => [
                'callable' => 'updateBuyStatistic',
                'priority' => 100
            ],
        ];
    }
}

如你所见， EventListener 对象的主要不同是需要用一个数组来确定回调方法和选择优先级。 callable 键是一个管理器可以读取以确定调用类中哪个方法的特殊数组输入。

将事件数据作为函数参数取得

当给事件的构造函数提供数据时，被提供的数据会转化成监听器的参数。一个视图层的例子是afterRender回调函数:

$this->eventManager()
    ->dispatch(new Event('View.afterRender', $this, ['view' => $viewFileName]));

View.afterRender 回调函数的监听器有以下签名:

function (Event $event, $viewFileName)

提供给事件构造函数的各值会按照它们在数据数组的顺序转化成函数的参数。如果你使用一个关联数组， array_values 的结果将会决定函数参数的顺序。

注解

和2.x不同，将事件数据转化成监听器参数是一个不可取消的默认行为。

发送事件

一旦你得到一个事件管理器的实例，你可以使用 Event\EventManager::dispatch() 来发送事件。该方法接收一个 Cake\Event\Event 实例。让我们看看发送事件:

// 一个事件监听器在发送之前已经实例化。
// 创建一个新事件并发送它。
$event = new Event('Model.Order.afterPlace', $this, [
    'order' => $order
]);
$this->eventManager()->dispatch($event);

Cake\Event\Event 在构造函数中接收3个参数。第一个是事件名，你应该尽可能确保该名字是唯一可读的。我们推荐以下惯例: Layer.eventName 对应发生在一个层级的事件（例如；Controller.startup，View.beforeRender），Layer.Class.eventName 对应发生在某个层的特定类中的事件，比方说 Model.User.afterRegister 或者 Controller.Courses.invalidAccess。

第二个参数是 subject ，表明着对象与事件的关联，通常是触发与自身相关的事件的类，$this 是最常见的使用例子。尽管一个部件（Component）也能触发控制器事件。标题类（subject class）依然非常重要，因为监听器可以迅速访问对象的属性，有机会动态地检查和变更它们。

最后，第三个参数是附加事件数据。这里可以是任意你认为有用的数据，因此监听器可以依据你传递的数据来发生动作。这个参数可以是任意类型的，我们推荐传递一个关联数组。

The Event\EventManager::dispatch() 方法接收一个事件对象作为参数并且通知所有订阅了的监听器。

停止事件

像DOM事件一样，你也许想停止一个事件让追加的监听器不会收到通知。当检测出处理不能再进行下去的代码的时候，中止保存操作的模型回调函数(比方说 beforeSave)能够让你知道如何停止。

你也可以在你的回调函数中返回一个 false 来中止事件，或者在事件对象上调用 stopPropagation() 方法:

public function doSomething($event)
{
    // ...
    return false; // 停止事件
}

public function updateBuyStatistic($event)
{
    // ...
    $event->stopPropagation();
}

停止一个事件将会停止任何被调用的回调函数。触发事件的附加代码也许会根据事件是否被停止而有不同的表现。通常来说，停止 ‘after’ 事件没有意义，不过停止 ‘before’ 事件经常被用来阻止整个操作的发生。

你可以使用 isStopped() 方法来检查是否事件被停止:

public function place($order)
{
    $event = new Event('Model.Order.beforePlace', $this, ['order' => $order]);
    $this->eventManager()->dispatch($event);
    if ($event->isStopped()) {
        return false;
    }
    if ($this->Orders->save($order)) {
        // ...
    }
    // ...
}

在之前的例子，如果事件在 beforePlace 过程中被停止的话，订单不会被保存。

取得事件结果

每当回调函数返回一个非null和false的值，都会被保存在事件对象的 $result 属性里面。这在你想要让回调函数调整事件的执行时比较有帮助。在让我们用 beforePlace 来举例子，让回调函数修改 $order 数据。

每个事件结果都可以通过直接使用事件对象结果属性或者返回回调函数自身的值来改变:

// 一个监听器的回调函数
public function doSomething($event)
{
    // ...
    $alteredData = $event->getData('order') + $moreData;
    return $alteredData;
}

// 另一个监听器的回调函数
public function doSomethingElse($event)
{
    // ...
    $event->setResult(['order' => $alteredData] + $this->result());
}

// 使用事件结果
public function place($order)
{
    $event = new Event('Model.Order.beforePlace', $this, ['order' => $order]);
    $this->eventManager()->dispatch($event);
    if (!empty($event->getResult()['order'])) {
        $order = $event->getResult()['order'];
    }
    if ($this->Orders->save($order)) {
        // ...
    }
    // ...
}

转化任意事件对象的属性和拥有传递到下一个回调函数的新数据是可能的。在多数例子中，作为事件数据或者结果来提供对象，直接转化对象，是保持相同参照和修改被共享到所有回调函数的调用的最优解决方案。

删除回调函数和监听器

如果有任何理由你想要从事件管理器删除任意的回调函数，只需要使用你用来登录它的前两个参数来调用 Cake\Event\EventManager::off() 方法:

// 登录一个函数
$this->eventManager()->on('My.event', [$this, 'doSomething']);

// 删除一个函数
$this->eventManager()->off('My.event', [$this, 'doSomething']);

// 登录一个匿名函数
$myFunction = function ($event) { ... };
$this->eventManager()->on('My.event', $myFunction);

// 删除匿名函数
$this->eventManager()->off('My.event', $myFunction);

// 添加一个事件监听器
$listener = new MyEventLister();
$this->eventManager()->on($listener);

// 从监听器删除一个简单的事件键
$this->eventManager()->off('My.event', $listener);

// 删除监听器包含的所有回调函数
$this->eventManager()->off($listener);

事件是让你在应用中把关心的东西分开的非常好的方法。它让类与其它类之间保持耦合与凝聚力。事件可以利用于应用代码的疏结合和作成能够扩张的插件。

记住更大的能力带来更大的责任。使用太多的事件会让调试更困难并且需要额外的结合测试。

扩展阅读

Behaviors

组件

助件

section_section-testing-events

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Internationalization & Localization

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Logging

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Modelless Forms

class Cake\Form\Form

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Plugins

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

REST

许多刚入门的开发者开始意识到他们需要把他们应用的核心功能展示（遍及）给更多的人。通过对外提供你应用中简单，开放的核心接口，借此可以帮助你的平台（应用）为更多的人所接受，同时允许与其他系统进行混合搭配以及简单的融合。

REST可以帮你有效地向他人提供在你的应用中已创建的逻辑（方法）。这非常方便，通常基于XML（这里所指的是简单的XML，并不是SOAP的那种复杂格式），同时依赖HTTP头来引导。在Cakephp中公开你的REST接口是非常方便的一件事。

简单的设置

最快捷的方法去创建并运行REST是通过在你的配置文件config/routes.php中添加少许几行代码来配置资源路由(resource routes).

一旦用来映射REST请求到指定控制器方法的路由已经配置好后，下一步我们就可以在控制器的方法中添加业务逻辑。最基本的控制器类似于以下代码：:

// src/Controller/RecipesController.php
class RecipesController extends AppController
{
    //以下代码CakePHP的使用者应该都了解，再次不做赘述
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('RequestHandler');
    }

    public function index()
    {
        $recipes = $this->Recipes->find('all');
        $this->set([
            'recipes' => $recipes,
            '_serialize' => ['recipes']
        ]);
    }

    public function view($id)
    {
        $recipe = $this->Recipes->get($id);
        $this->set([
            'recipe' => $recipe,
            '_serialize' => ['recipe']
        ]);
    }

    public function add()
    {
        $recipe = $this->Recipes->newEntity($this->request->getData());
        if ($this->Recipes->save($recipe)) {
            $message = 'Saved';
        } else {
            $message = 'Error';
        }
        $this->set([
            'message' => $message,
            'recipe' => $recipe,
            '_serialize' => ['message', 'recipe']
        ]);
    }

    public function edit($id)
    {
        $recipe = $this->Recipes->get($id);
        if ($this->request->is(['post', 'put'])) {
            $recipe = $this->Recipes->patchEntity($recipe, $this->request->getData());
            if ($this->Recipes->save($recipe)) {
                $message = 'Saved';
            } else {
                $message = 'Error';
            }
        }
        $this->set([
            'message' => $message,
            '_serialize' => ['message']
        ]);
    }

    public function delete($id)
    {
        $recipe = $this->Recipes->get($id);
        $message = 'Deleted';
        if (!$this->Recipes->delete($recipe)) {
            $message = 'Error';
        }
        $this->set([
            'message' => $message,
            '_serialize' => ['message']
        ]);
    }
}

具有REST特性的控制器通常使用一些转换过的扩展来生成基于不同请求的不同的格式（视图）。既然我们现在在处理REST请求，我们将会生成一个XML的格式（视图）。你也可以通过CakePHP的内置方法:doc:/views/json-and-xml-views`已达到输出JSON格式（视图）的目的。在这个内置的PHP类:php:class:`XmlView，我们定义了一个叫做``_serialize``的视图变量。这个特殊的格式（视图）变量是用来定义哪些视图变量``XmlView``应该被格式化成XML

如果我们想要在数据被转换成XML之前修改它们，我们不应该（不能）定义这个``_serialize``视图变量，而是应该使用模板文件。我们把RecipesController的REST视图放在**src/Template/Recipes/xml**内。或者我们也可以使用:php:class:Xml 类来简单快速的在这些视图中输些XML。

index方法的REST视图的简单的代码:

// src/Template/Recipes/xml/index.ctp
// Do some formatting and manipulation on
// the $recipes array.
$xml = Xml::fromArray(['response' => $recipes]);
echo $xml->asXML();

当使用:php:meth:Cake\Routing\Router::extensions() 来开放一个特殊的文档格式时，CakePHP会自动寻找匹配这个文档格式的视图helper方法。由于我们的例子中使用的是XML所以没有任何内置的helper方法，但是如果你创建了自定义的helper方法，那么它会被自动加载并在那些视图中被利用。

返回的XML可能最终像下面的例子这样：:

<recipes>
    <recipe>
        <id>234</id>
        <created>2008-06-13</created>
        <modified>2008-06-14</modified>
        <author>
            <id>23423</id>
            <first_name>Billy</first_name>
            <last_name>Bob</last_name>
        </author>
        <comment>
            <id>245</id>
            <body>Yummy yummmy</body>
        </comment>
    </recipe>
    ...
</recipes>

创建edit方法的业务逻辑会有点懵逼，不过还好。由于你提供的API输出的是XML，自然来说你的第一选择是接收XML格式的数据。不需要担心的是，由于有了:php:class:Cake\Controller\Component\RequestHandler 和 Cake\Routing\Router 可以让事情更简单。如果一个POST/PUT请求发送了XML格式的数据，那么数据会经过CakePHP的:php:class:Xml 类的处理，所有数据都会合并到``$this->request->getData()`` 中因为这些特性，处理和发送XML数据是毫无阻碍的，你完全不必去修改控制器或者模型的任何代码。所有你需要的都会合并到``$this->request->getData()`` 中。

接收其他格式的数据

典型的REST应用不仅可以输出不同格式的数据，同时也可以接收不同格式的数据在CakePHP中:php:class:RequestHandlerComponent 帮助我们实现了这个目标。一般来说，它会解码通过POST/PUT请求所接收到的JSON/XML的任何数据并且在``$this->request->getData()`` 中告诉你数据的格式。当然如果你需要的话，你也可以自定义其他的反序列化方法以此丰富你的数据接收/发送格式（通过:php:meth:RequestHandler::addInputType() 来添加）。

具有REST特性的路由

CakePHP的路由使得实现REST变得简单。查阅资源路由（resource-routes）:ref:resource-routes 以获取更多信息

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Security

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

Security

Cross Site Request Forgery

Security

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Security

class Cake\Utility\Security

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Sessions

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Testing

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Validation

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

App Class

class Cake\Core\App

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

集合

class Cake\Collection\Collection

集合类(Collection classes)提供了一组工具来操作数组或 Traversable(横穿) 对象。如果你使用过underscore.js，你就能对 Traversable 对象所具有的功能有大致的了解。

集合的实例是不可变的; 修改一个集合将会产生一个新的集合。这让使用集合对象产生更少的副作用并且有更多的可预测性。

简单例子

集合可以使用数组或者 Traversable 对象创建出来。每当你操作CakePHP中的 ORM时，你也会和集合发生作用。集合的一个简单使用:

use Cake\Collection\Collection;

$items = ['a' => 1, 'b' => 2, 'c' => 3];
$collection = new Collection($items);

// 创建一个包含元素的新集合
// 拥有比1大的值。
$overOne = $collection->filter(function ($value, $key, $iterator) {
    return $value > 1;
});

你也可以使用 collection() 这种helper（辅助）方法来替代 new Collection():

$items = ['a' => 1, 'b' => 2, 'c' => 3];

// 这两个都创建出Collection实例.
$collectionA = new Collection($items);
$collectionB = collection($items);

使用helper方法的优点是比 new Collection($items) 更容易建立连接。

Collection\CollectionTrait 能让你将类似collection的功能都任意地整合进应用中已有的 Traversable 对象。

方法（Methods）列表

append

avg

buffered

chunk

chunkWithKeys

combine

compile

contains

countBy

each

every

extract

filter

first

groupBy

indexBy

insert

isEmpty

last

listNested

map

match

max

median

min

nest

reduce

reject

sample

shuffle

skip

some

sortBy

stopWhen

sumOf

take

through

transpose

unfold

zip

迭代（Iterating）

Cake\Collection\Collection::each(callable $c)

集合可以通过 each() 和 map() 方法来转换为一个新的集合。 each() 方法不会创建一个新的集合，但是能让你修改集合中的任意对象:

$collection = new Collection($items);
$collection = $collection->each(function ($value, $key) {
    echo "Element $key: $value";
});

each() 的返回值是一个集合对象。Each会迅速迭代集合同时将结果回调到集合中的每个值上。

Cake\Collection\Collection::map(callable $c)

map() 方法会基于一开始的集合内的各对象产生回调影响后的输出结果，来创建一个新集合:

$items = ['a' => 1, 'b' => 2, 'c' => 3];
$collection = new Collection($items);

$new = $collection->map(function ($value, $key) {
    return $value * 2;
});

// $result的内容是 ['a' => 2, 'b' => 4, 'c' => 6];
$result = $new->toArray();

map() 通过迭代时逐渐更新内部项目来创建一个新的迭代器。

Cake\Collection\Collection::extract($matcher)

map() 的一个最常用的功能是从集合中选取一个单独的项目。如果你打算建一个由个别属性值的元素组成的列表，你可以使用 extract() 方法:

$collection = new Collection($people);
$names = $collection->extract('name');

// $result 内容是 ['mark', 'jose', 'barbara'];
$result = $names->toArray();

集合中还存在着很多其它方法，你也可以使用点分割的表现方式来选取需要的项目。这个例子将会返回一个从文章列表里提取的作者名（author names）的集合:

$collection = new Collection($articles);
$names = $collection->extract('author.name');

// $result 内容是 ['Maria', 'Stacy', 'Larry'];
$result = $names->toArray();

最后，如果你使用的属性不被认为是一个正确的路径，你可以用一个回调方法返回它:

$collection = new Collection($articles);
$names = $collection->extract(function ($article) {
    return $article->author->name . ', ' . $article->author->last_name;
});

时常有这么一回事，你需要选取（extract）一个在复杂的数组或对象中，被嵌套在其它结构里面共同的键（这里指的是’number’)。这种情况你可以用 {*} 来配对表路径的键。当你从 HasMany（有很多）和BelongsToMany（属于很多）的关联数据中进行选取时，这种匹配方式会很实用:

$data = [
    [
        'name' => 'James',
        'phone_numbers' => [
            ['number' => 'number-1'],
            ['number' => 'number-2'],
            ['number' => 'number-3'],
        ]
    ],
    [
        'name' => 'James',
        'phone_numbers' => [
            ['number' => 'number-4'],
            ['number' => 'number-5'],
        ]
    ]
];

$numbers = (new Collection($data))->extract('phone_numbers.{*}.number');
$numbers->toList();
// Returns ['number-1', 'number-2', 'number-3', 'number-4', 'number-5']

这个例子和其它例子不同，使用的是 toList() 方法。这是个我们在有可能有相同的键的时候也能得到结果的重要方法。 toList() 方法允许我们在即使有很多键重复的情况下也能得到所有的值。

不同于 Cake\Utility\Hash::extract() ，这个方法只允许 {*} 通配符。并不支持其它的通配符和匹配属性。

Cake\Collection\Collection::combine($keyPath, $valuePath, $groupPath = null)

集合允许你在已有的集合的基础上创建一个由键值对组成的新的集合。键和值的路径都可以使用点记法来表示:

$items = [
    ['id' => 1, 'name' => 'foo', 'parent' => 'a'],
    ['id' => 2, 'name' => 'bar', 'parent' => 'b'],
    ['id' => 3, 'name' => 'baz', 'parent' => 'a'],
];
$combined = (new Collection($items))->combine('id', 'name');

// Result will look like this when converted to array
[
    1 => 'foo',
    2 => 'bar',
    3 => 'baz',
];

你也可以选择性地使用 groupPath 来将基于键值对的结果分组:

$combined = (new Collection($items))->combine('id', 'name', 'parent');

// 当转换成数组后结果将会如下
[
    'a' => [1 => 'foo', 3 => 'baz'],
    'b' => [2 => 'bar']
];

最后你可以用 closures 来动态地构建一个keys/values/groups路径，比方说当你需要用到entities（实体）和dates（日期）时（被ORM转换成了 Cake/Time 的实例），你可能会想要将结果根据日期（date）进行分组:

$combined = (new Collection($entities))->combine(
    'id',
    function ($entity) { return $entity; },
    function ($entity) { return $entity->date->toDateString(); }
);

// 当转换成数组时结果将会如下
[
    'date string like 2015-05-01' => ['entity1->id' => entity1, 'entity2->id' => entity2, ..., 'entityN->id' => entityN]
    'date string like 2015-06-01' => ['entity1->id' => entity1, 'entity2->id' => entity2, ..., 'entityN->id' => entityN]
]

Cake\Collection\Collection::stopWhen(callable $c)

你可以通过 stopWhen() 方法在任意点上停止迭代。在集合中使用这个方法时，如果某一个元素传入可调用方法返回false，将会产生一个新的集合并停止产生其它返回结果:

$items = [10, 20, 50, 1, 2];
$collection = new Collection($items);

$new = $collection->stopWhen(function ($value, $key) {
    // 在出现第一个大于30的值的时停止
    return $value > 30;
});

// $result 内容是 [10, 20];
$result = $new->toArray();

Cake\Collection\Collection::unfold(callable $c)

有时集合的内部项目包含有拥有更多内部项目的数组或迭代器。如果你希望让这些内部结构变得平行并且一次迭代就能遍历所有元素，你可以使用 unfold() 方法。它将会创建一个单一嵌套着每个元素的新集合:

$items = [[1, 2, 3], [4, 5]];
$collection = new Collection($items);
$new = $collection->unfold();

// $result 内容是 [1, 2, 3, 4, 5];
$result = $new->toList();

当传递一个可调用函数到 unfold() 时，你可以控制原始的集合中的项目的哪一个来执行unfolded（展开）操作。这在返回分页服务的数据时很有帮助:

$pages = [1, 2, 3, 4];
$collection = new Collection($pages);
$items = $collection->unfold(function ($page, $key) {
    // 返回一页结果的假想web服务
    return MyService::fetchPage($page)->toArray();
});

$allPagesItems = $items->toList();

如果你使用的是PHP 5.5+版本，你在 unfold() 中使用关键词 yield 来返回集合的每个项目中你需要数量的元素:

$oddNumbers = [1, 3, 5, 7];
$collection = new Collection($oddNumbers);
$new = $collection->unfold(function ($oddNumber) {
    yield $oddNumber;
    yield $oddNumber + 1;
});

// $result 内容是 [1, 2, 3, 4, 5, 6, 7, 8];
$result = $new->toList();

Cake\Collection\Collection::chunk($chunkSize)

当处理集合中包含有非常多数量的项目时，把它们批量处理或许比一个个处理更好一点。你可以使用 chunk() 将一个集合分割成多个固定容量的数组:

$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
$collection = new Collection($items);
$chunked = $collection->chunk(2);
$chunked->toList(); // [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11]]

chunk 方法在进行批量处理时非常有用，用一个数据库结果来举例子:

$collection = new Collection($articles);
$collection->map(function ($article) {
        // Change a property in the article
        $article->property = 'changed';
    })
    ->chunk(20)
    ->each(function ($batch) {
        myBulkSave($batch); // 该方法将会被每个批量处理（batch）调用
    });

Cake\Collection\Collection::chunkWithKeys($chunkSize)

与 chunk()`相似，``chunkWithKeys()` 允许你将一个集合保留着键分割成更小的几部分进行处理。这在分割关联数组时十分有用:

$collection = new Collection([
    'a' => 1,
    'b' => 2,
    'c' => 3,
    'd' => [4, 5]
]);
$chunked = $collection->chunkWithKeys(2)->toList();
// Creates
[
    ['a' => 1, 'b' => 2],
    ['c' => 3, 'd' => [4, 5]]
]

3.4.0 新版功能: chunkWithKeys() was added in 3.4.0

过滤（Filtering）

Cake\Collection\Collection::filter(callable $c)

集合能够基于回调方法简单地过滤并创建新的集合。你能用 filter() 创建一个符合回调标准元素构成的集合:

$collection = new Collection($people);
$ladies = $collection->filter(function ($person, $key) {
    return $person->gender === 'female';
});
$guys = $collection->filter(function ($person, $key) {
    return $person->gender === 'male';
});

Cake\Collection\Collection::reject(callable $c)

与 filter() 对立的是 reject()。该方法执行一个消极过滤，它将符合过滤条件的元素都删除:

$collection = new Collection($people);
$ladies = $collection->reject(function ($person, $key) {
    return $person->gender === 'male';
});

Cake\Collection\Collection::every(callable $c)

你可以用过滤方法来进行真伪测试。要检测是否集合中每个元素都符合测试条件的话你可以使用 every():

$collection = new Collection($people);
$allYoungPeople = $collection->every(function ($person) {
    return $person->age < 21;
});

Cake\Collection\Collection::some(callable $c)

你可以用 some()` 方法来检测集合中包含的元是否至少有一个符合过滤条件:

$collection = new Collection($people);
$hasYoungPeople = $collection->some(function ($person) {
    return $person->age < 21;
});

Cake\Collection\Collection::match(array $conditions)

你想要提取出一个只包含你指定属性的元素的新集合的话，你可以使用 match() 方法:

$collection = new Collection($comments);
$commentsFromMark = $collection->match(['user.name' => 'Mark']);

Cake\Collection\Collection::firstMatch(array $conditions)

属性名可以用点记法表示。你可以遍历过嵌套着的实例并匹配它们的值，当你只需要第一个匹配的元素时，你可以用 firstMatch():

$collection = new Collection($comments);
$comment = $collection->firstMatch([
    'user.name' => 'Mark',
    'active' => true
]);

就像你在上面看到的那样， match() 和 firstMatch() 都让你能用复数条件进行匹配。另外，条件能用于不同的路径，能够允许你用复杂的方式表现。

集成（Aggregation）

Cake\Collection\Collection::reduce(callable $c)

map() 的对立操作是 reduce() 。该方法能够从集合的所有元素中得到一个单一的结果:

$totalPrice = $collection->reduce(function ($accumulated, $orderLine) {
    return $accumulated + $orderLine->price;
}, 0);

在上面例子中， $totalPrice 将是集合中所有单价的总和。需要注意 reduce() 的第二个参数将为reduce操作传递一个初期值:

$allTags = $collection->reduce(function ($accumulated, $article) {
    return array_merge($accumulated, $article->tags);
}, []);

Cake\Collection\Collection::min(string|callable $callback, $type = SORT_NUMERIC)

需要选取一个属性的最小值的话，可以使用 min() 方法，注意它会返回集合中拥有该最小值的元素，而不仅仅是一个值:

$collection = new Collection($people);
$youngest = $collection->min('age');

echo $youngest->name;

你也能通过提供正确的路径或者一个回调函数来选择你要比较的属性:

$collection = new Collection($people);
$personYoungestChild = $collection->min(function ($person) {
    return $person->child->age;
});

$personWithYoungestDad = $collection->min('dad.age');

Cake\Collection\Collection::max(string|callable $callback, $type = SORT_NUMERIC)

以上用发也能应用到 max() 方法上，它将返回集合中拥有该属性最大值的的元素:

$collection = new Collection($people);
$oldest = $collection->max('age');

$personOldestChild = $collection->max(function ($person) {
    return $person->child->age;
});

$personWithOldestDad = $collection->max('dad.age');

Cake\Collection\Collection::sumOf(string|callable $callback)

最后， sumOf() 方法会返回所有元素某项属性的和值:

$collection = new Collection($people);
$sumOfAges =  $collection->sumOf('age');

$sumOfChildrenAges = $collection->sumOf(function ($person) {
    return $person->child->age;
});

$sumOfDadAges = $collection->sumOf('dad.age');

Cake\Collection\Collection::avg($matcher = null)

该方法能计算集合中元素的平均值。选择一个复合路径或者函数来确定需要计算哪样属性的平均值:

$items = [
   ['invoice' => ['total' => 100]],
   ['invoice' => ['total' => 200]],
];

// 平均值: 150
$average = (new Collection($items))->avg('invoice.total');

3.5.0 新版功能.

Cake\Collection\Collection::median($matcher = null)

该方法可计算一组元素的中间值。在参数中输入一个复合路径或者函数来确定需要计算哪样属性的中间值:

$items = [
  ['invoice' => ['total' => 400]],
  ['invoice' => ['total' => 500]],
  ['invoice' => ['total' => 100]],
  ['invoice' => ['total' => 333]],
  ['invoice' => ['total' => 200]],
];

// Median: 333
$median = (new Collection($items))->median('invoice.total');

3.5.0 新版功能.

分组和统计（Grouping and Counting）

Cake\Collection\Collection::groupBy($callback)

当集合的某项属性的值一样时，可以用不同的键来将它们结合到一个新的collection中:

$students = [
    ['name' => 'Mark', 'grade' => 9],
    ['name' => 'Andrew', 'grade' => 10],
    ['name' => 'Stacy', 'grade' => 10],
    ['name' => 'Barbara', 'grade' => 9]
];
$collection = new Collection($students);
$studentsByGrade = $collection->groupBy('grade');

// 转化成数组后结果将会如下:
[
  10 => [
    ['name' => 'Andrew', 'grade' => 10],
    ['name' => 'Stacy', 'grade' => 10]
  ],
  9 => [
    ['name' => 'Mark', 'grade' => 9],
    ['name' => 'Barbara', 'grade' => 9]
  ]
]

一般情况，可以提供一个点分割路径来选取嵌套结构的值或者提供你自己的回调函数来进行动态的结合:

$commentsByUserId = $comments->groupBy('user.id');

$classResults = $students->groupBy(function ($student) {
    return $student->grade > 6 ? 'approved' : 'denied';
});

Cake\Collection\Collection::countBy($callback)

如果想要知道不同的分组范围内的出现次数，你可以用 countBy() 方法。它的参数与上面已经知道的 groupBy` 相同:

$classResults = $students->countBy(function ($student) {
    return $student->grade > 6 ? 'approved' : 'denied';
});

// 转化成数组后结果将会如下:
['approved' => 70, 'denied' => 20]

Cake\Collection\Collection::indexBy($callback)

有些特定的时候你知道你想要用来分组的某元素的某属性时唯一的，这时候你可以使用 indexBy() 方法:

$usersById = $users->indexBy('id');

// 转化成数组后结果将会如下:
[
    1 => 'markstory',
    3 => 'jose_zap',
    4 => 'jrbasso'
]

和 groupBy() 方法一样，你也能使用路径表属性或者回调函数:

$articlesByAuthorId = $articles->indexBy('author.id');

$filesByHash = $files->indexBy(function ($file) {
    return md5($file);
});

Cake\Collection\Collection::zip($elements)

使用 zip() 方法能够将不同集合中的元素结合到一起。它将返回一个元素结合后的集合, 其中处于集合中同一位置的元素将被结合到一起:

$odds = new Collection([1, 3, 5]);
$pairs = new Collection([2, 4, 6]);
$combined = $odds->zip($pairs)->toList(); // [[1, 2], [3, 4], [5, 6]]

你也能够一次性打包复数个集合:

$years = new Collection([2013, 2014, 2015, 2016]);
$salaries = [1000, 1500, 2000, 2300];
$increments = [0, 500, 500, 300];

$rows = $years->zip($salaries, $increments)->toList();
// 结果:
[
    [2013, 1000, 0],
    [2014, 1500, 500],
    [2015, 2000, 500],
    [2016, 2300, 300]
]

就像你看到的， zip() 方法在转换多重数组时非常实用:

$data = [
    2014 => ['jan' => 100, 'feb' => 200],
    2015 => ['jan' => 300, 'feb' => 500],
    2016 => ['jan' => 400, 'feb' => 600],
]

// 把'jan'和'feb'数据打包到一起

$firstYear = new Collection(array_shift($data));
$firstYear->zip($data[0], $data[1])->toList();

// 或者 $firstYear->zip(...$data) 当 PHP >= 5.6

// 结果
[
    [100, 300, 400],
    [200, 500, 600]
]

排序（Sorting）

Cake\Collection\Collection::sortBy($callback)

集合的值可以基于某一列或者一个自定义函数来升序或降序排列。使用 sortBy 你可以根据集合中的某项值来生成一个排序过的:

$collection = new Collection($people);
$sorted = $collection->sortBy('age');

像上面那样，你可以传递一个拥有值的列名或者属性名来排序。你也能用点分割的方法来指定属性路径。下面一个例子将会根据作者的名字对作品进行排序:

$collection = new Collection($articles);
$sorted = $collection->sortBy('author.name');

sortBy() 方法可以让你柔软地定义一个提取功能动态地选择集合中两个值的比较值:

$collection = new Collection($articles);
$sorted = $collection->sortBy(function ($article) {
    return $article->author->name . '-' . $article->title;
});

为了定义集合要如何排序，你可以提供 SORT_ASC 或者 SORT_DESC 当作第二个参数以确定要“升序”还是“降序”。默认情况下，集合会自动选择降序:

$collection = new Collection($people);
$sorted = $collection->sortBy('age', SORT_ASC);

有时你需要定义你用来比较的是哪一类数据。这种情况你需要在 sortBy() 方法中提供第三个参数，参数需要在以下定数中选择一个:

SORT_NUMERIC: 用于比较数值

SORT_STRING: 用于比较字符串的值

SORT_NATURAL: 对包含数字的字符串进行排序时，那些数字会以自然顺序排列。比方说”10”会显示在”2”的后面

SORT_LOCALE_STRING: 根据当前环境来比较字符串

默认情况下, SORT_NUMERIC 将自动使用:

$collection = new Collection($articles);
$sorted = $collection->sortBy('title', SORT_ASC, SORT_NATURAL);

警告

一次以上用迭代来对集合///////////////////////////////进行排序通常比较麻烦。如果你打算这么做，可以考虑将集合转换成数组或者对它简单使用 compile() 方法。

使用树结构（Tree Data）数据

Cake\Collection\Collection::nest($idPath, $parentPath)

并非所有数据都是用线形表示的。集合可以让复杂的嵌套构造变得更加平坦化和结构化。用 nest() 方法能够很容易创建一个根据父元素的标识符属性来把子元素分组的嵌套结构。

此方法需要两个参数。第一个参数是用来辨别元素的属性，第二个参数是识别关系的标识符属性名:

$collection = new Collection([
    ['id' => 1, 'parent_id' => null, 'name' => 'Birds'],
    ['id' => 2, 'parent_id' => 1, 'name' => 'Land Birds'],
    ['id' => 3, 'parent_id' => 1, 'name' => 'Eagle'],
    ['id' => 4, 'parent_id' => 1, 'name' => 'Seagull'],
    ['id' => 5, 'parent_id' => 6, 'name' => 'Clown Fish'],
    ['id' => 6, 'parent_id' => null, 'name' => 'Fish'],
]);

$collection->nest('id', 'parent_id')->toArray();
// 结果
[
    [
        'id' => 1,
        'parent_id' => null,
        'name' => 'Birds',
        'children' => [
            ['id' => 2, 'parent_id' => 1, 'name' => 'Land Birds', 'children' => []],
            ['id' => 3, 'parent_id' => 1, 'name' => 'Eagle', 'children' => []],
            ['id' => 4, 'parent_id' => 1, 'name' => 'Seagull', 'children' => []],
        ]
    ],
    [
        'id' => 6,
        'parent_id' => null,
        'name' => 'Fish',
        'children' => [
            ['id' => 5, 'parent_id' => 6, 'name' => 'Clown Fish', 'children' => []],
        ]
    ]
];

子元素嵌套在集合中的每个元素的 children 属性里面。这样的数据表现方式对于展示某些品目或者将元素放置到树结构的确定的层级上时会比较有帮助。

Cake\Collection\Collection::listNested($dir = 'desc', $nestingKey = 'children')

将 nest() 进行反转的是 listNested() 。该方法能够将一个树结构变成一个线形结构。它需要两个参数，第一参数决定运行模式（升序，降序，或者保持不变），第二个是指向集合中各元素的子元素的属性名。

输入之前的例子中构建的嵌套结构，我们可以展开它:

$nested->listNested()->toList();

// 结果
[
    ['id' => 1, 'parent_id' => null, 'name' => 'Birds', 'children' => [...]],
    ['id' => 2, 'parent_id' => 1, 'name' => 'Land Birds'],
    ['id' => 3, 'parent_id' => 1, 'name' => 'Eagle'],
    ['id' => 4, 'parent_id' => 1, 'name' => 'Seagull'],
    ['id' => 6, 'parent_id' => null, 'name' => 'Fish', 'children' => [...]],
    ['id' => 5, 'parent_id' => 6, 'name' => 'Clown Fish']
]

默认情况下，树结构的头部到末尾都会被转化。你可以指示它仅仅返回树结构最末端的元素:

  $nested->listNested()->toArray();

  // 结果
。  [
      ['id' => 3, 'parent_id' => 1, 'name' => 'Eagle'],
      ['id' => 4, 'parent_id' => 1, 'name' => 'Seagull'],
      ['id' => 5, 'parent_id' => 6, 'name' => 'Clown Fish']
  ]

一旦你将一个树结构转换成列表结构，使用 printer() 方法能够设置列表的输出方式:

$nested->listNested()->printer('name', 'id', '--')->toArray();

// Returns
[
    3 => 'Eagle',
    4 => 'Seagull',
    5 -> '--Clown Fish',
]

printer() 方法也可以让你使用回调函数来生成键或者值:

$nested->listNested()->printer(
    function ($el) {
        return $el->name;
    },
    function ($el) {
        return $el->id;
    }
);

其它方法

Cake\Collection\Collection::isEmpty()

可以让你知道一个集合是否有包含元素:

$collection = new Collection([]);
// 结果为 true
$collection->isEmpty();

$collection = new Collection([1]);
// 结果为 false
$collection->isEmpty();

Cake\Collection\Collection::contains($value)

使用 contains() 方法能让你快速检查集合是否包含某个特定的值:

$items = ['a' => 1, 'b' => 2, 'c' => 3];
$collection = new Collection($items);
$hasThree = $collection->contains(3);

其中的比较是通过 === 来执行的，如果你希望执行一个松散的比较，你可以使用 some() 方法。

Cake\Collection\Collection::shuffle()

有时你可能希望随机显示集合的值。要生成一个各个值被分配到随机位置的集合的话，可以使用 shuffle:

$collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3]);

// This could return [2, 3, 1]
$collection->shuffle()->toArray();

Cake\Collection\Collection::transpose()

当你翻转一个集合时，你能得到每一行都由原先在同一列上的元素组成的集合:

$items = [
   ['Products', '2012', '2013', '2014'],
   ['Product A', '200', '100', '50'],
   ['Product B', '300', '200', '100'],
   ['Product C', '400', '300', '200'],
]
$transpose = (new Collection($items))->transpose()->toList();

// 返回
[
    ['Products', 'Product A', 'Product B', 'Product C'],
    ['2012', '200', '300', '400'],
    ['2013', '100', '200', '300'],
    ['2014', '50', '100', '200'],
]

3.3.0 新版功能: Collection::transpose() 追加于 3.3.0.

抽取元素

Cake\Collection\Collection::sample(int $size)

当做一个快速的静态分析时，对一个集合的元素进行随机化的处理比较常见。另一个比较常见的处理是，从集合中抽取几个随机的值出来以进行更多的测试。比方说你想要随机抽取5名用户来进行A/B测试，你可以使用 sample() 方法:

$collection = new Collection($people);

// 从集合中随机抽取最大20名用户
$testSubjects = $collection->sample(20);

sample() 会根据你定义的第一个参数来决定最大的抽取数。如果集合中没有足够数量的元素来满足样本要求，那么将返回元素被随机排列过后的整个元素本身。

Cake\Collection\Collection::take(int $size, int $from)

无论何时你想要集合中的某一部分的时候，可以使用 take() 方法，它会创建一个数量为你在第一个参数中定义的，同时位置由你传的第二个参数定义的新集合:

$topFive = $collection->sortBy('age')->take(5);

// 从位置4开始在集合中抽取5个人
$nextTopFive = $collection->sortBy('age')->take(5, 4);

位置是从0开始的，所以第一个位置其实是``0``。

Cake\Collection\Collection::skip(int $positions)

像 take() 的第二个参数能够让你从集合中取值时略过一些元素，你也可以用 skip() 来拿到某个位置之后余下的元素:

$collection = new Collection([1, 2, 3, 4]);
$allExceptFirstTwo = $collection->skip(2)->toList(); // [3, 4]

Cake\Collection\Collection::first()

一个 take() 的最常用的用法是取得集合的第一个元素。一个快捷方法 first() 也能让你得到相同的效果:

$collection = new Collection([5, 4, 3, 2]);
$collection->first(); // Returns 5

Cake\Collection\Collection::last()

相似地，你也能用 last()` 方法来取得集合最后一个元素:

$collection = new Collection([5, 4, 3, 2]);
$collection->last(); // Returns 2

集合扩展

Cake\Collection\Collection::append(array|Traversable $items)

你也可以把复数个集合组合成一个。这让你能够从不同的资源中聚集数据，并把它们串联起来，然后更顺畅地使用其它的集合方法。 append() 方法将返回一个包含着两边资源值的新集合:

$cakephpTweets = new Collection($tweets);
$myTimeline = $cakephpTweets->append($phpTweets);

// 两边资源中包含cakefest的Tweets
$myTimeline->filter(function ($tweet) {
    return strpos($tweet, 'cakefest');
});

警告

当从不同的资源处进行增加合并时，你可以预期到两个集中有一样的键的存在。举个例子，当你合并两个简单的数组，这种情况将会在你用 toArray() 把集合转换为数组时出现问题。如果你不想要一个集合中的值因为键相同而覆盖掉另一集合中的值，你需要确保使用 toList() 来去掉它们的键而表示整个集合的值。

元素的更新

Cake\Collection\Collection::insert(string $path, array|Traversable $items)

有时，你或许有两个不同数据的集合，你想要将其中一组的元素插入到另一组中间去。这是一个从没有支持数据结合以及合并的资源中取得数据的常见例子。

集合提供一个 insert() 方法让你可以将集合中的各个元素注入到另一个集合中:

$users = [
    ['username' => 'mark'],
    ['username' => 'juan'],
    ['username' => 'jose']
];

$languages = [
    ['PHP', 'Python', 'Ruby'],
    ['Bash', 'PHP', 'Javascript'],
    ['Javascript', 'Prolog']
];

$merged = (new Collection($users))->insert('skills', $languages);

当转换成数组之后， $merged 集合将会时:

[
    ['username' => 'mark', 'skills' => ['PHP', 'Python', 'Ruby']],
    ['username' => 'juan', 'skills' => ['Bash', 'PHP', 'Javascript']],
    ['username' => 'jose', 'skills' => ['Javascript', 'Prolog']]
];

insert() 的第一个参数是一个点分割路径，用来指定元素将要插入的位置。第二个参数是任意的你想要转化成集合的对象。

请注意要素是根据它们的位置顺序进行插入的，因此，第二个集合的第一个元素会合并到第一个集合的第一个元素中。

如果第二个集合中没有足够的元素插入到第一个集合中，那么对应的属性将会是 null:

$languages = [
    ['PHP', 'Python', 'Ruby'],
    ['Bash', 'PHP', 'Javascript']
];

$merged = (new Collection($users))->insert('skills', $languages);

// 结果
[
    ['username' => 'mark', 'skills' => ['PHP', 'Python', 'Ruby']],
    ['username' => 'juan', 'skills' => ['Bash', 'PHP', 'Javascript']],
    ['username' => 'jose', 'skills' => null]
];

insert() 方法可以操作包含 ArrayAccess 接口的数组元素或者对象。

让集合的方法重复使用

使用集合闭包方法在工作小或者明确的时候非常有效，但是它也容易很快陷入麻烦。这在需要使用大量不同方法时或者闭包方法不仅仅只有几行时比较明显。

有些情况你用于集合方法的逻辑可以在你应用的许多地方重复利用。这中种情况建议你将复杂的集合逻辑抽取出来定义成一个类。举个例子，想象一下下面一样的长的闭包方法:

$collection
        ->map(function ($row, $key) {
            if (!empty($row['items'])) {
                $row['total'] = collection($row['items'])->sumOf('price');
            }

            if (!empty($row['total'])) {
                $row['tax_amount'] = $row['total'] * 0.25;
            }

            // 后面有更多的代码...

            return $modifiedRow;
        });

它可以通过创建另一个类来重构:

class TotalOrderCalculator
{

        public function __invoke($row, $key)
        {
            if (!empty($row['items'])) {
                $row['total'] = collection($row['items'])->sumOf('price');
            }

            if (!empty($row['total'])) {
                $row['tax_amount'] = $row['total'] * 0.25;
            }

            // 后面有更多代码...

            return $modifiedRow;
        }
}

// 在你的map()函数使用这些逻辑
$collection->map(new TotalOrderCalculator)

Cake\Collection\Collection::through(callable $c)

有时一个集合连锁使用一些方法也能够被重复利用，不过它们必须按照特定的顺序。在这些情况中，你可以用 through() 来与一个包含了 __invoke 的类组合以构建方便的数据调取:

$collection
        ->map(new ShippingCostCalculator)
        ->map(new TotalOrderCalculator)
        ->map(new GiftCardPriceReducer)
        ->buffered()
       ...

以上的方法可以被提取进一个新的类中，这样就不需要每次都重复调用它们:

class FinalCheckOutRowProcessor
{

        public function __invoke($collection)
        {
                return $collection
                        ->map(new ShippingCostCalculator)
                        ->map(new TotalOrderCalculator)
                        ->map(new GiftCardPriceReducer)
                        ->buffered()
                       ...
        }
}

// 现在你能使用 through() 方法来一次性调用所有方法
$collection->through(new FinalCheckOutRowProcessor);

集合优化

Cake\Collection\Collection::buffered()

集合一般在大多数情况下创建新集合时会延迟使用函数。这意味着即使你调用一个函数也不等于马上就会执行它。在这个类中的大多数函数都是这种情况。延迟评价在你不使用集合中的全部的值时能够节约资源。当迭代器早早停止的时候你或许并没有用到所有的值，或者一个例外/失败提前出现。

另外，延迟评价帮助某些操作的速度提高。思考一下下面的例子:

$collection = new Collection($oneMillionItems);
$collection = $collection->map(function ($item) {
    return $item * 2;
});
$itemsToShow = $collection->take(30);

如果集合没有延迟处理，即使我们只想要取出30个元素我们也将不得不处理百万条数据。相对地， map操作仅仅会作用到我们使用的30条元素。即使是很小的集合，当我使用复数回操作时也能够从延迟评价中得到好处。举个例子：调用 map() 两回然后调用 filter() 。

延迟评价也有它的缺点。如果你早期对集合进行优化，你会执行多次相同的操作。考虑一下下面的例子:

$ages = $collection->extract('age');

$youngerThan30 = $ages->filter(function ($item) {
    return $item < 30;
});

$olderThan30 = $ages->filter(function ($item) {
    return $item > 30;
});

如果我们两次迭代 youngerThan30 和 olderThan30，集合将需要执行 extract() 操作两次。这是因为集合时不变的，延迟的抽出操作将会为两个过滤器使用。

幸运的是我们可以用一个简单的方法来克服这个问题。如果你打算从确定的操作中不止一次重复利用某些值，你能用 buffered() 方法将一个结果编入另一个集合中:

$ages = $collection->extract('age')->buffered();
$youngerThan30 = ...
$olderThan30 = ...

现在，当两个集合进行迭代时，它们只会调取抽出操作一次。

让集合能够迭代回

buffered() 方法在将non-rewindable的迭代器转化为集合时会比较实用，因为这样可以迭代一次以上:

// 在 PHP 5.5+
public function results()
{
    ...
    foreach ($transientElements as $e) {
        yield $e;
    }
}
$rewindable = (new Collection(results()))->buffered();

复制集合

Cake\Collection\Collection::compile(bool $preserveKeys = true)

有时候你需要从其它的集合中克隆出元素。这在你需要在不同地方同时迭代相同的一组元素时非常有帮助。 compile() 方法可以从另一个集合中克隆出一个:

$ages = $collection->extract('age')->compile();

foreach ($ages as $age) {
    foreach ($collection as $element) {
        echo h($element->name) . ' - ' . $age;
    }
}

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Folder & File

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Hash

class Cake\Utility\Hash

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Http Client

class Cake\Network\Http\Client(mixed $config = [])

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Inflector

class Cake\Utility\Inflector

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Number

class Cake\I18n\Number

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Registry Objects

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Text

class Cake\Utility\Text

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Time

class Cake\I18n\Time

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Xml

class Cake\Utility\Xml

Xml类充许将数组转换成 SimpleXMLElement 或者 DOMDocument 对象，并且可以转回数组。

创建XML对象

static Cake\Utility\Xml::build($input, array $options = [])

你可使用Xml::build() 载入XML-ish数据。取决于你 $options 的参数，这个方法允许你返回一个 SimpleXMLElement (default) or DOMDocument 对象，在各种数据源中，你可使用 Xml::build() 去创建一个XML对象。例如，你可以通过下面的设置创建XML:

$text = '<?xml version="1.0" encoding="utf-8"?>
<post>
    <id>1</id>
    <title>Best post</title>
    <body> ... </body>
</post>';
$xml = Xml::build($text);

你也可以通过本地文件创建Xml对象:

//本地文件
$xml = Xml::build('/home/awesome/unicorns.xml');

你也可以通可一个数组创建Xml对象:

$data = [
    'post' => [
        'id' => 1,
        'title' => 'Best post',
        'body' => ' ... '
    ]
];
$xml = Xml::build($data);

如果你的输入参数是无效的，Xml类会抛出一个异常:

$xmlString = 'What is XML?';
try {
    $xmlObject = Xml::build($xmlString); // 这儿会抛出一个异常
} catch (\Cake\Utility\Exception\XmlException $e) {
    throw new InternalErrorException();
}

注解

DOMDocument 和 SimpleXML 实现了不同的API’s。你从XML请求的对象，一定要使用正确的方法。

把Xml字符串转换成数组

toArray($obj);

用Xml类把Xml字符串转换成数组是非简单的。默认你将获得返回值是SimpleXml对象:

$xmlString = '<?xml version="1.0"?><root><child>value</child></root>';
$xmlArray = Xml::toArray(Xml::build($xmlString));

如果你的XML是无效的将会执行 Cake\Utility\Exception\XmlException 异常类。

把数组转换成Xml

$xmlArray = ['root' => ['child' => 'value']];
//你也可以使用 Xml::build().
$xmlObject = Xml::fromArray($xmlArray, ['format' => 'tags']);
$xmlString = $xmlObject->asXML();

你数组最上级必须包含一个元素而且不能是数字，如果你的数据不是这种格式，Xml装会抛出一个异常，无效的数组示例:

// 最上层数组的键名是一个数字
[
    ['key' => 'value']
];

// 最上层数组有多个键值
[
    'key1' => 'first value',
    'key2' => 'other value'
];

默认的数组值将作为一个xml标签输出，如果你想自定义一个属性或者文本值，你可以在属性加面加@。文本值用 @作为键名:

$xmlArray = [
    'project' => [
        '@id' => 1,
        'name' => 'Name of project, as tag',
        '@' => 'Value of project'
    ]
];
$xmlObject = Xml::fromArray($xmlArray);
$xmlString = $xmlObject->asXML();

The content of $xmlString will be:

<?xml version="1.0"?>
<project id="1">Value of project<name>Name of project, as tag</name></project>

使用命名空间

使用XML命名空间，在数组中创键一个名字是xmlns的键名：在一个通用的命名空间或输入前缀的xmlns：自定义命名空间。 看下面的示例:

$xmlArray = [
    'root' => [
        'xmlns:' => 'https://cakephp.org',
        'child' => 'value'
    ]
];
$xml1 = Xml::fromArray($xmlArray);

$xmlArray(
    'root' => [
        'tag' => [
            'xmlns:pref' => 'https://cakephp.org',
            'pref:item' => [
                'item 1',
                'item 2'
            ]
        ]
    ]
);
$xml2 = Xml::fromArray($xmlArray);

$xml1 和 $xml2 的值分别是:

<?xml version="1.0"?>
<root xmlns="https://cakephp.org"><child>value</child>

<?xml version="1.0"?>
<root><tag xmlns:pref="https://cakephp.org"><pref:item>item 1</pref:item><pref:item>item 2</pref:item></tag></root>

创建一个子节点

当你创建一个XML文档，你只需要对你的文档使用原生接口操作增加，移除或者操作子节点:

// 使用 SimpleXML
$myXmlOriginal = '<?xml version="1.0"?><root><child>value</child></root>';
$xml = Xml::build($myXmlOriginal);
$xml->root->addChild('young', 'new value');

// 使用 DOMDocument
$myXmlOriginal = '<?xml version="1.0"?><root><child>value</child></root>';
$xml = Xml::build($myXmlOriginal, ['return' => 'domdocument']);
$child = $xml->createElement('young', 'new value');
$xml->firstChild->appendChild($child);

小技巧

用SimpleXMLElement 或者 DomDocument处理Xml后， 可以使用Xml::toArray()。

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Constants & Functions

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Debug Kit

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Migrations

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Appendices

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

Appendices contain information regarding the new features introduced in each version and the migration path between versions.

3.x Migration Guide

3.x Migration Guide

General Information

CakePHP Development Process

Glossary

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.x Migration Guide

Migration guides contain information regarding the new features introduced in each version and the migration path between versions.

3.5 Migration Guide

3.5 Migration Guide

3.4 Migration Guide

3.4 Migration Guide

3.3 Migration Guide

3.3 Migration Guide

3.2 Migration Guide

3.2 Migration Guide

3.1 Migration Guide

3.1 Migration Guide

3.0 Migration Guide

3.0 Migration Guide

New ORM Upgrade Guide

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.5 Migration Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.4 Migration Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.3 Migration Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.2 Migration Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

3.1 Migration Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

New ORM Upgrade Guide

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

CakePHP Development Process

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Glossary

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

PHP Namespace Index

c

| c |
- | Cake |
|     Cake\Cache |
|     Cake\Collection |
|     Cake\Console |
|     Cake\Controller |
|     Cake\Controller\Component |
|     Cake\Core |
|     Cake\Database\Schema |
|     Cake\Filesystem |
|     Cake\Form |
|     Cake\I18n |
|     Cake\Mailer |
|     Cake\Network\Http |
|     Cake\ORM |
|     Cake\ORM\Behavior |
|     Cake\Routing |
|     Cake\Utility |
|     Cake\Validation |
|     Cake\View |
|     Cake\View\Helper |

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Not Found

The page you’re looking for cannot be found. Try using the search bar to find what you’re looking for.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Chronos

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Contents

Preface

CakePHP 概览

规约来替代设定

模型（Model）层

视图（View）层

控制器（Controller）层

CakePHP请求周期

让我们开始吧

附录

求助指南

CakePHP 约定

CakePHP 的文件夹结构

快速入门

內容管理系統教程

安装 CakePHP

检查安装

CMS 教程 － 创建数据库

数据库配置

创建第一个的模型

CMS 教案 - 创建 Articles 控制器

创建 Article 列表模版

创建 View 动作

创建视图模版

添加 Artciles

创建 add 模版

添加简单 slug 生成功能

添加 edit 动作

创建 edit 模版

更新验证规则

添加 delete 行为

3.x Migration Guide

3.5 Migration Guide

3.5 Migration Guide

3.4 Migration Guide

3.4 Migration Guide

3.3 Migration Guide

3.3 Migration Guide

3.2 Migration Guide

3.2 Migration Guide

3.1 Migration Guide

3.1 Migration Guide

3.0 Migration Guide

3.0 Migration Guide

New ORM Upgrade Guide

教程以及范例

內容管理系統教程

安装 CakePHP

检查安装

CMS 教程 － 创建数据库

数据库配置

创建第一个的模型

CMS 教案 - 创建 Articles 控制器

创建 Article 列表模版

创建 View 动作

创建视图模版

添加 Artciles

创建 add 模版

添加简单 slug 生成功能

添加 edit 动作

创建 edit 模版

更新验证规则

添加 delete 行为

CMS 教程 － Tags 和 Users

添加标签至 Articles

启用标记功能

使用标签搜寻 articles

改善标示功能

CMS 教案 - 认证

添加密码哈希

贡献

文档

翻译

文档格式指南

问题跟踪系统

报告臭虫

报告安全问题

代码

初始设置

制作补丁

提交拉取请求

编码规范

添加新特性

缩进

行的长度

控制结构

比较

函数调用

方法的定义

方法链接(Method Chaining)

代码的注释

包括文件

PHP 标签

命名规则

向后兼容性指南

升级指南

使用 CakePHP

开发 CakePHP

Getting Started

安装

Configuration

Routing

Connecting Routes

Creating RESTful Routes

Dispatcher Filters

Request & Response Objects

Middleware

控制器

关于控制器的更多内容

页面控制器

组件

视图

关于视图的更多内容

View Cells

主题

JSON 和 XML 视图

助件

Models

Database Basics

Query Builder

Table Objects

Entities

Retrieving Data & Results Sets

Validating Data

Saving Data

Deleting Data

Associations - Linking Tables Together

Behaviors

CounterCache

Timestamp

Translate

Tree

Schema System

ORM Cache Shell

Using CakePHP

Authentication

Bake Console

Code Generation with Bake

Extending Bake

Caching

Shells, Tasks & Console Tools

Shell Helpers

Interactive Console (REPL)

Running Shells as Cron Jobs

I18N Shell

Completion Shell

Plugin Shell

Routes Shell

Upgrade Shell

Server Shell

Cache Shell

Debugging

Deployment

Email

Error & Exception Handling

事件系统（Events System）

事件的使用例

访问事件管理器（Event Managers）

全局事件管理器

跟踪事件

核心事件

注册监听器

注册匿名监听器

和既存监听器互相作用

优先顺序设置

将事件数据作为函数参数取得

发送事件

停止事件

取得事件结果

删除回调函数和监听器

扩展阅读

Internationalization & Localization

Logging

Modelless Forms

Pagination

Plugins

REST

简单的设置

接收其他格式的数据

具有REST特性的路由

Security

Security

Cross Site Request Forgery

Security

Sessions

Testing

Validation

Utility Classes

App Class

集合

简单例子

方法（Methods）列表

迭代（Iterating）

过滤（Filtering）

集成（Aggregation）

分组和统计（Grouping and Counting）

排序（Sorting）

使用树结构（Tree Data）数据

其它方法

抽取元素

集合扩展

元素的更新

让集合的方法重复使用

集合优化

让集合能够迭代回

复制集合

Folder & File

Hash

Http Client

Inflector

Number

Registry Objects

Text

Time

Xml

创建XML对象

把Xml字符串转换成数组

把数组转换成Xml

使用命名空间

创建一个子节点

Plugins

Chronos

Debug Kit

Migrations

ElasticSearch

Upgrade Tool

Other

Constants & Functions

Appendices

3.x Migration Guide

3.x Migration Guide

General Information

CakePHP Development Process

Glossary

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

ElasticSearch

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

欢迎

CakePHP CookBook 是一个公开地开发和社区可以编辑的文档项目。我们希望把文档的质量、有效性和准确性都保持在一个较高的水平。请注意在右上角的“改善本文档”按钮; 它会引导您进入当前页面的 GitHub 在线编辑器，让您可以轻松地为文档贡献任何添加、删除或更正。

在任何地方阅读本书

您几乎可以在任何地方阅读本书，当前提供的格式有 PDF 和 EPUB，您可以在更多设备上阅读它，也可以(把它下载下来)离线阅读。

PDF

EPUB

原文出处 [http://github.com/cakephp/docs]

获取帮助

如果你遇到困难，有一些地方 你可以获取帮助。

第一步

学习一个新的框架即富有挑战又令人兴奋.为了能够长期的帮助你,我们创建了包含很多例子和配方的食谱(cookbook for cake),去完成一些普通的任务.如果你是一个新手，你可以从快速入门 开始,它会告诉你cakephp 会为你提供什么和它是怎么做到的.

当你完成了Bookmarker的训练之后,你可以重点去关注cakephp 应用的以下几个重要部分。

The CakePHP 请求处理周期

The CakePHP使用的一般约定 .

Controllers 处理请求、models协调、返回应用创建的响应输出.

Views 应用的展示层. 提供了进行HTML, JSON以及应用所需其它格式要求的强大而丰富的工具.

Models 所有应用的核心组件. 控制了应用中所需的校验、域处理逻辑.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Contents

CakePHP 概览

规约来替代设定

模型（Model）层

视图（View）层

控制器（Controller）层

CakePHP请求周期

让我们开始吧

附录

快速入门

內容管理系統教程

CMS 教程 － 创建数据库

CMS 教案 - 创建 Articles 控制器

3.0 Migration Guide

教程以及范例

內容管理系統教程

CMS 教程 － 创建数据库

CMS 教案 - 创建 Articles 控制器

CMS 教程 － Tags 和 Users

CMS 教案 - 认证

贡献

文档

问题跟踪系统

代码

编码规范

向后兼容性指南

安装

Configuration

Routing

Connecting Routes

Creating RESTful Routes

Request & Response Objects

控制器

关于控制器的更多内容

视图

关于视图的更多内容

Models

Database Basics

Query Builder

Table Objects

Entities

Retrieving Data & Results Sets

Validating Data

Saving Data

Deleting Data

Associations - Linking Tables Together

Behaviors

Schema System

ORM Cache Shell

Authentication

Bake Console

Code Generation with Bake

Extending Bake

Caching

Shells, Tasks & Console Tools

Shell Helpers

Interactive Console (REPL)

Running Shells as Cron Jobs

I18N Shell

Completion Shell

Plugin Shell

Routes Shell

Upgrade Shell

Server Shell

Cache Shell

Debugging

Deployment

Email

Error & Exception Handling

事件系统（Events System）

事件的使用例

访问事件管理器（Event Managers）

核心事件

注册监听器

发送事件

扩展阅读

Internationalization & Localization

Logging

Modelless Forms

Pagination

Plugins

REST

简单的设置

接收其他格式的数据

具有REST特性的路由

Security

Security

Cross Site Request Forgery

Security

Sessions

Testing

Validation

App Class

集合

简单例子

方法（Methods）列表

迭代（Iterating）

过滤（Filtering）

集成（Aggregation）

排序（Sorting）

使用树结构（Tree Data）数据

其它方法

Folder & File

Hash

Http Client

Inflector

Number

Registry Objects

Text

Time

Xml

创建XML对象

把Xml字符串转换成数组

把数组转换成Xml

使用命名空间

创建一个子节点

Constants & Functions

Debug Kit

Migrations

Appendices

3.x Migration Guide

General Information

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Using CakePHP

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

安装

Configuration

Routing

Request & Response Objects

控制器

组件

页面控制器

视图

View Cells

助件

JSON 和 XML 视图

Models

Table Objects

Query Builder

Entities

Error & Exception Handling

Caching

Logging

Modelless Forms

Sessions

REST

Authentication

Pagination

Cross Site Request Forgery

Email

Form

Html

Validation

Testing

Deployment

Shells, Tasks & Console Tools

贡献

教程以及范例

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Upgrade Tool

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can refer to the English version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。

Middleware

注解

The documentation is not currently supported in Chinese language for this page.

Please feel free to send us a pull request on Github [https://github.com/cakephp/docs] or use the Improve This Doc button to directly propose your changes.

You can referer to the english version in the select top menu to have information about this page’s topic.

© 版权所有 2021, Cake Software Foundation, Inc. 最后更新于 4月 09, 2021. 由 Sphinx 2.4.4 创建。