LaravelのFactoryが便利な件（Fakerの使い方&日本語訳付き）

## 概要
Factoryを使用すると、単体テストに必要なランダムデータを自動生成できます。

参考：[Laravel5.5でほぼ完成されたModelFactoryの使い方](https://qiita.com/fagai/items/7f63d651cbed3664b758)

## 環境
PHP 7.3.14
Laravel 6.11.0

## 前提

適当ですが、以下のようなテーブルと、それに対応するモデルを用意します。
![スクリーンショット 2020-03-12 16.20.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103853/4770d9f0-9150-02e8-14f4-419ae4ab022f.png)

Factoryファイルは手動で作成しても良いですが、以下のようにartisanで生成できます。

```bash
php artisan make:factory UserDetailModelFactory
```

## Factoryの定義方法

定義ファイルの単位は、基本的にモデルごとになります。
定義時、使用時に、モデルのクラス名を指定するためです。

```database/factories/UserDetailModelFactory.php
<?php

/** @var Factory $factory */

use App\Http\Models\UserDetailModel;
use App\Http\Models\UserModel;
use Faker\Generator as Faker;
use Illuminate\Database\Eloquent\Factory;

$factory->define(UserDetailModel::class, function (Faker $faker) {
    return [
        'name' => $faker->name(),
        'description' => $faker->text(),
        'number' => $faker->randomDigitNotNull,
        'is_public' => $faker->boolean,
        'user_id' => function() {
            // リレーションが必要な場合、以下のようにFactoryで生成できます
            // UserModelFactory.phpという別のファイルで定義したFactory
            return factory(UserModel::class)->create()->user_id;
        },
    ];
});

$factory->state(UserDetailModel::class, '公開', function (Faker $faker) {
    return [
        'is_public' => true,
    ];
});

$factory->state(UserDetailModel::class, '非公開', function (Faker $faker) {
    return [
        'is_public' => false,
    ];
});

```
```database/factories/UserModelFactory.php
#（省略）
```

## Factoryの使用方法

```php
//ユーザー詳細を作成
$userDetailModel = factory(UserDetailModel::class)->create();
```

```php
//ユーザー詳細を２件作成
$userDetailModels = factory(UserDetailModel::class, 2)->create();
```

```php
//ユーザー詳細を指定IDで作成
$userDetailModel = factory(UserDetailModel::class)->create(['user_id' => 100]);
```

```php
//ユーザー詳細を作成すると同時に指定のアカウント名のユーザーを作成
$userDetailModel = factory(UserDetailModel::class)->create([
    'user_id' => function () {
        return factory(UserModel::class)->create([
            'account_name' => 'あかうんとめい',
        ])->user_id;
    }
]);
```

概要で紹介した記事を見ると、多対多のリレーションも作成できるようです。

## Fakerの使い方&日本語訳

Fakerを使って、ランダムデータの定義を作成します。

※以下、コメントアウトされているものは、en_USロケールでは利用できましたが、
ja_JPロケールでは利用できなかったので、日本語対応できていないようです。

本家はこちら https://github.com/fzaninotto/Faker#formatters

### フォーマッター

```php
// LaravelのFactoryでFakerを使用する場合は、
// app.php の 'faker_locale' => 'ja_JP' にてロケールを設定できます
$faker = \Faker\Factory::create('ja_JP');

//Faker\Provider\Base
var_dump($faker->randomDigit); // 7
var_dump($faker->randomDigitNot(5)); // 0, 1, 2, 3, 4, 6, 7, 8, or 9
var_dump($faker->randomDigitNotNull); // 5
var_dump($faker->randomNumber($nbDigits = null, $strict = false)); // 79907610
var_dump($faker->randomFloat($nbMaxDecimals = null, $min = 0, $max = null)); // 48.8932
var_dump($faker->numberBetween($min = 1000, $max = 9000)); // 8567
var_dump($faker->randomLetter); // 'b'
// 指定された配列から、ランダムな部分配列を返します
var_dump($faker->randomElements($array = array('a', 'b', 'c'), $count = 1)); // array('c')
var_dump($faker->randomElement($array = array('a', 'b', 'c'))); // 'b'
var_dump($faker->shuffle('こんにちは、世界')); // '界、にこんちは世'
var_dump($faker->shuffle(array(1, 2, 3))); // array(2, 1, 3)
var_dump($faker->numerify('こんにちは ###')); // 'こんにちは 609'
var_dump($faker->lexify('こんにちは ???')); // 'こんにちは wgt'
var_dump($faker->bothify('こんにちは ##??')); // 'こんにちは 42jz'
var_dump($faker->asciify('こんにちは ***')); // 'こんにちは R6+'
var_dump($faker->regexify('[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}')); // sm0@y8k96a.ej

//Faker\Provider\Lorem
var_dump($faker->word); // 'aut'
var_dump($faker->words($nb = 3, $asText = false)); // array('porro', 'sed', 'magni')
var_dump($faker->sentence($nbWords = 6, $variableNbWords = true)); // 'Sit vitae voluptas sint non voluptates.'
var_dump($faker->sentences($nb = 3, $asText = false)); // array('Optio quos qui illo error.', 'Laborum vero a officia id corporis.', 'Saepe provident esse hic eligendi.')
var_dump($faker->paragraph($nbSentences = 3, $variableNbSentences = true)); // 'Ut ab voluptas sed a nam. Sint autem inventore aut officia aut aut blanditiis. Ducimus eos odit amet et est ut eum.'
var_dump($faker->paragraphs($nb = 3, $asText = false)); // array('Quidem ut sunt et quidem est accusamus aut. Fuga est placeat rerum ut. Enim ex eveniet facere sunt.', 'Aut nam et eum architecto fugit repellendus illo. Qui ex esse veritatis.', 'Possimus omnis aut incidunt sunt. Asperiores incidunt iure sequi cum culpa rem. Rerum exercitationem est rem.')
var_dump($faker->text($maxNbChars = 200)); // 'Fuga totam reiciendis qui architecto fugiat nemo. Consequatur recusandae qui cupiditate eos quod.'

//Faker\Provider\ja_JP\Person
var_dump($faker->title()); // 'Ms.'
var_dump($faker->titleMale); // 'Mr.'
var_dump($faker->titleFemale); // 'Ms.'
//        var_dump($faker->suffix); // 'Jr.'
var_dump($faker->name()); // '中津川 太一'
var_dump($faker->firstName()); // '知実'
var_dump($faker->firstNameMale); // '直人'
var_dump($faker->firstNameFemale); // '香織'
var_dump($faker->lastName); // '吉本'

//Faker\Provider\ja_JP\Address
//        var_dump($faker->cityPrefix); // 'Lake'
var_dump($faker->secondaryAddress); // 'ハイツ若松101号'
//        var_dump($faker->state); // 'NewMexico'
//        var_dump($faker->stateAbbr); // 'OH'
var_dump($faker->citySuffix); // '市'
var_dump($faker->streetSuffix); // '町'
var_dump($faker->buildingNumber); // '484'
var_dump($faker->city); // '村山市'
var_dump($faker->streetName); // '三宅町'
var_dump($faker->streetAddress); // '杉山町宇野8-1-4'
var_dump($faker->postcode); // '3007501'
var_dump($faker->address); // '5011271  大阪府石田市北区大垣町木村8-8-8 ハイツ浜田110号'
var_dump($faker->country); // 'エストニア'
var_dump($faker->latitude($min = -90, $max = 90)); // 77.147489
var_dump($faker->longitude($min = -180, $max = 180)); // 86.211205

//Faker\Provider\ja_JP\PhoneNumber
var_dump($faker->phoneNumber); // '090-6357-1253'
//        var_dump($faker->tollFreePhoneNumber); // '(888) 937-7238'
var_dump($faker->e164PhoneNumber); // '+2944809901570'

//Faker\Provider\ja_JP\Company
//        var_dump($faker->catchPhrase); // 'Monitored regional contingency'
//        var_dump($faker->bs); // 'e-enable robust architectures'
var_dump($faker->company); // '有限会社 西之園'
var_dump($faker->companySuffix); // 'Ltd'
var_dump($faker->jobTitle); // 'Cashier'

//Faker\Provider\ja_JP\Text
var_dump($faker->realText($maxNbChars = 200, $indexSize = 2)); // だい。さわやかになるよ」カムパネルラといったにしばらくむいたちの方法ほうさえてきた。それからみて、とても押おしの上を鳴らしかたまって光っていた男が立ってその銀河ぎんかたまっておやかれがつました。そしてこなら近くにあの人馬がゆれたのです」「いえずさわやかないようとしてほんとうと思ったのです。そこ、この傾斜けい、どおまえ、ぼくをあげて狂気きょ"...

//Faker\Provider\DateTime
var_dump($faker->unixTime($max = 'now')); // 58781813
var_dump($faker->dateTime($max = 'now', $timezone = null)); // DateTime('2008-04-25 08:37:17', 'Asia/Tokyo')
var_dump($faker->dateTimeAD($max = 'now', $timezone = null)); // DateTime('1800-04-29 20:38:49', 'Asia/Tokyo')
var_dump($faker->iso8601($max = 'now')); // '1978-12-09T10:10:29+0000'
var_dump($faker->date($format = 'Y-m-d', $max = 'now')); // '1979-06-09'
var_dump($faker->time($format = 'H:i:s', $max = 'now')); // '20:49:42'
var_dump($faker->dateTimeBetween($startDate = '-30 years', $endDate = 'now', $timezone = null)); // DateTime('2003-03-15 02:00:49', 'Asia/Tokyo')
var_dump($faker->dateTimeInInterval($startDate = '-30 years', $interval = '+ 5 days', $timezone = null)); // DateTime('2003-03-15 02:00:49', 'Asia/Tokyo')
var_dump($faker->dateTimeThisCentury($max = 'now', $timezone = null)); // DateTime('1915-05-30 19:28:21', 'Asia/Tokyo')
var_dump($faker->dateTimeThisDecade($max = 'now', $timezone = null)); // DateTime('2007-05-29 22:30:48', 'Asia/Tokyo')
var_dump($faker->dateTimeThisYear($max = 'now', $timezone = null)); // DateTime('2011-02-27 20:52:14', 'Asia/Tokyo')
var_dump($faker->dateTimeThisMonth($max = 'now', $timezone = null)); // DateTime('2011-10-23 13:46:23', 'Asia/Tokyo')
var_dump($faker->amPm($max = 'now')); // 'pm'
var_dump($faker->dayOfMonth($max = 'now')); // '04'
var_dump($faker->dayOfWeek($max = 'now')); // 'Friday'
var_dump($faker->month($max = 'now')); // '06'
var_dump($faker->monthName($max = 'now')); // 'January'
var_dump($faker->year($max = 'now')); // '1993'
var_dump($faker->century); // 'VI'
var_dump($faker->timezone); // 'Europe/Paris'

//$timezone引数を受け入れるメソッドは、デフォルトでdate_default_timezone_get()になります。
//各メソッドにカスタムタイムゾーン文字列を渡すか、$faker::setDefaultTimezone($timezone)を使用してすべての時間メソッドにカスタムタイムゾーンを一度に定義できます。

//Faker\Provider\Internet
var_dump($faker->email); // 'tkshlerin@collins.com'
var_dump($faker->safeEmail); // 'king.alford@example.org'
var_dump($faker->freeEmail); // 'bradley72@gmail.com'
var_dump($faker->companyEmail); // 'russel.durward@mcdermott.org'
var_dump($faker->freeEmailDomain); // 'yahoo.com'
var_dump($faker->safeEmailDomain); // 'example.org'
var_dump($faker->userName); // 'naoto.ogaki'
var_dump($faker->password); // 'k&|X+a45*2['
var_dump($faker->domainName); // 'wolffdeckow.net'
//        var_dump($faker->domainWord); // 'feeney'
var_dump($faker->tld); // 'jp'
var_dump($faker->url); // 'http://www.skilesdonnelly.biz/aut-accusantium-ut-architecto-sit-et.html'
var_dump($faker->slug); // 'aut-repellat-commodi-vel-itaque-nihil-id-saepe-nostrum'
var_dump($faker->ipv4); // '109.133.32.252'
var_dump($faker->localIpv4); // '10.242.58.8'
var_dump($faker->ipv6); // '8e65:933d:22ee:a232:f1c1:2741:1f10:117c'
var_dump($faker->macAddress); // '43:85:B7:08:10:CA'

//Faker\Provider\UserAgent
var_dump($faker->userAgent); // 'Mozilla/5.0 (Windows CE) AppleWebKit/5350 (KHTML, like Gecko) Chrome/13.0.888.0 Safari/5350'
var_dump($faker->chrome); // 'Mozilla/5.0 (Macintosh; PPC Mac OS X 10_6_5) AppleWebKit/5312 (KHTML, like Gecko) Chrome/14.0.894.0 Safari/5312'
var_dump($faker->firefox); // 'Mozilla/5.0 (X11; Linuxi686; rv:7.0) Gecko/20101231 Firefox/3.6'
var_dump($faker->safari); // 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_7_1 rv:3.0; en-US) AppleWebKit/534.11.3 (KHTML, like Gecko) Version/4.0 Safari/534.11.3'
var_dump($faker->opera); // 'Opera/8.25 (Windows NT 5.1; en-US) Presto/2.9.188 Version/10.00'
var_dump($faker->internetExplorer); // 'Mozilla/5.0 (compatible; MSIE 7.0; Windows 98; Win 9x 4.90; Trident/3.0)'

//Faker\Provider\Payment
var_dump($faker->creditCardType); // 'MasterCard'
var_dump($faker->creditCardNumber); // '4485480221084675'
var_dump($faker->creditCardExpirationDate); // DateTime('2011-10-23 13:46:23', 'Asia/Tokyo')
var_dump($faker->creditCardExpirationDateString); // '04/13'
var_dump($faker->creditCardDetails); // array('MasterCard', '4485480221084675', '吉田 あすか', '04/13')
//ランダムIBANを生成します。国をランダムにするには$countryCodeをnullに設定します。
$countryCode = 20;
var_dump($faker->iban($countryCode)); // 'IT31A8497112740YZ575DJ28BP4'
var_dump($faker->swiftBicNumber); // 'RZTIAT22263'

//Faker\Provider\Color
var_dump($faker->hexcolor); // '#fa3cc2'
var_dump($faker->rgbcolor); // '0,255,122'
var_dump($faker->rgbColorAsArray); // array(0,255,122)
var_dump($faker->rgbCssColor); // 'rgb(0,255,122)'
var_dump($faker->safeColorName); // 'fuchsia'
var_dump($faker->colorName); // 'Gainsbor'
var_dump($faker->hslColor); // '340,50,20'
var_dump($faker->hslColorAsArray); // array(340,50,20)

//Faker\Provider\File
var_dump($faker->fileExtension); // 'avi'
var_dump($faker->mimeType); // 'video/x-msvideo'
//ランダムなファイルをソースからターゲットディレクトリにコピーし、フルパスまたはファイル名を返します
mkdir('/tmp/source');
mkdir('/tmp/target');
touch('/tmp/source/file1');
touch('/tmp/source/file2');
var_dump($faker->file($sourceDir = '/tmp/source', $targetDir = '/tmp/target')); // '/tmp/target/08b08f31-7975-3b79-b37b-5df544666301.'
var_dump($faker->file($sourceDir, $targetDir, false)); // '13b73edae8443990be1aa8f1a483bc27.jpg'

//Faker\Provider\Image
//LoremPixel（http://lorempixel.com/）が提供する画像生成
var_dump($faker->imageUrl($width = 640, $height = 480)); // 'http://lorempixel.com/640/480/'
var_dump($faker->imageUrl($width, $height, 'cats')); // 'http://lorempixel.com/800/600/cats/'
var_dump($faker->imageUrl($width, $height, 'cats', true, 'Faker')); // 'http://lorempixel.com/800/400/cats/Faker'
var_dump($faker->imageUrl($width, $height, 'cats', true, 'Faker', true)); // 'http://lorempixel.com/gray/800/400/cats/Faker/' Monochrome image
var_dump($faker->image($dir = '/tmp', $width = 640, $height = 480)); // '/tmp/13b73edae8443990be1aa8f1a483bc27.jpg'
var_dump($faker->image($dir, $width, $height, 'cats')); // 'tmp/13b73edae8443990be1aa8f1a483bc27.jpg' it's a cat!
var_dump($faker->image($dir, $width, $height, 'cats', false)); // '13b73edae8443990be1aa8f1a483bc27.jpg' it's a filename without path
var_dump($faker->image($dir, $width, $height, 'cats', true, false)); // it's a no randomize images (default: `true`)
var_dump($faker->image($dir, $width, $height, 'cats', true, true, 'Faker')); // 'tmp/13b73edae8443990be1aa8f1a483bc27.jpg' it's a cat with 'Faker' text. Default, `null`.

//Faker\Provider\Uuid
var_dump($faker->uuid); // '7e57d004-2b97-0e7a-b45f-5387367791cd'

//Faker\Provider\Barcode
var_dump($faker->ean13); // '4006381333931'
var_dump($faker->ean8); // '73513537'
var_dump($faker->isbn13); // '9790404436093'
var_dump($faker->isbn10); // '4881416324'

//Faker\Provider\Miscellaneous
var_dump($faker->boolean); // false
var_dump($faker->boolean($chanceOfGettingTrue = 50)); // true
var_dump($faker->md5); // 'de99a620c50f2990e87144735cd357e7'
var_dump($faker->sha1); // 'f08e7f04ca1a413807ebc47551a40a20a0b4de5c'
var_dump($faker->sha256); // '0061e4c60dac5c1d82db0135a42e00c89ae3a333e7c26485321f24348c7e98a5'
var_dump($faker->locale); // en_UK
var_dump($faker->countryCode); // UK
var_dump($faker->languageCode); // en
var_dump($faker->currencyCode); // EUR
var_dump($faker->emoji); // 😁

//Faker\Provider\Biased
//20に近くなる可能性が高い、10〜20の乱数を取得します
var_dump($faker->biasedNumberBetween($min = 10, $max = 20, $function = 'sqrt')); //

//Faker\Provider\HtmlLorem
//2レベル以下の深さで、どのレベルでも3エレメント以下のHTMLドキュメントを生成します。
var_dump($faker->randomHtml(2, 3)); // <html><head><title>Aut illo dolorem et accusantium eum.</title></head><body><form action="example.com" method="POST"><label for="username">sequi</label><input type="text" id="username"><label for="password">et</label><input type="password" id="password"></form><b>Id aut saepe non mollitia voluptas voluptas.</b><table><thead><tr><tr>Non consequatur.</tr><tr>Incidunt est.</tr><tr>Aut voluptatem.</tr><tr>Officia voluptas rerum quo.</tr><tr>Asperiores similique.</tr></tr></thead><tbody><tr><td>Sapiente dolorum dolorem sint laboriosam commodi qui.</td><td>Commodi nihil nesciunt eveniet quo repudiandae.</td><td>Voluptates explicabo numquam distinctio necessitatibus repellat.</td><td>Provident ut doloremque nam eum modi aspernatur.</td><td>Iusto inventore.</td></tr><tr><td>Animi nihil ratione id mollitia libero ipsa quia tempore.</td><td>Velit est officia et aut tenetur dolorem sed mollitia expedita.</td><td>Modi modi repudiandae pariatur voluptas rerum ea incidunt non molestiae eligendi eos deleniti.</td><td>Exercitationem voluptatibus dolor est iste quod molestiae.</td><td>Quia reiciendis.</td></tr><tr><td>Inventore impedit exercitationem voluptatibus rerum cupiditate.</td><td>Qui.</td><td>Aliquam.</td><td>Autem nihil aut et.</td><td>Dolor ut quia error.</td></tr><tr><td>Enim facilis iusto earum et minus rerum assumenda quis quia.</td><td>Reprehenderit ut sapiente occaecati voluptatum dolor voluptatem vitae qui velit.</td><td>Quod fugiat non.</td><td>Sunt nobis totam mollitia sed nesciunt est deleniti cumque.</td><td>Repudiandae quo.</td></tr><tr><td>Modi dicta libero quisquam doloremque qui autem.</td><td>Voluptatem aliquid saepe laudantium facere eos sunt dolor.</td><td>Est eos quis laboriosam officia expedita repellendus quia natus.</td><td>Et neque delectus quod fugit enim repudiandae qui.</td><td>Fugit soluta sit facilis facere repellat culpa magni voluptatem maiores tempora.</td></tr><tr><td>Enim dolores doloremque.</td><td>Assumenda voluptatem eum perferendis exercitationem.</td><td>Quasi in fugit deserunt ea perferendis sunt nemo consequatur dolorum soluta.</td><td>Maxime repellat qui numquam voluptatem est modi.</td><td>Alias rerum rerum hic hic eveniet.</td></tr><tr><td>Tempore voluptatem.</td><td>Eaque.</td><td>Et sit quas fugit iusto.</td><td>Nemo nihil rerum dignissimos et esse.</td><td>Repudiandae ipsum numquam.</td></tr><tr><td>Nemo sunt quia.</td><td>Sint tempore est neque ducimus harum sed.</td><td>Dicta placeat atque libero nihil.</td><td>Et qui aperiam temporibus facilis eum.</td><td>Ut dolores qui enim et maiores nesciunt.</td></tr><tr><td>Dolorum totam sint debitis saepe laborum.</td><td>Quidem corrupti ea.</td><td>Cum voluptas quod.</td><td>Possimus consequatur quasi dolorem ut et.</td><td>Et velit non hic labore repudiandae quis.</td></tr></tbody></table></body></html>
```

### 修飾子

`$factory->unique()->xxx()` を使用するとユニークな値を生成できます。

編集中

## まとめ
Fakerの網羅的な使い方が無さそうだったのでまとめてみました。
この記事は日本語話者の足がかりとして見ていただき、基本的には[公式のREADME](https://github.com/fzaninotto/Faker)を見るようにしてください。

ランダムデータ生成は単体テストでは欠かせないものです。
LaravelのFactoryは、設定の必要も無く即使用できるため、絶対使った方が良いですよ！