快速开始指南

体验和学习CakePHP的最好方式就是坐下来并创建一些东西。首先,我们将构建一个简单的内容管理应用程序。

内容管理教程

本教程将指导您创建一个简单的 CMS 应用程序。首先,我们将安装CakePHP,创建数据库,并构建简单的文章管理功能。

以下是您需要准备的内容:

  1. 数据库服务器。在本教程中,我们将使用MySQL服务器。您需要了解足够的SQL知识以创建数据库,并从教程中运行SQL代码片段。CakePHP将处理应用程序所需的所有查询构建。由于我们使用的是MySQL,请确保已在PHP中启用了 pdo_mysql 扩展。

  2. 基本的PHP知识。

在开始之前,请确保您已经安装了最新版本的PHP:

php -v

您至少应该安装了PHP 8.1 (CLI) 或更高版本。您的Web服务器的PHP版本也必须是 8.1 或更高版本,并且应与命令行界面(CLI)的PHP版本相同。

获取CakePHP

安装CakePHP最简单的方法是使用Composer。Composer是一种从终端或命令行提示符中安装CakePHP的简单方法。首先,如果您尚未安装Composer,您需要下载并安装Composer。如果您已经安装了cURL,请运行以下命令:

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

或者,您可以从 Composer网站 下载 composer.phar

然后,在您的安装目录中,只需在终端中键入以下命令,将CakePHP应用程序骨架安装在当前工作目录的 cms 目录中:

php composer.phar create-project --prefer-dist cakephp/app:5.* cms

如果您已下载并运行了 Composer Windows Installer,则在您的安装目录中(例如 C:\wamp\www\dev)中,键入以下命令:

composer self-update && composer create-project --prefer-dist cakephp/app:5.* cms

使用Composer的优点是它会自动完成一些重要的设置任务,例如设置正确的文件权限并为您创建 config/app.php 文件。

还有其他安装CakePHP的方法。如果您无法或不想使用Composer,请查看 Installation 部分。

无论您如何下载和安装CakePHP,一旦设置完成,您的目录结构应该类似于以下内容:

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

现在是了解一下CakePHP目录结构的好时机:请查看 CakePHP文件夹结构 部分。

如果您在本教程中迷失方向,可以在GitHub上查看最终结果 `https://github.com/cakephp/cms-tutorial`_

检查我们的安装

我们可以通过检查默认的主页来快速检查我们的安装是否正确。在此之前,您需要启动开发服务器:

cd /path/to/our/app

bin/cake server

Note

对于Windows系统,命令应为 bin\cake server (注意反斜杠)。

这将在端口8765上启动PHP内置的Web服务器。在您的Web浏览器中打开 http://localhost:8765 ,您将看到欢迎页面。所有项目符号应该是绿色的厨师帽,除了CakePHP能否连接到您的数据库。如果不是这样,您可能需要安装其他PHP扩展或设置目录权限。

接下来,我们将构建我们的 数据库并创建我们的第一个模型

CMS教程 - 创建数据库

现在我们已经安装了CakePHP,让我们为我们的 CMS 应用程序设置数据库。如果您还没有这样做,请创建一个空数据库供本教程使用,可以自行选择名称,例如 cake_cms 。 如果您使用的是MySQL/MariaDB,您可以执行以下SQL语句来创建必要的表:

CREATE DATABASE cake_cms;

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());

如果您使用的是PostgreSQL,请连接到 cake_cms 数据库并执行以下SQL语句:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created TIMESTAMP,
    modified TIMESTAMP
);

CREATE TABLE articles (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(191) NOT NULL,
    body TEXT,
    published BOOLEAN DEFAULT FALSE,
    created TIMESTAMP,
    modified TIMESTAMP,
    UNIQUE (slug),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE TABLE tags (
    id SERIAL PRIMARY KEY,
    title VARCHAR(191),
    created TIMESTAMP,
    modified TIMESTAMP,
    UNIQUE (title)
);

CREATE TABLE articles_tags (
    article_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (article_id, tag_id),
    FOREIGN KEY (tag_id) REFERENCES tags(id),
    FOREIGN 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.', TRUE, NOW(), NOW());

您可能已经注意到 articles_tags 表使用了复合主键。CakePHP几乎在每个地方都支持复合主键,这使您可以拥有更简单的模式,而无需额外的 id 列。

我们使用的表和列名不是任意的。通过使用CakePHP的 命名约定,我们可以更有效地利用CakePHP,并避免需要配置框架。虽然CakePHP足够灵活,可以适应几乎任何数据库模式,但遵循约定将节省您的时间,因为您可以利用CakePHP提供的基于约定的默认设置。

数据库配置

接下来,让我们告诉CakePHP我们的数据库在哪里以及如何连接到它。在 config/app_local.php 文件中,将 Datasources.default 数组中的值替换为适用于您的设置的值。一个示例的完成配置数组可能如下所示:

<?php
return [
    // 更多配置...
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            // 如果您使用的是PostgreSQL,请将Mysql替换为Postgres
            'driver' => 'Cake\Database\Driver\Mysql',
            'persistent' => false,
            'host' => 'localhost',
            'username' => 'cakephp',
            'password' => 'AngelF00dC4k3~',
            'database' => 'cake_cms',
            // 如果您使用的是PostgreSQL,请注释掉下面的行
            'encoding' => 'utf8mb4',
            'timezone' => 'UTC',
            'cacheMetadata' => true,
        ],
    ],
    // 更多配置...
];

