viernes, 15 de febrero de 2013

Clases y Tablas - Por qué no son lo mismo.

Clases y Tablas, Por qué no son lo mismo.


Siempre le insistido a quienes me leen en el Blog (o grupo de Yii en Español) que no es lo mismo "Tabla" que "Clase", sin embargo a veces recibo respuestas de algunas personas que se molestan y defienden a ciegas aquella idea de que "son lo mismo".

Normalmente siempre empiezo por insistir que: "No es lo mismo crear una Arquitectura de Clases, que crear Una Clase con 500 métodos", en este último caso, luciendose de haber hecho un programa de 20.000 lineas que solo él y dios sabrán como funciona.  Por contraparte, la Arquitectura de Clases es delicada, es toda una dama.

Es incorrecto pensar que una Clase, por el hecho de tener atributos igual que una Tabla es entonces inmediatamente "emparejable con una tabla de base de datos". Es un terrible concepto arraigado por la falta de análisis y por el hecho de programar a ciegas.

La Clase es la "idea" maestra, el concepto, mientras que la "tablita de base de datos" es solo una artimaña tosca para guardar la información de la clase.  De aqui que siempre digo que es un error diseñar un sistema pensando en el modelo de base de datos (el diagrama de tablas, el diagrama de entidad-relación).


No siempre una clase es almacenada en una "tabla"

No siempre una "tabla" representa a la Clase, No siempre una tabla representa a una Relación y finalmente no siempre una tabla representa a una Entidad.

Cuales son las diferencias entre Clases de Asociación y Entidades. Concepto.

Caso de Ejemplo de Diseño UML:
Antes de explicar mas abajo necesito que tengas claro este ejemplo de caso de negocio, para que comprendas mejor el diagrama que está mas abajo y los conceptos de Clase-Entidad y Clase-de-Asociación.

"Una persona quiere laborar como agente de ventas para una empresa de RealtyRentals, se le denomina El Agente (primer sustantivo detectado en la conversación). Para poder laborar en la empresa, este Agente necesita adquirir un Plan (segundo sustantivo), este Plan se le cobra mensualmente y le permite realizar ciertas operaciones de acuerdo a su pago (no detallaré qué y cómo, no viene al caso, sino enredamos el ejemplo).  Adicionalmente, este Agente querrá publicar información en su propio website privado, por lo tanto le daremos una LLave de Acceso (tercer sustantivo) para que a través de ella pueda leer recursos web en su propio website.  Esta Llave de Acceso se paga también mensualmente pero separado del pago del Plan de membresía"

Una Clase-Entidad representa a una Entidad, a un objeto Real
Se reconocen por ser un SUSTANTIVO en las conversación con el cliente. De ahí el hecho de que el análisis UML haga énfasis en anotar cuales sustantivos usa el cliente durante su conversación contigo como analista. Por ejemplo: El Agente. Es una clase-entidad porque representa a un ser humano operando como agente de ventas en un negocio. El arte de UML está en saber oir: cuales sustantivos son una real basura y cuales son valiosos.

Una Clase de Asociación. 
Es también una clase, pero enfocada a relacionar dos Clases-Entidad.  Representa la forma en cómo dos objetos se relacionan. Por ejemplo, informa de la relación que ocurrirá cuando el Agente seleccione un Plan.  Ambos Agente y Plan son Clases-Entidades, mientras que La Relación sería: "La historia de Planes adquiridos por El Agente en el Tiempo y Soportados por un Pago"....no adivinaste? "EL INVOICE".

Una Clase de Asociación tiene un diagrama UML específico.
Se representa así como muestro aca abajo: una linea punteada terminando en  flecha que apunta a la linea recta entre las dos entidades a ser relacionadas, indicando que: "La factura guarda la relacion entre las entiadades: el Plan y el Pago".



La relación XY

Siempre hago referencia a que un diagrama XY (la relación XY) que incluye clases-entidad y clases-de-asociación se llama: "Relación XY", porque XY representa la asociación entre la clase X y la Y.

Explicando el Diagrama de Clases



La clase-entidad "AgentPayment" se relaciona con otra clase-entidad "AgentPlan" mediante la clase de asociación: "AgentPlanInvoice".  AgentPayment es independiente es un pago, es único, igual que AgentPlan, son clases simples, que representan una entidad.

AgentPlanInvoice informa cómo estas dos se relacionan (el pago a un plan), no es un objeto "físico" como las primeras, sino es un paso en el tiempo.  AgentPlanInvoice es una Factura que le damos al Agente por querer contratar el AgentPlan seleccionado, esa factura le da acceso por tiempo limitado a usar el sistema.

Verás que también tenemos ResourceKeyInvoice, que según el requisto del cliente (arriba) le da derecho al agente de tener una "llave de recursos web" para que pueda insertar contenido web en el propio website del Agente.

Extensión de Clases

El objeto de mostrar esta extensión aquí es demostrar que no siempre una "Clase" se almacena igual que una  "Tabla".

La extensión aquí se requiere porque AgentPlanInvoice y ResourceKeyInvoice derivan o extienden su funcionalidad de una clase abstracta llamada Invoice que agrupa cosas comunes entre estas, es abstracta porque no puede usarse así "a rin pelao"...(yo soy un invoice !!!,  de quien ? de que tipo ?).

El Invoice (La Factura) le provee a sus clases extendidas la funcionalidad e incluso atributos, podriamos tener en esta clase base (Invoice) un método llamado: "sendByEmail()" el cual enviará este invoice al Agente por correo, sea "de clase" ResourceKey o "de clase" AgentPlan. El símbolo UML para denotar la extensión es la flecha con cabeza blanca sólida.

¿ Cómo almacenar las clases en un modelo de datos ?

He aquí el guiso. Y He aquí porqué siempre digo que hacer el sistema empezando el diagrama de datos es siempre un error que viene de vieja escuela y de fundamentos teóricos oxidados y mal formados, en su mayoría hecho asi por comodidad y por el hecho de no profundizar en el Análisis de Sistemas.

AgentPlanInvoice y ResourcePlanInvoice estan diagramados en dos clases distintas, eso lleva a pensar al diseñador de software que deben ir en dos "tablas" separadas.....de nuevo...esta malo. Una cosa es: Diagramado UML, diagramado de Negocio, otra "diagramado de datos".

En este ejemplo no se requieren dos "tablas" separadas para almacenar a AgentPlanInvoice y ResourceKeyInvoice, sino solo una.  Esto demuestra la razón de mi insistencia. Podrias almacenar AMBAS CLASES en una sola tabla asi:

"AgentInvoice" { agentId, invoiceType,  invoiceNumber, invoiceTotal, expirationDate, creationDate }

Ahora, será tarea de la clase base Invoice, leer un registro de LA TABLA "AgentInvoice" y entregar en consecuencia un objeto de clase AgentPlanInvoice o de ResourceKeyInvoice, según indique el registro de base de datos.

Ahora te habrás dado cuenta que aunque el diagrama UML habla de tres clases (Invoice, AgentPlanInvoice y ResourceKeyInvoice) estas se almacenan en una sola, y no las tres, sino solo dos, ya que Invoice es abstracta.

"El análisis produndo de software es el camino al buen software"


viernes, 1 de febrero de 2013

tutorial mínimo de yii




En el pasado...

En tu antigua app hecha en PHP tu seguramente habras tenido piezas de codigo, funciones y demas cosas accesibles directamente asi:

http://miapp/cosa/mas/otra/crearorden.php

Eso es totalmente inseguro, a menos que tengas muchas reglas internas y mucha protección, pero si no es asi, estaras dispuesto a aceptar que cualquier que analice uno de tus form sepa cual es la accion a donde ese form va a enviar un POST y te bombardearán.

Yii framework te da una CAPA DE PROTECCION para que la única manera de acceder a ese mismo recurso "crearorden" se haga solo mediante una URL y pasando previamente por un punto de control: EL CONTROLADOR.

Aqui entramos a hablar de MVC. Model, View y Controller.

En tu antiguo sistema, tu guardabas tu informacion en tu base de datos, seguramente desde una consulta SQL horrorosamente igual a esta:
"insert into orden(...campos...) values(...y valores aqui...)";
Eso tambien es inseguro, propenso a inyección SQL, y peor aun inmanejable y dificilmente exportable.

El MODELO

Yii Framework te provee el MODELO para gestionar facilmente objetos persistentes (cosas que se guardan en una "tabla"), el modelo es una representacion de una TABLA (Orden.php), el modelo es algo mucho mas avanzado en términos de modelado UML, pero para no enredar el papagallo aqui vamos a simplificarlo solo a una "tabla", que en realidad no se llama "tabla" sino "relacion".

Supon que tienes:


Código:
$orden = new Orden();
$orden->idorden = '123-ABC';
$orden->total = 1000;
$orden->cliente = "nombre del cliente";
// ok..simplemente usando las clases base
// que Yii te provee podrás hacer:
$orden->insert();
y listo...la cosa se guardo en la base de datos. Simple. 

Esto se llama: 
CActiveRecord. Conseguiras muchos ejemplos en el foro y en la documentacion de Yii.
Dónde guarda Yii los modelos ? En protected/models.
Cómo se accede a ese modelo ? Directamente no....sigue leyendo tigre...

LA VISTA

La vista es la forma de presentar información, no hay lógica de negocios en las vistas, la lógica se la das a UN COMPONENTE o a ciertos ACTIONS (lee mas adelante), pero nunca a las vistas.

Mi papa siempre decía: "cuando se calcula..se calcula, cuando se imprime..se imprime". Eso significa que "o cantas o silbas"....y traduciendo a codigo: O muestras o calculas...pero no ambas.

La vista se aloja en /protected/views/<controllername>/nombrevista.php

Porque dentro de un <controllername> ? Para ordenar, nada mas, desde cualquier parte puedes acceder a cualquier vista, pero este esquema ayuda a ordenar.

Cómo accedo a una vista ? 
Desde un ACTION, el cual explico mas abajo.

Qué hago en una vista ?
Mostrar el modelo, mostrar tablas, imprimir html. Podria recomendarte esta extension para escribir en una vista:
http://christiansalazar.github.com/jamboree/

EL "CONTROLLER" y EL ACTION

Por fin aqui no ? Bueno, esta es la "pega" que une el modelo con la vista. Es tambien el punto de entrada, en programacion orientada a EVENTOS (como lo es YII) esto se considera un ENTRYPOINT (del viejo esquema C en donde una funcion main() es la encargada de iniciar el programa).

Si ya creaste un modelo Orden.php y ya tienes una vista "protected/views/orden/ver.php" entonces ahora querras acceder a esta vista para ver el modelo (cual modelo ? el que seleccionaremos en el controller en base a los argumentos de la URL).
Código:
http://www.miapp.com/tuapp/index.php?r=orden/ver&idorden=123

Explico la forma de esa URL para Yii Framework:


"r=orden/ver" es la forma de decirle a Yii que vaya a la controladora "ordenController.php" localizada por defecto en "protected/controllers", y que en esa clase busque el ACTION "ver". Habrás pensado que cuando puse "ver" en la url haya sido respecto a la vista "/protected/views/orden/ver.php" pues no, es el action dentro de ordenController.php.


¿ Cómo se pone ese action en ordenController.php ?


asi: Editas /protected/controller/ordenController.php y dentro escribes:

Código:
<?php
public function OrdenController extends CController {
    public function actionVer($idorden){
        $model = Orden::model()->findByPk($idorden);
        if($model != null){
           $this->render("ver", array('laorden'=>$model));
        }else{
           throw new CHttpException(404, "orden no hallada");
        }
    }
}
?>

Fíjate que es dentro de actionVer en donde se invoca al modelo segun el argumento de la URL, para entonces finalmente pedirle al controller que haga una presentacion de la vista "
ver.php" ( render('ver') ), la cual "se asume que" estara localizada en:
protected/views/orden/ver.php. Pestale cuidado a por qué puse la palabra "ver" en color rojo.

El layout

Es importante, es quien da el marco html para que dentro de el se presenten las vistas, habras asumido que no tendrás que poner en cada vista el cintillo...el banner..el sidebar...estas en lo cierto. Eso lo hace el layout, veras que cada controller puede tener un atributo llamado "layout", que por defecto puede ser:
public $layout = '\layouts\main'; eso le dice a Yii que para renderizar las vistas del controller lo haga usando el layout localizado en protected/views/layouts/main.php, el cual a su vez veras que incluye otros mas, pero eso es tema mas avanzado, aqui quiero que conozcas la base sin muchos detalles.

Muy Importante:  Dónde se presenta la vista en un Layout ?

En Yii hay una variable clave llamada $content.   En donde esa variable se ponga será allí en donde la vista se dibuje.

Fíjate este ejemplo, podria estar perfectamente ubicado en:  tuapp/protected/views/layouts/prueba.php, y para que Yii lo use para renderizar una vista hay que mencionarlo en el controller en el atributo $layout.

<html>
   <body>
         <span>Aqui va el cuerpo: </span>
         <div><?php echo $content; ?></div>
   </body>
</html>

Lo que hará será incrustar allí (donde este $content) el contenido de aquella vista que en un controller qusimos "renderizar" usando una llamada a $this->render('ver');

Cómo funciona YII

1) Tu usuario pone en el browser:  http://website.com/cosa/index.php?r=site/prueba

2) El archivo index.php recibe el request (siempre lo hace, jamas otro script recibe el foco).

3) El core de Yii levanta tu archivo de config indicado en index.php y de éste se incializa.

4) Levanta a:  protected/controllers/siteController.php.  (sensible a mayusculas minusculas).

5) Busca el método: "public function actionPrueba" y lo ejecuta.

6) Si la URL incluye argumentos como: &cedula=123&nombre=christian, se los pasará como argumentos al método actionPrueba, por tanto si esperas esos argumentos, ponlos en el método asi:
public function actionPrueba($cedula="", $nombre="").
(nota el ="" detras de cada argumento, eso dice que son opcionales, si no lo pones así entonces ocurrirá una excepción si el usuario no los indica en la URL).

7) En el método actionPrueba es donde tu actuas.  Podrias levantar un modelo cualquiera asi:
public function actionPrueba($idproducto){
   $p = Producto::model()->findByPk($idproducto);
   if($p != null){
      $this->render('producto', array('cosa'=>$p));
   }
}

8) Siguiendo el ejemplo del paso 7, has indicado que quieres renderizar la vista "producto":
"/protected/views/prueba/producto.php", eso es debido a que en el paso 7 solo pusiste "producto" sin ruta, (si quisieras indicar la ruta de otra vista pondrias:
"applications.views.otrolado.detalle", eso usaría la vista: "protected/views/otrolado/detalle.php")

9) La vista "producto.php" es levantada del disco, y se le entregan variables PHP, cuales variables ? las que le diste en el paso7 mediante un array, por tanto dentro de la vista producto.php puedes escribir esto:
<?php
   echo "has invocado a la vista. el objeto entregado por el controller es: "
      .$cosa->idproducto.", ".$cosa->nombreProducto;
?>

10) Cuando en el paso 7 llamaste a render, Yii le dio a tu vista unas variables, las has usado para crear la vista y ahora sera insertada en el Layout.  Yii va a levantar el Layout indicado en el controller, según la variable indicada:

public function siteController extends CController {
    public $layout = "mi-layout";
    ...
}

Se usara al achivo:  protected/views/layouts/mi-layout.php,  Yii cargará toda la vista recien renderizada en el paso 9 en una variable especial llamada: $content la cual tu vas a poner en algun lado del layout: literalmente donde te de la gana:

<!-- contenido del archivo: protected/views/layouts/prueba.php -->
<html>

   <body>
         <span>Aqui va el cuerpo: </span>
         <div>
<?php echo $content; ?></div>
   </body>
</html>

(el texto de color "verde" es lo que se repetirá siempre, no importa cual vista estes renderizando, siempre que incluyas este layout en tu controladora)

11) El resultado del paso 10 será entregado al browser del cliente, el cual dirá:

<html>
   <body>
         <span>Aqui va el cuerpo: </span>
         <div>has invocado a la vista. el objeto entregado por el controller es: 123, Arroz</div>
   </body>
</html>





EL COMPONENTE

Cómo hacer un componente. Lee eso.

basicamente un componente aloja la lógica de negocios, yo le llamo un "API" porque es la libreria de funciones core de tu aplicacion. Hay cosas que necesitas en varias partes de la aplicacion, esas "cosas que van en varias partes" que son "reutilizables" son parte del "core" de tu aplicacion, y deben estar localizadas en un punto de comun acceso para toda la app, no abuses del componente, lo hagas un desastre, úsalo pero sin abuso.
Se usa asi:
Código:
Yii::app()->micomponente->calcularNomina($idempleado);

Esa funcion de negocios puede ser llamada desde cualquier parte de tu app, va a centralizar el proceso de calculo de de nomina de un empleado.


Y por qué no va en la clase Empleado Christian..??!! (me lo han gritado), Porque este tipo de funciones de negocio involucra muchas otras clases y no solo al Empleado, invoulcra además a la Nomina, al HoarioLaboral, al TurnoQueCumple, a muchas otras clases, entonces para no adivinar en cual de esas otras debe ir...va afuera, en un API.

Dejare el tema hasta aqui. Creo ser suficientemente claro para darte un inicio en Yii.
Suerte