Open takanori-matsushita opened 4 years ago
リスト 6.1: Userモデルを生成する LaravelでははじめからUserモデルが用意されているので、そちらを使う。 app/User.php
リスト 6.2: (usersテーブルを作るための) Userモデルのマイグレーション
database/migrations/create_users_table.php
が元から用意されているのでこちらを使用する
.envのデータベースの設定を変更(今回はpostgreSQLを使用する)
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=データベース名
DB_USERNAME=ユーザー名
DB_PASSWORD=パスワード
マイグレーション実行
php artisan migrate
もし上のコマンドでうまくいかないときは、設定のキャッシュクリアしてもう一度マイグレーションを実行する
php artisan config:clear
演習
$ php artisan migrate:rollback
app/User.php
に最初から用意してある。
演習
php arisan tinker
>>> get_parent_class($user)
=> "Illuminate\Foundation\Auth\User"
>>> $parentClass = get_parent_class($user)
=> "Illuminate\Foundation\Auth\User"
>>> get_parent_class($parentClass)
=> "Illuminate\Database\Eloquent\Model"
php arisan tinker
>>> $user = new User();
=> App\User
>>> $user->name = 'Michael Hartl'
=> "Michael Hartl"
>>> $user->email = 'mhartl@example.com'
=> "mhartl@example.com"
>>> $user->password = 'password'
=> "password"
>>> $user->save()
=> true
>>> $user
=> App\User {#3047
updated_at: "2020-04-12 18:04:18",
created_at: "2020-04-12 18:04:18",
name: "Michael Hartl",
email: "mhartl@example.com",
id: 3,
}
カラム情報の取り出し
>>> $user->name
=> "Michael Hartl"
>>> $user->email
=> "mhartl@example.com"
>>> $user->updated_at
=> Illuminate\Support\Carbon @1586714658 {#3043
date: 2020-04-12 18:04:18.0 UTC (+00:00),
timezone: "UTC",
}
createメソッド
$foo = User::create([
"name" => "A Nother",
"email" => "another@example.org",
"password" => "password"
])
レコードの削除
>>> $foo->delete()
=> true
>>> User::find(1)
=> App\User {#3068
id: 1,
name: "Michael Hartl",
email: "mhartl@example.com",
email_verified_at: null,
created_at: "2020-04-12 18:16:49",
updated_at: "2020-04-12 18:16:49",
}
findメソッド
>>> User::find(3)
=> null
whereメソッド
>>> User::where("email", "mhartl@example.com")->first()=> App\User {#3064 id: 1,
name: "Michael Hartl",
email: "mhartl@example.com",
email_verified_at: null,
created_at: "2020-04-12 18:16:49",
updated_at: "2020-04-12 18:16:49",
}
firstメソッド
>>> User::first()
=> App\User {#3042
id: 1,
name: "Michael Hartl",
email: "mhartl@example.com",
email_verified_at: null,
created_at: "2020-04-12 18:16:49",
updated_at: "2020-04-12 18:16:49",
}
allメソッド
>>> User::all()
=> Illuminate\Database\Eloquent\Collection {#3071
all: [
App\User {#3043
id: 1,
name: "Michael Hartl",
email: "mhartl@example.com",
email_verified_at: null,
created_at: "2020-04-12 18:16:49",
updated_at: "2020-04-12 18:16:49",
},
App\User {#3060
id: 2,
name: "A Nother",
email: "another@example.org",
email_verified_at: null,
created_at: "2020-04-12 18:25:48",
updated_at: "2020-04-12 18:25:48",
},
],
}
演習
>>> User::where("name", "Michael Hartl")->first()
=> App\User {#3070
id: 1,
name: "Michael Hartl",
email: "mhartl@example.com",
email_verified_at: null,
created_at: "2020-04-12 18:16:49",
updated_at: "2020-04-12 18:16:49",
}
>>> $all = User::all()
=> Illuminate\Database\Eloquent\Collection {#3071
all: [
App\User {#3043
id: 1,
name: "Michael Hartl",
email: "mhartl@example.com",
email_verified_at: null,
created_at: "2020-04-12 18:16:49",
updated_at: "2020-04-12 18:16:49",
},
App\User {#3060
id: 4,
name: "A Nother",
email: "another@example.org",
email_verified_at: null,
created_at: "2020-04-12 18:25:48",
updated_at: "2020-04-12 18:25:48",
},
],
}
>>> get_class($all)
=> "Illuminate\Database\Eloquent\Collection"
>>> count($all)
=> 2
reload的なメソッドは探したが用意されていないかも
演習
>>> $user->name = "taka"
=> "taka"
>>> $user->save();
=> true
>>> $user->update(["email"=>"taka@mail.com"]);
=> true
>>> $user->created_at = $user->created_at->subYear()
testファイルの作成
php artisan make:test UserTest
リスト 6.4: デフォルトのUserテスト (モックのみ)
class UserTest extends TestCase
{
/**
* A basic feature test example.
*
* @return void
*/
public function testExample()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
フォームリクエストを作成し、以下のように記述する。ここでは、まだバリデーションの設定をしない。
[参考]バリデーションテスト
php artisan make:request
app/Http/Requests/UserFormRequest.php
rulesメソッドを以下のように書く。
public function rules()
{
return [
"name" => "",
];
}
リスト 6.5: 有効なUserかどうかをテストする green tests/Feature/UserTest.php
class UserTest extends TestCase
{
/**
* A basic feature test example.
*
* @dataProvider dataProviderUser
* @return void
*/
public function testShouldBeValid($name, $email, $expect)
{
$request = new UserFormRequest();
$rules = $request->rules();
$item = ["name" => $name, "email" => $email];
$validator = Validator::make($item, $rules);
$result = $validator->passes();
$this->assertEquals($expect, $result);
}
public function dataProviderUser()
{
return [
'true' => ["Example User", "user@example.com", true],
];
}
}
データプロバイダを使うと、同じテストコードに違うパラメータを与えることができる。 [参考]データプロバイダとは
リスト 6.6: green
vendor/bin/phpunit
リスト 6.7: name属性にバリデーションに対するテスト red
tests/Feature/UserTest.php
dataProviderUserメソッドに以下の文を追加
'name required error' => ["", "user@example.com", false],
リスト 6.8: red
vendor/bin/phpunit
この時点ではバリデーションを実行した結果がtrueで
$this->assertEquals($expect, $result);
この部分で値が一致しないためFailuresになる。
リスト 6.9: name属性の存在性を検証するgreen app/Http/Requests/UserFormRequest.php
public function rules()
{
return [
"name" => "required",
];
}
tinkerでの確認方法 tinkerでバリデーション
>>> Validator::make(["name"=>""],["name"=>"required"])->errors()->toArray()
=> [
"name" => [
"The name field is required.",
],
]
リスト 6.10: green
vendor/bin/phpunit
リスト 6.11: email属性の検証に対するテストred
dataProviderUserメソッドに以下を追加
'email required error' => ["Example User", "", false],
リスト 6.12: email属性の存在性を検証するgreen app/Http/Requests/UserFormRequest.php
public function rules()
{
return [
"name" => "required",
"email" => "required", //追加
];
}
リスト 6.13: green
vendor/bin/phpunit
演習
>>> Validator::make(["name"=>"","email"=>""],["name"=>"required","email"=>"required"])->errors()->toArray()
=> [
"name" => [
"The name field is required.",
],
"email" => [
"The email field is required.",
],
]
>>> Validator::make(["name"=>"","email"=>""],["name"=>"required","email"=>"required"])->errors()->first(email)
=> "The email field is required."
リスト 6.14: nameの長さの検証に対するテスト red tests/Feature/UserTest.php dataProviderメソッドに追加
'name max_length error' => [str_repeat("a", 51), "user@example.com", false],
'email max_length error' => ["Example User", str_repeat("a", 244) . "@example.com", false],
リスト 6.15: red
vendor/bin/phpunit
リスト 6.16: name属性に長さの検証を追加するgreen
public function rules()
{
return [
"name" => "required|max:50",
"email" => "required|max:255",
];
}
リスト 6.17: green
vendor/bin/phpunit
演習
省略
>>> Validator::make(["name"=>str_repeat("a",55)],["name"=>"max:50"])->errors()->toArray()
=> [
"name" => [
"The name may not be greater than 50 characters.",
],
]
リスト 6.18: 有効なメールフォーマットをテストするgreen tests/Feature/UserTest.php dataProviderUserメソッドに追加
'email user@example.com' => ["Example User", "user@example.com", true],
'email USER@foo.COM' => ["Example User", "USER@foo.com", true],
'email A_US-ER@foo.bar.org' => ["Example User", "A_US-ER@foo.bar.org", true],
'email first.last@foo.jp' => ["Example User", "first.last@foo.jp", true],
'email alice+bob@baz.cn' => ["Example User", "alice+bob@baz.cn", true],
リスト 6.19: メールフォーマットの検証に対するテスト red tests/Feature/UserTest.php dataProviderUserメソッドに追加
'email user@example,com' => ["Example User", "user@example,com", false],
'email user_at_foo.org' => ["Example User", "user_at_foo.org", false],
'email user.name@example.' => ["Example User", "user.name@example.", false],
'email foo@bar_baz.com' => ["Example User", "foo@bar_baz.com", false],
'email foo@bar+baz.com' => ["Example User", "foo@bar+baz.com", false],
リスト 6.20: red
vendor/bin/phpunit
リスト 6.21: メールフォーマットを正規表現で検証するgreen Laravelでは、バリデーションにemail:filterを指定すると、メールアドレスのフォーマットかチェックできる。 app/Http/Requests/UserFormRequest.php
public function rules()
{
return [
"name" => "required|max:50",
"email" => "required|max:255|email:filter",
];
}
リスト 6.22: green
vendor/bin/phpunit
演習
Laravelのバリデーションemail:filterでは、これも無効なアドレスとして認識するため、省略
変更前
変更後
リスト 6.24: 重複するメールアドレス拒否のテスト red 実際にデータベースに保存されているデータを取得し、重複するかチェックする。 tests/Feature/UserTest.php
public function dataProviderUser()
{
$this->createApplication();
$user = User::find(1)->toArray();
return [
'email unique error' => [$user["name"], $user["email"], false],
];
}
[参考]Error: Call to a member function connection() on nullの対策
リスト 6.25: メールアドレスの一意性を検証する green
public function rules()
{
return [
~省略~
"email" => "required|max:255|email:filter|unique:users",
];
}
リスト 6.26: 大文字小文字を区別しない、一意性のテスト green tests/Feature/UserTest.php emailテスト用のデータプロバイダを用意する。
/**
* A basic feature test example.
*
* @dataProvider emailDataProvider
* @return void
*/
public function testEmailUpper($email, $expect)
{
$emailUpper = strtoupper($email);
$result = $this->stringUpper($emailUpper);
$this->assertEquals($expect, $result);
}
protected function stringUpper($emailUpper)
{
$users = User::all();
foreach ($users as $user) {
if ($emailUpper === strtoupper($user["email"])) {
return true;
}
}
return false;
}
~中略~
public function emailDataProvider()
{
$user = User::find(1)->toArray();
return [
'email upper lower passed' => ["user@example.com", false],
'email upper lower error' => [$user["email"], true],
];
}
リスト 6.27: メールアドレスの大文字小文字を無視した一意性の検証 green 上記でgreenのため省略
リスト 6.28: green
vendor/bin/phpunit
ここの操作は不要(参考までに)
マイグレーションの作成
Laravelでは、はじめから用意されていたUserモデルのマイグレーションファイルにuniqueが設定してあるため、uniqueの設定は不要。以下は参考までに。
php artisan make:migration add_index_to_users_email
リスト 6.29: メールアドレスの一意性を強制するためのマイグレーション 以下はuniqueを指定する方法。 database/migrations/[timestamp]_add_index_to_users_email
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->unique('email');
});
}
リスト 6.30: Userのデフォルトfixture red リスト 6.31: 空のfixtureファイルgreen 省略
リスト 6.32: email属性を小文字に変換してメールアドレスの一意性を保証する green Laravelで用意されているUserモデルには、初めから対応しているので省略。
演習
小文字のテスト
public function testEmaillower($email, $expect)
{
$emailLower = strtolower($email);
$result = $this->stringLower($emailLower);
$this->assertEquals($expect, $result);
}
protected function stringLower($emailUpper)
{
$users = User::all();
foreach ($users as $user) {
if ($emailUpper === strtolower($user["email"])) {
return true;
}
}
return false;
}
省略
Laravelでは用意されているUserモデルに実装済みのため、省略
リスト 6.41: パスワードの最小文字数をテストする red tests/Feature/UserTest.php testPasswordInvalidメソッドとpasswordDataProviderを追加
/**
* A basic feature test example.
*
* @dataProvider passwordDataProvider
* @return void
*/
public function testPasswordInvalid($password, $expect)
{
$request = new UserFormRequest();
$rules = $request->rules();
$item = ["name" => "test", "email" => "example@laravel.com", "password" => $password];
$validator = Validator::make($item, $rules);
$result = $validator->passes();
$this->assertEquals($expect, $result);
}
public function passwordDataProvider()
{
return [
'blank password' => [str_repeat(" ", 6), false],
'minimum length password' => [str_repeat("a", 5), false],
];
}
リスト 6.42: セキュアパスワードの完全な実装 green app/Http/Requests/UserFormRequest.php
public function rules()
{
return [
"name" => "required|max:50",
"email" => "required|max:255|email:filter|unique:users",
"password" => "required|min:6" //追加
];
}
リスト 6.43: green
vendor/bin/phpunit
演習
上記テストで確認済みのため省略
tinkerで確認
>>> Validator::make(["password"=>"aaa"],["password"=>"min:6"])->errors()->toArray()
=> [
"password" => [
"The password must be at least 6 characters.",
],
]
実際のデータベースに保存していたため、以下のコマンドでマイグレーションのやり直し
php artisan migrate:refresh
tinkerでデータの登録
php artisan tinker
>>> $user = new User()
=> App\User {#3058}
>>> $user->name = "Michael Hartl"
=> "Michael Hartl"
>>> $user->email = "mhartl@example.com"
=> "mhartl@example.com"
>>> $user->password = "foobar"
=> "foobar"
>>> $user->save()
=> true
第6章ユーザーのモデルを作成する
branch: modeling-users