Laravelは、表現力豊かで美しい構文を持つPHPのウェブアプリケーションフレームワーク。豊富なパッケージとライブラリでプログラミングの面倒なタスクが簡素化され、開発作業も捗ります。

Laravelを使ったクリエイティブプロジェクトのひとつとして、個人ブログの構築があります。今回はLaravelを使ってブログを構築し、Kinstaで公開する方法をご紹介していきます。

本記事で例として取り上げるプロジェクトのコードの全貌はこちらでご覧ください。

前提条件

これからご紹介する例では、以下を前提とします。

  • ウェブサーバー(今回の例ではXAMPPを使用)
  • アプリケーションのコードを公開するためのGitHub、GitLab、またはBitbucketのアカウント
  • Laravelがインストールされている状態
  • Kinstaのアプリケーションホスティングを使用するためのMyKinstaアカウント(お持ちでない場合は、無料利用枠をお使いください)

XAMPPのコントロールパネルで、ApacheMySQLモジュールサービスが稼働していることを確認します。実行されていない場合は、「Actions」欄の各サービスの「Start」ボタンをクリックしてください。XAMPPのコントロールパネルは以下のようになっています。

XAMPPのコントロールパネル
XAMPPのコントロールパネル

デフォルトでは、MySQL/MariaDBはポート3306で動作します。ポートを変更する場合は注意してください。

XAMPP以外のウェブサーバーを使用している場合は、Apacheまたは他のサーバーソフトウェアを実行し、ローカルマシンにMariaDBサーバーをインストールします。

phpMyAdminのクイックスタート

  1. MySQLとApacheが起動している状態で、ブラウザにアクセスします。
  2. phpMyAdminを開き、http://localhost/phpmyadmin/を貼り付けると、以下のような画面が表示されます。
phpMyAdminをブラウザで開く
phpMyAdminをブラウザで開く

phpMyAdminは、MySQLとMariaDB用のデータベース管理ツールです。

Laravelプロジェクトの作成

これで、Laravelを使ってブログを作成する準備が整いました。オペレーティングシステムはWindowsを使用します。

  1. マシンのターミナルかコマンドラインインターフェイス(CLI)にアクセス。
  2. laravel new blogコマンドで、Laravelプロジェクト「blog」を作成します。
  3. cd blogコマンドで、プロジェクトのblogディレクトリを開きます。
  4. このディレクトリをコードエディターで開きます。
  5. プロジェクトが正常にビルドされたことを確認するため、ターミナルまたはCMDでphp artisan serveを実行。
  6. ローカルのアドレス出力をクリックし、ブラウザに出力。ブラウザに、デフォルトのLaravelウェルカムページが表示されればOKです。
Laravelのウェルカムページ
Laravelのウェルカムページ

データベースの設定

次にブラウザでphpMyAdminに戻り、データベース「blog」を作成し、設定を行っていきます。

  1. Database」タブで「Create database」セクションのフィールドに「blog」と入力します。
  2. Create」ボタンをクリック。
phpMyAdminでデータベースを作成
phpMyAdminでデータベースを作成
  1. blogプロジェクトのルートにある.envファイルのデータベース接続を更新。DB_DATABASEDB_PASSWORDの値を作成したものに置き換えます。

接続情報は、以下のようになります。

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=your-db-username
DB_PASSWORD=your-db-password

その他のデータベース接続情報は.envファイルと同じになりますが、DB_PORTを3306から3307に変更するなど、接続の値を変更した場合は、.envファイルを更新してください。

投稿テーブルの作成

続いてデータベースモデルを作成し、変更を移行します。

  1. ターミナルでphp artisan make:model Post -mcを実行し、モデル「Post」、テーブル「posts」、マイグレーションファイル、コントローラーを作成します。
コマンドラインでモデル、マイグレーションファイル、コントローラを作成
コマンドラインでモデル、マイグレーションファイル、コントローラを作成
  1. database/migrationsディレクトリを確認し、作成したマイグレーションファイルを開きます。ファイルの形式は、YYYY_MM_DD_ID_create_posts_table.phpです。
  2. マイグレーションファイルのup()メソッドにtitledescriptionimage属性を持つスキーマを作成。
public function up() {
  Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title')->nullable();
    $table->text('description')->nullable();
    $table->string('image')->nullable();
    $table->timestamps();
  });
}
  1. ターミナルに移動し、php artisan migrateを使用して、以下のように変更を移行します。
Laravelデータベースのマイグレーション
Laravelデータベースのマイグレーション
  1. ブラウザでphpMyAdminにアクセスし、postsテーブルを確認します。
移行されたpostsテーブルがphpMyAdminに表示される
移行されたpostsテーブルがphpMyAdminに表示される

コントローラーの作成

ビューとコントローラを追加すると、データベースセットのビジネスロジックが実装されます。ビューは、モデルからのデータオブジェクトを表示するユーザーインターフェース。コントローラーは、モデルとビュー間のデータ実行の流れを管理する役割を担います。

  1. Bladeファイルを作成する前に、ターミナルでまずnpm install、その後npm run devを実行します。最初のコマンドは、必要なnpmパッケージをインストールするもので、2つ目のコマンドでVite開発サーバーを起動します。
  2. app/Http/Controllersディレクトリに移動し、PostController.phpファイルを開き、コントローラーメソッドのindexを作成します。このメソッドは、単純なテキストをブラウザにレンダリングするもの。PostControllerクラスに以下のコードを貼り付けます。
public function index() {
  $post = "Laravel解説記事パート1";
  return view('posts.index', ['post'=>$post]);
}

これによって、$postをコンテキスト変数として、インデックスBladeテンプレートのviewsセクションに渡します。$postは表示するテキストで(この例では「Laravel解説記事パート1」)、後ほどこれを投稿のループに置き換えます。

  1. resources/viewsディレクトリに、layoutspostsの2つのディレクトリを作成します。
  2. layoutsディレクトリ内にapp.blade.phpファイルを作成します。他のBladeファイルはこのファイルを継承。
  3. 以下のコードをapp.blade.phpにコピーします。
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Blog</title>
  <!-- Styles →
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

<!-- Navbar →
<header>
  <nav class="navbar bg-primary">
    <div class="container-fluid">
      <a class="navbar-brand" href="{{ route('posts.index') }}">Mini-Blog</a>
    </div>
  </nav>
</header>


<body>
  @yield('content')
</body>


<footer class="footer mt-auto py-3 bg-dark">
  <div class="container d-lg-flex justify-content-between">
    <span class="text-light">Mini-Blog © 2023</span>
  </div>
</footer>

<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"  integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</html>

このHTMLコードを使用することで、Bootstrapバージョン 5.2.3、JavaScript、CSSアセットをバンドルするViteをインポートします。生成されたページには、ナビゲーションバー(navbar)付きのヘッダーと、その下にスクリプトが呼び出されたフッターがあります。本文は、@yield('content')によって、他のBladeファイルから動的コンテンツがレンダリングされます。

postsディレクトリには、createとreadオペレーションを実装するためのBladeファイルが格納されています。

  1. postsディレクトリ内にBladeファイル「index.blade.php」を作成し、以下のコードを貼り付けます。
@extends('layouts.app')
@section('content')
<div class="container">
  <div class="titlebar">
    <h1>Blog list</h1>
  </div>
  <hr>
  <p>The Blog 1 - {{ $post }}</p>
</div>
@endsection

このコードは、layoutsページのapp.blade.phpファイルから継承しています。ブラウザでレンダリングすると、各ブログ記事のコンテンツと、layoutsフォルダ内のapp.blade.phpファイルから継承したナビゲーションバーとフッターが表示されます。セクションタグの間に、アプリケーションの実行時にブラウザでレンダリングするコンテンツを、コントローラーから渡します。

  1. routesディレクトリにルートを設定。ルートを設定することで、App/ProvidersディレクトリのRouteServiceProvider(アプリのルートファイルの読み込みを担うクラス)を自動的に読み込むことができます。
  2. routes/web.phpファイル内でuse AppHttpControllersPostControllerを使って、PostControllerをインポートします。
  3. Route::resource('posts', PostController::class);routes/web.phpファイルに追加し、ルートを設定。
  4. Vite開発サーバーを起動したまま、php artisan serveを使ってターミナルでアプリケーションを実行。
  5. ブラウザでhttp://127.0.0.1:8000/postsを開き、ブログ記事リストを表示します。

ページは以下のようになるはず。

ブログアプリケーションがブラウザに表示される
ブログアプリケーションがブラウザに表示される

次のステップは、すべての投稿の表示、投稿の作成、そして投稿を保存するためのコントローラーメソッドの定義です。対応するセクションでルートを追加し、Bladeファイルを作成します。

ブログ投稿ページの作成

