Searcher es un generador de consultas de búsqueda independiente del marco. Las consultas de búsqueda se escriben utilizando criterios y se pueden ejecutar en MySQL, MongoDB, ElasticSearch, archivos o cualquier otra cosa que desee. La última versión solo admite PHP 7 . Ahora probado también con Humbug
¿Alguna vez has visto un código responsable de buscar algo basándose en muchos criterios diferentes? ¡Puede convertirse en un gran desastre! Imagine que tiene un formulario con 20 campos y todos ellos tienen algún impacto en las condiciones de búsqueda. No es una buena idea pasar un formulario completo a algún servicio y dejar que analice todo en un solo lugar. Gracias a esta biblioteca, puede dividir la responsabilidad de crear criterios de consulta en varias clases más pequeñas. Una clase por filtro. Un CriteriaBuilder
por Criteria
. De esta manera, dentro de CriteriaBuilder
solo te preocupas por un Criteria
, lo que lo hace mucho más legible y fácil de mantener. Luego puede usar exactamente los mismos Criteria
para diferentes búsquedas, con diferentes CriteriaBuilder
e incluso diferentes SearchingContext
que pueden usar incluso diferentes bases de datos. Incluso puedes utilizar el buscador para buscar archivos en tu sistema gracias a FinderSearchingContext
.
La documentación completa se puede encontrar en http://searcher.rtfd.io/
Puede instalar la biblioteca a través del compositor escribiendo en la terminal:
$ compositor requiere krzysztof-gzocha/buscador
La integración con Symfony se realiza en SearcherBundle
CriteriaBuilder
: creará nuevas condiciones para Criteria
únicos,
Criteria
: modelo que se pasará a CriteriaBuilder
. Sólo necesitas hidratarlo de alguna manera, así te será útil. Los criterios pueden contener múltiples campos dentro y todos (o algunos) de ellos pueden usarse dentro de CriteriaBuilder
.
SearchingContext
: contexto de búsqueda única. Este servicio debe saber cómo obtener resultados de una consulta construida y contiene algo llamado QueryBuilder
, pero puede ser cualquier cosa que funcione para usted: cualquier servicio. Esta es una capa de abstracción entre la búsqueda y la base de datos. Hay diferentes contextos para ORM, ODM, Elastica, Files de Doctrine, etc. Si no hay un contexto para usted, puede implementar uno; no debería ser difícil.
Searcher
: retiene la colección de CriteriaBuilder
y pasará Criteria
al CriteriaBuilder
apropiado.
Digamos que queremos buscar personas cuya edad se encuentre en algún rango filtrado. En este ejemplo usaremos QueryBuilder de Doctrine, por lo que usaremos QueryBuilderSearchingContext
y especificaremos en nuestro CriteriaBuidler
que debe interactuar solo con DoctrineORMQueryBuilder
, pero recuerda que no tenemos que usar solo Doctrine.
En primer lugar, necesitaríamos crear AgeRangeCriteria
, la clase que contendrá los valores de edad mínima y máxima. Aquí ya se han implementado Criteria
predeterminados.
class AgeRangeCriteria implementa CriteriaInterface{private $minimalAge;private $maximalAge;/** * Solo método requerido. * Si devuelve verdadero, entonces se pasará a algunos de los CriteriaBuilder(s) */función pública deberíaBeApplied(): bool{return null !== $this->minimalAge && null !== $this->maximalAge; }// captadores, definidores, lo que sea}
En un segundo paso nos gustaría especificar las condiciones que deberían imponerse para este modelo. Es por eso que necesitaríamos crear AgeRangeCriteriaBuilder
clase AgeRangeCriteriaBuilder implementa CriteriaBuilderInterface{función pública buildCriteria(CriteriaInterface $criterios,SearchingContextInterface $searchingContext) {$searchingContext->getQueryBuilder() ->andWhere('e.age >= :edad mínima') ->andWhere('e.age <=:maximalEge') ->setParameter('edadminimal', $criterios->getEdadMinimal()) ->setParameter('edadmaximal', $criterios->getMaximalAge()); }la función pública permiteCriteria(CriteriaInterface $criteria): bool{return $criteria instancia de AgeRangeCriteria; }/** * Puede omitir este método si va a extender desde AbstractORMCriteriaBuilder. */la función pública admiteSearchingContext(SearchingContextInterface $searchingContext): bool{return $searchingContext instancia de QueryBuilderSearchingContext; } }
En los próximos pasos necesitaríamos crear colecciones para ambos: Criteria
y CriteriaBuidler
.
$builders = new CriteriaBuilderCollection();$builders->addCriteriaBuilder(new AgeRangeCriteriaBuilder());$builders->addCriteriaBuilder(/** resto de constructores */);
$ageRangeCriteria = new AgeRangeCriteria();// Tenemos que completar el modelo antes de buscar$ageRangeCriteria->setMinimalAge(23);$ageRangeCriteria->setMaximalAge(29);$criteria = new CriteriaCollection();$criteria->addCriteria( $ageRangeCriteria);$criteria->addCriteria(/** resto de criterios */);
Ahora nos gustaría crear nuestro SearchingContext
y completarlo con QueryBuilder tomado de Doctrine ORM.
$contexto = nuevo QueryBuilderSearchingContext($queryBuilder);$buscador = nuevo Buscador($constructores, $contexto);$buscador->búsqueda($criteriaCollection); // ¡Sí, tenemos nuestros resultados!
Si existe una pequeña posibilidad de que su QueryBuilder devuelva null
cuando espera un objeto o matriz transitable, puede usar WrappedResultsSearcher
en lugar de la clase Searcher
normal. Actuará exactamente igual que Searcher
, pero devolverá ResultCollection
, que funcionará solo con una matriz o Traversable
y, si el resultado es simplemente null
su código seguirá funcionando. Así es como se verá:
$buscador = nuevo WrappedResultsSearcher(nuevo buscador($constructores, $contexto));$resultados = $buscador->búsqueda($criteriaCollection); // instancia de ResultCollectionforeach ($results as $result) {// ¡funcionará!}foreach ($results->getResults() as $result) {// Dado que ResultCollection tiene el método getResults(), ¡esto también funcionará!}
Para ordenar sus resultados puede utilizar Criteria
ya implementados. No es necesario implementarlo desde cero. Tenga en cuenta que aún necesita implementar su CriteriaBuilder
(esta característica aún está en desarrollo). Digamos que desea ordenar sus resultados y necesita el valor p.id
en su CriteriaBuidler para hacerlo, pero le gustaría mostrarlo como pid
al usuario final. ¡Nada más sencillo! Así es como puedes crear OrderByCriteria:
$mappedFields = ['pid' => 'p.id', 'valueForUser' => 'valueForBuilder'];$criteria = new MappedOrderByAdapter(new OrderByCriteria('pid'),$mappedFields);// $criteria->getMappedOrderBy () = 'p.id'// $criterios->getOrderBy() = 'pid'
Por supuesto, no es necesario utilizar MappedOrderByAdapter
; puede utilizar solo OrderByCriteria
, pero entonces el usuario sabrá exactamente qué campos se utilizan para ordenar.
Criteria
para la paginación también están implementados y no es necesario hacerlo, pero tenga en cuenta que aún necesita implementar CriteriaBuilder
que lo utilizará y realizará la paginación real (esta característica está en desarrollo). Supongamos que desea permitir que su usuario final cambie las páginas, pero no el número de elementos por página. Puedes usar este código de ejemplo:
$criterios = nuevo ImmutablePaginationAdapter( nuevos criterios de paginación($página = 1, $itemsPerPage = 50) );// $criterios->setItemsPerPage(250); <- el usuario puede intentar cambiarlo// $criteria->getItemsPerPage() = 50 <- pero en realidad no puede hacerlo// $criteria->getPage() = 1
Por supuesto, si desea permitir que el usuario cambie la cantidad de elementos por página, también puede omitir ImmutablePaginationAdapter
y usar solo PaginationCriteria
.
Todas las ideas y solicitudes de extracción son bienvenidas y apreciadas :) Si tiene algún problema con el uso, no dude en crear un problema, podemos resolverlo juntos.
Comando para ejecutar la prueba: composer test
.
Todas las pruebas unitarias se prueban con la biblioteca padric/humbug para pruebas de mutación, con el objetivo de mantener el indicador de puntuación de mutación igual o cerca del 100%.
Para ejecutar pruebas de mutación necesita instalar humbug y ejecutar: humbug
en el directorio principal. La salida debe almacenarse en humbuglog.txt
.
En orden alfabético
https://github.com/chkris
https://github.com/pawelhertman
https://github.com/usrugany
https://github.com/wojciech-olszewski
Licencia: MIT
Autor: Krzysztof Gzocha