【PHP】マッチ機能

マッチングアプリによくあるマッチ機能を実装しました。
![match 1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/852fd507-f292-775f-6aff-912c7b032092.gif)
#スワイプカード
まずはスワイプを行うカードを作成します。
![swipe_card.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/a6d3224f-64b0-c486-2ced-da7cbddbc6bf.gif)

```html
<div class="card">
    <div class="matching_btn">
        <label>
            <div class="fa-image_range">
                <i class="fas fa-times-circle"></i>
            </div>
            <input type="button" id="unmatch_btn" style="display:none;">
        </label>
        <label>
            <div class="fa-image_range">
                <i class="fas fa-heart"></i>
            </div>
            <input type="button" id="match_btn" style="display:none">
        </label>
    </div>
</div>

<script src=" https://code.jquery.com/jquery-3.4.1.min.js "></script>
<script>
$(document).on('click', '#match_btn', function() {
    $('.card').animate({
        "marginLeft": "758px"
    }).fadeOut();
});

$(document).on('click', '#unmatch_btn', function() {
    $('.card').animate({
        "marginRight": "758px"
    }).fadeOut();
});
</script>
```
`HTML`でカードのレイアウト、`JavaScript`でボタンクリック時にカードが動くよう実装しています。

```html
<i class="fas fa-times-circle"></i>
:
<i class="fas fa-heart"></i>
```
`Font Awasome`で`♡`と`×`を引用。

https://fontawesome.com/

#ユーザー数に合わせてカード作成
登録されているユーザー数だけ、カードを表示します。

```php
$user = new User($current_user);
$users = $user->get_users("all");
foreach ($users as $user) :
    if ($user['id'] != $current_user['id']) :
        if (!check_match($user['id'], $current_user['id'])) :
?>
<div class="card">
    <label>
        <i class="far fa-times-circle profile_clear"></i>
        <input type="button" id="profile_clear">
    </label>
    <img src="/user/image/<?= $user['image'] ?>" class="mypage">
    <h3 class="profile_name"><?= $user['name'] ?></h3>
    <p class="comment"><?= $user['profile'] ?></p>
    <div class="matching_btn">
        <label>
            <div class="fa-image_range">
                <i class="fas fa-times-circle"></i>
            </div>
            <input type="button" id="unmatch_btn" style="display:none;">
        </label>
        <label>
            <div class="fa-image_range">
                <i class="fas fa-heart"></i>
            </div>
            <input type="button" id="match_btn" style="display:none">
        </label>
    </div>
</div>
<?php
        endif;
    endif;
endforeach;
```
`$user->get_users("all")`で現在登録されているユーザー情報を取得しており、
`foreach`関数でユーザー数だけカードを表示させています。
![swipe_card1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/84b4fbdd-223d-0b29-f5a9-a1b32437ba71.gif)
現状、すべてのカードが連動して処理に反応してしまうので、１枚１枚動かせるようにします。
また、レイアウトもカードが重なるように修正していきます。

```html
<div class="card" id="match<?= $user['id'] ?>">
:
:
<i class="fas fa-times-circle"></i>
</div>
<input type="button" id="unmatch_btn" data-target="#match<?= $user['id'] ?>" style="display:none;">
<input type="hidden" class="unmatch_user_id" value="<?= $current_user['id'] ?>">
:
:
<input type="button" id="match_btn" data-target="#match<?= $user['id'] ?>" style="display:none">
<input type="hidden" id="modal<?= $user['id'] ?>_userid" value="<?= $user['id'] ?>">
<input type="hidden" class="match_user_id" value="<?= $current_user['id'] ?>">
</label>
<script>
$(document).on('click', '#unmatch_btn', function() {
    var target_modal = $(this).data("target");
    $(target_modal).animate({
        "marginRight": "758px"
    }).fadeOut();
});

$(document).on('click', '#match_btn', function() {　　
    var target_modal = $(this).data("target");
    $(target_modal).animate({
        "marginLeft": "758px"
    }).fadeOut();
});
</script>
```
`data-taget`を使用して、１枚１枚動くようにし、
`style='position: absolute;'`でカードが重ならないようにします。
![swipe_card2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/cd08af49-4838-8e0c-6858-9490da8e061a.gif)
#ユーザIDを保存するマッチテーブル
カードをスワイプしたときに、ユーザIDを保存するテーブルを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/974a62fe-cf3b-c609-2eba-0e501bac8f7d.png)
`matchテーブル`に`スワイプされる側のユーザID`を`user_id`、`スワイプする側のユーザID`を`match_user_id`として保存します。
画面上だと、このようにDBに値が渡ります。
![swipe_card4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/43bbd281-3ce6-1637-fe0a-8e11afa4e8de.gif)
※ユーザIDはそれぞれ次のようになっています。
test_user：7
test_user2：8

