创建新闻项目

您现在知道如何使用 CodeIgniter 从数据库读取数据,但您还没有向数据库写入任何信息。在本节中,您将扩展之前创建的新闻控制器和模型以包含此功能。

启用 CSRF 过滤器

在创建表单之前,让我们启用 CSRF 保护。

打开 **app/Config/Filters.php** 文件并更新 $methods 属性,如下所示

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public $methods = [
        'post' => ['csrf'],
    ];

    // ...
}

它配置 CSRF 过滤器以对所有 **POST** 请求启用。您可以在 安全 库中阅读有关 CSRF 保护的更多信息。

警告

通常,如果您使用 $methods 过滤器,您应该 禁用自动路由(旧版),因为 自动路由(旧版) 允许任何 HTTP 方法访问控制器。使用您不期望的方法访问控制器可能会绕过过滤器。

添加路由规则

在您开始将新闻项目添加到 CodeIgniter 应用程序之前,您需要在 **app/Config/Routes.php** 文件中添加一条额外的规则。确保您的文件包含以下内容

<?php

// ...

use App\Controllers\News;
use App\Controllers\Pages;

$routes->get('news', [News::class, 'index']);
$routes->get('news/new', [News::class, 'new']); // Add this line
$routes->post('news', [News::class, 'create']); // Add this line
$routes->get('news/(:segment)', [News::class, 'show']);

$routes->get('pages', [Pages::class, 'index']);
$routes->get('(:segment)', [Pages::class, 'view']);

用于 'news/new' 的路由指令位于用于 'news/(:segment)' 的指令之前,以确保显示创建新闻项目的表单。

$routes->post() 行定义了 POST 请求的路由器。它只匹配到 URI 路径 **/news** 的 POST 请求,并映射到 News 类的 create() 方法。

您可以在 设置路由规则 中了解更多关于不同路由类型的知识。

创建表单

创建 news/create 视图文件

要将数据输入数据库,您需要创建一个表单,您可以在其中输入要存储的信息。这意味着您将需要一个包含两个字段的表单,一个用于标题,一个用于文本。您将在模型中从我们的标题中推导出 slug。

在 **app/Views/news/create.php** 中创建一个新的视图

<h2><?= esc($title) ?></h2>

<?= session()->getFlashdata('error') ?>
<?= validation_list_errors() ?>

<form action="/news" method="post">
    <?= csrf_field() ?>

    <label for="title">Title</label>
    <input type="input" name="title" value="<?= set_value('title') ?>">
    <br>

    <label for="body">Text</label>
    <textarea name="body" cols="45" rows="4"><?= set_value('body') ?></textarea>
    <br>

    <input type="submit" name="submit" value="Create news item">
</form>

这里可能只有四件事看起来不熟悉。

session() 函数用于获取 Session 对象,而 session()->getFlashdata('error') 用于向用户显示与 CSRF 保护相关的错误。但是,默认情况下,如果 CSRF 验证检查失败,将抛出异常,因此它尚不可用。有关更多信息,请参见 失败时的重定向

表单助手 提供的 validation_list_errors() 函数用于报告与表单验证相关的错误。

csrf_field() 函数创建一个包含 CSRF 令牌的隐藏输入,有助于防止一些常见的攻击。

表单助手 提供的 set_value() 函数用于在发生错误时显示旧的输入数据。

新闻控制器

返回您的 News 控制器。

添加 News::new() 以显示表单

首先,创建一个方法来显示您创建的 HTML 表单。

<?php

namespace App\Controllers;

use App\Models\NewsModel;
use CodeIgniter\Exceptions\PageNotFoundException;

class News extends BaseController
{
    // ...

    public function new()
    {
        helper('form');

        return view('templates/header', ['title' => 'Create a news item'])
            . view('news/create')
            . view('templates/footer');
    }
}

我们使用 helper() 函数加载 表单助手。大多数助手函数需要在使用前加载助手。

然后它返回创建的表单视图。

添加 News::create() 以创建新闻项目

接下来,创建一个方法来从提交的数据中创建新闻项目。

您将在这里做三件事

  1. 检查提交的数据是否通过了验证规则。

  2. 将新闻项目保存到数据库。

  3. 返回成功页面。

