Files
predis/lib/Predis/Iterator/Scan/AbstractScanIterator.php
T
2013-11-04 16:53:56 +01:00

184 lines
4.1 KiB
PHP

<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Iterator\Scan;
use Iterator;
use Countable;
use Predis\ClientInterface;
use Predis\NotSupportedException;
/**
* This class provides the base implementation for a fully-rewindable
* PHP iterator that can incrementally iterate over collections stored
* on Redis by leveraging the SCAN family of commands (Redis >= 2.8).
*
* @author Daniele Alessandri <suppakilla@gmail.com>
* @link http://redis.io/commands/scan
*/
abstract class AbstractScanIterator implements Iterator
{
protected $client;
protected $match;
protected $count;
protected $valid;
protected $scanmore;
protected $elements;
protected $cursor;
protected $position;
protected $current;
/**
* @param ClientInterface $client Client connected to Redis.
* @param string $match Pattern to match during the server-side iteration.
* @param int $count Hints used by Redis to compute the number of results per iteration.
*/
public function __construct(ClientInterface $client, $match = null, $count = null)
{
$this->client = $client;
$this->match = $match;
$this->count = $count;
$this->reset();
}
/**
* Ensures that the client instance supports the specified
* Redis command required to perform the server-side iteration.
*
* @param ClientInterface Client connected to Redis.
* @param string $commandID Command ID (e.g. `SCAN`).
*/
protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The specified server profile does not support the `$commandID` command.");
}
}
/**
* Resets the inner state of the iterator.
*/
protected function reset()
{
$this->valid = true;
$this->scanmore = true;
$this->elements = array();
$this->cursor = 0;
$this->position = -1;
$this->current = null;
}
/**
* Returns an array of options for the SCAN command.
*
* @return array
*/
protected function getScanOptions()
{
$options = array();
if (strlen($this->match) > 0) {
$options['MATCH'] = $this->match;
}
if ($this->count > 0) {
$options['COUNT'] = $this->count;
}
return $options;
}
/**
* Performs a new SCAN to fetch new elements in the collection from
* Redis, effectively advancing the iteration process.
*
* @return array
*/
protected abstract function executeScanCommand();
/**
* Populates the local buffer of elements fetched from the server
* during the iteration.
*/
protected function feed()
{
list($cursor, $elements) = $this->executeScanCommand();
if (!$cursor) {
$this->scanmore = false;
}
$this->cursor = $cursor;
$this->elements = $elements;
}
/**
* Extracts next values for key() and current().
*/
protected function extractNext()
{
$this->position++;
$this->current = array_shift($this->elements);
}
/**
* {@inheritdoc}
*/
public function rewind()
{
$this->reset();
}
/**
* {@inheritdoc}
*/
public function current()
{
return $this->current;
}
/**
* {@inheritdoc}
*/
public function key()
{
return $this->position;
}
/**
* {@inheritdoc}
*/
public function next()
{
if (!$this->elements && $this->scanmore) {
$this->feed();
}
if ($this->elements) {
$this->extractNext();
} else if ($this->cursor) {
$this->next();
} else {
$this->valid = false;
}
}
/**
* {@inheritdoc}
*/
public function valid()
{
return $this->valid;
}
}