Browse Source

Rework the API for external protocol processors.

Daniele Alessandri 11 years ago
parent
commit
16d17af577
30 changed files with 177 additions and 274 deletions
  1. 2 1
      CHANGELOG.md
  2. 0 7
      lib/Predis/Connection/ComposableConnectionInterface.php
  3. 1 13
      lib/Predis/Connection/ComposableStreamConnection.php
  4. 0 50
      lib/Predis/Protocol/ComposableProtocolInterface.php
  5. 1 2
      lib/Predis/Protocol/ProtocolException.php
  6. 8 8
      lib/Predis/Protocol/ProtocolInterface.php
  7. 2 2
      lib/Predis/Protocol/RequestSerializerInterface.php
  8. 4 4
      lib/Predis/Protocol/ResponseHandlerInterface.php
  9. 3 3
      lib/Predis/Protocol/ResponseReaderInterface.php
  10. 29 51
      lib/Predis/Protocol/Text/ComposableTextProtocol.php
  11. 7 11
      lib/Predis/Protocol/Text/ResponseBulkHandler.php
  12. 4 4
      lib/Predis/Protocol/Text/ResponseErrorHandler.php
  13. 8 12
      lib/Predis/Protocol/Text/ResponseIntegerHandler.php
  14. 8 12
      lib/Predis/Protocol/Text/ResponseMultiBulkHandler.php
  15. 11 11
      lib/Predis/Protocol/Text/ResponseMultiBulkStreamHandler.php
  16. 3 2
      lib/Predis/Protocol/Text/ResponseStatusHandler.php
  17. 13 9
      lib/Predis/Protocol/Text/TextProtocol.php
  18. 3 4
      lib/Predis/Protocol/Text/TextRequestSerializer.php
  19. 19 18
      lib/Predis/Protocol/Text/TextResponseReader.php
  20. 1 1
      tests/Predis/Connection/ComposableStreamConnectionTest.php
  21. 1 1
      tests/Predis/Iterator/MultiBulkResponseSimpleTest.php
  22. 1 1
      tests/Predis/Iterator/MultiBulkResponseTupleTest.php
  23. 39 38
      tests/Predis/Protocol/Text/ComposableTextProtocolTest.php
  24. 1 1
      tests/Predis/Protocol/Text/ResponseBulkHandlerTest.php
  25. 1 1
      tests/Predis/Protocol/Text/ResponseIntegerHandlerTest.php
  26. 1 1
      tests/Predis/Protocol/Text/ResponseMultiBulkHandlerTest.php
  27. 1 1
      tests/Predis/Protocol/Text/ResponseMultiBulkStreamHandlerTest.php
  28. 1 1
      tests/Predis/Protocol/Text/TextProtocolTest.php
  29. 3 3
      tests/Predis/Protocol/Text/TextRequestSerializerTest.php
  30. 1 1
      tests/Predis/Protocol/Text/TextResponseReaderTest.php

+ 2 - 1
CHANGELOG.md

@@ -5,7 +5,8 @@ v0.9.0 (201x-xx-xx)
 
 
 - Dropped support for streamable multibulk responses. Actually we still ship the
 - Dropped support for streamable multibulk responses. Actually we still ship the
   iterator response classes just in case anyone would want to build custom stuff
   iterator response classes just in case anyone would want to build custom stuff
-  at a level lower than the client abstraction.
+  at a level lower than the client abstraction (our standard and composable text
+  protocol processors still handle them and can be used as an example).
 
 
 - The `Predis\Option` namespace is now known as `Predis\Configuration` and have
 - The `Predis\Option` namespace is now known as `Predis\Configuration` and have
   a fully-reworked `Options` class with the ability to lazily initialize values
   a fully-reworked `Options` class with the ability to lazily initialize values

+ 0 - 7
lib/Predis/Connection/ComposableConnectionInterface.php

