Criteria builder¶
Idea¶
In searcher library CriteriaBuilder
class is used to actually build a part of
the searching query for some abstract database. To do so it requires a specific Criteria
and some abstract query builder.
Query criteria builders can work with multiple other SearchingContext
,
which can work with multiple libraries and databases like:
- Doctrine ORM for MySQL, MariaDB, Postgres
- Doctrine ODM for MongoDB
- ruflin/elastica for ElasticSearch
- and anything else that will came to your mind - even files
Only classes that are implementing \KGzocha\Searcher\CriteriaBuilder\CriteriaBuilderInterface
can be used
as a criteria builders. This means that builders need to implement 3 methods:
buildCriteria()
which will setup the conditions onSearchingContext
with values taken fromCriteria
,allowsCriteria()
which determines if this builders can handle specificCriteria
,supportsSearchingContext()
which obviously determines if this builder can be used with this specificSearchingContext
.
Doctrine example¶
Describing Criteria
we’ve used example of searching for people, lets create a builder for this example using Doctrine’s ORM.
In order to do it we will need to create a builder which allows our SpecificAgeCriteria and
will support Doctrine’s searching context which is \KGzocha\Searcher\Context\Doctrine\QueryBuilderSearchingContext
.
use \KGzocha\Searcher\CriteriaBuilder\Doctrine\AbstractORMCriteriaBuilder;
use \KGzocha\Searcher\Criteria\CriteriaInterface;
use \KGzocha\Searcher\Context\Doctrine\QueryBuilderSearchingContext;
use \KGzocha\Searcher\Context\SearchingContextInterface;
class SpecificAgeCriteriaBuilder extends AbstractORMCriteriaBuilder
{
public function allowsCriteria(CriteriaInterface $criteria): bool
{
return $criteria instanceof SpecificAgeCriteria;
}
/**
* @param SpecificAgeCriteria $criteria
* @param QueryBuilderSearchingContext $searchingContext
*/
public function buildCriteria(
CriteriaInterface $criteria,
SearchingContextInterface $searchingContext
) {
$searchingContext
->getQueryBuilder()
->andWhere('p.age = :age') // use andWhere, not where
->setParameter(
'age',
$criteria->getAge()
);
}
}
That’s it! You can see new classes are used in here like AbstractORMCriteriaBuilder
or QueryBuilderSearchingContext
,
but don’t worry those are very simple classes which are already implemented and should only help you to start using this library.
AbstractORMCriteriaBuilder
- abstract CriteriaBuilder class which will allow onlyQueryBuilderSearchingContext
to be used (You can see there is nosupportSearchingContext
method).QueryBuilderSearchingContext
- searching context which will work only with Doctrine’s ORM QueryBuilder
Whats the most important for us are the methods allowsCriteria()
and of course buildCriteria()
.
In allowsCriteria()
we have to just specify that we want only care about SpecificAgeCriteria.
The actual building of the query is taking place on buildCriteria()
. What is going on there?
- We are fetching Doctrine’s QueryBuilder by
$searchingContext->getQueryBuilder()
, - we are adding and condition and setting parameter,
- we are specifying value of this parameter with value taken from
Criteria
.
The most important part in here is to use andWhere instead of where, why?
Because there might be another CriteriaBuilder
before and using where would might have overwrite it’s logic.
It’s really important for you to always think about single CriteriaBuilder
as a part of complete query.
You should always work only on your part - you don’t want to mess up logic from different CriteriaBuilder
.
Troubleshooting¶
You might experience problems when trying to declare the same join in two separate criteria builders. In such scenarios you have to try to not perform second join if it’s already there.
Too long, didn’t read¶
What do you need to know about CriteriaBuilder:
- It can be any class implementing
CriteriaBuilderInterface
- Build query using SearchingContext’s QueryBuilder and values from Criteria
- You should be careful with constructing queries and not overwrite logic from different builder
- Always think about it like a single part from a massive and complex query