<?php

namespace App\Controllers;

use App\Models\NewsModel;
use CodeIgniter\Exceptions\PageNotFoundException;

class News extends BaseController
{
    // ...

    public function create()
    {
        helper('form');

        $data = $this->request->getPost(['title', 'body']);

        // Checks whether the submitted data passed the validation rules.
        if (! $this->validateData($data, [
            'title' => 'required|max_length[255]|min_length[3]',
            'body'  => 'required|max_length[5000]|min_length[10]',
        ])) {
            // The validation fails, so returns the form.
            return $this->new();
        }

        // Gets the validated data.
        $post = $this->validator->getValidated();

        $model = model(NewsModel::class);

        $model->save([
            'title' => $post['title'],
            'slug'  => url_title($post['title'], '-', true),
            'body'  => $post['body'],
        ]);

        return view('templates/header', ['title' => 'Create a news item'])
            . view('news/success')
            . view('templates/footer');
    }
}

上面的代码添加了许多功能。

检索数据

首先,我们使用 IncomingRequest 对象 $this->request,它由框架在控制器中设置。

我们从用户提交的 POST 数据中获取必要的项目,并将它们设置在 $data 变量中。

验证数据

接下来,您将使用控制器提供的助手函数 validateData() 来验证提交的数据。在这种情况下,标题和正文字段是必需的,并且在特定长度内。

CodeIgniter 拥有一个强大的验证库,如上所示。您可以阅读有关 验证库 的更多信息。

如果验证失败,我们将调用您刚刚创建的 new() 方法并返回 HTML 表单。

保存新闻项目

如果验证通过了所有规则,我们将通过 $this->validator->getValidated() 获取验证后的数据,并将它们设置在 $post 变量中。

加载并调用 NewsModel。这负责将新闻项目传递到模型中。 save() 方法根据它是否找到与主键匹配的数组键,自动处理插入或更新记录。

这包含一个新函数 url_title()。此函数由 URL 助手 提供,它会剥离您传递给它的字符串,将所有空格替换为连字符 (-),并确保所有内容都为小写字符。这会为您提供一个不错的 slug,非常适合创建 URI。

返回成功页面

在此之后,加载视图文件并返回以显示成功消息。在 app/Views/news/success.php 中创建一个视图,并编写一条成功消息。

这可能很简单,例如

<p>News item created successfully.</p>

NewsModel 更新

唯一剩下的就是确保您的模型已设置好,以便能够正确保存数据。所使用的 save() 方法将根据主键的存在来确定是插入信息还是更新已存在的行。在本例中,没有传递 id 字段,因此它将在其表 news 中插入新行。

但是,默认情况下,模型中的插入和更新方法实际上不会保存任何数据,因为它不知道哪些字段可以安全更新。编辑 NewsModel 以在 $allowedFields 属性中提供可更新字段的列表。

<?php

namespace App\Models;

use CodeIgniter\Model;

class NewsModel extends Model
{
    protected $table = 'news';

    protected $allowedFields = ['title', 'slug', 'body'];
}

此新属性现在包含我们允许保存到数据库的字段。请注意,我们省略了 id?这是因为您几乎不需要这样做,因为它是在数据库中自动递增的字段。这有助于防止大规模赋值漏洞。如果您的模型正在处理您的时间戳,您也应该将它们省略。

创建新闻项目

现在将您的浏览器指向您安装 CodeIgniter 的本地开发环境,并在 URL 中添加 ** /news/new **。添加一些新闻并查看您创建的不同页面。

../_images/tutorial3.png ../_images/tutorial4.png

恭喜

您刚刚完成了您的第一个 CodeIgniter4 应用程序!

下面的图表显示了您的项目的 **app** 文件夹,其中包含您创建或修改的所有文件。

app/
├── Config
│   ├── Filters.php (Modified)
│   └── Routes.php  (Modified)
├── Controllers
│   ├── News.php
│   └── Pages.php
├── Models
│   └── NewsModel.php
└── Views
    ├── news
    │   ├── create.php
    │   ├── index.php
    │   ├── success.php
    │   └── view.php
    ├── pages
    │   ├── about.php
    │   └── home.php
    └── templates
        ├── footer.php
        └── header.php