martes, 3 de mayo de 2016

PHP - Carrito de Compras Parte I - Creación de la Base de Datos

1. Entorno

  • NetBeans IDE 6.9.1
  • WampServer 2.1.

2. Introducción

En el siguiente tutorial vamos a desarrollar un carrito de compras o lo que seria un sistema de ventas usando el lenguaje de programación PHP, como base de datos vamos a usar el MySQL 5.1. y tambien crearemos un reporte en formato excel de las ventas. La base de datos que vamos a crear es una base de datos con fines didácticos, dado que nos faltaría crear mas tablas, como la tabla cliente, categoría, unidad de medida, etc pero si nos explayamos mucho nos quedaría muy largo el tutorial. Ademas en el ejemplo no se explica como disminuir un stock, debido a que eso siempre se les pide a los alumnos universitario que investiguen como hacerlo, pero si quieren una ayudita lo pueden hacer creando Triggers en la base de datos. La aplicación se desarrollara en un formato web usando el modelo de Programación en Capas.
Para poder ejecutar el MySQL debemos de tener instalador el WampServer 2.1. en nuestra computadora.

3. Desarrollo

La base de datos tendría las siguientes tablas. Venta, Producto y DetalleVenta 

https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTHuiVqabF1F4_bIU01JRmQ0awlgtCzMquQPvOen1vrx-DhugA627haT1qCb1RL8RZ-WxvpCpAruroTnlkPREnXMygyYSoAkMlqsYEl4kO3-uK9pJYPS7wYt4ddSOvcw16o9yGl1Ed2bM/s1600/diagrama.png
A continuación les paso el script de creación de la base de datos


-- CREADO POR: HENRY JOE WONG URQUIZA
-- FECHA: 24FEB2011
-- ------------------------------------------------------
-- TUTORIAL DE COMO HACER UN CARRITO DE COMPRAS USANDO
-- EL MODELO VISTA CONTROLADOR
--
-- Creando la base de datos
--

CREATE DATABASE IF NOT EXISTS bdtutorial;
USE bdtutorial;

--
-- Creando la tabla `detalleventa`
--

DROP TABLE IF EXISTS `detalleventa`;
CREATE TABLE `detalleventa` (
  `codigoVenta` int(11) NOT NULL,
  `codigoProducto` int(11) NOT NULL,
  `cantidad` decimal(18,2) NOT NULL,
  `descuento` decimal(18,2) NOT NULL,
  PRIMARY KEY  (`codigoVenta`,`codigoProducto`),
  KEY `FK_DetalleVenta_Producto` (`codigoProducto`),
  CONSTRAINT `FK_DetalleVenta_Producto` FOREIGN KEY (`codigoProducto`) REFERENCES `producto` (`codigoProducto`),
  CONSTRAINT `FK_DetalleVenta_Venta` FOREIGN KEY (`codigoVenta`) REFERENCES `venta` (`codigoVenta`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Creando la tabla `producto`
--

DROP TABLE IF EXISTS `producto`;
CREATE TABLE `producto` (
  `codigoProducto` int(11) NOT NULL,
  `nombre` varchar(100) NOT NULL,
  `precio` decimal(18,2) NOT NULL,
  PRIMARY KEY  (`codigoProducto`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Creando la tabla venta
--

DROP TABLE IF EXISTS `venta`;
CREATE TABLE `venta` (
  `codigoVenta` int(11) NOT NULL,
  `cliente` varchar(100) NOT NULL,
  `fecha` datetime NOT NULL,
  PRIMARY KEY  (`codigoVenta`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

El Patrón MVC en PHP - Parte III

El controlador
El controlador, aunque muchos de ustedes no lo crean, es quien tal vez, lleva “la peor parte”. En muchas ocasiones, es complicado programar el controlador de manera previsible para que pueda evolucionar, y generalmente, es sometido a refactorizaciones constantes, incluso mayores que las que puede sufrir el modelo.
Recordemos que el controlador, es quien debe interactuar con el modelo y con la vista.
Para hacerlo, deberá previamente reconocer y manejar los distintos eventos del usuario, para saber:

1. A qué modelo / modelos invocar
2. Qué y cuáles propiedades o atributos del modelo/modelos modificar o parámetros deberá entregar a sus métodos
3. A qué vista entregar la información

¡Pobre hombre! Le toca una tarea extenuante. Veamos paso a paso, como ayudar a este pobre “controller-man” en su tarea.

Supongamos entonces, que tenemos dos modelos:

Archivo models.php
 
class ModeloUno {
   var $propiedad;
   function a($parametro) {
      $this->propiedad = $parametro;
  }
}

class ModeloDos {
   var $propiedad_1;
   var $propiedad_2;
   function b($param1, $param2) {
      $this->propiedad_1 = $param1;
      $this->propiedad_2 = $param2;
   }
}

Y a la vez, tenemos dos vistas:

Template vista_1.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="es">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Vista Modelo 1</title>
</head>
<body>
<div id="page">
   <p>El valor de la <b>propiedad</b> es <b>{propiedad}</b></p>
</div>
</body>
</html>
 
Template vista_2.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="es">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Vista Modelo 2</title>
</head>
<body>
<div id="page">
  <p>El valor de <b>propiedad_1</b> es <b>{propiedad_1}</b> mientras que el de    <b>propiedad_2</b> es <b>{propiedad_2}</b></p>
</div>
</body>
</html>

Y la lógica de éstas, es la siguiente:

Archivo view.php

function set_identificadores($vista) {
   $identificadores = array();
   if($vista) {
      switch ($vista) {
         case 'vista_1':
            $identificadores = array('propiedad');
            break;
         case 'vista_2':
            $identificadores = array('propiedad_1', 'propiedad_2');
            break;
      }
      return $identificadores;
   }
}

function armar_diccionario($vista, $data) {
   $diccionario = array();
   $identificadores = set_identificadores($vista);
   if($identificadores) {
      foreach ($identificadores as $identificador) {
         if(array_key_exists($identificador, $data)) {
            $diccionario[$identificador] = $data[$identificador];
        }
      }
   }
   return $diccionario;
}

function render_data($vista, $data) {
   $html = '';
   if(($vista)&&($data)) {
      $diccionario = armar_diccionario($vista, $data);
      if($diccionario) {
         $html = file_get_contents('html/'.$vista.'.html');
         foreach ($diccionario as $clave=>$valor) {
            $html = str_replace('{'.$clave.'}', $valor, $html);
         }
       }
   }
   print $html;
}

Entonces, nuestro controlador procederá de la siguiente forma:

Primer paso:
identificar el modelo

Para esto, el controlador previamente, tendrá que reconocer el evento que ejecuta el usuario y saber como manejarlo. Para ello, la forma de pensarlo “informáticamente” sería:

si usuario [evento] entonces [realizar acción]

En nuestro caso, los eventos admitidos, serán llamdas por URL mediante el método $_GET.
Primero, identificará el evento respondiendo a las siguientes preguntas:

• ¿existe el evento de llamada mediante “$_GET”?
• Si existe ¿a qué evento, el usuario, quiere que responda?

Para esto, utilizará la siguiente función:

function capturar_evento() {
   $vista = '';
   if($_GET) {
      if(array_key_exists('vista', $_GET)) {
         $vista = $_GET['vista'];
      }
   }
   return $vista;
}

Devolviendo así, el evento capturado a través de la variable “$vista”.
Con el evento “en la mano”, se ocupará ahora de identificar el modelo:

function identificar_modelo($vista) {
   if($vista) {
      switch ($vista) {
         case 'vista_1':
            $modelo = 'ModeloUno';
            break;
         case 'vista_2':
            $modelo = 'ModeloDos';
            break;
         default:
            exit();
      }
   }
   return $modelo;
}

Segundo paso: invocar al modelo efectuando los cambios adecuados
Nuestro controlador, ya sabe a que modelo recurrir. Ahora, solo resta invocarlo y modificarlo si es necesario:

function invocar_modelo($modelo) {
   if($modelo) {
      require_once('models.php');
      $data = new $modelo();
      settype($data, 'array');
      return $data;
   }
   #las modificaciones al modelo se harían aquí
}

Tercer paso:
enviar la información a la vista

Finalmente, nuestro controlador, enviará la información obtenida del modelo, a la vista.
Para hacerlo, utilizará una función donde preparará esta información para al fin enviarla:

function enviar_data() {
   $vista = capturar_evento();
   if($vista) {
      $modelo = identificar_modelo($vista);
      if($modelo) {
         $data = invocar_modelo($modelo);
         if($data) {
            require_once('view.php');
            render_data($vista, $data);
         }
      }
   }
}

El controlador, solo deberá llamar a su propia función enviar_data() y la vista automáticamente, estará en condiciones de mostrar los resultados en pantalla al usuario:  
enviar_data();

Si el usuario ingresara en la URL http://servidor/controller.php no verá nada en pantalla.
Si ingresara en http://servidor/controller.php?vista=vista_2 verá lo siguiente: