Searcher是一个与框架无关的搜索查询生成器。搜索查询是使用条件编写的,可以针对 MySQL、MongoDB、ElasticSearch、文件或您喜欢的任何其他内容运行。最新版本仅支持 PHP 7 。现在也用 Humbug 进行了测试
您是否见过负责根据许多不同标准搜索某些内容的代码?它可能会变得一团糟!假设您有一个包含 20 个字段的表单,所有这些字段都会对搜索条件产生一些影响。将整个表单传递给某些服务并让它在一个地方解析所有内容并不是一个好主意。借助这个库,您可以将构建查询条件的责任分配给几个较小的类。每个过滤器一类。每个Criteria
一个CriteriaBuilder
。这样,在CriteriaBuilder
中您只关心一个Criteria
,这使得它更具可读性和可维护性。您稍后可以使用完全相同的Criteria
进行不同的搜索,使用不同的CriteriaBuilder
甚至不同的SearchingContext
(甚至可以使用不同的数据库)。借助FinderSearchingContext
您甚至可以使用搜索器在系统上查找文件。
完整文档可以在 http://searcher.rtfd.io/ 找到
您可以通过在终端中输入以下命令来通过 Composer 安装该库:
$ 作曲家需要 krzysztof-gzocha/searcher
与 Symfony 的集成是在SearcherBundle中完成的
CriteriaBuilder
- 将为单个Criteria
构建新的条件,
Criteria
- 将传递给CriteriaBuilder
模型。你只需要以某种方式给它补充水分,这样它就会有用。 Criteria 内部可以保存多个字段,并且所有(或部分)字段可以在CriteriaBuilder
内部使用,
SearchingContext
- 单个搜索的上下文。该服务应该知道如何从构造的查询中获取结果,并且它包含名为QueryBuilder
的东西,但它可以是任何适合您的服务 - 任何服务。这是搜索和数据库之间的抽象层。 Doctrine的ORM、ODM、Elastica、 Files等都有不同的上下文。如果没有适合您的上下文,您可以实现一个 - 这应该不难,
Searcher
- 保存CriteriaBuilder
的集合并将Criteria
传递给适当的CriteriaBuilder
。
假设我们想要搜索年龄在某个过滤范围内的人。在此示例中,我们将使用 Doctrine 的 QueryBuilder,因此我们将使用QueryBuilderSearchingContext
并在CriteriaBuidler
中指定它应该仅与DoctrineORMQueryBuilder
交互,但请记住,我们不必仅使用 Doctrine。
首先,我们需要创建AgeRangeCriteria
- 该类将保存最小和最大年龄的值。这里已经实现了默认Criteria
。
class AgeRangeCriteria 实现 CriteriaInterface{private $minimalAge;private $maximalAge;/** * 仅必需的方法。 * 如果将返回 true,那么它将被传递给某些 CriteriaBuilder(s) */public function shouldBeApplied(): bool{return null !== $this->minimalAge && null !== $this->maximalAge; }// getter、setter,等等}
在第二步中,我们要指定该模型应施加的条件。这就是为什么我们需要创建AgeRangeCriteriaBuilder
类 AgeRangeCriteriaBuilder 实现 CriteriaBuilderInterface{public function buildCriteria(CriteriaInterface $criteria,SearchingContextInterface $searchingContext) {$searchingContext->getQueryBuilder() ->andWhere('e.age >= :minimalAge') ->andWhere('e.age <= :maximalAge') ->setParameter('minimalAge', $criteria->getMinimalAge()) ->setParameter('maximalAge', $criteria->getMaximalAge()); }公共函数allowsCriteria(CriteriaInterface $criteria): bool{return $criteria instanceof AgeRangeCriteria; }/** * 如果您将从 AbstractORMCriteriaBuilder 扩展,则可以跳过此方法。 */公共函数supportsSearchingContext(SearchingContextInterface $searchingContext): bool{return $searchingContext instanceof QueryBuilderSearchingContext; } }
在接下来的步骤中,我们需要为Criteria
和CriteriaBuidler
创建集合。
$builders = new CriteriaBuilderCollection();$builders->addCriteriaBuilder(new AgeRangeCriteriaBuilder());$builders->addCriteriaBuilder(/** 其余构建器 */);
$ageRangeCriteria = new AgeRangeCriteria();// 我们必须在搜索之前填充模型$ageRangeCriteria->setMinimalAge(23);$ageRangeCriteria->setMaximalAge(29);$criteria = new CriteriaCollection();$criteria->addCriteria($ageRangeCriteria);$criteria->addCriteria(/** 其余条件 */);
现在我们想要创建SearchingContext
并使用来自 Doctrine ORM 的 QueryBuilder 填充它。
$context = new QueryBuilderSearchingContext($queryBuilder);$searcher = new Searcher($builders, $context);$searcher->search($criteriaCollection); // 是的,我们得到了结果!
如果当您期望可遍历对象或数组时 QueryBuilder 返回null
的可能性很小,那么您可以使用WrappedResultsSearcher
而不是普通的Searcher
类。它的行为与Searcher
完全相同,但它会返回ResultCollection
,它仅适用于数组或Traversable
,如果结果为null
您的代码仍然可以工作。其外观如下:
$searcher = new WrappedResultsSearcher(new Searcher($builders, $context));$results = $searcher->search($criteriaCollection); // ResultCollectionforeach 的实例 ($results as $result) {// 可以工作!}foreach ($results->getResults() as $result) {// 由于 ResultCollection 有 getResults() 方法,这也可以工作!}
为了对结果进行排序,您可以使用已经实施的Criteria
。您不需要从头开始实施它。请记住,您仍然需要为其实现CriteriaBuilder
(此功能仍在开发中)。 假设您想要对结果进行排序,并且需要 CriteriaBuidler 中的值p.id
来执行此操作,但您希望将其显示为pid
给最终用户。没有什么比这更简单的了!这是创建 OrderByCriteria 的方法:
$mappedFields = ['pid' => 'p.id', 'valueForUser' => 'valueForBuilder'];$criteria = new MappedOrderByAdapter(new OrderByCriteria('pid'),$mappedFields);// $criteria->getMappedOrderBy () = 'p.id'// $criteria->getOrderBy() = 'pid'
当然,您不需要使用MappedOrderByAdapter
- 您可以仅使用OrderByCriteria
,但是用户将确切地知道哪些字段正在用于排序。
分页Criteria
也已实现,您不需要执行此操作,但请记住,您仍然需要实现CriteriaBuilder
来利用它并执行实际分页(此功能正在开发中)。假设您希望允许最终用户更改页面,但不允许更改每页的项目数。您可以使用以下示例代码:
$criteria = new ImmutablePaginationAdapter( new PaginationCriteria($page = 1, $itemsPerPage = 50) );// $criteria->setItemsPerPage(250); <- 用户可以尝试更改它// $criteria->getItemsPerPage() = 50 <- 但他实际上不能这样做// $criteria->getPage() = 1
当然,如果您想允许用户更改每页的项目数,您也可以跳过ImmutablePaginationAdapter
并仅使用PaginationCriteria
。
所有的想法和拉取请求都受到欢迎和赞赏:)如果您在使用方面有任何问题,请随时提出问题,我们可以一起解决您的问题。
运行测试的命令: composer test
。
所有单元测试均使用 padric/humbug 库进行突变测试,旨在保持突变分数指标等于或接近 100%。
要运行突变测试,您需要安装 humbug 并在主目录中运行: humbug
。输出应存储在humbuglog.txt
中。
按字母顺序排列
https://github.com/chkris
https://github.com/pawelhertman
https://github.com/ustrugany
https://github.com/wojciech-olszewski
许可证:麻省理工学院
作者:克日什托夫·格佐查