4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Webアプリ開発初学者向け Laravelハンズオン講座

Last updated at Posted at 2022-04-23

はじめに

自己紹介?

アルバイト先でLaravelでWebアプリを作ることになり, php初学者から頑張ってなんとか要求されたものを作り上げました. そして, 今後のために部局内向けのLaravel講座の資料を作ることになったのですが, その資料から機密事項を除いて一般化したものがこの記事になります.

概要&目的

  • Laravelなどの多くのwebフレームワークで採用されているMVCの概念を知る.
  • Laravelでの開発の流れを知る.ここでは, ToDoアプリの開発を通して基本的な機能に触れていきます.

平易な表現を目指したため一部厳密ではない箇所があります. また, 本文中で参考サイトへのリンクを貼っているので, 必要に応じて参照してください.

前提・対象読者

このハンズオン講座では, 以下の前提知識のもとで進行します.

  • php の基本的な文法を知っている(FizzBuzzや, 互除法による最小公倍数の計算などを作成できる程度)
    • 一応phpを何も知らなくてもコードのコピペだけで動作させることができますが, 本講座ではphpの文法の解説はしていないため別で学習することをおすすめします.
  • classがなんとなーくわかる
  • html, css の記法を知っている

これらに不安がある場合は, 先にこれらを学習してから進めることを推奨します.

また, Webアプリ開発の知識は不要です(この記事でなんとなくのイメージが掴めます).

準備

準備

本講座では, Laravelの実行環境としてdocker-composeのCLIツールを使います.

  1. docker-composeの導入
    WindowsではWSLを使うと良いかと思います. (参考サイト Mac, Windows/Linux)

  2. 使用するファイルのダウンロード
    GitのCLIを使っている場合は, 任意のディレクトリで $ git clone https://github.com/KateSawada/laravel-handson.git でcloneできます. もしくは, ブラウザで https://github.com/KateSawada/laravel-handson.git を開き, 右上の緑のcloneボタンからダウンロード, 解凍してください.
    また, この講座の終了時点での完成した状態のプログラム類一式をcompleteブランチで提供しています. 必要に応じて参照してください.

  3. Cloneしたディレクトリに移動し,$ docker-compose up --build -dでコンテナを起動します. 二回目以降は, --buildは省略できます.
    ここまで正しくできている場合は, 2つのコンテナが起動します. $ docker-compose psで2つのコンテナの status が up になっていることを確認してください.
    エラーが出る場合は, 各手順に間違いが無いか確認してください. -dを省略すると全てのログを表示させられるので, 検索に役立つでしょう(この場合はCtrl+Cで終了できます).

  4. Laravelアプリケーションの作成
    $ docker-compose exec web bashで, webコンテナに入り, $ rm .gitkeepの後 $ composer create-project --prefer-dist laravel/laravel . "8.*"を実行します(補足: 空のディレクトリをgitで管理できないため, ダミーのファイル.gitkeepを入れておいたのですが, $ composer create-projectは空のディレクトリにのみ実行できるため, rmによって既存のファイルを消去してディレクトリを空にしました). これで, handson/にLaravelのプロジェクトが作成されます. ブラウザで http://localhost:8080 にアクセスすると, 初期ページが表示されます.
    The stream of file "/var/www/html/storage/logs/laravel.log" could not be opened ...というパーミッション周りのエラーが出た場合は, $ chmod -R 777 storage bootstrap/cache を実行してください(参考).
    本講座では, 以降はhandson/をルートとしてパスを表記します. また, 以後出てくるコマンドは全てコンテナ内で実行してください.

  5. Laravelの設定
    ローカルの開発環境や動作確認環境, 本番環境などで切り分けたい設定などを扱うため, 環境変数を記述する.envファイルを使用します. ここでは, ローカルの環境のための設定を記述しましょう.
    .envを開いてDB関係の変数(11行目付近にあると思います)を以下のように設定します. ここで記述するDB_DATABASE, DB_USERNAME, DB_PASSWORDの値は, docker-compose.ymlのdb内に記述された値と対応しています.

.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=handson
DB_USERNAME=user
DB_PASSWORD=password

補足

  • コンテナから出る際は, sshなどと同様に$ exitで戻ります.
  • dockerの終了時は, コンテナから出た状態で $ docker-compose downを実行することで全てのコンテナを安全に落とすことができます.

知っておきたい諸概念

.envの利用

Webアプリケーション開発の過程において, 主に

  • ローカル環境(各自のPC)
  • 開発環境/テスト環境
  • 本番環境

の3つの動作環境が登場します. そしてそれぞれにおいて異なる設定をすることが多いため, それらの相違点を簡単に管理するために.envというファイルが用いられます.

Laravelでは, プロジェクトのルートに.envが作成されます. 準備の章でDB関係の設定を変更したファイルのことです.
環境の切り分けとして, 以下のような例が想定されます.

  • ローカル環境では認証(ログイン処理)を飛ばして, 指定のテスト用ユーザーを使いたい.
  • 開発環境, 本番環境では認証されたユーザーを使いたい.

これらの, 環境ごとに固有の設定や利用するAPI のアクセス情報はソース管理やセキュリティの観点から.envに記述するのが良いでしょう.
このファイルはLaravelのデフォルトではgitでは管理されない(.gitignoreによって管理対象から除外されている)ため, 複数人で同一のプロジェクトを開発する場合はgit外で内容について共有する必要があります.

.env の各値は, Laravel のプログラム内では config ファイルを通して使用することが推奨されています.
まずは, config/handson.phpを作成し, 以下を記述してください.

config/handson.php
<?php
return[
    'HIMITSU_PASSWORD' => env('HIMITSU_PASSWORD', '1qaz2wsx'),
];

'変数名' => env('変数名', 'デフォルト値')という書式で記述します.

続いて.env に以下を追記しましょう.

.env
HIMITSU_PASSWORD=abcdefg

なお, このconfig/ のファイルは全てgitで管理されます. そのため, ここのデフォルト値に大事な値を書くとgitで管理されてしまい, 不意に流出してしまう…なんてことが起こり得るため注意しましょう. しかし本命の値を .env に記述すれば, こちらはgit管理から除外されているため, この例における"abcdefg"は共有されずに済みます.

最後に, .envの更新が終わったら$ php artisan config:cacheを実行します. このコマンドは .env を更新する度に必要なので, 忘れないようにしましょう.

補足ですが, 準備の章で編集したDB関係の変数をconfigに書く必要はありません. プログラム中で直接読み出して使用する値のみconfigに記述する必要があります.

composer によるパッケージ管理

ここまでで, $ composer xxxxxというコマンドが登場しました. composer は, Laravel のプロジェクトにおけるパッケージ(追加機能を提供してくれるプログラムなど)の管理を担っており, node.js での npm, python での pip などに相当します. 導入したいパッケージの情報は composer.jsonに, 現在導入されているパッケージの情報は composer.lock に記載されます. パッケージのプログラム自体は git では管理されず, 他の環境ではこれら2つのファイルをもとにパッケージを再構築します.

補足: 「導入したいパッケージの情報」「現在導入されているパッケージの情報」の違いですが, 前者は「パッケージAのバージョン3.0以上4.0未満を入れたい」というような人間側の希望を書いておき,後者はその希望を元に諸々の調整をした結果導入されたものの情報が記述されます. 基本的に人間が編集するのはcomposer.jsonで, composer.lockはいじらないようにしましょう.

再構築の際は,$ composer update$ composer installの2種類のコマンドが使えますが, これらの使い分けには注意が必要です. チーム内で誰かがパッケージを追加して push し, 他の人またはサーバーでそれを pull して再構築する際は, $ composer installを使用しましょう. updateはcomposer.jsonを元に再構築するだけでなく文字通りパッケージのアップデートも行うため, comoser.lockが書き換わる可能性があります. この時, このアップデートが原因で動作不良を起こす可能性があります. 先にローカルなどで動作確認をしておき, 特に本番環境上では$ composer updateは使わずに$ composer installを使うと良いかと思います.

MVCとは?

MVCとは, Model, View, Controllerの頭文字で, webアプリケーションの機能を分割して実装する考え方です. 大規模なwebアプリケーションを実装する時に, この3つに分けることで処理がごちゃごちゃに混線せずに, 比較的スッキリしたコードに収まると感じています.

Model(データの持つ属性と操作を記述する)

Laravelではapp/Models/にphpファイルで定義します. 筆者はオブジェクト指向に近いと感じており, 他のところからはメソッドを呼び出すだけで動作するようになると全体のコードがスッキリすると思います.

例: Task

  • プロパティ(属性)として「タスクのタイトル」「完了済か否か」の2つを持つ.
  • メソッド(操作)として「指定したTaskの取得」ができる.

View(表示されるページを記述する)

htmlファイルのようなものですが, 特に動的に(データに応じて変更されて)生成されるページを指して使われることが多い気がします. Laravelではresources/views/に拡張子 .blade.php(通称bladeファイル)で定義します. htmlの記法にphpの記法を追加したようなもので, for文やif文などを使うことができるhtmlというイメージです.

例: Taskの一覧ページ

  • for文でタスクを一つずつ一覧表示に追加する
  • if文で完了済と未完了のものを区別して別々の処理を行う

Controller(全体の処理の流れを記述する)

クライアント(ユーザーのwebブラウザなど)からのリクエストに応じてModelを操作するなどの処理を行い, その結果をViewなどで返す…といった処理の中核を担います. Laravelではapp/Http/Controllersに定義します.
例: TaskController
リクエストに応じて,

  • ページのViewを返す
  • Taskを追加する
    などの動作をする.

Modelの実装

Modelの作成

$ php artisan make:model Task でTaskモデルが作成されます. Modelのファイルとしてapp/Models/Task.phpが新たに作られます.
このファイルが, Task として登録されたデータ全てを扱う管理人のような役割を担います.
ここからはこれを編集して, Task を完成させましょう.

参考: Modelの作成

プロパティの定義

まずは, プロパティを記述しましょう. 前述の通り, Taskには「タスクのタイトル」「完了済か否か」を持たせます.
おそらくTaskの定義の最初にuse HasFactory;のような記述があると思うので, その下に以下を追記します. fillable の他にも guarded, hidden などで目的に応じてプロパティを指定できますが, 詳細は割愛します.
参考: Modelのプロパティの種類

app/Models/Task.php
<?php

namespace App\Models;

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

class Task extends Model
{
    use HasFactory;
    protected $fillable = ['title', 'isDone',]; // 追加
}

メソッドの定義

次に, メソッドを記述しましょう.
ここでは, 「指定したTaskの取得」というメソッド getTaskFromId()を作成します. このメソッドはController等, Task.phpの外から実行することが想定されるためpublicを付しています. また, where()を用いて条件の指定をしています. idについてプロパティを明示的に追加していませんが, mysqlでは「キー」というカラムを一意に特定するための概念が登場し, 特に指定しないと自動で整数値のidが付加されます. (キーについて解説するとそれだけで記事3本くらいの分量になりそうなので, 詳細は割愛します.)
また, boolean型を扱う際は注意が必要なようです. 頭の片隅に置いておくといいかもしれません. (詳細)

app/Models/Task.php
class Task extends Model
{
    use HasFactory;
    protected $fillable = ['title', 'isDone',];

    // 追加
    public function getTaskFromId($id) {
        return Task::where('id', $id)->first();
    }
}

Migration

これでModelは完成しましたが, データベース上にTaskの情報を格納するテーブルがまだ無いため, Migration によってテーブルを作成します(本(一つひとつのデータ)をしまうために本棚(テーブル)が必要だから作ろう, というイメージ).

その前に, データベースの頻出用語や基本について次からのページで触れておきます.

データベース用語(分類の種類)

  • database
    基本的にアプリケーションごとに割り当てる, 一番大きな分類. 今回は, docker-compose.ymlのdb/environment/MYSQL_DATABASE と .env の DB_DATABASE で指定している.
  • table
    扱うデータの種類(Model)ごとに作成する. 例えば, Task のデータを扱うテーブルとして tasks を用意する, など. C言語の構造体などのように, 予めプロパティの名前と型などを指定する.
  • column(日本語: カラム)
    テーブル内の一つひとつのデータを指す.

データベースの操作

新たなターミナル画面でdocker-laravelのディレクトリに移動し, $ docker-compose up -d をした状態で$ docker-compose exec db bashによってdbのコンテナに入ります. ここで$ mysql -u user -pを実行し, .env等で設定したパスワードを入力してデータベースを操作できるようになります.
まずは, > show databases;(セミコロンを忘れないように)で, 全てのデータベースを確認できます. 今回のアプリケーションではデータベースとしてhandsonを使っているため, > use handson;によってデータベースを指定しましょう.