タイトルを入力し、説明を追加したら、画像をアップロードしてブログ記事を作成します。それから、記事を順番に表示しましょう。

  1. app/ModelsディレクトリでPost.phpファイルを開きます。
  2. use HasFactory;コードブロック下のPostクラスに、protected $fillable = ['title', 'description', 'image'];を追加。

このコードによって、大量割り当てからモデルの属性を保護します。

  1. app/Http/Controllers/PostController.phpファイルで、use AppModelsPost;を使用してPostモデルをインポート。
  2. PostControllerクラスのindexcreateコントローラーメソッドを以下のコードに置き換えます。
// すべての投稿を表示
public function index() {
  $posts = Post::orderBy('created_at', 'desc')->get();
  return view('posts.index', ['posts' => $posts]);
}
    
// 投稿を作成
public function create() {
  return view('posts.create');
}

先ほど作成したindexメソッドによって、PHPアプリケーションがすべての投稿を取得し、時系列に並べた上で、posts変数に格納します。return viewで、views/postsディレクトリのコンテキスト変数として、投稿がindex.blade.phpファイルに渡されます。createメソッドはcreate.blade.phpファイルを返し、投稿を作成しようとすると、views/postsディレクトリに配置します。

  1. 以下のコードを使用して、コントローラメソッドのstoreを作成(ブログ記事をデータベースに保存)。次のコードをindexcreateメソッド下のPostControllerクラスに貼り付けます。
// 投稿を保存
public function store(Request $request) {
  // 検証
  $request->validate([
    'title' => 'required',
    'description' => 'required',
    'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
  ]);

  $post = new Post;

  $file_name = time() . '.' . request()->image->getClientOriginalExtension();
  request()->image->move(public_path('images'), $file_name);

  $post->title = $request->title;
  $post->description = $request->description;
  $post->image = $file_name;

  $post->save();
  return redirect()->route('posts.index')->with('success', 'Post created successfully.');
}

storeメソッドは、本文のデータに関するクライアントのリクエストを処理し、引数としてrequestを受け取ります。次に、投稿を作成する際に使用されるフィールドを検証し、Postモデルからpostインスタンスを作成します。入力されたフィールドデータは、作成されたインスタンスに割り当てられ、保存されます。「Post created successfully」(投稿が作成されました)というフラッシュテキストとともに、indexのビューにリダイレクトされます。

投稿へのルートの追加

以下の手順で、web.phpファイルにルートを追加します。

  1. プロジェクトのルートにあるroutesディレクトリで、web.phpファイルを開きます。
  2. 既存のコードを次のように置き換えて、コントローラーメソッドのルートを登録。
<?php

use IlluminateSupportFacadesRoute;
use AppHttpControllersPostController;

Route::resource('/', PostController::class)->names([
  'index' => 'posts.index',
  'create' => 'posts.create',
  'store' => 'posts.store',
  'show' => 'posts.show',
]);

これらのルートによって、データオブジェクトが作成、保存、表示されます。

Bladeファイルの作成

ビューを作成するには、PostControllerクラスに戻ります。

  1. resources/views/postsディレクトリに、Bladeファイル「create.blade.php」を作成し、以下のコードを貼り付けます。
@extends('layouts.app')
@section('content')
<div class="container">
  <h1>Add Post</h1>
  <section class="mt-3">
    <form method="post" action="{{ route('posts.store') }}" enctype="multipart/form-data">
      @csrf
      <!-- データ未入力時のエラーメッセージ -->
      @if ($errors->any())
        <div class="alert alert-danger">
          <ul>
            @foreach ($errors->all() as $error)
              <li>{{ $error }}</li>
            @endforeach
          </ul>
        </div>
      @endif
      <div class="card p-3">
        <label for="floatingInput">Title</label>
        <input class="form-control" type="text" name="title">
        <label for="floatingTextArea">Description</label>
        <textarea class="form-control" name="description" id="floatingTextarea" cols="30" rows="10"></textarea>
        <label for="formFile" class="form-label">Add Image</label>
        <img src="" alt="" class="img-blog">
        <input class="form-control" type="file" name="image">
      </div>
      <button class="btn btn-secondary m-3">Save</button>
    </form>
  </section>
    
</div>
@endsection

上記では、まずcreate.blade.php@extends('layouts.app')を使用して、layoutsディレクトリのapp.blade.phpのコンテンツ(ヘッダー、ナビゲーションバー、フッターなど)を継承します。また、h1タグ内にAdd Postテキストを追加して、{{route('posts.store')}}アクションを含むpostメソッドでフォームを作成します。

