# PHPのフレームワークLaravelでAlgoliaを使うための環境構築 その3
👇の Live Coding Session - Advanced Search with Laravel and Algolia by Nuno Maduro を自分でも試しているのですが、
前回はPestでテストを走らせて、データベースがありませんがなエラーが出るところまでいきました。
ということで、 Pest.php を👇のようにしてRefreshDatabaseを呼ぶようにしてみました。
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(Tests\TestCase::class, RefreshDatabase::class)->in('Feature');
すると👇のようにSQLiteのファイルがそれっぽくなっています。
で、テスト流すと、20個プロダクトあるはずが0件ですよ、と。イイ感じになってきました。
$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
FAIL Tests\Feature\ExampleTest
⨯ has products
---
• Tests\Feature\ExampleTest > has products
Failed asserting that 0 matches expected 20.
# テストデータの準備
database -> migrationsの中でテストデータを準備するところの中に20個のProductを作るようにってことで👇のupメソッドの中で。
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
factory(\App\Product::class, 20)->create();
}
するとテストが通るようになりました!
$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
PASS Tests\Feature\ExampleTest
✓ has products
Tests: 2 passed
Time: 0.25s
# プロダクトの属性
Productがtitle, description, priceという属性を持っているかというテストを追加。
test('has a title, description, and a price', function() {
$product = Product::first();
assertNotEmpty($product->title);
assertNotEmpty($product->description);
assertNotEmpty($product->price);
});
そして、CreateProductsTableクラスのupメソッドの中で👇のようにString型のTitleと、Text型のDescriptionとInteger型のPriceを追加。
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description');
$table->integer('price');
$table->timestamps();
});
そしてテストを流すと、、👇何やらエラーが。
$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
FAIL Tests\Feature\ExampleTest
⨯ has products
⨯ has a title, description, and a price
---
• Tests\Feature\ExampleTest > has products
Illuminate\Database\QueryException
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: products.title (SQL: insert into "products" ("updated_at", "created_at") values (2020-07-20 09:24:20, 2020-07-20 09:24:20))
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:671
これにはFakerというテスト用のモジュールを使って、、という流れ。ProductFactoryクラスのコードは👇
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Product;
use Faker\Generator as Faker;
$factory->define(Product::class, function (Faker $faker) {
return [
'title' => $faker->title,
'description' => $faker->text,
'price' => $faker->randomNumber(2)
];
});
で、テストをすると👇のように通りました〜
$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
PASS Tests\Feature\ExampleTest
✓ has products
✓ has a title, description, and a price
Tests: 3 passed
Time: 0.21s
そして、ExampleTestってクラス名が微妙だよねってことで、ProductTestという名前に変更。
./vendor/bin/pest をしてテストが成功するのを確認したらいよいよ、、
# Algoliaにデータを送る
ここでLaravel Scoutを使う。通常は👇でインストールするけど、
composer require laravel/scout
👇のAlgolia拡張版の方を入れると、基本的にはLaravel Scoutと同じだけど、Algolia用の実装が追加されている、とのこと。
composer require algolia/scout-extended
実際に中身を見ていくと👇のようにlaravel/scoutやalgoliasearch-client-phpが入っています、と。
Package operations: 4 installs, 0 updates, 0 removals
- Installing riimu/kit-phpencoder (v2.4.0): Downloading (100%)
- Installing laravel/scout (v8.1.0): Downloading (100%)
- Installing algolia/algoliasearch-client-php (2.7.0): Downloading (100%)
- Installing algolia/scout-extended (v1.9.0): Downloading (100%)
# Productモデルを検索可能にする
Product.phpにて👇のようにSearchable。
<?php
namespace App;
use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use Searchable;
}
テスト書くよ、と。👇のように検索した結果がローカルのデータベースと同じ件数であること。
test('has search', function() {
$response = Product::search();
assertEquals($response->count(), Product::count());
});
YouTube上ではテストが成功していますが、何もAlgoliaの設定を入れていないので👇のようにテストは失敗します。
a$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
FAIL Tests\Feature\ProductTest
⨯ has products
⨯ has a title, description, and a price
⨯ has search
---
• Tests\Feature\ProductTest > has products
Algolia\AlgoliaSearch\Exceptions\UnreachableException
Impossible to connect, please check your Algolia Application Id.
at vendor/algolia/algoliasearch-client-php/src/RetryStrategy/ApiWrapper.php:187
そして、何のことやらよくわかってないですが(笑)、Laravel Scoutの設定ファイル(?)をpublishします。
$ php artisan vendor:publish
Which provider or tag's files would you like to publish?:
[0 ] Publish files from all providers and tags listed below
[1 ] Provider: Facade\Ignition\IgnitionServiceProvider
[2 ] Provider: Fideloper\Proxy\TrustedProxyServiceProvider
[3 ] Provider: Fruitcake\Cors\CorsServiceProvider
[4 ] Provider: Illuminate\Foundation\Providers\FoundationServiceProvider
[5 ] Provider: Illuminate\Mail\MailServiceProvider
[6 ] Provider: Illuminate\Notifications\NotificationServiceProvider
[7 ] Provider: Illuminate\Pagination\PaginationServiceProvider
[8 ] Provider: Laravel\Scout\ScoutServiceProvider
[9 ] Provider: Laravel\Tinker\TinkerServiceProvider
[10] Tag: cors
[11] Tag: flare-config
[12] Tag: ignition-config
[13] Tag: laravel-errors
[14] Tag: laravel-mail
[15] Tag: laravel-notifications
[16] Tag: laravel-pagination
> 8
Copied File [/vendor/laravel/scout/config/scout.php] To [/config/scout.php]
Publishing complete.
そして、configディレクトリのscout.phpをみると👇のような設定箇所があります。
'algolia' => [
'id' => env('ALGOLIA_APP_ID', ''),
'secret' => env('ALGOLIA_SECRET', ''),
],
ってことで、.envファイルにAlgoliaのクレデンシャルを追加していきます。
ALGOLIA_APP_ID=xxx
ALGOLIA_SECRET=xxx
で、テストすると、今度はAlgolia側にproductsっていうインデックスが無いよ、と。データベースはテーブル作るとこからやってくれるけど、Algoliaに関してはインデックスは自分で作っておきなさいって感じなのかな〜
$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
FAIL Tests\Feature\ProductTest
✓ has products
✓ has a title, description, and a price
⨯ has search
---
• Tests\Feature\ProductTest > has search
Algolia\AlgoliaSearch\Exceptions\NotFoundException
Index products does not exist
at vendor/algolia/algoliasearch-client-php/src/RetryStrategy/ApiWrapper.php:208
って、Algoliaのダッシュボードみたらproductsインデックスは既にあって、データもそれっぽいのが20件入ってますよ、と。ってか、タイトルがDr.とかMr.とかなのがちょっとウケというか、なんというかソレじゃない感。笑
そして、もっかいテスト流したら通ったので、indexを作ってる間にテストが流れちゃってたとかそんな感じかな、と。
$ ./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ basic test
PASS Tests\Feature\ProductTest
✓ has products
✓ has a title, description, and a price
✓ has search
Tests: 4 passed
Time: 0.74s
ということで、今日はAlgoliaとやりとりするところまで出来ました。