coiai Logo
coiai

MVC とは?を理解するために簡単なアプリをつくる with Laravel

❓ これは何

ソフトウェアを構築するには、様々な設計モデルがあります。

今回はバックエンドの開発で基礎的で代表的なMVCモデルを少しわかったつもりになるために、
簡単なメモアプリを作ります。

この記事では Laravel を使っています。
まだ Hello World ができていない方は、先に済ませておきましょう。
M1 mac でLaravel のHelloWorldする方法

このページでの🐏はコラムです。読み飛ばしてOKです。

今回完成すると次のようなものになります。
この記事ではスタイリングなどの解説はしていません。
1時間内でとりあえず作ることを目標にしています。

🪴 環境

この記事では Apple Silicon に合わせた書き方になっている箇所があります。(Docker関係)
ご注意ください。

  • Apple m1 MacBook Air
  • 14.5(23F79)

🔧 やり方

MVC(Model-View-Controller)は、ソフトウェア設計の基本原則の一つです。

アプリケーションの構造を

  • Model
  • View
  • Controller

の3つの部分に分けることで、保守性と可読性を向上させます。

🐳 初期設定

ここではApple m1 での設定となっています。
主にDockerに関する操作についてです。

docker-compose.yml は次のようにしました。

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: laravel-app
    container_name: laravel-app
    restart: unless-stopped
    working_dir: /var/www
    volumes:
      - .:/var/www
    networks:
      - laravel
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_PORT=3306
      - DB_DATABASE=your_database_name
      - DB_USERNAME=your_database_user
      - DB_PASSWORD=your_database_password

  webserver:
    image: arm64v8/nginx:alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "8000:80"
    volumes:
      - .:/var/www
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - laravel

  db:
    image: arm64v8/mariadb:10.5
    container_name: db
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=your_database_name
      - MYSQL_USER=your_database_user
      - MYSQL_PASSWORD=your_database_password
    volumes:
      - dbdata:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - laravel

volumes:
  dbdata:

networks:
  laravel:
    driver: bridge

.env ファイルに次のコードを追記します。

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_database_user
DB_PASSWORD=your_database_password

コンテナを起動し、コンテナにアクセスします。

docker-compose up -d
docker-compose exec app bash

migrate したら exit します。

php artisan migrate

マイグレーションファイルの作成

Laravelでは、マイグレーションファイルを使ってデータベーススキーマ(スキーマとは簡単にいうと構造のこと)の変更を定義します。
マイグレーションファイルは、PHPコードでデータベースのテーブルやカラムの追加、削除、変更を記述します。

database/migrationsディレクトリに新しいマイグレーションファイルを生成します。

notes というテーブルが作成されます。

実行後、database/migrations/ホゲホゲcreate_notes_table.php というファイルが作成されていると思います。(ホゲホゲには日付などが入っているはず)

php artisan make:migration create_notes_table --create=notes

🐏 php artisan とは?

  • command: 実行するコマンド(例: make:migration, serve, migrateなど)
  • options: オプションとして指定するもの(例: –force, –quietなど)
  • arguments: コマンドに渡す引数(例: マイグレーションの名前など)
php artisan [command] [options] [arguments]

create_notes_table.php

function up()の中身を次のように追記します。

upメソッド
マイグレーションを適用する際に実行されます。
例では、notesテーブルを作成し、
id, title, content, timestamps
のカラムを定義しています。

downメソッド
マイグレーションをロールバックする際に実行されます。
例では、notesテーブルを削除しています。
ロールバックとはデータベースのマイグレーションを元に戻す操作を指します。具体的には、適用されたマイグレーションを取り消し、以前の状態に戻すことです。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('notes', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('notes');
    }
};

マイグレーションを実行します。
このコマンドで上記コードのupが実行されることになります。。

php artisan migrate

📦 MODEL

メモモデルの作成

モデルはデータベースとのやり取りや、データの検証の実装を担当します。

