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

Yesod comentado

No entiendo el razonamiento...veamos xDDD

Yo tengo varias tablas con un ID como identificador, pero ese ID puede ser el mismo en diferentes tablas, con lo cual, se me hace extraño que tenga que coger ID cuando puede haber varios productos con el mismo ID pero con diferente ruta...

¿Me lo puedes explicar mejor? Me acabo de hacer un lío xD

0voto

Leonardo-Tadei comentado

Tenés varias tablas de Productos?

0voto

Yesod comentado

Si, dentro de la carpeta productos tengo varias subcarpetas para las diferentes familias de los productos. Es decir:

Productos
|->Llaveros
|->Colgantes
|->Anillos
...
...
etc

Cada uno de los productos cuenta con los mismos identificativos: ID, Nombre, Descripcion, Precio, Imagen.

ID: Autoincrementable.(INT)
Nombre: Nombre del producto. (Text o Varchar2)
Descripción: Breve resumen del producto (Text o Varchar2)
Precio: Coste del producto (Double)
Imagen: Ruta absoluta de la imagen del producto (Text o Varchar2) - Única por producto

0voto

Leonardo-Tadei comentado

No entiendo algo: decís que estás guardando todo esto en MySQL, pero en un servidor de bases de datos, no existe el concepto de "carpeta".

Cuantas tablas de Productos tenés en MySQL?
Cómo se llama cada una?
Cómo es el proceso para crear un producto de una nueva familia?

0voto

Yesod comentado

Dentro de la BASE DE DATOS CARRITO que sería el símil a PRODUCTOS (CARPETA), existen varias tablas (Subcarpetas).
Estructura de la BASE DE DATOS

Cada uno de los productos cuenta con los mismos identificativos: ID, Nombre, Descripcion, Precio, Imagen.

ID: Autoincrementable.(INT)
Nombre: Nombre del producto. (Text o Varchar2)
Descripción: Breve resumen del producto (Text o Varchar2)
Precio: Coste del producto (Double)
Imagen: Ruta absoluta de la imagen del producto (Text o Varchar2) - Única por producto

Ejemplo estructura de las tablas

Los ID de cada tabla son únicos, pero puede haber los mismo ID por diferentes tablas, es decir:

Tabla Colgantes:
ID: 1
Nombre: Monstruo
Descripción: Terrible
Precio: 2.18
Imagen: /productos/colgantes/img/MonstruoTerrible.png

Tabla Llaveros:
ID: 1
Nombre: Digimon
Descripción: Muy bonito
Precio: 5.10
Imagen: /productos/llaveros/img/Digimon-01.png

Lo cual, pueden existir varios ID iguales, dentro de la propia base de datos, pero nunca puede haber varios ID iguales dentro dentro de la misma tabla.

0voto

Leonardo-Tadei comentado

Estimado @Yesod,

tenés mal normalizado el almacenmaiento, y por eso tenés ahora problemas y varias complicaciones de implementación (como por ejemplo que crear una nueva familia implica crear una tabla!)

El almacenamiento correcto para datos como esos es:

Familia
-------
id
nombre

Producto
--------
id
nombre
id_familia
descripción
precio
imagen

De esta manera crear una nueva familia solo consiste en agregar un registro a la tabla Familia, discriminar los productos por familia es solo filtrarlos por id familia y los ID de los Productos pasan a ser únicos, solucionando y simplificando cualquier problema del carrito de compras que pudieras tener.

Sobre todo teniendo en cuenta que estás haciendo esto para aprender, te conviene hacerlo lo más prolijo y correcto posible, así aprendés a hacer las cosas de la mejor manera.

Saludos cordiales!

0voto

Yesod comentado

¿Entonces tu como harías el código?

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