viernes, 26 de diciembre de 2014

Trabajando con bases de datos

Es muy seguro que en nuestros trabajos necesitemos conectarnos a una base de datos. En ésta sección veremos como:

  • Configurar una conexión a base de datos
  • Definir una clase Active Record (Registro Activo)
  • Realizar consultas usando la clase Active Record
  • Desplegar datos en una página a través de una vista

Preparando la base de datos

Yii nos permite trabajar con diferentes base de datos como SQLite, MySQL, PostgreSQL, MSSQL u Oracle.

Para nuestro ejemplo utilizaremos MySQL en el que crearemos una base de datos yii2basic y una tabla pais con algunos registros.

CREATE TABLE IF NOT EXISTS `pais` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nombre` varchar(50) NOT NULL,
  `codigo` varchar(3) NOT NULL,
  `poblacion` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Colombia','CO', 47846160);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Venezuela','VE', 31648930);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Argentina','AR', 42192500);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Ecuador','EC', 16013143);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Uruguay','UY', 3286314);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Paraguay','PY', 6672633);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Bolivia','BO', 10027254);
INSERT INTO `pais`(`nombre`, `codigo`, `poblacion`) VALUES ('Chile','CL', 17819054);



Configurar una conexión a base de datos

Por una lado, debemos habilitar las extensiones correspondientes a nuestra base de datos en la configuración de PHP. Para nuestro caso es php_mysqlphp_pdo_mysql.

Por otro lado, abrimos el archivo \config\db.php y cambiamos los parámetros de acuerdo a nuestra base de datos. En nuestro caso:

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=yii2basic',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
];

Para acceder a esta configuración en el código de nuestra aplicación lo podemos hacer con la expresión Yii::$app->db.

Creando el Active Record (Registro Activo)

Para representar y extraer los datos de la tabla pais, creamos una clase pais derivada de Active Record. El archivo en el cual guardamos es \models\Pais.php con el siguiente contenido:

<?php

namespace app\models;

use yii\db\ActiveRecord;

class Pais extends ActiveRecord
{
}

Este es todo el código que debemos escribir. No es necesario especificar el nombre de la tabla, ya que el nombre de la clase se asocia al nombre de la tabla.

Es posible sobreescribir el método yii\db\ActiveRecord::tableName()  para especificar de manera explícita el nombre de la tabla. El código sería algo similar a:

class Pais extends ActiveRecord
{
    public static function tableName()
    {
        return 'tbl_paises';
    }
}

Creando la Acción

Crearemos un controlador propio para nuestra tabla, y la acción index como la acción por defecto o que se ejecutará si no se especifica de manera explícitamente en la url. Creamos el archivo \controllers\PaisController.php con el siguiente contenido:

<?php

namespace app\controllers;

use yii\web\Controller;
use yii\data\Pagination;
use app\models\Pais;

class PaisController extends Controller
{
    public function actionIndex()
    {
        $query = Pais::find();

        $pagination = new Pagination([
            'defaultPageSize' => 5,
            'totalCount' => $query->count(),
        ]);

        $paises = $query->orderBy('nombre')
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->all();

        return $this->render('index', [
            'paises' => $paises,
            'pagination' => $pagination,
        ]);
    }
}

Analicemos un poco el código.

Tenemos la llamada a Country::find() la cual recupera todos los datos de nuestra tabla. El límite de datos recuperados se realiza con ayuda del objeto yii\data\Pagination. El objeto Pagination tiene dos propósitos:
  1. Ajustar las cláusulas offset y limit de la consulta sql y recuperar un conjunto específico de datos. En nuestro ejemplo, páginas de 5 registros cada una.
  2. Desplegar de manera consistente los botones de paginación en nuestra vista.
Al final, se retorna la vista index con los datos de los países y la información de la paginación.

Creando la vista

Bajo el directorio views, crearemos un subdirectorio de nombre pais. En este subdirectorio se guardarán todas las vistas utilizadas en nuestro controlador. Creamos el archivo \views\pais\index.php con el siguiente código:

<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>Países</h1>
<ul>
<?php foreach ($paises as $pais): ?>
    <li>
        <?= Html::encode("{$pais->nombre} ({$pais->codigo})") ?>:
        <?= $pais->poblacion ?>
    </li>
<?php endforeach; ?>
</ul>

<?= LinkPager::widget(['pagination' => $pagination]) ?>

La vista tiene dos secciones. La primera, que toma los datos de los países y los presenta como una lista HTML con viñetas (unordered); y la segunda, el widget yii\widgets\LinkPager para mostrar los botones de paginación.

Probando

Para probar el resultado de nuestro trabajo podemos en nuestro navegador web escribir la url:
http://hostname/index.php?r=pais/index

El resultado será similar al siguiente:



Sugerencias


  • Al crear nuestra base de datos, es bueno definir una conexión (cotejamiento) del tipo utf8.
  • Nuestros archivos deben ser grabados como UTF-8 sin BOM.



También te puede interesar:
DAO - Database Access Objects (Objetos de acceso a base de datos)
Generador de Consultas (Query Builder)
Active Record (Registro Activo)

jueves, 25 de diciembre de 2014

Configurando el lenguaje

Si hemos revisado la entrada Formularios en Yii 2, habremos notado que los mensajes se presentan en inglés. Algo lógico puesto que el lenguaje por defecto es el inglés.

En una aplicación Yii se definen dos lenguajes: el lenguaje fuente y el lenguaje objetivo.

El lenguaje fuente es el lenguaje original de la aplicación; los mensajes son directamente escritos como:

echo \Yii::t('app', 'Soy un mensaje cualquiera!');

El lenguaje objetivo es el lenguaje que debería ser usado para desplegar una determinada página, como por ejemplo el lenguaje al que deben traducirse los mensajes originales. El lenguaje objetivo se configura en el archivo

\basic\config\web.php

especificando el lenguaje en el que queremos mostrar los mensajes

$config = [
    'id' => 'basic',
    'basePath' => dirname(__DIR__),
    'language' => 'es',
    'bootstrap' => ['log'],
    'components' => [
...

El lenguaje también puede ser especificado en tiempo de ejecución. Se lo debe realizar antes de generar cualquier salida para que tenga el efecto deseado. Para lograrlo, basta con cambiar la propiedad de la aplicación al valor deseado de la siguiente manera:

\Yii::$app->language = 'es';

El formato del lenguaje/lugar es ll-cc donde:

  • ll es un código de 2 o 3 letras de acuerdo a ISO-639
  • cc es el código del país de acuerdo a ISO-3166

Como podemos notar en nuestro ejemplo, podemos indicar únicamente el lenguaje.

Los mensaje de validación de nuestro formulario visto en la entrada anterior, configurando la aplicación al español, se verán como en la siguiente imagen:




También te puede interesar:
Formularios en Yii 2

domingo, 7 de diciembre de 2014

Formularios en Yii 2

Crearemos un formulario sencillo mediante el cual podemos recolectar información de los usuarios. El objetivo es aprender a crear las vistas, una acción, y  por supuesto un modelo.

Para nuestro ejemplo, crearemos un formulario en el que usuario deba ingresar su nombre y correo, ambos de manera obligatoria. Y nos basaremos en nuestra aplicación basic.

Creando un modelo 

Nuestro modelo se llamará IngresoFormulario y crearemos el archivo de nombre /models/IngresoFormulario.php con el siguiente código:

<?php

namespace app\models;

use yii\base\Model;

class IngresoFormulario extends Model
{
    public $nombre;
    public $correo;

    public function rules()
    {
        return [
            [['nombre', 'correo'], 'required'],
            ['correo', 'email'],
        ];
    }
}

?> 

Analicemos un poco el código...

La clase IngresoFormulario se extiende de yii\base\Model, la cual es provista por Yii y se utiliza comúnmente para representar datos de un formulario.

  • yii\base\Model se utiliza para modelos que no están asociados con tablas de bases de datos.
  • yii\db\ActiveRecord es la clase normalmente utilizada cuando se trata de una correspondencia con un tabla de base de datos.

Nuestra clase tiene dos variables públicas, nombre y correo que se utilizarán para almacenar los datos ingresados por el usuario. También tenemos un método llamado rules(), el cual tiene las reglas de validación. Para nuestro caso las reglas son:

  • nombre y  correo son datos necesarios u obligatorios.
  • correo debe ser una dirección de correo válida, por eso se lo valida como del tipo email.


Creando la Acción

En nuestro controlador /controllers/SiteController.php crearemos una acción de nombre Ingreso. El código nos queda de la siguiente manera:

public function actionIngreso()
{
$model = new IngresoFormulario;

if ($model->load(Yii::$app->request->post()) && $model->validate()) {
// Valida los datos recibidos en $model

// Se puede manipular los datos de $model

return $this->render('confirmar-ingreso', ['model' => $model]);
} else {
// Se despliega la pagina inicial o si hay un error de validacion
return $this->render('ingreso', ['model' => $model]);
}
}

Analicemos un poco el código...

En primer lugar, se crea un objeto llamado IngresoFormulario. Se proceden a poblar el modelo con los datos provenientes de $_POST. Si el modelo se pobla exitosamente, se llama a validate() para asegurar que los datos son válidos.

La expresión Yii::$app representa la instancia de la aplicación, la cual es globalmente accessible. También provee componentes como request, response, db entre otros. En nuestro código se utiliza request para acceder a los datos $_POST.

Si todo es correcto, se devuelve la vista confirmar-ingreso. Si no se han recibido datos o se produjo un error, la vista ingreso es la devuelta junto con cualquier mensaje de error que pudo haberse producido.

En nuestro controlador Site es muy importante especificar que se va a utilizar el modelo IngresoFormulario. Para ello añadimos:

<?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\IngresoFormulario;

class SiteController extends Controller
{

Creando las Vistas

Como habremos notado, nuestro controlador utiliza dos vistas. Una para recibir los datos, y otra para confirmar la recepción.

Para nuestro formulario, creamos un archivo /views/site/ingreso.php con el siguiente código:

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'nombre') ?>

    <?= $form->field($model, 'correo') ?>

    <div class="form-group">
        <?= Html::submitButton('Enviar', ['class' => 'btn btn-primary']) ?>
    </div>

<?php ActiveForm::end(); ?>

Analicemos un poco el código...

Se utiliza un widget llamado ActiveForm para construir el formulario HTML. Los métodos begin() y end() generan los tags de apertura y cierre del formulario. Entre estos métodos, se utiliza el método field() para generar los campos del formulario. Por último, el helper  Html::submitButton nos permite generar el botón submit.

La otra vista es más sencilla. Creamos el archivo /views/site/confirmar-ingreso.php con el siguiente código:

<?php
use yii\helpers\Html;
?>
<p>Usted ha ingresado la siguiente informacion:</p>

<ul>
    <li><label>Nombre</label>: <?= Html::encode($model->nombre) ?></li>
    <li><label>Correo</label>: <?= Html::encode($model->correo) ?></li>
</ul>

En ésta segunda vista, sencillamente presentamos la información que fue ingresada a través del formulario.

Probando

Para revisar nuestro trabajo, accedemos a través de nuestro navegador web utilizando la URL
http://127.0.0.1/projects/basic/web/index.php?r=site/ingreso

Veremos una página como la siguiente.



Si ingresamos los datos del formulario correctamente y presionamos el botón Enviar, veremos algo similar a:



Si llenamos de manera incorrecta el formulario, se realizarán las validaciones correspondientes (por ahora se mostrarán los mensajes en inglés)



Explicación

Si realizamos diferentes pruebas con nuestro formulario, podemos notar su comportamiento. Por un lado, si hacemos clic en el un campo, y luego en el otro, veremos automáticamente el mensaje de que el campo no puede quedar en blanco. Esto se debe a que se realizan validaciones desde el lado del cliente mediante JavaScript. Si enviamos nuestro formulario, se realiza una segunda validación, pero esta vez en el lado del servidor. Obviamente, si deshabilitamos JavaScript en nuestro navegador web, las validaciones siempre se harán únicamente del lado del servidor.

Por otro lado,podemos notar que las etiquetas se generan automáticamente. El nombre del campo se utiliza como etiqueta del mismo, por lo que es una buena sugerencia utilizar nombres descriptivos y claros para nuestros campos. Claro está que si queremos nuestras propias etiquetas podemos utilizar un código similar al siguiente:

<?= $form->field($model, 'nombre')->label('Nombres y Apellidos') ?>
<?= $form->field($model, 'correo')->label('Correo electrónico') ?>


También te puede interesar:
Instalando Yii 2
Hola mundo!