ファミレスのメニューシステムもどき作ってみた

しばらくぶりにシステム作ってみました。
飲食店のチェーン店でタブレットのメニューシステムを見てた時、「作れそうかも」と思ったこと。

ですがPHPはまだまだ初心者。想像しながらの穴だらけ試作システムです。
DBも初めて連携しました。

**やりたいこと**
 - DBからメニューを書出し
 - メニュー注文機能の作成(追加、変更、削除)
 - 検索システム

ブラウザからDBにメニューを入れる管理システムも作ってみました。
[▶︎ファミレスのメニューもどき管理画面を作ってみた](https://qiita.com/kanrek_jyosi/items/252cf415c11769bd2e11)

下記が相関関係図です。
![relation.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641189/e9740c92-d49a-1709-80ee-42d4969babb4.jpeg)

##トップページ index.php
XDでざっくりデザイン作成後、HTMLとCSSで組み立て。
こんな感じのUIです。
![menutop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641189/4baaddf1-2685-dc18-8337-8cf1f818a69d.png)
メニューボックスをクリックするとメニュー注文へ。

[▶︎サンプルサイトはこちら](https://mymenu.okamechan.com/menulist/)

共通のDB接続はパーツ化してインクルード。
DBからSELECTで全データを取得後配列化。

```php:index.php
//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:index.php
<?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">`

```js:bace.js
//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');
    }
  });
```

:::note warn
jQueryでappendメソッドで後から追加した要素にclickイベントを効かせるようにするには要素に対してではなく、documentに対してイベントを設定しないとダメみたいです。
:::

受け取り先の$_GETでは
`for($i = 0; $i < $count_menu+1; $i++)`
こうすると数が合うようになりました。

```php:order.php
$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で要素の集計(カートの中身のようなイメージ)にしました。
下記のようなページ移行です。
![menu_list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641189/fad723ea-7aad-c4fd-e830-7a654e2e7b50.png)
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にアップしました。
宜しかったらどうぞ。

[https://github.com/mugikomugi/menulist.git](https://github.com/mugikomugi/menulist.git)