Skip to content

Commit

Permalink
feature #5948 Add mode to search all/any terms (all as default)
Browse files Browse the repository at this point in the history
  • Loading branch information
tasiot committed Nov 6, 2023
1 parent 25e7d16 commit f542df6
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 61 deletions.
16 changes: 8 additions & 8 deletions doc/crud.rst
Original file line number Diff line number Diff line change
Expand Up @@ -240,21 +240,21 @@ Search, Order, and Pagination Options
->setSearchFields(null)
// call this method to focus the search input automatically when loading the 'index' page
->setAutofocusSearch()
// match any terms (default mode)
// term1 in (field1 or field2) or term2 in (field1 or field2)
->setSearchMode(SearchMode::ANY_TERMS)
// force to match all the terms
// force to match all the terms (default mode)
// term1 in (field1 or field2) and term2 in (field1 or field2)
->setSearchMode(SearchMode::ALL_TERMS)
// match any terms
// term1 in (field1 or field2) or term2 in (field1 or field2)
->setSearchMode(SearchMode::ANY_TERMS)
;
}

.. tip::

The search engine makes an OR query by default (searching for ``foo bar``
returns items with ``foo`` OR ``bar`` OR ``foo bar``). You can wrap all or
part of your query with quotes to make an exact search: ``"foo bar"`` only
returns items with that exact content, including the middle white space.
The search engine splits all terms by default (searching for ``foo bar``
returns items with ``foo`` and ``bar``). You can wrap all or part of your
query with quotes to make an exact search: ``"foo bar"`` only returns
items with that exact content, including the middle white space.

::

Expand Down
2 changes: 1 addition & 1 deletion src/Dto/CrudDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ final class CrudDto
private ?string $decimalSeparator = null;
private array $defaultSort = [];
private ?array $searchFields = [];
private string $searchMode = SearchMode::ANY_TERMS;
private string $searchMode = SearchMode::ALL_TERMS;
private bool $autofocusSearch = false;
private bool $showEntityActionsAsDropdown = true;
private ?PaginatorDto $paginatorDto = null;
Expand Down
2 changes: 1 addition & 1 deletion src/Dto/SearchDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class SearchDto
private ?array $appliedFilters;
private string $searchMode;

public function __construct(Request $request, ?array $searchableProperties, ?string $query, array $defaultSort, array $customSort, ?array $appliedFilters, string $searchMode = SearchMode::ANY_TERMS)
public function __construct(Request $request, ?array $searchableProperties, ?string $query, array $defaultSort, array $customSort, ?array $appliedFilters, string $searchMode = SearchMode::ALL_TERMS)
{
$this->request = $request;
$this->searchableProperties = $searchableProperties;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

use EasyCorp\Bundle\EasyAdminBundle\Test\AbstractCrudTestCase;
use EasyCorp\Bundle\EasyAdminBundle\Tests\TestApplication\Controller\DashboardController;
use EasyCorp\Bundle\EasyAdminBundle\Tests\TestApplication\Controller\Search\AllTermsCrudSearchController;
use EasyCorp\Bundle\EasyAdminBundle\Tests\TestApplication\Controller\Search\AnyTermsCrudSearchController;

class AllTermsCrudSearchControllerTest extends AbstractCrudTestCase
class AnyTermsCrudSearchControllerTest extends AbstractCrudTestCase
{
protected function getControllerFqcn(): string
{
return AllTermsCrudSearchController::class;
return AnyTermsCrudSearchController::class;
}

protected function getDashboardFqcn(): string
Expand Down Expand Up @@ -41,29 +41,29 @@ public static function provideSearchTests(): iterable
$numOfPostsWrittenByEachAuthor = 4;
$numOfPostsPublishedByEachUser = 2;

yield 'search by blog post title and author or publisher email no results' => [
'"Blog Post 10" "user4@"',
yield 'search by blog post title yields no results' => [
'blog post',
0,
];

yield 'search by blog post title and author or publisher email' => [
'Blog Post "user4@"',
$numOfPostsWrittenByEachAuthor + $numOfPostsPublishedByEachUser,
yield 'search by blog post slug yields no results' => [
'blog-post',
0,
];

yield 'search by author and publisher email' => [
'user1 user2@',
$numOfPostsPublishedByEachUser,
yield 'search by author or publisher email' => [
'@example.com',
$totalNumberOfPosts,
];

yield 'search by author and publisher email no results' => [
'user1 user3@',
0,
yield 'quoted search by author or published email' => [
'"user4@"',
$numOfPostsWrittenByEachAuthor + $numOfPostsPublishedByEachUser,
];

yield 'search by author or publisher email' => [
'user4',
$numOfPostsWrittenByEachAuthor + $numOfPostsPublishedByEachUser,
yield 'multiple search by author or publisher email (partial or complete)' => [
'"[email protected]" "user4@"',
2 * $numOfPostsWrittenByEachAuthor + 2 * $numOfPostsPublishedByEachUser,
];
}
}
29 changes: 14 additions & 15 deletions tests/Controller/Search/CustomCrudSearchControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,32 @@ public static function provideSearchTests(): iterable
{
// the CRUD Controller associated to this test has configured the search
// properties used by the search engine. That's why results are not the default ones
$totalNumberOfPosts = 20;
$numOfPostsWrittenByEachAuthor = 4;
$numOfPostsPublishedByEachUser = 2;

yield 'search by blog post title yields no results' => [
'blog post',
yield 'search by blog post title and author or publisher email no results' => [
'"Blog Post 10" "user4@"',
0,
];

yield 'search by blog post slug yields no results' => [
'blog-post',
0,
yield 'search by blog post title and author or publisher email' => [
'Blog Post "user4@"',
$numOfPostsWrittenByEachAuthor + $numOfPostsPublishedByEachUser,
];

yield 'search by author or publisher email' => [
'@example.com',
$totalNumberOfPosts,
yield 'search by author and publisher email' => [
'user1 user2@',
$numOfPostsPublishedByEachUser,
];

yield 'quoted search by author or published email' => [
'"user4@"',
$numOfPostsWrittenByEachAuthor + $numOfPostsPublishedByEachUser,
yield 'search by author and publisher email no results' => [
'user1 user3@',
0,
];

yield 'multiple search by author or publisher email (partial or complete)' => [
'"[email protected]" "user4@"',
2 * $numOfPostsWrittenByEachAuthor + 2 * $numOfPostsPublishedByEachUser,
yield 'search by author or publisher email' => [
'user4',
$numOfPostsWrittenByEachAuthor + $numOfPostsPublishedByEachUser,
];
}
}
36 changes: 27 additions & 9 deletions tests/Controller/Search/DefaultCrudSearchControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,36 @@ public static function provideSearchTests(): iterable
$totalNumberOfPosts,
];

yield 'default search is OR search' => [
yield 'search all blog posts (use quotes)' => [
[],
'post 17',
'"blog post"',
$totalNumberOfPosts,
];

yield 'use quotes to make an AND search' => [
yield 'search all terms' => [
[],
'blog post-17',
1,
];

yield 'search all terms (inversed terms)' => [
[],
'post-17 blog',
1,
];

yield 'search all terms with quotes' => [
[],
'"post 17"',
1,
];

yield 'search all terms with quotes (inversed terms)' => [
[],
'"17 post"',
0,
];

yield 'quoted terms with inside quotes' => [
[
['title' => 'Foo "Bar Baz', 'slug' => 'foo-bar-baz'],
Expand All @@ -143,16 +161,16 @@ public static function provideSearchTests(): iterable
1,
];

yield "multiple quoted terms (it's an OR of two AND terms)" => [
yield 'multiple quoted terms' => [
[],
'"post 17" "post 18"',
2,
'"Blog post" "post 17"',
1,
];

yield "multiple quoted terms and unquoted terms (it's an OR search again)" => [
yield 'multiple quoted terms and unquoted terms' => [
[],
'"post 17" "post 18" post 5',
$totalNumberOfPosts,
'"Blog post" "post 17" post ipsum',
1,
];
}

Expand Down
18 changes: 12 additions & 6 deletions tests/Dto/SearchDtoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ class SearchDtoTest extends TestCase
{
public function testQueryStringIsTrimmedAutomatically()
{
$dto = new SearchDto(new Request(), null, ' foo ', [], [], null, SearchMode::ANY_TERMS);
$dto = new SearchDto(new Request(), null, ' foo ', [], [], null);
$this->assertSame('foo', $dto->getQuery());
}

public function testDefaultSort()
{
$dto = new SearchDto(new Request(), null, null, ['foo' => 'ASC'], [], null, SearchMode::ANY_TERMS);
$dto = new SearchDto(new Request(), null, null, ['foo' => 'ASC'], [], null);
$this->assertSame(['foo' => 'ASC'], $dto->getSort());
}

Expand All @@ -26,7 +26,7 @@ public function testDefaultSort()
*/
public function testSortConfigMerging(array $defaultSort, array $customSort, array $expectedSortConfig)
{
$dto = new SearchDto(new Request(), null, null, $defaultSort, $customSort, null, SearchMode::ANY_TERMS);
$dto = new SearchDto(new Request(), null, null, $defaultSort, $customSort, null);
$this->assertSame($expectedSortConfig, $dto->getSort());
}

Expand All @@ -35,7 +35,7 @@ public function testSortConfigMerging(array $defaultSort, array $customSort, arr
*/
public function testIsSortingField(array $defaultSort, array $customSort, string $fieldName, bool $expectedResult)
{
$dto = new SearchDto(new Request(), null, null, $defaultSort, $customSort, null, SearchMode::ANY_TERMS);
$dto = new SearchDto(new Request(), null, null, $defaultSort, $customSort, null);
$this->assertSame($expectedResult, $dto->isSortingField($fieldName));
}

Expand All @@ -44,7 +44,7 @@ public function testIsSortingField(array $defaultSort, array $customSort, string
*/
public function testGetSortDirection(array $defaultSort, array $customSort, string $fieldName, string $expectedDirection)
{
$dto = new SearchDto(new Request(), null, null, $defaultSort, $customSort, null, SearchMode::ANY_TERMS);
$dto = new SearchDto(new Request(), null, null, $defaultSort, $customSort, null);
$this->assertSame($expectedDirection, $dto->getSortDirection($fieldName));
}

Expand All @@ -53,10 +53,16 @@ public function testGetSortDirection(array $defaultSort, array $customSort, stri
*/
public function testGetQueryTerms(string $query, array $expectedQueryTerms)
{
$dto = new SearchDto(new Request(), null, $query, [], [], null, SearchMode::ANY_TERMS);
$dto = new SearchDto(new Request(), null, $query, [], [], null);
$this->assertSame($expectedQueryTerms, $dto->getQueryTerms());
}

public function testDefaultSearchMode()
{
$dto = new SearchDto(new Request(), null, null, ['foo' => 'ASC'], [], null);
$this->assertSame(SearchMode::ALL_TERMS, $dto->getSearchMode());
}

public function testSearchMode()
{
foreach ([SearchMode::ANY_TERMS, SearchMode::ALL_TERMS] as $searchMode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Tests\TestApplication\Entity\BlogPost;

class AllTermsCrudSearchController extends AbstractCrudController
class AnyTermsCrudSearchController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
Expand All @@ -17,7 +17,7 @@ public static function getEntityFqcn(): string
public function configureCrud(Crud $crud): Crud
{
return parent::configureCrud($crud)
->setSearchFields(['title', 'author.email', 'publisher.email'])
->setSearchMode(SearchMode::ALL_TERMS);
->setSearchFields(['id', 'author.email', 'publisher.email'])
->setSearchMode(SearchMode::ANY_TERMS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public static function getEntityFqcn(): string
public function configureCrud(Crud $crud): Crud
{
return parent::configureCrud($crud)
->setSearchFields(['id', 'author.email', 'publisher.email']);
->setSearchFields(['title', 'author.email', 'publisher.email']);
}
}

0 comments on commit f542df6

Please sign in to comment.