Skip to content

Commit

Permalink
Merge #134
Browse files Browse the repository at this point in the history
134: Improve the $options parameter in search() method r=curquiza a=curquiza

- rename `toJson` into `toJSON`: same naming as Stripe and Twilio
- add `rawSearch()` method
- `transformHits` callback can take any callback to completely transform the hits
- Add `transformFacetsDistribution` option in `search()` method (type: callback)
- Add `removeZeroFacets` option in `search()` method (type: boolean)
- Add `transformHits()`, `transformFacetsDistribution()` and `removeZeroFacets()` methods.

### Usage

```php
$searchResult = $index->search('prince');
$searchResult->removeZeroFacets()

// OR

$searchResult = $index->search('prince', [], ['removeZeroFacets' => true]);
```

```php
$keepAmericanSniperFunc = function (array $hits) {
    return array_filter(
        $hits,
        function (array $hit) { return 'American Sniper' === $hit['title']; }
    );
};

$searchResult = $index->search('american');
$searchResult->transformHits($keepAmericanSniperFunc)

// OR

$response = $this->index->search('prince', [], $options = ['transformHits' => $keepAmericanSniperFunc]);
```


Co-authored-by: Clémentine Urquizar <clementine@meilisearch.com>
  • Loading branch information
bors[bot] and curquiza authored Jan 21, 2021
2 parents c9b9a84 + a610784 commit a15b868
Show file tree
Hide file tree
Showing 6 changed files with 524 additions and 165 deletions.
9 changes: 8 additions & 1 deletion .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ delete_one_document_1: |-
delete_documents_1: |-
$client->index('movies')->deleteDocuments([23488, 153738, 437035, 363869]);
search_1: |-
$client->index('movies')->search('american ninja');
// Do a search
$searchResults = $client->index('movies')->search('american ninja');
// Get results in an Array using a getter
$hits = $searchResults->getHits();
// Get the decoded response of MeiliSearch, see response below
$response = $searchResults->getRaw();
get_update_1: |-
$client->index('movies')->getUpdateStatus(1);
get_all_updates_1: |-
Expand Down
36 changes: 12 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,44 +110,41 @@ With the `updateId`, you can check the status (`enqueued`, `processed` or `faile

```php
// MeiliSearch is typo-tolerant:
print_r($index->search('harry pottre'));
$hits = $index->search('harry pottre')->getHits();
print_r($hits);
```

Output:

```php
Array
(
[hits] => Array
[0] => Array
(
[0] => Array
(
[id] => 4
[title] => Harry Potter and the Half-Blood Prince
)

[id] => 4
[title] => Harry Potter and the Half-Blood Prince
)

[offset] => 0
[limit] => 20
[processingTimeMs] => 1
[query] => harry pottre
)
```

#### Custom Search <!-- omit in toc -->

All the supported options are described in the [search parameters](https://docs.meilisearch.com/guides/advanced_guides/search_parameters.html) section of the documentation.

💡 **More about the `search()` method in [the Wiki](https://github.com/meilisearch/meilisearch-php/wiki/Search).**

```php
$index->search('prince',
$index->search(
'prince',
[
'attributesToHighlight' => ['*'],
'filters' => 'book_id > 10'
]
);
)->getRaw(); // Return in Array format
```

JSON output:

```json
{
"hits": [
Expand All @@ -163,15 +160,6 @@ $index->search('prince',
}
```

With `filters`, both single and double quotes are supported.
```php
// Enclosing with double quotes
$index->search('prince', ['filters' => "title = 'Le Petit Prince' OR author = 'J. R. R. Tolkien'"]);

// Enclosing with single quotes
$index->search('hobbit', ['filters' => 'title = "The Hitchhiker\'s Guide to the Galaxy" OR author = "J. R. R. Tolkien"']);
```

## 🤖 Compatibility with MeiliSearch

This package only guarantees the compatibility with the [version v0.18.1 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.18.1).
Expand Down
27 changes: 17 additions & 10 deletions src/Endpoints/Indexes.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,26 +145,33 @@ public function waitForPendingUpdate($updateId, $timeoutInMs = 5000, $intervalIn
*/
public function search($query, array $searchParams = [], array $options = [])
{
$parameters = array_merge(
['q' => $query],
$searchParams
);

$result = $this->http->post(self::PATH.'/'.$this->uid.'/search', $parameters);
$result = $this->rawSearch($query, $searchParams);

if (\array_key_exists('raw', $options) && $options['raw']) {
return $result;
}

$searchResult = new SearchResult($result);

if (\array_key_exists('transformHits', $options) && \is_callable($options['transformHits'])) {
$searchResult = $searchResult->filter($options['transformHits']);
}
$searchResult->applyOptions($options);

return $searchResult;
}

/**
* @param string $query
*
* @return array
*/
public function rawSearch($query, array $searchParams = [])
{
$parameters = array_merge(
['q' => $query],
$searchParams
);

return $this->http->post(self::PATH.'/'.$this->uid.'/search', $parameters);
}

// Stats

public function stats(): array
Expand Down
84 changes: 67 additions & 17 deletions src/Search/SearchResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,19 @@ class SearchResult implements Countable, IteratorAggregate
private $limit;

/**
* `nbHits` is the attributes returned by the MeiliSearch server
* and its value will not be modified by the methods in this class.
* Please, use `hitsCount` if you want to know the real size of the `hits` array at any time.
*
* @var int
*/
private $nbHits;

/**
* @var int
*/
private $hitsCount;

/**
* @var bool
*/
Expand Down Expand Up @@ -67,6 +76,7 @@ public function __construct(array $body)
$this->offset = $body['offset'];
$this->limit = $body['limit'];
$this->nbHits = $body['nbHits'];
$this->hitsCount = \count($body['hits']);
$this->exhaustiveNbHits = $body['exhaustiveNbHits'] ?? false;
$this->processingTimeMs = $body['processingTimeMs'];
$this->query = $body['query'];
Expand All @@ -76,24 +86,64 @@ public function __construct(array $body)
}

/**
* Return a new {@see SearchResult} instance with the hits filtered using `array_filter($this->hits, $callback, ARRAY_FILTER_USE_BOTH)`.
* Return a new {@see SearchResult} instance.
*
* The $callback receives both the current hit and the key, in that order.
* The $options parameter is an array, and the following keys are accepted:
* - removeZeroFacets (boolean)
* - transformFacetsDistribution (callable)
* - transformHits (callable)
*
* The method DOES not trigger a new search.
* The method does NOT trigger a new search.
*
* @return SearchResult
*/
public function filter(callable $callback): self
public function applyOptions($options): self
{
if (\array_key_exists('removeZeroFacets', $options) && true === $options['removeZeroFacets']) {
$this->removeZeroFacets();
}
if (\array_key_exists('transformHits', $options) && \is_callable($options['transformHits'])) {
$this->transformHits($options['transformHits']);
}
if (\array_key_exists('transformFacetsDistribution', $options) && \is_callable($options['transformFacetsDistribution'])) {
$this->transformFacetsDistribution($options['transformFacetsDistribution']);
}

return $this;
}

public function transformHits(callable $callback): self
{
$results = array_filter($this->hits, $callback, ARRAY_FILTER_USE_BOTH);
$this->hits = $callback($this->hits);
$this->hitsCount = \count($this->hits);

$this->hits = $results;
$this->nbHits = \count($results);
return $this;
}

public function transformFacetsDistribution(callable $callback): self
{
$this->facetsDistribution = $callback($this->facetsDistribution);

return $this;
}

public function removeZeroFacets(): self
{
$filterAllFacets = function (array $facets) {
$filterOneFacet = function (array $facet) {
return array_filter(
$facet,
function ($v, $k) { return 0 !== $v; },
ARRAY_FILTER_USE_BOTH
);
};

return array_map($filterOneFacet, $facets);
};

return $this->transformFacetsDistribution($filterAllFacets);
}

public function getHit(int $key, $default = null)
{
return $this->hits[$key] ?? $default;
Expand All @@ -119,12 +169,17 @@ public function getLimit(): int

public function getHitsCount(): int
{
return $this->nbHits;
return $this->hitsCount;
}

public function count(): int
{
return $this->hitsCount;
}

public function getNbHits(): int
{
return \count($this->hits);
return $this->nbHits;
}

public function getExhaustiveNbHits(): bool
Expand Down Expand Up @@ -160,7 +215,7 @@ public function getFacetsDistribution(): array
*
* @return array<string, mixed>
*/
public function fetchRawInfo(): array
public function getRaw(): array
{
return $this->raw;
}
Expand All @@ -172,7 +227,7 @@ public function toArray(): array
'offset' => $this->offset,
'limit' => $this->limit,
'nbHits' => $this->nbHits,
'hitsCount' => \count($this->hits),
'hitsCount' => $this->hitsCount,
'exhaustiveNbHits' => $this->exhaustiveNbHits,
'processingTimeMs' => $this->processingTimeMs,
'query' => $this->query,
Expand All @@ -181,7 +236,7 @@ public function toArray(): array
];
}

public function toJson(): string
public function toJSON(): string
{
return \json_encode($this->toArray(), JSON_PRETTY_PRINT);
}
Expand All @@ -190,9 +245,4 @@ public function getIterator(): ArrayIterator
{
return new ArrayIterator($this->hits);
}

public function count(): int
{
return \count($this->hits);
}
}
Loading

0 comments on commit a15b868

Please sign in to comment.