メモアプリケーションでは、Noteモデルがこれに該当します。Noteモデルはメモのデータ(タイトルと内容)を管理します

メモモデルの作成

php artisan make:model Note

modelsの中の Note.php に次のコードを記述します。

use HasFactory;
Laravelのファクトリ機能を使用します。

protected $fillable = [‘title’, ‘content’];:
マスアサインメントを許可する属性を指定します。

マスアサインメント(Mass Assignment)とは、配列やオブジェクトからモデルの複数の属性に一括で値を割り当てることです。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Note extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'title',
        'content',
    ];
}

🐏 use HasFactory; とは?

ファクトリは、テストデータを作成するクラスであるFactoryを使用して、データベーステーブルにランダムなデータを生成する機能です。

🎮 CONTROLLER

controller の作成

コントローラーはユーザーの入力に応じてモデルとビューを調整します。
リクエストを受け取り、適切なモデルとビューを呼び出してレスポンスを返します。

メモアプリケーションでは、NoteControllerがコントローラーに該当します。
NoteControllerはメモの作成、表示、編集、削除のロジックを担当します。

メモコントローラの作成

php artisan make:controller NoteController --resource

app/Http/Controllers/NoteController.php に次のコードを追加します。

各メソッドは、特定のアクション(一覧表示、作成、保存、表示、編集、更新、削除)を担当します。

リクエストを処理し、適切なビューを返します。

$request->validate([
       'title' => 'required',  // タイトルは必須
       'content' => 'required', // 内容も必須
]);

こういった書き方で、バリデーションを実装できます。

<?php

namespace App\Http\Controllers;

use App\Models\Note;
use Illuminate\Http\Request;

class NoteController extends Controller
{
    // メモの一覧を表示するメソッド
    public function index()
    {
        // データベースからすべてのメモを取得
        $notes = Note::all();
        
        // 'notes.index'ビューを表示し、取得したメモをビューに渡す
        return view('notes.index', compact('notes'));
    }

    // 新しいメモを作成するフォームを表示するメソッド
    public function create()
    {
        // 'notes.create'ビューを表示
        return view('notes.create');
    }

    // 新しいメモを保存するメソッド
    public function store(Request $request)
    {
        // リクエストデータをバリデート
        $request->validate([
            'title' => 'required',  // タイトルは必須
            'content' => 'required', // 内容も必須
        ]);

        // リクエストデータを使って新しいメモを作成
        Note::create($request->all());

        // メモの一覧ページにリダイレクトし、成功メッセージを表示
        return redirect()->route('notes.index')
                        ->with('success', 'Note created successfully.');
    }

    // 特定のメモを表示するメソッド
    public function show(Note $note)
    {
        // 'notes.show'ビューを表示し、特定のメモをビューに渡す
        return view('notes.show', compact('note'));
    }

    // 特定のメモを編集するフォームを表示するメソッド
    public function edit(Note $note)
    {
        // 'notes.edit'ビューを表示し、特定のメモをビューに渡す
        return view('notes.edit', compact('note'));
    }

    // 特定のメモを更新するメソッド
    public function update(Request $request, Note $note)
    {
        // リクエストデータをバリデート
        $request->validate([
            'title' => 'required',  // タイトルは必須
            'content' => 'required', // 内容も必須
        ]);

        // 特定のメモを更新
        $note->update($request->all());

        // メモの一覧ページにリダイレクトし、成功メッセージを表示
        return redirect()->route('notes.index')
                        ->with('success', 'Note updated successfully');
    }

    // 特定のメモを削除するメソッド
    public function destroy(Note $note)
    {
        // 特定のメモを削除
        $note->delete();

        // メモの一覧ページにリダイレクトし、成功メッセージを表示
        return redirect()->route('notes.index')
                        ->with('success', 'Note deleted successfully');
    }
}

ルートの設定

ルートの設定

routes/web.php に次のコードを追記します。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\NoteController;

Route::get('/', [NoteController::class, 'index']);

Route::resource('notes', NoteController::class);

👁️ VIEW

Viewの作成

ビューはユーザーインターフェースを表示します。
データの表示やユーザーの入力を受け付けます。

メモアプリケーションでは、index.blade.php、create.blade.php、edit.blade.php、show.blade.phpがビューに該当します。
これらのビューは、メモのリスト表示、作成フォーム、編集フォーム、詳細表示を担当します。

まずは resources/views に layout.blade.php を作ります。

共通レイアウトを定義し、各ビューで使用します。
ヘッダーやフッターなど、どのページでも使うものもここに書いておくと、このファイルの役割がわかりやすいでしょう。

<!DOCTYPE html>
<html>
<head>
    <title>Memo App</title>
</head>
<body>
    @yield('content')
</body>
</html>

Resources/views フォルダに notes というディレクトリを作り、下記ファイルを作成します。

  • index.blade.php
  • create.blade.php
  • edit.blade.php
  • show.blade.php

index.blade.php

メモの一覧を表示し、各メモに対して詳細表示、編集、削除のリンクがあります。

@extends('layout')

@section('content')
    <h1>Notes</h1>
    <a href="{{ route('notes.create') }}">Create a new note</a>
    <ul>
        @foreach ($notes as $note)
            <li>
                <a href="{{ route('notes.show', $note->id) }}">{{ $note->title }}</a>
                <a href="{{ route('notes.edit', $note->id) }}">Edit</a>
                <form action="{{ route('notes.destroy', $note->id) }}" method="POST">
                    @csrf
                    @method('DELETE')
                    <button type="submit">Delete</button>
                </form>
            </li>
        @endforeach
    </ul>
@endsection

🐏 hoge.blade.php とは?

hoge.blade.php とかくと、Laravelが提供するテンプレートエンジンの「Blade」が使用できます。
BladeはPHPのテンプレートエンジンで、HTML, PHP をより見やすく、書きやすくすることが出来ます。

  • @extends(‘layout’)は、layout.blade.phpを継承することを示しています。
  • @section(‘content’)と@endsectionの間に、レイアウトに挿入するコンテンツを記述します。
  • @foreachループを使って、$notesコレクションの各メモを表示します。
  • @csrfはCSRFトークンを生成し、フォームの送信を保護します。
  • @method(‘DELETE’)はHTMLフォームでDELETEメソッドを使うためのBladeディレクティブです。

🐏 CSRFトークンとは?

CSRF(Cross-Site Request Forgery、クロスサイトリクエストフォージェリ)は、
ユーザーが意図しないリクエストをWebアプリケーションに送信する攻撃です。
CSRFトークンは、この攻撃を防ぐために使用されるセキュリティ機構です。

基本的にPOSTの時には @csrf と書いておけばいいでしょう()

create.blade.php

メモの作成フォームです。

@extends('layout')

@section('content')
    <h1>Create Note</h1>
    <form action="{{ route('notes.store') }}" method="POST">
        @csrf
        <label>Title:</label>
        <input type="text" name="title">
        <label>Content:</label>
        <textarea name="content"></textarea>
        <button type="submit">Create</button>
    </form>
@endsection

edit.blade.php

メモの編集フォームです。

@extends('layout')

@section('content')
    <h1>Edit Note</h1>
    <form action="{{ route('notes.update', $note->id) }}" method="POST">
        @csrf
        @method('PUT')
        <label>Title:</label>
        <input type="text" name="title" value="{{ $note->title }}">
        <label>Content:</label>
        <textarea name="content">{{ $note->content }}</textarea>
        <button type="submit">Update</button>
    </form>
@endsection

show.blade.php

メモの詳細画面です。

@extends('layout')

@section('content')
    <h1>{{ $note->title }}</h1>
    <p>{{ $note->content }}</p>
    <a href="{{ route('notes.index') }}">Back to Notes</a>
@endsection

これで完成です!
実行し、確認してみましょう。

投稿日: 2024年7月16日
カテゴリ: Laravel, おすすめ
タグ: プログラミング
coiai

coiai

この記事もおすすめ

MetaStore コンテンツ型のアプリ内課金を実装する

MetaStore コンテンツ型のアプリ内課金を実装する

MetaStoreのコンテンツ型のアプリ内課金を実装する方法についてです。 コンテンツを追加する 右上のアドオンを作成ボタンを押す。 アドオンタイプ 一度購入したら、それ以降は購入しない設定は耐久型を選びます。アプリ内のコインや石など、消耗品は消耗品を選びます。 価格設定 価格設定タブに進むとコンテンツの価格を設定できます。有料のコンテンツをまだ登録したことない場合は支払い情報の設定が住んでいないはずなので、支払い情報の設定が先に必要になります。 DUC データユーズチェックアップ 左メニューの必要条件の中のデータ使用状況の確認を開きます。 例えばIAPでユーザー認識が必要な場合は User ID, ユーザー名が必要な場合は User Profile の追加ボタンを押します。 何に使うかの用途と説明が求められるのでそこに使用用途を記述してください。 ここまで出来たらリクエストを送信ボタンを押します。 このようにデータの取り扱いについて質問されるので答えてください。英語で書いてあるので、なんとなく何が書いてあるか順番にさらっと説明します。 データの使用状況の確認 左サイドバーから必要条件⇒データ使用状況の確認をクリックします。 これが設定されていないと以下の文言のポップアップが表示されます。 読んでくださった方へ 株式会社coiaiでは、Quest向け、PCVR、Vision OS向けの開発も得意としています。新規開発ももちろん、開発途中でメンバーが必要といった場合でも請け負えますので、ご相談ください!

Microsoft PowerToys 使わないのは損

Microsoft PowerToys 使わないのは損

普段MacユーザーでWindowsの歯がゆさを我慢している方は絶対に入れたほうがいい公式のアプリを紹介します。生産性のバク上がり間違いなし?です。 インストール パッケージマネージャから入れるも良し。WindowsStoreから入れるも良し。 https://learn.microsoft.com/ja-jp/windows/powertoys/install?tabs=store%2Cextract-094 特におすすめの機能 FancyZones(ウィンドウマネージャー) Windowsのスナップ機能の超強化版。自分で好きなウィンドウレイアウトを作成して、ドラッグするだけでウィンドウがピッタリ配置される。マルチモニター環境では特に神。 欲を言うなら固定したアプリを保存する機能がほしかった&#8230;&#8230;!!これに関してはほかのツールを試すしかなさそう。 PowerToys Run(クイックランチャー) Alt + Space でどこからでも起動。アプリ検索、ファイル検索、計算、Web検索、シェルコマンド実行など、プラグインで拡張可能。macOSのSpotlightやAlfredに相当する機能がWindowsで使える。 私は普段Mac使いなので、この機能がMicrosoftの純正として使えるのはかなりアツイ。 コマンドパレット win alt Space で起動。PowerToys Run との使い分けがじゃっかんめんどくさくて一緒になってたらよかったなと思う。 頻繁に使うコマンド・アプリ・ツールに1つのインターフェイスから素早くアクセスできる。カスタマイズ性が高い。 Keyboard Manager(キーリマッパー) キーの再マップやカスタムショートカットの作成ができる。CapsLockをCtrlに変えたり、独自のショートカットを定義したり。レジストリを触らなくていいのが楽。 Text Extractor(OCR) Win + Shift + T で画面上のどこからでもテキストをOCRで読み取ってコピーできる。スクリーンショットから文字を抜き出したいときに最高。日本語も対応。 これ普通に神機能過ぎてやばい。布教したい。 Advanced Paste(高度な貼り付け) クリップボードの内容を好きな形式に変換して貼り付け。プレーンテキスト化、JSON整形、Markdown変換など。AI機能もオプション で使える。 Light Switch ライトモードとダークモードが時間によって切り替わるようになる。 なぜ標準でつけない!? 日常で地味に助かる機能 ユーティリティ 概要 Always On Top Win + Ctrl + T でウィンドウを最前面に固定 [&hellip;]

