浏览代码

Add new command class useful to execute "raw" Redis commands.

By raw we mean that input arguments are not filtered and responses are
not parsed, which means arguments must follow the command signature as
defined by Redis and complex responses are left untouched.

When instantiating an instance of `Predis\Command\RawCommand` you must
pass at least the command ID. You can pass further arguments in the
array or you can just set them later with `RawCommand::setArguments()`
but you cannot modify the command ID once instantiated.

  $command = new Predis\Command\RawCommand(['SET', 'foo', 'bar']);
  $response = $client->executeCommand($command);

While higher level abstractions built upon `Predis\Client` should just
use commands created by the profile in use, inner parts of the library
might use raw commands to provide certain functionalities making sure
that input and output of commands are always consistent, independent
of the profile.

NOTE: Backported from v0.9.
Daniele Alessandri 11 年之前
父节点
当前提交
973c9a7031
共有 3 个文件被更改,包括 304 次插入0 次删除
  1. 5 0
      CHANGELOG.md
  2. 158 0
      lib/Predis/Command/RawCommand.php
  3. 141 0
      tests/Predis/Command/RawCommandTest.php

+ 5 - 0
CHANGELOG.md

@@ -14,6 +14,11 @@ v0.8.5 (2013-xx-xx)
     - hashes (cursor-based iterator using `HSCAN`)
     - lists (plain iterator using `LRANGE`)
 
+- It is now possible to execute "raw commands" using `Predis\Command\RawCommand`
+  and a variable list of command arguments. Input arguments are not filtered and
+  responses are not parsed, which means arguments must follow the signature of
+  the command as defined by Redis and complex responses are left untouched.
+
 - List of deprecated methods:
 
     - `Predis\Client::multiExec()`: superseded by `Predis\Client::transaction()`

+ 158 - 0
lib/Predis/Command/RawCommand.php

