2021-02-10 22:59:23 +08:00
< ? php
/*
* This file is part of Flarum .
*
* For detailed copyright and license information , please view the
* LICENSE file that was distributed with this source code .
*/
namespace Flarum\Tests\integration\extenders ;
use Carbon\Carbon ;
use Flarum\Discussion\Search\DiscussionSearcher ;
use Flarum\Extend ;
2021-04-20 04:59:53 +08:00
use Flarum\Group\Group ;
2021-03-02 22:57:40 +08:00
use Flarum\Query\QueryCriteria ;
2021-02-10 22:59:23 +08:00
use Flarum\Search\AbstractRegexGambit ;
2021-04-20 04:59:53 +08:00
use Flarum\Search\AbstractSearcher ;
2021-02-10 22:59:23 +08:00
use Flarum\Search\GambitInterface ;
2021-02-25 00:17:40 +08:00
use Flarum\Search\SearchState ;
2021-03-08 05:32:41 +08:00
use Flarum\Testing\integration\RetrievesAuthorizedUsers ;
use Flarum\Testing\integration\TestCase ;
2021-02-10 22:59:23 +08:00
use Flarum\User\User ;
2021-04-20 04:59:53 +08:00
use Illuminate\Contracts\Container\BindingResolutionException ;
use Illuminate\Database\Eloquent\Builder ;
2021-02-10 22:59:23 +08:00
class SimpleFlarumSearchTest extends TestCase
{
use RetrievesAuthorizedUsers ;
public function prepDb ()
{
$this -> database () -> rollBack ();
// We need to insert these outside of a transaction, because FULLTEXT indexing,
// which is needed for search, doesn't happen in transactions.
// We clean it up explcitly at the end.
$this -> database () -> table ( 'discussions' ) -> insert ([
[ 'id' => 1 , 'title' => 'DISCUSSION 1' , 'created_at' => Carbon :: now () -> toDateTimeString (), 'user_id' => 1 , 'comment_count' => 1 ],
[ 'id' => 2 , 'title' => 'DISCUSSION 2' , 'created_at' => Carbon :: now () -> toDateTimeString (), 'user_id' => 1 , 'comment_count' => 1 ],
]);
$this -> database () -> table ( 'posts' ) -> insert ([
[ 'id' => 1 , 'discussion_id' => 1 , 'created_at' => Carbon :: now () -> toDateTimeString (), 'user_id' => 1 , 'type' => 'comment' , 'content' => '<t><p>not in text</p></t>' ],
[ 'id' => 2 , 'discussion_id' => 2 , 'created_at' => Carbon :: now () -> toDateTimeString (), 'user_id' => 1 , 'type' => 'comment' , 'content' => '<t><p>lightsail in text</p></t>' ],
]);
// We need to call these again, since we rolled back the transaction started by `::app()`.
$this -> database () -> beginTransaction ();
$this -> populateDatabase ();
}
/**
* @ inheritDoc
*/
protected function tearDown () : void
{
parent :: tearDown ();
$this -> database () -> table ( 'discussions' ) -> whereIn ( 'id' , [ 1 , 2 ]) -> delete ();
$this -> database () -> table ( 'posts' ) -> whereIn ( 'id' , [ 1 , 2 ]) -> delete ();
}
public function searchDiscussions ( $query , $limit = null )
{
$this -> app ();
$actor = User :: find ( 1 );
2021-03-02 22:57:40 +08:00
$criteria = new QueryCriteria ( $actor , [ 'q' => $query ]);
2021-02-10 22:59:23 +08:00
return $this -> app () -> getContainer () -> make ( DiscussionSearcher :: class ) -> search ( $criteria , $limit ) -> getResults ();
}
/**
* @ test
*/
public function works_as_expected_with_no_modifications ()
{
$this -> prepDb ();
$searchForAll = json_encode ( $this -> searchDiscussions ( 'in text' , 5 ));
2021-03-05 22:43:35 +08:00
$this -> assertStringContainsString ( 'DISCUSSION 1' , $searchForAll );
$this -> assertStringContainsString ( 'DISCUSSION 2' , $searchForAll );
2021-02-10 22:59:23 +08:00
$searchForSecond = json_encode ( $this -> searchDiscussions ( 'lightsail' , 5 ));
2021-03-05 22:43:35 +08:00
$this -> assertStringNotContainsString ( 'DISCUSSION 1' , $searchForSecond );
$this -> assertStringContainsString ( 'DISCUSSION 2' , $searchForSecond );
2021-02-10 22:59:23 +08:00
}
/**
* @ test
*/
public function custom_full_text_gambit_has_effect_if_added ()
{
$this -> extend (( new Extend\SimpleFlarumSearch ( DiscussionSearcher :: class )) -> setFullTextGambit ( NoResultFullTextGambit :: class ));
$this -> assertEquals ( '[]' , json_encode ( $this -> searchDiscussions ( 'in text' , 5 )));
}
/**
* @ test
*/
public function custom_filter_gambit_has_effect_if_added ()
{
$this -> extend (( new Extend\SimpleFlarumSearch ( DiscussionSearcher :: class )) -> addGambit ( NoResultFilterGambit :: class ));
$this -> prepDb ();
$withResultSearch = json_encode ( $this -> searchDiscussions ( 'noResult:0' , 5 ));
2021-03-05 22:43:35 +08:00
$this -> assertStringContainsString ( 'DISCUSSION 1' , $withResultSearch );
$this -> assertStringContainsString ( 'DISCUSSION 2' , $withResultSearch );
2021-02-10 22:59:23 +08:00
$this -> assertEquals ( '[]' , json_encode ( $this -> searchDiscussions ( 'noResult:1' , 5 )));
}
/**
* @ test
*/
public function search_mutator_has_effect_if_added ()
{
$this -> extend (( new Extend\SimpleFlarumSearch ( DiscussionSearcher :: class )) -> addSearchMutator ( function ( $search , $criteria ) {
$search -> getquery () -> whereRaw ( '1=0' );
}));
$this -> prepDb ();
$this -> assertEquals ( '[]' , json_encode ( $this -> searchDiscussions ( 'in text' , 5 )));
}
/**
* @ test
*/
public function search_mutator_has_effect_if_added_with_invokable_class ()
{
$this -> extend (( new Extend\SimpleFlarumSearch ( DiscussionSearcher :: class )) -> addSearchMutator ( CustomSearchMutator :: class ));
$this -> prepDb ();
$this -> assertEquals ( '[]' , json_encode ( $this -> searchDiscussions ( 'in text' , 5 )));
}
2021-04-20 04:59:53 +08:00
/**
* @ test
*/
public function cant_resolve_custom_searcher_without_fulltext_gambit ()
{
$this -> expectException ( BindingResolutionException :: class );
$this -> app () -> getContainer () -> make ( CustomSearcher :: class );
}
/**
* @ test
*/
public function can_resolve_custom_searcher_with_fulltext_gambit ()
{
$this -> extend (
( new Extend\SimpleFlarumSearch ( CustomSearcher :: class )) -> setFullTextGambit ( CustomFullTextGambit :: class )
);
$anExceptionWasThrown = false ;
try {
$this -> app () -> getContainer () -> make ( CustomSearcher :: class );
} catch ( BindingResolutionException $e ) {
$anExceptionWasThrown = true ;
}
$this -> assertFalse ( $anExceptionWasThrown );
}
2021-02-10 22:59:23 +08:00
}
class NoResultFullTextGambit implements GambitInterface
{
/**
* { @ inheritdoc }
*/
2021-02-25 00:17:40 +08:00
public function apply ( SearchState $search , $searchValue )
2021-02-10 22:59:23 +08:00
{
$search -> getQuery ()
-> whereRaw ( '0=1' );
}
}
class NoResultFilterGambit extends AbstractRegexGambit
{
2021-02-25 00:17:40 +08:00
/**
* { @ inheritdoc }
*/
public function getGambitPattern ()
{
return 'noResult:(.+)' ;
}
2021-02-10 22:59:23 +08:00
/**
* { @ inheritdoc }
*/
2021-02-25 00:17:40 +08:00
public function conditions ( SearchState $search , array $matches , $negate )
2021-02-10 22:59:23 +08:00
{
$noResults = trim ( $matches [ 1 ], ' ' );
if ( $noResults == '1' ) {
$search -> getQuery ()
-> whereRaw ( '0=1' );
}
}
}
class CustomSearchMutator
{
public function __invoke ( $search , $criteria )
{
$search -> getQuery () -> whereRaw ( '1=0' );
}
}
2021-04-20 04:59:53 +08:00
class CustomSearcher extends AbstractSearcher
{
// This isn't actually used, we just need it to implement the abstract method.
protected function getQuery ( User $actor ) : Builder
{
return Group :: query ();
}
}
class CustomFullTextGambit implements GambitInterface
{
public function apply ( SearchState $search , $bit )
{
}
}