enctype="multipart/form-data"は、画像のアップロードを可能にするもので、csrfはクロスサイトスクリプティング(XSS)攻撃からフォームを保護するものです。そして、エラーメッセージによって無効なフィールドエントリと属性(field attributes)が表示され、フォームのラベルと入力項目が生成されます。

  1. index.blade.phpファイルのコードを以下のコードに置き換えて、すべてのブログ記事を表示します。
@extends('layouts.app')
@section('content')
<div class="container">
  <div class="titlebar">
    <a class="btn btn-secondary float-end mt-3" href="{{ route('posts.create') }}" role="button">Add Post</a>
    <h1>Mini post list</h1>
  </div>
    
  <hr>
  
  @if ($message = Session::get('success'))
  <div class="alert alert-success">
    <p>{{ $message }}</p>
  </div>
  @endif
         @if (count($posts) > 0)
    @foreach ($posts as $post)
      <div class="row">
        <div class="col-12">
          <div class="row">
            <div class="col-2">
              <img class="img-fluid" style="max-width:50%;" src="{{ asset('images/'.$post->image)}}" alt="">
            </div>
            <div class="col-10">
              <h4>{{$post->title}}</h4>
            </div>
          </div>
          <p>{{$post->description}}</p>
          <hr>
        </div>
      </div>
    @endforeach
  @else
    <p>No Posts found</p>
  @endif
</div>
@endsection

このコードによって、投稿追加ボタンが実装されます。クリックすると、投稿が作成され、任意のデータがページの本文に渡されます。ifの条件は、データベースにデータがあるかどうかをチェックします。データがある場合はパス、データがなければ、「No Posts found」(ページが見つかりませんでした)と表示されます。

ページの構造化

これで、php artisan serveを使用して、ブログ記事を作成・表示するアプリケーションを実行できます。<a href="http://127.0.0.1:8000">http://127.0.0.1:8000</a >を開くと、ページは次のようになるはず。

ブログアプリケーションがブラウザに表示される
ブログアプリケーションがブラウザに表示される

記事を追加すると、このように表示されます。

ブラウザにブログアプリケーションの記事が表示される
ブラウザにブログアプリケーションの記事が表示される

LaravelブログをKinstaにデプロイする方法

Kinstaのアプリケーションホスティングサービスを利用して、Laravelアプリをデプロイおよびテストするには、以下の手順に従ってください。

  1. .htaccessファイルの作成
  2. コードをリポジトリにプッシュ
  3. MyKinstaでデータベースを作成
  4. MyKinstaでプロジェクトをセットアップ
  5. ブログをビルドしてデプロイ

.htaccessファイルの作成

プロジェクトのルートフォルダに.htaccessファイルを作成し、以下のコードを貼り付けます。

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

これによって、アプリケーションのリクエストをデプロイメント内のpublic/index.phpにリダイレクトします。

コードをリポジトリにプッシュ

プロジェクトのリポジトリを作成して、コードを公開します。GitHub、GitLab、またはBitbucketを使用してコードをホストし、MyKinstaにデプロイできます。

MyKinstaでデータベースをセットアップ

以下の手順で、MyKinstaにデータベースを作成します。

  1. サービスを追加」ボタンをクリックして、「データベース」を選択。
  2. データベースの情報を入力(以下スクリーンショット参照)。なお、「データベースのユーザー名」はデフォルトのままにしてください。
MyKinstaでデータベースを作成
MyKinstaでデータベースを作成

設定する情報は、データベース名表示名データベースタイプ、 バージョンデータベースのユーザー名データセンターの所在地、およびサイズです。今回の例では、データベースにMariaDBを使用し、サイズは「Db3(CPU=1/RAM=4GB/ディスク容量=10GB)82.55ドル/月)」を選択します。データベースのタイプとサイズは、要件に応じて選択してください。

  1. 設定を終えたら、「続行」をクリック。
  2. 月額料金を確認し、支払い情報を選択して、「データベースを作成」をクリックします。

MyKinstaでプロジェクトをセットアップ

続いて、アプリケーションをMyKinstaにデプロイします。

  1. MyKinstaの「ダッシュボード」画面に移動します。
  2. サービスを追加」をクリックし、「アプリケーション」を選択。
MyKinstaのダッシュボードでアプリケーションを追加
MyKinstaのダッシュボードでアプリケーションを追加