@@ -0,0 +1,158 @@
+<?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\Command;
+
+use InvalidArgumentException;
+
+/**
+ * Class for generic "anonymous" Redis commands.
+ *
+ * This command class does not filter input arguments or parse responses, but
+ * can be used to leverage the standard Predis API to execute any command simply
+ * by providing the needed arguments following the command signature as defined
+ * by Redis in its documentation.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RawCommand implements CommandInterface
+{
+    private $hash;
+    private $commandID;
+    private $arguments;
+
+    public function __construct(array $arguments)
+    {
+        if (!$arguments) {
+            throw new InvalidArgumentException("Arguments array is missing the command ID");
+        }
+
+        $this->commandID = array_shift($arguments);
+        $this->arguments = $arguments;
+    }
+
+    /**
+     * Creates a new raw command using a variadic method.
+     *
+     * @param string $commandID Redis command ID.
+     * @param string ... Arguments list for the command.
+     */
+    public static function create($commandID /* [ $arg, ... */)
+    {
+        $arguments = func_get_args();
+        $command = new self($arguments);
+
+        return $command;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getId()
+    {
+        return $this->commandID;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setArguments(array $arguments)
+    {
+        $this->arguments = $arguments;
+        unset($this->hash);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setRawArguments(array $arguments)
+    {
+        $this->setArguments($arguments);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getArguments()
+    {
+        return $this->arguments;
+    }
+
+    /**
+     * Gets the argument from the arguments list at the specified index.
+     *
+     * @param array $arguments Position of the argument.
+     */
+    public function getArgument($index)
+    {
+        if (isset($this->arguments[$index])) {
+            return $this->arguments[$index];
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setHash($hash)
+    {
+        $this->hash = $hash;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getHash()
+    {
+        if (isset($this->hash)) {
+            return $this->hash;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function parseResponse($data)
+    {
+        return $data;
+    }
+
+    /**
+     * Helper function used to reduce a list of arguments to a string.
+     *
+     * @param string $accumulator Temporary string.
+     * @param string $argument Current argument.
+     * @return string
+     */
+    protected function toStringArgumentReducer($accumulator, $argument)
+    {
+        if (strlen($argument) > 32) {
+            $argument = substr($argument, 0, 32) . '[...]';
+        }
+
+        $accumulator .= " $argument";
+
+        return $accumulator;
+    }
+
+    /**
+     * Returns a partial string representation of the command with its arguments.
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return array_reduce(
+            $this->getArguments(),
+            array($this, 'toStringArgumentReducer'),
+            $this->getId()
+        );
+    }
+}

+ 141 - 0
tests/Predis/Command/RawCommandTest.php

@@ -0,0 +1,141 @@
+<?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\Command;
+
+use PHPUnit_Framework_TestCase as StandardTestCase;
+
+/**
+ *
+ */
+class RawCommandTest extends StandardTestCase
+{
+    /**
+     * @group disconnected
+     */
+    public function testConstructorWithCommandID()
+    {
+        $commandID = 'PING';
+        $command = new RawCommand(array($commandID));
+
+        $this->assertSame($commandID, $command->getId());
+        $this->assertEmpty($command->getArguments());
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testConstructorWithCommandIDAndArguments()
+    {
+        $commandID = 'SET';
+        $commandArgs = array('foo', 'bar');
+
+        $command = new RawCommand(array_merge((array) $commandID, $commandArgs));
+
+        $this->assertSame($commandID, $command->getId());
+        $this->assertSame($commandArgs, $command->getArguments());
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testStaticCreate()
+    {
+        $command = RawCommand::create('SET');
+        $this->assertSame('SET', $command->getId());
+        $this->assertEmpty($command->getArguments());
+
+        $command = RawCommand::create('SET', 'foo', 'bar');
+        $this->assertSame('SET', $command->getId());
+        $this->assertSame(array('foo', 'bar'), $command->getArguments());
+    }
+
+    /**
+     * @group disconnected
+     * @expectedException InvalidArgumentException
+     * @expectedExceptionMessage Arguments array is missing the command ID
+     */
+    public function testExceptionOnMissingCommandID()
+    {
+        $command = new RawCommand(array());
+    }
+
+    /**
+     * @group disconnected
+     * @expectedException PHPUnit_Framework_Error_Warning
+     * @expectedExceptionMessage Missing argument 1 for Predis\Command\RawCommand::create()
+     */
+    public function testPHPWarningOnMissingCommandIDWithStaticCreate()
+    {
+        RawCommand::create();
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testSetArguments()
+    {
+        $commandID = 'SET';
+        $command = new RawCommand(array($commandID));
+
+        $command->setArguments($commandArgs = array('foo', 'bar'));
+        $this->assertSame($commandArgs, $command->getArguments());
+
+        $command->setArguments($commandArgs = array('hoge', 'piyo'));
+        $this->assertSame($commandArgs, $command->getArguments());
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testSetRawArguments()
+    {
+        $commandID = 'SET';
+        $command = new RawCommand(array($commandID));
+
+        $command->setRawArguments($commandArgs = array('foo', 'bar'));
+        $this->assertSame($commandArgs, $command->getArguments());
+
+        $command->setRawArguments($commandArgs = array('hoge', 'piyo'));
+        $this->assertSame($commandArgs, $command->getArguments());
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testSetAndGetHash()
+    {
+        $hash = "key-hash";
+        $arguments = array('SET', 'key', 'value');
+        $command = new RawCommand($arguments);
+
+        $this->assertNull($command->getHash());
+
+        $command->setHash($hash);
+        $this->assertSame($hash, $command->getHash());
+
+        $command->setArguments(array('hoge', 'piyo'));
+        $this->assertNull($command->getHash());
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testToString()
+    {
+        $arguments = array('SET', 'key', 'value');
+        $expected = implode(' ', $arguments);
+
+        $command = new RawCommand($arguments);
+
+        $this->assertEquals($expected, (string) $command);
+    }
+}