All Projects → krzysztof-gzocha → Searcher

krzysztof-gzocha / Searcher

Licence: mit
Searcher core

Projects that are alternatives of or similar to Searcher

Lyrics.ovh
Source of lyrics.ovh and API to search for lyrics of a song
Stars: ✭ 112 (-7.44%)
Mutual labels:  search
Googleimageshell
Google image search extension for Windows Explorer.
Stars: ✭ 116 (-4.13%)
Mutual labels:  search
Dfi
Peer-to-peer torrent indexing
Stars: ✭ 118 (-2.48%)
Mutual labels:  search
Searchable
Search/filter functionality for Laravel's Eloquent models
Stars: ✭ 113 (-6.61%)
Mutual labels:  search
Hypertag
Knowledge Management for Humans using Machine Learning & Tags
Stars: ✭ 116 (-4.13%)
Mutual labels:  search
Instant Username Search
⚡ Instantly search for the availability of your username on more than 100 social media sites.
Stars: ✭ 118 (-2.48%)
Mutual labels:  search
Baiduspider
BaiduSpider,一个爬取百度搜索结果的爬虫,目前支持百度网页搜索,百度图片搜索,百度知道搜索,百度视频搜索,百度资讯搜索,百度文库搜索,百度经验搜索和百度百科搜索。
Stars: ✭ 105 (-13.22%)
Mutual labels:  search
Ext Solr
A TYPO3 extension that integrates the Apache Solr search server with TYPO3 CMS. dkd Internet Service GmbH is developing the extension. Community contributions are welcome. See CONTRIBUTING.md for details.
Stars: ✭ 118 (-2.48%)
Mutual labels:  search
Evernote Alfred
使用 Alfred 快速搜索印象笔记中的内容
Stars: ✭ 116 (-4.13%)
Mutual labels:  search
Regular
🔍The convenient paste of regular expression🔎
Stars: ✭ 118 (-2.48%)
Mutual labels:  search
Alfred Learn Anything
Alfred workflow to search Learn Anything
Stars: ✭ 115 (-4.96%)
Mutual labels:  search
Mapboxgeocoder.swift
Address search and reverse geocoding in Swift or Objective-C on iOS, macOS, tvOS, and watchOS
Stars: ✭ 115 (-4.96%)
Mutual labels:  search
Haystack
🔍 Haystack is an open source NLP framework that leverages Transformer models. It enables developers to implement production-ready neural search, question answering, semantic document search and summarization for a wide range of applications.
Stars: ✭ 3,409 (+2717.36%)
Mutual labels:  search
Faltu
Search sort, filter, limit an array of objects in Mongo-style.
Stars: ✭ 112 (-7.44%)
Mutual labels:  search
Distancepicker
Custom UIKit control to select a distance with a pan gesture, written in Swift
Stars: ✭ 118 (-2.48%)
Mutual labels:  search
Jobfunnel
Scrape job websites into a single spreadsheet with no duplicates.
Stars: ✭ 1,528 (+1162.81%)
Mutual labels:  search
Sqlkit
SQL builder and powerful database toolkit for Golang
Stars: ✭ 117 (-3.31%)
Mutual labels:  query-builder
Elassandra
Elassandra = Elasticsearch + Apache Cassandra
Stars: ✭ 1,610 (+1230.58%)
Mutual labels:  search
Jstarcraft Example
基于JStarCraft RNS引擎,Spring Boot框架和公共数据集搭建的千人千面演示项目. 系统会根据用户的行为记录,自动调整用户的推荐内容和搜索内容.使用者可以通过该项目了解*推荐系统*与*搜索系统*的运作流程. 涵盖了个性化推荐与个性化搜索2个部分.
Stars: ✭ 119 (-1.65%)
Mutual labels:  search
Searchobjectgraphql
GraphQL plugin for SearchObject gem
Stars: ✭ 118 (-2.48%)
Mutual labels:  search

Searcher Build Status Scrutinizer Code Quality Code Coverage Packagist SensioLabsInsight

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 with Humbug

See this 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. One CriteriaBuilder per Criteria. This way, inside CriteriaBuilder you care only about one Criteria, which makes it a lot more readable and maintanable. You can later use exactly the same Criteria for different searches, with different CriteriaBuilder and even different SearchingContext which can use even different databases. You can even use searcher to find files on your system thanks to FinderSearchingContext.

Full documentation

Full documentation can be found at http://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 in SearcherBundle

Idea

  • CriteriaBuilder - will build new conditions for single Criteria,
  • Criteria - model that will be passed to CriteriaBuilder. 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 inside CriteriaBuilder,
  • SearchingContext - context of single search. This service should know how to fetch results from constructed query and it holds something called QueryBuilder, 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 of CriteriaBuilder and will pass Criteria to appropriate CriteriaBuilder.

Example

Let's say we want to search for people whose age is in some filtered range. In this example we will use Doctrine's QueryBuilder, so we will use QueryBuilderSearchingContext and will specify in our CriteriaBuidler that it should interact only with Doctrine\ORM\QueryBuilder, but remember that we do not have to use only Doctrine.

1. Criteria

First of all we would need to create AgeRangeCriteria - the class that will holds values of minimal and maximal age. There are already implemented default Criteria in here.

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(): bool
    {
        return null !== $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 create AgeRangeCriteriaBuilder

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

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

3. Collections

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

$builders = new CriteriaBuilderCollection();

$builders->addCriteriaBuilder(new AgeRangeCriteriaBuilder());
$builders->addCriteriaBuilder(/** rest of builders */);
$ageRangeCriteria = new AgeRangeCriteria();

// We have to populate the model before searching
$ageRangeCriteria->setMinimalAge(23);
$ageRangeCriteria->setMaximalAge(29);

$criteria = new CriteriaCollection();
$criteria->addCriteria($ageRangeCriteria);
$criteria->addCriteria(/** rest of criteria */);

4. SearchingContext

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

$context  = new QueryBuilderSearchingContext($queryBuilder);

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

If there is even small chance that your QueryBuilder will return null when you are expecting traversable object or array then you can use WrappedResultsSearcher instead of normal Searcher class. It will act exactly the same as Searcher, but it will return ResultCollection, which will work only with array or \Traversable and if result will be just null your code will still work. Here is how it will looks like:

$searcher = new WrappedResultsSearcher(new Searcher($builders, $context));
$results = $searcher->search($criteriaCollection);  // instance of ResultCollection
foreach ($results as $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 implemented Criteria. You don't need to implement it from scratch. Keep in mind that you still need to implement your CriteriaBuilder for it (this feature is still under development). Let's say you want to order your results and you need value p.id in your CriteriaBuidler to do it, but you would like to show it as pid to end-user. Nothing simpler! This is how you can create OrderByCriteria:

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

Of course you don't need to use MappedOrderByAdapter - you can use just OrderByCriteria, 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 implement CriteriaBuilder 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 = new ImmutablePaginationAdapter(
  new PaginationCriteria($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 the ImmutablePaginationAdapter and use just PaginationCriteria.

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 with padric/humbug library for mutation testing, aiming to keep Mutation 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 in humbuglog.txt.

Thanks to

In alphabetical order

License

License: MIT
Author: Krzysztof Gzocha

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].