Ver código fonte

Extract base class for iterators based on the SCAN family of commands.

The iterators based on SCAN, SSCAN, ZSCAN and HSCAN will extend this abstract
class to share most of the logic which is common for all of the Redis commands
in the SCAN family.
Daniele Alessandri 11 anos atrás
pai
commit
d09d8edc7d

+ 182 - 0
lib/Predis/Iterator/Scan/AbstractScanIterator.php

@@ -0,0 +1,182 @@
+<?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();
+        $this->next();
+    }
+
+    /**
+     * {@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 {
+            $this->valid = false;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function valid()
+    {
+        return $this->valid;
+    }
+}

+ 5 - 126
lib/Predis/Iterator/Scan/KeyspaceIterator.php

@@ -11,9 +11,7 @@
 
 namespace Predis\Iterator\Scan;
 
-use Iterator;
 use Predis\ClientInterface;
-use Predis\NotSupportedException;
 
 /**
  * Abstracts the iteration of the keyspace on a Redis instance
@@ -23,142 +21,23 @@ use Predis\NotSupportedException;
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @link http://redis.io/commands/scan
  */
-class KeyspaceIterator implements Iterator
+class KeyspaceIterator extends AbstractScanIterator
 {
-    protected $client;
-    protected $match;
-    protected $count;
-
-    protected $valid;
-    protected $scanmore;
-    protected $elements;
-    protected $position;
-    protected $cursor;
-
     /**
-     * @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.
+     * {@inheritdoc}
      */
     public function __construct(ClientInterface $client, $match = null, $count = null)
     {
-        if (!$client->getProfile()->supportsCommand('SCAN')) {
-            throw new NotSupportedException('The specified server profile does not support the SCAN command.');
-        }
-
-        $this->client = $client;
-        $this->match = $match;
-        $this->count = $count;
-
-        $this->reset();
-    }
-
-    /**
-     * Resets the inner state of the iterator.
-     */
-    protected function reset()
-    {
-        $this->valid = true;
-        $this->scanmore = true;
-        $this->elements = array();
-        $this->position = -1;
-        $this->cursor = 0;
-    }
-
-    /**
-     * 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;
-        }
+        $this->requiredCommand($client, 'SCAN');
 
-        if ($this->count > 0) {
-            $options['COUNT'] = $this->count;
-        }
-
-        return $options;
+        parent::__construct($client, $match, $count);
     }
 
     /**
-     * Performs a new SCAN to fetch new elements in the collection from
-     * Redis, effectively advancing the iteration process.
-     *
-     * @return array
+     * {@inheritdoc}
      */
     protected function executeScanCommand()
     {
         return $this->client->scan($this->cursor, $this->getScanOptions());
     }
-
-    /**
-     * 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;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function rewind()
-    {
-        $this->reset();
-        $this->next();
-    }
-
-    /**
-     * {@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->position++;
-            $this->current = array_shift($this->elements);
-        } else {
-            $this->valid = false;
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function valid()
-    {
-        return $this->valid;
-    }
 }