Skip to content

feat(php): add iterator helper methods #936

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

namespace Algolia\AlgoliaSearch\Iterators;

use Algolia\AlgoliaSearch\Api\SearchClient;

abstract class AbstractAlgoliaIterator implements \Iterator
{
protected $indexName;

/**
* @var SearchClient
*/
protected $searchClient;

/**
* @var array RequestOptions passed when getting new batch from Algolia
*/
protected $requestOptions;

/**
* @var int
*/
protected $key = 0;

/**
* @var int
*/
protected $batchKey = 0;

/**
* @var int
*/
protected $page = 0;

/**
* @var array response from the last Algolia API call,
* this contains the results for the current page
*/
protected $response;

/**
* Call Algolia' API to get new result batch.
*/
abstract protected function fetchNextPage();

/**
* Sometimes the Iterator is using search internally, this method
* is used to clean the results, like remove the highlight.
*
* @return array formatted synonym array
*/
abstract protected function formatHit(array $hit);

public function __construct(
$indexName,
SearchClient $searchClient,
$requestOptions = []
) {
$this->indexName = $indexName;
$this->searchClient = $searchClient;
$this->requestOptions = $requestOptions + [
'hitsPerPage' => 1000,
];

$this->fetchNextPage();
}

/**
* Return the current element.
*
* @return array
*/
#[\ReturnTypeWillChange]
public function current()
{
$hit = $this->response['hits'][$this->batchKey];

return $this->formatHit($hit);
}

/**
* Move forward to next element.
*/
#[\ReturnTypeWillChange]
public function next()
{
$this->key++;
$this->batchKey++;
if ($this->valid()) {
return;
}

$this->fetchNextPage();
}

/**
* Return the key of the current element.
*
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->key;
}

/**
* Checks if current position is valid. If the current position
* is not valid, we call Algolia' API to load more results
* until it's the last page.
*
* @return bool the return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure
*/
#[\ReturnTypeWillChange]
public function valid()
{
return isset($this->response['hits'][$this->batchKey]);
}

/**
* Rewind the Iterator to the first element.
*/
#[\ReturnTypeWillChange]
public function rewind()
{
if (0 !== $this->key) {
$this->key = 0;
$this->batchKey = 0;
$this->page = 0;
$this->response = null;
$this->fetchNextPage();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Algolia\AlgoliaSearch\Iterators;

final class ObjectIterator extends AbstractAlgoliaIterator
{
public function getCursor()
{
return isset($this->response['cursor'])
? $this->response['cursor']
: null;
}

/**
* Exporting objects (records) doesn't use the search function but the
* browse method, no client-side formatting is required.
*
* @return array the exact same $hit
*/
protected function formatHit(array $hit)
{
return $hit;
}

protected function fetchNextPage()
{
if (is_array($this->response) && !isset($this->response['cursor'])) {
return;
}

$cursor = [];
if (isset($this->response['cursor'])) {
$cursor['cursor'] = $this->response['cursor'];
}

$this->response = $this->searchClient->browse(
$this->indexName,
array_merge($this->requestOptions, $cursor)
);

$this->batchKey = 0;
}
}
31 changes: 31 additions & 0 deletions clients/algoliasearch-client-php/lib/Iterators/RuleIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Algolia\AlgoliaSearch\Iterators;

final class RuleIterator extends AbstractAlgoliaIterator
{
protected function formatHit(array $hit)
{
unset($hit['_highlightResult']);

return $hit;
}

protected function fetchNextPage()
{
if (
is_array($this->response) &&
$this->key >= $this->response['nbHits']
) {
return;
}

$this->response = $this->searchClient->searchRules(
$this->indexName,
array_merge($this->requestOptions, ['page' => $this->page])
);

$this->batchKey = 0;
$this->page++;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Algolia\AlgoliaSearch\Iterators;

final class SynonymIterator extends AbstractAlgoliaIterator
{
protected function formatHit(array $hit)
{
unset($hit['_highlightResult']);

return $hit;
}

protected function fetchNextPage()
{
if (
is_array($this->response) &&
$this->key >= $this->response['nbHits']
) {
return;
}

$this->response = $this->searchClient->searchSynonyms(
$this->indexName,
null,
$this->page,
$this->requestOptions['hitsPerPage'],
$this->requestOptions
);

$this->batchKey = 0;
$this->page++;
}
}
27 changes: 27 additions & 0 deletions playground/php/src/search.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,30 @@
],
])
);

// browse records
$results = $client->browseObjects($indexName);

$objects = [];
foreach ($results as $object) {
$objects[] = $object;
}
var_dump($objects);

// browse synonyms
$results = $client->browseSynonyms($indexName);

$synonyms = [];
foreach ($results as $synonym) {
$synonyms[] = $synonym;
}
var_dump($synonyms);

// browse rules
$results = $client->browseRules($indexName);

$rules = [];
foreach ($results as $rule) {
$rules[] = $rule;
}
var_dump($rules);
42 changes: 42 additions & 0 deletions templates/php/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ use {{invokerPackage}}\Algolia;
use {{invokerPackage}}\ApiException;
use {{invokerPackage}}\Configuration\{{configClassname}};
use {{invokerPackage}}\Exceptions\ExceededRetriesException;
use {{invokerPackage}}\Iterators\ObjectIterator;
use {{invokerPackage}}\Iterators\RuleIterator;
use {{invokerPackage}}\Iterators\SynonymIterator;
use {{invokerPackage}}\ObjectSerializer;
use {{invokerPackage}}\RetryStrategy\ApiWrapper;
use {{invokerPackage}}\RetryStrategy\ApiWrapperInterface;
Expand Down Expand Up @@ -363,6 +366,45 @@ use {{invokerPackage}}\Support\Helpers;
$requestOptions
);
}

/**
* Helper: Iterate on the `browse` method of the client to allow aggregating objects of an index.
*
* @param string $indexName Index name
* @param array $requestOptions Request options
*
* @return ObjectIterator
*/
public function browseObjects($indexName, $requestOptions = [])
{
return new ObjectIterator($indexName, $this, $requestOptions);
}

/**
* Helper: Iterate on the `searchRules` method of the client to allow aggregating rules of an index.
*
* @param string $indexName Index name
* @param array $requestOptions Request options
*
* @return RuleIterator
*/
public function browseRules($indexName, $requestOptions = [])
{
return new RuleIterator($indexName, $this, $requestOptions);
}

/**
* Helper: Iterate on the `searchSynonyms` method of the client to allow aggregating synonyms of an index.
*
* @param string $indexName Index name
* @param array $requestOptions Request options
*
* @return SynonymIterator
*/
public function browseSynonyms($indexName, $requestOptions = [])
{
return new SynonymIterator($indexName, $this, $requestOptions);
}
{{/isSearchClient}}

private function sendRequest($method, $resourcePath, $headers, $queryParameters, $httpBody, $requestOptions, $useReadTransporter = false)
Expand Down
28 changes: 27 additions & 1 deletion website/docs/clients/migration-guides/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,33 @@ console.log(synonyms, synonyms.length);
<TabItem value="php">

```php
// WIP

// browse records
$results = $client->browseObjects($indexName);

$objects = [];
foreach ($results as $object) {
$objects[] = $object;
}
var_dump($objects);

// browse synonyms
$results = $client->browseSynonyms($indexName);

$synonyms = [];
foreach ($results as $synonym) {
$synonyms[] = $synonym;
}
var_dump($synonyms);

// browse rules
$results = $client->browseRules($indexName);

$rules = [];
foreach ($results as $rule) {
$rules[] = $rule;
}
var_dump($rules);

```

Expand Down