🤸‍♀️

MVCを考えながらミニWebアプリを作る

に公開

はじめに

こんにちは!
今回はMVCの設計思想に基づきながらWebアプリ開発をしていきたいと思います!
今回作成するWebアプリは、合成画像を作成できるカメラアプリです
PHPを書くのは初めてなので、規模は小さく、学び多めで開発しました。

目次

  1. アプリ概要
  2. 使用技術
  3. MVCって?
  4. 実装

1. アプリ概要

  • フォトフレームを用意し、Webカメラで撮影したものと合成した画像を作成できるWebアプリ
  • 撮影されたすべての画像は公開され、いいねやコメントが閲覧可能である

要件

  • ユーザー機能
  • ギャラリー機能
  • 編集機能
    を作成します
    以下それぞれの機能についての詳細

ユーザー機能

  • ユーザー登録(メールアドレス、ユーザー名、パスワード)
  • 登録後のメール認証
  • ユーザー名とパスワードでのログイン
  • ユーザー名とパスワードでログインできます。パスワードを忘れた場合は、再設定ができるメールを送信できます。
  • 常にワンクリックでログアウトできる
  • ログイン後にユーザー情報の変更が可能

ギャラリー機能

  • この機能は公開されている
  • すべてのユーザーが編集した画像を作成日順で表示できる
  • ログインユーザーのみ、いいねやコメントを行える
  • 画像に新しいコメントがついた場合、画像作者にメール通知がされる(デフォルトで有効で無効化もできる)
  • 画像一覧はページネーションされる:1ページあたり最低5件

編集機能

  • この機能はログイン済みのユーザーのみ利用できる
  • 未ログインユーザーは丁寧に拒否される
  • ページは以下の2つのセクションを含む
    • webカメラのプレビュー、合成画像の一覧、撮影ボタンを含むメインセクション
    • 過去に撮影した画像のサムネイルを表示するサイドセクション
  • 合成画像を選択するまでは撮影ボタンは無効である必要がある
  • 最終的な画像生成(画像の合成を含む)はサーバーサイドで行われる必要がある
  • webカメラを持たないユーザーのために画像アップロードを許可する
  • ユーザーは自分の画像のみを削除できる

2. 使用技術

  • 言語
    • サーバー側:PHP
    • クライアント側:HTML、CSS、JavaScript(ブラウザ標準APIのみ)
  • 開発環境
    • docker

3. MVCとは

  • MVCとは、アプリの役割を3つに分けて整理する設計思想
    • M(Model): データ・処理
    • V(View): 画面表示
    • C(Controller): 処理の流れを制御
      それぞれの役割
      Model
  • DBとのやり取り
  • データの取得・保存
  • ビジネスロジック
    例
  • ユーザー登録
  • 投稿画像の保存
  • いいね数の更新

View

  • HTMLを出力
  • 見た目だけ担当
  • ロジックは極力書かない
    例
  • ログイン画面
  • 投稿一覧
  • 画像表示

Controller(コントローラ

  • リクエストを受け取る
  • Modelを呼ぶ
  • Viewを選ぶ
    例
  • ログイン処理
  • 画像アップロード処理
  • コメント投稿処理

MVCは処理を機能ごとに分けて進める意識が大事だと思います
例:ログイン処理

  1. ユーザーが /login にアクセス
  2. Controller が受け取る
  3. Model にログイン確認を依頼
  4. 結果を View に渡す
  5. HTMLを返す
ブラウザ
  ↓
Controller
  ↓
Model(DB確認)
  ↓
Controller
  ↓
View(HTML)
  ↓
ブラウザ

のようにこの処理はMVCのどれで処理してどこに渡すのかを考えながら設計する必要があります。

以下のようにディレクトリを分けておくとわかりやすいです

camagru/
├── public/
│   └── index.php        ← 入口(全リクエスト)
├── controllers/
│   ├── AuthController.php
│   └── PhotoController.php
├── models/
│   ├── User.php
│   └── Photo.php
├── views/
│   ├── auth/
│   │   └── login.php
│   └── photo/
│       └── gallery.php
└── config/
    └── database.php

ポイントは、

  • 小さく分ける
  • 役割を混ぜない

です

実装

1. 入口

今回はPHPなどはすでにインストールされている前提で進めます。
まず、ルートディレクトリ直下は、

camagru/
├── public/
├── app/
├── config/
└── storage/

のように準備します。
ルートディレクトリで、

touch public/index.php

中身は、

<?php
echo 'Hello App!';

動作確認してみます。

cd camagru
php -S localhost:8000 -t public

http://localhost:8000
にアクセスして、「Hello App!」が表示されていればOKです!

2. MVCを意識した構成

1) ディレクトリを追加

mkdir -p app/Core app/Controllers app/Views

2) ルータを作る

app/Core/Router.php

<?php

class Router
{
    public function dispatch(): void
    {
        $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

        if ($path === '/' || $path === '') {
            require_once __DIR__ . '/../Controllers/HomeController.php';
            (new HomeController())->index();
            return;
        }

        if ($path === '/login') {
            require_once __DIR__ . '/../Controllers/AuthController.php';
            (new AuthController())->login();
            return;
        }

        http_response_code(404);
        require_once __DIR__ . '/../Views/error/404.php';
    }
}

3) コントローラを追加

app/Controllers/HomeController.php

<?php

class HomeController
{
    public function index(): void
    {
        require __DIR__ . '/../Views/home.php';
    }
}

app/Controllers/AuthController.php

<?php

class AuthController
{
    public function login(): void
    {
        require __DIR__ . '/../Views/auth/login.php';
    }
}

4) View を追加

mkdir -p app/Views/auth app/Views/error

app/Views/home.php

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Home</title></head>
<body>
  <h1>Camagru Home</h1>
  <a href="/login">Login</a>
</body>
</html>

app/Views/auth/login.php

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Login</title></head>
<body>
  <h1>Login</h1>
  <a href="/">Back</a>
</body>
</html>

app/Views/error/404.php

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>404</title></head>
<body>
  <h1>404 Not Found</h1>
  <a href="/">Back</a>
</body>
</html>
  1. public/index.php を Router 経由にする

public/index.php

<?php

require_once __DIR__ . '/../app/Core/Router.php';

$router = new Router();
$router->dispatch();

3) コントローラーを追加
の部分でViewの中身を書いてしまえば表示されますが、ここがMVCの大事な観点で、責務の分離です。
表示と制御を分けるというのが本質です。
一見遠回りに見えますが大事なクッションです!

ここで、わたしは「RouterとControllersって役割似ていないか?」と考えてしまいました。

  • Routerは、
    • URL は何か
    • どの Controller / action を呼ぶか
    • HTTPレベルの入口制御
      を判断し、
  • Controllersでは、
    • GETかPOSTか
    • 入力が正しいか
    • ログイン成功か失敗か
    • どの View を出すか
    • リダイレクトするか

の判断を行っています。
同じ案内役に見えますが、扱うものが全然違うので分けて管理するのですね!

動作確認してみましょう

php -S localhost:8000 -t public

http://localhost:8000/
→ Home

http://localhost:8000/login
→ Login

http://localhost:8000/xxx
→ 404


ページが見れました!

まとめ

  • MVCは3つの役割に分割して処理する設計思想
  • Controllerで見せるページの分岐を処理する

続きもどんどん書いていこうと思います!

Discussion