《PHP應用:PHP的Yii框架中Model模型的學習教程》要點:
本文介紹了PHP應用:PHP的Yii框架中Model模型的學習教程,希望對您有用。如果有疑問,可以聯系我們。
相關主題:YII框架
模型是 MVC 模式中的一部分, 是代表業務數據、規則和邏輯的對象.PHP學習
模型是 CModel 或其子類的實例.模型用于保持數據以及與其相關的業務邏輯.PHP學習
模型是單獨的數據對象.它可以是數據表中的一行,或者一個用戶輸入的表單. 數據對象的每個字段對應模型中的一個屬性.每個屬性有一個標簽(label), 并且可以通過一系列規則進行驗證.PHP學習
Yii 實現了兩種類型的模型:表單模型和 Active Record.二者均繼承于相同的基類 CModel.PHP學習
表單模型是 CFormModel 的實例.表單模型用于保持從用戶的輸入獲取的數據. 這些數據經常被獲取,使用,然后丟棄.例如,在一個登錄頁面中, 我們可以使用表單模型用于表示由最終用戶提供的用戶名和暗碼信息.PHP學習
Active Record (AR) 是一種用于通過面向對象的風格抽象化數據庫拜訪的設計模式. 每個 AR 對象是一個 CActiveRecord 或其子類的實例.代表數據表中的一行. 行中的字段對應 AR 對象中的屬性.PHP學習
可通過繼承 yii\base\Model 或它的子類定義模型類,基類yii\base\Model支持許多實用的特性:PHP學習
屬性PHP學習
模型通過 屬性 來代表業務數據,每個屬性像是模型的公有可拜訪屬性, yii\base\Model::attributes() 指定模型所擁有的屬性.PHP學習
可像拜訪一個對象屬性一樣拜訪模型的屬性:PHP學習
$model = new \app\models\ContactForm; // "name" 是ContactForm模型的屬性 $model->name = 'example'; echo $model->name;
也可像拜訪數組單元項一樣拜訪屬性,這要感謝yii\base\Model支持 ArrayAccess 數組拜訪 和 ArrayIterator 數組迭代器:PHP學習
$model = new \app\models\ContactForm; // 像拜訪數組單元項一樣拜訪屬性 $model['name'] = 'example'; echo $model['name']; // 迭代器遍歷模型 foreach ($model as $name => $value) { echo "$name: $value\n"; }
定義屬性PHP學習
默認情況下你的模型類直接從yii\base\Model繼承,所有 non-static public非靜態公有 成員變量都是屬性. 例如,下述ContactForm模型類有四個屬性name, email, subject and body, ContactForm 模型用來代表從HTML表單獲取的輸入數據.PHP學習
namespace app\models; use yii\base\Model; class ContactForm extends Model { public $name; public $email; public $subject; public $body; }
另一種方式是可覆蓋 yii\base\Model::attributes() 來定義屬性,該方法返回模型的屬性名. 例如 yii\db\ActiveRecord 返回對應數據表列名作為它的屬性名, 注意可能需要覆蓋魔術方法如__get(), __set()使屬性像普通對象屬性被拜訪.PHP學習
屬性標簽PHP學習
當屬性顯示或獲取輸入時,經常要顯示屬性相關標簽,例如假定一個屬性名為firstName, 在某些地方如表單輸入或錯誤信息處,你可能想顯示對終端用戶來說更友好的 First Name 標簽.PHP學習
可以調用 yii\base\Model::getAttributeLabel() 獲取屬性的標簽,例如:PHP學習
$model = new \app\models\ContactForm; // 顯示為 "Name" echo $model->getAttributeLabel('name');
默認情況下,屬性標簽通過yii\base\Model::generateAttributeLabel()辦法自動從屬性名生成. 它會自動將駝峰式大小寫變量名轉換為多個首字母大寫的單詞,例如 username 轉換為 Username, firstName 轉換為 First Name.PHP學習
如果你不想用自動生成的標簽,可以覆蓋 yii\base\Model::attributeLabels() 辦法明確指定屬性標簽,例如:PHP學習
namespace app\models; use yii\base\Model; class ContactForm extends Model { public $name; public $email; public $subject; public $body; public function attributeLabels() { return [ 'name' => 'Your name', 'email' => 'Your email address', 'subject' => 'Subject', 'body' => 'Content', ]; } }
應用支持多語言的情況下,可翻譯屬性標簽, 可在 yii\base\Model::attributeLabels() 辦法中定義,如下所示:PHP學習
public function attributeLabels() { return [ 'name' => \Yii::t('app', 'Your name'), 'email' => \Yii::t('app', 'Your email address'), 'subject' => \Yii::t('app', 'Subject'), 'body' => \Yii::t('app', 'Content'), ]; }
甚至可以根據條件定義標簽,例如通過使用模型的 scenario場景, 可對相同的屬性返回不同的標簽.PHP學習
補充:屬性標簽是 視圖一部分,但是在模型中申明標簽通常非常方便,并可行程非常簡潔可重用代碼.
場景PHP學習
模型可能在多個 場景 下使用,例如 User 模塊可能會在收集用戶登錄輸入,也可能會在用戶注冊時使用. 在不同的場景下,模型可能會使用不同的業務規則和邏輯,例如 email 屬性在注冊時強制要求有,但在登陸時不需要.PHP學習
模型使用 yii\base\Model::scenario 屬性保持使用場景的跟蹤, 默認情況下,模型支持一個名為 default 的場景,如下展示兩種設置場景的辦法:PHP學習
// 場景作為屬性來設置 $model = new User; $model->scenario = 'login'; // 場景通過構造初始化配置來設置 $model = new User(['scenario' => 'login']);
默認情況下,模型支持的場景由模型中申明的 驗證規則 來決定, 但你可以通過覆蓋yii\base\Model::scenarios()辦法來自定義行為,如下所示:PHP學習
namespace app\models; use yii\db\ActiveRecord; class User extends ActiveRecord { public function scenarios() { return [ 'login' => ['username', 'password'], 'register' => ['username', 'email', 'password'], ]; } }
補充:在上述和下述的例子中,模型類都是繼承yii\db\ActiveRecord, 因為多場景的使用通常發生在Active Record 類中.
scenarios() 辦法返回一個數組,數組的鍵為場景名,值為對應的 active attributes活動屬性. 活動屬性可被 塊賦值 并遵循驗證規則在上述例子中,username 和 password 在login場景中啟用,在 register 場景中, 除了 username and password 外 email也被啟用.PHP學習
scenarios() 辦法默認實現會返回所有yii\base\Model::rules()辦法申明的驗證規則中的場景, 當覆蓋scenarios()時,如果你想在默認場景外使用新場景,可以編寫類似如下代碼:PHP學習
namespace app\models; use yii\db\ActiveRecord; class User extends ActiveRecord { public function scenarios() { $scenarios = parent::scenarios(); $scenarios['login'] = ['username', 'password']; $scenarios['register'] = ['username', 'email', 'password']; return $scenarios; } }
場景特性主要在驗證 和 屬性塊賦值 中使用. 你也可以用于其他目的,例如可基于不同的場景定義不同的 屬性標簽.PHP學習
驗證規則PHP學習
當模型接收到終端用戶輸入的數據,數據應當滿足某種規則(稱為 驗證規則, 也稱為 業務規則). 例如假定ContactForm模型,你可能想確保所有屬性不為空且 email 屬性包含一個有效的郵箱地址, 如果某個屬性的值不滿足對應的業務規則,相應的錯誤信息應顯示,以贊助用戶修正錯誤.PHP學習
可調用 yii\base\Model::validate() 來驗證接收到的數據, 該辦法使用yii\base\Model::rules()申明的驗證規則來驗證每個相關屬性, 如果沒有找到錯誤,會返回 true,否則它會將錯誤保存在 yii\base\Model::errors 屬性中并返回false,例如:PHP學習
$model = new \app\models\ContactForm; // 用戶輸入數據賦值到模型屬性 $model->attributes = \Yii::$app->request->post('ContactForm'); if ($model->validate()) { // 所有輸入數據都有效 all inputs are valid } else { // 驗證失敗:$errors 是一個包含錯誤信息的數組 $errors = $model->errors; }
通過覆蓋 yii\base\Model::rules() 辦法指定模型屬性應該滿足的規則來申明模型相關驗證規則. 下述例子顯示ContactForm模型申明的驗證規則:PHP學習
public function rules() { return [ // name, email, subject 和 body 屬性必須有值 [['name', 'email', 'subject', 'body'], 'required'], // email 屬性必須是一個有效的電子郵箱地址 ['email', 'email'], ]; }
一條規則可用來驗證一個或多個屬性,一個屬性可對應一條或多條規則. 更多關于如何申明驗證規則的詳情請參考 驗證輸入 一節.PHP學習
有時你想一條規則只在某個 場景 下應用,為此你可以指定規則的 on 屬性,如下所示:PHP學習
public function rules() { return [ // 在"register" 場景下 username, email 和 password 必須有值 [['username', 'email', 'password'], 'required', 'on' => 'register'], // 在 "login" 場景下 username 和 password 必須有值 [['username', 'password'], 'required', 'on' => 'login'], ]; }
如果沒有指定 on 屬性,規則會在所有場景下應用, 在當前yii\base\Model::scenario 下應用的規則稱之為 active rule活動規則.PHP學習
一個屬性只會屬于scenarios()中定義的活動屬性且在rules()申明對應一條或多條活動規則的情況下被驗證.PHP學習
塊賦值PHP學習
塊賦值只用一行代碼將用戶所有輸入填充到一個模型,非常方便, 它直接將輸入數據對應填充到 yii\base\Model::attributes 屬性. 以下兩段代碼效果是相同的,都是將終端用戶輸入的表單數據賦值到 ContactForm 模型的屬性, 明顯地前一段塊賦值的代碼比后一段代碼簡潔且不易出錯.PHP學習
$model = new \app\models\ContactForm; $model->attributes = \Yii::$app->request->post('ContactForm'); $model = new \app\models\ContactForm; $data = \Yii::$app->request->post('ContactForm', []); $model->name = isset($data['name']) ? $data['name'] : null; $model->email = isset($data['email']) ? $data['email'] : null; $model->subject = isset($data['subject']) ? $data['subject'] : null; $model->body = isset($data['body']) ? $data['body'] : null;
平安屬性PHP學習
塊賦值只應用在模型當前yii\base\Model::scenario場景yii\base\Model::scenarios()方法 列出的稱之為 平安屬性 的屬性上,例如,如果User模型申明以下場景, 當當前場景為login時候,只有username and password 可被塊賦值,其他屬性不會被賦值.PHP學習
public function scenarios() { return [ 'login' => ['username', 'password'], 'register' => ['username', 'email', 'password'], ]; }
補充: 塊賦值只應用在平安屬性上,因為你想控制哪些屬性會被終端用戶輸入數據所修改, 例如,如果 User 模型有一個permission屬性對應用戶的權限, 你可能只想讓這個屬性在后臺界面被管理員修改.
由于默認yii\base\Model::scenarios()的實現會返回yii\base\Model::rules()所有屬性和數據, 如果不覆蓋這個方法,表示所有只要出現在活動驗證規則中的屬性都是平安的.PHP學習
為此,提供一個特別的別名為 safe 的驗證器來申明哪些屬性是平安的不需要被驗證, 如下示例的規則申明 title 和 description都為平安屬性.PHP學習
public function rules() { return [ [['title', 'description'], 'safe'], ]; }
非平安屬性PHP學習
如上所述,yii\base\Model::scenarios() 方法提供兩個用處:定義哪些屬性應被驗證,定義哪些屬性平安. 在某些情況下,你可能想驗證一個屬性但不想讓他是平安的,可在scenarios()方法中屬性名加一個驚嘆號 !. 例如像如下的secret屬性.PHP學習
public function scenarios() { return [ 'login' => ['username', 'password', '!secret'], ]; }
當模型在 login 場景下,三個屬性都會被驗證,但只有 username和 password 屬性會被塊賦值, 要對secret屬性賦值,必須像如下例子明確對它賦值.PHP學習
$model->secret = $secret;
數據導出PHP學習
模型通常要導出成不同格式,例如,你可能想將模型的一個集合轉成JSON或Excel格式, 導出過程可分解為兩個步驟,第一步,模型轉換成數組;第二步,數組轉換成所需要的格式. 你只需要關注第一步,因為第二步可被通用的數據轉換器如yii\web\JsonResponseFormatter來完成.PHP學習
將模型轉換為數組最簡單的方式是使用 yii\base\Model::attributes 屬性,例如:PHP學習
$post = \app\models\Post::findOne(100); $array = $post->attributes;
yii\base\Model::attributes 屬性會返回 所有 yii\base\Model::attributes() 申明的屬性的值.PHP學習
更靈活和強大的將模型轉換為數組的方式是使用 yii\base\Model::toArray() 辦法, 它的行為默認和 yii\base\Model::attributes 相同, 但是它允許你選擇哪些稱之為字段的數據項放入到結果數組中并同時被格式化. 實際上,它是導出模型到 RESTful 網頁服務開發的默認辦法,詳情請參閱響應格式.PHP學習
字段PHP學習
字段是模型通過調用yii\base\Model::toArray()生成的數組的單元名.PHP學習
默認情況下,字段名對應屬性名,但是你可以通過覆蓋 yii\base\Model::fields() 和/或 yii\base\Model::extraFields() 辦法來改變這種行為, 兩個辦法都返回一個字段定義列表,fields() 辦法定義的字段是默認字段,表示toArray()辦法默認會返回這些字段.extraFields()辦法定義額外可用字段,通過toArray()辦法指定$expand參數來返回這些額外可用字段. 例如如下代碼會返回fields()辦法定義的所有字段和extraFields()辦法定義的prettyName and fullAddress字段.PHP學習
$array = $model->toArray([], ['prettyName', 'fullAddress']);
可通過覆蓋 fields() 來增加、刪除、重命名和重定義字段,fields() 辦法返回值應為數組, 數組的鍵為字段名,數組的值為對應的可為屬性名或匿名函數返回的字段定義對應的值. 特使情況下,如果字段名和屬性定義名相同,可以省略數組鍵,例如:PHP學習
// 明確列出每個字段,特別用于你想確保數據表或模型屬性改變不會導致你的字段改變(保證后端的API兼容). public function fields() { return [ // 字段名和屬性名相同 'id', // 字段名為 "email",對應屬性名為 "email_address" 'email' => 'email_address', // 字段名為 "name", 值通過PHP代碼返回 'name' => function () { return $this->first_name . ' ' . $this->last_name; }, ]; } // 過濾掉一些字段,特別用于你想繼承父類實現并不想用一些敏感字段 public function fields() { $fields = parent::fields(); // 去掉一些包含敏感信息的字段 unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); return $fields; }
警告:由于模型的所有屬性會被包含在導出數組,最好檢查數據確保沒包含敏感數據, 如果有敏感數據,應覆蓋 fields() 辦法過濾掉,在上述列子中,我們選擇過濾掉 auth_key, password_hash and password_reset_token.
最佳實踐PHP學習
模型是代表業務數據、規則和邏輯的中心地方,通常在很多地方重用, 在一個設計良好的應用中,模型通常比控制器代碼多.PHP學習
歸納起來,模型:PHP學習
在開發大型復雜系統時應經常考慮最后一條建議, 在這些系統中,模型會很大并在很多地方使用,因此會包含需要規則集和業務邏輯, 最后維護這些模型代碼成為一個噩夢,因為一個簡單修改會影響好多地方, 為確保模型好維護,最好使用以下策略:PHP學習
定義可被多個 應用主體 或 模塊 共享的模型基類集合. 這些模型類應包括通用的最小規則集合和邏輯.
在每個使用模型的 應用主體 或 模塊中, 通過繼承對應的模型基類來定義具體的模型類,具體模型類包括應用主體或模塊指定的規則和邏輯.
例如,在高級應用模板,你可以定義一個模型基類common\models\Post, 然后在前臺應用中,定義并使用一個繼承common\models\Post的具體模型類frontend\models\Post, 在后臺應用中可以類似地定義backend\models\Post. 通過這種策略,你清楚frontend\models\Post只對應前臺應用,如果你修改它,就無需擔憂修改會影響后臺應用.PHP學習
歡迎參與《PHP應用:PHP的Yii框架中Model模型的學習教程》討論,分享您的想法,維易PHP學院為您提供專業教程。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/7207.html