I am trying to update my stock level by subtracting the cart item quantity from the product quantity in the database when a user completes an order using the POST method. Everytime I run the method the success function occurs but the field doesnt update doesnt update.
Could anyone tell me why?
My Controller:
public function index ()
{
$products = Product::all();
return view('products', compact('products'));
}
public function cart()
{
return view('cart');
}
public function addToCart($id)
{
$product = Product::find($id);
if(!$product) {
abort(404);
}
$cart = session()->get('cart');
// if cart is empty then this will be the first product
if(!$cart) {
$cart = [
$id => [
"name" => $product->name,
"quantity" => 1,
"price" => $product->unit_price
]
];
session()->put('cart', $cart);
return redirect()->back()->with('success', 'Product added to cart successfully!');
}
// if cart isnt empty then check if this product exist then increment quantity
if(isset($cart[$id])) {
$cart[$id]['quantity']++;
session()->put('cart', $cart);
return redirect()->back()->with('success', 'Product added to cart successfully!');
}
// if item doesnt exist in cart then add to cart with quantity = 1
$cart[$id] = [
"name" => $product->name,
"quantity" => 1,
"price" => $product->unit_price
];
session()->put('cart', $cart);
return redirect()->back()->with('success', 'Product added to cart successfully!');
}
public function update(Request $request)
{
if($request->id and $request->quantity)
{
$cart = session()->get('cart');
$cart[$request->id]["quantity"] = $request->quantity;
session()->put('cart', $cart);
session()->flash('success', 'Cart updated successfully');
}
}
public function remove(Request $request)
{
if($request->id) {
$cart = session()->get('cart');
if(isset($cart[$request->id])) {
unset($cart[$request->id]);
session()->put('cart', $cart);
}
session()->flash('success', 'Product removed successfully');
}
}
public function stock (Request $request)
{
if($request->id and $request->quantity)
{
$cart = session()->get('cart');
$cart[$request->id]['quantity'] = $request->quantity;
$products = Product::all();
$stock = $products->unit_stock;
$quantity = $stock - $cart;
return $quantity;
}
}
My Route:
Route::post('stock', 'ProductController#stock');
My view cart.blade.php:
#extends('layout')
#section('content')
<table id="cart" class="table table-hover table-condensed">
<thead>
<tr>
<th style="width:50%">Product</th>
<th style="width:10%">Price</th>
<th style="width:8%">Quantity</th>
<th style="width:22%" class="text-center">Subtotal</th>
<th style="width:10%"></th>
</tr>
</thead>
<tbody>
<?php $total = 0 ?>
#if(session('cart'))
#foreach(session('cart') as $id => $details)
<?php $total += $details['price'] * $details['quantity'] ?>
<tr>
<td data-th="Product">
<div class="row">
<div class="col-sm-9">
<h4 class="nomargin">{{ $details['name'] }}</h4>
</div>
</div>
</td>
<td data-th="Price">${{ $details['price'] }}</td>
<td data-th="Quantity">
<input type="number" value="{{ $details['quantity'] }}" class="form-control quantity" />
</td>
<td data-th="Subtotal" class="text-center">${{ $details['price'] * $details['quantity'] }}</td>
<td class="actions" data-th="">
<button class="btn btn-info btn-sm update-cart" data-id="{{ $id }}"><i class="fa fa-refresh"></i></button>
<button class="btn btn-danger btn-sm remove-from-cart" data-id="{{ $id }}"><i class="fa fa-trash-o"></i></button>
</td>
</tr>
#endforeach
#endif
</tbody>
<tfoot>
<tr class="visible-xs">
<td class="text-center"><strong>Total {{ $total }}</strong></td>
</tr>
<tr>
<td><i class="fa fa-angle-left"></i> Continue Shopping</td>
<td colspan="2" class="hidden-xs"></td>
<td class="hidden-xs text-center"><strong>Total ${{ $total }}</strong></td>
</tr>
</tfoot>
<div class="row">
<div class="btn col-md-12">
Test
</div>
</div>
</table>
<script type="text/javascript">
$("#order-complete").click(function (e){
e.preventDefault();
var ele = $(this);
$.ajax({
url: '{{ url('stock') }}',
method: "post",
data: {_token: '{{ csrf_token() }}'},
success: function () {
window.location.reload();
}
});
});
</script>
#endsection
I can see a couple of potential issues that might be causing this. Firstly, it looks like you're trying to set stock against all of the products in your database in one go by loading a collection containing them all, rather than looping/loading the ones contained in the order ($request). You do this here;
$products = Product::all();
Then you try to change the stock for all products in the collection here;
$stock = $products->unit_stock;
$quantity = $stock - $cart;
I imagine you should have a collection of products in your $cart variable that you should loop over and load to manipulate. Some pseudo code to illustrate my point;
foreach($product in $cart){
$loadedProduct = Product::find($product);
$loadedProduct->stock = $loadedProduct->stock - $product["quantity"];
$loadedProduct->save();
}
You also aren't saving any products in the code you provided. There's an example of this in the pseudo code above.
I can spot a few mistakes from your code.
Lets focus on the function that the ajax request calls.
This line here tells me that there is a data id and quantity being sent.
if($request->id and $request->quantity)
From the look of your Route, it is in the body. But in the ajax function, you're didn't include any data except the csrf token. Try adding id and quantity data. This is just an assumption of the value.
data: {_token: '{{ csrf_token() }}', id: 6, quantity: 2},
Secondly, this function returns a collections of product.
$products = Product::all();
So if you would like to modify a product you must access its index. e.g.
$products[0]->unit_stock = 3;
$products[0]->save();
Or what Lewis has stated, you can use a foreach loop to iterate every object in the collection
Related
So when I put a route name with a single parameter it works flawlessly but when I pass named route with two parameters I get a 500 error in my console which looks like this:GET http://127.0.0.1:8000/admin/packages/package-programs/kathmandu/action?query= 500 (Internal Server Error).
<?php
namespace App\Http\Controllers\AdminVisible;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Program;
use App\Package;
use DB;
class PackageProgramController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index($packageSlug)
{
$showCounts = Program::count();
$packages = Package::firstOrFail();
return view('admin.pages.packageprogram',compact('showCounts','packageSlug','packages'));
}
function action($packageSlug,Request $request)
{
if($request->ajax())
{
$output = '';
$query = $request->get('query');
if($query != '')
{
$data = DB::table('programs')
->where('id', 'like', '%'.$query.'%')
->orWhere('day', 'like', '%'.$query.'%')
->orWhere('Package_Type', 'like', '%'.$query.'%')
->orWhere('title', 'like', '%'.$query.'%')
->orderBy('id', 'desc')
->get();
}
else
{
$data = DB::table('programs')
->orderBy('id', 'desc')
->get();
}
$total_row = $data->count();
if($total_row > 0)
{
foreach($data as $row)
{
$packageProgram = ['packageProgram' => $row->id];
$route = route('PackageProgram.edit',['packageSlug' => $packageSlug, 'packageProgram' => $packageProgram]);
$output .= '
<tr>
<th scope="row"><input type="checkbox" name="ids[]" class="selectbox" value="'.$row->id.'" onchange="change()"></th>
<td onClick="location.href=\''.$route.'\' " style="cursor: pointer">'.$row->id.'</td>
<td onClick="location.href=\''.$route.'\' " style="cursor: pointer">'.$row->day.'</td>
<td onClick="location.href=\''.$route.'\' " style="cursor: pointer">'.$row->title.'</td>
<td onClick="location.href=\''.$route.'\' " style="cursor: pointer">'.$row->description.'</td>
</tr>
';
}
}
else
{
$output = '
<tr>
<td align="center" colspan="12">No Data Found</td>
</tr>
';
}
$data = array(
'table_data' => $output,
'total_data' => $total_row
);
echo json_encode($data);
}
}
public function create($packageSlug, Package $package)
{
return view('admin.create.createPackageProgram',compact('packageSlug','package'));
}
public function store($packageSlug,Request $request)
{
$packages = Package::where('slug', $packageSlug)->firstOrFail();
$data = request()->validate([
'day' => 'required',
'title' => 'required',
'description' => 'required',
]);
$packages->program()->create($data);
switch ($request->input('action')) {
case 'preview':
return redirect()->intended(route('PackageProgram',$packageSlug))->with('message', 'Package Program has been added.');
break;
default:
return redirect()->back()->with('message', 'Package Program has been added.');
break;
}
}
public function edit($packageSlug,Program $packageProgram,Package $package)
{
return view('admin.edit.editPackageProgram',compact('packageSlug','packageProgram','package'));
}
public function update($packageSlug, Program $packageProgram)
{
$data = request()->validate([
'day' => 'required',
'title' => 'required',
'description' => 'required',
]);
$packageProgram->update($data);
return redirect()->intended(route('PackageProgram',$packageSlug))->with('message', 'Package Program has been updated.');
}
public function delete(Request $request) {
$data = request()->validate([
'deleteSelected' => 'required',
]);
$id = $request->get('ids');
$data = DB::delete('delete from programs where id in ('.implode(",",$id).')');
return redirect()->back()->with('message', 'Testimony has been deleted.');
}
}
My blade file looks something like this:
#extends('layouts.app')
#section('style')
<link href="{{ asset('css/Admin/sql-data-viewer.css') }}" rel="stylesheet">
<style></style>
#endsection
#section('content')
<section class="data-viewer">
<div class="d-flex justify-content-between px-3">
<h3 class="text-white">Select {{$package->Package_Name}} {{$package->Package_Type}} Days to change</h3>
<button type="button" class="btn add-data text-white rounded-pill">Add Day <i class="fas fa-plus"></i></button>
</div>
<form>
#csrf
#method('DELETE')
#if(session()->has('message'))
<div class="alert alert-success">
{{ session()->get('message') }}
</div>
#endif
<div class="d-flex justify-content-between selectDelete">
<div class="delete pl-3 mt-3 mb-3">
<label for="deleteSelected">Action:</label>
<select name="deleteSelected" id="deleteSelected" class="#error('deleteSelected') is-invalid #enderror" name="deleteSelected" >
<option disabled selected>---------</option>
<option>Delete Selected Package Program</option>
</select>
<button formaction="{{ route('PackageProgram.delete',$package) }}" formmethod="POST" type="submit" class="go" id="deleleGo" onclick="deleteBtn()">Go</button>
<span id="selected">0</span> of {{$showCounts}} selected
#error('deleteSelected')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
<strong id="selectError">You must check at least one checkbox</strong>
</div>
<div class="search pr-3 mt-3 mb-3">
<label for="search">Search:</label>
<input id="search" type="text" color="#000" class="rounded #error('search') is-invalid #enderror" name="search" value="{{ old('search') }}" autocomplete="search" placeholder="Search">
#error('search')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<table class="table table-hover table-striped table-dark">
<thead>
<tr>
<th scope="col"><input type="checkbox" id="checkHead" class="selectall"></th>
<th scope="col">Id</th>
<th scope="col">Day</th>
<th scope="col">Title</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody></tbody>
</table>
</form>
</section>
#endsection
#section('script')
<script src="{{ asset('/js/sqlData.js') }}"></script>
<script>
$(document).ready(function(){
fetch_data();
function fetch_data(query = '')
{
$.ajax({
url:"{{ route('PackageProgram.action',$packageSlug) }}",
method:'GET',
data:{query:query},
dataType:'json',
success:function(data)
{
$('tbody').html(data.table_data);
}
})
}
$(document).on('keyup', '#search', function(){
var query = $(this).val();
fetch_data(query);
});
});
function checkboxError(){
var number = document.querySelectorAll('.selectbox:checked').length;
if(number == 0) {
var a = document.getElementById("selectError").style.display = "block";
return false;
}
}
window.addEventListener('DOMContentLoaded', (event) => {
var deleteBtn = document.getElementById("deleleGo");
deleteBtn.onclick = checkboxError;
});
</script>
#endsection
So my route file looks something like this:
Route::prefix('package-programs')->group(function() {
Route::get('/', 'AdminVisible\packagePackageProgramController#index')->name('PackagePrograms');
Route::get('/action', 'AdminVisible\packagePackageProgramController#action')->name('PackagePrograms.action');
Route::prefix('{packageSlug}')->group(function() {
Route::get('/', 'AdminVisible\PackageProgramController#index')->name('PackageProgram');
Route::get('/action', 'AdminVisible\PackageProgramController#action')->name('PackageProgram.action');
Route::get('/create', 'AdminVisible\PackageProgramController#create')->name('PackageProgram.create');
Route::post('/create', 'AdminVisible\PackageProgramController#store')->name('PackageProgram.store');
Route::delete('/delete','AdminVisible\PackageProgramController#delete')->name('PackageProgram.delete');
Route::get('/{packageProgram}/edit', 'AdminVisible\PackageProgramController#edit')->name('PackageProgram.edit');
Route::patch('/{packageProgram}', 'AdminVisible\PackageProgramController#update')->name('PackageProgram.update');
});
});
It might be I do not know how to pass named route with two parameters but in my blade file, I been doing it like this, and there it works. Is it something different that must be done in the controller.
First start from blade (please check comments):
#extends('layout')
#section('content')
<div class="row">
<table class="table table-hover table-striped table-dark" id="slugTb">
<thead>
<tr>
<th scope="col"><input type="checkbox" id="checkHead" class="selectall"></th>
<th scope="col">Id</th>
<th scope="col">Day</th>
<th scope="col">Title</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
#endsection
#section('scripts')
<script>
$(document).ready(function() {
var query = 'damnSon';
$.ajax({
url: "{{ route('test.action') }}",
method: 'GET',
data: {
'slug': '{{ $packageSlug }}',
'query': query
},
dataType: 'json',
})
.done(function(data) {
console.log(data) //use console.log to debug
$('#slugTb tbody').html(data.table_data); //set table id so that you don't miss the right one
})
.fail(function(err) {
console.log(err) //in case if error happens
})
.always(function() {
console.log( "complete" ); //result despite the response code
});
});
</script>
#endsection
You used deprecated jquery method like success check
Better use this three: done,fail,always
Next route web.php:
Route::get('action', ['as' => 'test.action', 'uses' => 'TestController#action']);
In your case better to use Request params bag so that you can add as much params as you want.
Next controller:
function action(Request $request)
{
$total_row = 1;
$packageSlug = $request->get('slug'); //names that you set in ajax data tag: {'slug': '{{ $packageSlug }}','query': query}
$query = $request->get('query');
$output = '<tr>
<td align="center" colspan="1">' . $packageSlug . '</td>
<td align="center" colspan="1">' . $query .'</td>
</tr>';
$data = array(
'table_data' => $output,
'total_data' => $total_row
);
return response()->json($data);
}
You should return something from the controller so blade can show that data and json encode it so that js could parse it. That is why return response()->json($data);
Other way:
route:
Route::get('/action/{slug}/{query}',['as' => 'test.action', 'uses' => 'TestController#action']);
blade script:
<script>
$(document).ready(function() {
var query = 'damnSon';
$.ajax({
url: 'action/{{ $packageSlug }}/' + query,
method: 'GET',
dataType: 'json',
})
.done(function(data) {
console.log(data) //use console.log to debug
$('#slugTb tbody').html(data.table_data); //set table id so that you don't miss the right one
})
.fail(function(err) {
console.log(err) //in case if error happens
})
.always(function() {
console.log( "complete" ); //result despite the response code
});
});
</script>
and controller:
function action($slug, $query)
{
$total_row = 1;
$packageSlug = $slug;
$query = $query;
$output = '<tr>
<td align="center" colspan="1">' . $packageSlug . '</td>
<td align="center" colspan="1">' . $query .'</td>
</tr>';
$data = array(
'table_data' => $output,
'total_data' => $total_row
);
return response()->json($data);
}
Not recommended just because you manually type route in ajax request: url: 'action/{{ $packageSlug }}/' + query if your route changes you have to change it in js.
I'm trying to add products items into the shopping cart when I click to add to cart button but facing some error how to fix it error
please see this error
Non-static method Gloudemans\Shoppingcart\Cart::add() should not be called statically
http://localhost/Projects/E-commerce/cart/action
Controller
namespace App\ Http\ Controllers;
use Illuminate\ Http\ Request;
use Gloudemans\ Shoppingcart\ Cart;
class CartController extends Controller {
public
function cart() {
$cartcontent = Cart::Content();
return view('front_end/cart', ['cartcontent' => $cartcontent]);
}
public
function addcart(Request $request) {
$image = [$request - > product_image];
$add = Cart::add(
$request - > productid,
$request - > product_name,
$request - > qty,
$request - > product_price,
$image
);
if ($add) {
redirect('/cart');
}
}
html view
<tbody class="cart-table__body">
#foreach($cartcontent as $cartcontents)
<tr class="cart-table__row">
<td class="cart-table__column cart-table__column--image">
<a href="{{$cartcontents->product_image}}">
<img src="{{$cartcontents->product_image}}" alt="">
</a>
</td>
<td class="cart-table__column cart-table__column--product">
{{$cartcontents->product_name}}
</td>
<td class="cart-table__column cart-table__column--price" data-title="Price">
{{$cartcontents->product_price}}</td>
<td class="cart-table__column cart-table__column--quantity" data-title="Quantity">
<div class="input-number">
<input class="form-control input-number__input" type="number" min="1" value="
{{$cartcontents->qty}}">
<div class="input-number__add"></div>
<div class="input-number__sub"></div>
</div>
</td>
<td class="cart-table__column cart-table__column--total" data-title="Total"></td>
<td class="cart-table__column cart-table__column--remove">
<a href="" class="btn btn-light btn-sm btn-svg-icon">
<svg width="12px" height="12px">
<use xlink:href="{{url('public/assets/images/sprite.svg#cross-12')}}"></use>
</svg>
</a>
</td>
</tr>
#endforeach
</tbody>
Use this method to pass cart data to your view
public function cart()
{
$cartcontent = Cart::Content();
$cart_data = [];
foreach($cart_list as $cart){
$cart_data [] = [
//define keys as per your cart's content and pass $cart_data in your view
//like this:
// 'product' => $cart->product
];
}
return view('front_end/cart')->with(compact(['cart_data']));
}
After that loop through cart_data in your view just like you did.
I have validation issue when I tried to apply the coupon code.
I have to apply on 4 condition
If I applied the correct coupon from the database then it will be fine.
If I applied the correct coupon again from the database then it will be
show the message 'This Coupon Have Already Used'.
If I just directly key in button (blank value) it will show the message 'Please Insert
The Coupon Code'
But the problem is what I key in the wrong coupon code, I need to
have 'Wrong Coupon Code Entered' message displayed
Below is the controller part for the function:-
public function checkCoupon(Request $res)
{
$code = $res->code;
$check = DB::table('coupons')
->where('coupon_code',$code)
->get();
if(count($check)=="1") {
$user_id = Auth::user()->id;
$check_used = DB::table('used_coupons')
->where('user_id', $user_id)
->where('coupon_id', $check[0]->id)
->count();
if($check_used=="0"){
$used_add = DB::table('used_coupons')
->insert([
'coupon_id' => $check[0]->id,
'user_id' => $user_id
]);
$insert_cart_total = DB::table('cart_total')
->insert([
'cart_total' => Cart::total(),
'discount' => $check[0]->discount,
'user_id' => $user_id,
'gtotal' => Cart::total() - (Cart::total() * $check[0]->discount)/100,
]);
}
else{
?>
<div class="alert alert-warning">This Coupon Have Already Used</div>
<?php
}
}
else if($code==$check){
?>
<div class="alert alert-danger">Wrong Coupon Code Entered</div>
<?php }
else{
?>
<div class="alert alert-danger">Please Insert The Coupon Code </div>
<?php }
}
JS file for apply coupon function button:-
$(document).ready(function(){
$('#coupon_btn').click(function(){
var coupon_id = $('#coupon_id').val();
$.ajax({
url:'{{url('/checkCoupon')}}',
data: 'code=' + coupon_id,
success:function(res){
$('#cartTotal').html(res);
}
})
});
});
View File
<div class="cart-total" >
<h4>Total Amount</h4>
<table>
<tbody>
<tr>
<td>Sub Total</td>
<td>$ <?php echo Cart::subtotal(); ?></td>
</tr>
<tr>
<td>Tax (%)</td>
<td>$ <?php echo Cart::tax(); ?></td>
</tr>
<tr>
<td>Grand Total new</td>
<td>$ <?php echo Cart::total(); ?></td>
</tr>
<tr>
<td>Discount(%) </td>
<td> <?php echo $disnew; ?></td>
</tr>
<tr>
<td>Grand Total (After discount) </td>
<td>$ <?php echo $gtnew; ?></td>
</tr>
</tbody>
</table>
<input type="submit" class="btn update btn-block" style="color: white;font-weight: bold;" value="Continue Shopping">
Checkout
</div>
To check used coupons better to use exists instead of count.
To get coupon better to use first instead of get (first - return first element, you dont need to use index on collection)
I think, in this situation better to use returns. Code and logic looks clearly.
public function checkCoupon(Request $res)
{
$code = $res->input('code');
$userId = Auth::user()->id;
if(!$code){
return ['error' => '<div class="alert alert-danger">Please Insert The Coupon Code </div>'];
}
$coupon = DB::table('coupons')
->where('coupon_code', $code)
->first();
if(!$coupon) {
return ['error' => '<div class="alert alert-danger">Wrong Coupon Code Entered</div>'];
}
$isUsed = DB::table('used_coupons')
->where('user_id', $userId)
->where('coupon_id', $coupon->id)
->exists();
if($isUsed){
return ['error' => '<div class="alert alert-warning">This Coupon Have Already Used</div>'];
}
DB::table('used_coupons')
->insert([
'coupon_id' => $coupon->id,
'user_id' => $userId
]);
DB::table('cart_total')
->insert([
'cart_total' => Cart::total(),
'discount' => $coupon->discount,
'user_id' => $userId,
'gtotal' => Cart::total() - (Cart::total() * $coupon->discount)/100,
]);
return [
'subtotal' => Cart::subtotal(),
'total' => Cart::total()
];
}
Jquery:
$(document).ready(function(){
$('#coupon_btn').click(function(){
var coupon_id = $('#coupon_id').val();
$.ajax({
url:'{{url('/checkCoupon')}}',
dataType: "json",
data: {code: coupon_id},
success:function(res){
if(res.error){
$('...error_selector...').html(res.error);
} else {
$('...total_selector...').html(res.total);
$('...subtotal_selector...').html(res.subtotal);
}
}
})
});
});
I’m new to jQuery/ajax and even PHP/Symfony2 but I’m learning.
I simply am trying to update my quantity field in my Quantity table in my database using this jQuery number spinner.
The script does work (I get success in console) but if I refresh the page, the quantity changes back to the default/original of ‘1’. How can I make it so if the user changes the quantity it gets updated through to the database. I’m lost on how to do this correctly. Do I need additional code in my controller?
twig:
{% extends '::base.html.twig' %}
{% block body %}
<h1 class="text-center"><u><i>Your Cart</i></u></h1>
<div class="container">
<div class="who_is_logged_in">
{% if user is null %}
Login
{% else %}
<u>Hello<strong> {{ user }}</strong></u>
{% endif %}
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Price Per Unit</th>
<th>Remove Product</th>
</tr>
</thead>
<tbody>
{% for key, product in quantity %}
<tr>
<td>{{ product.product }}</td> <!--Product-->
<td>
<input class="spinner" value="{{ product.quantity }}" style="width:30px">
</td> <!--Quantity-->
<td>${{ product.product.price|default('') }}</td> <!--Price-->
<td>
<a href="{{ path('product_remove', {'id': product.product.id }) }}">
<button name="REMOVE" type="button" class="btn btn-danger" id="removeButton">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</a>
</td><!--Remove-->
</tr>
{% endfor %}
</tbody>
</table> <!--top table-->
<div class="money-container">
<p class="text-right">Total Cost: ${{ totalCostOfAllProducts }}</p>
</div> <!--moneyContainer-->
{% for flash_message in app.session.flashbag.get('notice') %}
<div class="flash-notice">
<strong>{{ flash_message }}</strong>
</div> <!--flashNotice-->
{% endfor %}
</div> <!--container-->
<ul>
<li>
<a href="{{ path('product') }}">
Add More Products
</a>
</li>
<li>
<a href="{{ path('product_bought') }}">
Buy These Products
</a>
</li>
</ul>
<script type="text/javascript">
$(".spinner").spinner();
$('input.spinner').on('spinstop', function(){
min: 0
console.log('spinner changed');
var $this = $(this);
var $value = $('spinner').val();
$.ajax({
url: "{{ path('product_showCart') }}",
method: 'POST',
data : {
quantity: $this.val()
}
}).done(function(resp){
console.log('success', resp);
}).error(function(err){
console.log('error', resp);
});
});
</script>
{% endblock %}
ProductController Relevant Functions:
/**
* Creates the option to 'add product to cart'.
*
* #Route("/{id}/addToCart", name="product_addToCart")
* #Method("GET")
* #Template()
*/
public function addToCartAction(Request $request, $id) {
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('ShopBundle:Product')->find($id);
$product->getId();
$product->getName();
$product->getPrice();
$cart = $em->getRepository('ShopBundle:UserCart')->findOneBy(['user' => $this->getUser(), 'submitted' => false]);
// $quantity = $em->getRepository('ShopBundle:Quantity')->findOneBy(['id' => $this->getUser()]);
if ($this->checkUserLogin()) {
$this->addFlash('notice', 'Login to Create a Cart');
return $this->redirectToRoute('product');
}
// --------------------- assign added products to userCart id ------------------------ //
$quantity = new Quantity();
if (is_null($cart) || $cart->getSubmitted(true)) {
$cart = new UserCart();
}
$cart->setTimestamp(new \DateTime()); // Set Time Product was Added
$quantity->setQuantity(1); // Set Quantity Purchased.......Make jQuery # Spinner the input of setQuantity()
$cart->setSubmitted(false); // Set Submitted
$cart->setUser($this->getUser()); // Sets the User ONCE
$cart->addQuantity($quantity); // Add Quantity ONCE
$quantity->setUserCart($cart); // Create a UserCart ONCE
$quantity->setProduct($product); // Sets the Product to Quantity Association ONCE
$em->persist($product);
$em->persist($cart);
$em->persist($quantity);
$em->flush();
$this->addFlash('notice', 'The product: '.$product->getName().' has been added to the cart!');
return $this->redirectToRoute('product');
}
/**
* Shows Empty Cart
*
* #Route("/showCart", name="product_showCart")
* #METHOD("GET")
* #Template()
*/
public function showCartAction(Request $request) {
// --------------------------- show only what the user added to their cart --------------------------- //
$em = $this->getDoctrine()->getManager();
$user = $this->getUser();
if ($this->checkUserLogin()) {
$this->addFlash('notice', 'Login to Create a Cart');
return $this->redirectToRoute('product');
}
$cart = $em->getRepository('ShopBundle:UserCart')->findOneBy(['user' => $this->getUser(), 'submitted' => false]);
$prodsInCartCost = $cart->getQuantities();
//BELOW just to show what I think I should do...doesn't work though
foreach ($prodsInCartCost as $key => $value) {
$prodsInCartCost = $value->getQuantity();
//Is the below condition on the right track??
if ($request->getMethod() == 'POST') {
$value->setQuantity([/*WHAT GOES HERE?*/]);
$em->persist($value);
$em->flush();
}
}
//end showing what I think I should do example
if (!$cart) {
$this->addFlash('notice', 'There is NO CART');
return $this->redirectToRoute('product');
}
$sub = $cart->getSubmitted();
/**
* Function in UserCart that Maps to Quantity where product values lives.
* $quantity is an object (ArrayCollection / PersistentCollection)
*/
if ($sub == false) {
$quantity = $cart->getQuantities();
} else {
$this->addFlash('notice', 'Cart should be EMPTY');
}
if (!$cart) {
throw $this->createNotFoundException(
'ERROR: You got past Gondor with an EMPTY CART'
);
}
$totalCostOfAllProducts = 0;
$totalCostOfAllProducts = $this->getTotalCost($cart, $totalCostOfAllProducts);
if (empty($price) && empty($quantity) && empty($totalCostOfAllProducts)) {
$price = 0; $quantity = 0; $totalCostOfAllProducts = 0;
}
return array(
'user' => $cart->getUser(), // for :UserCart
'cart' => $cart,
'quantity' => $cart->getQuantities(), // for :UserCart
// 'quantity' => $quantity, // for :UserCart
'totalCostOfAllProducts' => $totalCostOfAllProducts,
);
}
As far as I know you can't mix flash messages with ajax request. You must change your controller action for return a json message that would be processed in javascript, and them maybe change the html value of some element. In that way you can inform the user about the action be successful. After refresh the page the quantity values should be loaded from database in the same way that it was the first time.
//controller action
public function ajaxAction($id)
{
...
$result = array("responseCode" => 200, "data" => $data);
return new Response(json_encode($result ), 200, array('Content-Type' => 'application/json'));
}
//js code
$.ajax({
url: "{{ path('product_showCart') }}",
method: 'POST',
data : {
quantity: $this.val()
}
}).done(function(resp){
if (resp.responseCode == 200) {
$('#div_quantity').html(resp.data)
}
}).error(function(err){
console.log('error', resp);
});
This code is not tested but you can get the idea.
I’m not sure if I’m asking my question in the best way possible or being totally clear but I’ll do my best.
I have the field $quantity in my Quantity entity. Then in one of my controllers I create an instance of my class entity Quantity like this: $quantity = new Quantity();. Finally I set the quantity like this: $quantity->setQuantity(1); just so things make sense and my app can run.
Then in my twig file I implement the jQuery number spinner (https://jqueryui.com/spinner/). I place the quantity field (1) in as the value.
Then in my script for the spinner I try to make it so when I click up or down the quantity is consequently updated in the database. I FAIL. This is what I need help with.
Ultimately I want to update the total cost of the users cart depending on the quantity of the products in the cart.
ProductController relevant functions:
/**
* Creates the option to 'add product to cart'.
*
* #Route("/{id}/addToCart", name="product_addToCart")
* #Method("GET")
* #Template()
*/
public function addToCartAction(Request $request, $id) {
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('ShopBundle:Product')->find($id);
$product->getId();
$product->getName();
$product->getPrice();
$cart = $em->getRepository('ShopBundle:UserCart')->findOneBy(['user' => $this->getUser(), 'submitted' => false]);
// $quantity = $em->getRepository('ShopBundle:Quantity')->findOneBy(['id' => $this->getUser()]);
if ($this->checkUserLogin()) {
$this->addFlash('notice', 'Login to Create a Cart');
return $this->redirectToRoute('product');
}
// --------------------- assign added products to userCart id ------------------------ //
$quantity = new Quantity();
if (is_null($cart) || $cart->getSubmitted(true)) {
$cart = new UserCart();
}
$cart->setTimestamp(new \DateTime()); // Set Time Product was Added
$quantity->setQuantity(1); // Set Quantity Purchased.......Make jQuery # Spinner the input of setQuantity()
$cart->setSubmitted(false); // Set Submitted
$cart->setUser($this->getUser()); // Sets the User ONCE
$cart->addQuantity($quantity); // Add Quantity ONCE
$quantity->setUserCart($cart); // Create a UserCart ONCE
$quantity->setProduct($product); // Sets the Product to Quantity Association ONCE
$em->persist($product);
$em->persist($cart);
$em->persist($quantity);
$em->flush();
$this->addFlash('notice', 'The product: '.$product->getName().' has been added to the cart!');
return $this->redirectToRoute('product');
}
/**
* Shows Empty Cart
*
* #Route("/showCart", name="product_showCart")
* #METHOD("GET")
* #Template()
*/
public function showCartAction(Request $request) {
// --------------------------- show only what the user added to their cart --------------------------- //
$em = $this->getDoctrine()->getManager();
$user = $this->getUser();
if ($this->checkUserLogin()) {
$this->addFlash('notice', 'Login to Create a Cart');
return $this->redirectToRoute('product');
}
// $product = $em->getRepository('ShopBundle:Product')->f
$cart = $em->getRepository('ShopBundle:UserCart')->findOneBy(['user' => $this->getUser(), 'submitted' => false]);
// $productsInUsersCart = $em->getRepository('ShopBundle:Quantity')->findOneBy(['product' => $cart->getId()]);
// dump($productsInUsersCart); die;
// dump($cart); die;
if (!$cart) {
$this->addFlash('notice', 'There is NO CART');
return $this->redirectToRoute('product');
}
$sub = $cart->getSubmitted();
/**
* Function in UserCart that Maps to Quantity where product values lives.
* $quantity is an object (ArrayCollection / PersistentCollection)
*/
if ($sub == false) {
$quantity = $cart->getQuantities();
} else {
$this->addFlash('notice', 'Cart should be EMPTY');
}
if (!$cart) {
throw $this->createNotFoundException(
'ERROR: You got past Gondor with an EMPTY CART'
);
}
$totalCostOfAllProducts = 0;
$totalCostOfAllProducts = $this->getTotalCost($cart, $totalCostOfAllProducts);
if (empty($price) && empty($quantity) && empty($totalCostOfAllProducts)) {
$price = 0; $quantity = 0; $totalCostOfAllProducts = 0;
}
return array(
'user' => $cart->getUser(), // for :UserCart
'cart' => $cart,
'quantity' => $cart->getQuantities(), // for :UserCart
// 'quantity' => $quantity, // for :UserCart
'totalCostOfAllProducts' => $totalCostOfAllProducts,
);
}
twig file where jQuery spinner script is (and the only thing that works is the jQuery spinner increasing or decreasing numbers...nothing else):
{% extends '::base.html.twig' %}
{% block body %}
<h1 class="text-center"><u><i>Your Cart</i></u></h1>
<div class="container">
<div class="who_is_logged_in">
{% if user is null %}
Login
{% else %}
<u>Hello<strong> {{ user }}</strong></u>
{% endif %}
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Price Per Unit</th>
<th>Remove Product</th>
</tr>
</thead>
<tbody>
{% for key, product in quantity %}
<tr>
<td>{{ product.product }}</td> <!--Product-->
<td>
<input class="spinner" value="{{ product.quantity }}" style="width:30px">
</td> <!--Quantity-->
<td>${{ product.product.price|default('') }}</td> <!--Price-->
<td>
<a href="{{ path('product_remove', {'id': product.product.id }) }}">
<button name="REMOVE" type="button" class="btn btn-danger" id="removeButton">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</a>
</td><!--Remove-->
</tr>
{% endfor %}
</tbody>
</table> <!--top table-->
<div class="money-container">
<p class="text-right">Total Cost: ${{ totalCostOfAllProducts }}</p>
</div> <!--moneyContainer-->
{% for flash_message in app.session.flashbag.get('notice') %}
<div class="flash-notice">
<strong>{{ flash_message }}</strong>
</div> <!--flashNotice-->
{% endfor %}
</div> <!--container-->
<ul>
<li>
<a href="{{ path('product') }}">
Add More Products
</a>
</li>
{# {% if cartArray is empty %} #}
{# {% else %} #}
<li>
<a href="{{ path('product_bought') }}">
Buy These Products
</a>
</li>
{# {% endif %} #}
</ul>
<script type="text/javascript">
$(".spinner").spinner();
$('input.spinner').on('change', function(){
var $this = $(this);
$.ajax({
url: '{{ path('product_showCart') }}',
method: 'POST',
data : {
quantity: $this.val()
}
}).done(function(resp){
console.log('success', resp);
}).error(function(err){
console.log('error', resp);
});
});
</script>
{% endblock %}
If you can't already tell I'm new to jQuery/web development but I'm learning day by day. I could really use some help/guidance!
EDIT:
I changed my script to this and now I see my messages in my console but still nothing gets updated/changed in the database and when I refresh my page, the quantity goes back to display '1'.
<script type="text/javascript">
$(".spinner").spinner();
$('input.spinner').on('spinstop', function(){
console.log('spinner changed');
var $this = $(this);
$.ajax({
url: "{{ path('product_showCart') }}",
method: 'GET',
data : {
quantity: $this.val()
}
}).done(function(resp){
console.log('success', resp);
}).error(function(err){
console.log('error', resp);
});
});
</script>