vendor/predis/predis/src/Command/Processor/KeyPrefixProcessor.php line 195

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Predis package.
  4.  *
  5.  * (c) Daniele Alessandri <suppakilla@gmail.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Predis\Command\Processor;
  11. use Predis\Command\CommandInterface;
  12. use Predis\Command\PrefixableCommandInterface;
  13. /**
  14.  * Command processor capable of prefixing keys stored in the arguments of Redis
  15.  * commands supported.
  16.  *
  17.  * @author Daniele Alessandri <suppakilla@gmail.com>
  18.  */
  19. class KeyPrefixProcessor implements ProcessorInterface
  20. {
  21.     private $prefix;
  22.     private $commands;
  23.     /**
  24.      * @param string $prefix Prefix for the keys.
  25.      */
  26.     public function __construct($prefix)
  27.     {
  28.         $this->prefix $prefix;
  29.         $this->commands = array(
  30.             /* ---------------- Redis 1.2 ---------------- */
  31.             'EXISTS' => 'static::all',
  32.             'DEL' => 'static::all',
  33.             'TYPE' => 'static::first',
  34.             'KEYS' => 'static::first',
  35.             'RENAME' => 'static::all',
  36.             'RENAMENX' => 'static::all',
  37.             'EXPIRE' => 'static::first',
  38.             'EXPIREAT' => 'static::first',
  39.             'TTL' => 'static::first',
  40.             'MOVE' => 'static::first',
  41.             'SORT' => 'static::sort',
  42.             'DUMP' => 'static::first',
  43.             'RESTORE' => 'static::first',
  44.             'SET' => 'static::first',
  45.             'SETNX' => 'static::first',
  46.             'MSET' => 'static::interleaved',
  47.             'MSETNX' => 'static::interleaved',
  48.             'GET' => 'static::first',
  49.             'MGET' => 'static::all',
  50.             'GETSET' => 'static::first',
  51.             'INCR' => 'static::first',
  52.             'INCRBY' => 'static::first',
  53.             'DECR' => 'static::first',
  54.             'DECRBY' => 'static::first',
  55.             'RPUSH' => 'static::first',
  56.             'LPUSH' => 'static::first',
  57.             'LLEN' => 'static::first',
  58.             'LRANGE' => 'static::first',
  59.             'LTRIM' => 'static::first',
  60.             'LINDEX' => 'static::first',
  61.             'LSET' => 'static::first',
  62.             'LREM' => 'static::first',
  63.             'LPOP' => 'static::first',
  64.             'RPOP' => 'static::first',
  65.             'RPOPLPUSH' => 'static::all',
  66.             'SADD' => 'static::first',
  67.             'SREM' => 'static::first',
  68.             'SPOP' => 'static::first',
  69.             'SMOVE' => 'static::skipLast',
  70.             'SCARD' => 'static::first',
  71.             'SISMEMBER' => 'static::first',
  72.             'SINTER' => 'static::all',
  73.             'SINTERSTORE' => 'static::all',
  74.             'SUNION' => 'static::all',
  75.             'SUNIONSTORE' => 'static::all',
  76.             'SDIFF' => 'static::all',
  77.             'SDIFFSTORE' => 'static::all',
  78.             'SMEMBERS' => 'static::first',
  79.             'SRANDMEMBER' => 'static::first',
  80.             'ZADD' => 'static::first',
  81.             'ZINCRBY' => 'static::first',
  82.             'ZREM' => 'static::first',
  83.             'ZRANGE' => 'static::first',
  84.             'ZREVRANGE' => 'static::first',
  85.             'ZRANGEBYSCORE' => 'static::first',
  86.             'ZCARD' => 'static::first',
  87.             'ZSCORE' => 'static::first',
  88.             'ZREMRANGEBYSCORE' => 'static::first',
  89.             /* ---------------- Redis 2.0 ---------------- */
  90.             'SETEX' => 'static::first',
  91.             'APPEND' => 'static::first',
  92.             'SUBSTR' => 'static::first',
  93.             'BLPOP' => 'static::skipLast',
  94.             'BRPOP' => 'static::skipLast',
  95.             'ZUNIONSTORE' => 'static::zsetStore',
  96.             'ZINTERSTORE' => 'static::zsetStore',
  97.             'ZCOUNT' => 'static::first',
  98.             'ZRANK' => 'static::first',
  99.             'ZREVRANK' => 'static::first',
  100.             'ZREMRANGEBYRANK' => 'static::first',
  101.             'HSET' => 'static::first',
  102.             'HSETNX' => 'static::first',
  103.             'HMSET' => 'static::first',
  104.             'HINCRBY' => 'static::first',
  105.             'HGET' => 'static::first',
  106.             'HMGET' => 'static::first',
  107.             'HDEL' => 'static::first',
  108.             'HEXISTS' => 'static::first',
  109.             'HLEN' => 'static::first',
  110.             'HKEYS' => 'static::first',
  111.             'HVALS' => 'static::first',
  112.             'HGETALL' => 'static::first',
  113.             'SUBSCRIBE' => 'static::all',
  114.             'UNSUBSCRIBE' => 'static::all',
  115.             'PSUBSCRIBE' => 'static::all',
  116.             'PUNSUBSCRIBE' => 'static::all',
  117.             'PUBLISH' => 'static::first',
  118.             /* ---------------- Redis 2.2 ---------------- */
  119.             'PERSIST' => 'static::first',
  120.             'STRLEN' => 'static::first',
  121.             'SETRANGE' => 'static::first',
  122.             'GETRANGE' => 'static::first',
  123.             'SETBIT' => 'static::first',
  124.             'GETBIT' => 'static::first',
  125.             'RPUSHX' => 'static::first',
  126.             'LPUSHX' => 'static::first',
  127.             'LINSERT' => 'static::first',
  128.             'BRPOPLPUSH' => 'static::skipLast',
  129.             'ZREVRANGEBYSCORE' => 'static::first',
  130.             'WATCH' => 'static::all',
  131.             /* ---------------- Redis 2.6 ---------------- */
  132.             'PTTL' => 'static::first',
  133.             'PEXPIRE' => 'static::first',
  134.             'PEXPIREAT' => 'static::first',
  135.             'PSETEX' => 'static::first',
  136.             'INCRBYFLOAT' => 'static::first',
  137.             'BITOP' => 'static::skipFirst',
  138.             'BITCOUNT' => 'static::first',
  139.             'HINCRBYFLOAT' => 'static::first',
  140.             'EVAL' => 'static::evalKeys',
  141.             'EVALSHA' => 'static::evalKeys',
  142.             'MIGRATE' => 'static::migrate',
  143.             /* ---------------- Redis 2.8 ---------------- */
  144.             'SSCAN' => 'static::first',
  145.             'ZSCAN' => 'static::first',
  146.             'HSCAN' => 'static::first',
  147.             'PFADD' => 'static::first',
  148.             'PFCOUNT' => 'static::all',
  149.             'PFMERGE' => 'static::all',
  150.             'ZLEXCOUNT' => 'static::first',
  151.             'ZRANGEBYLEX' => 'static::first',
  152.             'ZREMRANGEBYLEX' => 'static::first',
  153.             'ZREVRANGEBYLEX' => 'static::first',
  154.             'BITPOS' => 'static::first',
  155.             /* ---------------- Redis 3.2 ---------------- */
  156.             'HSTRLEN' => 'static::first',
  157.             'BITFIELD' => 'static::first',
  158.             'GEOADD' => 'static::first',
  159.             'GEOHASH' => 'static::first',
  160.             'GEOPOS' => 'static::first',
  161.             'GEODIST' => 'static::first',
  162.             'GEORADIUS' => 'static::georadius',
  163.             'GEORADIUSBYMEMBER' => 'static::georadius',
  164.         );
  165.     }
  166.     /**
  167.      * Sets a prefix that is applied to all the keys.
  168.      *
  169.      * @param string $prefix Prefix for the keys.
  170.      */
  171.     public function setPrefix($prefix)
  172.     {
  173.         $this->prefix $prefix;
  174.     }
  175.     /**
  176.      * Gets the current prefix.
  177.      *
  178.      * @return string
  179.      */
  180.     public function getPrefix()
  181.     {
  182.         return $this->prefix;
  183.     }
  184.     /**
  185.      * {@inheritdoc}
  186.      */
  187.     public function process(CommandInterface $command)
  188.     {
  189.         if ($command instanceof PrefixableCommandInterface) {
  190.             $command->prefixKeys($this->prefix);
  191.         } elseif (isset($this->commands[$commandID strtoupper($command->getId())])) {
  192.             call_user_func($this->commands[$commandID], $command$this->prefix);
  193.         }
  194.     }
  195.     /**
  196.      * Sets an handler for the specified command ID.
  197.      *
  198.      * The callback signature must have 2 parameters of the following types:
  199.      *
  200.      *   - Predis\Command\CommandInterface (command instance)
  201.      *   - String (prefix)
  202.      *
  203.      * When the callback argument is omitted or NULL, the previously
  204.      * associated handler for the specified command ID is removed.
  205.      *
  206.      * @param string $commandID The ID of the command to be handled.
  207.      * @param mixed  $callback  A valid callable object or NULL.
  208.      *
  209.      * @throws \InvalidArgumentException
  210.      */
  211.     public function setCommandHandler($commandID$callback null)
  212.     {
  213.         $commandID strtoupper($commandID);
  214.         if (!isset($callback)) {
  215.             unset($this->commands[$commandID]);
  216.             return;
  217.         }
  218.         if (!is_callable($callback)) {
  219.             throw new \InvalidArgumentException(
  220.                 'Callback must be a valid callable object or NULL'
  221.             );
  222.         }
  223.         $this->commands[$commandID] = $callback;
  224.     }
  225.     /**
  226.      * {@inheritdoc}
  227.      */
  228.     public function __toString()
  229.     {
  230.         return $this->getPrefix();
  231.     }
  232.     /**
  233.      * Applies the specified prefix only the first argument.
  234.      *
  235.      * @param CommandInterface $command Command instance.
  236.      * @param string           $prefix  Prefix string.
  237.      */
  238.     public static function first(CommandInterface $command$prefix)
  239.     {
  240.         if ($arguments $command->getArguments()) {
  241.             $arguments[0] = "$prefix{$arguments[0]}";
  242.             $command->setRawArguments($arguments);
  243.         }
  244.     }
  245.     /**
  246.      * Applies the specified prefix to all the arguments.
  247.      *
  248.      * @param CommandInterface $command Command instance.
  249.      * @param string           $prefix  Prefix string.
  250.      */
  251.     public static function all(CommandInterface $command$prefix)
  252.     {
  253.         if ($arguments $command->getArguments()) {
  254.             foreach ($arguments as &$key) {
  255.                 $key "$prefix$key";
  256.             }
  257.             $command->setRawArguments($arguments);
  258.         }
  259.     }
  260.     /**
  261.      * Applies the specified prefix only to even arguments in the list.
  262.      *
  263.      * @param CommandInterface $command Command instance.
  264.      * @param string           $prefix  Prefix string.
  265.      */
  266.     public static function interleaved(CommandInterface $command$prefix)
  267.     {
  268.         if ($arguments $command->getArguments()) {
  269.             $length count($arguments);
  270.             for ($i 0$i $length$i += 2) {
  271.                 $arguments[$i] = "$prefix{$arguments[$i]}";
  272.             }
  273.             $command->setRawArguments($arguments);
  274.         }
  275.     }
  276.     /**
  277.      * Applies the specified prefix to all the arguments but the first one.
  278.      *
  279.      * @param CommandInterface $command Command instance.
  280.      * @param string           $prefix  Prefix string.
  281.      */
  282.     public static function skipFirst(CommandInterface $command$prefix)
  283.     {
  284.         if ($arguments $command->getArguments()) {
  285.             $length count($arguments);
  286.             for ($i 1$i $length; ++$i) {
  287.                 $arguments[$i] = "$prefix{$arguments[$i]}";
  288.             }
  289.             $command->setRawArguments($arguments);
  290.         }
  291.     }
  292.     /**
  293.      * Applies the specified prefix to all the arguments but the last one.
  294.      *
  295.      * @param CommandInterface $command Command instance.
  296.      * @param string           $prefix  Prefix string.
  297.      */
  298.     public static function skipLast(CommandInterface $command$prefix)
  299.     {
  300.         if ($arguments $command->getArguments()) {
  301.             $length count($arguments);
  302.             for ($i 0$i $length 1; ++$i) {
  303.                 $arguments[$i] = "$prefix{$arguments[$i]}";
  304.             }
  305.             $command->setRawArguments($arguments);
  306.         }
  307.     }
  308.     /**
  309.      * Applies the specified prefix to the keys of a SORT command.
  310.      *
  311.      * @param CommandInterface $command Command instance.
  312.      * @param string           $prefix  Prefix string.
  313.      */
  314.     public static function sort(CommandInterface $command$prefix)
  315.     {
  316.         if ($arguments $command->getArguments()) {
  317.             $arguments[0] = "$prefix{$arguments[0]}";
  318.             if (($count count($arguments)) > 1) {
  319.                 for ($i 1$i $count; ++$i) {
  320.                     switch (strtoupper($arguments[$i])) {
  321.                         case 'BY':
  322.                         case 'STORE':
  323.                             $arguments[$i] = "$prefix{$arguments[++$i]}";
  324.                             break;
  325.                         case 'GET':
  326.                             $value $arguments[++$i];
  327.                             if ($value !== '#') {
  328.                                 $arguments[$i] = "$prefix$value";
  329.                             }
  330.                             break;
  331.                         case 'LIMIT';
  332.                             $i += 2;
  333.                             break;
  334.                     }
  335.                 }
  336.             }
  337.             $command->setRawArguments($arguments);
  338.         }
  339.     }
  340.     /**
  341.      * Applies the specified prefix to the keys of an EVAL-based command.
  342.      *
  343.      * @param CommandInterface $command Command instance.
  344.      * @param string           $prefix  Prefix string.
  345.      */
  346.     public static function evalKeys(CommandInterface $command$prefix)
  347.     {
  348.         if ($arguments $command->getArguments()) {
  349.             for ($i 2$i $arguments[1] + 2; ++$i) {
  350.                 $arguments[$i] = "$prefix{$arguments[$i]}";
  351.             }
  352.             $command->setRawArguments($arguments);
  353.         }
  354.     }
  355.     /**
  356.      * Applies the specified prefix to the keys of Z[INTERSECTION|UNION]STORE.
  357.      *
  358.      * @param CommandInterface $command Command instance.
  359.      * @param string           $prefix  Prefix string.
  360.      */
  361.     public static function zsetStore(CommandInterface $command$prefix)
  362.     {
  363.         if ($arguments $command->getArguments()) {
  364.             $arguments[0] = "$prefix{$arguments[0]}";
  365.             $length = ((int) $arguments[1]) + 2;
  366.             for ($i 2$i $length; ++$i) {
  367.                 $arguments[$i] = "$prefix{$arguments[$i]}";
  368.             }
  369.             $command->setRawArguments($arguments);
  370.         }
  371.     }
  372.     /**
  373.      * Applies the specified prefix to the key of a MIGRATE command.
  374.      *
  375.      * @param CommandInterface $command Command instance.
  376.      * @param string           $prefix  Prefix string.
  377.      */
  378.     public static function migrate(CommandInterface $command$prefix)
  379.     {
  380.         if ($arguments $command->getArguments()) {
  381.             $arguments[2] = "$prefix{$arguments[2]}";
  382.             $command->setRawArguments($arguments);
  383.         }
  384.     }
  385.     /**
  386.      * Applies the specified prefix to the key of a GEORADIUS command.
  387.      *
  388.      * @param CommandInterface $command Command instance.
  389.      * @param string           $prefix  Prefix string.
  390.      */
  391.     public static function georadius(CommandInterface $command$prefix)
  392.     {
  393.         if ($arguments $command->getArguments()) {
  394.             $arguments[0] = "$prefix{$arguments[0]}";
  395.             $startIndex $command->getId() === 'GEORADIUS' 4;
  396.             if (($count count($arguments)) > $startIndex) {
  397.                 for ($i $startIndex$i $count; ++$i) {
  398.                     switch (strtoupper($arguments[$i])) {
  399.                         case 'STORE':
  400.                         case 'STOREDIST':
  401.                             $arguments[$i] = "$prefix{$arguments[++$i]}";
  402.                             break;
  403.                     }
  404.                 }
  405.             }
  406.             $command->setRawArguments($arguments);
  407.         }
  408.     }
  409. }