# 使用數據庫
本章節將介紹如何如何創建一個從數據表?`country`?中讀取國家數據并顯示出來的頁面。為了實現這個目標,你將會配置一個數據庫連接,創建一個[活動記錄](http://www.yiichina.com/doc/guide/2.0/db-active-record)類,并且創建一個[操作](http://www.yiichina.com/doc/guide/2.0/structure-controllers)及一個[視圖](http://www.yiichina.com/doc/guide/2.0/structure-views)。
貫穿整個章節,你將會學到:
* 配置一個數據庫連接
* 定義一個活動記錄類
* 使用活動記錄從數據庫中查詢數據
* 以分頁方式在視圖中顯示數據
請注意,為了掌握本章你應該具備最基本的數據庫知識和使用經驗。尤其是應該知道如何創建數據庫,如何通過數據庫終端執行 SQL 語句。
## 準備數據庫
首先創建一個名為?`yii2basic`?的數據庫,應用將從這個數據庫中讀取數據。你可以創建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 數據庫,Yii 內置多種數據庫支持。簡單起見,后面的內容將以 MySQL 為例做演示。
然后在數據庫中創建一個名為?`country`?的表并插入簡單的數據。可以執行下面的語句:
~~~
CREATE TABLE `country` (
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `country` VALUES ('AU','Australia',18886000);
INSERT INTO `country` VALUES ('BR','Brazil',170115000);
INSERT INTO `country` VALUES ('CA','Canada',1147000);
INSERT INTO `country` VALUES ('CN','China',1277558000);
INSERT INTO `country` VALUES ('DE','Germany',82164700);
INSERT INTO `country` VALUES ('FR','France',59225700);
INSERT INTO `country` VALUES ('GB','United Kingdom',59623400);
INSERT INTO `country` VALUES ('IN','India',1013662000);
INSERT INTO `country` VALUES ('RU','Russia',146934000);
INSERT INTO `country` VALUES ('US','United States',278357000);
~~~
此時便有了一個名為?`yii2basic`?的數據庫,在這個數據庫中有一個包含三個字段的數據表?`country`,表中有十行數據。
## 配置數據庫連接
開始之前,請確保你已經安裝了 PHP?[PDO](http://www.php.net/manual/en/book.pdo.php)?擴展和你所使用的數據庫的 PDO 驅動(例如 MySQL 的?`pdo_mysql`)。對于使用關系型數據庫來講,這是基本要求。
驅動和擴展安裝可用后,打開?`config/db.php`?修改里面的配置參數對應你的數據庫配置。該文件默認包含這些內容:
~~~
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=yii2basic',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
~~~
`config/db/php`?是一個典型的基于文件的[配置](http://www.yiichina.com/doc/guide/2.0/concept-configurations)工具。這個文件配置了數據庫連接 yii\db\Connection 的創建和初始化參數,應用的 SQL 查詢正是基于這個數據庫。
上面配置的數據庫連接可以在應用中通過?`Yii::$app->db`?表達式訪問。
> 補充:`config/db.php`?將被包含在應用配置文件?`config/web.php`?中,后者指定了整個[應用](http://www.yiichina.com/doc/guide/2.0/structure-applications)如何初始化。請參考[配置](http://www.yiichina.com/doc/guide/2.0/concept-configurations)章節了解更多信息。
## 創建活動記錄
創建一個繼承自[活動記錄](http://www.yiichina.com/doc/guide/2.0/db-active-record)類的類?`Country`,把它放在?`models/Country.php`?文件,去代表和讀取?`country`?表的數據。
~~~
<?php
namespace app\models;
use yii\db\ActiveRecord;
class Country extends ActiveRecord
{
}
~~~
這個?`Country`?類繼承自 yii\db\ActiveRecord。你不用在里面寫任何代碼。只需要像現在這樣,Yii 就能根據類名去猜測對應的數據表名。
> 補充:如果類名和數據表名不能直接對應,可以覆寫 yii\db\ActiveRecord::tableName() 方法去顯式指定相關表名。
使用?`Country`?類可以很容易地操作?`country`?表數據,就像這段代碼:
~~~
use app\models\Country;
// 獲取 country 表的所有行并以 name 排序
$countries = Country::find()->orderBy('name')->all();
// 獲取主鍵為 “US” 的行
$country = Country::findOne('US');
// 輸出 “United States”
echo $country->name;
// 修改 name 為 “U.S.A.” 并在數據庫中保存更改
$country->name = 'U.S.A.';
$country->save();
~~~
> 補充:活動記錄是面向對象、功能強大的訪問和操作數據庫數據的方式。你可以在[活動記錄](http://www.yiichina.com/doc/guide/2.0/db-active-record)章節了解更多信息。除此之外你還可以使用另一種更原生的被稱做[數據訪問對象](http://www.yiichina.com/doc/guide/2.0/db-dao)的方法操作數據庫數據。
## 創建操作
為了向最終用戶顯示國家數據,你需要創建一個操作。相比之前小節掌握的在?`site`?控制器中創建操作,在這里為所有和國家有關的數據新建一個控制器更加合理。新控制器名為?`CountryController`,并在其中創建一個?`index`?操作,如下:
~~~
<?php
namespace app\controllers;
use yii\web\Controller;
use yii\data\Pagination;
use app\models\Country;
class CountryController extends Controller
{
public function actionIndex()
{
$query = Country::find();
$pagination = new Pagination([
'defaultPageSize' => 5,
'totalCount' => $query->count(),
]);
$countries = $query->orderBy('name')
->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render('index', [
'countries' => $countries,
'pagination' => $pagination,
]);
}
}
~~~
把上面的代碼保存在?`controllers/CountryController.php`?文件中。
`index`?操作調用了活動記錄?`Country::find()`?方法,去生成查詢語句并從?`country`?表中取回所有數據。為了限定每個請求所返回的國家數量,查詢在 yii\data\Pagination 對象的幫助下進行分頁。?`Pagination`?對象的使命主要有兩點:
* 為 SQL 查詢語句設置?`offset`?和?`limit`?從句,確保每個請求只需返回一頁數據(本例中每頁是 5 行)。
* 在視圖中顯示一個由頁碼列表組成的分頁器,這點將在后面的段落中解釋。
在代碼末尾,`index`?操作渲染一個名為?`index`?的視圖,并傳遞國家數據和分頁信息進去。
## 創建視圖
在?`views`?目錄下先創建一個名為?`country`?的子目錄。這個目錄存儲所有由?`country`?控制器渲染的視圖。在?`views/country`?目錄下創建一個名為?`index.php`?的視圖文件,內容如下:
~~~
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>Countries</h1>
<ul>
<?php foreach ($countries as $country): ?>
<li>
<?= Html::encode("{$country->name} ({$country->code})") ?>:
<?= $country->population ?>
</li>
<?php endforeach; ?>
</ul>
<?= LinkPager::widget(['pagination' => $pagination]) ?>
~~~
這個視圖包含兩部分用以顯示國家數據。第一部分遍歷國家數據并以無序 HTML 列表渲染出來。第二部分使用 yii\widgets\LinkPager 去渲染從操作中傳來的分頁信息。小部件?`LinkPager`?顯示一個分頁按鈕的列表。點擊任何一個按鈕都會跳轉到對應的分頁。
## 試運行
瀏覽器訪問下面的 URL 看看能否工作:
~~~
http://hostname/index.php?r=country/index
~~~

首先你會看到顯示著五個國家的列表頁面。在國家下面,你還會看到一個包含四個按鈕的分頁器。如果你點擊按鈕 “2”,將會跳轉到顯示另外五個國家的頁面,也就是第二頁記錄。如果觀察仔細點你還會看到瀏覽器的 URL 變成了:
~~~
http://hostname/index.php?r=country/index&page=2
~~~
在這個場景里,yii\data\Pagination 提供了為數據結果集分頁的所有功能:
* 首先 yii\data\Pagination 把 SELECT 的子查詢?`LIMIT 5 OFFSET 0`?數據表示成第一頁。因此開頭的五條數據會被取出并顯示。
* 然后小部件 yii\widgets\LinkPager 使用 yii\data\Pagination::createUrl() 方法生成的 URL 去渲染翻頁按鈕。URL 中包含必要的參數`page`?才能查詢不同的頁面編號。
* 如果你點擊按鈕 “2”,將會發起一個路由為?`country/index`?的新請求。yii\data\Pagination 接收到 URL 中的?`page`?參數把當前的頁碼設為 2。新的數據庫請求將會以?`LIMIT 5 OFFSET 5`?查詢并顯示。
## 總結
本章節中你學到了如何使用數據庫。你還學到了如何取出并使用 yii\data\Pagination 和 yii\widgets\LinkPager 顯示數據。
下一章中你會學到如何使用 Yii 中強大的代碼生成器?[Gii](http://www.yiichina.com/doc/guide/2.0/tool-gii),去幫助你實現一些常用的功能需求,例如增查改刪(CRUD)數據表中的數據。事實上你之前所寫的代碼全部都可以由 Gii 自動生成。
- 介紹(Introduction)
- 關于 Yii(About Yii)
- 從 Yii 1.1 升級(Upgrading from Version 1.1)
- 入門(Getting Started)
- 安裝 Yii(Installing Yii)
- 運行應用(Running Applications)
- 第一次問候(Saying Hello)
- 使用 Forms(Working with Forms)
- 玩轉 Databases(Working with Databases)
- 用 Gii 生成代碼(Generating Code with Gii)
- 更上一層樓(Looking Ahead)
- 應用結構(Application Structure)
- 結構概述(Overview)
- 入口腳本(Entry Scripts)
- 應用(Applications)
- 應用組件(Application Components)
- 控制器(Controllers)
- 模型(Models)
- 視圖(Views)
- 模塊(Modules)
- 過濾器(Filters)
- 小部件(Widgets)
- 前端資源(Assets)
- 擴展(Extensions)
- 請求處理(Handling Requests)
- 運行概述(Overview)
- 引導(Bootstrapping)
- 路由引導與創建 URL(Routing and URL Creation)
- 請求(Requests)
- 響應(Responses)
- Sessions and Cookies
- 錯誤處理(Handling Errors)
- 日志(Logging)
- 關鍵概念(Key Concepts)
- 組件(Components)
- 屬性(Properties)
- 事件(Events)
- 行為(Behaviors)
- 配置(Configurations)
- 別名(Aliases)
- 類自動加載(Class Autoloading)
- 服務定位器(Service Locator)
- 依賴注入容器(Dependency Injection Container)
- 配合數據庫工作(Working with Databases)
- 數據庫訪問(Data Access Objects): 數據庫連接、基本查詢、事務和模式操作
- 查詢生成器(Query Builder): 使用簡單抽象層查詢數據庫
- 活動記錄(Active Record): 活動記錄對象關系映射(ORM),檢索和操作記錄、定義關聯關系
- 數據庫遷移(Migrations): 在團體開發中對你的數據庫使用版本控制
- Sphinx
- Redis
- MongoDB
- ElasticSearch
- 接收用戶數據(Getting Data from Users)
- 創建表單(Creating Forms)
- 輸入驗證(Validating Input)
- 文件上傳(Uploading Files)
- 收集列表輸入(Collecting Tabular Input)
- 多模型同時輸入(Getting Data for Multiple Models)
- 顯示數據(Displaying Data)
- 格式化輸出數據(Data Formatting)
- 分頁(Pagination)
- 排序(Sorting)
- 數據提供器(Data Providers)
- 數據小部件(Data Widgets)
- 操作客戶端腳本(Working with Client Scripts)
- 主題(Theming)
- 安全(Security)
- 認證(Authentication)
- 授權(Authorization)
- 處理密碼(Working with Passwords)
- 客戶端認證(Auth Clients)
- 安全領域的最佳實踐(Best Practices)
- 緩存(Caching)
- 概述(Overview)
- 數據緩存(Data Caching)
- 片段緩存(Fragment Caching)
- 分頁緩存(Page Caching)
- HTTP 緩存(HTTP Caching)
- RESTful Web 服務
- 快速入門(Quick Start)
- 資源(Resources)
- 控制器(Controllers)
- 路由(Routing)
- 格式化響應(Response Formatting)
- 授權驗證(Authentication)
- 速率限制(Rate Limiting)
- 版本化(Versioning)
- 錯誤處理(Error Handling)
- 開發工具(Development Tools)
- 調試工具欄和調試器(Debug Toolbar and Debugger)
- 使用 Gii 生成代碼(Generating Code using Gii)
- TBD 生成 API 文檔(Generating API Documentation)
- 測試(Testing)
- 概述(Overview)
- 搭建測試環境(Testing environment setup)
- 單元測試(Unit Tests)
- 功能測試(Functional Tests)
- 驗收測試(Acceptance Tests)
- 測試夾具(Fixtures)
- 高級專題(Special Topics)
- 高級應用模版(Advanced Project Template)
- 從頭構建自定義模版(Building Application from Scratch)
- 控制臺命令(Console Commands)
- 核心驗證器(Core Validators)
- 國際化(Internationalization)
- 收發郵件(Mailing)
- 性能優化(Performance Tuning)
- 共享主機環境(Shared Hosting Environment)
- 模板引擎(Template Engines)
- 集成第三方代碼(Working with Third-Party Code)
- 小部件(Widgets)
- Bootstrap 小部件(Bootstrap Widgets)
- jQuery UI 小部件(jQuery UI Widgets)
- 助手類(Helpers)
- 助手一覽(Overview)
- Array 助手(ArrayHelper)
- Html 助手(Html)
- Url 助手(Url)