@@ -22,13 +22,6 @@ use Predis\Protocol\ProtocolInterface;
  */
  */
 interface ComposableConnectionInterface extends SingleConnectionInterface
 interface ComposableConnectionInterface extends SingleConnectionInterface
 {
 {
-    /**
-     * Sets the protocol processor used by the connection.
-     *
-     * @param ProtocolInterface $protocol Protocol processor.
-     */
-    public function setProtocol(ProtocolInterface $protocol);
-
     /**
     /**
      * Gets the protocol processor used by the connection.
      * Gets the protocol processor used by the connection.
      */
      */

+ 1 - 13
lib/Predis/Connection/ComposableStreamConnection.php

@@ -23,7 +23,7 @@ use Predis\Protocol\Text\TextProtocol;
  */
  */
 class ComposableStreamConnection extends StreamConnection implements ComposableConnectionInterface
 class ComposableStreamConnection extends StreamConnection implements ComposableConnectionInterface
 {
 {
-    private $protocol;
+    protected $protocol;
 
 
     /**
     /**
      * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
      * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
@@ -35,18 +35,6 @@ class ComposableStreamConnection extends StreamConnection implements ComposableC
         $this->protocol = $protocol ?: new TextProtocol();
         $this->protocol = $protocol ?: new TextProtocol();
     }
     }
 
 
-    /**
-     * {@inheritdoc}
-     */
-    public function setProtocol(ProtocolInterface $protocol)
-    {
-        if ($protocol === null) {
-            throw new \InvalidArgumentException("The protocol instance cannot be a null value");
-        }
-
-        $this->protocol = $protocol;
-    }
-
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */

+ 0 - 50
lib/Predis/Protocol/ComposableProtocolInterface.php

@@ -1,50 +0,0 @@
-<?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\Protocol;
-
-/**
- * Interface that defines a customizable protocol processor that serializes
- * Redis commands and parses replies returned by the server to PHP objects
- * using a pluggable set of classes defining the underlying wire protocol.
- *
- * @author Daniele Alessandri <suppakilla@gmail.com>
- */
-interface ComposableProtocolInterface extends ProtocolInterface
-{
-    /**
-     * Sets the command serializer to be used by the protocol processor.
-     *
-     * @param CommandSerializerInterface $serializer Command serializer.
-     */
-    public function setSerializer(CommandSerializerInterface $serializer);
-
-    /**
-     * Returns the command serializer used by the protocol processor.
-     *
-     * @return CommandSerializerInterface
-     */
-    public function getSerializer();
-
-    /**
-     * Sets the response reader to be used by the protocol processor.
-     *
-     * @param ResponseReaderInterface $reader Response reader.
-     */
-    public function setReader(ResponseReaderInterface $reader);
-
-    /**
-     * Returns the response reader used by the protocol processor.
-     *
-     * @return ResponseReaderInterface
-     */
-    public function getReader();
-}

+ 1 - 2
lib/Predis/Protocol/ProtocolException.php

@@ -14,8 +14,7 @@ namespace Predis\Protocol;
 use Predis\CommunicationException;
 use Predis\CommunicationException;
 
 
 /**
 /**
- * Exception class that identifies errors encountered while
- * handling the Redis wire protocol.
+ * Errors encountered while handling the wire protocol.
  *
  *
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */

+ 8 - 8
lib/Predis/Protocol/ProtocolInterface.php

@@ -15,15 +15,15 @@ use Predis\Command\CommandInterface;
 use Predis\Connection\ComposableConnectionInterface;
 use Predis\Connection\ComposableConnectionInterface;
 
 
 /**
 /**
- * Interface that defines a protocol processor that serializes Redis commands
- * and parses replies returned by the server to PHP objects.
+ * Defines a pluggable protocol processor capable of serializing commands and
+ * deserializing responses into PHP objects directly from a connection.
  *
  *
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
-interface ProtocolInterface extends ResponseReaderInterface
+interface ProtocolInterface
 {
 {
     /**
     /**
-     * Writes a Redis command on the specified connection.
+     * Writes a command to the specified connection.
      *
      *
      * @param ComposableConnectionInterface $connection Connection to Redis.
      * @param ComposableConnectionInterface $connection Connection to Redis.
      * @param CommandInterface $command Redis command.
      * @param CommandInterface $command Redis command.
@@ -31,10 +31,10 @@ interface ProtocolInterface extends ResponseReaderInterface
     public function write(ComposableConnectionInterface $connection, CommandInterface $command);
     public function write(ComposableConnectionInterface $connection, CommandInterface $command);
 
 
     /**
     /**
-     * Sets the options for the protocol processor.
+     * Reads a response from the specified connection and deserializes it.
      *
      *
-     * @param string $option Name of the option.
-     * @param mixed $value Value of the option.
+     * @param ComposableConnectionInterface $connection Connection to Redis.
+     * @return mixed
      */
      */
-    public function setOption($option, $value);
+    public function read(ComposableConnectionInterface $connection);
 }
 }

+ 2 - 2
lib/Predis/Protocol/CommandSerializerInterface.php → lib/Predis/Protocol/RequestSerializerInterface.php

@@ -14,11 +14,11 @@ namespace Predis\Protocol;
 use Predis\Command\CommandInterface;
 use Predis\Command\CommandInterface;
 
 
 /**
 /**
- * Interface that defines a custom serializer for Redis commands.
+ * Defines a pluggable serializer for Redis commands.
  *
  *
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
-interface CommandSerializerInterface
+interface RequestSerializerInterface
 {
 {
     /**
     /**
      * Serializes a Redis command.
      * Serializes a Redis command.

+ 4 - 4
lib/Predis/Protocol/ResponseHandlerInterface.php

@@ -14,18 +14,18 @@ namespace Predis\Protocol;
 use Predis\Connection\ComposableConnectionInterface;
 use Predis\Connection\ComposableConnectionInterface;
 
 
 /**
 /**
- * Interface that defines an handler able to parse a reply.
+ * Defines a pluggable handler used to parse a particular type of response.
  *
  *
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
 interface ResponseHandlerInterface
 interface ResponseHandlerInterface
 {
 {
     /**
     /**
-     * Parses a type of reply returned by Redis and reads more data from the
-     * connection if needed.
+     * Deserializes the response returned by Redis and reads more data from the
+     * connection when needed.
      *
      *
      * @param ComposableConnectionInterface $connection Connection to Redis.
      * @param ComposableConnectionInterface $connection Connection to Redis.
-     * @param string $payload Initial payload of the reply.
+     * @param string $payload Raw payload.
      * @return mixed
      * @return mixed
      */
      */
     function handle(ComposableConnectionInterface $connection, $payload);
     function handle(ComposableConnectionInterface $connection, $payload);

+ 3 - 3
lib/Predis/Protocol/ResponseReaderInterface.php

@@ -14,15 +14,15 @@ namespace Predis\Protocol;
 use Predis\Connection\ComposableConnectionInterface;
 use Predis\Connection\ComposableConnectionInterface;
 
 
 /**
 /**
- * Interface that defines a response reader able to parse replies returned by
- * Redis and deserialize them to PHP objects.
+ * Defines a pluggable reader capable of parsing responses returned by Redis and
+ * deserializing them to PHP objects.
  *
  *
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
 interface ResponseReaderInterface
 interface ResponseReaderInterface
 {
 {
     /**
     /**
-     * Reads replies from a connection to Redis and deserializes them.
+     * Reads responses from the connection.
      *
      *
      * @param ComposableConnectionInterface $connection Connection to Redis.
      * @param ComposableConnectionInterface $connection Connection to Redis.
      * @return mixed
      * @return mixed

+ 29 - 51
lib/Predis/Protocol/Text/ComposableTextProtocol.php

@@ -13,62 +13,32 @@ namespace Predis\Protocol\Text;
 
 
 use Predis\Command\CommandInterface;
 use Predis\Command\CommandInterface;
 use Predis\Connection\ComposableConnectionInterface;
 use Predis\Connection\ComposableConnectionInterface;
+use Predis\Protocol\RequestSerializerInterface;
+use Predis\Protocol\ProtocolInterface;
 use Predis\Protocol\ResponseReaderInterface;
 use Predis\Protocol\ResponseReaderInterface;
-use Predis\Protocol\CommandSerializerInterface;
-use Predis\Protocol\ComposableProtocolInterface;
 
 
 /**
 /**
- * Implements a customizable protocol processor that uses the standard Redis
- * wire protocol to serialize Redis commands and parse replies returned by
- * the server using a pluggable set of classes.
+ * Composable protocol processor for the standard Redis wire protocol using
+ * pluggable handlers to serialize requests and deserialize responses.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
-class ComposableTextProtocol implements ComposableProtocolInterface
+class ComposableTextProtocol implements ProtocolInterface
 {
 {
     private $serializer;
     private $serializer;
     private $reader;
     private $reader;
 
 
     /**
     /**
-     * @param array $options Set of options used to initialize the protocol processor.
+     * @param RequestSerializerInterface $serializer Request serializer.
+     * @param ResponseReaderInterface $reader Response reader.
      */
      */
-    public function __construct(Array $options = array())
-    {
-        $this->setSerializer(new TextCommandSerializer());
-        $this->setReader(new TextResponseReader());
-
-        if (count($options) > 0) {
-            $this->initializeOptions($options);
-        }
-    }
-
-    /**
-     * Initializes the protocol processor using a set of options.
-     *
-     * @param array $options Set of options.
-     */
-    private function initializeOptions(Array $options)
-    {
-        foreach ($options as $k => $v) {
-            $this->setOption($k, $v);
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setOption($option, $value)
-    {
-        switch ($option) {
-            case 'iterable_multibulk':
-                $handler = $value ? new ResponseMultiBulkStreamHandler() : new ResponseMultiBulkHandler();
-                $this->reader->setHandler(TextProtocol::PREFIX_MULTI_BULK, $handler);
-                break;
-
-            default:
-                throw new \InvalidArgumentException("The option $option is not supported by the current protocol");
-        }
+    public function __construct(
+        RequestSerializerInterface $serializer = null,
+        ResponseReaderInterface $reader = null
+    ) {
+        $this->setRequestSerializer($serializer ?: new TextRequestSerializer());
+        $this->setResponseReader($reader ?: new TextResponseReader());
     }
     }
 
 
     /**
     /**
@@ -96,33 +66,41 @@ class ComposableTextProtocol implements ComposableProtocolInterface
     }
     }
 
 
     /**
     /**
-     * {@inheritdoc}
+     * Sets the request serializer used by the protocol processor.
+     *
+     * @param RequestSerializerInterface $serializer Request serializer.
      */
      */
-    public function setSerializer(CommandSerializerInterface $serializer)
+    public function setRequestSerializer(RequestSerializerInterface $serializer)
     {
     {
         $this->serializer = $serializer;
         $this->serializer = $serializer;
     }
     }
 
 
     /**
     /**
-     * {@inheritdoc}
+     * Returns the request serializer used by the protocol processor.
+     *
+     * @return RequestSerializerInterface
      */
      */
-    public function getSerializer()
+    public function getRequestSerializer()
     {
     {
         return $this->serializer;
         return $this->serializer;
     }
     }
 
 
     /**
     /**
-     * {@inheritdoc}
+     * Sets the response reader used by the protocol processor.
+     *
+     * @param ResponseReaderInterface $reader Response reader.
      */
      */
-    public function setReader(ResponseReaderInterface $reader)
+    public function setResponseReader(ResponseReaderInterface $reader)
     {
     {
         $this->reader = $reader;
         $this->reader = $reader;
     }
     }
 
 
     /**
     /**
-     * {@inheritdoc}
+     * Returns the Response reader used by the protocol processor.
+     *
+     * @return ResponseReaderInterface
      */
      */
-    public function getReader()
+    public function getResponseReader()
     {
     {
         return $this->reader;
         return $this->reader;
     }
     }

+ 7 - 11
lib/Predis/Protocol/Text/ResponseBulkHandler.php

@@ -17,8 +17,8 @@ use Predis\Protocol\ProtocolException;
 use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 
 
 /**
 /**
- * Implements a response handler for bulk replies using the standard wire
- * protocol defined by Redis.
+ * Handler for the bulk response type of the standard Redis wire protocol.
+ * It translates the payload to a string or a NULL.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
@@ -26,19 +26,15 @@ use Predis\Protocol\ResponseHandlerInterface;
 class ResponseBulkHandler implements ResponseHandlerInterface
 class ResponseBulkHandler implements ResponseHandlerInterface
 {
 {
     /**
     /**
-     * Handles a bulk reply returned by Redis.
-     *
-     * @param ComposableConnectionInterface $connection Connection to Redis.
-     * @param string $lengthString Bytes size of the bulk reply.
-     * @return string
+     * {@inheritdoc}
      */
      */
-    public function handle(ComposableConnectionInterface $connection, $lengthString)
+    public function handle(ComposableConnectionInterface $connection, $payload)
     {
     {
-        $length = (int) $lengthString;
+        $length = (int) $payload;
 
 
-        if ("$length" !== $lengthString) {
+        if ("$length" !== $payload) {
             CommunicationException::handle(new ProtocolException(
             CommunicationException::handle(new ProtocolException(
-                $connection, "Cannot parse '$lengthString' as bulk length"
+                $connection, "Cannot parse '$payload' as the length of the bulk response"
             ));
             ));
         }
         }
 
 

+ 4 - 4
lib/Predis/Protocol/Text/ResponseErrorHandler.php

@@ -16,8 +16,8 @@ use Predis\Connection\ComposableConnectionInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 
 
 /**
 /**
- * Implements a response handler for error replies using the standard wire
- * protocol defined by Redis.
+ * Handler for the error response type of the standard Redis wire protocol.
+ * It translates the payload to a complex response object for Predis.
  *
  *
  * This handler returns a reply object to notify the user that an error has
  * This handler returns a reply object to notify the user that an error has
  * occurred on the server.
  * occurred on the server.
@@ -30,8 +30,8 @@ class ResponseErrorHandler implements ResponseHandlerInterface
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */
-    public function handle(ComposableConnectionInterface $connection, $errorMessage)
+    public function handle(ComposableConnectionInterface $connection, $payload)
     {
     {
-        return new ResponseError($errorMessage);
+        return new ResponseError($payload);
     }
     }
 }
 }

+ 8 - 12
lib/Predis/Protocol/Text/ResponseIntegerHandler.php

@@ -17,8 +17,8 @@ use Predis\Protocol\ProtocolException;
 use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 
 
 /**
 /**
- * Implements a response handler for integer replies using the standard wire
- * protocol defined by Redis.
+ * Handler for the integer response type of the standard Redis wire protocol.
+ * It translates the payload an integer or NULL.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
@@ -26,21 +26,17 @@ use Predis\Protocol\ResponseHandlerInterface;
 class ResponseIntegerHandler implements ResponseHandlerInterface
 class ResponseIntegerHandler implements ResponseHandlerInterface
 {
 {
     /**
     /**
-     * Handles an integer reply returned by Redis.
-     *
-     * @param ComposableConnectionInterface $connection Connection to Redis.
-     * @param string $number String representation of an integer.
-     * @return int
+     * {@inheritdoc}
      */
      */
-    public function handle(ComposableConnectionInterface $connection, $number)
+    public function handle(ComposableConnectionInterface $connection, $payload)
     {
     {
-        if (is_numeric($number)) {
-            return (int) $number;
+        if (is_numeric($payload)) {
+            return (int) $payload;
         }
         }
 
 
-        if ($number !== 'nil') {
+        if ($payload !== 'nil') {
             CommunicationException::handle(new ProtocolException(
             CommunicationException::handle(new ProtocolException(
-                $connection, "Cannot parse '$number' as numeric response"
+                $connection, "Cannot parse '$payload' as a numeric response"
             ));
             ));
         }
         }
 
 

+ 8 - 12
lib/Predis/Protocol/Text/ResponseMultiBulkHandler.php

@@ -17,8 +17,8 @@ use Predis\Protocol\ProtocolException;
 use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 
 
 /**
 /**
- * Implements a response handler for multi-bulk replies using the standard
- * wire protocol defined by Redis.
+ * Handler for the multibulk response type of the standard Redis wire protocol.
+ * It returns multibulk responses as PHP arrays.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
@@ -26,19 +26,15 @@ use Predis\Protocol\ResponseHandlerInterface;
 class ResponseMultiBulkHandler implements ResponseHandlerInterface
 class ResponseMultiBulkHandler implements ResponseHandlerInterface
 {
 {
     /**
     /**
-     * Handles a multi-bulk reply returned by Redis.
-     *
-     * @param ComposableConnectionInterface $connection Connection to Redis.
-     * @param string $lengthString Number of items in the multi-bulk reply.
-     * @return array
+     * {@inheritdoc}
      */
      */
-    public function handle(ComposableConnectionInterface $connection, $lengthString)
+    public function handle(ComposableConnectionInterface $connection, $payload)
     {
     {
-        $length = (int) $lengthString;
+        $length = (int) $payload;
 
 
-        if ("$length" !== $lengthString) {
+        if ("$length" !== $payload) {
             CommunicationException::handle(new ProtocolException(
             CommunicationException::handle(new ProtocolException(
-                $connection, "Cannot parse '$lengthString' as multi-bulk length"
+                $connection, "Cannot parse '$payload' as the length of the multibulk response"
             ));
             ));
         }
         }
 
 
@@ -50,7 +46,7 @@ class ResponseMultiBulkHandler implements ResponseHandlerInterface
 
 
         if ($length > 0) {
         if ($length > 0) {
             $handlersCache = array();
             $handlersCache = array();
-            $reader = $connection->getProtocol()->getReader();
+            $reader = $connection->getProtocol()->getResponseReader();
 
 
             for ($i = 0; $i < $length; $i++) {
             for ($i = 0; $i < $length; $i++) {
                 $header = $connection->readLine();
                 $header = $connection->readLine();

+ 11 - 11
lib/Predis/Protocol/Text/ResponseMultiBulkStreamHandler.php

@@ -18,8 +18,12 @@ use Predis\Protocol\ProtocolException;
 use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 
 
 /**
 /**
- * Implements a response handler for iterable multi-bulk replies using the
- * standard wire protocol defined by Redis.
+ * Handler for the multibulk response type of the standard Redis wire protocol.
+ * It returns multibulk responses as iterators that can stream bulk elements.
+ *
+ * Please note that streamable multibulk replies are not globally supported
+ * by the abstractions built-in into Predis such as for transactions or
+ * pipelines. Use them with care!
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
@@ -27,19 +31,15 @@ use Predis\Protocol\ResponseHandlerInterface;
 class ResponseMultiBulkStreamHandler implements ResponseHandlerInterface
 class ResponseMultiBulkStreamHandler implements ResponseHandlerInterface
 {
 {
     /**
     /**
-     * Handles a multi-bulk reply returned by Redis in a streamable fashion.
-     *
-     * @param ComposableConnectionInterface $connection Connection to Redis.
-     * @param string $lengthString Number of items in the multi-bulk reply.
-     * @return MultiBulkResponseSimple
+     * {@inheritdoc}
      */
      */
-    public function handle(ComposableConnectionInterface $connection, $lengthString)
+    public function handle(ComposableConnectionInterface $connection, $payload)
     {
     {
-        $length = (int) $lengthString;
+        $length = (int) $payload;
 
 
-        if ("$length" != $lengthString) {
+        if ("$length" != $payload) {
             CommunicationException::handle(new ProtocolException(
             CommunicationException::handle(new ProtocolException(
-                $connection, "Cannot parse '$lengthString' as multi-bulk length"
+                $connection, "Cannot parse '$payload' as the length of the multibulk response"
             ));
             ));
         }
         }
 
 

+ 3 - 2
lib/Predis/Protocol/Text/ResponseStatusHandler.php

@@ -16,8 +16,9 @@ use Predis\Connection\ComposableConnectionInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseHandlerInterface;
 
 
 /**
 /**
- * Implements a response handler for status replies using the standard wire
- * protocol defined by Redis.
+ * Handler for the status response type of the standard Redis wire protocol.
+ * It translates certain classes of status response to PHP objects or just
+ * returns the payload as a string.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>

+ 13 - 9
lib/Predis/Protocol/Text/TextProtocol.php

@@ -21,7 +21,7 @@ use Predis\Protocol\ProtocolException;
 use Predis\Protocol\ProtocolInterface;
 use Predis\Protocol\ProtocolInterface;
 
 
 /**
 /**
- * Implements a protocol processor for the standard wire protocol defined by Redis.
+ * Protocol processor for the standard Redis wire protocol.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
@@ -51,7 +51,7 @@ class TextProtocol implements ProtocolInterface
     public function __construct()
     public function __construct()
     {
     {
         $this->mbiterable = false;
         $this->mbiterable = false;
-        $this->serializer = new TextCommandSerializer();
+        $this->serializer = new TextRequestSerializer();
     }
     }
 
 
     /**
     /**
@@ -123,14 +123,18 @@ class TextProtocol implements ProtocolInterface
     }
     }
 
 
     /**
     /**
-     * {@inheritdoc}
+     * Enables or disables returning multibulk responses as specialized PHP
+     * iterators used to stream bulk elements of a multibulk response instead
+     * returning a plain array.
+     *
+     * Please note that streamable multibulk replies are not globally supported
+     * by the abstractions built-in into Predis such as for transactions or
+     * pipelines. Use them with care!
+     *
+     * @param bool $value Enable or disable streamable multibulk responses.
      */
      */
-    public function setOption($option, $value)
+    public function useIterableMultibulk($value)
     {
     {
-        switch ($option) {
-            case 'iterable_multibulk':
-                $this->mbiterable = (bool) $value;
-                break;
-        }
+        $this->mbiterable = (bool) $value;
     }
     }
 }
 }

+ 3 - 4
lib/Predis/Protocol/Text/TextCommandSerializer.php → lib/Predis/Protocol/Text/TextRequestSerializer.php

@@ -12,16 +12,15 @@
 namespace Predis\Protocol\Text;
 namespace Predis\Protocol\Text;
 
 
 use Predis\Command\CommandInterface;
 use Predis\Command\CommandInterface;
-use Predis\Protocol\CommandSerializerInterface;
+use Predis\Protocol\RequestSerializerInterface;
 
 
 /**
 /**
- * Implements a pluggable command serializer using the standard  wire protocol
- * defined by Redis.
+ * Request serializer for the standard Redis wire protocol.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
-class TextCommandSerializer implements CommandSerializerInterface
+class TextRequestSerializer implements RequestSerializerInterface
 {
 {
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}

+ 19 - 18
lib/Predis/Protocol/Text/TextResponseReader.php

@@ -18,15 +18,14 @@ use Predis\Protocol\ResponseHandlerInterface;
 use Predis\Protocol\ResponseReaderInterface;
 use Predis\Protocol\ResponseReaderInterface;
 
 
 /**
 /**
- * Implements a pluggable response reader using the standard wire protocol
- * defined by Redis.
+ * Response reader for the standard Redis wire protocol.
  *
  *
  * @link http://redis.io/topics/protocol
  * @link http://redis.io/topics/protocol
  * @author Daniele Alessandri <suppakilla@gmail.com>
  * @author Daniele Alessandri <suppakilla@gmail.com>
  */
  */
 class TextResponseReader implements ResponseReaderInterface
 class TextResponseReader implements ResponseReaderInterface
 {
 {
-    private $handlers;
+    protected $handlers;
 
 
     /**
     /**
      *
      *
@@ -37,10 +36,11 @@ class TextResponseReader implements ResponseReaderInterface
     }
     }
 
 
     /**
     /**
-     * Returns the default set of response handlers for all the type of replies
-     * that can be returned by Redis.
+     * Returns the default handlers for the supported type of responses.
+     *
+     * @return array
      */
      */
-    private function getDefaultHandlers()
+    protected function getDefaultHandlers()
     {
     {
         return array(
         return array(
             TextProtocol::PREFIX_STATUS     => new ResponseStatusHandler(),
             TextProtocol::PREFIX_STATUS     => new ResponseStatusHandler(),
@@ -53,10 +53,10 @@ class TextResponseReader implements ResponseReaderInterface
 
 
     /**
     /**
      * Sets a response handler for a certain prefix that identifies a type of
      * Sets a response handler for a certain prefix that identifies a type of
-     * reply that can be returned by Redis.
+     * response that can be returned by Redis.
      *
      *
-     * @param string $prefix Identifier for a type of reply.
-     * @param ResponseHandlerInterface $handler Response handler for the reply.
+     * @param string $prefix Identifier of the type of response.
+     * @param ResponseHandlerInterface $handler Response handler.
      */
      */
     public function setHandler($prefix, ResponseHandlerInterface $handler)
     public function setHandler($prefix, ResponseHandlerInterface $handler)
     {
     {
@@ -64,10 +64,9 @@ class TextResponseReader implements ResponseReaderInterface
     }
     }
 
 
     /**
     /**
-     * Returns the response handler associated to a certain type of reply that
-     * can be returned by Redis.
+     * Returns the response handler associated to a certain type of response.
      *
      *
-     * @param string $prefix Identifier for a type of reply.
+     * @param string $prefix Identifier of the type of response.
      * @return ResponseHandlerInterface
      * @return ResponseHandlerInterface
      */
      */
     public function getHandler($prefix)
     public function getHandler($prefix)
@@ -85,13 +84,13 @@ class TextResponseReader implements ResponseReaderInterface
         $header = $connection->readLine();
         $header = $connection->readLine();
 
 
         if ($header === '') {
         if ($header === '') {
-            $this->protocolError($connection, 'Unexpected empty header');
+            $this->onProtocolError($connection, 'Unexpected empty header');
         }
         }
 
 
         $prefix = $header[0];
         $prefix = $header[0];
 
 
         if (!isset($this->handlers[$prefix])) {
         if (!isset($this->handlers[$prefix])) {
-            $this->protocolError($connection, "Unknown prefix: '$prefix'");
+            $this->onProtocolError($connection, "Unknown prefix: '$prefix'");
         }
         }
 
 
         $handler = $this->handlers[$prefix];
         $handler = $this->handlers[$prefix];
@@ -100,14 +99,16 @@ class TextResponseReader implements ResponseReaderInterface
     }
     }
 
 
     /**
     /**
-     * Helper method used to handle a protocol error generated while reading a
-     * reply from a connection to Redis.
+     * Handles protocol errors generated while reading responses from the
+     * connection.
      *
      *
      * @param ComposableConnectionInterface $connection Connection to Redis that generated the error.
      * @param ComposableConnectionInterface $connection Connection to Redis that generated the error.
      * @param string $message Error message.
      * @param string $message Error message.
      */
      */
-    private function protocolError(ComposableConnectionInterface $connection, $message)
+    protected function onProtocolError(ComposableConnectionInterface $connection, $message)
     {
     {
-        CommunicationException::handle(new ProtocolException($connection, $message));
+        CommunicationException::handle(
+            new ProtocolException($connection, $message)
+        );
     }
     }
 }
 }

+ 1 - 1
tests/Predis/Connection/ComposableStreamConnectionTest.php

@@ -75,7 +75,7 @@ class ComposableStreamConnectionTest extends ConnectionTestCase
     public function testReadsMultibulkRepliesAsIterators()
     public function testReadsMultibulkRepliesAsIterators()
     {
     {
         $connection = $this->getConnection($profile, true);
         $connection = $this->getConnection($profile, true);
-        $connection->getProtocol()->setOption('iterable_multibulk', true);
+        $connection->getProtocol()->useIterableMultibulk(true);
 
 
         $connection->executeCommand($profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol')));
         $connection->executeCommand($profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol')));
         $connection->writeCommand($profile->createCommand('lrange', array('metavars', 0, -1)));
         $connection->writeCommand($profile->createCommand('lrange', array('metavars', 0, -1)));

+ 1 - 1
tests/Predis/Iterator/MultiBulkResponseSimpleTest.php

@@ -131,7 +131,7 @@ class MultiBulkResponseSimpleTest extends StandardTestCase
         );
         );
 
 
         $protocol = new TextProtocol();
         $protocol = new TextProtocol();
-        $protocol->setOption('iterable_multibulk', true);
+        $protocol->useIterableMultibulk(true);
 
 
         $connection = new ComposableStreamConnection($parameters, $protocol);
         $connection = new ComposableStreamConnection($parameters, $protocol);
 
 

+ 1 - 1
tests/Predis/Iterator/MultiBulkResponseTupleTest.php

@@ -117,7 +117,7 @@ class MultiBulkResponseTupleTest extends StandardTestCase
         );
         );
 
 
         $protocol = new TextProtocol();
         $protocol = new TextProtocol();
-        $protocol->setOption('iterable_multibulk', true);
+        $protocol->useIterableMultibulk(true);
 
 
         $connection = new ComposableStreamConnection($parameters, $protocol);
         $connection = new ComposableStreamConnection($parameters, $protocol);
 
 

+ 39 - 38
tests/Predis/Protocol/Text/ComposableTextProtocolTest.php

@@ -21,27 +21,56 @@ class ComposableTextProtocolTest extends StandardTestCase
     /**
     /**
      * @group disconnected
      * @group disconnected
      */
      */
-    public function testCustomSerializer()
+    public function testConstructor()
     {
     {
-        $serializer = $this->getMock('Predis\Protocol\CommandSerializerInterface');
+        $protocol = new ComposableTextProtocol();
+
+        $this->assertInstanceOf(
+            'Predis\Protocol\Text\TextRequestSerializer', $protocol->getRequestSerializer()
+        );
+        $this->assertInstanceOf(
+            'Predis\Protocol\Text\TextResponseReader', $protocol->getResponseReader()
+        );
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testConstructorWithArguments()
+    {
+        $serializer = $this->getMock('Predis\Protocol\RequestSerializerInterface');
+        $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface');
+
+        $protocol = new ComposableTextProtocol($serializer, $reader);
+
+        $this->assertSame($serializer, $protocol->getRequestSerializer());
+        $this->assertSame($reader, $protocol->getResponseReader());
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testCustomRequestSerializer()
+    {
+        $serializer = $this->getMock('Predis\Protocol\RequestSerializerInterface');
 
 
         $protocol = new ComposableTextProtocol();
         $protocol = new ComposableTextProtocol();
-        $protocol->setSerializer($serializer);
+        $protocol->setRequestSerializer($serializer);
 
 
-        $this->assertSame($serializer, $protocol->getSerializer());
+        $this->assertSame($serializer, $protocol->getRequestSerializer());
     }
     }
 
 
     /**
     /**
      * @group disconnected
      * @group disconnected
      */
      */
-    public function testCustomReader()
+    public function testCustomResponseReader()
     {
     {
         $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface');
         $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface');
 
 
         $protocol = new ComposableTextProtocol();
         $protocol = new ComposableTextProtocol();
-        $protocol->setReader($reader);
+        $protocol->setResponseReader($reader);
 
 
-        $this->assertSame($reader, $protocol->getReader());
+        $this->assertSame($reader, $protocol->getResponseReader());
     }
     }
 
 
     /**
     /**
@@ -53,10 +82,9 @@ class ComposableTextProtocolTest extends StandardTestCase
 
 
         $command = $this->getMock('Predis\Command\CommandInterface');
         $command = $this->getMock('Predis\Command\CommandInterface');
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
-        $serializer = $this->getMock('Predis\Protocol\CommandSerializerInterface');
+        $serializer = $this->getMock('Predis\Protocol\RequestSerializerInterface');
 
 
-        $protocol = new ComposableTextProtocol();
-        $protocol->setSerializer($serializer);
+        $protocol = new ComposableTextProtocol($serializer);
 
 
         $connection->expects($this->once())
         $connection->expects($this->once())
                    ->method('writeBytes')
                    ->method('writeBytes')
@@ -80,8 +108,7 @@ class ComposableTextProtocolTest extends StandardTestCase
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
         $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface');
         $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface');
 
 
-        $protocol = new ComposableTextProtocol();
-        $protocol->setReader($reader);
+        $protocol = new ComposableTextProtocol(null, $reader);
 
 
         $reader->expects($this->once())
         $reader->expects($this->once())
                    ->method('read')
                    ->method('read')
@@ -90,30 +117,4 @@ class ComposableTextProtocolTest extends StandardTestCase
 
 
         $this->assertSame('bulk', $protocol->read($connection));
         $this->assertSame('bulk', $protocol->read($connection));
     }
     }
-
-    /**
-     * @group disconnected
-     */
-    public function testSetMultibulkOption()
-    {
-        $protocol = new ComposableTextProtocol();
-        $reader = $protocol->getReader();
-
-        $protocol->setOption('iterable_multibulk', true);
-        $this->assertInstanceOf('Predis\Protocol\Text\ResponseMultiBulkStreamHandler', $reader->getHandler('*'));
-
-        $protocol->setOption('iterable_multibulk', false);
-        $this->assertInstanceOf('Predis\Protocol\Text\ResponseMultiBulkHandler', $reader->getHandler('*'));
-    }
-
-    /**
-     * @group disconnected
-     * @expectedException InvalidArgumentException
-     * @expectedExceptionMessage The option unknown_option is not supported by the current protocol
-     */
-    public function testSetInvalidOption()
-    {
-        $protocol = new ComposableTextProtocol();
-        $protocol->setOption('unknown_option', true);
-    }
 }
 }

+ 1 - 1
tests/Predis/Protocol/Text/ResponseBulkHandlerTest.php

@@ -75,7 +75,7 @@ class ResponseBulkHandlerTest extends StandardTestCase
     /**
     /**
      * @group disconnected
      * @group disconnected
      * @expectedException Predis\Protocol\ProtocolException
      * @expectedException Predis\Protocol\ProtocolException
-     * @expectedExceptionMessage Cannot parse 'invalid' as bulk length
+     * @expectedExceptionMessage Cannot parse 'invalid' as the length of the bulk response
      */
      */
     public function testInvalidLength()
     public function testInvalidLength()
     {
     {

+ 1 - 1
tests/Predis/Protocol/Text/ResponseIntegerHandlerTest.php

@@ -55,7 +55,7 @@ class ResponseIntegerHandlerTest extends StandardTestCase
     /**
     /**
      * @group disconnected
      * @group disconnected
      * @expectedException Predis\Protocol\ProtocolException
      * @expectedException Predis\Protocol\ProtocolException
-     * @expectedExceptionMessage Cannot parse 'invalid' as numeric response
+     * @expectedExceptionMessage Cannot parse 'invalid' as a numeric response
      */
      */
     public function testInvalid()
     public function testInvalid()
     {
     {

+ 1 - 1
tests/Predis/Protocol/Text/ResponseMultiBulkHandlerTest.php

@@ -68,7 +68,7 @@ class ResponseMultiBulkHandlerTest extends StandardTestCase
     /**
     /**
      * @group disconnected
      * @group disconnected
      * @expectedException Predis\Protocol\ProtocolException
      * @expectedException Predis\Protocol\ProtocolException
-     * @expectedExceptionMessage Cannot parse 'invalid' as multi-bulk length
+     * @expectedExceptionMessage Cannot parse 'invalid' as the length of the multibulk response
      */
      */
     public function testInvalid()
     public function testInvalid()
     {
     {

+ 1 - 1
tests/Predis/Protocol/Text/ResponseMultiBulkStreamHandlerTest.php

@@ -36,7 +36,7 @@ class ResponseMultiBulkStreamHandlerTest extends StandardTestCase
     /**
     /**
      * @group disconnected
      * @group disconnected
      * @expectedException Predis\Protocol\ProtocolException
      * @expectedException Predis\Protocol\ProtocolException
-     * @expectedExceptionMessage Cannot parse 'invalid' as multi-bulk length
+     * @expectedExceptionMessage Cannot parse 'invalid' as the length of the multibulk response
      */
      */
     public function testInvalid()
     public function testInvalid()
     {
     {

+ 1 - 1
tests/Predis/Protocol/Text/TextProtocolTest.php

@@ -89,7 +89,7 @@ class TextProtocolTest extends StandardTestCase
     public function testIterableMultibulkSupport()
     public function testIterableMultibulkSupport()
     {
     {
         $protocol = new TextProtocol();
         $protocol = new TextProtocol();
-        $protocol->setOption('iterable_multibulk', true);
+        $protocol->useIterableMultibulk(true);
 
 
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
 
 

+ 3 - 3
tests/Predis/Protocol/Text/TextCommandSerializerTest.php → tests/Predis/Protocol/Text/TextRequestSerializerTest.php

@@ -16,14 +16,14 @@ use \PHPUnit_Framework_TestCase as StandardTestCase;
 /**
 /**
  *
  *
  */
  */
-class TextCommandSerializerTest extends StandardTestCase
+class TextRequestSerializerTest extends StandardTestCase
 {
 {
     /**
     /**
      * @group disconnected
      * @group disconnected
      */
      */
     public function testSerializerIdWithNoArguments()
     public function testSerializerIdWithNoArguments()
     {
     {
-        $serializer = new TextCommandSerializer();
+        $serializer = new TextRequestSerializer();
 
 
         $command = $this->getMock('Predis\Command\CommandInterface');
         $command = $this->getMock('Predis\Command\CommandInterface');
 
 
@@ -45,7 +45,7 @@ class TextCommandSerializerTest extends StandardTestCase
      */
      */
     public function testSerializerIdWithArguments()
     public function testSerializerIdWithArguments()
     {
     {
-        $serializer = new TextCommandSerializer();
+        $serializer = new TextRequestSerializer();
 
 
         $command = $this->getMock('Predis\Command\CommandInterface');
         $command = $this->getMock('Predis\Command\CommandInterface');
 
 

+ 1 - 1
tests/Predis/Protocol/Text/TextResponseReaderTest.php

@@ -55,7 +55,7 @@ class TextResponseReaderTest extends StandardTestCase
         $reader = new TextResponseReader();
         $reader = new TextResponseReader();
 
 
         $protocol = new ComposableTextProtocol();
         $protocol = new ComposableTextProtocol();
-        $protocol->setReader($reader);
+        $protocol->setResponseReader($reader);
 
 
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');
         $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface');