どーも!
たかぽんです!
今回はSymfonyにて、Fixtureというものを利用してテストデータを作ってみようと思います!
ちなみに、FixtureといえばPHPUnitではテスト前後のちょっとした用意的なニュアンスで使われていた気がします。
では、さっそく行ってみましょう!
目次
Fixtureをインストールする
まず最初にfixture用のコンポーネントをインストールします。
composer require orm-fixtures --dev
上記コマンドを叩くだけでインストールは問題なく進むはずです...!
これでfixtureに関連する機能を使えるようになるはずです。
次にFixtureを作成します!
Fixtureを作成する
Fixtureは"php bin/console make:fixtures"といったコマンドを叩くことで作成できます。
taka@Taka my_project % php bin/console make:fixtures
The class name of the fixtures to create (e.g. AppFixtures):
> UserCommentFixtures
created: src/DataFixtures/UserCommentFixtures.php
Success!
Next: Open your new fixtures class and start customizing it.
Load your fixtures by running: php bin/console doctrine:fixtures:load
Docs: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html
コマンドを叩くと、作成するFixtureのクラス名どうする?って聞かれるので入力します。
今回、Userとそれに紐づくCommentのテーブルにデータを追加するので、"UserCommentFixtures"としてみました。
実行後、"UserCommentFixtures.php"というファイルが自動生成されていればOKです。
次にFixtureの中身を作っていきます。
User, Commentのデータを作成するFixtureを実装する
では、コーディングしていきましょう!
今回はUserテーブルに対して10人分のデータを、そしてさらにその10人に紐づくCommentのデータをUserごとに100件づつ追加する...といった感じにしていきます。
みていただいた方が早いと思うので先に全体のコードを置いておきます。
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use App\Entity\User;
use App\Entity\Comment;
class UserCommentFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
// User 10人分
for ($i = 0; $i < 10; $i++) {
$user = new User();
$user->setName('user'.$i);
$user->setAge(rand(20, 60));
$manager->persist($user);
$manager->flush();
// UserごとComment 100件分
for ($j = 0; $j < 100; $j++) {
$comment = new Comment();
$comment->setUserId($user->getId());
$comment->setMessage('This is comment '.$j.' for user '.$i);
$manager->persist($comment);
}
}
$manager->flush();
}
}
Fixtureでは上記のように、Entityからインスタンスを作成、し、作成したインスタンスを"persist", "flush"を使って反映させていきます。
やっていることは簡単でUserインスタンスを作成し、保存、保存したUserごとにさらにforでcommentを作成し、userのidをとメッセージを保存...といった具合ですね。
あまり筆者も深掘りしていませんが、persistを実行することでインスタンスの内容を保存対象へ追加、flushで実際にDBへ保存していそうです。
そのため、途中で"$user->getId()"で$userインスタンスから値を取得しているのですが、Userインスタンスを作成した後にflushでDBへ保存をしないとidが存在せず、エラーになりました。
Fixtureに必要なのは実はこれだけです...!
次に実行して確認をしてみようと思います!
Fixtureをload(実行)する
それでは!
Fixtureを実行していきます!
php bin/console doctrine:fixtures:load
実行は上記のコマンドだけでOKです。
taka@Taka my_project % php bin/console doctrine:fixtures:load
Careful, database "symfony_test" will be purged. Do you want to continue? (yes/no) [no]:
> yes
> purging database
> loading App\DataFixtures\UserCommentFixtures
実行をすると、"symfony_test" will be purged、つまり、symfony_testのデータが全て消えるけど大丈夫?と聞かれていますね。
今回はテストデータ作成用のDBなので、yesを。
(本番のDBになっていそうだったら絶対に実行は控えてくださいね...w)
すると、問題なく実行がされるかと思います。
そして、
mysql> select * from user;
+----+-------+-----+
| id | name | age |
+----+-------+-----+
| 31 | user0 | 29 |
| 32 | user1 | 43 |
| 33 | user2 | 39 |
| 34 | user3 | 43 |
| 35 | user4 | 57 |
| 36 | user5 | 50 |
| 37 | user6 | 46 |
| 38 | user7 | 29 |
| 39 | user8 | 37 |
| 40 | user9 | 55 |
+----+-------+-----+
10 rows in set (0.00 sec)
mysql> select * from comment;
+------+---------+-------------------------------+
| id | user_id | message |
+------+---------+-------------------------------+
| 111 | 31 | This is comment 0 for user 0 |
| 112 | 31 | This is comment 1 for user 0 |
| 113 | 31 | This is comment 2 for user 0 |
...
...
...
| 209 | 31 | This is comment 98 for user 0 |
| 210 | 31 | This is comment 99 for user 0 |
| 211 | 32 | This is comment 0 for user 1 |
| 212 | 32 | This is comment 1 for user 1 |
| 213 | 32 | This is comment 2 for user 1 |
...
mysql> select count() from comment; +----------+ | count() |
+----------+
| 1000 |
+----------+
1 row in set (0.01 sec)
このような感じでUserには10件、CommentにはUserごと100件のデータが作成されました!
これで結構大規模なデータでもパパッと追加できそうです..!
さて、そしてもう一点だけ。
このままだとデータの内容が味気ないですよね。
もうちょっと現実に沿ったデータを生成してみたい...!
というわけで最後におまけでそこまでやってみようと思います!
Factoryを利用してテストデータをリッチにする!
さて、それでは先ほどはコメントが全て"This is comment 1 for~"となっていたりして、微妙でしたよね...
ここで、はそれをもっとしっかりしたmessageにしたり、ユーザー名をちゃんと日本人にありそうな名称にしたり...といったことをやっていきます。
まずはランダムな値生成のために、fakerというものを使うので、composerでインストールします。
composer require fzaninotto/faker --dev
コマンドを実行したら、"UserCommentFixtures"を以下のように修正します。
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use App\Entity\User;
use App\Entity\Comment;
use Faker\Factory;
class UserCommentFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
$faker = Factory::create('ja_JP');
dd(Factory::create('ja_JP')->realText());
// User 10人分
for ($i = 0; $i < 10; $i++) {
$user = new User();
$user->setName($faker->name);
$user->setAge($faker->numberBetween(5, 100));
$manager->persist($user);
$manager->flush();
// UserごとComment 10件分
for ($j = 0; $j < 10; $j++) {
$comment = new Comment();
$comment->setUserId($user->getId());
$comment->setMessage($faker->realText);
$manager->persist($comment);
}
}
$manager->flush();
}
}
そして再度実行すると...?
mysql> select * from user;
+----+---------------+-----+
| id | name | age |
+----+---------------+-----+
| 51 | 田辺 英樹 | 91 |
| 52 | 坂本 直子 | 71 |
| 53 | 斉藤 和也 | 17 |
| 54 | 藤本 英樹 | 10 |
| 55 | 浜田 拓真 | 65 |
| 56 | 山口 直樹 | 96 |
| 57 | 渚 幹 | 49 |
| 58 | 桐山 幹 | 90 |
| 59 | 山田 太郎 | 74 |
| 60 | 渚 真綾 | 19 |
+----+---------------+-----+
10 rows in set (0.00 sec)
mysql> select * from comment limit 5\G
*************************** 1. row ***************************
id: 4125
user_id: 76
message: Alice very politely; but she gained courage as she could have been changed several times since then.' 'What do you know about it, and on it (as she had been running half an hour or so there were no.
*************************** 2. row ***************************
id: 4126
user_id: 76
message: Alice thought this must ever be A secret, kept from all the first minute or two, and the small ones choked and had been running half an hour or so, and giving it something out of the Mock Turtle. So.
*************************** 3. row ***************************
id: 4127
user_id: 76
message: Queen. 'I never thought about it,' said the Cat, 'a dog's not mad. You grant that?' 'I suppose so,' said Alice. 'Off with her friend. When she got into it), and handed them round as prizes. There.
*************************** 4. row ***************************
id: 4128
user_id: 76
message: I can't understand it myself to begin again, it was good practice to say but 'It belongs to a mouse, That he met in the schoolroom, and though this was not much like keeping so close to her that she.
*************************** 5. row ***************************
id: 4129
user_id: 76
message: I hadn't begun my tea--not above a week or so--and what with the birds and beasts, as well wait, as she swam about, trying to box her own children. 'How should I know?' said Alice, very much at.
5 rows in set (0.00 sec)
このような感じでちょっとそれっぽいデータになりました!
"$faker = Factory::create('ja_JP');"で日本語のデータ生成になるように設定をして、"$faker->name"といった具合で生成することが可能です。
また、$faker->realTextで日本語の生成できた気がしたんですが...何故かできず...何か変わったのかもですね。
ちなみに、使えるメソッドなどはこちらなどを参考にするとわかるかと思います。
(例えば上記リンク先ではcitySuffixが呼び出せそうなことがわかりますね...!)
ちなみにmessageの箇所をcitySuffixを"$comment->setMessage($faker->realText);"にすると...
mysql> select * from comment limit 5\G
*************************** 1. row ***************************
id: 4225
user_id: 86
message: 市
"市"が入ったりするわけですね...w
色々あるので、ぜひコード眺めながら色々試してみてくださいね!
まとめ
今回はテスト用のデータを作成するFixtureを試してみました...!
そんなに難しくもなく、サクッとできましたね!
local環境で動作確認するためにデータを作成...といった時にも色々活用はできそう。
fakerも使えるのでそれなりにまともなデータを追加はできそうなので、これからも活用していきたいですね...!
それでわ!