Yii2 基礎:安裝,控制器、視圖、數據模型

1. Yii2 的安裝啓動;

1.1 安裝;

  • 方法1 :訪問 Yii 官網,進入下載頁面,下載 Yii2 的基本應用程序模板的歸檔文件
# 進入項目目錄創建單個項目文件夾
cd /data/project/test/
mkdir yii2
cd yii2

# 下載歸檔文件
wget https://github.com/yiisoft/yii2/releases/download/2.0.17/yii-basic-app-2.0.17.tgz

# 解壓後多出一個 basic 文件夾
tar zcvf yii-basic-app-2.0.17.tgz

# 修改配置文件
cd basic/
vim config/web.php
# 查詢關鍵字 “cookieValidationKey”,修改如下
'cookieValidationKey' => 'asdf',

# 設置緩存文件夾可寫權限
chmod -R 777 runtime
chmod -R 777 web/assets

# 檢查 1:訪問 http://192.168.2.214/yii2/basic/requirements.php
# 頁面沒有報錯項目說明,則當前環境符合 Yii2 運行標準

# 檢查 2:訪問 http://192.168.2.214/yii2/basic/web/
# 看到 “Congratulations!” 說明框架安裝成功
  • 方法2 :Composer 安裝
# 進入項目目錄創建單個項目文件夾
cd /data/project/test/
mkdir yii2
cd yii2

# 安裝
create-project yiisoft/yii2-app-basic basic
# 文件自動下載完成後會自動配置目錄權限
Generating autoload files
> yii\composer\Installer::postCreateProject
chmod('runtime', 0777)...done.
chmod('web/assets', 0777)...done.
chmod('yii', 0755)...done.
> yii\composer\Installer::postInstall
# 訪問 http://192.168.2.214/yii2/basic/requirements.php
# 看到 “Congratulations!” 說明框架安裝成功

1.2 請求處理流程;

參考頁面:https://www.yiichina.com/doc/guide/2.0/structure-overview
當一個請求來到了入口腳本之後(basic/web/index.php),這個入口腳本的本質工作並不是去處理請求,把請求的處理交給了應用主體。應用主體在代碼中就是一個對象
應用主體在正式處理請求之前,會去加載一堆應用組件、以及一些相應的模塊,去幫助更好的處理請求。應用主體在正式處理請求的時候,會把請求的處理委託給一個控制器。
控制器在處理請求的時候,如果需要和數據庫打交道的話,會讓模型和數據庫進行交流。然後控制器在處理請求完成之後,如果想要回饋給用戶一些信息的話,它會使用視圖去回饋內容。
視圖爲了更好的展現回饋的內容,會去使用一些小部件,以及一些前端資源包
在這裏插入圖片描述

1.3 命名空間;

// 新建文件 A.php
<?php
namespace a\b\c;

class Apple{
	function info(){
		echo 'this is Apple A';
	}
}

// 新建文件 B.php
<?php
namespace d\e\f;

class Apple{
	function info(){
		echo 'this is Apple B';
	}
}

// 新建文件 C.php
<?php
// 不存在於任何命名空間:全局類
class Apple{
	function info(){
		echo 'this is Apple C';
	}
}

// 新建文件 index.php
<?php
require_once('A.php');
require_once('B.php');
require_once('C.php');

// use 關鍵字:一旦使用 Apple() 類,默認使用 a\b\c 下的 Apple()
use a\b\c\Apple;
// as 關鍵字:重命名類名
use d\e\f\Apple as bApple;

// $a_app = new a\b\c\Apple();
$a_app = new Apple();
$a_app2 = new Apple();
$a_app->info();

$b_app = new bApple();

// 訪問全局類
$c_app = new \Apple();

2. 控制器;

  • 控制器目錄:basic/controllers
  • 實例:創建 basic/controllers/HelloController.php
<?php

// 控制器類必須放在命名空間中,還必須繼承 controllers(yii\web\Controller) 類
namespace app\controllers;

// use 全局類 Yii
use Yii;
use yii\web\Controller;
use yii\web\cookie;

class HelloController extends controller{

    // 2.1 控制器的創建
    // 專門處理請求的方法不叫方法,叫操作
    public function actionIndex(){
        echo 'Hello World';
 
    }

    // 2.2 請求處理
    public function actionRequest(){
        // 參考: https://www.yiichina.com/doc/guide/2.0/runtime-requests

        // 通過請求組件獲取瀏覽器 URL 傳來的參數
        // 通過全局類 Yii 裏的 $app 靜態變量(應用主體)
        // 這個應用主體在開始的時候會加載各種各樣的應用組件
        // 有一個 request 的請求組件
        $request = Yii::$app->request;

        // 獲取 get 數據
        echo $request->get('id', 0) . "<br>";

        // 獲取 post 數據
        echo $request->post('data', 'no data') . "<br>";

        // 判斷是否 get / post 過來的數據
        if($request->isGet){
            echo 'this is get method' . "<br>";
        }

        // 獲取用戶的 ip
        echo $request->userIP . "<br>";
    }


    // 2.3 響應處理
    public function actionResponse(){
        // 參考:https://www.yiichina.com/doc/guide/2.0/runtime-responses

        // 當瀏覽器發送來一個請求之後,在操作裏對請求經過處理之後
        // 服務器會把請求處理結果打包成一個消息再返回給瀏覽器,這個消息就稱之爲響應
        // 在操作中可以對這些響應進行一些設置和處理
        // 要處理響應,需要通過一個響應組件,響應組件的獲取和請求組件的獲取非常的相似
        $response = Yii::$app->response;

        // 設置狀態碼
        $response->statusCode = '200';

        // 設置 HTTP 頭
        $response->headers->set('pragma', 'max-age=5');
        $response->headers->remove('pragma');
        $response->headers->add('pragma2', 'no-cache');
        // 跳轉
        $response->headers->add('location', 'http://www.baidu.com');
        $this->redirect('http://www.baidu.com', 302);

        // 文件下載
        $response->headers->add('content-disposition', 'attachment; filename="a.jpg"');
        $response->sendFile('./robots.txt');
    }


    // 2.4 session 處理
    public function actionSession(){
        // 參考:https://www.yiichina.com/doc/guide/2.0/runtime-sessions-cookies

        // 需要獲取 session 應用組件
        $session = Yii::$app->session;
        
        // 判斷 session 是否開啓
        $session->open();
        if($session->isActive){
             echo 'session is active';
        }

        // 設置一個 session
        $session->set('user', 'zhangsan');  // 當做對象
        $session['user2'] = 'lisi';         // 當做數組
        // 數組式訪問接口,參考:https://www.php.net/manual/zh/class.arrayaccess.php
        // 實現了這個接口的類,它所產生的對象都可以當成數組來使用
        // session 組件就是繼承了 ArrayAccess

        // 獲取 session
        echo $session->get('user') . "<br>";
        echo $session->get('user2') . "<br>";

        // 刪除 session
        $session->remove('user');
        unset($session['user2']);
        echo $session->get('user2') . "<br>";

    }


    // 2.5 cookie 處理
    public function actionCookie(){
        // 往響應中塞入 cookie 數據
        $cookies = Yii::$app->response->cookies;

        $cookie_data = [
            'name' => 'user', 
            'value' => 'zhangsan1'
        ];

        // 添加 cookie
        $cookies->add(new Cookie($cookie_data));

        // 刪除 cookie
        $cookies->remove('user');

        // 從請求中獲取 cookie
        $cookies = Yii::$app->request->cookies;
        echo $cookies->getValue('user', 'nodata');

    }


}

3. 視圖;

3.1 視圖文件的創建、數據傳遞、數據安全;

  • 實例:修改 basic/controllers/HelloController.php
<?php
// 新增方法
// 視圖
public function actionView1(){
    // 3.1 視圖文件創建:basic/views/hello/view1.php
    return $this->renderPartial('view1');

    // 3.2 數據傳遞
    $data = [
        'view_hello_str' => 'Hello God!',
        'view_hello_arr' => ['hahahaha!' , 'heiheiheihei!']
    ];
    return $this->renderPartial('view1', $data);

    // 3.3 數據安全
    $data['str'] = 'Hello Jerry!<script>alert(11)</script>';
    return $this->renderPartial('view1', $data);
}
  • 創建視圖文件:basic/views/hello/view1.php
<!-- 3.11 視圖文件創建: -->
<h1>Hello world!</h1>

<!-- 3.12 數據傳遞 -->
<h1><?=$view_hello_str;?></h1>
<h1><?=$view_hello_arr[1];?></h1>

<!-- 3.13 數據安全 -->
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<!-- script代碼原樣輸出 -->
<h1><?=Html::encode($str);?></h1>
<!-- 過濾 script 代碼 -->
<h1><?=HtmlPurifier::process($str);?></h1>
  • 訪問 http://192.168.2.214/yii2/basic/web/index.php?r=hello/view1
    在這裏插入圖片描述

3.2 佈局文件;

  • 創建視圖佈局文件:basic/views/layouts/common.php
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <h1>hello common</h1>
    
    <?=$content;?>

    <!-- 數據塊 -->
    <h1>      
        <?php if(isset($this->blocks['block1'])): ?>
            <?=$this->blocks['block1'];?>
        <?php else: ?>
            <h1>hello common2</h1>
        <?php endif; ?>
    </h1>
</head>
</html>
  • 創建視圖文件:basic/views/hello/about.php
<h2>about 頁面:hello about</h2>

<!-- render() 方法傳遞參數 -->
<h3>參數傳遞:<?=$v_hello_str;?></h3>

<!-- 呈現 about2.php 的內容 -->
<?php echo '導入 about2 內容:' . $this->render('about2');?>

<!-- 數據塊 -->
<?php $this->beginBlock('block1'); ?>
<h1>replace common2</h1>
<?php $this->endBlock(); ?>

  • 創建視圖文件:basic/views/hello/about2.php
<h2>hello about2</h2>
  • 修改 basic/controllers/HelloController.php
<?php
// 添加如下方法

public $layout = 'common';

public function actionIndex(){
    // 3.21 佈局文件
    // 1. 會把視圖文件裏面的內容放到一個 $content 的變量中
    // 2. 會把佈局文件顯示出來:common.php
    return $this->render('about', ['v_hello_str' => 'hello world']); // 顯示 common + about
    return $this->renderPartial('about');   // 顯示 about

}

4. 數據模型(活動記錄);

4.1 數據模型之單表增刪改查;

  • 修改數據庫配置文件:basic/config/db.php
  • 創建活動記錄:basic/models/Test.php
<?php

namespace app\models;

use yii\db\ActiveRecord;

// 創建數據模型,對數據庫 Test 進行操作
class Test extends ActiveRecord{

    // 設定表名(如果表名和類名不一致)
    public static function tableName(){
        return 'test';
    }


    public function rules(){
        // 驗證器參考:https://www.yiichina.com/doc/guide/2.0/tutorial-core-validators
        return [
            ['id', 'integer'],
            ['title', 'string', 'length' => [0, 10]]
        ];
    }

}
  • 創建 basic/controllers/TestController.php
<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\Test;    // 加載 model

class TestController extends controller{

    public function actionIndex(){
        // 1. 單表查詢
        // 查詢數據,同時防止 SQL 注入
        $id = '1 or 1=1';
        $sql = "SELECT * FROM test WHERE id = :id";
        $results = Test::findBySql($sql, [':id' => $id])->all();
        // 返回一個數組,數組裏面是 id = 1 的對象

        // id = 1;
        $results = Test::find()->where(['id' => 1])->all();

        // id > 0;
        $results = Test::find()->where(['>', 'id', 0])->all();

        // id >= 1 AND id <= 2
        $results = Test::find()->where(['between', 'id', 1, 2])->all();

        // title like "%title1%"
        $results = Test::find()->where(['like', 'title', 'title1'])->all();

        // 更多 where 方法參考:https://www.yiichina.com/doc/api/2.0/yii-db-queryinterface#where()-detail

        // 對象在內存裏的佔用量比數組高,所以要優化
        // 查詢結果轉化爲數組
        $results = Test::find()->where(['like', 'title', 'title1'])->asArray()->all();

        // 批量查詢
        foreach(Test::find()->asArray()->batch(1) as $tests){
            print_R($tests);
        }

		// 另: createCommand() 查詢
		// $sql = "SELECT * FROM test WHERE id = " . $id;
       	// $results = Yii::$app->db->createCommand($sql)->queryAll();

        // 2. 單表刪除:調用對象 delete() 方法
        $results = Test::find()->where(['id' => 1])->all();
        $results[0]->delete();

        // 刪除條件
        Test::deleteAll('id>:id', [':id' => 0]);
        echo '<pre>';print_R($results);

        // 3. 單表添加數據
        $test = new Test;
        $test->title = 'title4';
        // 調用 model 設置的驗證器
        $test->validate();
        if($test->hasErrors()){
            echo $test->getErrors();
            exit;
        }
        // $test->save();

        // 4. 單表數據修改
        $test = Test::find()->where(['id'=> 3])->one();
        //print_r($test);
        $test->title = 'title33';
        $test->save();

    }
}

