krzysztof-gzocha / searcher
Searcher是一个与框架无关的搜索查询构建器。搜索查询使用条件编写,可以针对MySQL、MongoDB、ElasticSearch或文件运行。
Requires
- php: ^7
Requires (Dev)
- doctrine/mongodb-odm: ^1.0.0
- doctrine/orm: ^2.5.0
- phpmd/phpmd: ^2.4.3
- phpunit/phpunit: ^5
- ruflin/elastica: ^2.1.0
- symfony/finder: ^2.0.5
Suggests
- doctrine/mongodb-odm: to use with Doctrine's ODM
- doctrine/orm: to use with Doctrine's ORM
- ruflin/elastica: to use with ruflin/elastica
- symfony/finder: to use with Symfony Finder component
This package is not auto-updated.
Last update: 2024-09-14 18:31:36 UTC
README
Searcher

这是什么?
Searcher是一个与框架无关的搜索查询构建器。搜索查询使用条件编写,可以针对MySQL、MongoDB、ElasticSearch、文件或其他任何你喜欢的东西运行。最新版本仅支持PHP 7。现在也测试了Humbug
查看这个演示以更好地理解
为什么?
你是否曾见过基于许多不同条件的代码负责搜索某个东西?这可能会变得相当混乱!想象一下,你有一个包含20个字段的形式,所有这些字段都对搜索条件有影响。将整个表单传递给某个服务并在一个地方解析所有内容并不是一个好主意。感谢这个库,你可以将构建查询条件的责任分割到几个更小的类中。一个类对应一个过滤器。一个CriteriaBuilder
对应一个Criteria
。这样,在CriteriaBuilder
中,你只关心一个Criteria
,这使得它更加易于阅读和维护。你可以稍后使用完全相同的Criteria
进行不同的搜索,使用不同的CriteriaBuilder
和甚至不同的SearchingContext
,这些上下文可以使用不同的数据库。你甚至可以使用searcher通过FinderSearchingContext
在系统上查找文件
。
完整文档
完整文档可在http://searcher.rtfd.io/找到
安装
您可以通过在终端中输入以下命令通过composer安装库
$ composer require krzysztof-gzocha/searcher
集成
在SearcherBundle中完成与Symfony的集成
想法
CriteriaBuilder
- 将为单个Criteria
构建新的 条件,Criteria
- 传递给CriteriaBuilder
的模型。您只需以某种方式对其进行填充,使其变得有用。条件可以包含多个字段,并且所有(或某些)字段都可能在CriteriaBuilder
中使用,SearchingContext
- 单次搜索的上下文。该服务应知道如何从构建的查询中检索结果,并持有名为QueryBuilder
的东西,但它可以是任何对您有用的服务 - 任何服务。这是搜索和数据库之间的抽象层。Doctrine 的 ORM、ODM、Elastica、文件 等都有不同的上下文。如果您没有上下文,您可以实现一个 - 这不会很难。Searcher
- 持有CriteriaBuilder
集合,并将Criteria
传递给适当的CriteriaBuilder
。
示例
假设我们想要搜索年龄在某个过滤范围内的 人。在这个例子中,我们将使用 Doctrine 的 QueryBuilder,所以我们将使用 QueryBuilderSearchingContext
,并在我们的 CriteriaBuidler
中指定它应仅与 Doctrine\ORM\QueryBuilder
交互,但请记住,我们不必只使用 Doctrine。
1. 条件
首先,我们需要创建 AgeRangeCriteria
- 该类将保存最小和最大年龄的值。默认的 Criteria
已经在这里实现了。
class AgeRangeCriteria implements CriteriaInterface { private $minimalAge; private $maximalAge; /** * Only required method. * If will return true, then it will be passed to some of the CriteriaBuilder(s) */ public function shouldBeApplied(): bool { return null !== $this->minimalAge && null !== $this->maximalAge; } // getters, setters, whatever }
2. 条件构建器
在第二步中,我们希望指定对该模型应施加的条件。这就是为什么我们需要创建 AgeRangeCriteriaBuilder
class AgeRangeCriteriaBuilder implements 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()); } public function allowsCriteria( CriteriaInterface $criteria ): bool { return $criteria instanceof AgeRangeCriteria; } /** * You can skip this method if you will extend from AbstractORMCriteriaBuilder. */ public function supportsSearchingContext( SearchingContextInterface $searchingContext ): bool { return $searchingContext instanceof QueryBuilderSearchingContext; } }
3. 集合
在接下来的步骤中,我们需要为 Criteria
和 CriteriaBuidler
创建集合。
$builders = new CriteriaBuilderCollection(); $builders->addCriteriaBuilder(new AgeRangeCriteriaBuilder()); $builders->addCriteriaBuilder(/** rest of builders */);
$ageRangeCriteria = new AgeRangeCriteria(); // We have to populate the model before searching $ageRangeCriteria->setMinimalAge(23); $ageRangeCriteria->setMaximalAge(29); $criteria = new CriteriaCollection(); $criteria->addCriteria($ageRangeCriteria); $criteria->addCriteria(/** rest of criteria */);
4. 搜索上下文
现在,我们想要创建我们的 SearchingContext
,并用从 Doctrine ORM 中获取的 QueryBuilder 来填充它。
$context = new QueryBuilderSearchingContext($queryBuilder); $searcher = new Searcher($builders, $context); $searcher->search($criteriaCollection); // Yay, we have our results!
如果您在期望可遍历对象或数组时,QueryBuilder 返回 null
的可能性很小,那么您可以使用 WrappedResultsSearcher
而不是正常的 Searcher
类。它将像 Searcher
一样工作,但它将返回 ResultCollection
,它仅适用于数组或 \Traversable
,如果结果只是 null
,则您的代码仍然可以工作。下面是这样做的示例
$searcher = new WrappedResultsSearcher(new Searcher($builders, $context)); $results = $searcher->search($criteriaCollection); // instance of ResultCollection foreach ($results as $result) { // will work! } foreach ($results->getResults() as $result) { // Since ResultCollection has method getResults() this will also work! }
排序
为了对结果进行排序,您可以使用已经实现的 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); <- user can try to change it // $criteria->getItemsPerPage() = 50 <- but he can't actualy do it // $criteria->getPage() = 1
当然,如果允许用户更改每页的项目数,您也可以跳过 ImmutablePaginationAdapter
并仅使用 PaginationCriteria
。
贡献
所有想法和 pull 请求都受到欢迎并受到赞赏 :) 如果您在使用过程中遇到任何问题,请不要犹豫,创建一个问题,我们可以一起解决这个问题。
开发
运行测试的命令: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