Creating a Simple Shopping Cart Application - Step 4 - Adding a Checkout Order Form

In this step we need to review the contents of the cart before supplying additional information and placing the order.

The following action can be added to app/Http/controllers/scordersController.php. It will pull each item from the cart into an array called $lineItems. The cart only contains a productid and quantity for each line item of the order. For the order to be reviewed, we need to display more details about each of the products. With this in mind we will get a full product object using Product::findById($productid) and append it to the array. This will allow us to access the Product details from the view.

public function checkout()
{
    if (Session::has('cart')) {
        $cart = Session::get('cart');
        $lineitems = array();
        foreach ($cart as $productid => $qty) {
            $lineitem['product'] = \App\Models\Product::find($productid);
            $lineitem['qty'] = $qty;
            $lineitems[] = $lineitem;
        }
        return view('scorders.checkout')->with('lineitems', $lineitems);
    }
    else {
        Flash::error("There are no items in your cart");
        return redirect(route('products.displaygrid'));
    }
}

If we have a controller function we must have a corresponding route. Add the following route to routes/web.php

Route::get('scorders/checkout', 'App\Http\Controllers\scorderController@checkout')->name('scorders.checkout');

To make the checkout button on the displaygrid home page work we need to add this route to the button. Add the route {{route('scorders.checkout')}} as follows

Now we need to add a checkout order form view. To do this add the following code to a file called resources/views/scorders/checkout.blade.php

@extends('layouts.app') 
@section('content') 
<H2>Place Order</h2> 
{{ Form::open(array('url' => 'scorders/placeorder', 'method' => 'post')) }} 
@csrf <table class="table table-condensed table-bordered"> 
    <thead> 
        <tr><th>Id</th><th>Name</th><th>Description</th><th>Colour</th><th>Price</th><th>Quantity</th>
        </tr>
    </thead> 
    <tbody> 
    @php $ttlCost=0; $ttlQty=0;@endphp 
    @foreach ($lineitems as $lineitem) 
        @php $product=$lineitem['product']; @endphp 
        <tr> 
            <td><input size="3" style="border:none" type="text" name="productid[]" readonly value="{{ $product->id }}"></td> 
              <td>{{ $product->name }}</td> 
              <td>{{ $product->description }}</td> 
              <td>{{ $product->colour }}</td> 
              <td><div class="price">{{ $product->price }}</div></td> 
              <td> <input size="3" style="border:none" class="qty" type="text" name="quantity[]" readonly value="<?php echo $lineitem['qty'] ?>"> </td> 
              <td> 
                  <button type="button" class="btn btn-default add"><span class="glyphicon glyphicon-plus"/></button> 
                  <button type="button" class="btn btn-default subtract"><span class="glyphicon glyphicon-minus"/></button> 
                  <button type="button" class="btn btn-default value="remove" onClick="$(this).closest('tr').remove();"><span class="glyphicon glyphicon-remove"/></button> 
              </td>
              @php $ttlQty = $ttlQty + $lineitem['qty']; $ttlCost = $ttlCost + ($product->price*$lineitem['qty']); 
              @endphp 
        </tr> 
    @endforeach
    </tbody> 
</table> 
<button type="submit" class="btn btn-primary">Submit</button> {{ Form::close() }} 
@endsection 

This is an order form and the data from the form will ultimately be submitted to an action called placeOrderAction() in ScorderController.php. Although there is a lot of information displayed on the order form (including the total quantity of items in the order and the total cost of the order overall) all that is actually required to process the order is the productid and quantity for each lineitem. Both of these are actually in input boxes but these inputs are styled so there will be no border and they are readonly. The input boxes will not be apparent to the user but they allow the final data to be submitted. 

As there can be any number of rows and therefore any number of productid and quantity input boxes they need to be processed as arrarys. This is done by naming the fields name="productid[ ]" and name="quantity[ ]". The square brackets in the name allow the information to be submitted and processed as arrays.

The final column in the table contains three buttons styled with glyphicons. These buttons will allow the user to increase or reduce the quantity of the item on that line, or remove the line altogether.

Now we need an action which will process the order form once it is submitted. The following function, when added to app/Http/controllers/scordersController.php, will create a new order record in the database. Once this order has been saved the orderID which was generated in the database is retrieved and can be used as a foreign key in the order detail line item table. The loop processes the arrays of productids and quantities and adds a new order detail line item for each row of the order detail.

public function placeorder(Request $request)
{
    $thisOrder = new \App\Models\Scorder();
    $thisOrder->orderdate = (new \DateTime())->format("Y-m-d H:i:s");
    $thisOrder->save();
    $orderID = $thisOrder->id;
    $productids = $request->productid;
    $quantities = $request->quantity;
    for($i=0;$i<sizeof($productids);$i++) {
        $thisOrderDetail = new \App\Models\OrderDetail();
        $thisOrderDetail->orderid = $orderID;
        $thisOrderDetail->productid = $productids[$i];
        $thisOrderDetail->quantity = $quantities[$i];
        $thisOrderDetail->save();
    }
    Session::forget('cart');
    Flash::success("Your Order has Been Placed");
    return redirect(route('products.displaygrid'));
}

This function will require a corresponding route. Add the following line to routes/web.php

Route::post('scorders/placeorder', 'App\Http\Controllers\scorderController@placeorder')->name('scorders.placeorder');

Leave a Reply