95.全文搜索(二)
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 95 小节:First Class Search: Implementation
本节内容
上一节我们初步了解了Scout 和 Algolia ,这一节我们初步实现话题搜索功能。我们依然是从新建测试开始:
forum\tests\Feature\SearchTest.php
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class SearchTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function a_user_can_search_threads()
{
$search = 'foobar';
create('App\Thread',[],2);
create('App\Thread',['body' => "A thread with {$search} term."],2);
$results = $this->getJson("/threads/search?q={$search}")->json();
$this->assertCount(2,$results['data']);
}
}
添加路由:
forum\routes\web.php
.
Route::get('threads/create','ThreadsController@create');
Route::get('threads/search','SearchController@show');
.
新建控制器并添加show()
方法:
$ php artisan make:controller SearchController
forum\app\Http\Controllers\SearchController.php
<?php
namespace App\Http\Controllers;
use App\Thread;
class SearchController extends Controller
{
public function show()
{
$search = request('q');
return Thread::search($search)->paginate(20);
}
}
运行测试:
我们搜索出来的结果也会显示在页面上,所以我们来修改下代码:
<?php
namespace App\Http\Controllers;
use App\Thread;
use App\Trending;
class SearchController extends Controller
{
public function show(Trending $trending)
{
$search = request('q');
$threads = Thread::search($search)->paginate(20);
if (request()->expectsJson()) {
return $threads;
}
return view('threads.index',[
'threads' => $threads,
'trending' => $trending->get()
]);
}
}
再次运行测试:
但是现在有一个问题需要我们解决。由于我们在forum\config\scout.php
设置的驱动是algolia
:
.
'driver' => env('SCOUT_DRIVER', 'algolia'),
.
因此在我们每次新建话题时,话题都会被同步到 Algolia 上,比如刚刚测试的时候新建的话题:
我们并不需要每次都进行同步,所以我们进行下处理,只在刚刚的测试中应用algolia
驱动进行同步,其他的测试则不应用algolia
驱动:
forum\phpunit.xml
.
.
<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="SCOUT_DRIVER" value="null"/>
</php>
</phpunit>
并且,在刚才的测试中,我们应用algolia
驱动,还要在测试之后删除我们的测试数据:
forum\tests\Feature\SearchTest.php
<?php
namespace Tests\Feature;
use App\Thread;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class SearchTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function a_user_can_search_threads()
{
// 启用驱动
config(['scout.driver' => 'algolia']);
$search = 'foobar';
create('App\Thread',[],2);
create('App\Thread',['body' => "A thread with {$search} term."],2);
// 由于网络等因素,所以我们进行以下处理
do {
sleep(.25);
$results = $this->getJson("/threads/search?q={$search}")->json();
} while (empty($results));
$this->assertCount(2,$results['data']);
// 删除测试数据
Thread::latest()->take(4)->unsearchable();
}
}
运行全部测试:
现在我们在话题列表页面加上搜索功能:
forum\resources\views\threads\index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8">
@include ('threads._list')
{{ $threads->render() }}
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
Search
</div>
<div class="panel-body">
<form method="GET" action="/threads/search">
<div class="form-group">
<input type="text" name="q" placeholder="Search for something..." class="form-control">
</div>
<div class="form-group">
<button class="btn btn-default" type="submit">Search</button>
</div>
</form>
</div>
</div>
@if(count($trending))
.
.
进行搜索: