Yii2 結構指引

pardon110發表於2019-07-20

概述

同laravel一樣,yii應用也有兩個入口,分別是 web 基礎應用 和console 控制檯應用

  • 入口指令碼

    • 定義全域性常量
    • 註冊 Composer 自動載入器
    • 包含 Yii 類檔案
    • 載入應用配置
    • 建立一個應用例項並配置
    • 呼叫 yii\base\Application::run($config) 來處理請求
  • 應用主體

    • 例項化 (new yii\web\Application($config))->run()
    • 屬性
      • 必要屬性 id, basePath
      • 重要屬性 aliases,bootstrap
        • 可將模組ID加入到 bootstrap 陣列中
        • bootsrap 屬性中每個元件需要指定以下一項
          • 應用 元件 ID
          • 模組 ID
          • 類名
          • 配置陣列
          • 建立並返回一個元件的無名稱函式
        • catchAll屬性 僅 Web applications 網頁應用支援
          • 指定一個要處理所有使用者請求的 控制器方法, 通常在維護模式下使用,同一個方法處理所有使用者請求

            如果模組 ID 和應用元件 ID 同名,優先使用應用元件 ID 在啟動階段,每個元件都會例項化。如果元件類實現介面 yii\base\BootstrapInterface,也會呼叫 bootstrap() 方法

  • 應用元件components配置

    • 每一個應用元件指定一個key-value對的陣列,key代表元件ID, value代表元件類名或 配置
    • 應用中註冊的元件,可以通過表示式 \Yii::$app->ComponentID 全域性訪問
  • 屬性 controllerMap

    • 指定一個控制器 ID 到任意控制器類
    • 陣列的鍵代表控制器ID, 陣列的值代表對應的類名
  • 屬性controllerNamespace

    • 該屬性指定控制器類預設的名稱空間,預設為 app\controllers
  • 屬性 modules,鍵為模組id

  • languagename,全域性可訪問的引數 params

  • sourceLanguage, timeZone 語言,時區

  • 實用屬性

    • charset 應用使用的字符集
    • defaultRoute 該屬性指定未配置的請求的響應 路由 規則,可能包含模組 ID,控制器 ID,動作 ID
    • extensions 該屬性用陣列列表指定應用安裝和使用的 擴充套件, 預設使用 @vendor/yiisoft/extensions.php 檔案返回的陣列
    • layout,layoutPath,runtimePath,viewPath,vendorPath,enableCoreCommands

應用事件

  • 應用在處理請求過程中會觸發的事件
    • on eventName 語法配置事件處理程式碼
  • 事件
    • EVENT_BEFORE_REQUEST
    • EVENT_AFTER_REQUEST
    • EVENT_BEFORE_ACTION
    • EVENT_AFTER_ACTION
  • 流程
    • 應用主體物件觸發 beforeAction 事件 --> 模組觸發 --> 控制器觸發
    • 注意 模組 和 控制器 都會觸發 afterAction 事件。 這些物件的觸發順序和 beforeAction 相反

任何一個事件處理中設定 yii\base\ActionEvent::$isValid 設定為 false 會停止觸發後面的事件

應用元件

  • 應用主體是服務定位器, 它部署一組提供各種不同功能的 應用元件 來處理請求
  • 訪問已註冊到應用上的元件例項 \Yii::$app->componentID
  • 應用元件在 應用主體配置 yii\base\Application::$components 屬性

應用元件就像全域性變數,謹慎註冊太多應用元件 一個應用元件只會在第一次訪問時例項化, 如果處理請求過程沒有訪問的話就不例項化

  • 可以使用閉包來引導啟動自定義的元件
  • 核心應用元件(類似laravel中的應用啟動陣列)
    • request 元件 用來收集使用者請求並解析 路由
    • db 代表一個可以執行資料庫操作的資料庫連線
    • assetManager 管理資源包和資源釋出
    • errorHandler: 處理 PHP 錯誤和異常
    • formatter: 格式化輸出顯示給終端使用者的資料
    • i18n: 支援資訊翻譯和格式化
    • log: 管理日誌物件
    • yii\swiftmailer\Mailer 支援生成郵件結構併傳送
    • response: 代表傳送給使用者的響應
    • session: 代表會話資訊
    • urlManager: 支援URL地址解析和建立
    • user: 代表認證登入使用者資訊,僅在Web applications 網頁應用中可用
    • view: 支援渲染檢視

控制器

  • 繼承 yii\base\Controller 類的物件,負責處理請求和生成響應
  • 動作
    • 控制器由 操作 組成,它是執行終端使用者請求的最基礎的單元, 一個控制器可有一個或多個操作
  • 路由
    • 終端使用者通過所謂的路由尋找到動作
    • 模組ID: 僅存在於控制器屬於非應用的模組
    • 控制器ID: 同應用(或同模組如果為模組下的控制)
    • 操作ID: 同控制器下唯一標識操作的字串
  • 建立
    • 控制器應繼承yii\web\Controller 或它的子類
    • 繼承 yii\console\Controller 或它的子類
    • 控制器ID 應僅包含英文小寫字母、數字、下劃線、中橫槓和正斜槓
  • 控制器佈署
    • 通過配置 controller map 來強制上述的控制器ID和類名對應,
    • 應用場景 在使用第三方不能掌控類名的控制器上
  • 建立動作
    • 內聯操作 無需重用的情況下優先使用
    • 獨立操作 繼承 yii\base\Action 或它的子類的類
      • 主要用於多個控制器重用,或重構為擴充套件
      • 應用場景如 yii\web\ViewAction , yii\web\ErrorAction

要使用獨立操作,需要通過控制器中覆蓋 yii\base\Controller::actions() 方法在action map中申明 建立的獨立操作類,必須實現公有的名稱為 run() 的方法,與操作方法類似

  • 動作結果
    • 返回值可為 響應 物件,作為響應傳送給終端使用者
    • 對於 Web applications 網頁應用,返回值可為任意資料, 它賦值給yii\web\Response::$data
    • 對於 console applications 控制檯應用,返回值可為整數, 表示命令列下執行的 exit status 退出狀態
  • 動作引數,對於Web applications 網頁應用, 每個動作引數的值從$_GET中獲得,引數名作為鍵
  • 預設動作
    • 當路由 只包含控制器ID, 會使用所請求的控制器的預設操作
    • 由控制器中的 $defaultAction 指定預設動作
  • 控制器生命週期
    • 應用主體 --> 請求路由 --> 建立控制器
      1. 控制器 init() 方法被呼叫
      2. 建立操作物件
        • 未提供ID,使用default action ID 預設操作ID
        • 在 action map(控制器actions方法) 找到操作ID, 會建立一個獨立操作
        • 操作ID對應操作方法,會建立一個內聯操作
        • 否則會丟擲 yii\base\InvalidRouteException 異常
      3. 控制器按順序呼叫應用主體、模組(如果控制器屬於模組)、 控制器的 beforeAction() 方法
        • 任意一個呼叫返回false,後面未呼叫的 beforeAction() 會跳過並且操作執行會被取消
        • 預設情況下每個 beforeAction() 方法會觸發一個 beforeAction 事件
      4. 控制器執行操作
      5. 控制器按順序呼叫控制器、模組(如果控制器屬於模組)、應用主體的 afterAction() 方法
      6. 應用主體獲取操作結果並賦值給響應
  • 小結
    • 訪問請求資料
    • 根據請求資料呼叫模型方法和其他服務元件
    • 使用檢視構造響應
    • 不應處理被模型處理的請求資料
    • 應避免嵌入html或其他程式碼,這些程式碼最好在檢視中處理

模型類

  • 代表業務資料,規則和邏輯的物件
  • yii\base\Model 類特性
    • 屬性
      • 定義 覆蓋 attriutes()指定模型所擁有的屬性 或定義非靜態公有成員變數
      • 實現了ArrayAccess 陣列訪問, ArrayIterator 陣列迭代器
    • 屬性標籤
      • $model->getAttributeLabel('name')
      • 通過使用模型的 scenario場景, 可對相同的屬性返回不同的標籤
    • 塊賦值
    • 驗證規則
    • 資料匯出
  • 場景
    • 在不同的場景下, 模型可能會使用不同的業務規則和邏輯
    • 例如 email 屬性在註冊時強制要求有,但在登陸時不需要
    • 使用 yii\base\Model::$scenario 屬性保持使用場景的跟蹤
    • 可以通過覆蓋 yii\base\Model::scenarios() 方法來自定義行為
    • 場景特性主要在驗證 和 屬性塊賦值 中使用
  • 驗證規則
    • 呼叫 yii\base\Model::validate() 來驗證接收到的資料
    • 使用 yii\base\Model::rules() 申明的驗證規則
    • 使用 yii\base\Model::$errors 屬性儲存錯誤
  • 非安全屬性驗證
    • 在 scenarios() 方法中屬性名加一個驚歎號 !
    • 應用場景 在某些情況下,可能想驗證一個屬性但不想讓他是安全
  • 資料匯出
    • 模型轉換成陣列 yii\base\Model::attributes()
    • 陣列轉換成需要的格式
      • 通常使用 資料轉換器如 yii\web\JsonResponseFormatter
      • 更靈活和強大的將模型轉換為陣列的方式是使用 yii\base\Model::toArray() 方法
  • 欄位
    • 可以通過覆蓋 fields() 和/或 extraFields() 方法來改變這種行為
    • fields() 方法定義的欄位是預設欄位, 表示 toArray() 方法預設會返回這些欄位
    • 應用場景 通常使用覆蓋 fields() 方法過濾掉 一些包含敏感資訊的欄位
  • 實踐
    • 模型是代表業務資料、規則和邏輯的中心地方,通常在很多地方重用
    • 不應直接訪問請求,session和其他環境資料, 這些資料應該由控制器傳入到模型
    • 單個模型中避免太多的 場景
      • 常用策略 定義可被多個 應用主體 或 模組 共享的模型基類集合。 這些模型類應包含通用的最小規則集合和邏輯
      • 通過繼承對應的模型基類來定義具體的模型類,具體模型類包含應用主體或模組指定的規則和邏輯

檢視

  • 檢視模板為PHP指令碼檔案, 主要包含HTML程式碼和展示類PHP程式碼,通過view應用元件來管理渲染檢視
  • 組織檢視
    • 控制器渲染的檢視檔案預設放在 @app/views/ControllerID 目錄下
    • 對於 小部件 渲染的檢視檔案預設放在 WidgetPath/views 目錄
    • 可覆蓋控制器或小部件的 yii\base\ViewContextInterface::getViewPath() 方法來自定義檢視檔案預設目錄
  • 控制器中渲染
    • render(): 渲染一個 檢視名 並使用一個 佈局 返回到渲染結果
    • renderPartial(): 渲染一個 檢視名 並且不使用佈局
    • renderAjax(): 渲染一個 檢視名 並且不使用佈局
    • renderFile(): 渲染一個檢視檔案目錄或 別名下的檢視檔案
  • 小部件中渲染
    • render(): 渲染一個 檢視名.
    • renderFile(): 渲染一個檢視檔案目錄或 別名下的檢視檔案
  • 檢視中渲染
    • 呼叫view component檢視元件提供的以下方法
    • render(): 渲染一個 檢視名
    • renderAjax(): 渲染一個 檢視名 並注入所有註冊的JS/CSS指令碼和檔案
  • 其他地方渲染
    • Yii::$app->view 訪問 view 應用元件
  • 檢視名規則
    • 可省略副檔名
    • 以雙斜槓 // 開頭,對應的檢視檔案路徑為 @app/views/ViewName
    • 檢視名以單斜槓/開始,檢視檔案路徑以當前使用模組 的 view path 開始
  • 檢視中訪問資料
    • 推送方式 是通過檢視渲染方法的第二個引數傳遞資料,據格式應為名稱-值的陣列
    • 拉取方式 可讓檢視從view component檢視元件或其他物件中主動獲得資料(如Yii::app), app),‘this->context->id
    • view component 檢視元件提供 params 引數屬性來讓不同檢視共享資料
    • 佈局中訪問資料,可使用兩個預定義變數 $this 和 $content
      • 前者對應和普通檢視類似的view 檢視元件 後者包含呼叫render()方法渲染內容檢視的結果
  • 檢視事件

模組化

  • 建立模組
    • 存在一個模組類檔案,該檔案所在目錄稱之為 base_path
    • 每個模組都有一個繼承 yii\base\Module 的模組類,該類可被自動載入
      • 應用主體例項 類似會建立該模組類唯一例項,模組例項用來幫模組內程式碼共享資料和元件
      • 通常模組塊類 init() 方法包含很多初始化模組屬性程式碼
  • 引導啟動模組
    • 模組加入到應用主體的 bootstrap 屬性中
    • 配置 modules項,值為陣列,鍵為模組名,值模組類
  • 模組巢狀
    • 子模組必須在父模組 modules 屬性中申明
    • 模組在大型專案中常備使用,這些專案的特性可分組

過濾器

  • 除了控制器外,可在 模組或應用主體 中申明過濾器

在模組或應用主體中申明過濾器,在only 和 except 屬性中使用路由 代替動作 ID, 因在模組或應用主體中只用動作ID並不能唯一指定到具體動作

  • 過濾器是 控制器動作 執行之前或之後執行的物件

  • 應用場景 許可權驗證,內容壓縮過濾器可在動作執行之後發給終端使用者之前壓縮響應內容

  • 使用

    • 過濾器 本質上是一類特殊的行為,可在控制器的 behaviors() 方法來宣告過濾器
    • 控制器類的過濾器預設應用到該類的 所有 動作, only屬性則明確指定
  • 多個過濾器執行規則

    • 預過濾
      • 執行應用主體 --> 模組級別 --> 控制器 --> 若過濾器終止後續不再執行
    • 成功通過預過濾器則進入執行動作
    • 後過濾 倒序執行控制器過濾器--> 倒序模組中 --> 倒序執行應用主體中 behaviors() 列出的過濾器
  • 建立過濾器

    • 若返回值為 false 則之後的過濾器和動作不會執行
    • 繼承 yii\base\ActionFilter 類並覆蓋 beforeAction() 或 afterAction() 方法來建立動作的過濾器
  • 核心過濾器(類似於java的概念,laravel中的是中介軟體)

    • Yii 核心過濾器在 yii\filters 名稱空間下
    • AccessControl 提供基於 rules 規則的訪問控制
      • 決定允許還是拒絕請求動作的執行,若無答合的規則,則訪問被拒絕
      • 應用場景 比如使用者 IP 地址、登入狀態等等)的規則,
    • 認證方法過濾器
      • 認證方法過濾器類在 yii\filters\auth 名稱空間下
      • 認證方法過濾器通過 HTTP Basic Auth 或 OAuth 2 來認證一個使用者
      • 如 yii\filters\auth\HttpBasicAuth 來認證一個使用者
        • user identity class 類必須 實現 findIdentityByAccessToken() 方法
      • ContentNegotiator 支援響應內容格式處理和語言處理
        • 通過 GET 引數和 Accept HTTP 頭部來決定響應內容格式和語言
        • 亦可在應用主體上配置。
        • 如果請求中沒有檢測到內容格式和語言, 使用 formats 和 languages 第一個配置項
    • HttpCache 利用 Last-Modified 和 Etag HTTP 頭實現客戶端快取
    • PageCache 實現伺服器端整個頁面的快取
    • RateLimiter 根據 漏桶演算法 來實現速率限制,主要用在實現 RESTful APIs
    • VerbFilter 檢查請求動作的 HTTP 請求方式是否允許執行, 如果不允許,會丟擲 HTTP 405異常
    • Cors filter 應在授權/認證過濾器之前定義, 以保證 CORS 頭部被髮送
    • 若要將CORS過濾器新增到 API 中的 yii\rest\ActiveController 類, 還要檢查 REST Controllers 中的部分

小部件Widgets

  • 在檢視中使用的可重用單元, 使用物件導向方式建立複雜和可配置使用者介面單元
  • Yii提供許多優秀的小部件
    • 比如 active form,menu, jQuery UI widgets, Twitter Bootstrap widgets
  • 使用
    • 在檢視中可呼叫 yii\base\Widget::widget() 方法使用小部件
    • 小部件會在 begin() 和 end() 執行處分別起止標籤

呼叫 yii\base\Widget::end() 的時候,一些小部件將使用 輸出緩衝 來調整封閉的內容

  • 小部件的全域性預設值可以通過 DI 容器配置, 如 \Yii::$container->set(xx,yy)
  • 建立小部件
    1. widget() 方法
      • 繼承 yii\base\Widget 類,覆蓋 init() 或 run() 方法
      • 前者屬性賦值,後者返回小部件生成渲染結果的程式碼,通常大段程式碼採用 render 方法
    2. begin() 和 end() 方法
      • PHP 輸出緩衝 ob_start() 在 init() 啟動
      • 所有在 init() 和 run() 方法之間的輸出內容都會被獲取,並在 run() 處理和返回
  • 流程
    • begin 時會建立 一個新的小部件例項,並在構造結構時呼叫init 方法
    • 在 end 方法時,會呼叫 run 方法並輸出結果
  • 小結
    • 通常邏輯程式碼在小部件類,展示內容在檢視中
    • 小部件設計是獨立的,丟棄它不需要額外的處理
    • 小部件是可以重用的類,檢視只是應用中使用的普通PHP指令碼

前端資源(Assets)

  • Yii 中的資源是和 Web 頁面相關的檔案,通常放在 web 可訪問的目錄下,直接被 Web 伺服器呼叫

  • 在檢視中註冊一個資源包, 在渲染 Web 頁面時會包含包中的 CSS 和 JavaScript 檔案

  • 定義資源包

    • 資源包 放在一個目錄下的資源集合
    • 資源包指定為繼承 yii\web\AssetBundle 的 PHP 類, 包名為可自動載入的 PHP 類名
    • 在資源包類中,要指定資源所在位置,包含的檔案,以及其他包的依賴關係
  • 資源位置

    • 源資源,釋出資源,外部資源
    • 推薦 指定 basePath 而不是 sourcePath
  • 資源依賴 通過 $depends 屬性來指定

  • 資源選項

    • 可指定 cssOptions 和 jsOptions 屬性來自定義頁面包含 CSS 和 JavaScript 檔案的方式,
    • 這些屬性值會分別傳遞給 yii\web\View::registerCssFile() 和 yii\web\View::registerJsFile() 方法
    • 預設情況下,當釋出資源包時,所有在 yii\web\AssetBundle::$sourcePath 目錄裡的內容都會發布
  • 使用資源包

    • 在檢視中呼叫 yii\web\AssetBundle::register() 方法註冊資源
    • 在檢視模板可使用如下程式碼註冊資源包
      • use app\assets\AppAsset;AppAsset::register($this);
      • 在其他地方註冊資源包,應提供檢視對,如在小部件類中註冊資源包, 可以通過 $this->view 獲取檢視物件
  • 動態資源包

    • 應用場景 語言本地化覆蓋 yii\web\AssetBundle::init() 方法來實現
    • 特定資源包 通過 yii\web\AssetBundle::register() 返回的例項進行調整
  • 自定義資源包 assetManager

    • Yii 通過配置名為 assetManager 的應用元件來使用 yii\web\AssetManager, 配置 $bundles屬性自定義資源包行為
    • 在應用配置中配置 assetManager設定cdn資源, sourcePath則一定不要釋出該資源
    • 資源包元件-->管理器-->bundles-->資源包類名-->對應的配置陣列
    • 在 yii\web\AssetBundle::init() 方法內或在註冊的資源包物件上進行的調整優先於 AssetManager 配置
  • 資源對映 “修復”多個資源包中資原始檔的錯誤或者不相容 $assetMap 屬性

  • 釋出資源 assetManager

    • 可 basePath 和 baseUrl 屬性自定義釋出位置
    • 可使用符號連結(若系統允許)'linkAssets' => true,
    • 資源包放在 Web 不能訪問的目錄, 當檢視註冊資源時資源會被拷貝到一個 Web 可訪問的目錄中
  • 清除快取 'appendTimestamp' => true

  • 常用資源包

    • yii\web\YiiAsset 包含 yii.js 檔案
    • yii\web\JqueryAsset 包含 jQuery Bower 包的 jquery.js 檔案
    • yii\bootstrap\BootstrapAsset 包含 Twitter Bootstrap 框架的 CSS 檔案
    • yii\bootstrap\BootstrapPluginAsset JavaScript 檔案
    • yii\jui\JuiAsset 包含 jQuery UI 庫的 CSS 和 JavaScript 檔案
  • 資源轉換

    • yii\web\AssetManager::$converter 自定義預處理命令和支援的擴充套件語法
    • yii\web\AssetConverter::$commands 屬性指定支援的擴充套件語法
  • 合併和壓縮

    • asset manager 資源管理器
    • asset 命令 自動處理資源包命令(生成相應配置檔案)
      • yii asset/template assets.php
      • jsCompressor 和 cssCompressor定控制檯命令或PHP回撥函式來處理合並和壓縮
    • 資源包分組
      • 指出輸出的bundles包分組, allShared,allBackEnd,allFrontEnd

擴充套件

  • 類的自舉引導
    • bootstrapping class (自舉類)實現 yii\base\BootstrapInterface 介面
    • 實現 bootstrap 方法,接收主體應用引數, 置於 myname\mywidget名稱空間之下
    • 應用場景 擴充套件可響應應用的 beginRequest 事件,做一些環境的設定工作
    • 將自舉類在 composer.json 檔案中列出來,每一個請求的自舉過程中,自動例項化自舉類並呼叫其 bootstrap() 方法
  • 運算元據庫
    • 在需要訪問資料庫的類中申明一個 db 屬性,該屬性擴充套件使用哪個DB連線
    • 提供 資料遷移 來運算元據庫的結構修改,而不是使用SQL文字檔案
    • 儘量使遷移檔案適用於不同的 DBMS
    • 在遷移檔案中避免使用 Active Record
  • 使用Assets
    • 手動這些 asset 檔案拷貝到特定的 Web 可以讀取的資料夾
    • 申明一個 asset bundle 並依靠 asset 釋出機制自動將這些檔案
  • 國際化和本地化
    • 擴充套件為終端使用者顯示資訊,這些資訊應該用 Yii::t() 包裝起來,以便可以進行翻譯
    • 若擴充套件顯示數字、日期等,用 yii\i18n\Formatter 中適當的格式化規則做格式化