新闻部分

在上一节中,我们通过编写一个引用静态页面的类,介绍了框架的一些基本概念。我们通过添加自定义路由规则清理了 URI。现在是时候引入动态内容并开始使用数据库了。

创建一个数据库来使用

CodeIgniter 安装假设您已设置了适当的数据库,如要求中所述。在本教程中,我们提供了 MySQL 数据库的 SQL 代码,并且我们还假设您拥有一个合适的客户端来发出数据库命令(mysql、MySQL Workbench 或 phpMyAdmin)。

您需要创建一个名为ci4tutorial的数据库,该数据库可用于本教程,然后配置 CodeIgniter 以使用它。

使用您的数据库客户端,连接到您的数据库并运行以下 SQL 命令(MySQL)

CREATE TABLE news (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    title VARCHAR(128) NOT NULL,
    slug VARCHAR(128) NOT NULL,
    body TEXT NOT NULL,
    PRIMARY KEY (id),
    UNIQUE slug (slug)
);

此外,添加一些种子记录。目前,我们只向您展示创建表的 SQL 语句,但您应该知道,一旦您熟悉 CodeIgniter,就可以通过编程方式完成此操作;您可以阅读有关 迁移种子 的内容,以便稍后创建更有用的数据库设置。

需要注意的是:“slug” 在网络发布的语境中,是指 URL 中用于识别和描述资源的简短文本,对用户和 SEO 友好。

种子记录可能类似于

INSERT INTO news VALUES
(1,'Elvis sighted','elvis-sighted','Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app.'),
(2,'Say it isn\'t so!','say-it-isnt-so','Scientists conclude that some programmers have a sense of humor.'),
(3,'Caffeination, Yes!','caffeination-yes','World\'s largest coffee shop open onsite nested coffee shop for staff only.');

连接到您的数据库

您在安装 CodeIgniter 时创建的本地配置文件 .env 应该将数据库属性设置取消注释并适当地设置为要使用的数据库。确保您已按照 数据库配置 中的说明正确配置了数据库。

database.default.hostname = localhost
database.default.database = ci4tutorial
database.default.username = root
database.default.password = root
database.default.DBDriver = MySQLi

设置您的模型

不要在控制器中直接编写数据库操作,而应该将查询放在模型中,以便以后可以轻松地重复使用。模型是您检索、插入和更新数据库或其他数据存储中的信息的地方。它们提供对数据的访问。您可以在 使用 CodeIgniter 的模型 中了解更多信息。

创建 NewsModel

打开 app/Models 目录并创建一个名为 NewsModel.php 的新文件,并添加以下代码。

<?php

namespace App\Models;

use CodeIgniter\Model;

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

此代码与之前使用的控制器代码类似。它通过扩展 CodeIgniter\Model 并加载数据库库来创建一个新模型。这将使数据库类通过 $this->db 对象可用。

添加 NewsModel::getNews() 方法

现在数据库和模型已经设置好了,你需要一种方法来从数据库中获取所有帖子。为此,CodeIgniter 中包含的数据库抽象层 - 查询构建器 - 在 CodeIgniter\Model 中使用。这使得你能够编写一次“查询”,并使其在 所有支持的数据库系统 上运行。Model 类还允许你轻松地使用查询构建器,并提供一些额外的工具来简化数据操作。将以下代码添加到你的模型中。

    public function getNews($slug = false)
    {
        if ($slug === false) {
            return $this->findAll();
        }

        return $this->where(['slug' => $slug])->first();
    }

使用这段代码,你可以执行两种不同的查询。你可以获取所有新闻记录,或者通过其 slug 获取新闻条目。你可能已经注意到,$slug 变量在运行查询之前没有转义;查询构建器 会为你完成这项工作。

这里使用的两种方法,findAll()first(),由 CodeIgniter\Model 类提供。它们已经知道要使用的表,基于我们在 NewsModel 类中设置的 $table 属性。它们是辅助方法,使用查询构建器在当前表上运行它们的命令,并以你选择的格式返回结果数组。在这个例子中,findAll() 返回一个数组数组。

显示新闻

现在查询已经写好了,模型应该与将向用户显示新闻条目的视图绑定。这可以在我们之前创建的 Pages 控制器中完成,但为了清晰起见,定义了一个新的 News 控制器。

添加路由规则

修改你的 app/Config/Routes.php 文件,使其看起来如下

<?php

// ...

use App\Controllers\News; // Add this line
use App\Controllers\Pages;

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

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

这确保了请求到达 News 控制器,而不是直接到达 Pages 控制器。第二个 $routes->get() 行将带有 slug 的 URI 路由到 News 控制器中的 show() 方法。

创建 News 控制器

app/Controllers/News.php 中创建新的控制器。

<?php

namespace App\Controllers;

use App\Models\NewsModel;

class News extends BaseController
{
    public function index()
    {
        $model = model(NewsModel::class);

        $data['news'] = $model->getNews();
    }

    public function show($slug = null)
    {
        $model = model(NewsModel::class);

        $data['news'] = $model->getNews($slug);
    }
}

查看代码,你可能会发现它与我们之前创建的文件有一些相似之处。首先,它扩展了 BaseController,后者扩展了 CodeIgniter 的核心类 Controller,它提供了一些辅助方法,并确保你可以访问当前的 RequestResponse 对象,以及 Logger 类,用于将信息保存到磁盘。

接下来,有两个方法,一个用于查看所有新闻项目,另一个用于查看特定新闻项目。

接下来,model() 函数用于创建 NewsModel 实例。这是一个辅助函数。你可以在 全局函数和常量 中了解更多信息。你也可以编写 $model = new NewsModel();,如果你不使用它。

你可以看到,$slug 变量在第二个方法中传递给模型的方法。模型使用这个 slug 来识别要返回的新闻项目。

完成 News::index() 方法

现在数据通过我们的模型被控制器检索,但还没有显示任何内容。接下来要做的是,将这些数据传递给视图。修改 index() 方法使其看起来像这样

<?php

namespace App\Controllers;

use App\Models\NewsModel;

class News extends BaseController
{
    public function index()
    {
        $model = model(NewsModel::class);

        $data = [
            'news'  => $model->getNews(),
            'title' => 'News archive',
        ];

        return view('templates/header', $data)
            . view('news/index')
            . view('templates/footer');
    }

    // ...
}

上面的代码从模型中获取所有新闻记录并将其分配给一个变量。标题的值也被分配给 $data['title'] 元素,所有数据都被传递给视图。你现在需要创建一个视图来渲染新闻项目。

创建新闻/索引视图文件

创建 **app/Views/news/index.php** 并添加以下代码。

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

<?php if (! empty($news) && is_array($news)): ?>

    <?php foreach ($news as $news_item): ?>

        <h3><?= esc($news_item['title']) ?></h3>

        <div class="main">
            <?= esc($news_item['body']) ?>
        </div>
        <p><a href="/news/<?= esc($news_item['slug'], 'url') ?>">View article</a></p>

    <?php endforeach ?>

<?php else: ?>

    <h3>No News</h3>

    <p>Unable to find any news for you.</p>

<?php endif ?>

注意

我们再次使用 esc() 来帮助防止 XSS 攻击。但这次我们还传递了“url”作为第二个参数。这是因为攻击模式根据输出使用的上下文而有所不同。

在这里,每个新闻项目都被循环并显示给用户。您可以看到我们用 PHP 和 HTML 混合编写了模板。如果您更喜欢使用模板语言,您可以使用 CodeIgniter 的 视图解析器 或第三方解析器。

完成 News::show() 方法

新闻概述页面现在已经完成,但仍然缺少一个显示单个新闻项目的页面。之前创建的模型是以一种可以轻松用于此功能的方式创建的。您只需要在控制器中添加一些代码并创建一个新的视图。返回到 News 控制器并使用以下内容更新 show() 方法

<?php

namespace App\Controllers;

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

class News extends BaseController
{
    // ...

    public function show($slug = null)
    {
        $model = model(NewsModel::class);

        $data['news'] = $model->getNews($slug);

        if (empty($data['news'])) {
            throw new PageNotFoundException('Cannot find the news item: ' . $slug);
        }

        $data['title'] = $data['news']['title'];

        return view('templates/header', $data)
            . view('news/view')
            . view('templates/footer');
    }
}

不要忘记添加 use CodeIgniter\Exceptions\PageNotFoundException; 来导入 PageNotFoundException 类。

而不是在没有参数的情况下调用 getNews() 方法,传递了 $slug 变量,因此它将返回特定的新闻项目。

创建新闻/视图视图文件

唯一剩下的就是创建相应的视图,位于 **app/Views/news/view.php**。将以下代码放入此文件中。

<h2><?= esc($news['title']) ?></h2>
<p><?= esc($news['body']) ?></p>

将您的浏览器指向您的“新闻”页面,即 **localhost:8080/news**,您应该会看到新闻项目的列表,每个项目都有一个链接来显示单个文章。

../_images/tutorial2.png