05 Carrito de compras – Taller de desarrollo de una Tienda en Línea

Hola, bienvenido(a), al Post 05 del Taller de Desarrollo de una Tienda en línea con Bootstrap, Laravel 5.1 y API Paypal.

Hoy vamos a crear nuestro Carrito de compras, este es uno de los elementos más importantes de nuestra Tienda en línea, le permite al usuario elegir los productos que podrían convertirse en un pedido.

Para implementar el carrito se pueden usar paquetes de Laravel, entre otros:

En nuestro caso vamos a desarrollar nuestra propia versión de un carrito de compras, misma que contará con las funcionalidades básicas de todo carrito, a saber:

  1. Agregar item
  2. Eliminar item
  3. Actualizar item
  4. Mostrar carrito
  5. Vaciar carrito
  6. Obtener total (a pagar)

Nuestra versión usara un array para almacenar todos los items, mismos que serán objetos creados usando nuestro modelo Product, dicho array se guardara en una variable de sesión para que este disponible en cualquier parte del sitio.

Todas las operaciones de agregar item, eliminar item, etc., se realizarán sobre el array por lo que no tendremos la necesidad de almacenar el carrito en nuestra base de datos, solo al final si el usuario decide enviar el pedido, entonces guardaremos esa información en la base de datos.

En esta clase vemos entre otros temas de Laravel, los siguientes:

  • Rutas y Controladores
  • Vistas, vistas parciales y templates
  • Uso de Blade (motor de plantillas)
  • Uso de Eloquent (ORM)
  • Inyección de dependencias
  • Sesiones

Te comparto el vídeo de la clase de hoy:

