entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

Carrito de Compra en PHP

Buenas noches compañeros, llevo un tiempo realizando una página web (como practica) para hacer compras online y aprender un poco. Me ha surgido este problema.

<?php session_start(); 

/* INCLUIMOS LA CLASE DEL PEDIDO Y LA CONEXIÓN A LA BD */ 
require_once("./carrito.class.php"); 
require_once('./conexion.php');  

/* COGEMOS LOS DATOS POR GET */ 
$id = $_GET['id']; 
$cantidad = $_GET['cantidad']; 
$imagen = $_GET['imagen'];
$ruta = $_GET['ruta'];

/* SI NO HAY SESION DE CARRITO CREAMOS UN OBEJTO NUEVO SI LO HAY, UNSERIALIZASMOS EN LA VARIABLE EN OBJETO CARRITO */ 
if(!$_SESSION['carrito']){ 
    $obj_kart = new obj_carrito(); 
}else{ 
    $obj_kart = unserialize($_SESSION['carrito']); 
} 

/* PREGUTAMOS SI EL ARTÍCULO ESTÁ EN EL CARRITO */ 
if($obj_kart->find_prod($imagen)){ 
    /* SI ESTÁ, SE AÑADE LA CANTIDAD SIN NECESIDAD DE HACER LA CONSULTA */ 
    $obj_kart->add_changue_prod($imagen,"","",$cantidad,""); 
}else{ 
    /* PREGUNTAMOS LOS DATOS DEL PRODUCTO A LA BASE DE DATOS */ 
    $query  =mysql_query("SELECT id, nombre, precio, imagen FROM ".$ruta." WHERE id='".$id."'")or die(mysql_error());
    $fetch = mysql_fetch_array($query); 

    /* AÑADIMOS EL PRODUCTO NUEVO PUESTO QUE SABEMOS QUE NO ESTÁ EN EL CARRITO */ 
    $obj_kart->add_changue_prod($id, $fetch['nombre'],$fetch['precio'],$cantidad,$fetch['imagen']);
} 

/* GUARDAMOS EN LA VARIABLE DE SESSIÓN EL OBJETO DEL CARRITO SERIALIZADO */ 
$_SESSION['carrito'] = serialize($obj_kart); 

?> 

Esta parte del código se da a entender por si sola...el problema viene cuando quiero añadir un segundo artículo de la base de datos o añadir cantidad a un artículo ya existente.

/* ESTA FUNCIÓN AÑADE ARTÍCULOS O CAMBIA CANTIDADES AL ARTÍCULO */ 
    function add_changue_prod($id,$nombre,$precio,$cantidad,$imagen){ 
        $productos = $this->productos; 
        $poner = true; 

        foreach($productos as $key => $producto){ 
            if($imagen == $producto->imagen){ 
                $poner = false; 
                if(!$cantidad){ 
                    $producto->cantidad++; 
                }else{ 
                    $producto->cantidad = $cantidad; 
                } 
            } 
        } 

        if($poner){ 
            if(!$cantidad){ 
                $cantidad = 1; 
            } 
            $A = $key + 1; 
            $this->productos[$A] = new datos_producto(); 
            $this->productos[$A]->numArt = $A; 
            $this->productos[$A]->id = $id; 
            $this->productos[$A]->nombre = $nombre ; 
            $this->productos[$A]->precio = $precio ; 
            $this->productos[$A]->cantidad = $cantidad; 
            $this->productos[$A]->imagen = $imagen ; 
        } 
    } 

Estoy un poco pillado y no consigo darle salida...cabe decir, que el id es un identificador único por tabla, es decir, puede haber varios ID dentro de la misma base de datos que sean iguales, por eso he cogido $imagen, que es la ruta absoluta de la imagen y esta si es única e irrepetible porque nunca hay dos imágenes iguales.

1 Respuesta

2votos

Leonardo-Tadei Puntos227320

Me parece que te estás haciendo lio... cuándo decís "el id es un identificador único por tabla", dado que al carrito cargarás Productos, tendrías que poder usar siempre el ID del producto como clave única del carrito...

Luego, la función add_changue_prod() es innecesariamente compleja. Podrías definirla como:

function add_changue_prod($id,$nombre,$precio,$imagen$cantidad=1,){
...

de manera tal que si no recibe cantidad, será 1 por default, y si recibe un valor, se usará ese, con lo que podés sacar todas las preguntas sobre $cantidad que se usa ahora como bandera.

Saludos

0voto

Leonardo-Tadei comentado

Con las tablas normalizadas, el código quedaría algo así:

<?php
session_start(); 
/* INCLUIMOS LA CLASE DEL CARRITO Y LA CONEXIÓN A LA BD */ 
require_once("./carrito.class.php"); 
require_once('./conexion.php');  

/* COGEMOS LOS DATOS POR GET 
(sería mejor por POST. Al ser el ID único, solo hace falta este y la cantidad) */ 
$id = $_GET['id']; 
$cantidad = $_GET['cantidad']; 

/* SI NO HAY SESION DE CARRITO CREAMOS UN OBEJTO NUEVO SI LO HAY, UNSERIALIZASMOS EN LA VARIABLE EN OBJETO CARRITO */ 
if(! isset($_SESSION['carrito'])){ 
    $obj_kart = new obj_carrito(); 
}else{ 
    $obj_kart = unserialize($_SESSION['carrito']); 
} 

/* PREGUTAMOS SI EL ARTÍCULO ESTÁ EN EL CARRITO */ 
if($obj_kart->find_prod($id)){ 
    /* SI ESTÁ, SE AÑADE LA CANTIDAD SIN NECESIDAD DE HACER LA CONSULTA */ 
    $obj_kart->add_changue_prod($id,"","",$cantidad,""); 
}else{ 
    /* PREGUNTAMOS LOS DATOS DEL PRODUCTO A LA BASE DE DATOS
La query es ahora a una sola tabla.
(hay que cambiar esto a mysqli_* o a PDO porque las mysql_* dejarán de existir pronto) */ 
    $query  =mysql_query("SELECT id, nombre, precio, imagen FROM Productos WHERE id='".$id."'")or die(mysql_error());
    $fetch = mysql_fetch_array($query); 

    /* AÑADIMOS EL PRODUCTO NUEVO PUESTO QUE SABEMOS QUE NO ESTÁ EN EL CARRITO */ 
    $obj_kart->add_changue_prod($id, $fetch['nombre'],$fetch['precio'],$cantidad,$fetch['imagen']);
} 

/* GUARDAMOS EN LA VARIABLE DE SESSIÓN EL OBJETO DEL CARRITO SERIALIZADO
(en realidad no hace falta serializarlo: $_SESSION es un vector y un elemento de un vector puede ser un Objeto:
$_SESSION['carrito'] = $obj_kart;
Si no lo guardás serializado, no hace falta desserializarlo al leer la sesión */ 
$_SESSION['carrito'] = serialize($obj_kart); 
?> 

y el método add_changue_prod() de clase obj_carrito trabaja con el ID del Producto como clave, porque ahora el Producto respetando el modelo Entidad/Relación es una sola entidad accesible unívocamente.

Saludos!

0voto

Yesod comentado

Esto que me das a entender, ¿sería una tabla con todos los productos de todas las categorías almacenados ahí? ¿Esto es práctico? Es decir, en una página como pccomponentes, no creo que sea así como lo tengan hecho, sería un poco caos...

Lo que intento buscar es que sin una tabla general donde almacene todos los productos, se haga una sesión o tabla temporal o un form temporal donde almacene todos los productos de las diferentes familias...no se si me explico...

0voto

Leonardo-Tadei comentado

No solo es práctico tener una sola tabla de Productos: es lo que hace eficiente el almacenamiento y rápidas las consultas!

Claro que pccomponentes o dealextreme lo tienen así: es la única manera de no desbordar al RDBMS, ya que justamente los servidores de bases de datos son eficientes si el almacenamiento está normalizado (y muy ineficientes en caso contrario).

Pensá que para una tabla MySQL, tener 1 millón de registros es lo esperado por los diseñadores y para lo que se calcula la eficiencia de los algoritmos.

No entiendo tu 2do párrafo: con el esquema de amacenamiento que te indico más arriba podés trabajar sin ninguna cosa temporal ni nada raro. Si quisieras ver todos los productos de la familia "llaveros" que tiene el ID=34, basta con hacer:

SELECT * FROM Productos WHERE id_familia=34

y nada más...

Para que la eficiencia sea exactamente igual a tener a esa familia en una tabla aparte, basta con hacer un índice para el campo id_familia y nada más.

Saludos cordiales.

1voto

Yesod comentado

Vale, ya entendí, voy a hacerme unos esquemas en papel y remodelar la BD, te comento cuando lo tenga :)

Gracias

EDITO: Funciona perfectamente, ahora me queda arreglar la opción comprar...que se hace a través de Paypal :)

1voto

Leonardo-Tadei comentado

Me alegra! Marcá la respuesta así tu pregunta queda como solucionada.
Por la cuestión de Paypal, en caso de necesitar ayuda te conviene crear una nueva pregunta.
Saludos!

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta