Searcher — это конструктор поисковых запросов, не зависящий от платформы. Поисковые запросы пишутся с использованием критериев и могут выполняться с MySQL, MongoDB, ElasticSearch, файлами или чем-то еще, что вам нравится. Последняя версия поддерживает только PHP 7 . Теперь протестировано также с Humbug
Вы когда-нибудь видели код, отвечающий за поиск чего-либо по множеству различных критериев? Это может стать настоящим беспорядком! Представьте, что у вас есть форма с 20 полями, и все они каким-то образом влияют на условия поиска. Не лучшая идея передавать всю форму какому-либо сервису, чтобы он анализировал все в одном месте. Благодаря этой библиотеке вы можете разделить ответственность за создание критериев запроса на несколько более мелких классов. Один класс на фильтр. Один CriteriaBuilder
на каждый Criteria
. Таким образом, внутри CriteriaBuilder
вас интересует только один Criteria
, что делает его намного более читабельным и удобным в обслуживании. Позже вы сможете использовать одни и те же Criteria
для разных поисков, с разными CriteriaBuilder
и даже с разными SearchingContext
, которые могут использовать даже разные базы данных. Вы даже можете использовать поисковик для поиска файлов в вашей системе благодаря FinderSearchingContext
.
Полную документацию можно найти по адресу http://searcher.rtfd.io/.
Вы можете установить библиотеку через композитор, набрав в терминале:
$ композитор требует krzysztof-gzocha/searcher
Интеграция с Symfony осуществляется в SearcherBundle.
CriteriaBuilder
— создаст новые условия для отдельных Criteria
,
Criteria
— модель, которая будет передана в CriteriaBuilder
. Просто надо его как-то увлажнить, вот и пригодится. Критерии могут содержать внутри себя несколько полей, и все (или некоторые) из них могут использоваться внутри CriteriaBuilder
.
SearchingContext
— контекст одиночного поиска. Этот сервис должен знать, как получать результаты из созданного запроса, и он содержит что-то под названием QueryBuilder
, но это может быть что угодно, что вам подходит — любой сервис. Это уровень абстракции между поиском и базой данных. Существуют разные контексты для ORM, ODM, Elastica, Files и т. д. Doctrine. Если у вас нет контекста, вы можете его реализовать — это не должно быть сложно,
Searcher
— хранит коллекцию CriteriaBuilder
и передает Criteria
соответствующему CriteriaBuilder
.
Допустим, мы хотим найти людей , чей возраст находится в некотором отфильтрованном диапазоне. В этом примере мы будем использовать QueryBuilder Doctrine, поэтому мы будем использовать QueryBuilderSearchingContext
и укажем в нашем CriteriaBuidler
, что он должен взаимодействовать только с DoctrineORMQueryBuilder
, но помните, что нам не обязательно использовать только Doctrine.
Прежде всего нам нужно будет создать AgeRangeCriteria
— класс, который будет хранить значения минимального и максимального возраста. Здесь уже реализованы Criteria
по умолчанию.
класс AgeRangeCriteria реализует CriteriaInterface{private $minimalAge;private $maximalAge;/** * Только обязательный метод. * Если вернет true, то оно будет передано некоторым CriteriaBuilder(ам) */public function mustBeApplied(): bool{return null !== $this->minimalAge && null !== $this->maximalAge; }// геттеры, сеттеры, что угодно}
На втором этапе мы хотели бы указать условия, которые следует наложить на эту модель. Вот почему нам нужно будет создать 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()); } Публичная функция позволяетCriteria (CriteriaInterface $criteria): bool {return $criteria экземпляр AgeRangeCriteria; }/** * Вы можете пропустить этот метод, если будете наследовать от AbstractORMCriteriaBuilder. */public функция supportSearchingContext(SearchingContextInterface $searchingContext): bool{return $searchingContext экземпляр 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
и заполнить его QueryBuilder, взятым из Doctrine ORM.
$context = новый QueryBuilderSearchingContext($queryBuilder);$searcher = новый Searcher($builders, $context);$searcher->search($criteriaCollection); // Ура, у нас есть результаты!
Если есть хотя бы небольшая вероятность того, что ваш QueryBuilder вернет null
, когда вы ожидаете проходимый объект или массив, вы можете использовать WrappedResultsSearcher
вместо обычного класса Searcher
. Он будет действовать точно так же, как Searcher
, но вернет ResultCollection
, который будет работать только с массивом или Traversable
, и если результат будет null
, ваш код все равно будет работать. Вот как это будет выглядеть:
$searcher = новый WrappedResultsSearcher(новый Searcher($builders, $context));$results = $searcher->search($criteriaCollection); // экземпляр ResultCollectionforeach ($results as $result) {// будет работать!}foreach ($results->getResults() as $result) {// Поскольку ResultCollection имеет метод getResults(), это тоже будет работать!}
Чтобы отсортировать результаты, вы можете использовать уже реализованные Criteria
. Вам не нужно реализовывать его с нуля. Имейте в виду, что для этого вам все еще необходимо реализовать CriteriaBuilder
(эта функция все еще находится в стадии разработки). Допустим, вы хотите упорядочить результаты, и для этого вам нужно значение p.id
в CriteriaBuidler, но вы хотели бы показать его как 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 = новый ImmutablePaginationAdapter(новый 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
Лицензия: Массачусетский технологический институт
Автор: Кшиштоф Гзоха