Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Searcher core

License

NotificationsYou must be signed in to change notification settings

krzysztof-gzocha/searcher

Repository files navigation

SearcherBuild StatusScrutinizer Code QualityCode CoveragePackagistSensioLabsInsight

What is that?

Searcher is a framework-agnostic search query builder. Search queries are written using criterias and can be run against MySQL, MongoDB, ElasticSearch, files or whatever else you like.Latest version is supporting only PHP 7.Now tested also withHumbug

Seethis presentation to understand better

Why?

Have you ever seen code responsible for searching for something based on many different criteria? It can become quite a mess!Imagine you have a form with 20 fields and all of them have some impact on searching conditions.It's not a great idea to pass a whole form to some service at let it parse everything in one place.Thanks to this library you can split the responsibility of building query criteria to several smaller classes. One class per filter. OneCriteriaBuilder perCriteria.This way, insideCriteriaBuilder you care only about oneCriteria, which makes it a lot more readable and maintanable.You can later use exactly the sameCriteria for different searches, with differentCriteriaBuilder and even differentSearchingContext which can use even different databases.You can even use searcher to findfiles on your system thanks toFinderSearchingContext.

Full documentation

Full documentation can be found athttp://searcher.rtfd.io/

Installation

You can install the library via composer by typing in terminal:

$ composer require krzysztof-gzocha/searcher

Integration

Integration with Symfony is done inSearcherBundle

Idea

  • CriteriaBuilder - will build newconditions for singleCriteria,
  • Criteria - model that will be passed toCriteriaBuilder. You just need to hydrate it somehow, so it will be useful. Criteria can hold multiple fields inside and all (or some) of them might be used insideCriteriaBuilder,
  • SearchingContext - context of single search. This service should know how to fetch results from constructed query and it holds something calledQueryBuilder, but it can be anything that works for you - any service. This is an abstraction layer between search and database. There are different contexts for Doctrine's ORM, ODM, Elastica,Files and so on. If there is no context for you you can implement one - it's shouldn't be hard,
  • Searcher - holds collection ofCriteriaBuilder and will passCriteria to appropriateCriteriaBuilder.

Example

Let's say we want to search forpeople whoseage is in some filtered range.In this example we will use Doctrine's QueryBuilder, so we will useQueryBuilderSearchingContext and will specify in ourCriteriaBuidler that it should interact only withDoctrine\ORM\QueryBuilder, but remember that we donot have to use only Doctrine.

1. Criteria

First of all we would need to createAgeRangeCriteria - the class that will holds values of minimal and maximal age. There are already implemented defaultCriteria inhere.

class AgeRangeCriteriaimplements CriteriaInterface{private$minimalAge;private$maximalAge;/**    * Only required method.    * If will return true, then it will be passed to some of the CriteriaBuilder(s)    */publicfunctionshouldBeApplied():bool    {returnnull !==$this->minimalAge &&null !==$this->maximalAge;    }// getters, setters, whatever}

2. CriteriaBuilder

In second step we would like to specify conditions that should be imposed for this model.That's why we would need to createAgeRangeCriteriaBuilder

class AgeRangeCriteriaBuilderimplements CriteriaBuilderInterface{publicfunctionbuildCriteria(CriteriaInterface$criteria,SearchingContextInterface$searchingContext    ) {$searchingContext            ->getQueryBuilder()            ->andWhere('e.age >= :minimalAge')            ->andWhere('e.age <= :maximalAge')            ->setParameter('minimalAge',$criteria->getMinimalAge())            ->setParameter('maximalAge',$criteria->getMaximalAge());    }publicfunctionallowsCriteria(CriteriaInterface$criteria    ):bool    {return$criteriainstanceof AgeRangeCriteria;    }/**    * You can skip this method if you will extend from AbstractORMCriteriaBuilder.    */publicfunctionsupportsSearchingContext(SearchingContextInterface$searchingContext    ):bool    {return$searchingContextinstanceof QueryBuilderSearchingContext;    }}

3. Collections

In next steps we would need to create collections for both:Criteria andCriteriaBuidler.

$builders =newCriteriaBuilderCollection();$builders->addCriteriaBuilder(newAgeRangeCriteriaBuilder());$builders->addCriteriaBuilder(/** rest of builders */);
$ageRangeCriteria =newAgeRangeCriteria();// We have to populate the model before searching$ageRangeCriteria->setMinimalAge(23);$ageRangeCriteria->setMaximalAge(29);$criteria =newCriteriaCollection();$criteria->addCriteria($ageRangeCriteria);$criteria->addCriteria(/** rest of criteria */);

4. SearchingContext

Now we would like to create ourSearchingContext and populate it with QueryBuilder taken from Doctrine ORM.

$context  =newQueryBuilderSearchingContext($queryBuilder);$searcher =newSearcher($builders,$context);$searcher->search($criteriaCollection);// Yay, we have our results!

If there is even small chance that your QueryBuilder will returnnull when you are expecting traversable object or array then you can useWrappedResultsSearcher instead of normalSearcher class. It will act exactly the same asSearcher, but it will returnResultCollection, which will work only with array or\Traversable and if result will be justnull your code will still work. Here is how it will looks like:

$searcher =newWrappedResultsSearcher(newSearcher($builders,$context));$results =$searcher->search($criteriaCollection);// instance of ResultCollectionforeach ($resultsas$result) {// will work!}foreach ($results->getResults()as$result) {// Since ResultCollection has method getResults() this will also work!}

Order

In order to sort your results you can make use of already implementedCriteria. You don't need to implement it from scratch. Keep in mind that you still need to implement yourCriteriaBuilder for it (this feature is still under development). Let's say you want to order your results and you need valuep.id in your CriteriaBuidler to do it, but you would like to show it aspid to end-user. Nothing simpler!This is how you can create OrderByCriteria:

$mappedFields = ['pid' =>'p.id','valueForUser' =>'valueForBuilder'];$criteria =newMappedOrderByAdapter(newOrderByCriteria('pid'),$mappedFields);// $criteria->getMappedOrderBy() = 'p.id'// $criteria->getOrderBy() = 'pid'

Of course you don't need to useMappedOrderByAdapter - you can use justOrderByCriteria, but then user will know exactly what fields are beeing used to sort.

Pagination

Criteria for pagination is also implemented and you don't need to do it, but keep in mind that you still need to implementCriteriaBuilder that will make use of it and do actual pagination (this feature is under development).Let's say you want to allow your end-user to change pages, but not number of items per page.You can use this example code:

$criteria =newImmutablePaginationAdapter(newPaginationCriteria($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

Of course if you want to allow user to change number of items per page also you can skip theImmutablePaginationAdapter and use justPaginationCriteria.

Contributing

All ideas and pull requests are welcomed and appreciated :)If you have any problem with usage don't hesitate to create an issue, we can figure your problem out together.

Development

Command to run test:composer test.
All unit tests are tested withpadric/humbug library for mutation testing,aiming to keepMutation Score Indicator equal or close to 100%.

To run mutation tests you need to install humbug and run:humbug in main directory.Output should be stored inhumbuglog.txt.

Thanks to

In alphabetical order

License

License: MIT
Author: Krzysztof Gzocha


[8]ページ先頭

©2009-2025 Movatter.jp