Skip to content

Commit 68dfe7c

Browse files
committed
Merge branch 'main' into 8.8
2 parents 32580dc + bd99d31 commit 68dfe7c

File tree

11 files changed

+855
-5
lines changed

11 files changed

+855
-5
lines changed

.ci/test-matrix.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
STACK_VERSION:
3-
- 8.8-SNAPSHOT
3+
- 8.9-SNAPSHOT
44

55
PHP_VERSION:
66
- 8.2-cli

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
matrix:
1212
php-version: [7.4, 8.0, 8.1, 8.2]
1313
os: [ubuntu-latest]
14-
es-version: [8.8-SNAPSHOT]
14+
es-version: [8.9-SNAPSHOT]
1515

1616
steps:
1717
- name: Checkout

.github/workflows/unified-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
strategy:
2121
fail-fast: false
2222
matrix:
23-
stack_version: ['8.8.0-SNAPSHOT']
23+
stack_version: ['8.9.0-SNAPSHOT']
2424

2525
steps:
2626
- name: Checkout

src/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
final class Client implements ClientInterface
2929
{
3030
const CLIENT_NAME = 'es';
31-
const VERSION = '8.8.0';
31+
const VERSION = '8.9.0';
3232
const API_COMPATIBILITY_HEADER = '%s/vnd.elasticsearch+%s; compatible-with=8';
3333

3434
use ClientEndpointsTrait;
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<?php
2+
/**
3+
* Elasticsearch PHP Client
4+
*
5+
* @link https://github.com/elastic/elasticsearch-php
6+
* @copyright Copyright (c) Elasticsearch B.V (https://www.elastic.co)
7+
* @license https://opensource.org/licenses/MIT MIT License
8+
*
9+
* Licensed to Elasticsearch B.V under one or more agreements.
10+
* Elasticsearch B.V licenses this file to you under the MIT License.
11+
* See the LICENSE file in the project root for more information.
12+
*/
13+
declare(strict_types = 1);
14+
15+
namespace Elastic\Elasticsearch\Helper\Iterators;
16+
17+
use Countable;
18+
use Elastic\Elasticsearch\Exception\ClientResponseException;
19+
use Elastic\Elasticsearch\Exception\ServerResponseException;
20+
use Iterator;
21+
22+
class SearchHitIterator implements Iterator, Countable
23+
{
24+
25+
/**
26+
* @var SearchResponseIterator
27+
*/
28+
private SearchResponseIterator $searchResponses;
29+
30+
/**
31+
* @var int
32+
*/
33+
protected int $currentKey;
34+
35+
/**
36+
* @var int
37+
*/
38+
protected int $currentHitIndex;
39+
40+
/**
41+
* @var array|null
42+
*/
43+
protected ?array $currentHitData;
44+
45+
/**
46+
* @var int
47+
*/
48+
protected int $count = 0;
49+
50+
/**
51+
* Constructor
52+
*
53+
* @param SearchResponseIterator $searchResponses
54+
*/
55+
public function __construct(SearchResponseIterator $searchResponses)
56+
{
57+
$this->searchResponses = $searchResponses;
58+
}
59+
60+
/**
61+
* Rewinds the internal SearchResponseIterator and itself
62+
*
63+
* @return void
64+
* @throws ClientResponseException
65+
* @throws ServerResponseException
66+
* @see Iterator::rewind()
67+
*/
68+
public function rewind(): void
69+
{
70+
$this->currentKey = 0;
71+
$this->searchResponses->rewind();
72+
73+
// The first page may be empty. In that case, the next page is fetched.
74+
$currentPage = $this->searchResponses->current();
75+
if ($this->searchResponses->valid() && empty($currentPage['hits']['hits'])) {
76+
$this->searchResponses->next();
77+
}
78+
79+
$this->count = 0;
80+
if (isset($currentPage['hits']['total']['value'], $currentPage['hits']['total'])) {
81+
$this->count = $currentPage['hits']['total']['value'] ?? $currentPage['hits']['total'];
82+
}
83+
84+
$this->readPageData();
85+
}
86+
87+
/**
88+
* Advances pointer of the current hit to the next one in the current page. If there
89+
* isn't a next hit in the current page, then it advances the current page and moves the
90+
* pointer to the first hit in the page.
91+
*
92+
* @return void
93+
* @throws ClientResponseException
94+
* @throws ServerResponseException
95+
* @see Iterator::next()
96+
*/
97+
public function next(): void
98+
{
99+
$this->currentKey++;
100+
$this->currentHitIndex++;
101+
$currentPage = $this->searchResponses->current();
102+
if (isset($currentPage['hits']['hits'][$this->currentHitIndex])) {
103+
$this->currentHitData = $currentPage['hits']['hits'][$this->currentHitIndex];
104+
} else {
105+
$this->searchResponses->next();
106+
$this->readPageData();
107+
}
108+
}
109+
110+
/**
111+
* Returns a boolean indicating whether or not the current pointer has valid data
112+
*
113+
* @return bool
114+
* @see Iterator::valid()
115+
*/
116+
public function valid(): bool
117+
{
118+
return is_array($this->currentHitData);
119+
}
120+
121+
/**
122+
* Returns the current hit
123+
*
124+
* @return array
125+
* @see Iterator::current()
126+
*/
127+
public function current(): array
128+
{
129+
return $this->currentHitData;
130+
}
131+
132+
/**
133+
* Returns the current hit index. The hit index spans all pages.
134+
*
135+
* @return int
136+
* @see Iterator::key()
137+
*/
138+
public function key(): int
139+
{
140+
return $this->currentKey;
141+
}
142+
143+
/**
144+
* Advances the internal SearchResponseIterator and resets the currentHitIndex to 0
145+
*
146+
* @internal
147+
*/
148+
private function readPageData(): void
149+
{
150+
if ($this->searchResponses->valid()) {
151+
$currentPage = $this->searchResponses->current();
152+
$this->currentHitIndex = 0;
153+
$this->currentHitData = $currentPage['hits']['hits'][$this->currentHitIndex];
154+
} else {
155+
$this->currentHitData = null;
156+
}
157+
}
158+
159+
/**
160+
* {@inheritDoc}
161+
*/
162+
public function count(): int
163+
{
164+
return $this->count;
165+
}
166+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
<?php
2+
/**
3+
* Elasticsearch PHP Client
4+
*
5+
* @link https://github.com/elastic/elasticsearch-php
6+
* @copyright Copyright (c) Elasticsearch B.V (https://www.elastic.co)
7+
* @license https://opensource.org/licenses/MIT MIT License
8+
*
9+
* Licensed to Elasticsearch B.V under one or more agreements.
10+
* Elasticsearch B.V licenses this file to you under the MIT License.
11+
* See the LICENSE file in the project root for more information.
12+
*/
13+
declare(strict_types = 1);
14+
15+
namespace Elastic\Elasticsearch\Helper\Iterators;
16+
17+
use Elastic\Elasticsearch\ClientInterface;
18+
use Elastic\Elasticsearch\Exception\ClientResponseException;
19+
use Elastic\Elasticsearch\Exception\ServerResponseException;
20+
use Iterator;
21+
22+
class SearchResponseIterator implements Iterator
23+
{
24+
25+
/**
26+
* @var ClientInterface
27+
*/
28+
private ClientInterface $client;
29+
30+
/**
31+
* @var array
32+
*/
33+
private array $params;
34+
35+
/**
36+
* @var int
37+
*/
38+
private int $currentKey = 0;
39+
40+
/**
41+
* @var array
42+
*/
43+
private array $currentScrolledResponse;
44+
45+
/**
46+
* @var string|null
47+
*/
48+
private ?string $scrollId;
49+
50+
/**
51+
* @var string duration
52+
*/
53+
private $scrollTtl;
54+
55+
/**
56+
* Constructor
57+
*
58+
* @param ClientInterface $client
59+
* @param array $searchParams Associative array of parameters
60+
* @see ClientInterface::search()
61+
*/
62+
public function __construct(ClientInterface $client, array $searchParams)
63+
{
64+
$this->client = $client;
65+
$this->params = $searchParams;
66+
67+
if (isset($searchParams['scroll'])) {
68+
$this->scrollTtl = $searchParams['scroll'];
69+
}
70+
}
71+
72+
/**
73+
* Destructor
74+
*
75+
* @throws ClientResponseException
76+
* @throws ServerResponseException
77+
*/
78+
public function __destruct()
79+
{
80+
$this->clearScroll();
81+
}
82+
83+
/**
84+
* Sets the time to live duration of a scroll window
85+
*
86+
* @param string $timeToLive
87+
* @return $this
88+
*/
89+
public function setScrollTimeout(string $timeToLive): SearchResponseIterator
90+
{
91+
$this->scrollTtl = $timeToLive;
92+
return $this;
93+
}
94+
95+
/**
96+
* Clears the current scroll window if there is a scroll_id stored
97+
*
98+
* @return void
99+
* @throws ClientResponseException
100+
* @throws ServerResponseException
101+
*/
102+
private function clearScroll(): void
103+
{
104+
if (!empty($this->scrollId)) {
105+
/* @phpstan-ignore-next-line */
106+
$this->client->clearScroll(
107+
[
108+
'body' => [
109+
'scroll_id' => $this->scrollId
110+
],
111+
'client' => [
112+
'ignore' => 404
113+
]
114+
]
115+
);
116+
$this->scrollId = null;
117+
}
118+
}
119+
120+
/**
121+
* Rewinds the iterator by performing the initial search.
122+
*
123+
* @return void
124+
* @throws ClientResponseException
125+
* @throws ServerResponseException
126+
* @see Iterator::rewind()
127+
*/
128+
public function rewind(): void
129+
{
130+
$this->clearScroll();
131+
$this->currentKey = 0;
132+
/* @phpstan-ignore-next-line */
133+
$this->currentScrolledResponse = $this->client->search($this->params)->asArray();
134+
$this->scrollId = $this->currentScrolledResponse['_scroll_id'];
135+
}
136+
137+
/**
138+
* Fetches every "page" after the first one using the lastest "scroll_id"
139+
*
140+
* @return void
141+
* @throws ClientResponseException
142+
* @throws ServerResponseException
143+
* @see Iterator::next()
144+
*/
145+
public function next(): void
146+
{
147+
/* @phpstan-ignore-next-line */
148+
$this->currentScrolledResponse = $this->client->scroll(
149+
[
150+
'body' => [
151+
'scroll_id' => $this->scrollId,
152+
'scroll' => $this->scrollTtl
153+
]
154+
]
155+
)->asArray();
156+
$this->scrollId = $this->currentScrolledResponse['_scroll_id'];
157+
$this->currentKey++;
158+
}
159+
160+
/**
161+
* Returns a boolean value indicating if the current page is valid or not
162+
*
163+
* @return bool
164+
* @see Iterator::valid()
165+
*/
166+
public function valid(): bool
167+
{
168+
return isset($this->currentScrolledResponse['hits']['hits'][0]);
169+
}
170+
171+
/**
172+
* Returns the current "page"
173+
*
174+
* @return array
175+
* @see Iterator::current()
176+
*/
177+
public function current(): array
178+
{
179+
return $this->currentScrolledResponse;
180+
}
181+
182+
/**
183+
* Returns the current "page number" of the current "page"
184+
*
185+
* @return int
186+
* @see Iterator::key()
187+
*/
188+
public function key(): int
189+
{
190+
return $this->currentKey;
191+
}
192+
}

0 commit comments

Comments
 (0)