Searcher

What is that?

Search query builder library

It aims to split complex searching queries

into small classes

Framework-agnostic

Database-agnostic

Agnostic as much as possible

Can I use it with framework X?

Can I use it with database Y?

Some searching contexts are 

already implemented:

If you need more - just implement it. It's really easy

Doctrine ORM

MongoDB

Elastica

Symfony's Finder

Why should I use it?

It will enforce developers

to think about

splitting complex queries

with a lot of constraints

It will help you to create

small and

easily-testable

cirteria builders

with single responsibility

You can use it to create

chain searching process

in which results of first search can be

transformed into criteria of next search

Search #1

Search #2

Each of sub-searches may use completely different database

Supported PHP versions

PHP 5.4

PHP 5.5

PHP 5.6

PHP 7.0

PHP 7.1

HHVM

Travis CI

Scrutinizer

are inspecting each pull request

SensioLabsInsights

Style CI

Full documentation is always available by ReadTheDocs.org

It is well tested with help of

PHPUnit

PHPUnit 4.8.10 by Sebastian Bergmann and contributors.

...............................................................  63 / 194 ( 32%)
............................................................... 126 / 194 ( 64%)
............................................................... 189 / 194 ( 97%)
.....

Time: 830 ms, Memory: 8.00Mb

OK (194 tests, 281 assertions)

It is well tested with help of

Humbug

Tests: 194 Line Coverage: 100.00%
Humbug is analysing source files...
Mutation Testing is commencing on 46 files...

(.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out)
.........................................................
57 mutations were generated:
      57 mutants were killed
       0 mutants were not covered by tests
       0 covered mutants were not detected
       0 fatal errors were encountered
       0 time outs were encountered

Metrics:
    Mutation Score Indicator (MSI): 100%
    Mutation Code Coverage: 100%
    Covered Code MSI: 100%

Completely Open Sourced

Following PSR-2

Following semantic versioning

Installable via composer and packagist

All pull-requests and ideas are most welcome

How does it work?

Not the best way

Parameters

Results

Big

repository

method

Searcher approach

Parameters

Results

Criteria

Criteria

Criteria

Criteria builder

Criteria builder

Criteria builder

Only applicable criteria goes to builders

Multiple criteria are already implemented

Abstract criteria builders are already implemented

Small classes

Testable

Easy to read

Easy to understand

Example Symfony config

k_gzocha_searcher:
  contexts:
    people:
      context:
        service: my_database_searching_context

      criteria:
        - { class: \AgeRangeCriteria, name: ageRange }
        - { class: \TitleCriteria, name: title }
        - { class: \GenderCriteria, name: gender }
        - { class: \AlwaysApplicableCriteria, name: onlyAlive }

      builders:
        - { class: \AgeRangeCriteriaBuilder, name: ageRange }
        - { class: \TitleCriteriaBuilder, name: title }
        - { class: \GenderCriteriaBuilder, name: gender }
        - { class: \OnlyAliveCriteriaBuilder, name: onlyAlive }

Criteria?

Object responsible to all required parameter for single "filter".

For filtering by age range you need two parameters: ageMin and ageMax

Example 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()
    {
        return null !== $this->minimalAge && null !== $this->maximalAge;
    }

    // Getters, setters, whatever
}

Criteria builder?

Service, which will accept applicable Criteria as a parameter and will use to add constraint to query builder.

Criteria builder?

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
    ) {
        return $criteria instanceof AgeRangeCriteria;
    }

    /**
    * You can skip this method if you will extend from AbstractORMCriteriaBuilder.
    */
    public function supportsSearchingContext(
        SearchingContextInterface $searchingContext
    ) {
        return $searchingContext instanceof QueryBuilderSearchingContext;
    }
}

Searching context?

Service that holds actual query builder and knows how to fetch results from it

Finder searching context

class FinderSearchingContext extends AbstractSearchingContext
{
    /**
     * @param $finder Finder
     */
    public function __construct(Finder $finder)
    {
        parent::__construct($finder);
    }

    /**
     * @return Finder
     */
    public function getQueryBuilder()
    {
        return parent::getQueryBuilder();
    }

    /**
     * @return \Iterator
     */
    public function getResults()
    {
        return $this->getQueryBuilder()->getIterator();
    }
}

Fetching results..

Collect all hydrated criteria

Collect all criteria builders

Build proper searching context

Build Searcher service with them

Pass them to Searcher

Fetching results..

$context  = new QueryBuilderSearchingContext($queryBuilder);

$builders = new CriteriaBuilderCollection([
  new AgeRangeCriteriaBuilder(), 
  // .. rest of the builders
]);

$criteria = new CriteriaCollection([
  new AgeRangeCriteria(20, 25),
  // ... rest of hydrated criteria
]);

$searcher = new Searcher($builders, $context);

// Yay, we have our results!
$results = $searcher->search($criteria);

Thanks !

Contact

Krzysztof Gzocha