Yii - Modelos

Los modelos son objetos que representan reglas y lógica empresarial. Para crear un modelo, debe extender elyii\base\Model clase o sus subclases.

Atributos

Los atributos representan los datos comerciales. Se puede acceder a ellos como elementos de matriz o propiedades de objeto. Cada atributo es una propiedad de acceso público de un modelo. Para especificar qué atributos posee un modelo, debe anular elyii\base\Model::attributes() método.

Echemos un vistazo al ContactForm modelo de la plantilla de aplicación básica.

<?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;
      }
   }
?>

Step 1 - Crea una función llamada actionShowContactModel en el SiteController con el siguiente código.

public function actionShowContactModel() { 
   $mContactForm = new \app\models\ContactForm(); 
   $mContactForm->name = "contactForm"; 
   $mContactForm->email = "[email protected]"; 
   $mContactForm->subject = "subject"; 
   $mContactForm->body = "body"; 
   var_dump($mContactForm); 
}

En el código anterior, definimos el ContactForm modelar, establecer atributos y mostrar el modelo en la pantalla.

Step 2 - Ahora, si escribe http://localhost:8080/index.php?r=site/show-contact-model en la barra de direcciones del navegador web, verá lo siguiente.

Si su modelo se extiende desde yii\base\Model, entonces todas sus variables miembro (públicas y no estáticas) son atributos. Hay cinco atributos en elContactForm modelo: nombre, correo electrónico, asunto, cuerpo, verifyCode y puede agregar fácilmente nuevos.

Etiquetas de atributo

A menudo es necesario mostrar etiquetas asociadas con atributos. De forma predeterminada, las etiquetas de atributo las generayii\base\Model::generateAttributeLabel()método. Para declarar etiquetas de atributo manualmente, puede anular layii\base\Model::attributeLabels() método.

Step 1 - Si abres http://localhost:8080/index.php?r=site/contact, verá la siguiente página.

Tenga en cuenta que las etiquetas de atributo son las mismas que sus nombres.

Step 2 - Ahora, modifique el attributeLabels función en el ContactForm modelo de la siguiente manera.

public function attributeLabels() {
   return [
      'name' => 'name overridden',
      'email' => 'email overridden',
      'subject' => 'subject overridden',
      'body' => 'body overridden',
      'verifyCode' => 'verifyCode overridden',
   ];
}

Step 3 - Si abres http://localhost:8080/index.php?r=site/contact nuevamente, notará que las etiquetas han cambiado como se muestra en la siguiente imagen.

Escenarios

Puede utilizar un modelo en diferentes escenarios. Por ejemplo, cuando un invitado quiere enviar un formulario de contacto, necesitamos todos los atributos del modelo. Cuando un usuario quiere hacer lo mismo, ya está conectado, por lo que no necesitamos su nombre, ya que podemos tomarlo fácilmente de la base de datos.

Para declarar escenarios, debemos anular el scenarios()función. Devuelve una matriz cuyas claves son los nombres de los escenarios y los valores sonactive attributes. Los atributos activos son los que se deben validar. También pueden sermassively assigned.

Step 1 - Modificar el ContactForm modelo de la siguiente manera.

<?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' => 'name overridden',
            'email' => 'email overridden',
            'subject' => 'subject overridden',
            'body' => 'body overridden',
            'verifyCode' => 'verifyCode overridden',
         ];
      }
      /**
      * 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;
      }
   }
?>

Hemos agregado dos escenarios. Uno para el invitado y otro para el usuario autenticado. Cuando el usuario está autenticado, no necesitamos su nombre.

Step 2 - Ahora, modifique el actionContact función de la SiteController.

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,
   ]);
}

Step 3 - Tipo http://localhost:8080/index.php?r=site/contacten el navegador web. Notará que actualmente, todos los atributos del modelo son obligatorios.

Step 4 - Si cambia el escenario del modelo en el actionContact, como se indica en el siguiente código, encontrará que el atributo de nombre ya no es necesario.

$model->scenario = ContactForm::SCENARIO_EMAIL_FROM_USER;

Asignación masiva

La asignación masiva es una forma conveniente de crear un modelo a partir de múltiples atributos de entrada a través de una sola línea de código.

Las líneas de código son:

$mContactForm = new \app\models\ContactForm; 
$mContactForm->attributes = \Yii::$app->request->post('ContactForm');

Las líneas de código dadas anteriormente son equivalentes a:

$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;

El primero es mucho más limpio. Darse cuenta demassive assignment solo se aplica a safe attributes. Son solo los atributos del escenario actual enumerados en elscenario() función.

Exportación de datos

Los modelos a menudo deben exportarse en diferentes formatos. Para convertir el modelo en una matriz, modifique elactionShowContactModel función de la SiteController -

public function actionShowContactModel() {
   $mContactForm = new \app\models\ContactForm();
   $mContactForm->name = "contactForm";
   $mContactForm->email = "[email protected]";
   $mContactForm->subject = "subject";
   $mContactForm->body = "body";
   var_dump($mContactForm->attributes);
}

Tipo http://localhost:8080/index.php?r=site/show-contact-model en la barra de direcciones y verá lo siguiente:

Para convertir el modelo al JSON formato, modificar el actionShowContactModel funcionan de la siguiente manera:

public function actionShowContactModel() {
   $mContactForm = new \app\models\ContactForm();
   $mContactForm->name = "contactForm";
   $mContactForm->email = "[email protected]";
   $mContactForm->subject = "subject";
   $mContactForm->body = "body";
   return \yii\helpers\Json::encode($mContactForm);
}

Browser output -

{
   "name":"contactForm",
   "email":"[email protected]",
   "subject":"subject",
   "body":"body ",
   "verifyCode":null
}

Puntos importantes

Los modelos suelen ser mucho más rápidos que los controladores en una aplicación bien diseñada. Los modelos deberían -

  • Contienen lógica empresarial.
  • Contiene reglas de validación.
  • Contienen atributos.
  • No incrustar HTML.
  • No acceder directamente a las solicitudes.
  • No tener demasiados escenarios.