デフォルトサムネイル

Obsidian 情報整理のディレクトリ構成をどうすべきか

はじめに この記事はObsidian等、ディレクトリの構成を決められるメモアプリで、どのように情報を保存していくかについてのメモです。 ノート遍歴 私はあまりこだわりがなく情報をまばらに散らかしていました。 Google Keep, Evernote, Notion, iOS 純正のメモ, 紙のメモ帳 様々なアプリを試してきましたが、最近では主戦力のメモをアナログな紙とMacのメモ帳という貧弱な装備に戻ってし待っていました。 しかし結局デバイスや場所を跨ぐとなると、統一されたフォーマットでデータを保管したいと思いたち、せっかくなのできちんと整理しようとなったわけです。 情報整理フレームワーク 5選 有名なフレームワークを調べてまとめてみました。 PARA Methodby Tiago Forte https://paramethod.com 情報を「行動との距離」で4つに分類するフレームワーク。最もシンプルで始めやすそうな印象があります。 向いている人:GTD的にタスクを進めたい人、仕事とプライベートを横断して管理したい人 Zettelkastenツェッテルカステン ↓この記事めっちゃ良いのでこんなブログ読むよりこれ読んでください。 https://zettelkasten.de/introduction ドイツの社会学者ニクラス・ルーマンが実践した手法。フォルダ分類に頼らず、ノート同士をリンクで繋いでいくことで知識のネットワークを構築します。Obsidianのグラフビューとの相性は抜群です。 ノートは1つにつき1アイデア(Atomic Note)を原則とし、[[リンク]]でノート同士を結びます。フォルダは最小限に留めるのがポイントです。 向いている人:研究者、ライター、知識を長期的に蓄積・発展させたい人 Johnny Decimal https://johnnydecimal.com 引用:「10 以下」というコンセプトが Johnny.Decimal の中心にあります。 10単位のカテゴリ番号で情報を厳密に管理するシステム。「あのファイルどこだっけ?」がなくなります。 向いている人:整理整頓が好き、大量のノートを厳密に分類したい人 ACCESSby Nick Milo(Linking Your Thinking) バランス型MOC活用 PARAとZettelkastenの良いとこ取りをしたフレームワーク。MOC(Map of Content)という索引ノートを中心に、フォルダとリンクの両方を活用します。 向いている人:フォルダもリンクもバランスよく使いたい人 PARA × Zettelkasten ハイブリッド 実用的おすすめ PARAのフォルダ構造で大枠を整理しつつ、Zettelkastenのリンク思想で知識を繋ぐ。迷ったらこれがおすすめです。 [&hellip;]

この記事を書いた会社

株式会社coiaiは、「想像できることを美しく実現」を掲げ、XR・Web・アプリ・システム開発およびDX支援を行う会社です。 創業2022年、東京都練馬区に本社を置き、要件のヒアリングからPoC(概念実証)、本番運用まで一貫して伴走します。 まずはお気軽にご相談ください。

商号株式会社 coiai創業2022年1月設立2025年1月23日資本金1,500,000円(設立時点)本社所在地東京都練馬区関町北 3-6-9代表者代表取締役 竹村 啓佑 / 代表取締役 服部 陽良

主なご相談内容

会社概要・役員紹介を見る

詳しい会社情報は会社概要ページでご覧いただけます。

資料請求・無料相談

導入要件のヒアリングからPoC、本番運用まで伴走します。まずはお気軽にご相談ください。

お問い合わせの前に 個人情報保護方針 をご確認ください。