続いて, > show tables; で handson 内のテーブルを確認しましょう. 初期状態ではテーブルがまだ無いため, Emptyと表示されます. しかし, この後のMigrationの操作によって, Note を格納するためのテーブルが追加されます.
また, この画面では > FROM XX SELECT YY...;などのSQL文による操作もできます.

ここまででデータベースの基礎を扱いましたが, 深入りするとそれだけで講座一本分になってしまうので, これ以上のことは必要に応じて調べてください.

では話をMigrationに戻しましょう.

Migrationファイルの作成

作成したNoteのデータを扱うテーブルを作成するための設計図である Migrationファイルを作成します. 以下のコマンドで database/mirations/日付_crate_tasks_table.php が作成されます.
$ php artisan make:migration crate_tasks_table --create=tasks
次に作成されたファイルの, up()の中身を以下のように編集します.

database/mirations/日付_crate_tasks_table.php
// 省略

public function up()
{
    Schema::create('tasks', function (Blueprint $task) {
        $task->id();
        $task->timestamps();
        $task->text('title');
        $task->boolean('isDone');
    });
}

// 省略

Migrationの実行

webコンテナで$ php artisan migrate を実行することによって, 先の手順で作成したMigrationファイルを元にmigrationを実行できます.
ここまで終わると, > show tables; の結果にtasks等が追加されていることが確認できます.

Controllerの実装

Controllerの作成

$ php artisan make:controller HandsonControllerで新たなControllerが app/Http/Controllers/HandsonController.php として作られます.
このファイルが, リクエストに対する処理の中核を担います.
ここからはこのファイルを中心に編集して, 一連の処理を完成させましょう.

参考: ControllerとViewの作成

ルーティング

少し Controller から話題が逸れますが, Webアプリケーションなどではルーティング(routing)という概念があります. ルーティングとは, Controller の処理をするためにアクセスに対する受け口を作ることです. 言い換えれば, 「URL を作り, それに対応した処理を決めること」となるでしょう(いずれも厳密な言い方ではありませんが).
ルーティングは, その目的に応じて route/ 以下に分けて書かれます. api.php とweb.php がよく使われ, 前者は API としてのリクエスト, 後者は Web ページ表示のリクエストを記述する, というイメージです.

実際にルーティングを設定してみましょう. routes/web.php に以下を追記してください.

routes/web.php
Route::get('/handson', 'App\Http\Controllers\HandsonController@index');

これは, /handson の URL に get リクエストを受けた時に, app/Http/Controllers/HandsonController.php 内の関数 index()を呼び出すことを示しています.
HTTP のリクエストには, Webページや画像などの情報を要求する get, 情報を送ってその結果を要求する post などがあります. post が使われる場面の代表例は入力フォームなどが挙げられますが, 詳細は後ほど解説します.
参考: ルーティングからControllerからViewまでの流れ

Controller内の処理の実装

リクエストの受け口は作れたので, 実際の処理を記述しましょう.
app/Http/Controllers/HandsonController.php を, 以下のように編集します.

app/Http/Controllers/HandsonController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HandsonController extends Controller
{
    // 追加
    public function index(Request $request) {
        return "this is index() in handson";
    }
}

ブラウザで http://localhost:8080/handson (docker-compose.yml でポート番号を変更した場合は適宜読み替えてください)にアクセスしてみましょう. "this is index() in handson" と表示されたら成功です.

Modelの利用

新たなタスクを追加するページを作成しましょう. ここでは, 新規タスクの作成のページは静的, つまりいつアクセスしても同じものが表示されるようになっていても問題無いため, public内にある静的なhtmlファイルを返すように指定します.
まずは, new のURLの対するリクエストを処理するために route/web.php を編集します.

route/web.php
// 追加
Route::get('/new', function () {
    return File::get(public_path("static/new.html"));
});

public_path(FILE_NAME)で/public内のファイルを探し, それをreturn File::get()で返しています.

では, 返すhtmlファイルを作成しましょう. public/static/new.htmlを作成し, これを編集します.

public/static/new.html
<!DOCTYPE html>
<html lang="ja">
    <body>
        <h1>新規タスク作成</h1>
            <form action="/api/tasks/new" method="post">
                <span>タイトル:</span><input type="text" name="title">
                <button type="submit">保存</button>
            </form>
    </body>
</html>

参考: 静的ページ表示

次に, このページから送信されたデータを受け取ってデータベースに保存する処理を実装します.
この時のリクエストは外部からのデータの受け取りというインターフェース的な役割を担うため, routes/api.phpに記述して捌くようにしましょう. 以下を追記してください.

routes/api.php
Route::post('/tasks/new', 'App\Http\Controllers\TaskController@store'); // 追加

これまではRoute::get()を使っていましたが, 今回は POST によるリクエストを受け付けるために Route::post()を使用しています.

続いて, Task 関係に処理を捌くControllerを $ php artisan make:controller TaskController によって作成してください. HandsonController.php と同様, app/Http/Controllers 内にTaskController が生成されます. これを編集して, post されたタスクの情報をデータベースに格納する処理を実装しましょう.
上のほうにあるuse App\Models\Task;も忘れないようにしましょう.

app/Http/Controllers/TaskController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Task; //追加

class TaskController extends Controller
{
    // タスクの作成
    public function store(Request $request){
        $task = new Task;
        $task->title = $request->title ?? ""; // null の防止
        $task->isDone = false;
        $task->save();
        return redirect(url('/handson'));
    }
}

titleが空になることを防ぐために, クライアント側(new.html)とサーバー側(TaskController.php)で二重にチェックをしています. クライアント側ではinputでrequiredを指定, これをくぐり抜けてしまった場合にサーバー側でnull 合体演算子で空の文字列を入れるようにしています.

ここまでできたら, http://localhost:8080/new からタスクをいくつか生成してみましょう. そして db のコンテナで mysqlにログイン($ mysql -u user -p→パスワード入力)し, handson データベースを指定(> use handson;)をした状態で, > select * from tasks;を実行してみましょう. すると, 以下のように追加したデータが表示されます.

mysql> select * from tasks;
+----+---------------------+---------------------+-------+--------+
| id | created_at          | updated_at          | title | isDone |
+----+---------------------+---------------------+-------+--------+
|  1 | 2022-04-12 04:58:22 | 2022-04-12 04:58:22 | ???1  |      0 |
|  2 | 2022-04-12 04:59:10 | 2022-04-12 04:59:10 | task2 |      0 |
+----+---------------------+---------------------+-------+--------+
2 rows in set (0.00 sec)

さて, ここまででデータの追加ができるようになりましたが, 次に扱う View と組み合わせることで表示したいデータや変数などに応じて整形したページを生成して返すことができます. タスクを完了済扱いにする処理は後ほど実装します.

Viewの実装

View の作成

View は Model や Controller と異なりコマンドでの作成ができません. そのため手動でファイルを作成します. View は通常 resources/views/ に blade ファイルで配置されます. ここでは, resources/views/task/index.blade.php を以下のように作成しましょう.

resources/views/task/index.blade.php
<!DOCTYPE html>
<html lang="ja">
    <body>
        <h1>タスク一覧</h1>
            <table border="1">
            @foreach ($tasks as $task)
            <tr>
                @if($task->isDone)
                <td></td>
                @else
                <td></td>
                @endif
                <td>{{ $task->title }}</td>
            </tr>
            @endforeach
            </table>
    </body>
</html>

blade ファイルでよく使われる php の記法として, 次の2つを紹介します.

  1. 2重の波括弧{{ .... }}
    これで囲まれた部分は, そのまま php のprint文として実行した結果が表示されるイメージです.
  2. @によるブロック
    分岐やループなどによる php の制御を記述できます. @endXXの形で終了位置を明示する必要があります. ここでは登場しませんでしたが, @for@else if()などもあります. 今回はforeachと if で, 全てのtaskについてisDoneの値による分岐を組み込んで表示しています.

bladeファイルについての詳細はこちらの記事で丁寧に解説されています.

さて, 表示する変数は記述できましたが, この変数の中身は一体どこから来るのでしょうか. Viewで使用するデータの多くは Controllerから渡されます(その限りではありませんが, 今回は割愛します). ということで, TaskController にその役割を持たせるように編集しましょう.

app/Http/Controllers/TaskController.php
class TaskController extends Controller
{
    // ...省略

    // ↓追加
    // 一覧表示
    public function index(){
        $tasks = Task::all();
        return view('task.index', compact('tasks'));
    }
}

TaskのModelから全てのデータを受け取り, それをcompact()によって変数をviewに渡して表示させています. 複数の変数を渡したい時は, compact('var1', 'var2', ...) というように変数名を並べて書くことで実現できます.

最後に, この処理に対するルーティングを記述しましょう. routes/web.phpに以下を追記します.

route/web.php
Route::get('/task', 'App\Http\Controllers\TaskController@index');

ここまでで, Laravel の MVC の基本は一通り実装できました. https://localhost:8080/task にアクセスすると, これまでに作成したタスクの一覧が表示されます.

以降は, Laravel でよく使う記法や機能の実装について触れていきます.

Laravel のよく使う機能と実装


Log::debug()

エラー対処や動作確認等, printなどの関数によって動作を確認しながらプログラムを書く, という場面があると思います. Laravel では php の print()が使えないため, ログという形で専用の出力が用意されています. ここでは, サイトの情報の配列を出力してみましょう.
TaskController.php の先頭の use 群に以下を追記してください.

app/Http/Controllers/TaskController.php
use Illuminate\Support\Facades\Log;

これで, HandsonController.php 内でログの出力ができるようになります.

次に, index()return view(...); の前に以下を追記してください.

app/Http/Controllers/TaskController.php
Log::debug($tasks); // デプロイ時には消すorコメントアウトを推奨

この行が実行されると(つまり, ページにアクセスがあった時), ログファイルに $tasksの内容が出力されます. ログファイルは, デフォルトでは storage/logs/laravel.log になっています.
様々なものを出力できるため開発時には有力な機能ですが, ログファイルが膨大になることを防ぐために, 不要な出力はデプロイ時は消しておくのが良いでしょう.

今回はFacadeという機能でログ出力を実装しましたが, ヘルパ経由での実装もできます. (参考: ログ出力の方法, 参考: Facadeとヘルパ)

asset()

Laravel における静的コンテンツ(cssやjs, 画像など)は public/ に配置し, それらの読み込みには asset() が使われます. ここでは, css を作成し, それを読み込んでみましょう. もちろん, js や画像などの他のファイルも同様の方法で読み込むことができます.
まずは, public/static/css/style.css を作成し, 以下のように記述しましょう.

public/static/css/style.css
.background_yellow {
    background-color: yellow;
}

次に, resources/views/task/index.blade.php の<body>の上に以下を追記します.

resources/views/task/index.blade.php
<!DOCTYPE html>
<html lang="ja">
    <!-- ここから -->
    <head>
        <link rel="stylesheet" href="{{asset('static/css/style.css')}}" >
    </head>
    <!-- ここまでを追加 -->
    <body>
        ...
    </body>
</html>

asset()では, public/ をルートとしてパスを記述するため, public/ からではなく static/ から書き始めます. パスは文字列で与えるため, シングルクォートとダブルクォートを使い分けましょう.
ここで, 例えば<td>未</td><td class="background_yellow">未</td>と書き換えてページを読み込むと表の背景が黄色になって, スタイルシートを適用できたことが確認できるでしょう.

ルートパラメータの利用

ルートパラメータ によってURLへのアクセスにパラメータを付与し, 引数のように扱うことができます.
ここでは, 各タスクの詳細ページへのルーティングを, パラメータを用いて実装してみましょう.
routes/web.php に以下の行を追加します.

routes/web.php
Route::get('/task/details/{id}', 'App\Http\Controllers\TaskController@details');

{id}のように, 波括弧で囲むことによってその部分をパラメータとして受け取ることができます. そして受け取ったパラメータを, 次に作るdetails()に渡しています.

続いて, app/Http/Controllers/TaskController.php に 次ページの関数details()を追加します.
先程のindex()の実装時には触れませんでしたが, routes/web.php からの Controller の呼び出しでは, その時の Laravel への httpリクエスト(詳細は割愛) の情報を格納した引数Requestが付与されます. ここにルートパラメータの$idを追加することで受け取っています.
この詳細ページの bladeファイルは, もう少し後で実装します.

app/Http/Controllers/TaskController.php
<?php

namespace App\Http\Controllers;

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

class TaskController extends Controller
{
    // ...省略

    // ↓追加
    // 詳細表示
    public function details(Request $request, $id){
        $task = Task::getTaskFromId($id);
        return view('task.details', compact('task'));
    }
}

Form の利用

入力されたデータなどを Viewから Laravel サーバーに送る際, Form機能を利用します. (タスク作成の際は View ではなく, 静的ページから送信していました. Form を使うと, 初期値などを Controller から受け取る部分がコンパクトに記述できたりしして, 自然に blade ファイルに組み込むことができます.) 先程の詳細ページからタスクを完了済にするための Form を作成し, その情報をサーバーに送る処理を実装してみましょう.

参考:
Form作成

まずは, 必要なパッケージ を導入するため, $ composer require laravelcollective/htmlを実行します.
続いて, resources/views/task/details.blade.php を作成し, 以下のように記述します.
ここでは実際の動作には関係ありませんが, textarea を追加してみました. (ControllerやModelで適切に処理することで, メモを書くことができるようになったりします.)

resources/views/task/details.blade.php
<!DOCTYPE html>
<html lang="ja">
    <body>
        <h1>{{$task->title}}</h1>
        <div>
            @if($task->isDone)
            完了済
            @else
            {{ Form::open(['method'=>'post', 'url' => '/api/tasks/done', 'class'=>'form-article' ]) }}
            {{ Form::textarea('memo', '', ['placeholder'=>'memo...', 'cols'=>'40' ]) }}
            {{ Form::hidden('id', $task->id) }} 
            {{ Form::submit( '完了済にする' ) }}
            {{ Form::close() }}
            @endif
        </div>
    </body>
</html>

From::open()でこのフォームの設定をして, その次に内容を, 最後にFrom::close()で閉じることで作成できます. しかし, まだこの内容の受け口となる/tasks/doneを作っていないため, そのルーティングと動作を作成します.

ルーティングについては, new の時と同様 routes/api.php に記述しましょう. 以下を追記してください.

routes/api.php
Route::post('/tasks/done', 'App\Http\Controllers\TaskController@done');

動作は, TaskController に 記述しましょう.

app/Http/Controllers/TaskController.php
<?php

namespace App\Http\Controllers;

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

class TaskController extends Controller
{
    // ...

    // ↓を追記
    // タスクを完了済にする
    public function done(Request $request){
        Task::done($request->id);
        return redirect(url('/task'));
    }
}

続いて, app/Models/Task.php にTask::done()を実装しましょう.

app/Models/Task.php
<?php

namespace App\Models;

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

class Task extends Model
{
    // ...

    // ↓追加
    public function done($id){
        Task::where('id', $id)
            ->first()
            ->update(['isDone' => true,]);
    }
}

これで, details のページから「完了済にする」を押すと, その情報が TaskController, Task(Model) を経由してデータベースに保存されるようになりました.
試しに適当な id (今回は特に指定していないため 1 から自動で割り振られます)の details ページを, http://localhost:8080/task/details/1 などから表示して, 実際に完了済にできることを確認してみましょう.

url()

Laravel の Web アプリケーション内でのページ遷移のためのリンクは, url()を使って生成します. 特にApacheのサブディレクトリなどでは公開する場合は URL が https://hogehoge.com/サービス名/ のようになり, ドメイン名のみではアクセスできないことが想定されるため, この関数が重要な役割を果たします. (難しい言い方をすれば, 「パブリックルートまでのurlを補完」」してくれます.)
resources/views/task/index.blade.php を編集し, タスクのタイトルに対してdetailsページへのリンクを貼ってみましょう.

resources/views/task/index.blade.php
<td>{{ $task->title }}</td> <!-- これを以下のように置き換える -->
<td><a href="{{url('task/details/' . $task->id)}}">{{ $task->title }}</a></td>

おわりに

以上で, 本ハンズオン講座は終了となります. お疲れ様でした.
ここまでの内容は, 筆者が php/Laravel 未経験の状態から大学で学内向けサービス開発のアルバイトを始めてから約9ヶ月間の新サービスの開発経験の中で, 学んだことを一通りまとめたものとなっています. そのためかなりのボリュームになってしまいましたが, ここまでお疲れ様でした.
この講座での学びが今後役に立てば幸いです.

4
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?