Yii模型

模型代表业务逻辑和规则的对象。要创建一个模型,应该扩展 yii\base\Model类或它的子类。

属性

属性代表业务数据。它们可以像数组元素或对象的属性那样来访问。一个模型的每个属性都是公开访问的属性。要指定模型拥有什么属性,应该重写yii\base\Model::attributes() 方法。

我们看一下基本应用程序模板中的 ContactForm 模型。
<?php
   namespace app\models;
   use Yii;
   use yii\base\Model;
   /**
   * ContactForm is the model behind the contact form.
   */
   class ContactForm extends Model {
      public $name;
      public $email;
      public $subject;
      public $body;
      public $verifyCode;
      /**
      * @return array the validation rules.
      */
      public function rules() {
         return [
            // name, email, subject and body are required
            [['name', 'email', 'subject', 'body'], 'required'],
            // email has to be a valid email address
            ['email', 'email'],
            // verifyCode needs to be entered correctly
            ['verifyCode', 'captcha'],
         ];
      }
      /**
      * @return array customized attribute labels
      */
      public function attributeLabels() {
         return [
            'verifyCode' => 'Verification Code',
         ];
      }
      /**
      * Sends an email to the specified email address using the information 
         collected by this model.
      * @param  string  $email the target email address
      * @return boolean whether the model passes validation
      */
      public function contact($email) {
         if ($this->validate()) {
            Yii::$app->mailer->compose()
               ->setTo($email)
               ->setFrom([$this->email => $this->name])
               ->setSubject($this->subject)
               ->setTextBody($this->body)
               ->send();
            return true;
         }
         return false;
      }
   }
?>
第1步 - 在 SiteController中创建一个 actionShowContactModel 函数并使用下面的代码。
public function actionShowContactModel() { 
   $mContactForm = new \app\models\ContactForm(); 
   $mContactForm->name = "contactForm"; 
   $mContactForm->email = "user@gmail.com"; 
   $mContactForm->subject = "标题"; 
   $mContactForm->body = "内容主体"; 
   var_dump($mContactForm); 
}
在上面的代码中,我们定义 ContactForm 表单模型,设置属性,并在屏幕上显示模型。
第2步 - 现在,如果在Web浏览器的地址栏中输入URL:http://localhost:8080/index.php?r=site/show-contact-model ,应该会看到以下内容。
Yii模型

如模型是从 yii\base\Model 扩展,那么它的所有成员变量应该为公共且是非静态的属性。在 ContactForm 模型五个属性 - name, email, subject, body, verifyCode,也可以再添加一些新的。

属性标签

在应用中我们经常需要使用属性相关联来显示标签。默认情况下,属性标签由 yii\base\Model::generateAttributeLabel() 方法自动生成。要手动声明属性标签,可以覆盖yii\base\Model::attributeLabels() 方法。

第1步 - 如果在浏览器中打开URL: http://localhost:8080/index.php?r=site/contact,将看到以下页面。

注意,标签的名称与属性的名称相同。
步骤2 - 现在,中以下列方式修改在 ContactForm 模型中的 attributeLabels() 函数。
public function attributeLabels() {
   return [
      'name' => '名字',
      'email' => '邮箱地址',
      'subject' => '标题',
      'body' => '内容',
      'verifyCode' => '验证码',
   ];
}
第3步 - 如果再次打开URL:http://localhost:8080/index.php?r=site/contact,你会发现,标签已经改变如下面图片所示。

模型使用在不同的场景

可以使用模型在不同的场景。 例如,当一个访问用户要发送一份联系表单,我们需要所有的模型属性。 当用户已经登录,我们并不需要他的名字,因为我们可以很容易地从数据库把它读取出来。

要声明场景,应该覆盖 scenarios() 函数。它返回一个数组,其键是场景名称而其值是 Active 属性。Active属性是用来来验证的。它们也可以被大量分配。

