martes, 21 de febrero de 2012

Creación de un carrito de compras con PHP, POO y MYSQL...!

Bueno este es mi primer post y espero que les sea de buena utilidad.
A continuación veremos como se crea un carrito de compras usando PHP5, POO y MYSQL.
Al final del post se encontrará el link para descargar el código completo y la BD.

Primero que nada necesitaremos crearnos un par de tablas que vamos a trabajarlas.
Ahi la estructura de las tabla.(Las tablas la encontraran en el archivo adjunto de abajo.)


EMPEZEMOS:

1.Crearemos la clase Conexion: Conexion.class.php

<?php

class Conexion{
     private $hilo;       //Variable para retornar el valor de la conexion.
     private $resultSet;   //Variable para retornar el valor de la consulta.

     //Función que se ejecutará ni bien se haya instanciado en objeto Conexión.
     public function  __construct($server = '127.0.0.1',
                                            $username = 'root',
                                            $password = '',
                                            $database = 'carrito') {
        //Nos conectamos  la BD
        $this->hilo = mysql_pconnect($server,$username,$password);
  
        //Si en caso haya fallado la conexión a la BD mostramos un mensaje de error.
        if(!$this->hilo){
            die('No se pudo conectar a la Base de Datos:' . mysql_error());
        }

       //Si en caso no se ha podido acceder a la BD mostramos un mensaje de rror
        if(!mysql_select_db($database,$this->hilo)){
            die('No se pudo conectar a la BD '.$database.':'.  mysql_error());
        }
    }

    //Esta función nos permitirá ejecutar cualquier tipo de consulta Select, Insert, Update o Delete
    public function ejecutar($sql){
        $this->resultSet=mysql_query($sql);   //Si sale bien.

        if(!$this->resultSet){     //Si hay un error.
            die('No se pudo realzizar la consulta:<br />'.$sql.'<br />'.  mysql_error());
        }

        return $this->resultSet;  //Retorna el valor obtenido de la consulta.
    }

   //La función desctructor se ejecutará una vez terminado todo el script y cerrará la conexión
    public function  __destruct() {
        if(!$this->hilo)mysql_close($this->hilo);
    }

}
?>

2. Pasamos a crear la clase: Producto.class.php
//Se le asignara los atributos correspondientes
<?php

class Producto{
    //Atributos
    public $codpro;
    public $nompro;
    public $prepro;
    public $cantidad;


    //Constructor se ejecutará una vez instanciado al Objeto(recibirá 3 parámetros codpro,nompro y prepro)
    public function  __construct($c,$n,$p) {
        $this->codpro=$c;
        $this->nompro=$n;
        $this->prepro=$p;
        $this->cantidad=1;    //Se le asignara un valor por defecto 1.
    }
  
   //Metodo que nos permitirá calcular el precio Total por cada producto insertado al carrito
    public function precioTotal(){
        //Se aplica un formato para números con 2 decimales. 
        return number_format($this->prepro*$this->cantidad, 2, '.', '');
    }
}
?>

 3.Pasamos a crear la clase: Carrito.class.php
<?php

class Carrito{
    public $codigo;     //atributo codigo de carrito
    public $productos;        //atributo productos, contendra todo los productos seleccionados al carrito

    function  __construct($id) {
        $this->codigo=$id;
        $this->productos=array();   //instanciamos el atributo productos l ista para ser llenado de productos
    }

    //Indico el codigo y recupero un producto si es que existe en el carrito
    public function obtenerProducto($codigo){      
        foreach($this->productos as $indice => $producto){
            if($producto->codpro==(int)$codigo){
                return $producto;
            }
        }
        return null;
    }

    //Actualiza la cantidad de items para un mismo producto que ya existe en el carrito
    //En caso existe el mismo producto que se quiera insertar al carrito la cantidad suma +1
    public function actualizarCantidad($codigo,$cantidad){
        foreach ($this->productos as $indice => $producto){
            if($producto->codpro==(int)$codigo){
                $producto->cantidad +=$cantidad;
            }
        }
    }

    //Agrego o actualizo su cantidad de un producto al carrito
    public function agregarProducto($producto){
        //Busco el producto si ya fue insertado
        $yaIncluido = $this->obtenerProducto($producto->codpro); //Buscará si existe el producto
        if($yaIncluido){
            $this->actualizarCantidad($producto->codpro, 1);  //Busco y actualizo el producto
        }else{
            $this->productos[]=$producto;             //Agrego un nuevo producto al carrito
        }
    }

    //Calcular el monto total de los productos
    public function calcularMonto(){
        $monto = 0;
        foreach($this->productos as $indice => $producto){
            $monto += $producto->precioTotal();
        }
        return number_format($monto, 2, '.', '');
    }
   
   //Nos permitirá calcular la cantidad total de productos insertados al carrito
    public function calcularCantidad(){
        $cantidad = 0;
        foreach($this->productos as $indice => $producto){
            $cantidad += $producto->cantidad;
        }
        return $cantidad;
    }

    //Calcular descuento segun cantidad total.
    public function calcularDescuento(){
        $cantidad = $this->calcularCantidad();
        if($cantidad > 1000){
                return 20;
        }else if($cantidad > 100){
                return 10;
        }else if($cantidad > 3){
                return 2;
        }else
           return 0;
    }

    //Calcular precio total, con el montoTotal y el descuento.
    public function calcularPrecioTotal(){
        $total=$this->calcularMonto()*(100 - $this->calcularDescuento())/100;
        return number_format($total, 2, '.', '');
   }


   //Eliminar producto del carrito por su codigo
   //En este caso lo que hacemos es recorrer los productos, luego preguntamos si el código de producto
   //es diferente al código que estamos mandando, si es así entonces llenaremos los productos  en un nuevo
   //arreglo $pro2, luego de eso reemplazamos el atributo productos por el valor del arreglo $pro2.
   public function eliminarProducto($codigo){
       $pro2 = array();
       foreach ($this->productos as $indice => $producto){
            if($producto->codpro!=(int)$codigo){
               $pro2[]=$producto;
            }         
        }
        $this->productos=$pro2;  //Reemplaza por el valor del arreglo
   }

   //Actualizar cantidad ingresada.
  //Este metodo lo que hace simplemente es reemplazar la cantidad del producto por uno ingresada.
   public function actualizarCantidadIngresada($codigo,$cantidad){
        foreach ($this->productos as $indice => $producto){
            if($producto->codpro==(int)$codigo){
                $producto->cantidad =$cantidad;     //Reemplaza la cantidad existente en el producto
            }
        }
    }
  
}
?>

 4.Pasamos a crear la clase: ProductoDAO.class.php
<?php
//Incluimos las 2 clases necesarias para realizar la consulta. a la BD.
require_once ('Producto.class.php');
require_once ('Conexion.class.php');


class ProductoDAO{
    public $conexion;         //Variable que contendra el resultado de la conexion

    public function  __construct() {
        $this->conexion = new Conexion();  //Instanciamos el metodo Conexion de la clase Conexion.class.php
    }

    //Recupero en un array todos los productos en forma de objetos de la base de datos
    public function obtenerProductos(){
        $productos =  array();

        $result = $this->conexion->ejecutar("select codpro, nompro, prepro from producto");
        while($array = mysql_fetch_array($result)){
            //Creo una instanacia de producto y lo almanceo en el array
            $productos[] = new Producto($array['codpro'],$array['nompro'],$array['prepro']);
        }
        return $productos;
    }

    //Recupero un producto de foma de objeto de la base de datos indicandole su código

    public function obtenerProducto($codigo){
        $producto = null;
        $sql = "select codpro, nompro, prepro from producto where codpro=".  mysql_escape_string($codigo);
        $result = $this->conexion->ejecutar($sql);;
        if($array =  mysql_fetch_array($result)){
            //Creo una sola instancia que será devuelta..
            $producto = new Producto($array['codpro'],$array['nompro'],$array['prepro']);
        }
        return $producto;
    }

   //Funcion para guardar una Factura y su Detalle, recibirá como parámetros.
   //$productos - que contndra todos los productos agregados al carrito
   //$mon - El monto total de todo los productos
   //$des - El descuento total de todos los productos
   //$tot - El total de todo los productos
    function guardarFactura($productos,$mon,$des,$tot){

        //Autocommit = 0
        mysql_query("SET AUTOCOMMIT=0;"); //Para InnoDB, sirve para mantener la transaccion abierta
       
        //Inicio de transacción
        mysql_query("BEGIN;");
       
        //Operaciones en la Factura
        //Para este usaremos el codigo de 1 cliente
        $sql = "insert into factura (codcli,facfec,facmon,facdes,factot) ";
        $sql .= "values (1, now(),$mon,$des,$tot)";
        $rs =$this->conexion->ejecutar($sql);
       
        if(!$rs){
            echo "Error en la Transacción: ".mysql_error();
            mysql_query("ROLLBACK;");           //Terminar la transaccion si hay error
            exit();
        }
       
        //Recuperamos  el ID generado en el insert de la tabla "factura"
        $facnum = mysql_insert_id();

        //Recorremos e insertamos todos los productos a la tabla facdeta, todos con el mismo Id.       
        foreach($productos as $producto){
            $sql1 = "INSERT INTO facdeta(codpro,facnum,cantidad,precio,total)";
            $sql1 .= "values ($producto->codpro,$facnum, $producto->cantidad,$producto->prepro,{$producto->precioTotal()})";
            $rs = $this->conexion->ejecutar($sql1);
            if(!$rs){
                echo "Error en la Transacción: ".mysql_error();
                mysql_query("ROLLBACK;");    //Terminar la transaccion si hay error
                exit();
            }
        }

        if ($rs) {
            mysql_query("COMMIT");      //Terminar la transaccion
        }
    
        return $facnum;  //Retornamos el id
    }

}
?>

5. Por último tenemos en index.  Acá se hará todas las transacciones..

<?php
//Incluimos los 2 archivos para realizar toda la transacción
require_once ('Carrito.class.php');
require_once ('ProductoDAO.class.php');

session_start(); //Inicamos todas las sesiones

//Creamos al objeto carrito vacio  con un identificador de sesion
$carrito = new Carrito(session_id());

//Recupero el objeto carrito de la sesion en caso exista
if(isset($_SESSION['carrito'])) $carrito = $_SESSION['carrito'];

//Si el usuario realizo una acción
if(isset ($_GET['action'])){
    //Si el cliente ha seleccionado un producto
    switch ($_GET['action']){
        case 'agregar':
            //Recupero el producto de codigo indicado en la base de datos
            $productoDAO = new ProductoDAO();
            $producto = $productoDAO->obtenerProducto((int)$_GET['idProducto']);
            //Agrego al carrito de compras el producto recuperado de la base de datos
            $carrito->agregarProducto($producto);
            break;

        case 'vacear':
            //Reemplazo el atributo carrito de la sesion con un objeto carrito sin productos
            $carrito = new Carrito(session_id());
            break;

        case 'eliminar':
            //Llamo al metodo eliminarProducto retorno todos los productos menos el del código incicado
            $carrito->eliminarProducto((int)$_GET['idProducto']);
            break;

        case 'actualizar':
            //Atrapamos el nombre y valor de todos los textbox...
            //Luego vemos si tanto el codigo y la cantidad son mayores que 0.
            //Y actualizamos la cantidad 1 a 1 de cada producto
            foreach($_GET as $codigo => $cantidad){
                    if((int)$codigo > 0 && (int)$cantidad > 0){
                          //Actualizamos la cantidad para un mismo producto
                        $carrito->actualizarCantidadIngresada($codigo, $cantidad);
                    }
            }         
            break;

        case 'guardar':
            $productoDAO = new ProductoDAO();
            $facnum = $productoDAO->guardarFactura($carrito->productos,$carrito->calcularMonto(),$carrito->calcularDescuento(),$carrito->calcularPrecioTotal());
            break;
    }
   
    //Guardo nuevamente el carrito de la session
    $_SESSION['carrito'] = $carrito;
   
    header('Location: index.php');   //Regresamos ala pagina Inicial
    exit(); //Paramos el script
}

?>
<html>
    <head>
        <style>
            .link_button{
                    background-color:#444444;
                    color:#FFFFFF;
                    font-family:Arial, Helvetica, sans-serif;
                    font-size:12px;
                    font-weight:bold;
                    border: 1px solid #7F7F7F;
                    padding: 2px 3px 2px 3px;
                    cursor:pointer;
            }

            .productos_listado{
                    table-layout:fixed;
                    width:650px;
                    border: 1px solid #D3D4DF;
                    font-family:Arial, Helvetica, sans-serif;
                    font-size:12px;
            }

            .productos_listado caption{
                    background-color: #333333;
                    font-family:Arial, Helvetica, sans-serif;
                    font-size:14px;
                    font-weight:bold;
                    color:#FFFFFF;
                    padding:8px 0px 8px 0px;
            }

            .productos_listado th{
                    background-color: #D3D4DF;
                    color:#333333;
            }

            .productos_listado td{
                    height:24px;                   
            }
            .productos_listado td.td_linea{
                    height: 2px;
                    background-color: #333333;
                    padding: 2px 0px 4px 3px;
            } 

        </style>
    </head>
    <body topmargin="0" leftmargin="0">
        <div align="center" class="content">
            <form action="index.php" method="get">
             <table border="0" class="productos_listado">
                <caption>Listado de Productos</caption>
                <tr>
                    <th width="70px">C&oacute;digo</th>
                    <th>Detalle</th>
                    <th width="80px">Precio</th>
                    <th width="50px">Add</th>
                </tr>
                <?php
                //Recuperando datos de los productos
                $productoDAO = new ProductoDAO;
                $productos = $productoDAO->obtenerProductos();
                //Listamos todos los productos
                foreach ($productos as $producto){
                ?>
                <tr>
                    <td align="center"><b><?php echo $producto->codpro ;?></b></td>
                    <td><?php echo $producto->nompro ;?></td>
                    <td align="center">S/.<?php echo $producto->prepro ;?></td>
                    <td align="center">
                        <a href="javascript:void(0);"
                           onclick="window.location='index.php?action=agregar&idProducto=<?php echo $producto->codpro ;?>';">
                            <img src="img/shopcart.png" alt="Agregar" border="0" title="Agregar"/>
                        </a>
                    </td>
                </tr>
                <?php
                }
                ?>
            </table>
            <br />
            <hr>
            <?php
            $total = 0;
                //Si existe al menos un producto se generará todo lo demas.
                if(count($carrito->productos)>0){
            ?>
            <table border="0" class="productos_listado">
                <caption>Carrito de compras</caption>
                <tr>
                    <th width="40">&nbsp;</th>
                    <th width="60">Cant.</th>
                    <th width="70">C&oacute;digo</th>
                    <th>Nombre</th>
                    <th width="90">Precio unit.</th>
                    <th width="90">Precio total</th>
                </tr>
                <?php
                   //Listamos los productos insertados al carrito
                    foreach($carrito->productos as $producto){
                ?>
                <tr>
                    <td align="center">
                        <a href="javascript:void(0);"
                           onClick="window.location='index.php?action=eliminar&idProducto=<?php echo $producto->codpro ;?>';">
                            <img src="img/bin_closed.png" alt="Eliminar" border="0" title="Eliminar"/>
                        </a>
                    </td>
                    <td align="center">
                        <input type="text" name="<?php echo $producto->codpro ;?>"
                        value="<?php echo $producto->cantidad ;?>" maxlength="3" size="4" style="text-align: center" />
                    </td>
                    <td align="center"><?php echo $producto->codpro ;?></td>
                    <td align="center"><?php echo $producto->nompro ;?></td>
                    <td align="center">S/.<?php echo $producto->prepro ;?></td>
                    <td align="center">S/.<?php echo $producto->precioTotal() ;?></td>
                </tr>
                <?php
                    }
                ?>
                <tr>
                    <td class="td_linea" colspan="6"></td>
                </tr>
                <tr>
                    <td colspan="5" align="left">
                        <b>Monto:</b>
                    </td>
                    <td align="center">S/.<?php echo $carrito->calcularMonto(); ?></td>
                </tr>
                <tr>
                    <td colspan="5" align="left">
                        <b>Cantidad:</b>
                    </td>
                    <td align="center"><?php echo $carrito->calcularCantidad(); ?></td>
                </tr>
                <tr>
                    <td colspan="5" align="left">
                        <b>Descuento:</b>
                    </td>
                    <td align="center">%<?php echo $carrito->calcularDescuento() ; ?></td>
                </tr>
                <tr>
                    <td colspan="5" align="left">
                        <b>Total:</b>
                    </td>
                    <td align="center">S/.<?php echo $carrito->calcularPrecioTotal() ; ?></td>
                </tr>
            </table>
             <input type="button" value="Vacear Cesta" class="link_button" style="width:130px;"
                                    onClick="parent:location='index.php?action=vacear'"/>
            <input type="hidden" name="action" value="actualizar"  style="width:130px;"/>
            <input type="submit" value="Actualizar" class="link_button"  style="width:130px;"/>
           
            <!--<input type="submit" value="Guardar" name="guardar" class="link_button"  style="width:130px;"/>-->
            <input type="button" value="Grabar" class="link_button" style="width: 130px"
                   onclick="parent:location='index.php?action=guardar';">
            <?php
                    //var_dump($carrito);
            ?>
            <?php
                }else
                    echo 'No tiene ningun producto';  //Si no hay producto en el carrito se muestra un mensaje
            ?>
        </form>
        </div>
    </body>
</html>

---------------------------------------------------------------------------------------------------
Bueno esto es todo, como dije antes espero que les sirva para poder realizar trabajos más complejos en adelante usando la POO y la base de datos MYSQL.

Aca la descarga del archivo... (' ' ,)
Descargar