A continuación podéis seguir un tutorial de Yii2 en español, en él se describen los conceptos básicos para poder crear aplicaciones web utilizando los componentes que ofrece este magnífico Framework de PHP basado en el patrón de arquitectura MVC (Modelo Vista Controlador) y utilizando lo último del lenguaje php ya que para su puesta en marcha es requisito php 5.4 o mayor.
En este capítulo del tutorial de Yii2 veremos como forzar la descarga de archivos del servidor, para tal tarea crearemos un nuevo método privado en el controlador llamado downloadFile($dir, $file, $extensions=[]), que se encargará de realizar la operación de descarga, este método retornará un valor boolean true-false.
Crearemos una acción-vista llamada download, en la vista incluiremos un link que no permitirá realizar la descarga de un archivo, si ocurre algún error al descargar el archivo mostraremos un mensaje flash, advirtiendo al usuario del error, de lo contrario el archivo se podrá descargar correctamente.
1 - Crear en la carpeta web una carpeta llamada archivos y agregar los archivos que podrán ser descargados (en el capítulo anterior "Subir archivos al servidor" esta carpeta ya fue creada).
2 - Crear la vista download ...
<?php use yii\helpers\Url; ?>
<?php if (Yii::$app->session->hasFlash('errordownload')): ?>
<strong class="label label-danger">¡Ha ocurrido un error al descargar el archivo!</strong>
<?php else: ?>
<a href="<?= Url::toRoute(["site/download", "file" => "yii.pdf"]) ?>">Descargar archivo</a>
<?php endif; ?>
3 - Incluir el método privado downloadFile y la acción Download en el controlador ...
private function downloadFile($dir, $file, $extensions=[])
{
//Si el directorio existe
if (is_dir($dir))
{
//Ruta absoluta del archivo
$path = $dir.$file;
//Si el archivo existe
if (is_file($path))
{
//Obtener información del archivo
$file_info = pathinfo($path);
//Obtener la extensión del archivo
$extension = $file_info["extension"];
if (is_array($extensions))
{
//Si el argumento $extensions es un array
//Comprobar las extensiones permitidas
foreach($extensions as $e)
{
//Si la extension es correcta
if ($e === $extension)
{
//Procedemos a descargar el archivo
// Definir headers
$size = filesize($path);
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=$file");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . $size);
// Descargar archivo
readfile($path);
//Correcto
return true;
}
}
}
}
}
//Ha ocurrido un error al descargar el archivo
return false;
}
public function actionDownload()
{
if (Yii::$app->request->get("file"))
{
//Si el archivo no se ha podido descargar
//downloadFile($dir, $file, $extensions=[])
if (!$this->downloadFile("archivos/", Html::encode($_GET["file"]), ["pdf", "txt", "doc"]))
{
//Mensaje flash para mostrar el error
Yii::$app->session->setFlash("errordownload");
}
}
return $this->render("download");
}
En este capítulo veremos como realizar una subida múltiple de archivos, para ello crearemos un formulario activo (ActiveForm) que contendrá un input file multiple, este formulario estará conectado a un modelo de validación, desde el cual estableceremos los siguientes parámetros ...
- La subida de algún archivo es requerida
- El archivo no podrá tener un tamaño mayor de 1 MB
- El archivo no podrá tener un tamaño menor de 10 Bytes
- El archivo deberá tener una de las siguientes extensiones pdf, doc y txt
- El máximo de archivos que se pueden subir son 4.
Para la validación del campo input file utilizaremos la siguiente documentación ...
En este capítulo continuamos con la autenticación de usuarios y vamos a ver como crear controles de acceso para los usuarios registrados, el ejemplo consistirá en crear 2 roles, uno para usuarios registrados simples y otro para administradores, los usuarios simples tendrán acceso a determinadas secciones de la web y los administradores a otras, como ejemplo crearemos dos páginas, una reservada para los usuarios registrados simples y otra para los administradores, tras iniciar sesión se determinará su rol en el sistema y serán redireccionados a la página de user o admin dependiendo del rol asignado al usuario.
Para esta tarea agregaremos una nueva columna a la tabla users llamada role, por defecto esta columna tendrá el valor 1 que es el rol de los usuarios simples, el valor 2 asignará al usuario privilegios de administrador.
ALTER TABLE `users` ADD `role` INT NOT NULL DEFAULT '1';
2 - Crear los métodos isUserAdmin y isUserSimple en el modelo User.php que nos permitirán establecer los permisos de usuario, estos métodos regresarán un valor boolean, también tenemos que agregar la nueva propiedad $role ...
public $role;
public static function isUserAdmin($id)
{
if (Users::findOne(['id' => $id, 'activate' => '1', 'role' => 2])){
return true;
} else {
return false;
}
}
public static function isUserSimple($id)
{
if (Users::findOne(['id' => $id, 'activate' => '1', 'role' => 1])){
return true;
} else {
return false;
}
}
3 - Agregar la clase User al controlador SiteController.php para poder utilizar los métodos creados anteriormente ...
use app\models\User;
4 - Crear las acciones-vistas User y Admin para poder ver el ejemplo de control acceso de usuarios.
5 - Configurar el control de acceso de usuarios en el método behaviors que se encuentra en el controlador SiteController.php ...
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'user', 'admin'],
'rules' => [
[
//El administrador tiene permisos sobre las siguientes acciones
'actions' => ['logout', 'admin'],
//Esta propiedad establece que tiene permisos
'allow' => true,
//Usuarios autenticados, el signo ? es para invitados
'roles' => ['@'],
//Este método nos permite crear un filtro sobre la identidad del usuario
//y así establecer si tiene permisos o no
'matchCallback' => function ($rule, $action) {
//Llamada al método que comprueba si es un administrador
return User::isUserAdmin(Yii::$app->user->identity->id);
},
],
[
//Los usuarios simples tienen permisos sobre las siguientes acciones
'actions' => ['logout', 'user'],
//Esta propiedad establece que tiene permisos
'allow' => true,
//Usuarios autenticados, el signo ? es para invitados
'roles' => ['@'],
//Este método nos permite crear un filtro sobre la identidad del usuario
//y así establecer si tiene permisos o no
'matchCallback' => function ($rule, $action) {
//Llamada al método que comprueba si es un usuario simple
return User::isUserSimple(Yii::$app->user->identity->id);
},
],
],
],
//Controla el modo en que se accede a las acciones, en este ejemplo a la acción logout
//sólo se puede acceder a través del método post
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
6 - Modificar la acción Login para establecer las redirecciones dependiendo del rol que tenga el usuario ...
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
if (User::isUserAdmin(Yii::$app->user->identity->id))
{
return $this->redirect(["site/admin"]);
}
else
{
return $this->redirect(["site/user"]);
}
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
if (User::isUserAdmin(Yii::$app->user->identity->id))
{
return $this->redirect(["site/admin"]);
}
else
{
return $this->redirect(["site/user"]);
}
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
En el capítulo anterior vimos como autenticar usuarios trabajando sobre el modelo User, en este capítulo nos centraremos en crear un sistema que permita al usuario recuperar su password, para tal tarea, crearemos un formulario desde el cual el usuario deberá introducir su email, si su email existe en la tabla users le será enviado un correo electrónico con un código de verificación que será guardado en una nueva columna verification_code para que pueda restablecer su contraseña, la opción de resetado del password sólo está disponible hasta que el usuario cierre el navegador ya que controlaremos el proceso a través de variables de sesión.
1 - Crear la columna verification_code en la tabla users
ALTER TABLE users ADD verification_code VARCHAR(250) NOT NULL;
2 - Agregar la nueva columna al modelo User.php
public $verification_code;
3 - Crear la vista recoverpass.php formulario desde el cual el usuario deberá introducir su email
6 - Crear el modelo de validación para el formulario anterior, FormResetPass.php ...
<?php
namespace app\models;
use Yii;
use yii\base\model;
class FormResetPass extends model{
public $email;
public $password;
public $password_repeat;
public $verification_code;
public $recover;
public function rules()
{
return [
[['email', 'password', 'password_repeat', 'verification_code', 'recover'], 'required', 'message' => 'Campo requerido'],
['email', 'match', 'pattern' => "/^.{5,80}$/", 'message' => 'Mínimo 5 y máximo 80 caracteres'],
['email', 'email', 'message' => 'Formato no válido'],
['password', 'match', 'pattern' => "/^.{8,16}$/", 'message' => 'Mínimo 6 y máximo 16 caracteres'],
['password_repeat', 'compare', 'compareAttribute' => 'password', 'message' => 'Los passwords no coinciden'],
];
}
}
7 - Agregar al controlador las clases con los modelos de validación y la clase para trabajar con sesiones
use yii\web\Session;
use app\models\FormRecoverPass;
use app\models\FormResetPass;
8 - Incluir las acciones Recoverpass y Resetpass al controlador SiteController.php ...
public function actionRecoverpass()
{
//Instancia para validar el formulario
$model = new FormRecoverPass;
//Mensaje que será mostrado al usuario en la vista
$msg = null;
if ($model->load(Yii::$app->request->post()))
{
if ($model->validate())
{
//Buscar al usuario a través del email
$table = Users::find()->where("email=:email", [":email" => $model->email]);
//Si el usuario existe
if ($table->count() == 1)
{
//Crear variables de sesión para limitar el tiempo de restablecido del password
//hasta que el navegador se cierre
$session = new Session;
$session->open();
//Esta clave aleatoria se cargará en un campo oculto del formulario de reseteado
$session["recover"] = $this->randKey("abcdef0123456789", 200);
$recover = $session["recover"];
//También almacenaremos el id del usuario en una variable de sesión
//El id del usuario es requerido para generar la consulta a la tabla users y
//restablecer el password del usuario
$table = Users::find()->where("email=:email", [":email" => $model->email])->one();
$session["id_recover"] = $table->id;
//Esta variable contiene un número hexadecimal que será enviado en el correo al usuario
//para que lo introduzca en un campo del formulario de reseteado
//Es guardada en el registro correspondiente de la tabla users
$verification_code = $this->randKey("abcdef0123456789", 8);
//Columna verification_code
$table->verification_code = $verification_code;
//Guardamos los cambios en la tabla users
$table->save();
//Creamos el mensaje que será enviado a la cuenta de correo del usuario
$subject = "Recuperar password";
$body = "<p>Copie el siguiente código de verificación para restablecer su password ... ";
$body .= "<strong>".$verification_code."</strong></p>";
$body .= "<p><a href='http://yii.local/index.php?r=site/resetpass'>Recuperar password</a></p>";
//Enviamos el correo
Yii::$app->mailer->compose()
->setTo($model->email)
->setFrom([Yii::$app->params["adminEmail"] => Yii::$app->params["title"]])
->setSubject($subject)
->setHtmlBody($body)
->send();
//Vaciar el campo del formulario
$model->email = null;
//Mostrar el mensaje al usuario
$msg = "Le hemos enviado un mensaje a su cuenta de correo para que pueda resetear su password";
}
else //El usuario no existe
{
$msg = "Ha ocurrido un error";
}
}
else
{
$model->getErrors();
}
}
return $this->render("recoverpass", ["model" => $model, "msg" => $msg]);
}
public function actionResetpass()
{
//Instancia para validar el formulario
$model = new FormResetPass;
//Mensaje que será mostrado al usuario
$msg = null;
//Abrimos la sesión
$session = new Session;
$session->open();
//Si no existen las variables de sesión requeridas lo expulsamos a la página de inicio
if (empty($session["recover"]) || empty($session["id_recover"]))
{
return $this->redirect(["site/index"]);
}
else
{
$recover = $session["recover"];
//El valor de esta variable de sesión la cargamos en el campo recover del formulario
$model->recover = $recover;
//Esta variable contiene el id del usuario que solicitó restablecer el password
//La utilizaremos para realizar la consulta a la tabla users
$id_recover = $session["id_recover"];
}
//Si el formulario es enviado para resetear el password
if ($model->load(Yii::$app->request->post()))
{
if ($model->validate())
{
//Si el valor de la variable de sesión recover es correcta
if ($recover == $model->recover)
{
//Preparamos la consulta para resetear el password, requerimos el email, el id
//del usuario que fue guardado en una variable de session y el código de verificación
//que fue enviado en el correo al usuario y que fue guardado en el registro
$table = Users::findOne(["email" => $model->email, "id" => $id_recover, "verification_code" => $model->verification_code]);
//Encriptar el password
$table->password = crypt($model->password, Yii::$app->params["salt"]);
//Si la actualización se lleva a cabo correctamente
if ($table->save())
{
//Destruir las variables de sesión
$session->destroy();
//Vaciar los campos del formulario
$model->email = null;
$model->password = null;
$model->password_repeat = null;
$model->recover = null;
$model->verification_code = null;
$msg = "Enhorabuena, password reseteado correctamente, redireccionando a la página de login ...";
$msg .= "<meta http-equiv='refresh' content='5; ".Url::toRoute("site/login")."'>";
}
else
{
$msg = "Ha ocurrido un error";
}
}
else
{
$model->getErrors();
}
}
}
return $this->render("resetpass", ["model" => $model, "msg" => $msg]);
}
En el capítulo anterior vimos como registrar usuarios en la tabla users y como éstos tenían que activar su cuenta a través de un link de confirmación que es enviado a su correo electrónico, en este capítulo nos centramos en la autenticación de usuarios a través del modelo User, que contiene las herramientas necesarias para crear un correcto sistema de autenticado de usuarios, el objetivo es modificar el modelo User que viene por defecto en la aplicación esqueleto de Yii2 para adecuarlo correctamente a la tabla users generando las consultas que correspondan mediante ActiveRecord.
El código con las modificaciones en models/User.php ...
<?php
namespace app\models;
class User extends \yii\base\Object implements \yii\web\IdentityInterface
{
public $id;
public $username;
public $email;
public $password;
public $authKey;
public $accessToken;
public $activate;
/**
* @inheritdoc
*/
/* busca la identidad del usuario a través de su $id */
public static function findIdentity($id)
{
$user = Users::find()
->where("activate=:activate", [":activate" => 1])
->andWhere("id=:id", ["id" => $id])
->one();
return isset($user) ? new static($user) : null;
}
/**
* @inheritdoc
*/
/* Busca la identidad del usuario a través de su token de acceso */
public static function findIdentityByAccessToken($token, $type = null)
{
$users = Users::find()
->where("activate=:activate", [":activate" => 1])
->andWhere("accessToken=:accessToken", [":accessToken" => $token])
->all();
foreach ($users as $user) {
if ($user->accessToken === $token) {
return new static($user);
}
}
return null;
}
/**
* Finds user by username
*
* @param string $username
* @return static|null
*/
/* Busca la identidad del usuario a través del username */
public static function findByUsername($username)
{
$users = Users::find()
->where("activate=:activate", ["activate" => 1])
->andWhere("username=:username", [":username" => $username])
->all();
foreach ($users as $user) {
if (strcasecmp($user->username, $username) === 0) {
return new static($user);
}
}
return null;
}
/**
* @inheritdoc
*/
/* Regresa el id del usuario */
public function getId()
{
return $this->id;
}
/**
* @inheritdoc
*/
/* Regresa la clave de autenticación */
public function getAuthKey()
{
return $this->authKey;
}
/**
* @inheritdoc
*/
/* Valida la clave de autenticación */
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
/**
* Validates password
*
* @param string $password password to validate
* @return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
/* Valida el password */
if (crypt($password, $this->password) == $this->password)
{
return $password === $password;
}
}
}
En este capítulo empezamos a ver como implementar un sistema de autenticación de usuarios, Yii2 en su aplicación esqueleto nos muestra un ejemplo de como loguear a los usuarios, pero no nos muestra como implementar el registro de usuarios.
En este caso vamos a crear uno, con un formulario de registro y que solicite la activación de la cuenta de usuario mediante correo electrónico. Entre los objetivos de este ejemplo es mostrar como utilizar la tecnología ajax para impedir que un usuario se pueda registrar si el username o el email existen en la tabla users, ésto ya lo vimos en un capítulo anterior pero es interesante que lo volvamos a repasar.
Para que el usuario finalice su activación tendrá que hacer click en un enlace que previamente hemos enviado al usuario por correo electrónico, si los datos son correctos el usuario será activado y podrá iniciar sesión (la configuración del inicio de sesión lo veremos en el siguiente capítulo).
El código de este capítulo se puede ver a continuación:
1 - Instalar la tabla users.sql
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) AUTO_INCREMENT NOT NULL,
`username` varchar(50) NOT NULL,
`email` varchar(80) NOT NULL,
`password` varchar(250) NOT NULL,
`authKey` varchar(250) NOT NULL,
`accessToken` varchar(250) NOT NULL,
`activate` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
);
2 - Crear la vista register.php donde está el formulario de registro ...
3 - Crear el modelo de validación para el formulario de registro anterior, FormRegister.php
<?php
namespace app\models;
use Yii;
use yii\base\model;
use app\models\Users;
class FormRegister extends model{
public $username;
public $email;
public $password;
public $password_repeat;
public function rules()
{
return [
[['username', 'email', 'password', 'password_repeat'], 'required', 'message' => 'Campo requerido'],
['username', 'match', 'pattern' => "/^.{3,50}$/", 'message' => 'Mínimo 3 y máximo 50 caracteres'],
['username', 'match', 'pattern' => "/^[0-9a-z]+$/i", 'message' => 'Sólo se aceptan letras y números'],
['username', 'username_existe'],
['email', 'match', 'pattern' => "/^.{5,80}$/", 'message' => 'Mínimo 5 y máximo 80 caracteres'],
['email', 'email', 'message' => 'Formato no válido'],
['email', 'email_existe'],
['password', 'match', 'pattern' => "/^.{8,16}$/", 'message' => 'Mínimo 6 y máximo 16 caracteres'],
['password_repeat', 'compare', 'compareAttribute' => 'password', 'message' => 'Los passwords no coinciden'],
];
}
public function email_existe($attribute, $params)
{
//Buscar el email en la tabla
$table = Users::find()->where("email=:email", [":email" => $this->email]);
//Si el email existe mostrar el error
if ($table->count() == 1)
{
$this->addError($attribute, "El email seleccionado existe");
}
}
public function username_existe($attribute, $params)
{
//Buscar el username en la tabla
$table = Users::find()->where("username=:username", [":username" => $this->username]);
//Si el username existe mostrar el error
if ($table->count() == 1)
{
$this->addError($attribute, "El usuario seleccionado existe");
}
}
}
4 - Crear el modelo de registro activos (ActiveRecord) para la tabla users, Users.php
<?php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
class Users extends ActiveRecord{
public static function getDb()
{
return Yii::$app->db;
}
public static function tableName()
{
return 'users';
}
}
5 - Abrir el archivo de configuración config/params.php para incluir un título para la aplicación Yii, este título lo enviaremos en el correo electrónico al usuario, también agregaremos un salt para encriptar las contraseñas de usuario.
6 - Agregar las clases FormRegister y Users creadas anteriormente al controlador
use app\models\FormRegister;
use app\models\Users;
7 - Código para el controlador con la acción Register que utilizaremos para registrar al usuario, la acción Confirm que permitirá activar al usuario cuando haga click en el enlace adjunto en el correo electrónico y el método privado randKey($str, $long) para generar claves aleatorias para las columnas authKey y accessToken
<?php
private function randKey($str='', $long=0)
{
$key = null;
$str = str_split($str);
$start = 0;
$limit = count($str)-1;
for($x=0; $x<$long; $x++)
{
$key .= $str[rand($start, $limit)];
}
return $key;
}
public function actionConfirm()
{
$table = new Users;
if (Yii::$app->request->get())
{
//Obtenemos el valor de los parámetros get
$id = Html::encode($_GET["id"]);
$authKey = $_GET["authKey"];
if ((int) $id)
{
//Realizamos la consulta para obtener el registro
$model = $table
->find()
->where("id=:id", [":id" => $id])
->andWhere("authKey=:authKey", [":authKey" => $authKey]);
//Si el registro existe
if ($model->count() == 1)
{
$activar = Users::findOne($id);
$activar->activate = 1;
if ($activar->update())
{
echo "Enhorabuena registro llevado a cabo correctamente, redireccionando ...";
echo "<meta http-equiv='refresh' content='8; ".Url::toRoute("site/login")."'>";
}
else
{
echo "Ha ocurrido un error al realizar el registro, redireccionando ...";
echo "<meta http-equiv='refresh' content='8; ".Url::toRoute("site/login")."'>";
}
}
else //Si no existe redireccionamos a login
{
return $this->redirect(["site/login"]);
}
}
else //Si id no es un número entero redireccionamos a login
{
return $this->redirect(["site/login"]);
}
}
}
public function actionRegister()
{
//Creamos la instancia con el model de validación
$model = new FormRegister;
//Mostrará un mensaje en la vista cuando el usuario se haya registrado
$msg = null;
//Validación mediante ajax
if ($model->load(Yii::$app->request->post()) && Yii::$app->request->isAjax)
{
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
//Validación cuando el formulario es enviado vía post
//Esto sucede cuando la validación ajax se ha llevado a cabo correctamente
//También previene por si el usuario tiene desactivado javascript y la
//validación mediante ajax no puede ser llevada a cabo
if ($model->load(Yii::$app->request->post()))
{
if($model->validate())
{
//Preparamos la consulta para guardar el usuario
$table = new Users;
$table->username = $model->username;
$table->email = $model->email;
//Encriptamos el password
$table->password = crypt($model->password, Yii::$app->params["salt"]);
//Creamos una cookie para autenticar al usuario cuando decida recordar la sesión, esta misma
//clave será utilizada para activar el usuario
$table->authKey = $this->randKey("abcdef0123456789", 200);
//Creamos un token de acceso único para el usuario
$table->accessToken = $this->randKey("abcdef0123456789", 200);
//Si el registro es guardado correctamente
if ($table->insert())
{
//Nueva consulta para obtener el id del usuario
//Para confirmar al usuario se requiere su id y su authKey
$user = $table->find()->where(["email" => $model->email])->one();
$id = urlencode($user->id);
$authKey = urlencode($user->authKey);
$subject = "Confirmar registro";
$body = "<h1>Haga click en el siguiente enlace para finalizar tu registro</h1>";
$body .= "<a href='http://yii.local/index.php?r=site/confirm&id=".$id."&authKey=".$authKey."'>Confirmar</a>";
//Enviamos el correo
Yii::$app->mailer->compose()
->setTo($user->email)
->setFrom([Yii::$app->params["adminEmail"] => Yii::$app->params["title"]])
->setSubject($subject)
->setHtmlBody($body)
->send();
$model->username = null;
$model->email = null;
$model->password = null;
$model->password_repeat = null;
$msg = "Enhorabuena, ahora sólo falta que confirmes tu registro en tu cuenta de correo";
}
else
{
$msg = "Ha ocurrido un error al llevar a cabo tu registro";
}
}
else
{
$model->getErrors();
}
}
return $this->render("register", ["model" => $model, "msg" => $msg]);
}
En este capítulo del tutorial de Yii2 veremos como enviar correos electrónicos a través de la librería integrada SwiftMailer, para el ejemplo utilizaremos el servidor smtp de gmail y el formulario de contacto que viene por defecto en la aplicación esqueleto. Modificaremos el método contact del modelo ContactForm para poder enviar el correo a través de una plantilla (layout).
Es posible que os surja un error como el siguiente al enviar el correo con vuestra cuenta de gmail ...
Expected response code 250 but got code "535", with message "535-5.7.8 Username and Password not accepted. Learn more at 535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257 u6sm5939213wix.12 - gsmtp"
El código que interviene en este capítulo lo podéis ver a continuación:
Código del modelo 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)
{
$content = "<p>Email: " . $this->email . "</p>";
$content .= "<p>Name: " . $this->name . "</p>";
$content .= "<p>Subject: " . $this->subject . "</p>";
$content .= "<p>Body: " . $this->body . "</p>";
if ($this->validate()) {
Yii::$app->mailer->compose("@app/mail/layouts/html", ["content" => $content])
->setTo($email)
->setFrom([$this->email => $this->name])
->setSubject($this->subject)
->setTextBody($this->body)
->send();
return true;
} else {
return false;
}
}
}
En este capítulo finalizamos el sistema CRUD con la actualización de registros, para ello crearemos una nueva acción-vista llamada Update desde la cual podremos editar el alumno seleccionado a través de su id, para la selección del registro utilizaremos el método findOne($id) que buscará el registro a través de la clave primaria dada en el argumento, para la actualización utilizaremos el método update() que pasado por una sentencia if, nos regresará un valor boolean: true si la actualización se ha podido llevar a cabo correctamente y false para todo lo contrario.
En este capítulo continuamos construyendo el sistema CRUD y nos ocupamos de la opción DELETE para eliminar registros. Cada registro tiene un link asociado para la opción eliminar, como ejemplo, al hacer click sobre él, abriremos una ventana modal Bootstrap desde la cual se nos preguntará si queremos eliminar el registro seleccionado, en la ventana modal hay dos botones uno para cerrar la ventana y otro para eliminar el registro, si optamos por la opción eliminar el registro, ésta petición será formulada a una acción llamada Delete desde la cual procesaremos los datos para su eliminación a través del método deleteAll($condition, $params)
En este capítulo continuamos con la acción-vista View que lista los registros de la tabla alumnos, en el capítulo anterior ya vimos como integrar un formulario de búsqueda para filtrar los resultados, en esta ocasión mejoraremos el sistema incluyendo una paginación de resultados a través de la clase yii\data\Pagination y generaremos la consulta LIKE de un modo distinto a lo visto en el capítulo anterior, pero con los mismos resultados gracias a las herramientas que nos proporciona la clase yii\db\Query.
En este capítulo continuamos con la acción-vista "View" en la cual estamos listando los registros de la tabla alumnos, le integraremos un formulario de búsqueda y así poder filtrar y mostrar los resultados según el criterio de búsqueda del usuario, para ello generaremos la consulta a través del método findBySql($sql) de la clase ActiveRecord.
El código que interviene en este capítulo lo podéis ver a continuación:
Modelo de validación para el formulario de búsqueda FormSearch.php
<?php
namespace app\models;
use Yii;
use yii\base\model;
class FormSearch extends model{
public $q;
public function rules()
{
return [
["q", "match", "pattern" => "/^[0-9a-záéíóúñ\s]+$/i", "message" => "Sólo se aceptan letras y números"]
];
}
public function attributeLabels()
{
return [
'q' => "Buscar:",
];
}
}
La acción View que se encuentra en el controlador SiteController.php
<?php
namespace app\controllers;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\LoginForm;
use app\models\ContactForm;
use app\models\ValidarFormulario;
use app\models\ValidarFormularioAjax;
use yii\widgets\ActiveForm;
use yii\web\Response;
use app\models\FormAlumnos;
use app\models\Alumnos;
use app\models\FormSearch;
use yii\helpers\Html;
class SiteController extends Controller
{
public function actionView()
{
$table = new Alumnos;
$model = $table->find()->all();
$form = new FormSearch;
$search = null;
if($form->load(Yii::$app->request->get()))
{
if ($form->validate())
{
$search = Html::encode($form->q);
$query = "SELECT * FROM alumnos WHERE id_alumno LIKE '%$search%' OR ";
$query .= "nombre LIKE '%$search%' OR apellidos LIKE '%$search%'";
$model = $table->findBySql($query)->all();
}
else
{
$form->getErrors();
}
}
return $this->render("view", ["model" => $model, "form" => $form, "search" => $search]);
}
public function actionCreate()
{
$model = new FormAlumnos;
$msg = null;
if($model->load(Yii::$app->request->post()))
{
if($model->validate())
{
$table = new Alumnos;
$table->nombre = $model->nombre;
$table->apellidos = $model->apellidos;
$table->clase = $model->clase;
$table->nota_final = $model->nota_final;
if ($table->insert())
{
$msg = "Enhorabuena registro guardado correctamente";
$model->nombre = null;
$model->apellidos = null;
$model->clase = null;
$model->nota_final = null;
}
else
{
$msg = "Ha ocurrido un error al insertar el registro";
}
}
else
{
$model->getErrors();
}
}
return $this->render("create", ['model' => $model, 'msg' => $msg]);
}
public function actionSaluda($get = "Tutorial Yii")
{
$mensaje = "Hola Mundo";
$numeros = [0, 1, 2, 3, 4, 5];
return $this->render("saluda",
[
"saluda" => $mensaje,
"numeros" => $numeros,
"get" => $get,
]);
}
public function actionFormulario($mensaje = null)
{
return $this->render("formulario", ["mensaje" => $mensaje]);
}
public function actionRequest()
{
$mensaje = null;
if (isset($_REQUEST["nombre"]))
{
$mensaje = "Bien, has enviando tu nombre correctamente: " . $_REQUEST["nombre"];
}
$this->redirect(["site/formulario", "mensaje" => $mensaje]);
}
public function actionValidarformulario()
{
$model = new ValidarFormulario;
if ($model->load(Yii::$app->request->post()))
{
if($model->validate())
{
//Por ejemplo, consultar en una base de datos
}
else
{
$model->getErrors();
}
}
return $this->render("validarformulario", ["model" => $model]);
}
public function actionValidarformularioajax()
{
$model = new ValidarFormularioAjax;
$msg = null;
if ($model->load(Yii::$app->request->post()) && Yii::$app->request->isAjax)
{
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if ($model->load(Yii::$app->request->post()))
{
if ($model->validate())
{
//Por ejemplo hacer una consulta a una base de datos
$msg = "Enhorabuena formulario enviado correctamente";
$model->nombre = null;
$model->email = null;
}
else
{
$model->getErrors();
}
}
return $this->render("validarformularioajax", ['model' => $model, 'msg' => $msg]);
}
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
public function actionIndex()
{
return $this->render('index');
}
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
public function actionContact()
{
$model = new ContactForm();
if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('contactFormSubmitted');
return $this->refresh();
} else {
return $this->render('contact', [
'model' => $model,
]);
}
}
public function actionAbout()
{
return $this->render('about');
}
}