第1回 Hello World!

第1回 Hello World!

この記事について

プログラミング言語を学ぶとき、最初に書くプログラムは Hello World! と出力するものと相場が決まっています。

Laravel でも Hello World! してみましょう。ブラウザに「Hello World!」と表示するだけのプログラムを書いてみます。

1. テストを書く

テストの生成は以下のコマンドです。デフォルトでは tests/Feature の下にファイルを生成します。 --unit オプションをつけると、tests/Unit 以下にできます(こちらは単体テスト用のディレクトリです)。

$ php artisan make:test WelcomeTest

自動生成された WelcomeTest.php を以下のように書き換えます。

<?php
declare(strict_types=1);

namespace Tests\Feature;

use Tests\TestCase;

class WelcomeTest extends TestCase
{
    /**
     * assert to show 'Hello World!'
     *
     * @return void
     */
    public function testIndex()
    {
        $response = $this->get('/');
        $response->assertStatus(200);
        $this->assertEquals('Hello World!', $response->getContent());
    }
}

実行します。

$ ./vendor/bin/phpunit tests/Feature/WelcomeTest.php
PHPUnit 6.3.0 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 151 ms, Memory: 12.00MB

There was 1 failure:

1) Tests\Feature\WelcomeTest::testIndex
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Hello World!'
+'<!doctype html>
+<html lang="en">
(snip)

最初は失敗しますが問題ありません、これからアプリケーションのコードを書き換えてテストが通るようにします。

2. 組み込みサーバーを立ち上げる

テストの実行と並行して、ブラウザでの確認もしておきましょう。

一般的には、Apache や Nginx などのウェブサーバを介してブラウザとアプリケーションでデータのやり取りをしますが、Laravel では PHP の組み込みサーバーを利用して、アプリケーションを動作させることができます。

コンソールから、以下のコマンドを実行してください。

$ php artisan serve

デフォルトのポートは 8000 なので、ブラウザのアドレスバーに http://localhost:8000/ と入れてページを開いてみてください。

welcome page

ちゃんと表示されたでしょうか?

3. ルーティングを変更する

ルーティングは、/routes ディレクトリにあるファイルで定義されています。

web.php を開いてください。

インストール直後は以下のようになっています。

Route::get('/', function () {
    return view('welcome');
});

これを

Route::get('/', 'WelcomeController@index');

に変えてください。@のあとはメソッド名です(これを通常のメソッドと区別するためにアクションメソッドと呼びます)。

続いてコントローラークラスをつくります。

コンソールから、

$ php artisan make:controller WelcomeController

と実行します。

app/Http/Controllers 以下に WelcomeController.php が生成されているはずです。

エディタで開いてください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WelcomeController extends Controller
{
    //
}

これを以下のように変更します。先ほどルーティングに指定した、index メソッドを追加します。

<?php
declare(strict_types=1);

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WelcomeController extends Controller
{
    public function index()
    {
        return 'Hello World!';
    }
}

最初の例は、文字列を直接返すように書きました。

テストを実行してみましょう。

これでパスしたはずです。

続いて、ブラウザで http://localhost:8000/ を開いてみてください、画面の左上に「Hello World!」と出力されます(アクションメソッドから文字列で返した場合、ブラウザには text/plain でレスポンスを返します)。

4. ルートパラメーター

続いて、表示するメッセージを動的にするために、URLを変更してみます。

URLの一部に含まれる動的な値を「ルートパラメーター」と呼びます。

routes/web.php を開きます。

Route::get('/{message}', 'WelcomeController@index');

/ のあとにはどんな文字列が入れてもOKです。使う文字を制限したい場合には、以下のように正規表現を使って制限することができます。

Route::get('/{message}', 'WelcomeController@index')->where('message', '[a-zA-Z\-]+');

(上の例では、大文字小文字アルファベットと - だけが許容されます。それ以外の文字が含まれていた場合は 404 エラーになります)

続いて WelcomeController.php を編集します。

    public function index(string $message)
    {
        return $message;
    }

テストコードを書き換えます。

<?php
declare(strict_types=1);

namespace Tests\Feature;

use Tests\TestCase;

class WelcomeTest extends TestCase
{
    /**
     * assert to show 'Hello World!'
     *
     * @return void
     */
    public function testIndex()
    {
        $response = $this->get('/Hello%20World%21');
        $response->assertStatus(200);
        $this->assertEquals('Hello World!', $response->getContent());
    }
}

通りますね。

%20 とか %21 とかは、URLエンコードした記号(前者は半角スペース、後者はエクスクラメーションマーク)です。

では、ブラウザから以下のURLを開いてみてください。

http://localhost:8000/Hello%20World%21

「Hello World!」と表示されたでしょうか?

5. オプショナルなルートパラメーター

ルートパラメーターの後ろに ? をつけると、ルートパラメーターが空の場合にも同一のアクションメソッドで処理することができます。

先にテスト書きましょう。

    public function testIndexWithNoMessage()
    {
        $response = $this->get('/');
        $response->assertStatus(200);
        $this->assertEquals('no message', $response->getContent());
    }

再び routes/web.php を開きます。

Route::get('/{message?}', 'WelcomeController@index');

message の後ろに ? をつけるだけです。

テストを実行してみましょう。

./vendor/bin/phpunit tests/Feature/WelcomeTest.php
PHPUnit 6.3.0 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 151 ms, Memory: 12.00MB

There was 1 failure:

1) Tests\Feature\WelcomeTest::testIndexWithNoMessage
Expected status code 200 but received 500.
Failed asserting that false is true.

/Users/nunulk/var/www/laravel-tutorial/src/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:75
/Users/nunulk/var/www/laravel-tutorial/src/tests/Feature/WelcomeTest.php:25

FAILURES!
Tests: 2, Assertions: 3, Failures: 1.

testIndexWithNoMessage のテストが失敗しました(HTTP ステータスが 500 ということはサーバーエラーですね)。

ではテストが通るように WelcomeController.php を編集します。

    public function index(string $message = 'no message')
    {
        return $message;
    }

オプショナルなルートパラメーターは、アクションメソッドの引数でデフォルト値を与えてやります。

テストを実行します。

今度は通るはずです。

念のため、ブラウザから以下のURLを開いてみてください。

http://localhost:8000/

「no message」と表示されたでしょうか?

このように簡潔に書けるのでつい使ってしまいたくなりますが、オプショナルなルートパラメーターを多用すると、URLの管理が複雑になりますので、なるべく使わないように URL を設計するといいと思います。

6. クエリーストリング

続いて、クエリーストリングと呼ばれる URL に付加する文字列を受け取ってみましょう。

先ほどの URL を少しだけ変更します。

http://localhost:8000/?message=Hello%20World%21

?key=value という形で、動的な値をコントローラーに渡します。

routes/web.php を変更します。

Route::get('/', 'WelcomeController@index');

続いて WelcomeController.php を編集します。

    public function index(Request $request)
    {
        return $request->query('message');
    }

今度は引数に Request という型のオブジェクトを受け取るようにします。Request クラスが持つ query メソッドが、クエリーストリングから指定したキーを持つパラメーターを取ってきます。

テストをパスさせて、ブラウザでも確認してください(testIndex の方はパスしますが、testIndexWithNoMessage は失敗します。こちらは次のセクションでパスさせます)。

7. オプショナルなクエリーストリング

というわけで、WelcomeController.php を編集します。

    public function index(Request $request)
    {
        return $request->query('message', 'no message');
    }

query メソッドの第二引数に、キーが存在しない場合のデフォルト値を指定することができます。

まとめ

第1回目の今回は、3つの方法で「Hello World!」と表示してみました。

ルートパラメーターとクエリーストリングの扱い方を理解できたと思います。

ついでに機能テストの書き方も少し紹介しました。Laravel ではテストも非常に書きやすくなっているので、いままでテスト書くのが億劫でサボってしまっていた方も、Laravel なら、きっと、テストが書きたくなると思います。

次回以降はもうちょっと実践的な内容にしたいと思っております。

Posted in Routing on 7月 18, 2017