Laravel 演習入門

8番ホームページ(プロトタイプ)

Session の基礎

問題

以下のような間違い探しゲーム:「8番ホームページ」を作成してください。

今回は、プロトタイプ作成なので、 view の作り込みや、間違いの実装は不要です。
各ページの状態を Session で管理して、正しくページ遷移するように実装してください。


問題は、以下の手順で解いてください。

  1. Red:小さいテストを作成し、失敗を確認してください
  2. Green:テストを成功させてください
  3. Refactor:整理・整頓してください
  4. 必要に応じて、1から3を繰り返してください

ヒント

背景知識
便利なアサーションの例

アサーションの調べ方 も合わせてご覧ください。
今回は、以下を使うのではないかと思います。

解答例

続きを読む

実行環境:

Red

テストを作成します。
bash:

php artisan make:test NumberEightTest

tests/Feature/NumberEightTest.php:

<?php

namespace Tests\Feature;

use Tests\TestCase;

class NumberEightTest extends TestCase
{
    public function test_正常なスタートページ(): void
    {
        $response = $this->get('/page/1');
        $response->assertStatus(200)
            ->assertSessionHas('next_page', 2);
    }

    public function test_不正なスタートページ(): void
    {
        $response = $this->get('/page/3');
        $response->assertRedirect('/page/1')
            ->assertSessionMissing('next_page');

        $response = $this->get('/page/8');
        $response->assertRedirect('/page/1')
            ->assertSessionMissing('next_page');
    }
    
    public function test_正常な途中ページ(): void
    {
        $response = $this->withSession([
            'next_page' => 5,
        ])->get('/page/5');
        $response->assertStatus(200);
        $is_normal = (session('is_normal') === 'true');
        if($is_normal) {
            $response->assertSessionHas('next_page', 6);
        }else{
            $response->assertSessionHas('next_page', 5);
        }
    }
    
    public function test_異変な途中ページ(): void
    {
        $response = $this->withSession([
            'next_page' => 5,
        ])->get('/page/6');
        $response->assertRedirect('/page/1')
            ->assertSessionMissing('next_page');
    }

    public function test_不正な途中ページ(): void
    {
        $response = $this->withSession([
            'next_page' => 2,
        ])->get('/page/7');
        $response->assertRedirect('/page/1')
            ->assertSessionMissing('next_page');
    }

    public function test_正常なクリアページ(): void
    {
        $response = $this->withSession([
            'next_page' => 8,
        ])->get('/page/8');
        $response->assertStatus(200)
            ->assertSeeText('クリア')
            ->assertSessionMissing('next_page');
    }
    
}

たくさんのテストを一度に実行しますが、コメントアウトして、小分けにしても OK です。
テストの失敗を確認します。

Green

ルーティングを作成します。
routes/web.php:

use App\Http\Controllers\NumberEightController;
Route::get('/page/{number}', [NumberEightController::class, 'show'])->where('number', '[1-8]');

コントローラーを作成します。
bash:

php artisan make:controller NumberEightController

app/Http/Controllers/NumberEightController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;

class NumberEightController extends Controller
{
    public function show(Request $request, string $number)
    {
        $current_page = (int) $number;
        $session_page = (int) $request->session()->get('next_page', 1);

        if($current_page === 1) {
            $request->session()->put('next_page', 2);
            return "スタートページの view: <a href='/page/2'>先に進む</a>";
        }

        if($current_page !== $session_page) {
            $request->session()->flush();
            return redirect('/page/1');
        }

        if($current_page === 8) {
            $request->session()->flush();
            return 'クリアページの view';
        }

        $is_normal = (rand(0, 99) < 75);  // 75% が正常
        $next_page = $current_page + 1;
        if($is_normal) {
            $request->session()->put('next_page', $next_page);
            $request->session()->put('is_normal', 'true');
            return "正常ページの view: <a href='/page/{$current_page}'>元に戻る</a> <a href='/page/{$next_page}'>先に進む</a>";
        }else{
            $request->session()->put('next_page', $current_page);
            $request->session()->put('is_normal', 'false');
            return "異変ページの view: <a href='/page/{$current_page}'>元に戻る</a> <a href='/page/{$next_page}'>先に進む</a>";
        }
    }
}

テストを実行し、成功を確認してください。

Refactor

特にありません

解説

続きを読む

Session について

Note

セッションそのものの説明については、 PHPerKaigi2021 の「セッションの基本と応用」が、とても参考になります。
YouTubeスライド もあります。

ざっくりいうと、ステートレスな HTTP リクエストを、ステートフルにしてくれる仕組みです。
Laravel では、 Request オブジェクトの session メソッドを利用して、安全に扱えます。

今回のように、簡単なゲームの状態をサーバー側で持つこともできますし、ログイン状態を持つような場合にも使われます。

ただし、ログイン認証については、 Auth ミドルウェアを利用することがほとんどだと思いますので、直接 session を触る機会は、それほど多くはないかもしれません。


<= 問題を読んだ・解いた・理解したなどのチェックにご利用ください。クリックすると、チェックが変化します。
問題一覧に戻る