ショッピングサイトの レジ機能を作ります。このページの完成図は次のようになります。
2025年8月14日
決済完了ページからブラウザバックでレジページに戻ってきても、データが残っていないように変更しました。
2025年8月19日
Firefox でも決済完了ページからブラウザバックでレジページに戻ってきても、データが残っていないように変更しました。
レジ機能用のルートを追加します。routes / web.php を次のように変更してください。
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CartController;
Route::get('/', [CartController::class, 'index'])->name('cart.index');
Route::post('/cart/add', [CartController::class, 'addToCart'])->name('cart.add');
Route::get('/cart', [CartController::class, 'showCart'])->name('cart.show');
Route::post('/cart/update', [CartController::class, 'updateCart'])->name('cart.update');
Route::post('/cart/remove', [CartController::class, 'removeItem'])->name('cart.remove');
Route::post('/cart/clear', [CartController::class, 'clearCart'])->name('cart.clear');
// ここから
Route::get('/cart/checkout', [CartController::class, 'checkout'])->name('cart.checkout');
// ここまで追加
app / Http / Controllers の CartController.php を次のように変更してください。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Darryldecode\Cart\Facades\CartFacade as Cart;
use App\Models\Product;
use Illuminate\Testing\Constraints\SeeInOrder;
use Nette\Schema\Expect;
class CartController extends Controller
{
public function index()
{
$products = Product::all();
return view('products', compact('products'));
}
public function addToCart(Request $request)
{
$product = [
'id' => $request->id,
'name' => $request->name,
'price' => $request->price,
'quantity' => $request->quantity,
'attributes' => ['added_at' => now()]
];
Cart::add($product);
return redirect('/');
// return $this->showCart();
}
public function showCart()
{
$cartContent = Cart::getContent()->sortBy("attributes.added_at")->values();
return view('cart.show', compact('cartContent'));
}
public function updateCart(Request $request)
{
Cart::update($request->id, [
'quantity' => [
'relative' => false,
'value' => $request->quantity,
]
]);
return $this->showCart();
}
public function removeItem(Request $request)
{
Cart::remove($request->id);
return $this->showCart();
}
public function clearCart()
{
Cart::clear();
return $this->index();
}
// ここから
public function checkout()
{
$cartContent = Cart::getContent()->sortBy("attributes.added_at")->values();
return view('cart.checkout', compact('cartContent'));
}
// ここまで追加
}
public フォルダの style.css を次のように変更してください
/*****************************
style.css
copyright : vivacocoa.jp
last modified: Aug. 12, 2025
******************************/
body {
background-color: #ffffff;
margin: 0;
}
.spc {
display: flex;
background-color: #000000;
}
.spc>div:nth-child(1) {
text-align: left;
width: 30%;
}
.spc>div:nth-child(2) {
text-align: center;
width: 40%;
}
.spc>div:nth-child(3) {
text-align: right;
width: 30%;
}
h1 {
font-size: large;
margin: 16px;
color: #ffffff;
}
h1 a {
color: #ffffff;
text-decoration: none;
}
h1 a:hover {
border: 1px #ffffff solid;
padding: 8px px;
margin: 0px;
}
#btn-cart {
background-color: #ffd600;
color: #000000;
border: 0;
border-radius: 16px;
text-align: center;
font-size: small;
padding: 4px;
width: 100px;
margin: 16px;
font-weight: bolder;
}
#container {
margin-top: 16px;
margin-left: 8px;
}
.d-flex {
display: flex;
flex-wrap: wrap;
justify-content: left;
}
.product {
margin: 8px;
text-align: center;
}
.btn-yellow {
background-color: #ffd600;
border: 0;
border-radius: 16px;
text-align: center;
font-size: small;
margin-bottom: 8px;
width: 85%;
padding: 4px;
}
#btn-checkout {
background-color: #ffd600;
color: #000000;
border: 0;
border-radius: 16px;
text-align: center;
font-size: small;
padding: 4px;
width: 85%;
margin: 16px;
font-weight: bolder;
}
table {
width: 100%;
}
.a-center {
text-align: center;
}
.flex {
display: inline-flex;
/* display: inline-flexbox; */
}
.btn-delete {
text-decoration: underline;
color: blue;
border: 0;
background-color: #ffffff;
margin-top: 8px;
}
/* ここから */
.large-title {
font-size: large;
color: #ffffff;
margin: 16px;
padding: 0;
}
.height-32 {
height: 32px;
}
#container2 {
width: 85%;
margin: 0 auto;
}
label {
font-weight: bold;
text-align: left;
padding: 4px;
display: block;
width: 100%;
}
input {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
.spc2 {
display: flex;
background-color: #ffffff;
}
.spc2>div:nth-child(1) {
text-align: left;
width: 50%;
}
.spc2>div:nth-child(2) {
text-align: right;
width: 50%;
}
/* ここまで追加 */
public フォルダに browserbacked.js というファイルを作り、次のように記述してください。
2025年8月14日。
決済完了ページからブラウザバックで戻ってきても、データが残っていないように、この JavaScriptを追加します。
2025年8月19日。
Firefox でも有効になるように修正しました。
window.addEventListener('pageshow', function(event) {
if (event.persisted) {
window.location.reload();
document.getElementById('checkout-form').reset(); // for Firefox
}
});
resources / views / cart に checkout.blade.php というファイルを作り、次のように記述してください。
2025年8月14日。
決済完了ページからブラウザバックで戻ってきても、データが残っていないように変更しました。また、
決済完了ページへのデータの送り方を1箇所変更しました。変更になる箇所は2箇所2行です。
2025年8月19日。
Firefox でも決済完了ページからブラウザバックで戻ってきても、データが残っていないように変更しました。
変更になる箇所は1箇所1行です。
{{----------------------------
checkout.blade.php
copyright : vivacocoa.jp
last modified: Aug. 19, 2025
----------------------------}}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>お会計</title>
<link rel="stylesheet" href="{{url('style.css')}}">
{{-- 次の1行を追加しました。--}}
<script src="{{ url('browserbacked.js') }}"></script>
{{-- 上の1行を追加しました。--}}
</head>
<body>
<div class="spc">
<div>
<h1><a href="{{ route('cart.index') }}">AMAZONESS</a></h1>
</div>
<div>
<p class="large-title">チェックアウト</p>
</div>
<div>
<a href="{{route('cart.show')}}"><button type="button" id="btn-cart">
カート [ {{Cart::getTotalQuantity()}} ]
</button></a>
</div>
</div>
<div class="height-32"></div>
<div class="a-center">
{{-- 2025年8月19日、次の1行が変更になりました。--}}
<form id="checkout-form">
{{-- 2025年8月19日、上の1行が変更になりました。--}}
@csrf
<button type="button" class="btn-yellow"><strong>注文を確定する</strong></button>
</div>
<div id="container2">
<div class="a-center">
<p><small>合計金額: ¥ {{ number_format(Cart::getSubTotalWithoutConditions()) }} 税込
</small></p>
{{-- 次の1行を追加 --}}
<input type="hidden" name="totalprice" value="{{(Cart::getSubTotalWithoutConditions())}}">
{{-- 上の1行を追加 --}}
</div>
<div>
<label>お名前</label>
<input type="string" name="name" required>
</div>
<div>
<label>ご住所</label>
<input type="text" name="addr" required>
</div>
<div>
<label>カード番号</label>
<input type="number" name="cardNum" min="1000000000000000" max="9999999999999999" required placeholder="16桁数字">
</div>
<div>
<label>カード期限日</label>
<input type="sring" name="cardExp" required pattern="(0[1-9]|1[0-2])\/[0-9]{2}" placeholder="MM/YY">
</div>
<div>
<label>カードのお名前</label>
<input type="string" name="cardName" pattern="[a-zA-Z ]*" placeholder="アルファベットで入力してください" required>
</div>
<div>
<label>CVC</label>
<input type="string" name="cardCff" required pattern="[A-Za-z0-9]{3}|[A-Za-z0-9]{4}" placeholder="3桁か4桁の英数字">
</div>
<input type="hidden" name="date" value="<?php
date_default_timezone_set('Asia/Tokyo');
echo date("Y/m/d H:i"); ?>">
</form>
<div class="height-32"></div>
<div class="spc2">
<div>
<a href="{{ route('cart.index') }}"><button type="button" class="btn-yellow"><strong>ショッピングを続ける</strong></button></a>
</div>
<div>
<a href="{{ route('cart.show') }}"><button type="button" class="btn-yellow"><strong>カートに戻る</strong></button></a>
</div>
</div>
</div>
</body>
</html>
商品ページで止めていたリンクを張り直します。resources / views / cart の show.blade.php を次のように変更してください。 変更箇所は1箇所で3行です。
{{----------------------------
show.blade.php
copyright : vivacocoa.jp
last modified: Aug. 12, 2025
------------------------------}}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{url('style.css')}}">
<script src="{{url('staticposition.js')}}"></script>
<title>ショッピングカート</title>
</head>
<body>
<div class="spc">
<div>
<h1><a href="{{ route('cart.index') }}">AMAZONESS</a></h1>
</div>
<div></div>
<div>
{{-- ここから --}}
<form method="GET" action="{{ route('cart.checkout') }}">
@csrf
<button type="submit" id="btn-checkout"><strong>レジに進む</strong></button>
{{-- ここまで変更 --}}
</form>
</div>
</div>
<div id="container">
<table>
@foreach($cartContent as $item)
<tr>
<td>
<div class="a-center">
<p><strong>{{ $item->name }}</strong></p>
</div>
</td>
<td>
<div>
<p><small>¥</small> {{ number_format($item->price) }} <small>税込</small></p>
</div>
</td>
<td>
<div class="flex">
<form method="POST" action="{{route('cart.update')}}">
@csrf
<input type="hidden" name="id" value="{{$item->id}}">
<input type="number" name="quantity" onchange="submit()" style="width: 50px;" value="{{$item->quantity}}"> <small>個</small>
</form>
<form method="POST" action="{{route('cart.remove')}}">
@csrf
<input type="hidden" name="id" value="{{$item->id}}">
<button type="submit" class="btn-delete">削除</button>
</form>
</div>
</td>
<td>
<div>
<p><small>¥</small> {{ number_format($item->price * $item->quantity) }} <small>税込</small></p>
</div>
</td>
</tr>
@endforeach
<tr>
<td colspan="2">
<a href="{{ route('cart.index') }}"><button type="button" class="btn-yellow"><strong>ショッピングを続ける</strong></button></a>
</td>
<td class="a-right">
<form method="POST" action="{{ route('cart.clear') }}">
@csrf
<button type="submit" class="btn-yellow"><strong>カートを空にする</strong></button>
</form>
</td>
<td class="a-right">
<small>合計</small>
<small>¥</small> {{ number_format(Cart::getSubTotalWithoutConditions()) }} <small>税込</small>
</td>
</tr>
</table>
</div>
</body>
</html>
GitHub で、変更箇所だけアップロードしたりダウンロードするには、次のようにします。
# 変更箇所だけのアップロード
# ターミナルでローカルの cart ディレクトリに移動して
git add .
git commit -m "cart"
git push -u origin main
#変更箇所だけのダウンロード
# サーバーの cart ディレクトリに移動して
git pull
# おそらく、次のようなエラーが出ると思います。
error: Your local changes to the following files would be overwritten by merge:
[file name]
Please commit your change or stash them before you merge.
# 上記のエラーが出たら、次のようにコマンドします
git stash
# そして、もう一度 pull します。
git pull
# なお、このエラーが出るのは、最初に pull した時の1回目だけです。2回目からの pull ではエラーは出ないと思います。
お使いのブラウザで、localhost:8000 もしくは 127.0.0.1:8000 にアクセスしてください。 「ご注文を確定する」以外のボタンは、すべて機能しています。