Skip to content

Commit d2411d4

Browse files
committed
feat(php): add iterator helper methods
1 parent f1522a3 commit d2411d4

File tree

7 files changed

+359
-1
lines changed

7 files changed

+359
-1
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Iterators;
4+
5+
use Algolia\AlgoliaSearch\Api\SearchClient;
6+
7+
abstract class AbstractAlgoliaIterator implements \Iterator
8+
{
9+
protected $indexName;
10+
11+
/**
12+
* @var SearchClient
13+
*/
14+
protected $searchClient;
15+
16+
/**
17+
* @var array RequestOptions passed when getting new batch from Algolia
18+
*/
19+
protected $requestOptions;
20+
21+
/**
22+
* @var int
23+
*/
24+
protected $key = 0;
25+
26+
/**
27+
* @var int
28+
*/
29+
protected $batchKey = 0;
30+
31+
/**
32+
* @var int
33+
*/
34+
protected $page = 0;
35+
36+
/**
37+
* @var array response from the last Algolia API call,
38+
* this contains the results for the current page
39+
*/
40+
protected $response;
41+
42+
/**
43+
* Call Algolia' API to get new result batch.
44+
*/
45+
abstract protected function fetchNextPage();
46+
47+
/**
48+
* Sometimes the Iterator is using search internally, this method
49+
* is used to clean the results, like remove the highlight.
50+
*
51+
* @return array formatted synonym array
52+
*/
53+
abstract protected function formatHit(array $hit);
54+
55+
public function __construct($indexName, SearchClient $searchClient, $requestOptions = [])
56+
{
57+
$this->indexName = $indexName;
58+
$this->searchClient = $searchClient;
59+
$this->requestOptions = $requestOptions + [
60+
'hitsPerPage' => 1000,
61+
];
62+
63+
$this->fetchNextPage();
64+
}
65+
66+
/**
67+
* Return the current element.
68+
*
69+
* @return array
70+
*/
71+
#[\ReturnTypeWillChange]
72+
public function current()
73+
{
74+
$hit = $this->response['hits'][$this->batchKey];
75+
76+
return $this->formatHit($hit);
77+
}
78+
79+
/**
80+
* Move forward to next element.
81+
*/
82+
#[\ReturnTypeWillChange]
83+
public function next()
84+
{
85+
$this->key++;
86+
$this->batchKey++;
87+
if ($this->valid()) {
88+
return;
89+
}
90+
91+
$this->fetchNextPage();
92+
}
93+
94+
/**
95+
* Return the key of the current element.
96+
*
97+
* @return int
98+
*/
99+
#[\ReturnTypeWillChange]
100+
public function key()
101+
{
102+
return $this->key;
103+
}
104+
105+
/**
106+
* Checks if current position is valid. If the current position
107+
* is not valid, we call Algolia' API to load more results
108+
* until it's the last page.
109+
*
110+
* @return bool the return value will be casted to boolean and then evaluated.
111+
* Returns true on success or false on failure
112+
*/
113+
#[\ReturnTypeWillChange]
114+
public function valid()
115+
{
116+
return isset($this->response['hits'][$this->batchKey]);
117+
}
118+
119+
/**
120+
* Rewind the Iterator to the first element.
121+
*/
122+
#[\ReturnTypeWillChange]
123+
public function rewind()
124+
{
125+
if (0 !== $this->key) {
126+
$this->key = 0;
127+
$this->batchKey = 0;
128+
$this->page = 0;
129+
$this->response = null;
130+
$this->fetchNextPage();
131+
}
132+
}
133+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Iterators;
4+
5+
final class ObjectIterator extends AbstractAlgoliaIterator
6+
{
7+
public function getCursor()
8+
{
9+
return isset($this->response['cursor']) ? $this->response['cursor'] : null;
10+
}
11+
12+
/**
13+
* Exporting objects (records) doesn't use the search function but the
14+
* browse method, no client-side formatting is required.
15+
*
16+
* @return array the exact same $hit
17+
*/
18+
protected function formatHit(array $hit)
19+
{
20+
return $hit;
21+
}
22+
23+
protected function fetchNextPage()
24+
{
25+
if (is_array($this->response) && !isset($this->response['cursor'])) {
26+
return;
27+
}
28+
29+
$cursor = [];
30+
if (isset($this->response['cursor'])) {
31+
$cursor['cursor'] = $this->response['cursor'];
32+
}
33+
34+
$this->response = $this->searchClient->browse(
35+
$this->indexName,
36+
array_merge(
37+
$this->requestOptions,
38+
$cursor
39+
)
40+
);
41+
42+
$this->batchKey = 0;
43+
}
44+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Iterators;
4+
5+
final class RuleIterator extends AbstractAlgoliaIterator
6+
{
7+
protected function formatHit(array $hit)
8+
{
9+
unset($hit['_highlightResult']);
10+
11+
return $hit;
12+
}
13+
14+
protected function fetchNextPage()
15+
{
16+
if (is_array($this->response) && $this->key >= $this->response['nbHits']) {
17+
return;
18+
}
19+
20+
$this->response = $this->searchClient->searchRules(
21+
$this->indexName,
22+
array_merge(
23+
$this->requestOptions,
24+
['page' => $this->page]
25+
)
26+
);
27+
28+
$this->batchKey = 0;
29+
$this->page++;
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Iterators;
4+
5+
final class SynonymIterator extends AbstractAlgoliaIterator
6+
{
7+
protected function formatHit(array $hit)
8+
{
9+
unset($hit['_highlightResult']);
10+
11+
return $hit;
12+
}
13+
14+
protected function fetchNextPage()
15+
{
16+
if (is_array($this->response) && $this->key >= $this->response['nbHits']) {
17+
return;
18+
}
19+
20+
$this->response = $this->searchClient->searchSynonyms(
21+
$this->indexName,
22+
null,
23+
$this->page,
24+
$this->requestOptions['hitsPerPage'],
25+
$this->requestOptions
26+
);
27+
28+
$this->batchKey = 0;
29+
$this->page++;
30+
}
31+
}

clients/algoliasearch-client-php/lib/Support/Helpers.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
use Algolia\AlgoliaSearch\Api\SearchClient;
66
use Algolia\AlgoliaSearch\Exceptions\ExceededRetriesException;
77
use Algolia\AlgoliaSearch\Exceptions\NotFoundException;
8+
use Algolia\AlgoliaSearch\Iterators\ObjectIterator;
9+
use Algolia\AlgoliaSearch\Iterators\RuleIterator;
10+
use Algolia\AlgoliaSearch\Iterators\SynonymIterator;
811

912
final class Helpers
1013
{
@@ -221,4 +224,46 @@ private static function isKeyUpdated($key, $keyParams)
221224

222225
return $upToDate;
223226
}
227+
228+
/**
229+
* Helper: Iterate on the `browse` method of the client to allow aggregating objects of an index.
230+
*
231+
* @param string $indexName Index name
232+
* @param SearchClient $searchClient Search client
233+
* @param array $requestOptions Request options
234+
*
235+
* @return ObjectIterator
236+
*/
237+
public static function browseObjects($indexName, $searchClient, $requestOptions = [])
238+
{
239+
return new ObjectIterator($indexName, $searchClient, $requestOptions);
240+
}
241+
242+
/**
243+
* Helper: Iterate on the `searchRules` method of the client to allow aggregating rules of an index.
244+
*
245+
* @param string $indexName Index name
246+
* @param SearchClient $searchClient Search client
247+
* @param array $requestOptions Request options
248+
*
249+
* @return RuleIterator
250+
*/
251+
public static function browseRules($indexName, $searchClient, $requestOptions = [])
252+
{
253+
return new RuleIterator($indexName, $searchClient, $requestOptions);
254+
}
255+
256+
/**
257+
* Helper: Iterate on the `searchSynonyms` method of the client to allow aggregating rules of an index.
258+
*
259+
* @param string $indexName Index name
260+
* @param SearchClient $searchClient Search client
261+
* @param array $requestOptions Request options
262+
*
263+
* @return SynonymIterator
264+
*/
265+
public static function browseSynonyms($indexName, $searchClient, $requestOptions = [])
266+
{
267+
return new SynonymIterator($indexName, $searchClient, $requestOptions);
268+
}
224269
}

playground/php/src/search.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
$env = require_once('../loadEnv.php');
44

55
use Algolia\AlgoliaSearch\Api\SearchClient;
6+
use Algolia\AlgoliaSearch\Support\Helpers;
67

78
$client = SearchClient::create(
89
$env['ALGOLIA_APPLICATION_ID'],
@@ -27,3 +28,39 @@
2728
],
2829
])
2930
);
31+
32+
// browse records
33+
$results = Helpers::browseObjects(
34+
$indexName,
35+
$client,
36+
);
37+
38+
$objects = [];
39+
foreach ($results as $object) {
40+
$objects[] = $object;
41+
}
42+
var_dump($objects);
43+
44+
// browse synonyms
45+
$results = Helpers::browseSynonyms(
46+
$indexName,
47+
$client,
48+
);
49+
50+
$synonyms = [];
51+
foreach ($results as $synonym) {
52+
$synonyms[] = $synonym;
53+
}
54+
var_dump($synonyms);
55+
56+
// browse rules
57+
$results = Helpers::browseRules(
58+
$indexName,
59+
$client,
60+
);
61+
62+
$rules = [];
63+
foreach ($results as $rule) {
64+
$rules[] = $rule;
65+
}
66+
var_dump($rules);

website/docs/clients/migration-guides/index.mdx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,44 @@ console.log(synonyms, synonyms.length);
479479
<TabItem value="php">
480480

481481
```php
482-
// WIP
482+
483+
use Algolia\AlgoliaSearch\Support\Helpers;
484+
485+
// browse records
486+
$results = Helpers::browseObjects(
487+
$indexName,
488+
$client,
489+
);
490+
491+
$objects = [];
492+
foreach ($results as $object) {
493+
$objects[] = $object;
494+
}
495+
var_dump($objects);
496+
497+
// browse synonyms
498+
$results = Helpers::browseSynonyms(
499+
$indexName,
500+
$client,
501+
);
502+
503+
$synonyms = [];
504+
foreach ($results as $synonym) {
505+
$synonyms[] = $synonym;
506+
}
507+
var_dump($synonyms);
508+
509+
// browse rules
510+
$results = Helpers::browseRules(
511+
$indexName,
512+
$client,
513+
);
514+
515+
$rules = [];
516+
foreach ($results as $rule) {
517+
$rules[] = $rule;
518+
}
519+
var_dump($rules);
483520

484521
```
485522

0 commit comments

Comments
 (0)