Espero tus comentarios y nos vemos en el siguiente post 🙂

  • Este es el quinto post, pronto subiremos el proyecto a github 🙂

  • Linda Mejia Laura

    FISO muchas gracias por tu tiempo este tutorial me esta AYUDANDO MUCHOooooooo

    • Gracias a ti por seguir el taller, saludos 🙂

  • Linda Mejia Laura

    una pregunta para ti tu carrito es mejor que :
    LaravelShoppingCart
    Moltin/Cart
    PHPCart
    o porque no utilizaos esta vez alguno de estos paquetes?

    • Hola Laura, no creo que sea mejor que packages como los que mencionas, hicimos el carrito de esta forma solo con fines didácticos, para entender un poco la lógica que hay atrás de un carrito 🙂

  • German

    Hola, tengo una duda, en el modelo de base de datos, la propiedad quantity esta en la tabla order_items, sin embargo, a la hora de hacer la actualizacion de item haces referencia a “product->quantity”, es decir que en realidad la cantidad esta en modelo productos? Espero tu respuesta, gracias por los tutoriales

    • Hola German, cantidad (quantity) NO es una propiedad de los productos, sin embargo, al agregar un item al carrito necesitamos especificar la cantidad y para que esta este disponible en todas las operaciones que hacemos con los productos del carrito, lo que hacemos es generar de forma dinámica la propiedad “quantity” para el objeto $product y después agregar este objeto al array carrito:

      public function add(Product $product) {

      $product->quantity = 1;
      $cart[$product->slug] = $product;

      }

      Por eso cuando guardamos los items del pedido en la base de datos podemos hacer uso de $product->quantity, esto es gracias a que php nos permite generar propiedades de forma dinámica. Saludos!

      • German

        Muchisimas gracias por responder tan rápido, me sacaste varias dudas y como recién estoy aprendiendo php no tenía conocimiento de que se podían generar propiedades dinamicas. Saludos y gracias nuevamente por el tutorial.

  • Francisco Javier Guzman

    Excelente aporte con este curso, Saludos desde Honduras

    • Gracias Francisco por seguir el taller, saludos!

  • Alexandros Facio

    Hola Oved, bueno pues ahorita ya realice las pistas qu me diste de cambiar la variable de sesión y de todos modos en realizar los permisos a la carpeta storage para que pueda escribir. Esoy usando Laravel 5.2 el punto es que al realizar el “add” para anexar el item si se almacena el elemento on “put” al arreglo cart pero al redireccionar a “show” se resetea la variable de sesión, no persiste.

    estas son mis rutas:
    Route::bind(‘product’, function($slug) {
    return ShopProduct::where(‘slug’, $slug)->first();
    });

    Route::get(‘/’, [
    ‘uses’ => ‘StoreController@Index’
    ]);

    Route::get(‘product/{slug}’, [
    ‘as’ => ‘product-detail’,
    ‘uses’ => ‘StoreController@ShowDetail’
    ]);

    Route::get(‘cart/show’, [
    ‘as’ => ‘cart-show’,
    ‘uses’ => ‘CartController@ShowCart’
    ]);

    Route::get(‘cart/add/{product}’, [
    ‘as’ => ‘cart-add’,
    ‘uses’ => ‘CartController@AddCart’
    ]);

    Route::get(‘cart/delete/{product}’, [
    ‘as’ => ‘cart-delete’,
    ‘uses’ => ‘CartController@DeleteCart’
    ]);

    Route::get(‘cart/trash’, [
    ‘as’ => ‘cart-trash’,
    ‘uses’ => ‘CartController@TrashCart’
    ]);

    Route::get(‘cart/update/{product}/{quantity}’, [
    ‘as’ => ‘cart-update’,
    ‘uses’ => ‘CartController@UpdateCart’
    ]);

    Este es mi controllador cart:
    namespace ShopHttpControllers;

    use IlluminateHttpRequest;

    use ShopHttpRequests;
    use ShopHttpControllersController;
    use ShopProduct;

    class CartController extends Controller
    {
    //Crear variable de sesión para las operaciones del carrito
    public function __construct()
    {
    if (!Session::has(‘cart’)) Session::put(‘cart’, array());
    }

    //Show Cart
    public function ShowCart()
    {
    $cart = Session::get(‘cart’);
    $total = $this->total();
    return view(‘shop.cart’, compact(‘cart’, ‘total’));
    }

    //Trash Cart
    public function TrashCart()
    {
    Session::forget(‘cart’);
    return redirect()->route(‘cart-show’);
    }

    //Add Item
    public function AddCart(Product $product)
    {
    $cart = Session::get(‘cart’);
    $product->quantity = 1;
    $cart[$product->slug] = $product;
    Session::put(‘cart’, $cart);
    return redirect()->route(‘cart-show’);
    }

    //Delete Item
    public function DeleteCart(Product $product)
    {
    $cart = Session::get(‘cart’);
    unset($cart[$product->slug]);
    Session::put(‘cart’, $cart);
    return redirect()->route(‘cart-show’);
    }
    //Update Item
    public function UpdateCart(Product $product, $quantity)
    {
    $cart = Session::get(‘cart’);
    $cart[$product->slug]->quantity = $quantity;
    Session::put(‘cart’, $cart);
    return redirect()->route(‘cart-show’);
    }

    //Total shop
    private function TotalCart()
    {
    $cart = Session::get(‘cart’);
    $total = 0;
    foreach ($cart as $item) {
    $total += $item->price * $item->quantity;
    }

    return $total;
    }
    }

    Ojo ahorita decidi avanzar en el taller y estoy en el total incluso ahi me doy cuenta que no entra al metodo show por que no esta pasado ese metodo.

    Te anexo el error que me arroja

    • Ok, lo primero que veo es que en el método ShowCart llamas al método total $this->total(); pero en tu controller ese método se llama TotalCart, entonces tienes que llamarlo así $this->TotalCart(); corrige eso, haz otras pruebas y me avisas que pasa.

      • Alexandros Facio

        Oved ya quedo listo… el detalle esta que en Laravel 5.2 se creo un middleware en las que usa en las rutas para pasar las variables de sesión y se mantengan, llamado “web” por lo que nunca se generaba una variable de sesión, siempre estaba en blanco, ademas estoy usando la meta.

        la cual tampoco es generada, quedano asi mi codigo

        routes.php:
        /*
        |————————————————————————–
        | Application Routes
        |————————————————————————–
        |
        | This route group applies the “web” middleware group to every route
        | it contains. The “web” middleware group is defined in your HTTP
        | kernel and includes session state, CSRF protection, and more.
        |
        */

        Route::group([‘middleware’ => [‘web’]], function () {
        Route::bind(‘product’, function($slug) {
        return ShopProduct::where(‘slug’, $slug)->first();
        });

        Route::get(‘/’, [
        ‘uses’ => ‘StoreController@Index’
        ]);

        Route::get(‘product/{slug}’, [
        ‘as’ => ‘product-detail’,
        ‘uses’ => ‘StoreController@ShowDetail’
        ]);

        Route::get(‘cart/show’, [
        ‘as’ => ‘cart-show’,
        ‘uses’ => ‘CartController@ShowCart’
        ]);

        Route::get(‘cart/add/{product}’, [
        ‘as’ => ‘cart-add’,
        ‘uses’ => ‘CartController@AddCart’
        ]);

        Route::get(‘cart/delete/{product}’, [
        ‘as’ => ‘cart-delete’,
        ‘uses’ => ‘CartController@DeleteCart’
        ]);

        Route::get(‘cart/trash’, [
        ‘as’ => ‘cart-trash’,
        ‘uses’ => ‘CartController@TrashCart’
        ]);

        Route::get(‘cart/update/{product}/{quantity}’, [
        ‘as’ => ‘cart-update’,
        ‘uses’ => ‘CartController@UpdateCart’
        ]);
        });

        ahora estoy teneindo un problema que al realizar el update, no esta pasando en el route el parametro {cuantity}, enviando el error que no puede encontrar el

        Missing
        required parameters for [Route: cart-update] [URI:
        cart/update/{product}/{quantity}]. (View:
        D:xampphtdocsproyectos2015shopresourcesviewsshopcart.blade.php)

        Pero la vista cart es el mismo que tienes tu y el javascript esta funcionando perfectamente. La prueba que hice fue que omiti la cantidad en el parametro que estamos enviando {quantity}

        Route::get(‘cart/update/{product}’, [
        ‘as’ => ‘cart-update’,
        ‘uses’ => ‘CartController@UpdateCart’
        ]);

        • Jose Carlos Tovar

          Hola se pudo arreglar el error
          Missing required parameters for [Route: cart-update]

        • Mateo Diaz Lopez

          la solucion en es ta Route::get(‘cart/update/{product?} eber si la repuesta no es tarde checalo.

        • Victor Monroy

          Tengo tu mismo error, ¿Alguien ya lo soluciono?

          • Victor Monroy

            Lo acabo de solucionar jaja
            Route::get(‘cart/update/{product}/{quantity?}

          • Junior

            Gracias por el aporte

          • raza binaria

            Me salvaste Victor Monroy jamas se me habria ocurrido, me queda la duda de porque funciona asi con el signo de interrogación ‘?’.

          • Francisco Ramirez

            Gracias amigo ajhajhajahaj!! ME salvaste!! 😀

  • Edward

    Excelente, muy buen contenido!!!

  • Hugo Lesta

    Hola FISO, gracias por todo lo que haces, enseñas conocimientos muy valiosos.

    Tengo una consulta, parece ser que en el momento de actualizar la variable de session del carrito me brinda un error Creating default object from empty value el error está en la linea 57 de mi archivo cartController.php

    No estoy seguro si es un error mio o bien si es algo que se sumó en la nueva actualización, dejo el código que escribí.

    CartController.php = http://pastebin.com/u5spcJuE

    Cart-update.js = http://pastebin.com/7LpeGdWB

    cart.blade.php = http://pastebin.com/ufUZqRj2

    Routes.php = http://pastebin.com/ubQLpmsv

    Desde ya me encuentro agradecido!

    • Hola Hugo, disculpa apenas vi tu comentario y supongo que el error que hubiera ya lo corregiste, lo siento, gracias por seguir el taller, saludos!

      • Hugo Lesta

        Hola Fiso, gracias por tu comentario, mi proyecto quedó en stand by por el momento, la verdad no se por que me da este error, incluso parece bastante genérico. si puedes determinar por que me sucede esto de verdad te lo agradezco.

        Un saludo cordial!.

    • No se bien a que se deba el error, pero en la línea en que te lo marca (57 del CartController) lo que hacemos es usar una propiedad (quantity) que no existe, es decir que no fue definida para nuestro modelo Product, esto lo podemos hacer porque php nos permite crear de forma dinámica propiedades y métodos (gracias a métodos mágicos como __set), entonces lo que podría pasar es que estés usando una versión de php anterior a la que implemento estas características o también podría ser que estés usando Laravel 5.2, en ese caso, tendrías que modificar las peticiones routes en donde se manejan sesiones, porque esta nueva versión de Laravel cambia un poco esa parte, puedes revisar la documentación de Laravel 5.2, para ver lo que cambió. Espero esto te sea de ayuda. Saludos!

  • Edward

    Hola ovedfs muy buen contenido, puedes mostrar una referencia o ejemplo para rebajar la cantidad de productos? ya que agregue una columna para almacenar la cantidad de productos que se tenga en inventario.

  • romero santos dos

    porque me sale las variables de sesiones vacias al momento de agregar el producto a mi carrito eesta todo bien

    public function __construct() {

    if(!Session::has(‘cart’)) Session::put(‘cart’, array());

    }

    //mostrar

    public function show(){

    $cart= Session::get(‘cart’);

    return view(‘store.cart’, compact(‘cart’));

    }

    //agregar

    public function add(Product $product){

    $cart= Session::get(‘cart’);

    $product->quantity = 1;

    $cart[$product->slug]=$product;

    Session::put(‘cart’, $cart);

    return redirect()->route(‘cart-show’);

    }
    y en el route

    Route::bind(‘product’, function($slug){

    return AppProduct::where(‘slug’,$slug)->first();

    });

    Route::get(‘/’,[

    ‘as’ => ‘home’,

    ‘uses’ => ‘storeController@index’

    ]);

    Route::get(‘product/{slug}’,[

    ‘as’ => ‘product-detail’,

    ‘uses’ => ‘StoreController@show’

    ]);

    Route::get(‘cart/show’,

    [

    ‘as’ => ‘cart-show’,

    ‘uses’ => ‘CartController@show’]);

    Route::get(‘cart/add/{product}’,[

    ‘as’ => ‘cart-add’,

    ‘uses’ => ‘CartController@add’

    ]);

  • Steven

    Holaaa..que buenos tutoriales, tengo una pregunta, no entendi la parte del bind, quiere decir que si hay ‘product’ en cualquier parte de la url devuelve todo ese objeto?

    Gracias y que bueno explicas.

    • Hola Steven, si, mas o menos, de esta forma nos ahorramos esa tarea de recibir el slug o id y buscar el item en la base de datos, con el binding Laravel lo hace por nosotros. Saludos!

  • Juan Ramos

    Muy buen aporte, me sirvió bastante. Gracias

  • Julia Rosales

    Muchisimas gracias, estupendo tutorial! muchas gracias por compartir algo tan valioso como el conocimiento. Saludos desde Venezuela 🙂

    • Hola Julia, gracias por seguir el taller, saludos!

  • deyvis

    disculpa con respecto a la actualizacion . no me quiere salir

  • Niverd Manzanilla Antolinez

    ErrorException in CartController.php line 66: AppHttpControllersCartController::total(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "Appproducts" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition

    Amigo ovedfs, mi carrito funciono bien hasta que estuve manejando el capitulo 6 de usuarios.. ahora me sale ese error al intentar entrar en el carrito o intentar añadir algun item

    [img]https://uploads.disquscdn.com/images/6dabc2f1053ae492da941c305332da32b1eb8be67e0529ce74a69d3edcf28704.png[/img] https://uploads.disquscdn.com/images/2ca99b80719f04564054a529dffe255046be6c4b2daa7301c768f590938e41f7.png https://uploads.disquscdn.com/images/2db7cb8beed8ab4e29c62135b1519d5b47e2cae0425623b3f2ef30a4c5481d89.png https://uploads.disquscdn.com/images/8489a10010aa7e538425564c9489b0d974547ace23ef242d8c4eb0ff4d8b5514.png

  • Alejandro

    Buenas tardes, quien me ayuda con un problema que tengo para insertar los productos al carrito, cuando le paso por la url por ejemplo localhost:8000/cart/add/playera-5 si me agrega perfecto al carrito, osea que si esta ejecutandose el metodo correctamente, pero cuando lo selecciono desde la interfaz abajo lo que quiere mandar por la url es de esta manera: localhost:8000/cart/add/%Bproduct%7D cuando le doy agregar me crea vacio en el carrito porque no esta encontrando el producto en la base de datos mediante el slug, como soluciono este problema?? Pienso que es en este metodo del router

    Route::get(‘cart/add/{product}’, [
    ‘as’ => ‘cart-add’,
    ‘uses’ => ‘CartController@add’
    ]);

    asi tal cual lo tengo en mi codigo como esta en el video pero el problema es que no llama al producto en la bd!

    Gracias de antemano

  • Nikon

    Sé que el curso es viejo, pero lo estoy siguiendo perfectamente en un laravel 5.2.45 Muy bien explicado y perfecto, lo único que me dio problemas fue el apartado de actualizar la cantidad de un item no había manera de que me funcionara el javaScript al final puse el input en un formulario y lo envió al controlador por Post. el controlador hace su trabajo y va perfecto. Creo que si el trabajo va a depender del controlador tampoco es necesario el javaScript.

  • CESAR AURIS SAGA

    Yo tambien tengo un problema con el router update cuando agrego quantity al router me sale error aver si me ayudas estoy usando laravel 5.4

    [————Controlador———–]
    https://sites.google.com/site/imagenessubidasss/home/controlador.jpg

    [————Router———–]
    https://sites.google.com/site/imagenessubidasss/home/router.jpg

    [————Vista———–]
    https://sites.google.com/site/imagenessubidasss/home/vista.jpg

    ERROR
    https://sites.google.com/site/imagenessubidasss/home/error-vv.jpg

    Espero si hay una respuesta