しばらくぶりにシステム作ってみました。
飲食店のチェーン店でタブレットのメニューシステムを見てた時、「作れそうかも」と思ったこと。
ですがPHPはまだまだ初心者。想像しながらの穴だらけ試作システムです。
DBも初めて連携しました。
やりたいこと
- DBからメニューを書出し
- メニュー注文機能の作成(追加、変更、削除)
- 検索システム
ブラウザからDBにメニューを入れる管理システムも作ってみました。
▶︎ファミレスのメニューもどき管理画面を作ってみた
##トップページ index.php
XDでざっくりデザイン作成後、HTMLとCSSで組み立て。
こんな感じのUIです。
メニューボックスをクリックするとメニュー注文へ。
共通のDB接続はパーツ化してインクルード。
DBからSELECTで全データを取得後配列化。
//DB接続のインクルードは省略
//DBより一覧表書き出し
$sql_list = 'SELECT * FROM menulist order by ID ASC';
$stmt = $dbh->prepare($sql_list);
$stmt->execute();
$data =array();
$count = $stmt->rowCount();//レコード数取得
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$data[] = $row;
メニュー一覧はカテゴリーごとにまとめたかったので、それぞれforeachでループしました。
カテゴリーの順番も任意で。
メインの後にドリンクがくると何かしっくりいかないし、やはりサラダ、スープ、前菜など順番は大切かなと。
foreachの中にifでカテゴリーごとにループさせるのは分かったのですが、
if($row['category'] == 'メイン')
だといちいちカテゴリーごとにブロックを書かないといけないので、面倒い。時間を置いて考えて、for文で試してみました。
$cat_listという配列を手作り。任意の順番で並べたかったので下記のように記述。
$cat_list = ['メイン','サラダ','スープ','サイドメニュー','麺・パスタ','デザート','ドリンク'];
それぞれのsectionに同一ページスクロール用のidも付けたかったのでid用の配列も作成。
$cat_listの内容と順番を合わせておきます。
$category_id = ['mainmenu','salad','soup','sideMenu','pasta','dessert','drink'];
forの$iはforeachの中で使うとうまく出力しなかったので外側で変数に代入。
$cat_item = $cat_list[$i];
<?php for($i = 0; $i < count($cat_list); $i++): ?>
<!-- $iはforeachの中に入れるとちゃんと表示されないので外で変数にした -->
<?php $cat_item = $cat_list[$i]; ?>
<!-- idを付与 -->
<section id="<?php echo $category_id[$i]; ?>">
<h2 class="catTitle"><span>Category</span><?php echo $cat_list[$i]; ?></h2>
<ul class="menuBox">
<?php foreach($data as $row): ?>
<!-- カテゴリーごとにまとめて書き出し -->
<?php if($row['category'] == $cat_item): ?>
<li class="selectOrder">
<div class="img">
<img src="<?php echo $img_path.$row['image']; ?>" alt="">
<p class="cart">注文する</p>
</div>
<div class="details">
<p class="material"><?php echo $row['material']; ?></p>
<p class="menuName">商品名<span><?php echo $row['item']; ?></span></p>
<dl>
<dt>金額</dt>
<dd><span class="orderPlic"><?php echo number_format($row['plice']); ?></span>円<span class="smallText">(税込)</span></dd>
</dl>
</div>
</li>
<!-- //.selectOrder -->
<?php endif; ?>
<?php endforeach; ?>
</ul>
</section>
<?php endfor; ?>
思うようにリスト化出来ました。
嬉しい。
###注文確認フォーム
注文確認フォームは移行せず、同一ページ内で最初は非表示にしてメニューBOXがクリックされたらformが表示。
選んだアイテムだけが書き出されるようjsで操作。
ここはcount数で悩まされました。
jsで++countを置いているので、初期値を-1に
<input id="count" type="hidden" name="count_menu" value="-1">
//submitで持っていく値の個数と番号の変数
let count;
//商品をクリックしたら注文リストへ
jQuery('.selectOrder').on('click',function(){
//選んだ商品データを変数に入れておく
const orderName = jQuery('.menuName span',this).text();
const orderImg = jQuery('.img img',this).attr('src');
const orderPlice = jQuery('.orderPlic',this).text();
//カウントを取得しておかないとおかしくなる
count = jQuery('#count').attr('value');
//count位置重要
++count;
//TOP注文リスト表示、メニュー一覧非表示
jQuery('#orderBox').css('display','block');
jQuery('#header,#main').css('display','none');
//追加・変更ページ
jQuery('#orderChangeBox').css('display','block');
jQuery('#headerChange,#mainChange').css('display','none');
//注文の商品名、値段、画像、個数を書き出し、カウント数と合わせておく
//tableの中に要素書き出し
jQuery('#orderMenu,#changeMenu').append('<tr><th class="orderName">'+orderName+'</th><td class="orderImg"><img src="'+orderImg+'" alt=""></td><td class="orderOneplice">'+orderPlice+'円<span class="smallText">(税込)</span><img src="image/icon_x.svg" alt=""></td><td class="num"><input type="number" name="num'+count+'" min="1" max="50" value="1">個</td><td><p class="deleteMenu">削除<img src="image/icon_x.svg" alt=""></p></td></tr>');
//name属性+カウント数でgetで持っていく値と数を指定
jQuery('#count').before('<input type="hidden" name="title'+count+'" value="'+orderName+'"><input type="hidden" name="plice'+count+'" value="'+orderPlice+'"><input type="hidden" name="img'+count+'" value="'+orderImg+'">');
jQuery('#count').attr('value',count);
});
//MENU削除
jQuery(document).on('click', '.deleteMenu', function(){
//デリートボタンを押したtrのみを削除
jQuery(this).parents('tr').remove();
//現在のカウントを取得
count = jQuery('#count').attr('value');
//削除によって揃わなくなった個数と順番の連動を合わせる
for(let i=0; i < count; ++i){
jQuery('input[name^="title"]').eq(i).attr('name','title'+i);
jQuery('input[name^="plice"]').eq(i).attr('name','plice'+i);
jQuery('input[name^="num"]').eq(i).attr('name','num'+i);
jQuery('input[name^="img"]').eq(i).attr('name','img'+i);
}
//1個ずつ持っていく数を減らす
--count;
jQuery('#count').attr('value',count);
//確認リストから商品がなくなったらメニュー一覧を表示
if(count < 0){
jQuery('#orderBox,#orderChangeBox').css('display','none');
jQuery('#header,#main,#headerChange,#mainChange').css('display','block');
}
});
jQueryでappendメソッドで後から追加した要素にclickイベントを効かせるようにするには要素に対してではなく、documentに対してイベントを設定しないとダメみたいです。
受け取り先の$_GETでは
for($i = 0; $i < $count_menu+1; $i++)
こうすると数が合うようになりました。
$count_menu = isset($_GET['count_menu']);
//XSS関数作成html_escape()
$count_menu = html_escape($_GET['count_menu']);
$count_menu = (int)$count_menu;
$order_name = [];
$one_plice = [];
$num = [];
$sub_plise = [];
$order_img = [];
//設定したカウント数でname値を書き出し配列へ入れる
for($i = 0; $i < $count_menu+1; $i++){
$order_name[$i] = html_escape($_GET['title'.$i]);
$one_plice[$i] = html_escape($_GET['plice'.$i]);
$order_img[$i] = html_escape($_GET['img'.$i]);
//文字列内にある”,”を""に変換
$one_plice[$i] = str_replace(',', '',$one_plice[$i]);
$one_plice[$i] = (int)$one_plice[$i];
$num[$i] = html_escape($_GET['num'.$i]);
$num[$i] = (int)$num[$i];
//値段と個数を掛けておく
$sub_plise[$i] = $one_plice[$i] * $num[$i];
}
追記:構成見直して改装しました
検索機能をプラスして大きく仕様を変更しました。
メニューからは1つだけ選択しsubmitで送信、注文リストorder_change.phpで要素の集計(カートの中身のようなイメージ)にしました。
下記のようなページ移行です。
order_count.phpとorder_count_menu.phpの中身は同じです。Locationの飛び先だけが違います。
注文リストorder_change.phpの個数変更・削除はjsなので変更してメニュー一覧ページに飛ぶとデータは変更前に戻ってしまいます。
そこで変更データも持っていけるように、このページだけsubmitを2つに分けました。
clickイベントで合計ページに行く場合はactionをorder.phpへ、メニューに飛ぶ場合はorder_count_menu.phpへattrメソッドで切り替えです。
色々回り道をしましたが、とりあえずこの形で置いておくことにします。
GitHubにコードを公開しました
メニュー一覧のほか、管理画面、CSSなど一式をGitHubにアップしました。
宜しかったらどうぞ。