では、ajax処理でカードスワイプ時にDBへ値が渡るようにします。
処理の流れはこちらと似ているので参考までに。

https://qiita.com/ryouya3948/items/7b3899e8d2cc8c80dcc6

マッチボタンクリック時に、イベントが発火するようにします。

```js
$(document).on('click', '#match_btn', function(e) {
    e.stopPropagation();
    var current_user_id = $('.match_user_id').val(),
        target_modal = $(this).data("target"),
        user_id = $('' + target_modal + '_userid').val();
    $.ajax({
        type: 'POST',
        url: '../ajax_match_process.php',
        dataType: 'text',
        data: {
            current_user_id: current_user_id,
            user_id: user_id
        }
    }).done(function() {
    }).fail(function() {
   });
});
```
マッチボタンをクリックすると処理が走り、`ajax_match_process.php`に相互のユーザーIDを渡して`matchテーブル`に更新されます。

```php
//　ajax_match_process.php

if (isset($_POST)) {
  $current_user_id = $_POST['current_user_id'];
  $user_id = $_POST['user_id'];
  $action = '登録';
  $flash_type = 'sucsess';
  $sql = "INSERT INTO `match`(user_id,match_user_id)
  VALUES(:user_id,:matched_user_id)";
  try {
    $dbh = db_connect();
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':user_id' => $current_user_id, ':matched_user_id' => $user_id));
  } catch (\Exception $e) {
    error_log($e, 3, "../php/error.log");
    _debug('マッチ失敗');
    echo json_encode("error");
  }
}
```
このように取得したユーザーIDからDBへの更新を行っています。
次に`user_id`と`match_user_id`でお互いの値をもっているときに、モーダル画面を出力するイベントを発火させます。

※お互いの値をもっているときとは、下記のような状況のときです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/75e7197a-be2d-b4d9-8b30-ed682c551a1e.png)
#COOKIEを使ってマッチング画面表示
カードをスワイプして、お互いのユーザーIDを取得したときにCOOKIEを使ってマッチング画面を表示させます。
まずは`ajax_match_process.php`でDB更新時に、お互いのユーザーIDがあるか確認し、有ればCOOKIEを取得するような処理にします。

```php
// ajax_match_process.php
:
:
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(':user_id' => $current_user_id, ':matched_user_id' => $user_id));
    if (count(check_matchs($user_id, $current_user_id)) == 2) {
      setcookie('username', 1, time() + 60 * 60 * 24 * 7);
    } else {
      setcookie('username', "", time() - 60);
    }
  } catch (\Exception $e) {
:
:
function check_matchs($user_id, $current_user_id)
{
    $dbh = db_connect();
    $sql = "SELECT user_id,match_user_id
        FROM `match`
        WHERE (user_id = :user_id and match_user_id = :match_user_id) or (user_id = :match_user_id and match_user_id = :user_id)";
    $stmt = $dbh->prepare($sql);
    $stmt->execute(array(
      ':user_id' => $current_user_id,
      ':match_user_id' => $user_id
    ));
}
```
`check_matchs`関数でお互いのユーザーIDがあるか確認をとり、有れば名前を`username`、値を`1`としてCOOKIEを作成します。

```html
<div class="modal_match" style="display:none"></div>
<div class="match_process" id="match<?= $user['id'] ?>" style="display:none">
    <h2 class="post_title"><?= $user['name'] ?>さんとマッチしました</h2>
    <img name="profile_image" class="matching_img" src="/user/image/<?= $user['image'] ?>">
</div>
<i class="far fa-times-circle match_clear" style="display:none"></i>
```
COOKIEの値が条件と合えば、こちらのモーダル画面を出力するようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/79389db8-33ba-d359-3212-4b3a55398ead.png)

```js
:
:
            current_user_id: current_user_id,
            user_id: user_id
        }
    }).done(function() {
        var cookies = document.cookie;
        var cookiesArray = cookies.split(';');

        for (var c of cookiesArray) {
            var cArray = c.split('=');
            if (cArray[0] == ' username') {
                $('.modal_match').fadeIn();
                $(match_modal).fadeIn();
                $('.match_clear').fadeIn();
                $(document).on('click', '.far.fa-times-circle.match_clear', function() {
                    $('.modal_match').hide();
                    $(match_modal).hide();
                    $('.far.fa-times-circle.match_clear').hide();
                });
            }
        }
```
COOKIEから`username`の値を取得し、有ればモーダル画面表示するようにします。
COOKIEからの値取得方法は下記Qiitaを参考にさせていただきました。

https://qiita.com/dokkoisho/items/b415f1c9852c8fd12ec8

正常に動けば、このようにマッチ機能が動きます。
![match 1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/852fd507-f292-775f-6aff-912c7b032092.gif)