一、獲取當前控制器和方法
1 $controllerID = Yii::$app->controller->id;
2 $actionID = Yii::$app->controller->action->id;
二、創建url
1.控制器可以用urlManager組件
echo \Yii::$app->urlManager->createUrl(['site/page', 'id' => 'about']);
// /index.php/site/page/id/about/
echo \Yii::$app->urlManager->createUrl(['date-time/fast-forward', 'id' => 105])
// /index.php?r=date-time/fast-forward&id=105
echo \Yii::$app->urlManager->createAbsoluteUrl('blog/post/index');
// http://www.example.com/index.php/blog/post/index/
2.頁面上生成可以用url助手類
use yii\helpers\Url;
// 當前活動路由
// /index.php?r=management/default/users
echo Url::to('');
// 相同的控制器,不同的動作
// /index.php?r=management/default/page&id=contact
echo Url::toRoute(['page', 'id' => 'contact']);
// 相同模塊,不同控制器和動作
// /index.php?r=management/post/index
echo Url::toRoute('post/index');
// 絕對路由,不管是被哪個控制器調用
// /index.php?r=site/index
echo Url::toRoute('/site/index');
// 區分大小寫的控制器動作 `actionHiTech` 的 url 格式
// /index.php?r=management/default/hi-tech
echo Url::toRoute('hi-tech');
// 控制器和動作都區分大小寫的 url,如'DateTimeController::actionFastForward' :
// /index.php?r=date-time/fast-forward&id=105
echo Url::toRoute(['/date-time/fast-forward', 'id' => 105]);
// 從別名中獲取 URL
// http://google.com/
Yii::setAlias('@google', 'http://google.com/');
echo Url::to('@google');
// 獲取當前頁的標準 URL
// /index.php?r=management/default/users
echo Url::canonical();
// 獲得 home 主頁的 URL
// /index.php?r=site/index
echo Url::home();
Url::remember() ; // 保存URL以供下次使用
Url::previous(); // 取出前面保存的 URL
小技巧: 為生成一個指向 # 號(錨連接 ID )的 URL ,比如 /index.php?r=site/page&id=100#title, 你要 指定 # 參數 ,采用 Url::to(['post/read', 'id' => 100, '#' => 'title']) 來創建。
詳細可以參見
http://www.yiifans.com/yii2/guide/runtime-url-handling.html
三、設置auth_key
$this->auth_key = \Yii::$app->security->generateRandomString();
四、配置rbac
在配置文件中的components中加入:
'authManager' => [
'class' => 'yii\rbac\DbManager',
],
現在可以通過 \Yii::$app->authManager 訪問 authManager 。
可以建立測試數據如下:
public function actionInit()
{
$auth = Yii::$app->authManager;
// 添加 "createPost" 權限
$createPost = $auth->createPermission('createPost');
$createPost->description = 'Create a post';
$auth->add($createPost);
// 添加 "updatePost" 權限
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = 'Update post';
$auth->add($updatePost);
// 添加 "author" 角色并賦予 "createPost" 權限
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
// 添加 "admin" 角色并賦予 "updatePost"
// 和 "author" 權限
$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// 為用戶指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id (譯者注:user表的id)
// 通常在你的 User 模型中實現這個函數。
$auth->assign($author, 2);
$auth->assign($admin, 1);
}
如果你的應用允許用戶注冊,你需要在注冊時給新用戶指派一次角色。例如, 在高級項目模板中,要讓所有注冊用戶成為作者,你需要如下例所示修改 frontend\models\SignupForm::signup() 方法
public function signup()
{
if ($this->validate()) {
$user = new User();
$user->username = $this->username;
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
$user->save(false);
// 要添加以下三行代碼:
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->getId());
return $user;
}
return null;
}
更詳細可參見:http://www.yiichina.com/doc/guide/2.0/security-authorization
五、哈希化密碼
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
六、轉義
1.如果你需要的是純文本,你可以如下簡單的轉義:
<?= \yii\helpers\Html::encode($username) ?>
2.如果是 HTML ,我們可以用 HtmlPurifier 幫助類來執行:
<?= \yii\helpers\HtmlPurifier::process($description) ?>
七、數據庫配置
1.在配置文件中的conponents中加入:
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=example',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
2.有時你可能想要在建立起數據庫連接時立即執行一些語句來初始化一些環境變量 (比如設置時區或者字符集), 你可以通過為數據庫連接的 afterOpen 事件注冊一個事件處理器來達到目的。 你可以像這樣直接在應用配置中注冊處理器:
'db' => [
// ...
'on afterOpen' => function($event) {
// $event->sender refers to the DB connection
$event->sender->createCommand("SET time_zone = 'UTC'")->execute();
}
],
八、原生sql查詢
// 返回多行. 每行都是列名和值的關聯數組.
// 如果該查詢沒有結果則返回空數組
$posts = Yii::$app->db->createCommand('SELECT * FROM post')
->queryAll();
// 返回一行 (第一行)
// 如果該查詢沒有結果則返回 false
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=1')
->queryOne();
// 返回一列 (第一列)
// 如果該查詢沒有結果則返回空數組
$titles = Yii::$app->db->createCommand('SELECT title FROM post')
->queryColumn();
// 返回一個標量值
// 如果該查詢沒有結果則返回 false
$count = Yii::$app->db->createCommand('SELECT COUNT(*) FROM post')
->queryScalar();
九、原生sql防止sql注入
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValue(':id', $_GET['id'])
->bindValue(':status', 1)
->queryOne();
十、可以使用函數
`$params = [':id' => $_GET['id'], ':status' => 1];
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValues($params)
->queryOne();
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status', $params)
->queryOne();
十一、綁定參數是通過 預處理語句 實現的。 除了防止 SQL 注入攻擊, 它也可以通過一次預處理 SQL 語句, 使用不同參數多次執行, 來提升性能。
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id');
$post1 = $command->bindValue(':id', 1)->queryOne();
$post2 = $command->bindValue(':id', 2)->queryOne();
因為 bindParam() 支持通過引用來綁定參數, 上述代碼也可以像下面這樣寫:
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id')
->bindParam(':id', $id);
$id = 1;
$post1 = $command->queryOne();
$id = 2;
$post2 = $command->queryOne();
十二、執行非查詢語句
Yii::$app->db->createCommand('UPDATE post SET status=1 WHERE id=1')
->execute();
十三、對于 INSERT, UPDATE 和 DELETE 語句, 不再需要寫純SQL語句了, 你可以直接調用 insert()、 update()、 delete(), 來構建相應的 SQL 語句。
Yii::$app->db->createCommand()->insert('user', [
'name' => 'Sam',
'age' => 30,
])->execute();
// UPDATE (table name, column values, condition)
Yii::$app->db->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
// DELETE (table name, condition)
Yii::$app->db->createCommand()->delete('user', 'status = 0')->execute();
十四、batchInsert() 來一次插入多行,
// table name, column names, column values
Yii::$app->db->createCommand()->batchInsert('user', ['name', 'age'], [
['Tom', 30],
['Jane', 20],
['Linda', 25],
])->execute();
十五、引用表和列名稱
[[column name]]: 使用兩對方括號來將列名括起來;
{{table name}}: 使用兩對大括號來將表名括起來。
// 在 MySQL 中執行該 SQL : SELECT COUNT(`id`) FROM `employee`
$count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{employee}}")
->queryScalar();
十六、使用表前綴
1.表前綴設置:
'db' => [
// ...
'tablePrefix' => 'tbl_',
],
2.例子
// 在 MySQL 中執行該 SQL: SELECT COUNT(`id`) FROM `tbl_employee`
$count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}")
->queryScalar();
十七、執行事務
$db = Yii::$app->db;
$transaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
// ... executing other SQL statements ...
$transaction->commit();
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
}
十八、指定事務隔離級別
yii\db\Transaction::READ_UNCOMMITTED - 最弱的隔離級別,臟讀、不可重復讀以及幻讀都可能發生。
yii\db\Transaction::READ_COMMITTED - 避免了臟讀。
yii\db\Transaction::REPEATABLE_READ - 避免了臟讀和不可重復讀。
yii\db\Transaction::SERIALIZABLE - 最強的隔離級別, 避免了上述所有的問題。
$isolationLevel = \yii\db\Transaction::REPEATABLE_READ;
Yii::$app->db->transaction(function ($db) {
....
}, $isolationLevel);
// or alternatively
$transaction = Yii::$app->db->beginTransaction($isolationLevel);
十九、嵌套事務
1.方式1
Yii::$app->db->transaction(function ($db) {
// outer transaction
$db->transaction(function ($db) {
// inner transaction
});
});
2.方式2
$db = Yii::$app->db;
$outerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$innerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql2)->execute();
$innerTransaction->commit();
} catch (\Exception $e) {
$innerTransaction->rollBack();
throw $e;
}
$outerTransaction->commit();
} catch (\Exception $e) {
$outerTransaction->rollBack();
throw $e;
}
二十、操縱數據庫模式
createTable():創建一張表
renameTable():重命名一張表
dropTable():刪除一張表
truncateTable():刪除一張表中的所有行
addColumn():增加一列
renameColumn():重命名一列
dropColumn():刪除一列
alterColumn():修改一列
addPrimaryKey():增加主鍵
dropPrimaryKey():刪除主鍵
addForeignKey():增加一個外鍵
dropForeignKey():刪除一個外鍵
createIndex():增加一個索引
dropIndex():刪除一個索引
例如
// CREATE TABLE
Yii::$app->db->createCommand()->createTable('post', [
'id' => 'pk',
'title' => 'string',
'text' => 'text',
]);
二十一、查詢生成器
1.如下所示代碼是查詢構造器的一個典型用法:
$rows = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->where(['last_name' => 'Smith'])
->limit(10)
->all();
2.select()方法
$query->select(['user.id AS user_id', 'email']);
// 等同于:
$query->select('user.id AS user_id, email');
3.yii2.0支持子查詢
$subQuery = (new Query())->select('COUNT(*)')->from('user');
// SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post`
$query = (new Query())->select(['id', 'count' => $subQuery])->from('post');
4.distinct()方法
$query->select('user_id')->distinct();
5.addSelect()
$query->select(['id', 'username'])
->addSelect(['email']);
6.子查詢中再次查詢
$subQuery = (new Query())->select('id')->from('user')->where('status=1');
// SELECT * FROM (SELECT `id` FROM `user` WHERE status=1) u
$query->from(['u' => $subQuery]);
7.where()
7.1字符串格式
$query->where('status=1');
// or use parameter binding to bind dynamic parameter values
$query->where('status=:status', [':status' => $status]);
// raw SQL using MySQL YEAR() function on a date field
$query->where('YEAR(somedate) = 2015');
$query->where('status=:status')
->addParams([':status' => $status]);
7.2哈希格式
// ...WHERE (`status` = 10) AND (`type` IS NULL) AND (`id` IN (4, 8, 15))
$query->where([
'status' => 10,
'type' => null,
'id' => [4, 8, 15],
]);
7.3操作符格式
and: 操作數會被 AND 關鍵字串聯起來。例如,['and', 'id=1', 'id=2'] 將會生成 id=1 AND id=2。如果操作數是一個數組,它也會按上述規則轉換成 字符串。例如,['and', 'type=1', ['or', 'id=1', 'id=2']] 將會生成 type=1 AND (id=1 OR id=2)。 這個方法不會自動加引號或者轉義。
in: 第一個操作數應為字段名稱或者 DB 表達式。第二個操作符既可以是一個數組, 也可以是一個 Query 對象。它會轉換成IN 條件語句。如果第二個操作數是一個 數組,那么它代表的是字段或 DB 表達式的取值范圍。如果第二個操作數是 Query 對象,那么這個子查詢的結果集將會作為第一個操作符的字段或者 DB 表達式的取值范圍。 例如, ['in', 'id', [1, 2, 3]] 將生成 id IN (1, 2, 3)。 該方法將正確地為字段名加引號以及為取值范圍轉義。in 操作符還支持組合字段,此時, 操作數1應該是一個字段名數組,而操作數2應該是一個數組或者 Query 對象, 代表這些字段的取值范圍。
like: 第一個操作數應為一個字段名稱或 DB 表達式, 第二個操作數可以使字符串或數組, 代表第一個操作數需要模糊查詢的值。比如,['like', 'name', 'tester'] 會生成 name LIKE '%tester%'。 如果范圍值是一個數組,那么將會生成用 AND 串聯起來的 多個 like 語句。例如,['like', 'name', ['test', 'sample']] 將會生成 name LIKE '%test%' AND name LIKE '%sample%'。 你也可以提供第三個可選的操作數來指定應該如何轉義數值當中的特殊字符。 該操作數是一個從需要被轉義的特殊字符到轉義副本的數組映射。 如果沒有提供這個操作數,將會使用默認的轉義映射。如果需要禁用轉義的功能, 只需要將參數設置為 false 或者傳入一個空數組即可。需要注意的是, 當使用轉義映射(又或者沒有提供第三個操作數的時候),第二個操作數的值的前后 將會被加上百分號。
or like: 用法和 like 操作符類似,區別在于當第二個操作數為數組時, 會使用 OR 來串聯多個 LIKE 條件語句。
>, <=, 或者其他包含兩個操作數的合法 DB 操作符: 第一個操作數必須為字段的名稱, 而第二個操作數則應為一個值。例如,['>', 'age', 10] 將會生成 age>10。
8.附加條件
8.1andWhere()
$status = 10;
$search = 'yii';
$query->where(['status' => $status]);
if (!empty($search)) {
$query->andWhere(['like', 'title', $search]);
}
9、過濾條件
當 WHERE 條件來自于用戶的輸入時,你通常需要忽略用戶輸入的空值。 例如,在一個可以通過用戶名或者郵箱搜索的表單當中,用戶名或者郵箱 輸入框沒有輸入任何東西,這種情況下你想要忽略掉對應的搜索條件, 那么你就可以使用 yii\db\Query::filterWhere() 方法來實現這個目的:
// $username 和 $email 來自于用戶的輸入
$query->filterWhere([
'username' => $username,
'email' => $email,
]);
10、排序
// ... ORDER BY `id` ASC, `name` DESC
$query->orderBy([
'id' => SORT_ASC,
'name' => SORT_DESC,
]);
添加額外排序
$query->orderBy('id ASC')
->addOrderBy('name DESC');
11、groupBy()
$query->groupBy('id, status');
$query->groupBy(['id', 'status'])
->addGroupBy('age');
12、having()
$query->having(['status' => 1]);
$query->having(['status' => 1])
->andHaving(['>', 'age', 30]);
13、limit()和offset()
$query->limit(10)->offset(20);
14、join()
// ... LEFT JOIN `post` ON `post`.`user_id` = `user`.`id`
$query->join('LEFT JOIN', 'post', 'post.user_id = user.id');
你可以分別調用如下的快捷方法來指定 INNER JOIN, LEFT JOIN 和 RIGHT JOIN。
innerJoin()
leftJoin()
rightJoin()
$query->leftJoin('post', 'post.user_id = user.id');
15、連接子查詢
$subQuery = (new \yii\db\Query())->from('post');
$query->leftJoin(['u' => $subQuery], 'u.id = author_id');
16、union()
$query1 = (new \yii\db\Query())
->select("id, category_id AS type, name")
->from('post')
->limit(10);
$query2 = (new \yii\db\Query())
->select('id, type, name')
->from('user')
->limit(10);
$query1->union($query2);
注:你可以通過多次調用 union() 方法來追加更多的 UNION 子句。
17、 count(),sum($q), average($q), max($q), min($q)
18、all()和one()
// SELECT `id`, `email` FROM `user`
$rows = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->all();
// SELECT * FROM `user` WHERE `username` LIKE `%test%`
$row = (new \yii\db\Query())
->from('user')
->where(['like', 'username', 'test'])
->one();
注:one()返回一條數據
19、有時候,你也許想要測試或者使用一個由 yii\db\Query 對象創建的 SQL 語句。 你可以使用以下的代碼來達到目的:
$command = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->where(['last_name' => 'Smith'])
->limit(10)
->createCommand();
// 打印 SQL 語句
echo $command->sql;
// 打印被綁定的參數
print_r($command->params);
// 返回查詢結果的所有行
$rows = $command->queryAll();
20、索引查詢結果
// 返回 [100 => ['id' => 100, 'username' => '...', ...], 101 => [...], 103 => [...], ...]
$query = (new \yii\db\Query())
->from('user')
->limit(10)
->indexBy('id')
->all();
如需使用表達式的值做為索引,那么只需要傳遞一個匿名函數給 yii\db\Query::indexBy() 方法即可:
$query = (new \yii\db\Query())
->from('user')
->indexBy(function ($row) {
return $row['id'] . $row['username'];
})->all();
21、批處理查詢
$query = (new \yii\db\Query())
->from('user')
->indexBy('username');
foreach ($query->batch() as $users) {
// $users 的 “username” 字段將會成為索引
}
foreach ($query->each() as $username => $user) {
}
注:batch一次取100條數據,each數據表中的一行數據
二十二、活動記錄
1.聲明 AR 類
namespace app\models;
use yii\db\ActiveRecord;
class Customer extends ActiveRecord
{
/**
* @return string 返回該AR類關聯的數據表名
*/
public static function tableName()
{
return 'customer';
}
}
2.指定數據庫
public static function getDb()
{
return \Yii::$app->db2; // 使用名為 "db2" 的應用組件
}
3.查詢數據
// 取回所有活躍客戶(狀態為 *active* 的客戶)并以他們的 ID 排序:
$customers = Customer::find()
->where(['status' => Customer::STATUS_ACTIVE])
->orderBy('id')
->all();
// 返回ID為1的客戶:
$customer = Customer::find()
->where(['id' => 1])
->one();
// 取回活躍客戶的數量:
$count = Customer::find()
->where(['status' => Customer::STATUS_ACTIVE])
->count();
// 以客戶ID索引結果集:
$customers = Customer::find()->indexBy('id')->all();
// $customers 數組以 ID 為索引
// 用原生 SQL 語句檢索客戶:
$sql = 'SELECT * FROM customer';
$customers = Customer::findBySql($sql)->all();
3.1findOne 和 findAll()(前者返回第一個匹配到的實例,后者返回所有)
// 返回 id 為 1 的客戶
$customer = Customer::findOne(1);
// 返回 id 為 1 且狀態為 *active* 的客戶
$customer = Customer::findOne([
'id' => 1,
'status' => Customer::STATUS_ACTIVE,
]);
// 返回id為1、2、3的一組客戶
$customers = Customer::findAll([1, 2, 3]);
// 返回所有狀態為 "deleted" 的客戶
$customer = Customer::findAll([
'status' => Customer::STATUS_DELETED,
]);
3.2以數組形式獲取數據
// 以數組而不是對象形式取回客戶信息:
$customers = Customer::find()
->asArray()
->all();
// $customers 的每個元素都是鍵值對數組
4.批量獲取數據
// 一次提取 10 個客戶信息
foreach (Customer::find()->batch(10) as $customers) {
// $customers 是 10 個或更少的客戶對象的數組
}
// 一次提取 10 個客戶并一個一個地遍歷處理
foreach (Customer::find()->each(10) as $customer) {
// $customer 是一個 ”Customer“ 對象
}
// 貪婪加載模式的批處理查詢
foreach (Customer::find()->with('orders')->each() as $customer) {
}
5.操作數據(insert()、update()、delete()、insertAll()、updateAllCounts()、deleteAll())
// 插入新客戶的記錄
$customer = new Customer();
$customer->name = 'James';
$customer->email = 'james@example.com';
$customer->save(); // 等同于 $customer->insert();
// 更新現有客戶記錄
$customer = Customer::findOne($id);
$customer->email = 'james@example.com';
$customer->save(); // 等同于 $customer->update();
// 刪除已有客戶記錄
$customer = Customer::findOne($id);
$customer->delete();
// 刪除多個年齡大于20,性別為男(Male)的客戶記錄
Customer::deleteAll('age > :age AND gender = :gender', [':age' => 20, ':gender' => 'M']);
// 所有客戶的age(年齡)字段加1:
Customer::updateAllCounters(['age' => 1]);
5.數據輸入與有效性驗證
// 新建一條記錄
$model = new Customer;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
// 獲取用戶輸入的數據,驗證并保存
}
// 更新主鍵為$id的AR
$model = Customer::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
// 獲取用戶輸入的數據,驗證并保存
}
6.讀取默認值
$customer = new Customer();
$customer->loadDefaultValues();
// ... 渲染 $customer 的 HTML 表單 ...
7.查詢關聯的數據
class Customer extends \yii\db\ActiveRecord
{
public function getOrders()
{
// 客戶和訂單通過 Order.customer_id -> id 關聯建立一對多關系
return $this->hasMany(Order::className(), ['customer_id' => 'id']);
}
}
class Order extends \yii\db\ActiveRecord
{
// 訂單和客戶通過 Customer.id -> customer_id 關聯建立一對一關系
public function getCustomer()
{
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
建立關聯關系后,獲取關聯數據和獲取組件屬性一樣簡單, 執行以下相應getter方法即可:
// 取得客戶的訂單
$customer = Customer::findOne(1);
$orders = $customer->orders; // $orders 是 Order 對象數組
有時候需要在關聯查詢中傳遞參數,如不需要返回客戶全部訂單, 只需要返回購買金額超過設定值的大訂單, 通過以下getter方法聲明一個關聯數據 bigOrders :
class Customer extends \yii\db\ActiveRecord
{
public function getBigOrders($threshold = 100)
{
return $this->hasMany(Order::className(), ['customer_id' => 'id'])
->where('subtotal > :threshold', [':threshold' => $threshold])
->orderBy('id');
}
}
$orders = $customer->getBigOrders(200)->all();
8.中間關聯表
class Order extends \yii\db\ActiveRecord
{
public function getItems()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->viaTable('order_item', ['order_id' => 'id']);
}
}
以上方法取代了中間表,等價于:
class Order extends \yii\db\ActiveRecord
{
public function getOrderItems()
{
return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
}
public function getItems()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->via('orderItems');
}
}
9.延遲加載和即時加載(又稱惰性加載與貪婪加載)
$customers = Customer::find()->limit(100)
->with('orders')->all();
注意:當用即時加載定制 select() 時,確保連接 到關聯模型的列都被包括了,否則,關聯模型不會載入。如:
$orders = Order::find()->select(['id', 'amount'])->with('customer')->all();
// $orders[0]->customer 總是空的,使用以下代碼解決這個問題:
$orders = Order::find()->select(['id', 'amount', 'customer_id'])->with('customer')->all();
有時候,你想自由的自定義關聯查詢,延遲加載和即時加載都可以實現,如:
$customer = Customer::findOne(1);
// 延遲加載: SELECT * FROM order WHERE customer_id=1 AND subtotal>100
$orders = $customer->getOrders()->where('subtotal>100')->all();
// 即時加載: SELECT * FROM customer LIMIT 100
// SELECT * FROM order WHERE customer_id IN (1,2,...) AND subtotal>100
$customers = Customer::find()->limit(100)->with([
'orders' => function($query) {
$query->andWhere('subtotal>100');
},
])->all();
10逆關系
class Customer extends ActiveRecord
{
....
public function getOrders()
{
return $this->hasMany(Order::className(), ['customer_id' => 'id']);
}
}
class Order extends ActiveRecord
{
....
public function getCustomer()
{
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
為避免多余執行的后一條語句,我們可以為 customer或 orders 關聯關系定義相反的關聯關系,通過調用 yii\db\ActiveQuery::inverseOf() 方法可以實現。
class Customer extends ActiveRecord
{
....
public function getOrders()
{
return $this->hasMany(Order::className(), ['customer_id' => 'id'])->inverseOf('customer');
}
}
相對關系也可以用在即時加載中:
// SELECT * FROM customer
// SELECT * FROM order WHERE customer_id IN (1, 2, ...)
$customers = Customer::find()->with('orders')->all();
// 輸出相同
if ($customers[0]->orders[0]->customer === $customers[0]) {
echo '相同';
} else {
echo '不相同';
}
11、JOIN 類型關聯查詢
// 查找所有訂單并以客戶 ID 和訂單 ID 排序,并貪婪加載 "customer" 表
$orders = Order::find()->joinWith('customer')->orderBy('customer.id, order.id')->all();
// 查找包括書籍的所有訂單,并以 `INNER JOIN` 的連接方式即時加載 "books" 表
$orders = Order::find()->innerJoinWith('books')->all();
可以連接一個或多個關聯關系,可以自由使用查詢條件到關聯查詢, 也可以嵌套連接關聯查詢。如:
// 連接多重關系
// 找出24小時內注冊客戶包含書籍的訂單
$orders = Order::find()->innerJoinWith([
'books',
'customer' => function ($query) {
$query->where('customer.created_at > ' . (time() - 24 * 3600));
}
])->all();
// 連接嵌套關系:連接 books 表及其 author 列
$orders = Order::find()->joinWith('books.author')->all();
有時連接兩個表時,需要在關聯查詢的 ON 部分指定額外條件。 這可以通過調用 yii\db\ActiveQuery::onCondition() 方法實現:
class User extends ActiveRecord
{
public function getBooks()
{
return $this->hasMany(Item::className(), ['owner_id' => 'id'])->onCondition(['category_id' => 1]);
}
}
注意:如果通過 yii\db\ActiveQuery::with() 進行貪婪加載或使用惰性加載的話,則 on 條件會被放置在對應 SQL語句的 WHERE 部分。 因為,此時此處并沒有發生 JOIN 查詢。比如:
// SELECT * FROM user WHERE id=10
$user = User::findOne(10);
// SELECT * FROM item WHERE owner_id=10 AND category_id=1
$books = $user->books;
12、關聯表操作
$customer = Customer::findOne(1);
$order = new Order();
$order->subtotal = 100;
$customer->link('orders', $order);
13、作用域
namespace app\models;
use yii\db\ActiveQuery;
class CommentQuery extends ActiveQuery
{
public function active($state = true)
{
$this->andWhere(['active' => $state]);
return $this;
}
}
重點:
類必須繼承 yii\db\ActiveQuery (或者是其他的 ActiveQuery ,比如 yii\mongodb\ActiveQuery)。
必須是一個public類型的方法且必須返回 $this 實現鏈式操作。可以傳入參數。
檢查 yii\db\ActiveQuery 對于修改查詢條件是非常有用的方法。
其次,覆蓋yii\db\ActiveRecord::find() 方法使其返回自定義的查詢對象而不是常規的ActiveQuery。對于上述例子,你需要編寫如下代碼:
namespace app\models;
use yii\db\ActiveRecord;
class Comment extends ActiveRecord
{
/**
* @inheritdoc
* @return CommentQuery
*/
public static function find()
{
return new CommentQuery(get_called_class());
}
}
就這樣,現在你可以使用自定義的作用域方法了:
$comments = Comment::find()->active()->all();
$inactiveComments = Comment::find()->active(false)->all();
你也能在定義的關聯里使用作用域方法,比如:
class Post extends \yii\db\ActiveRecord
{
public function getActiveComments()
{
return $this->hasMany(Comment::className(), ['post_id' => 'id'])->active();
}
}
或者在執行關聯查詢的時候使用(on-the-fly 是啥?):
$posts = Post::find()->with([
'comments' => function($q) {
$q->active();
}
])->all();
14、事務操作
class Feature extends \yii\db\ActiveRecord
{
// ...
public function getProduct()
{
return $this->hasOne(Product::className(), ['id' => 'product_id']);
}
}
class Product extends \yii\db\ActiveRecord
{
// ...
public function getFeatures()
{
return $this->hasMany(Feature::className(), ['product_id' => 'id']);
}
}
重寫 yii\db\ActiveRecord::save() 方法:
class ProductController extends \yii\web\Controller
{
public function actionCreate()
{
// FIXME: TODO: WIP, TBD
}
}
(譯注:我覺得上面應該是原手冊里的bug)
在控制器層使用事務:
class ProductController extends \yii\web\Controller
{
public function actionCreate()
{
// FIXME: TODO: WIP, TBD
}
}
作為這些脆弱方法的替代,你應該使用原子操作方案特性。
class Feature extends \yii\db\ActiveRecord
{
// ...
public function getProduct()
{
return $this->hasOne(Product::className(), ['product_id' => 'id']);
}
public function scenarios()
{
return [
'userCreates' => [
'attributes' => ['name', 'value'],
'atomic' => [self::OP_INSERT],
],
];
}
}
class Product extends \yii\db\ActiveRecord
{
// ...
public function getFeatures()
{
return $this->hasMany(Feature::className(), ['id' => 'product_id']);
}
public function scenarios()
{
return [
'userCreates' => [
'attributes' => ['title', 'price'],
'atomic' => [self::OP_INSERT],
],
];
}
public function afterValidate()
{
parent::afterValidate();
// FIXME: TODO: WIP, TBD
}
public function afterSave($insert)
{
parent::afterSave($insert);
if ($this->getScenario() === 'userCreates') {
// FIXME: TODO: WIP, TBD
}
}
}
Controller里的代碼將變得很簡潔:
class ProductController extends \yii\web\Controller
{
public function actionCreate()
{
// FIXME: TODO: WIP, TBD
}
}
控制器非常簡潔:
class ProductController extends \yii\web\Controller
{
public function actionCreate()
{
// FIXME: TODO: WIP, TBD
}
}
- 環境搭建
- centos6.5 lnmp環境搭建
- svn環境搭建
- centos lamp安裝配置
- mysql
- mysql常用命令
- mysql技術內幕
- 1.1mysql體系結構
- 1.2mysql存儲引擎
- 1.3mysql連接
- linux
- linux-常用命令
- linux下vim命令
- 第三方平臺開發
- 微信開發之旅
- php
- php框架
- lavarel常用命令
- thinkPhp常用命令
- yii2.0.8
- 安裝
- yii常用
- yii配置
- yii常用2
- php源碼積累
- php字符串截取
- php圖片處理(gd)
- 二維數組保持索引排序(高低)
- 獲取一個月首尾天數
- 時間函數
- php內置函數
- html
- js
- 基本命令
- js案例
- js去空格
- css
- 基本樣式
- 案例
- ul li 橫向水平居中自適應案例
- 固定底部導航欄并自適應
- 購物車帶角標
- display的兼容解決
- 前端框架
- boostrap
- 常用類
- git
- 上傳項目到遠程倉庫GitHub