4.2 關聯查詢;

  • 創建活動記錄:basic/models/Customer.php
<?php

namespace app\models;

use yii\db\ActiveRecord;

class Customer extends ActiveRecord{
}
  • 創建活動記錄:basic/models/Order.php
<?php

namespace app\models;

use yii\db\ActiveRecord;

class Order extends ActiveRecord{
}
  • 修改 basic/controllers/TestController.php
<?php
// 顧客表 customer:id,name
// 訂單表 order:id,customer_id,price

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\Customer;
use app\models\Order;

class TestController extends controller{

    public function actionIndex(){
		
		// 1. 根據顧客查詢訂單信息
		// 返回的 $customer 爲 Customer 類的實例,是一個對象
		$customer = Customer::find()->where(['name' => 'zhangsan'])->one();
		// customer_id 屬於 order 表,id 屬於 customer 表
		// hasMany() 方法:一個顧客有對個訂單(一對多)
		$orders = $customer->hasMany('app\models\Order', ['customer_id' => 'id'])->asArray()->all();
		print_R($orders);
		
		// 總結:
		// 改進寫法 1:hasMany(Order::className(), []);
		// 改進寫法 2:
		// basic/models/Customer.php 追加方法:幫助顧客獲取訂單信息
	    // public function getOrders(){
	    //     return $this->hasMany(Order::className(), ['customer_id' => 'id'])->asArray();
	    // }
	    // 控制器修改:
	    $orders = $customer->getOrders();
	    // 或者以屬性的方式獲取訂單數據,
	    // 但是沒有在 customer 的活動記錄中定義過 orders 屬性
	    // 原因是在訪問對象裏不存在屬性的時候,會調用 __get() 方法,
	    // 然後去調用 get+屬性的名字() 方法,就是 getOrders() 方法,
	    // 然後在後面會再補上一個 all() 方法
	    $orders = $customer->orders; 


		// 2. 根據訂單查詢顧客的信息(類似上面代碼)
		// basic/models/Order.php 追加方法:
	    // public function getCustomer(){
	    	// hasOne() 方法:因爲一個訂單隻屬於一個顧客(一對一)
	    //    return $this->hasOne(Customer::className(), ['id' => 'customer_id'])->asArray();
	    // }
	    // 控制器寫如下代碼
	    $order = Order::find()->where(['id' => 1])->one();
	    // 調用 getCustomer() 方法後,補上 one() 方法(因爲之前調用 hasOne())
	    $customer = $order->customer;
	    print_R($customer);
    }
}
  • 關於關聯查詢的性能
<?php
// 1. 關聯查詢的結果會被緩存
$customer = Customer::find()->where(['name' => 'zhangsan'])->one();
$orders = $customer->orders; 	// 相當於執行了 SELECT * FROM order WHERE customer_id = 1;
// 如果第二次執行 $orders2 = $customer->orders; 的時候, 就不會去執行上面的 SELECT 語句
// 因爲第一次執行的時候,已經去訪問過數據庫,把數據塞到 orders 裏面
// 第二次執行,直接去 orders 裏拿數據
// 避免緩存的方法:
// unset($customer->orders);

// 2. 關聯查詢的多次查詢
$customers = Customer::find()->all();
foreach($customers as $customer){
	// 每次查詢訂單都會執行 SELECT 語句
	// 假設顧客有 100 個,就會執行 1+100 次 SELECT 語句,影響效率
	// 優化方法如下:
	// $customers = Customer::find()->with('orders')->all();
	// 相當於執行
	// SELECT * FROM customer 和 SELECT * FROM order WHERE customer_id in (...)
	// 查詢出來的結果塞入每一個顧客的 orders 裏
	// 之後 foreach() 的時候就不會執行 SELECT 語句了
	// 原來需要執行 1+100 次 SQL 語句,現在只要執行 1+1 次
	$orders = $customer->orders;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章