生のPHPでフリマサービスを作る_part3

### この記事のシリーズ
 - [生のPHPでフリマサービスを作る_part1](https://qiita.com/daichi_hasegawa_stars/items/22f12b7c9aa019781b27)
 - [生のPHPでフリマサービスを作る_part2](https://qiita.com/daichi_hasegawa_stars/items/286c5f8ea49ea79e4aa6)

## フリマサービス作成の流れ
1.機能を洗い出す
2.画面設計（今回はPHPの深掘りがメインなので割愛します）
3.テーブル設計
4.クラス設計 ← 今回もここ
5.実装

## クラス設計
前提として、私自身、勉強中の身なのでこれから作っていくクラス設計が合っているかどうかは未知数です。
ただ、基本は単一責任の原則に従って作っていく。
そうすれば、とりあえずは訳のわからないことにはならないはず。

### ユーザー登録機能のクラスを作成
まず、DBへの接続とSQLを実行するクラスを作成する

1. Databaseクラスを以下のように作成
※これ、接続情報ベタ書きしてますが、まじで良くないで実務ではやめてください。
今回はMAMP環境なのと、練習なのでベタ書きしているだけですからね。
```php:Database.php
<?php

// データベースクラス
class Database
{
    const DATABASE = 'mysql:dbname=freemarket;host=localhost;charset=utf8';
    const DATABASE_USER = 'root';
    const DATABASE_PASSWORD = 'root';
    const DATABASE_OPTIONS = array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
    );

    private $dbh;

    // 初期化
    public function __construct($dbh,$sql, $data)
    {
        $this->dbh = $dbh;
    }

    // DB接続
    public static function dbConnect()
    {
        //PDOオブジェクト生成（DBへ接続）
        $dbh = new PDO(self::DATABASE, self::DATABASE_USER, self::DATABASE_PASSWORD, self::DATABASE_OPTIONS);
        return $dbh;
    }
}

```

役割とその範囲は、「データベースに接続し、接続情報（PDOオブジェクト）を返す」クラスだ。
DBへの接続は、フリマサービスの性質上、さまざまなタイミングで実行される。そのためすぐに呼び出せるように
静的メソッドとして定義している。

ちょっと脱線してしまいますが、、staticについて深掘り。
```php:Database.php
 public static function dbConnect()
```
本来だと、クラスを使いたい時はインスタンスを生成しないといけないんだけど、以下のように使いやすくなる。
頻繁に使うクラスとかは静的メソッドにしたほうが良い。
```php
// 基本的なクラスの使い方
$db = new Database();
$dbh = $db->dbConnect();

// staticの場合
$db = Database::dbConnect();
```
「え、簡単に呼べるなら全部静的メソッドにすれば良くね？」
私も最初そう思った。
ただ、そんなうまい話はないと。
まあなぜすぐに呼べるのか？を考えればすぐに分かることなんですが、、
簡単に言うと、静的メソッドの場合、常にメモリを使ってるいる状態なので、全部のメソッドを静的にしたらメモリオーバーになって終わる。
と、僕はそう解釈しました。まあ気になる方は調べましょう。


2.　SQLを実行するためのクラスを以下のように作成
```php:Query.php
<?php

//Databaseクラスを読み込む
require('Class/DB/Database.php');

// クエリを実行するクラス
class Query
{
    private $sql;
    private $data;

    // 初期化
    public function __construct($sql, $data)
    {
        $this->sql = $sql;
        $this->data = $data;
    }

    // クエリ実行
    public static function queryPost($sql, $data)
    {
        //例外処理
        try {
            $stmt = Database::dbConnect()->prepare($sql);
            if (!$stmt->execute($data)) {
                debug('クエリに失敗しました。');
                // エラーメッセージ系のものも後でクラスに切り出します。
                // $err_msg['common'] = MSG07; ←今は一旦無視。
                return 0;
            };
            debug('クエリ成功');
            return $stmt;
        } catch (\Exception $e) {
            error_log('エラー発生:' . $e->getMessage());
            // エラーメッセージ系のものも後でクラスに切り出します。
            // $err_msg['common'] = MSG07; ←今は一旦無視。
        }
    }
}

```

3.　ユーザー登録するためのクラス
```php:Register.php
<?php

//Queryクラスを読み込む
require('Class/DB/Query.php');

//ユーザー登録クラス
class Register
{
    private $email;
    private $pass;

    // 実行するSQLを定数として定義
    const REGISTER_SQL = 'INSERT INTO users (email, pass, login_time, create_date) VALUES(:email, :pass, :login_time, :create_date)';

    // 初期化
    public function __construct($email, $pass)
    {
        $this->email = $email;
        $this->pass = $pass;
    }

    // ユーザー登録
    public function signup($email, $pass)
    {
        $sql = self::REGISTER_SQL;
        $data = array(
            ':email' => $email,
            ':pass' => password_hash($pass, PASSWORD_DEFAULT),
            ':login_time' => date('Y-m-d H:i:s'),
            ':create_date' => date('Y-m-d H:i:s')
        );
        //クエリ実行
        $stmt = Query::queryPost($sql, $data);

        //クエリが成功し、値が返ってきたら、ログイン有効時間などを設定する
        if ($stmt) {
            $sesLimit = 60 + 60;
            $_SESSION['login_date'] = time();
            $_SESSION['login_limit'] = $sesLimit;
            $_SESSION['user_id'] = Database::dbConnect()->lastInsertId();

            debug('セッション変数の中身:' . print_r($_SESSION, true));

            header("Location:mypage.php"); //マイページへ
        }
    }
}

?>
```


ユーザー登録は以上。
次は退会クラスでも作ります。

次回へ！