保存 config/app.php 文件后,您应该看到“CakePHP能够连接到数据库”部分显示为绿色的厨师帽。

Note

如果您的app文件夹中有 config/app_local.php 文件,则需要在该文件中配置数据库连接。

创建我们的第一个模型

模型是CakePHP应用程序的核心。它们使我们能够读取和修改数据,构建数据之间的关系,验证数据并应用应用程序规则。模型提供了创建控制器操作和模板所需的基础。

CakePHP的模型由 TableEntity 对象组成。 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): void
    {
        $this->addBehavior('Timestamp');
    }
}

我们附加了 Timestamp 行为,它将自动填充我们表的 createdmodified 列。通过将我们的Table对象命名为 ArticlesTable ,CakePHP可以使用命名约定,知道我们的模型使用 articles 表。CakePHP还使用约定知道 id 列是我们表的主键。

Note

如果CakePHP在 src/Model/Table 中找不到相应的文件,它将动态创建一个模型对象。这也意味着如果您错误地命名了文件(例如articlestable.php或ArticleTable.php),CakePHP将无法识别您的任何设置,并使用生成的模型。

我们还将为我们的Articles创建一个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 array $_accessible = [
        '*' => true,
        'id' => false,
        'slug' => false,
    ];
}

目前,我们的实体非常简单;我们只设置了 _accessible 属性,它控制了如何通过 Mass Assignment 修改属性。

我们目前无法对模型进行太多操作。接下来,我们将创建我们的第一个 Controller和Template,以便与我们的模型进行交互。

CMS教程 - 创建文章控制器

创建了我们的模型之后,我们需要一个用于文章的控制器。在CakePHP中,控制器处理HTTP请求并执行模型方法中包含的业务逻辑,以准备响应。我们将把这个新的控制器放在一个名为 ArticlesController.php 的文件中,放在 src/Controller 目录下。下面是基本的控制器的样子:

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

namespace App\Controller;

class ArticlesController extends AppController
{
}

现在,让我们为我们的控制器添加一个动作。动作是与控制器方法相关联的路由。例如,当用户请求 www.example.com/articles/index (也可以是 www.example.com/articles ),CakePHP将调用您的 ArticlesControllerindex 方法。该方法应该查询模型层,并通过在视图中渲染模板来准备响应。该动作的代码如下所示:

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

namespace App\Controller;

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

通过在我们的 ArticlesController 中定义 index() 函数,用户现在可以通过请求 www.example.com/articles/index 来访问其中的逻辑。类似地,如果我们定义了一个名为 foobar() 的函数,用户将能够通过 www.example.com/articles/foobar 来访问它。您可能会想以一种允许您获得特定URL的方式来命名您的控制器和动作。不要这样做。相反,遵循 CakePHP约定 中创建可读性强、有意义的动作名称。然后,您可以使用 Routing 来将您想要的URL与您创建的动作连接起来。

我们的控制器动作非常简单。它从数据库中获取一个分页的文章集合,使用通过命名约定自动加载的Articles模型。然后,它使用 set() 将文章传递给模板(我们很快会创建)。CakePHP在控制器动作完成后会自动渲染模板。

创建文章列表模板

既然我们的控制器从模型中获取数据并准备好视图上下文,让我们为索引动作创建一个视图模板。

CakePHP的视图模板是插入到应用程序布局中的呈现风格的PHP代码。虽然我们将在这里创建HTML,但视图也可以生成JSON、CSV甚至像PDF这样的二进制文件。

布局是包围视图的呈现代码。布局文件包含常见的站点元素,如标题、页脚和导航元素。您的应用程序可以有多个布局,并且可以在它们之间切换,但现在,让我们只使用默认布局。

CakePHP的模板文件存储在名为与其对应的控制器同名的文件夹中的 templates 文件夹中。因此,在这种情况下,我们需要创建一个名为’Articles’的文件夹。将以下代码添加到您的应用程序中:

<!-- 文件:templates/Articles/index.php -->

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

    <!-- 这里是我们通过$articles查询对象进行迭代的地方,打印出文章信息 -->

    <?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提供了一组视图助手,用于执行诸如创建链接、表单和分页按钮等任务。您可以在它们的章节中了解更多关于 Helpers 的信息,但这里需要注意的重要一点是, link() 方法将生成一个带有给定链接文本(第一个参数)和URL(第二个参数)的HTML链接。

在CakePHP中指定URL时,建议使用数组或 命名路由。这些语法允许您利用CakePHP提供的反向路由功能。

此时,您应该能够将浏览器指向 http://localhost:8765/articles/index 。您应该能够看到正确格式化的文章标题和表格列表的列表视图。

创建查看动作

如果您在文章列表页面中点击“查看”链接之一,您将看到一个错误页面,上面显示着还没有实现该动作的信息。让我们来修复一下:

// 添加到现有的 src/Controller/ArticlesController.php 文件

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

虽然这是一个简单的动作,但我们使用了一些强大的CakePHP功能。我们首先使用 findBySlug() ,它是一个 动态查找器。该方法允许我们创建一个基本查询,通过给定的slug找到文章。然后,我们使用 firstOrFail() 来获取第一条记录,或抛出一个 NotFoundException

我们的动作接受一个 $slug 参数,但是这个参数从哪里来呢?如果用户请求 /articles/view/first-post ,那么值“first-post”将作为 $slug 通过CakePHP的路由和调度层传递。如果我们使用保存的新动作重新加载浏览器,我们将看到另一个CakePHP错误页面,告诉我们缺少一个视图模板;让我们来修复一下。

创建查看模板

让我们为我们的新的“查看”动作创建一个视图模板,并将其放在 templates/Articles/view.php 中:

<!-- 文件:templates/Articles/view.php -->

<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 上点击链接或手动访问URL(如 /articles/view/first-post )来验证它是否正常工作。

添加文章

在创建了基本的读取视图之后,我们需要使新文章的创建成为可能。首先在 ArticlesController 中创建一个 add() 动作。我们的控制器现在应该如下所示:

<?php
// src/Controller/ArticlesController.php
namespace App\Controller;

use App\Controller\AppController;

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

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

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

            // 暂时硬编码user_id,并在构建身份验证时将其删除
            $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);
    }
}

下面是 add() 动作的功能:

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

  • 如果由于某种原因保存失败,只需渲染视图。这样我们就有机会向用户显示验证错误或其他警告。

每个CakePHP请求都包含一个请求对象,可以使用 $this->request 来访问它。请求对象包含有关刚刚接收到的请求的信息。我们使用 Cake\Http\ServerRequest::is() 方法来检查请求是否为HTTP POST请求。

我们的POST数据可以在 $this->request->getData() 中获得。如果您想查看它的样子,可以使用 pr()debug() 函数将其打印出来。为了保存我们的数据,我们首先将POST数据“marshal”到一个Article实体中。然后,使用我们之前创建的ArticlesTable持久化实体。

保存新文章后,我们使用FlashComponent的 success() 方法将消息设置到会话中。 success 方法是使用PHP的`魔术方法特性 <https://php.net/manual/en/language.oop5.overloading.php#object.call>`_ 提供的。Flash消息将在重定向后显示在下一页上。在我们的布局中,我们有 <?= $this->Flash->render() ?> ,它显示闪存消息并清除相应的会话变量。最后,在保存完成后,我们使用 Cake\Controller\Controller::redirect 将用户重定向到文章列表。参数 ['action' => 'index'] 转换为URL /articles ,即 ArticlesController 的index动作。您可以参考API中的 Cake\Routing\Router::url() 函数,以查看您可以为各种CakePHP函数指定URL的格式。

创建添加模板

下面是我们的添加视图模板:

<!-- 文件:templates/Articles/add.php -->

<h1>Add Article</h1>
<?php
    echo $this->Form->create($article);
    // 现在先硬编码用户。
    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表单的起始标签。下面是 $this->Form->create() 生成的HTML:

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

因为我们调用 create() 而没有指定URL选项,所以 FormHelper 假设我们希望表单提交回当前动作。

$this->Form->control() 方法用于创建具有相同名称的表单元素。第一个参数告诉CakePHP它们对应的字段,第二个参数允许您指定各种选项 - 在这种情况下,文本区域的行数。这里使用了一些内省和约定。 control() 将根据指定的模型字段输出不同的表单元素,并使用词形变化生成标签文本。您可以使用选项自定义标签、输入或表单控件的任何其他方面。 $this->Form->end() 调用关闭了表单。

现在让我们返回并更新我们的 templates/Articles/index.php 视图,以包含一个新的“添加文章”链接。在 <table> 之前添加以下行:

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

添加简单的Slug生成

如果我们现在保存一篇文章,保存将失败,因为我们没有创建一个slug属性,而且该列是 NOT NULL 。Slug值通常是文章标题的URL安全版本。我们可以使用ORM的 :ref:`beforeSave()回调 <table-callbacks>`来填充我们的slug:

<?php
// 在 src/Model/Table/ArticlesTable.php 中

namespace App\Model\Table;

use Cake\ORM\Table;
// 引入Text类
use Cake\Utility\Text;
// 引入EventInterface类
use Cake\Event\EventInterface;

// 添加以下方法。

public function beforeSave(EventInterface $event, $entity, $options)
{
    if ($entity->isNew() && !$entity->slug) {
        $sluggedTitle = Text::slug($entity->title);
        // 将slug修剪为模式中定义的最大长度
        $entity->slug = substr($sluggedTitle, 0, 191);
    }
}

这段代码很简单,没有考虑到重复的slug。但我们稍后会解决这个问题。

添加编辑动作

我们的应用程序现在可以保存文章,但我们不能编辑它们。让我们现在纠正一下。在您的 ArticlesController 中添加以下动作:

// 在 src/Controller/ArticlesController.php 中

// 添加以下方法。

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);
}

此动作首先确保用户已尝试访问现有记录。如果他们没有传递 $slug 参数,或者文章不存在,将抛出一个 NotFoundException ,并且CakePHP的错误处理程序将呈现适当的错误页面。

接下来,动作检查请求是否为POST或PUT请求。如果是,则使用POST/PUT数据更新我们的文章实体,使用 patchEntity() 方法。最后,我们调用 save() ,设置适当的闪存消息,并重定向或显示验证错误。

创建编辑模板

编辑模板应该如下所示:

<!-- 文件:templates/Articles/edit.php -->

<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();
?>

此模板输出编辑表单(填充了值),以及任何必要的验证错误消息。

现在,您可以更新您的索引视图,添加链接以允许用户编辑特定的文章:

<!-- 文件:templates/Articles/index.php  (添加编辑链接) -->

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

<!-- 这里是我们通过$articles查询对象进行迭代的地方,打印出文章信息 -->

<?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

// 在命名空间声明下面添加此use语句,以导入Validator类
use Cake\Validation\Validator;

// 添加以下方法。
public function validationDefault(Validator $validator): Validator
{
    $validator
        ->notEmptyString('title')
        ->minLength('title', 10)
        ->maxLength('title', 255)

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

    return $validator;
}

validationDefault() 方法告诉CakePHP在调用 save() 方法时如何验证您的数据。在这里,我们指定标题和正文字段都不能为空,并具有一定的长度约束。

CakePHP的验证引擎功能强大且灵活。它提供了一套常用规则,用于处理电子邮件地址、IP地址等任务,并提供了添加自定义验证规则的灵活性。有关更多信息,请查看 Validation 文档。

现在,您的验证规则已经就位,请尝试向验证错误消息自动显示的表单中添加一个空标题或正文的文章,以查看它的工作原理。

添加删除动作

接下来,让我们为用户提供删除文章的方式。首先,在 ArticlesController 中添加一个 delete() 动作:

// 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 指定的文章,并使用 $this->Flash->success() 在将用户重定向到 /articles 后显示确认消息。如果用户尝试使用GET请求删除文章, allowMethod() 将抛出异常。未捕获的异常将被CakePHP的异常处理程序捕获,并显示一个漂亮的错误页面。有许多内置的 Exceptions 可用于指示您的应用程序可能需要生成的各种HTTP错误。

由于我们只执行逻辑并重定向到另一个动作,因此此动作没有模板。您可能希望使用链接更新您的索引模板,以允许用户删除文章:

<!-- 文件:templates/Articles/index.php  (添加删除链接) -->

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

<!-- 这里是我们通过$articles查询对象进行迭代的地方,打印出文章信息 -->

<?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>

使用 postLink() 将创建一个链接,使用JavaScript执行POST请求来删除我们的文章。

通过基本的文章管理设置,我们将创建 标签和用户表的基本动作