ezimuel/guzzlestreams
A lightweight library that adds stream and iterator utilities on top of Guzzle, making it easier to work with PHP streams, filters, and resource handling. Useful for piping, buffering, and composing stream operations in HTTP-related code.
Installation
composer require ezimuel/guzzlestreams
First Use Case: Streaming Elasticsearch Responses
use Ezimuel\GuzzleStreams\Stream;
use GuzzleHttp\Client;
$client = new Client();
$response = $client->request('GET', 'https://your-elasticsearch-endpoint/_search');
// Stream the response body
$stream = Stream::fromResource($response->getBody());
$decoder = new \Elasticsearch\Serializers\SmartSerializer();
foreach ($stream as $chunk) {
$data = $decoder->decode($chunk, 'json');
// Process each chunk of data
}
Where to Look First
Stream.php for core functionality.GuzzleHttp\Psr7\Stream is extended in the package.elasticsearch/elasticsearch for serialization/deserialization patterns.$response = $client->request('GET', 'https://your-elasticsearch-endpoint/_search', [
'query' => 'your_query',
'size' => 1000, // Batch size
]);
$stream = Stream::fromResource($response->getBody());
$decoder = new \Elasticsearch\Serializers\SmartSerializer();
foreach ($stream as $chunk) {
$batch = $decoder->decode($chunk, 'json');
processBatch($batch); // Process in chunks
}
use Ezimuel\GuzzleStreams\Stream;
$stream = Stream::fromResource($response->getBody())
->filter(function ($chunk) {
// Example: Filter out specific fields
$data = json_decode($chunk, true);
unset($data['unwanted_field']);
return json_encode($data);
});
elasticsearch/elasticsearch with streaming.$client = Elastic\Elasticsearch\ClientBuilder::create()
->setHosts(['https://your-elasticsearch-endpoint'])
->setHandlerStack(GuzzleHttp\HandlerStack::create())
->setHandler(new \GuzzleHttp\Handler\CurlHandler())
->build();
// Override default response handling
$response = $client->search([
'index' => 'your_index',
'body' => ['query' => ['match_all' => new \stdClass()]],
]);
$stream = Stream::fromResource($response->getBody());
// Process stream as shown above
$client = new Client(['timeout' => 30]);
$retries = 3;
while ($retries--) {
try {
$response = $client->request('GET', 'https://your-elasticsearch-endpoint/_search');
$stream = Stream::fromResource($response->getBody());
foreach ($stream as $chunk) {
// Process chunk
}
break; // Success
} catch (\Exception $e) {
if ($retries === 0) throw $e;
sleep(1); // Backoff
}
}
Stream::close() explicitly or rely on PHP's __destruct():
$stream = Stream::fromResource($response->getBody());
// ... processing ...
$stream->close(); // Always close when done
try-finally block:
try {
$stream = Stream::fromResource($response->getBody());
foreach ($stream as $chunk) { /* ... */ }
} finally {
$stream->close();
}
spatie/fork or symfony/stream-writer to reconstruct JSON objects:
use Spatie\Fork\Json\JsonStreamer;
$streamer = new JsonStreamer();
$streamer->on('data', function ($data) {
// Process each JSON object
});
foreach ($stream as $chunk) {
$streamer->feed($chunk);
}
guzzle/streams (abandoned) and may not support the latest Guzzle versions.composer.json:
"require": {
"guzzlehttp/guzzle": "~6.0 || ~7.0" // Check package docs for exact version
}
Psr7 compatibility:
if (!method_exists($response->getBody(), 'isSeekable')) {
throw new \RuntimeException('Incompatible Guzzle version');
}
$stream = Stream::fromResource($response->getBody());
$chunks = iterator_to_array($stream); // Consume all chunks in one thread
Ezimuel\GuzzleStreams\Stream to add logic:
class LoggingStream extends Stream {
public function read($length) {
$data = parent::read($length);
\Log::debug('Read chunk:', ['length' => $length, 'data' => $data]);
return $data;
}
}
onRead, onClose) via traits or decorators.foreach ($stream as $chunk) {
\Log::debug('Raw chunk:', ['chunk' => substr($chunk, 0, 100) . '...']);
// Process chunk
}
slices or search_after is used for pagination.timeout or use connect_timeout.elasticsearch/elasticsearch, disable default response buffering:
$client->getEngine()->getClient()->getConfig()->set('buffer_response', false);
How can I help you explore Laravel packages today?