アプリケーションの追加」画面で以下の設定を行います。

  1. ブランチの選択」セクションでGitHubリポジトリを選択し、「コミットに際し自動でデプロイ」にチェックを入れます。
  2. 基本情報」セクションでアプリケーション名を入力し、データセンターの所在地を選択。
  3. Laravelはデプロイ時にアプリキーが必要になるため、「環境変数」セクションを開いて、「キー1」に「APP_KEY」を追加します。ローカルの.envファイルで定義されたAPP_KEYを使用するか、Laravelキージェネレーターを使って取得可能です。
  4. 続行」をクリックして次に進みます。
  5. アプリケーションのビルドリソース(CPUとRAM)を選択します。この例では、「標準のビルドマシン(1CPU/4GB RAM)」を使用。
  6. 「コンテナイメージを自動で設定」は選択したまま次の項目へ。
  7. 続行」をクリック。
  8. プロセスのセットアップ」で、アプリケーションのポッドサイズとインスタンスを変更可能です。今回の例ではデフォルト値を使用。
  9. 続行」をクリック。
  10. 最終確認画面で利用料金や支払い方法を確認し、「アプリケーションを作成」をクリックして、アプリケーションのデプロイを開始します。「デプロイメントの詳細」画面にリダイレクトされ、デプロイメントの進行状況が表示されます。

ブログをビルドしてデプロイ

続いて、データベースとアプリケーションをホストした状態で、データベースをアプリケーションに接続し、ビルドしてデプロイします。

データベースを接続するには、外部接続を使用します。データベースの「情報」画面の「外部情報」セクションで必要な情報を確認できます。

データベースの外部接続
データベースの外部接続
  1. デプロイしたアプリの「設定」画面の「環境変数」セクションに移動します。
  2. 環境変数を追加」をクリックし、外部接続に必要な情報を設定します。.envファイルと同じ変数を使用してください。
データベースの環境変数
データベースの環境変数

手動で編集した<code>env</code>変数を他の変数と区別したい場合には、上記スクリーンショットを参考にしてみてください。

APP_URL」はホストしているアプリケーションのURLで、「DB_CONNECTION」はmysqlです。

  1. アプリケーションの「設定」画面を開きます。
  2. Buildpack」セクションでPHPとNode.jsをBuildpackとして追加します。PHPアプリケーションであるため、PHPのBuildpackは最後に追加してください。
  3. デプロイする」をクリックしてアプリケーションを再構築します。

次に、データベースマイグレーションのプロセスを追加します。

  1. アプリケーション」>「プロセス」画面に移動します。
  2. ランタイムプロセス」セクションの「プロセスを追加」をクリック。
  3. 名前に「Migration」、タイプに「バックグラウンドプロセス」、startコマンドにphp artisan migrate --forceをそれぞれ設定します(Podサイズとインスタンスはデフォルト値のままでOK)。
  4. 続行」をクリックしてプロセスを作成。これによってビルドがトリガーされ、アプリケーションが再デプロイされます。
  5. アプリケーションの「ドメイン」画面でアプリケーションのリンクをクリック。
  6. なお、MyKinstaにデプロイされたブログアプリケーションには、投稿が表示されません。タイトルを入力し、説明を追加したら、画像を選択して投稿を作成します。

まとめ

Laravelを使えば、シンプルなブログをすぐに開発することができます。高速なページ読み込み、堅牢なコントローラーアーキテクチャ、堅牢なセキュリティにより、アプリケーションのパフォーマンスも容易に向上可能です。Kinstaの専用コントロールパネル「MyKinsta」を使えば、ウェブアプリケーションを効率的にリリース、出荷できます。また使用した分だけ支払う従量制の価格設定により、隠れたコストもありません。

Kinstaのホスティングなら、LaravelアプリがGoogle Cloud Platformのプレミアムティアで実行されるため、最高速度を実現できます。さらに、Cloudflare統合によるエンタープライズレベルのDDoS対策、悪意のあるユーザーを寄せ付けない高度なファイアウォールなども付帯します。

ウェブアプリ開発とホスティングをレベルアップしませんか?まずはアプリケーションホスティングの無料利用枠でその性能をお試しください。

Marcia Ramos Kinsta

I'm the Editorial Team Lead at Kinsta. I'm a open source enthusiast and I love coding. With more than 7 years of technical writing and editing for the tech industry, I love collaborating with people to create clear and concise pieces of content and improve workflows.