新聞展示功能?
在上一個章節里,我們寫了一個用于展示靜態頁面的類文件,通過這個簡單的例子我們把CI4框架里的一些基本的概念講解了一下。 我們還簡單的使用了CI4里面的路由功能,通過自定義路由規則實現了頁面的鏈接地址凈化,使頁面的訪問地址看起來更整潔和搜索引擎友好。 現在,我們要開始進行一些基于數據庫的動態內容的開發了。
建立教程所需的數據庫?
我們假設你已經安裝和 配置 好了用于 CodeIgniter4 運行所需的數據庫軟件。 我們也假設你會使用數據庫管理的客戶端工具(mysql,MySQL Workbench或者phpMyAdmin等)來運行稍后教程里提供的創建數據庫表和插入測試數據所需的SQL代碼。
下面我們就來教你如何為本教程創建一個數據庫,并且正確配置CodeIgniter來使用這個數據庫。
用你安裝好的數據庫客戶端工具打開數據庫,然后運行下面的兩段SQL代碼(MySQL適用)來創建一個數據表和插入一些測試數據。 隨著你對 CodeIgniter 的熟悉程度越來越高,這些數據庫相關的操作也可以通過程序代碼在CodeIgniter框架下完成,你可以閱讀 數據遷移 和 數據填充 這兩個章節來了解相關內容,以便掌握用程序代碼操作數據庫的相關技能。
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: 數據表里的 slug 字段在基于互聯網訪問的網站上是個非常有用的字段。 一般在這個字段里存放簡短的詞語來概括性描述數據內容,這將提升用戶打開網址時候的訪問體驗,并且這種網址也是搜索引擎友好的網址,有利于網站內容的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
創建你的數據模型文件?
我們要求你將數據庫的操作代碼寫在模型(Model)文件里面,以便以后代碼重用,不要將這些代碼寫在控制器(Controller)里。 你的模型文件們應該成為你處理數據庫相關的增、刪、改、查操作的默認地方。交由模型文件來操作數據庫或者其他格數的數據文件。
打開 app/Models/ 目錄,在這個目錄下面創建一個名字為 NewsModel.php 的文件,并在文件里加入如下代碼。 為了保證代碼運行順利,你需要確認一下已經正確的完成了數據庫的相關配置:doc:這里 <../database/configuration>。
<?php
namespace App\Models;
class NewsModel extends \CodeIgniter\Model
{
protected $table = 'news';
}
這段代碼和我們上一個章節里創建的控制器里的代碼類似。
我們通過繼承 CodeIgniter\Model
創建了一個新的模型文件,并加載了CI4內置的數據庫操作類庫。
后面我們可以在代碼里通過 $this->db
來調用數據庫的相關操作類庫。
現在我們的數據庫和數據模型文件已經建立好了。 我們首先寫一個方法從數據庫中獲取所有的新聞文章。 為實現這點,我們將使用 CodeIgniter 的數據庫抽象層工具 查詢構建器,通過它你可以編寫你的查詢代碼,并在 所有支持的數據庫平臺 上運行。 數據模型文件可以方便的和 查詢構建器 一起工作,并且提供了一些方法讓你操作數據的時候更加簡單。現在向你的模型中添加如下代碼。
public function getNews($slug = false)
{
if ($slug === false)
{
return $this->findAll();
}
return $this->asArray()
->where(['slug' => $slug])
->first();
}
通過這段代碼,你可以執行兩種不同的查詢,一種是獲取所有的新聞條目,另一種是根據特定的 slug 來獲取指定的新聞條目。 你可能注意到了,我們直接的進行了基于``$slug`` 變量的數據對比命令,并不需要預先執行相應字段的查詢操作,因為:doc:查詢構建器 <../database/query_builder> 自動幫我們完成了這個工作。
我們在這里用到的 findAll()
和 first()
都是 CodeIgniter4 的數據模型(Model)基礎類里面內置的方法。
他們根據我們在數據模型文件里(本例中是 NewsModel 文件)聲明的 $table
變量而知道該對哪個數據表進行操作。
這些方法通過 查詢構建器 運行指令操作當前數據表,并且會以數組的形式返回數據查詢結果。在這個例子里面,findAll()
的返回值是包含了指定數據表中的所有數據對象的一個數組。
顯示新聞?
現在,查詢已經在數據模型文件里寫好了,接下來我們需要將數據模型綁定到視圖上,向用戶顯示新聞條目了。
這可以在之前寫的 Pages
控制器里來做,但為了更清楚的闡述,我們定義了一個新的 News
控制器,創建在 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);
}
}
閱讀上面的代碼你會發現,這和之前寫的代碼有些相似之處。
首先,它繼承了*CodeIgniter*的一個核心類,Controller
,這個核心類提供了很多非常有用的方法,它確保你可以操作當前的 Request
和 Response
對象,也可以操作``Logger`` 類, 方便你把日志文件寫到磁盤里。
其次,有兩個方法用來顯示新聞條目,一個顯示所有的,另一個顯示特定的。
你可以看到第二個方法中調用模型方法時傳入了 $slug
參數,模型根據這個 slug 返回特定的新聞條目。
現在,通過模型,控制器已經獲取到數據了,但還沒有顯示出來。
下一步要做的就是將數據傳遞給視圖。
我們修改 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');
}
上面的代碼從模型中獲取所有的新聞條目,并賦值給一個變量(news)。
另外頁面的標題賦值給了 $data['title']
元素,然后所有的數據被傳遞給視圖。
現在你需要創建一個視圖文件來顯示新聞條目了,新建 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 ?>
這里,我們通過一個循環將所有的新聞條目顯示給用戶,你可以看到我們直接采用了 HTML 和 PHP 混用的寫法創建了一個視圖頁面。 如果你希望使用一種模板語言,你可以使用 CodeIgniter 的 視圖模版解析類 <../outgoing/view_parser> ,或其他的第三方解析器。
新聞的列表頁就做好了,但是我們還缺少一個顯示特定新聞條目的頁面。
我們可以調用之前創建的模型里的數據來實現這個功能,你只需要向控制器中添加一些代碼,然后再新建一個視圖就可以了。
回到 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');
}
我們并沒有直接調用 getNews()
方法,而是傳入了一個 $slug
參數,所以它會返回相應的新聞條目。
最后剩下的事是創建視圖文件 app/Views/news/view.php
并添加如下代碼 。
<?php echo ‘<h2>’.$news[‘title’].’</h2>’; echo $news[‘body’];
路由?
由于之前我們創建了基于通配符的路由規則,所以現在需要新增一條路由以便能訪問到你剛剛創建的控制器。
修改路由配置文件(app/config/routes.php)添加類似下面的代碼。
該規則可以讓地址中帶*news*的請求訪問 News
控制器而不是去訪問之前默認的 Pages
控制器。
第一行代碼可以讓訪問 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 來訪問你創建好的新聞列表頁面吧。 你將會看到如下圖一樣的一個展示新聞列表的網頁,列表里的每個文章都帶一個可以打開該條新聞詳情頁面的超級鏈接。
