点数
83点
感想
見やすくわかりやすい内容だった。
環境構築、サービスコンテナ、Laravel Breeze、フロントエンド、などわかりづらい部分もしっかりとした解説があり、よく理解することができた。
準備
環境構築
- curl -s https://laravel.build/example-app?php81 | bash
- cd example-app
- ./vendor/bin/sail up -d
sail環境のカスタマイズ
- sail artisan sail:publishでdocker-compose.ymlが変更され、dockerディレクトリにDockerfileなどが生成される。
- docker-compose.ymlのcontext: ./docker/8.2の部分でPHPバージョンの切り替えが可能。
- DockerfileをENV TZ='Asia/Tokyo'と書き換えてタイムゾーンを日本にする。
 (sail build --no-cacheでビルドが必要)
MySQLの文字コードを変更する
1. touch docker/8.2/my.cnf
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_BIN
[client]
default-character-set = utf8mb42. vi docker-compose.yml
mysql: 
    〜省略〜
    volumes:
            - 'sail-mysql:/var/lib/mysql'
           # 以下を追加
            - './docker/8.2/my.cnf:/etc/my.cnf'基本
コントローラの作成
1. sail artisan make:controller Sample/IndexController
以下を追加。
public function showId($id): string
{
    return "Hello {$id}"; // ※ PHP文字列の変数展開は{$xxx}
}2. route/web.phpに追加
Route::get('/sample/{id}', [\App\Http\Controllers\Sample\IndexController::class, 'showId']);
シングルアクションコントローラ
ADRパターンと呼ばれる設計で、コントローラは1つのアクションしか持たない。
PHPのマジックメソッド__invokde()でアクションを定義することで、重複して同名のメソッドが定義できないという制約を設けることができる。
1. sail artisan make:controller Tweet/IndexController --invokable
<?php
namespace App\Http\Controllers\Tweet;
use App\Http\Controllers\Controller;
use App\Services\TweetService;
use Illuminate\Http\Request;
use Illuminate\View\View;
class IndexController extends Controller
{
    /**
     * Handle the incoming request.
     *
     * @param Request $request
     * @param TweetService $tweetService
     * @return View
     */
    public function __invoke(Request $request, TweetService $tweetService): View
    {
        return view('tweet.index', ['tweets' => $tweetService->getTweets()]);
    }
}
2. route/web.phpに追加
Route::get('/tweet', \App\Http\Controllers\Tweet\IndexController::class)->name('tweet.index'); 
※ 第二引数はクラスのみ。配列ではないので注意。
データベースの作成
マイグレーション
1. sail artisan make:migration create_tweets_table
<?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('tweets', function (Blueprint $table) {
            $table->id();
            $table->string('content');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('tweets');
    }
};2. sail artisan migrateで実行
マイグレーションで外部キー作成する
1. sail artisan make:migration add_user_id_to_tweets
- ->constrained()とすると外部キーとするカラム名から参照するテーブルとカラムが決定される。- $table->foreign('user_id')->references('id')->on('users');よりも簡潔に書ける。
- ->cascadeOnDelete()とすると削除時に紐づくレコードも削除される。
<?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::table('tweets', function (Blueprint $table) {
            $table->foreignId('user_id')->after('id')->constrained()->cascadeOnDelete();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('tweets', function (Blueprint $table) {
            $table->dropForeign('tweets_user_id_foreign');
            $table->dropColumn('user_id');
        });
    }
};2. sail artisan migrate:fresh
シーディング
1. sail artisan make:seeder TweetsSeeder
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; // 追加
use Illuminate\Support\Str; // 追加
class TweetsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        DB::table('tweets')->insert([
            'content' => Str::random(100), // 追加
            'created_at' => now(), // 追加
            'updated_at' => now(), // 追加
        ]);
    }
}2. database/seeders/DatabaseSeeder.phpのrunメソッドに追加
$this->call([TweetsSeeder::class]);