第1步 - 以下方式修改 ContactForm 模型。
<?php
   namespace app\models;
   use Yii;
   use yii\base\Model;
   /**
   * ContactForm is the model behind the contact form.
   */
   class ContactForm extends Model {
      public $name;
      public $email;
      public $subject;
      public $body;
      public $verifyCode;
      const SCENARIO_EMAIL_FROM_GUEST = 'EMAIL_FROM_GUEST';
      const SCENARIO_EMAIL_FROM_USER = 'EMAIL_FROM_USER';
      public function scenarios() {
         return [
            self::SCENARIO_EMAIL_FROM_GUEST => ['name', 'email', 'subject', 
               'body', 'verifyCode'],
            self::SCENARIO_EMAIL_FROM_USER => ['email' ,'subject', 'body', 
               'verifyCode'],
         ];
      }
      /**
      * @return array the validation rules.
      */
      public function rules() {
         return [
            // name, email, subject and body are required
            [['name', 'email', 'subject', 'body'], 'required'],
            // email has to be a valid email address
            ['email', 'email'],
            // verifyCode needs to be entered correctly
            ['verifyCode', 'captcha'],
         ];
      }
      /**
      * @return array customized attribute labels
      */
      public function attributeLabels() {
         return [
            'name' => '名字',
            'email' => '电子邮箱',
            'subject' => '标题',
            'body' => '内容',
            'verifyCode' => '验证码',
         ];
      }
      /**
      * Sends an email to the specified email address using the information 
         collected by this model.
      * @param  string  $email the target email address
      * @return boolean whether the model passes validation
      */
      public function contact($email) {
         if ($this -> validate()) {
            Yii::$app->mailer->compose()
               ->setTo($email)
               ->setFrom([$this->email => $this->name]) 
               ->setSubject($this->subject) 
               ->setTextBody($this->body)
               ->send();
            return true;
         }
         return false;
      }
   }
?> 

我们增加了两个场景。一个用于访问游客用户,另一个用于身份验证的用户。当用户通过验证后,再不需要他填入名字。

第2步- 现在,修改 SiteController 的 actionContact 功能。
public function actionContact() {
   $model = new ContactForm();
   $model->scenario = ContactForm::SCENARIO_EMAIL_FROM_GUEST;
   if ($model->load(Yii::$app->request->post()) && $model->
      contact(Yii::$app->params ['adminEmail'])) {
         Yii::$app->session->setFlash('contactFormSubmitted');  
         return $this->refresh();
   }
   return $this->render('contact', [
      'model' => $model,
   ]);
} 

第3步 - 在浏览器访问URL => http://localhost:8080/index.php?r=site/contact 。你应该已经注意到,当前所有模型的属性都是必须的。

第4步 - 如果你在模式的 actionContact 动作中更改了场景。如下面给出的代码,你会发现 name 属性不再是必需的。
$model->scenario = ContactForm::SCENARIO_EMAIL_FROM_USER;

大量的分配

大规模的分配是通过一个单一的代码行创建多个输入模型属性的一种便捷方式。
如下的代码行 -
$mContactForm = new \app\models\ContactForm; 
$mContactForm->attributes = \Yii::$app->request->post('ContactForm');
上面给出的代码行相当于-
$mContactForm = new \app\models\ContactForm; 
$postData = \Yii::$app->request->post('ContactForm', []); 
$mContactForm->name = isset($postData['name']) ? $postData['name'] : null; 
$mContactForm->email = isset($postData['email']) ? $postData['email'] : null; 
$mContactForm->subject = isset($postData['subject']) ? $postData['subject'] : null; 
$mContactForm->body = isset($postData['body']) ? $postData['body'] : null; 

前者干净多了。注意,大量分配仅适用于安全属性。它们只是在 scenario() 函数中列出当前场景属性。

数据导出

模型往往需要以不同的格式导出。要转模型转换为数组,则修改 SiteController 的 actionShowContactModel() 函数-

public function actionShowContactModel() {
   $mContactForm = new \app\models\ContactForm();
   $mContactForm->name = "用户名称";
   $mContactForm->email = "user@gmail.com";
   $mContactForm->subject = "标题";
   $mContactForm->body = "内容";
   var_dump($mContactForm->attributes);
} 
在浏览器地址栏中输入URL:http://localhost:8080/index.php?r=site/show-contact-model,你会看到如下结果 -

要将模型转换成JSON格式,修改actionShowContactModel()函数如以下方式-
public function actionShowContactModel() {
   $mContactForm = new \app\models\ContactForm();
   $mContactForm->name = "username";
   $mContactForm->email = "user@gmail.com";
   $mContactForm->subject = "subject";
   $mContactForm->body = "body-content";
   return \yii\helpers\Json::encode($mContactForm);
}
浏览器输出 -

要点

模型通常是一个精心设计比控制器快得多的应用。模型应该-
  • 包含业务逻辑
  • 包含验证规则
  • 包含属性
  • 不嵌入HTML
  • 不能直接访问请求
  • 不要有太多的场景

上一篇: Yii使用动作 下一篇: Yii小部件(Widget)