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 http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 8 * @license https://www.gnu.org/licenses/lgpl-2.1.html GNU Lesser General Public License, Version 2.1 9 * 10 * Licensed to Elasticsearch B.V under one or more agreements. 11 * Elasticsearch B.V licenses this file to you under the Apache 2.0 License or 12 * the GNU Lesser General Public License, Version 2.1, at your option. 13 * See the LICENSE file in the project root for more information. 14 */ 15 16 17declare(strict_types = 1); 18 19namespace Elasticsearch\Helper\Iterators; 20 21use Elasticsearch\Client; 22use Iterator; 23 24class SearchResponseIterator implements Iterator 25{ 26 27 /** 28 * @var Client 29 */ 30 private $client; 31 32 /** 33 * @var array 34 */ 35 private $params; 36 37 /** 38 * @var int 39 */ 40 private $current_key = 0; 41 42 /** 43 * @var array 44 */ 45 private $current_scrolled_response; 46 47 /** 48 * @var string 49 */ 50 private $scroll_id; 51 52 /** 53 * @var string duration 54 */ 55 private $scroll_ttl; 56 57 /** 58 * Constructor 59 * 60 * @param Client $client 61 * @param array $search_params Associative array of parameters 62 * @see Client::search() 63 */ 64 public function __construct(Client $client, array $search_params) 65 { 66 $this->client = $client; 67 $this->params = $search_params; 68 69 if (isset($search_params['scroll'])) { 70 $this->scroll_ttl = $search_params['scroll']; 71 } 72 } 73 74 /** 75 * Destructor 76 */ 77 public function __destruct() 78 { 79 $this->clearScroll(); 80 } 81 82 /** 83 * Sets the time to live duration of a scroll window 84 * 85 * @param string $time_to_live 86 * @return $this 87 */ 88 public function setScrollTimeout(string $time_to_live): SearchResponseIterator 89 { 90 $this->scroll_ttl = $time_to_live; 91 return $this; 92 } 93 94 /** 95 * Clears the current scroll window if there is a scroll_id stored 96 * 97 * @return void 98 */ 99 private function clearScroll(): void 100 { 101 if (!empty($this->scroll_id)) { 102 $this->client->clearScroll( 103 [ 104 'body' => [ 105 'scroll_id' => $this->scroll_id 106 ], 107 'client' => [ 108 'ignore' => 404 109 ] 110 ] 111 ); 112 $this->scroll_id = null; 113 } 114 } 115 116 /** 117 * Rewinds the iterator by performing the initial search. 118 * 119 * @return void 120 * @see Iterator::rewind() 121 */ 122 public function rewind(): void 123 { 124 $this->clearScroll(); 125 $this->current_key = 0; 126 $this->current_scrolled_response = $this->client->search($this->params); 127 $this->scroll_id = $this->current_scrolled_response['_scroll_id']; 128 } 129 130 /** 131 * Fetches every "page" after the first one using the lastest "scroll_id" 132 * 133 * @return void 134 * @see Iterator::next() 135 */ 136 public function next(): void 137 { 138 $this->current_scrolled_response = $this->client->scroll( 139 [ 140 'body' => [ 141 'scroll_id' => $this->scroll_id, 142 'scroll' => $this->scroll_ttl 143 ] 144 ] 145 ); 146 $this->scroll_id = $this->current_scrolled_response['_scroll_id']; 147 $this->current_key++; 148 } 149 150 /** 151 * Returns a boolean value indicating if the current page is valid or not 152 * 153 * @return bool 154 * @see Iterator::valid() 155 */ 156 public function valid(): bool 157 { 158 return isset($this->current_scrolled_response['hits']['hits'][0]); 159 } 160 161 /** 162 * Returns the current "page" 163 * 164 * @return array 165 * @see Iterator::current() 166 */ 167 public function current(): array 168 { 169 return $this->current_scrolled_response; 170 } 171 172 /** 173 * Returns the current "page number" of the current "page" 174 * 175 * @return int 176 * @see Iterator::key() 177 */ 178 public function key(): int 179 { 180 return $this->current_key; 181 } 182} 183