新聞?wù)故竟δ?a class="headerlink" href="#id1" title="永久鏈接至標(biāo)題">?
在上一個(gè)章節(jié)里,我們寫(xiě)了一個(gè)用于展示靜態(tài)頁(yè)面的類(lèi)文件,通過(guò)這個(gè)簡(jiǎn)單的例子我們把CI4框架里的一些基本的概念講解了一下。 我們還簡(jiǎn)單的使用了CI4里面的路由功能,通過(guò)自定義路由規(guī)則實(shí)現(xiàn)了頁(yè)面的鏈接地址凈化,使頁(yè)面的訪問(wèn)地址看起來(lái)更整潔和搜索引擎友好。 現(xiàn)在,我們要開(kāi)始進(jìn)行一些基于數(shù)據(jù)庫(kù)的動(dòng)態(tài)內(nèi)容的開(kāi)發(fā)了。
建立教程所需的數(shù)據(jù)庫(kù)?
我們假設(shè)你已經(jīng)安裝和 配置 好了用于 CodeIgniter4 運(yùn)行所需的數(shù)據(jù)庫(kù)軟件。 我們也假設(shè)你會(huì)使用數(shù)據(jù)庫(kù)管理的客戶(hù)端工具(mysql,MySQL Workbench或者phpMyAdmin等)來(lái)運(yùn)行稍后教程里提供的創(chuàng)建數(shù)據(jù)庫(kù)表和插入測(cè)試數(shù)據(jù)所需的SQL代碼。
下面我們就來(lái)教你如何為本教程創(chuàng)建一個(gè)數(shù)據(jù)庫(kù),并且正確配置CodeIgniter來(lái)使用這個(gè)數(shù)據(jù)庫(kù)。
用你安裝好的數(shù)據(jù)庫(kù)客戶(hù)端工具打開(kāi)數(shù)據(jù)庫(kù),然后運(yùn)行下面的兩段SQL代碼(MySQL適用)來(lái)創(chuàng)建一個(gè)數(shù)據(jù)表和插入一些測(cè)試數(shù)據(jù)。 隨著你對(duì) CodeIgniter 的熟悉程度越來(lái)越高,這些數(shù)據(jù)庫(kù)相關(guān)的操作也可以通過(guò)程序代碼在CodeIgniter框架下完成,你可以閱讀 數(shù)據(jù)遷移 和 數(shù)據(jù)填充 這兩個(gè)章節(jié)來(lái)了解相關(guān)內(nèi)容,以便掌握用程序代碼操作數(shù)據(jù)庫(kù)的相關(guān)技能。
CREATE TABLE news (
id int(11) NOT NULL AUTO_INCREMENT,
title varchar(128) NOT NULL,
slug varchar(128) NOT NULL,
body text NOT NULL,
PRIMARY KEY (id),
KEY slug (slug)
);
Note: 數(shù)據(jù)表里的 slug 字段在基于互聯(lián)網(wǎng)訪問(wèn)的網(wǎng)站上是個(gè)非常有用的字段。 一般在這個(gè)字段里存放簡(jiǎn)短的詞語(yǔ)來(lái)概括性描述數(shù)據(jù)內(nèi)容,這將提升用戶(hù)打開(kāi)網(wǎng)址時(shí)候的訪問(wèn)體驗(yàn),并且這種網(wǎng)址也是搜索引擎友好的網(wǎng)址,有利于網(wǎng)站內(nèi)容的SEO優(yōu)化。
然后我們?cè)跀?shù)據(jù)表里插入如下測(cè)試數(shù)據(jù):
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.');
連接到你的數(shù)據(jù)庫(kù)?
CodeIgniter 安裝時(shí)會(huì)自動(dòng)生成一個(gè) .env
文件,確保里面的配置信息沒(méi)有被注釋掉,并且和你本地的數(shù)據(jù)庫(kù)實(shí)際情況相吻合:
database.default.hostname = localhost
database.default.database = ci4tutorial
database.default.username = root
database.default.password = root
database.default.DBDriver = MySQLi
創(chuàng)建你的數(shù)據(jù)模型文件?
我們要求你將數(shù)據(jù)庫(kù)的操作代碼寫(xiě)在模型(Model)文件里面,以便以后代碼重用,不要將這些代碼寫(xiě)在控制器(Controller)里。 你的模型文件們應(yīng)該成為你處理數(shù)據(jù)庫(kù)相關(guān)的增、刪、改、查操作的默認(rèn)地方。交由模型文件來(lái)操作數(shù)據(jù)庫(kù)或者其他格數(shù)的數(shù)據(jù)文件。
打開(kāi) app/Models/ 目錄,在這個(gè)目錄下面創(chuàng)建一個(gè)名字為 NewsModel.php 的文件,并在文件里加入如下代碼。 為了保證代碼運(yùn)行順利,你需要確認(rèn)一下已經(jīng)正確的完成了數(shù)據(jù)庫(kù)的相關(guān)配置:doc:這里 <../database/configuration>。
<?php
namespace App\Models;
class NewsModel extends \CodeIgniter\Model
{
protected $table = 'news';
}
這段代碼和我們上一個(gè)章節(jié)里創(chuàng)建的控制器里的代碼類(lèi)似。
我們通過(guò)繼承 CodeIgniter\Model
創(chuàng)建了一個(gè)新的模型文件,并加載了CI4內(nèi)置的數(shù)據(jù)庫(kù)操作類(lèi)庫(kù)。
后面我們可以在代碼里通過(guò) $this->db
來(lái)調(diào)用數(shù)據(jù)庫(kù)的相關(guān)操作類(lèi)庫(kù)。
現(xiàn)在我們的數(shù)據(jù)庫(kù)和數(shù)據(jù)模型文件已經(jīng)建立好了。 我們首先寫(xiě)一個(gè)方法從數(shù)據(jù)庫(kù)中獲取所有的新聞文章。 為實(shí)現(xiàn)這點(diǎn),我們將使用 CodeIgniter 的數(shù)據(jù)庫(kù)抽象層工具 查詢(xún)構(gòu)建器,通過(guò)它你可以編寫(xiě)你的查詢(xún)代碼,并在 所有支持的數(shù)據(jù)庫(kù)平臺(tái) 上運(yùn)行。 數(shù)據(jù)模型文件可以方便的和 查詢(xún)構(gòu)建器 一起工作,并且提供了一些方法讓你操作數(shù)據(jù)的時(shí)候更加簡(jiǎn)單?,F(xiàn)在向你的模型中添加如下代碼。
public function getNews($slug = false)
{
if ($slug === false)
{
return $this->findAll();
}
return $this->asArray()
->where(['slug' => $slug])
->first();
}
通過(guò)這段代碼,你可以執(zhí)行兩種不同的查詢(xún),一種是獲取所有的新聞條目,另一種是根據(jù)特定的 slug 來(lái)獲取指定的新聞條目。 你可能注意到了,我們直接的進(jìn)行了基于``$slug`` 變量的數(shù)據(jù)對(duì)比命令,并不需要預(yù)先執(zhí)行相應(yīng)字段的查詢(xún)操作,因?yàn)?doc:查詢(xún)構(gòu)建器 <../database/query_builder> 自動(dòng)幫我們完成了這個(gè)工作。
我們?cè)谶@里用到的 findAll()
和 first()
都是 CodeIgniter4 的數(shù)據(jù)模型(Model)基礎(chǔ)類(lèi)里面內(nèi)置的方法。
他們根據(jù)我們?cè)跀?shù)據(jù)模型文件里(本例中是 NewsModel 文件)聲明的 $table
變量而知道該對(duì)哪個(gè)數(shù)據(jù)表進(jìn)行操作。
這些方法通過(guò) 查詢(xún)構(gòu)建器 運(yùn)行指令操作當(dāng)前數(shù)據(jù)表,并且會(huì)以數(shù)組的形式返回?cái)?shù)據(jù)查詢(xún)結(jié)果。在這個(gè)例子里面,findAll()
的返回值是包含了指定數(shù)據(jù)表中的所有數(shù)據(jù)對(duì)象的一個(gè)數(shù)組。
顯示新聞?
現(xiàn)在,查詢(xún)已經(jīng)在數(shù)據(jù)模型文件里寫(xiě)好了,接下來(lái)我們需要將數(shù)據(jù)模型綁定到視圖上,向用戶(hù)顯示新聞條目了。
這可以在之前寫(xiě)的 Pages
控制器里來(lái)做,但為了更清楚的闡述,我們定義了一個(gè)新的 News
控制器,創(chuàng)建在 app/controllers/News.php 文件中。
<?php namespace App\Controllers;
use App\Models\NewsModel;
class News extends \CodeIgniter\Controller
{
public function index()
{
$model = new NewsModel();
$data['news'] = $model->getNews();
}
public function view($slug = null)
{
$model = new NewsModel();
$data['news'] = $model->getNews($slug);
}
}
閱讀上面的代碼你會(huì)發(fā)現(xiàn),這和之前寫(xiě)的代碼有些相似之處。
首先,它繼承了*CodeIgniter*的一個(gè)核心類(lèi),Controller
,這個(gè)核心類(lèi)提供了很多非常有用的方法,它確保你可以操作當(dāng)前的 Request
和 Response
對(duì)象,也可以操作``Logger`` 類(lèi), 方便你把日志文件寫(xiě)到磁盤(pán)里。
其次,有兩個(gè)方法用來(lái)顯示新聞條目,一個(gè)顯示所有的,另一個(gè)顯示特定的。
你可以看到第二個(gè)方法中調(diào)用模型方法時(shí)傳入了 $slug
參數(shù),模型根據(jù)這個(gè) slug 返回特定的新聞條目。
現(xiàn)在,通過(guò)模型,控制器已經(jīng)獲取到數(shù)據(jù)了,但還沒(méi)有顯示出來(lái)。
下一步要做的就是將數(shù)據(jù)傳遞給視圖。
我們修改 index()
方法成下面的樣子::
public function index()
{
$model = new NewsModel();
$data = [
'news' => $model->getNews(),
'title' => 'News archive',
];
echo view('templates/header', $data);
echo view('news/index', $data);
echo view('templates/footer');
}
上面的代碼從模型中獲取所有的新聞條目,并賦值給一個(gè)變量(news)。
另外頁(yè)面的標(biāo)題賦值給了 $data['title']
元素,然后所有的數(shù)據(jù)被傳遞給視圖。
現(xiàn)在你需要?jiǎng)?chuàng)建一個(gè)視圖文件來(lái)顯示新聞條目了,新建 app/Views/news/index.php 文件并添加如下代碼。
<h2><?= $title ?></h2>
<?php if (! empty($news) && is_array($news)) : ?>
<?php foreach ($news as $news_item): ?>
<h3><?= $news_item['title'] ?></h3>
<div class="main">
<?= $news_item['text'] ?>
</div>
<p><a href="<?= '/news/'.$news_item['slug'] ?>">View article</a></p>
<?php endforeach; ?>
<?php else : ?>
<h3>No News</h3>
<p>Unable to find any news for you.</p>
<?php endif ?>
這里,我們通過(guò)一個(gè)循環(huán)將所有的新聞條目顯示給用戶(hù),你可以看到我們直接采用了 HTML 和 PHP 混用的寫(xiě)法創(chuàng)建了一個(gè)視圖頁(yè)面。 如果你希望使用一種模板語(yǔ)言,你可以使用 CodeIgniter 的 視圖模版解析類(lèi) <../outgoing/view_parser> ,或其他的第三方解析器。
新聞的列表頁(yè)就做好了,但是我們還缺少一個(gè)顯示特定新聞條目的頁(yè)面。
我們可以調(diào)用之前創(chuàng)建的模型里的數(shù)據(jù)來(lái)實(shí)現(xiàn)這個(gè)功能,你只需要向控制器中添加一些代碼,然后再新建一個(gè)視圖就可以了。
回到 News
控制器,使用下面的代碼替換掉 view()
方法:
public function view($slug = NULL)
{
$model = new NewsModel();
$data['news'] = $model->getNews($slug);
if (empty($data['news']))
{
throw new \CodeIgniter\PageNotFoundException('Cannot find the page: '. $slug);
}
$data['title'] = $data['news']['title'];
echo view('templates/header', $data);
echo view('news/view', $data);
echo view('templates/footer');
}
我們并沒(méi)有直接調(diào)用 getNews()
方法,而是傳入了一個(gè) $slug
參數(shù),所以它會(huì)返回相應(yīng)的新聞條目。
最后剩下的事是創(chuàng)建視圖文件 app/Views/news/view.php
并添加如下代碼 。
<?php echo ‘<h2>’.$news[‘title’].’</h2>’; echo $news[‘body’];
路由?
由于之前我們創(chuàng)建了基于通配符的路由規(guī)則,所以現(xiàn)在需要新增一條路由以便能訪問(wèn)到你剛剛創(chuàng)建的控制器。
修改路由配置文件(app/config/routes.php)添加類(lèi)似下面的代碼。
該規(guī)則可以讓地址中帶*news*的請(qǐng)求訪問(wèn) News
控制器而不是去訪問(wèn)之前默認(rèn)的 Pages
控制器。
第一行代碼可以讓訪問(wèn) news/slug 地址的 URI 重定向到 News 控制器的 view() 方法。
$routes->get('news/(:segment)', 'News::view/$1');
$routes->get('news', 'News::index');
$routes->get('(:any)', 'Pages::view/$1');
在地址欄里輸入 localhost:8080/news 來(lái)訪問(wèn)你創(chuàng)建好的新聞列表頁(yè)面吧。 你將會(huì)看到如下圖一樣的一個(gè)展示新聞列表的網(wǎng)頁(yè),列表里的每個(gè)文章都帶一個(gè)可以打開(kāi)該條新聞詳情頁(yè)面的超級(jí)鏈接。
