Mi segunda aplicación con Yii: Calculadora Simple

Introducción.

Bien, aquí vamos con mi segundo paso en el camino de aprendizaje con Yii.  El día de hoy voy a hacer una práctica muy sencilla de como manipular los formularios en Yii.  Es en realidad muy fácil, sólo hace falta acostumbrarse.

El objetivo de la aplicación es la de desplegar dos campos (operandos) y una lista de selección (operador) y calcular el resultado de la operación aritmética elegida entre estos valores.  Es en realidad, el típico programita de calculadora.  Utilizará validadores de campos, asignación de campos a partir del request y un modelo basado en formularios.

Creación de la infraestructura básica.

Creación de la estructura de la aplicación.

$ yii/current/framework/yiic webapp /home/www/public/SimpleCalc

Create a Web application under ‘/home/www/public/SimpleCalc’? [Yes|No] yes
mkdir /home/www/public/SimpleCalc
mkdir /home/www/public/SimpleCalc/protected
mkdir /home/www/public/SimpleCalc/protected/runtime
generate protected/runtime/.yii
mkdir /home/www/public/SimpleCalc/protected/messages
generate protected/messages/.yii
generate protected/.htaccess
mkdir /home/www/public/SimpleCalc/protected/components
generate protected/components/MainMenu.php
mkdir /home/www/public/SimpleCalc/protected/components/views
generate protected/components/views/mainMenu.php
generate protected/components/UserIdentity.php
generate protected/yiic.bat
mkdir /home/www/public/SimpleCalc/protected/commands
mkdir /home/www/public/SimpleCalc/protected/commands/shell
generate protected/commands/shell/.yii
generate protected/yiic
generate protected/yiic.php
mkdir /home/www/public/SimpleCalc/protected/extensions
generate protected/extensions/.yii
mkdir /home/www/public/SimpleCalc/protected/controllers
generate protected/controllers/SiteController.php
mkdir /home/www/public/SimpleCalc/protected/models
generate protected/models/ContactForm.php
generate protected/models/LoginForm.php
mkdir /home/www/public/SimpleCalc/protected/config
generate protected/config/main.php
generate protected/config/console.php
mkdir /home/www/public/SimpleCalc/protected/views
mkdir /home/www/public/SimpleCalc/protected/views/site
generate protected/views/site/login.php
generate protected/views/site/contact.php
generate protected/views/site/index.php
mkdir /home/www/public/SimpleCalc/protected/views/system
generate protected/views/system/.yii
mkdir /home/www/public/SimpleCalc/protected/views/layouts
generate protected/views/layouts/main.php
mkdir /home/www/public/SimpleCalc/images
generate images/.yii
mkdir /home/www/public/SimpleCalc/assets
generate assets/.yii
mkdir /home/www/public/SimpleCalc/css
generate css/main.css
generate css/bg.gif
generate css/form.css
mkdir /home/www/public/SimpleCalc/themes
mkdir /home/www/public/SimpleCalc/themes/classic
mkdir /home/www/public/SimpleCalc/themes/classic/views
generate themes/classic/views/.htaccess
mkdir /home/www/public/SimpleCalc/themes/classic/views/site
generate themes/classic/views/site/.yii
mkdir /home/www/public/SimpleCalc/themes/classic/views/system
generate themes/classic/views/system/.yii
mkdir /home/www/public/SimpleCalc/themes/classic/views/layouts
generate themes/classic/views/layouts/.yii
generate index.php

Your application has been created successfully under /home/www/public/SimpleCalc.

Téngase en cuenta que /home/www/yii/current fue la ruta en donde se instaló el framework en la sesión inicial y /home/www/public es el document root de mi servidor de páginas.

Creación del modelo y el controlador.

$ cd /home/www/public/SimpleCalc

$ protected/yiic shell

Yii Interactive Tool v1.0
Please type ‘help’ for help. Type ‘exit’ to quit.

>> model Calculadora
Warning: you do not have a ‘db’ database connection as required by Active Record.
generate Calculadora.php

The ‘Calculadora’ class has been successfully created in the following file:
/home/www/public/SimpleCalc/protected/models/Calculadora.php

If you have a ‘db’ database connection, you can test it now with:
$model=Calculadora::model()->find();
print_r($model);

>> controller Calculadora index
generate CalculadoraController.php
mkdir /home/www/public/SimpleCalc/protected/views/calculadora
generate index.php

Controller ‘calculadora’ has been created in the following file:
/home/www/public/SimpleCalc/protected/controllers/CalculadoraController.php

You may access it in the browser using the following URL:
http://hostname/path/to/index.php?r=calculadora

Complementar el modelo.

El archivo es SimpleCalc/protected/models/Calculadora.php.  La clase base para los modelos que recubren formularios de usuario es CFormModel.

class Calculadora extends CFormModel
{
    // ...
}

Los valores manejados por el modelo serán tres: dos operandos y un operador.

    public $operando1;
    public $operando2;
    public $operador;

Los modelos en Yii permiten que se especifique las etiquetas que se asociarán a los campos del modelo cuando se presenten en una vista.  Para este caso, los operadores se llamarán A y B respectivamente.

    public function attributeLabels()
    {
        return array(
            'operando1' => 'A',
            'operando2' => 'B'
        );
    }

Se especifican las reglas que deben contener los campos del modelo para considerarlo válido según los siguientes criterios.

  • Los operandos 1 y 2 son requeridos y deberán ser de tipo real.
  • El operador deberá ser una de las siguientes opciones: +, -, *, /.
  • El operador2 no podrá ser cero si la operación es división.

Para las dos primeras verificaciones se utilizan reglas incluídas en Yii, para la última se utiliza una personalizada definida por un método del modelo (validarDivCero).

    public function rules()
    {
        return array(
            array('operando1', 'required'),
            array('operando1', 'type', 'type' => 'float'),
            array('operando2', 'required'),
            array('operando2', 'type', 'type' => 'float'),
            array('operador',  'in', 'range' => array('+', '-', '*', '/')),
            array('operando2', 'validarDivCero')
        );
    }

    public function validarDivCero($attribute, $params)
    {
        if($this -> operador == '/' && $this -> operando2 == 0)
            $this -> addError('operando2', 'El denominador de una división no puede ser cero.');
    }

Se especifican cuales de los campos son seguros para ser asignados automáticamente a partir de los valores recibidos en el $_POST.  Para este caso, como son todos los disponibles, podría obviarse la especificación.

    public function safeAttributes()
    {
        return array(
            'operando1, operando2, operador'
        );
    }

Se implementa un método operar() que contiene la lógica de la Calculadora, es decir, suma, resta, multiplica o divide según se le solicite.

    public function operar()
    {
        $r = 0;

        switch ($this -> operador)
        {
            case '+': $r = $this -> operando1 + $this -> operando2;
                      break;
            case '-': $r = $this -> operando1 - $this -> operando2;
                      break;
            case '/': $r = $this -> operando1 / $this -> operando2;
                      break;
            case '*': $r = $this -> operando1 * $this -> operando2;
                      break;
        }

        return $r;
    }

Agregué un método adicional, toString(), para preparar la versión en cadena de la operación solicitada para realizar algunas pruebas que mas adelante comentaré.

    public function toString()
    {
        if($this -> operando1 === null || $this -> operando2 === null)
            return "Operación indefinida!";

        return "{$this -> operando1} {$this -> operador} {$this -> operando2}";
    }

Complementar el controlador.

El archivo se encuentra en SimpleCalc/protected/controllers/CalculadoraController.php.

La acción index deberá mostrar el formulario vacío y dejarlo listo para que el usuario ingrese los datos a operar.  Se le indica entonces que utilice la vista index y se le envía con ella un objeto Calculadora recién construído para que muestre sus campos vacíos.

    public function actionIndex()
    {
        $this -> render('index', array('calc' => new Calculadora()));
    }

La acción operar será invocada por el formulario (ubicado en la vista) cuando el usuario haya ingresado los operandos, seleccionado el operador y esté solicitando su operación.  Su misión es la de crear un objeto Calculadora a partir de la información recibida, verificar su información y en caso de ser posible, ejecutar la operación y mostrar su resultado al usuario.

    public function actionOperar()
    {
        $calculadora = new Calculadora();

        if(isset($_POST['Calculadora']))
        {
            $calculadora -> attributes = $_POST['Calculadora'];

            if($calculadora -> validate())
            {
                // Exito
                $this -> render('index', array('calc' => $calculadora,
                                               'resultado' => $calculadora -> operar()));
                exit;
            }
        }

        // Fracaso
        $this -> render('index', array('calc' => $calculadora));
        exit;
    }

Crear la vista.

Este mini proyecto sólo utiliza una vista, index, a través de la cual se solicitan los datos al usuario y se muestra el resultado de la operación.  El archivo se encuentra en SimpleCalc/protected/views/calculadora/index.php.

Lo primero que hago es crear las etiquetas de <form> que enviarán el requerimiento a la acción operar del controlador Calculadora tan pronto como el usuario utilice el botón de submit.

<h2>Calculadora Simple</h2>
<br />
<div>
    <?= CHtml::form(CHtml::normalizeUrl(array('calculadora/operar'))); ?>

    <!-- El contenido del formulario va aquí. -->

    </form>
</div>

Se determina en donde se mostrarán los mensajes de error al usuario.

    <?= CHtml::errorSummary($calc); ?>

Se agregan los campos para los operandos, cada uno consta de una etiqueta (recordar el método attributeLabels del modelo) y del campo de texto.  En medio de ellos se incluye una lista de selección única con el signo de operación.

    <?= CHtml::activeLabel($calc, 'operando1'); ?>
    <?= CHtml::activeTextField($calc, 'operando1'); ?>

    <?= CHtml::activeDropDownList($calc, 'operador', array('+' => '+',
                                                           '-' => '-',
                                                           '*' => '*',
                                                           '/' => '/')); ?>

    <?= CHtml::activeLabel($calc, 'operando2'); ?>
    <?= CHtml::activeTextField($calc, 'operando2'); ?>

Se incluye un botón de submit para el envío del formulario.

    <?= CHtml::submitButton('='); ?>

Se incluye además un espacio para desplegar la respuesta en caso de tenerse disponible.

    <span style='font-size: 20px'>
        <?= (isset($resultado)) ? $resultado : ""; ?>
    </span>

Finalmente se muestra la representación en cadena (recordar el método toString del modelo) de la tarea realizada.

    <span style='font-weight: bolder;'>Operación: </span>
    <?= $calc -> toString(); ?> =
    <?= (isset($resultado)) ? $resultado : ""; ?>

Nótese como a lo largo de la vista se hace referencia al objeto $calc para obtener la información de la calculadora.  Este objeto es enviado desde el controlador cuando se le hace el render a la vista.  Igual sucede con la variable $resultado la cual, en este caso, sólo es enviada cuando el procesamiento de la operación es exitoso.

Acceder a la aplicación.

Utilizando un navegador web se debe acceder a la siguiente ubicación.

http://hostname/SimpleCalc/index.php?r=calculadora/index

Presentación final de la aplicación.
Presentación final de la aplicación.

11 thoughts on “Mi segunda aplicación con Yii: Calculadora Simple”

  1. Aunque sea bastante simple, me viene de perlas, por que la documentación para este framework no es que abunde.

    Sigues usando yii? lo recomiendas?

    Un saludo

    1. Saludos @Jesús. Te cuento que estoy en el proceso de aprender Yii, de a poquitos y con poco tiempo libre. Aún no lo he utilizado en un proyecto; sigo utilizando CodeIgniter y Kohana por ahora pero me parece que Yii es una muy buena alternativa.

      Tienes razón con respecto a la documentación de Yii, es escasa por ahora y a pesar de que el libro y el ejemplo del blog son muy buenos son demasiado específicos y por ahora me dejan muchas dudas por resolver antes de utilizar el framework en algo mas grande. Por ahora estoy estudiando el libro y haciendo algunos experimentos. En el blog podrás encontrar el registro de mis lecturas en las cuales resumo lo mas importante de la documentación.

      http://blog.jorgeivanmeza.com/tag/yii/

  2. hola cuando ejecuto el comando
    >> model Calculadora
    no me pasó de hay porque me dice que no puedo dejar mi cadena de conexión vacía, mi pregunta es como hiciste para pasar este paso si el ejemplo no le veo BD.

    gracias

  3. Saludos @johnny. Aparentemente este comportamiento del “yiic shell” fue modificado. Con la versión con que desarrollé el ejemplo se limitaba a presentar una advertencia, sin embargo probé el script con la última versión disponible (yii-1.0.8.r1317) y sucede lo que mencionas: termina con error por la falta de ConnectionString. Supongo que según esto los CFormModels deberán crearse a mano sin la ayuda del yiic.

  4. hola acabo de realizar este ejemplo en mi instalacion local de yii pero no me saca el formulario,yo copie todo tal como lo colocaste aca.

    me imprime has un pedazo de codigo

    toString(); ?> =
    ‘+’,’-‘=>’-‘,’*’=>’*’,’/’=>’/’)); ?>

    , no se cual es el error me podrias ayudar soy nuevo con este framework

    1. Saludos @andres. Debes tener un problema con tu código. Revisa la vista, probablemente te esté quedando mal la apertura/cierre de una sección de código PHP.

  5. saludos @jimezqm. revizando el codigo de la vista estaba bien , lo unico es que tenia que escribir completa la etiqueta de php y ya con eso me funciono bien. gracias.

  6. Me parecio un muy buen ejemplo lo hice y no me daba ningun resultado hasta que hice un var_dump del post y descubri que en el controlador estaba ‘Calculadora’ con la primera mayuscula y lo que le mandaba era ‘calculadora’ con minuscula la cambie y funciono bien

    gracias por el ejemplo

  7. tengo un problemilla me sale un error
    render(‘index’, array(‘calc’ => new Calculadora()));
    }
    public function actionOperar()
    {
    $calculadora = new Calculadora();
    if(isset($_POST[‘Calculadora’]))
    {
    $calculadora -> attributes = $_POST[‘Calculadora’];
    if($calculadora -> validate())
    {
    // Exito
    $this -> render(‘index’, array(‘calc’ => $calculadora,
    ‘resultado’ => $calculadora -> operar()));
    exit;
    }
    }
    // Fracaso
    $this -> render(‘index’, array(‘calc’ => $calculadora));
    exit;
    }
    ?>

Leave a Reply

Your email address will not be published. Required fields are marked *