BaseCommand::toArguments()   D
last analyzed

Complexity

Conditions 9
Paths 8

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 0
cts 28
cp 0
rs 4.909
c 0
b 0
f 0
cc 9
eloc 20
nc 8
nop 1
crap 90
1
<?php
2
namespace Disque\Command;
3
4
use Disque\Command\Argument\InvalidCommandArgumentException;
5
use Disque\Command\Argument\InvalidOptionException;
6
use Disque\Command\Argument\StringChecker;
7
use Disque\Command\Response\StringResponse;
8
9
abstract class BaseCommand implements CommandInterface
10
{
11
    use StringChecker;
12
13
    /**
14
     * The following constants define the default behavior in case the command
15
     * uses the base method setArguments()
16
     *
17
     * If you override the method completely, then this has no effect.
18
     * @see GetJob
19
     */
20
21
     /**
22
     * The command doesn't accept any arguments
23
     * Eg. INFO
24
     */
25
    const ARGUMENTS_TYPE_EMPTY = 0;
26
27
    /**
28
     * The command accepts a single argument, a string
29
     * Eg. ACKJOB job_id
30
     */
31
    const ARGUMENTS_TYPE_STRING = 1;
32
33
    /**
34
     * The command accepts a single string argument followed by an integer
35
     * Eg. QPEEK queue_name 1
36
     */
37
    const ARGUMENTS_TYPE_STRING_INT = 2;
38
39
    /**
40
     * The command accepts only string arguments and there must be at least one
41
     * Eg. FASTACK job_id1 job_id2 ... job_idN
42
     */
43
    const ARGUMENTS_TYPE_STRINGS = 3;
44
45
    /**
46
     * Available command options
47
     *
48
     * Provide default argument values.
49
     * If the value for the argument is not provided, is null, or is false,
50
     * the option will not be used.
51
     *
52
     * @var array
53
     */
54
    protected $options = [];
55
56
    /**
57
     * Available optional command arguments, and their mapping to options
58
     *
59
     * All available optional arguments must be defined here. If they are
60
     * processed by the method toArguments(), the $this->options variable
61
     * will automatically provide the default values.
62
     *
63
     * @var array
64
     */
65
    protected $availableArguments = [];
66
67
    /**
68
     * Arguments
69
     *
70
     * @var array
71
     */
72
    protected $arguments = [];
73
74
    /**
75
     * Tells the argument types for this command
76
     *
77
     * @var int
78
     */
79
    protected $argumentsType = self::ARGUMENTS_TYPE_STRING;
80
81
    /**
82
     * Tells which class handles the response
83
     *
84
     * @var string
85
     */
86
    protected $responseHandler = StringResponse::class;
87
88
    /**
89
     * Get command
90
     *
91
     * @return string Command
92
     */
93
    abstract public function getCommand();
94
95
    /**
96
     * Tells if this command blocks while waiting for a response, to avoid
97
     * being affected by connection timeouts.
98
     *
99
     * @return bool If true, this command blocks
100
     */
101
    public function isBlocking()
102
    {
103
        return false;
104
    }
105
106
    /**
107
     * Get processed arguments for command
108
     *
109
     * @return array Arguments
110
     */
111
    public function getArguments()
112
    {
113
        return $this->arguments;
114
    }
115
116
    /**
117
     * Set arguments for the command
118
     *
119
     * @param array $arguments Arguments
120
     * @return void
121
     * @throws InvalidCommandArgumentException
122
     */
123
    public function setArguments(array $arguments)
124
    {
125
        switch ($this->argumentsType) {
126
            case self::ARGUMENTS_TYPE_EMPTY:
127
                if (!empty($arguments)) {
128
                    throw new InvalidCommandArgumentException($this, $arguments);
129
                }
130
                $arguments = [];
131
                break;
132
            case self::ARGUMENTS_TYPE_STRING:
133
                $this->checkStringArgument($arguments);
134
                $arguments = [$arguments[0]];
135
                break;
136
            case self::ARGUMENTS_TYPE_STRING_INT:
137
                $this->checkStringArgument($arguments, 2);
138
                if (!is_int($arguments[1])) {
139
                    throw new InvalidCommandArgumentException($this, $arguments);
140
                }
141
                $arguments = [$arguments[0], (int) $arguments[1]];
142
                break;
143
            case self::ARGUMENTS_TYPE_STRINGS:
144
                $this->checkStringArguments($arguments);
145
                break;
146
            // A fallback in case a non-existing argument type is defined.
147
            // This could be prevented by using an Enum as the argument type
148
            default:
149
                throw new InvalidCommandArgumentException($this, $arguments);
150
        }
151
        $this->arguments = $arguments;
152
    }
153
154
    /**
155
     * Parse response
156
     *
157
     * @param mixed $body Response body
158
     * @return mixed Parsed response
159
     * @throws Disque\Command\Response\InvalidResponseException
160
     */
161
    public function parse($body)
162
    {
163
        $responseClass = $this->responseHandler;
164
        $response = new $responseClass();
165
        $response->setCommand($this);
166
        $response->setBody($body);
167
        return $response->parse();
168
    }
169
170
    /**
171
     * Build command arguments out of options
172
     *
173
     * Client-supplied options are amended with the default options defined
174
     * in $this->options. Options whose value is set to null or false are
175
     * ignored
176
     *
177
     * @param array $options Command options
178
     * @return array Command arguments
179
     * @throws InvalidOptionException
180
     */
181
    protected function toArguments(array $options)
182
    {
183
        if (empty($options)) {
184
            return [];
185
        } elseif (!empty(array_diff_key($options, $this->availableArguments))) {
186
            throw new InvalidOptionException($this, $options);
187
        }
188
189
        // Pad, don't overwrite, the client provided options with the default ones
190
        $options += $this->options;
191
        $arguments = [];
192
        foreach ($this->availableArguments as $option => $argument) {
193
            if (!isset($options[$option]) || $options[$option] === false) {
194
                continue;
195
            }
196
197
            $value = $options[$option];
198
            if (is_array($value)) {
199
                foreach ($value as $currentValue) {
200
                    $arguments[] = $argument;
201
                    $arguments[] = $currentValue;
202
                }
203
            } else {
204
                $arguments[] = $argument;
205
                if (!is_bool($value)) {
206
                    $arguments[] = $value;
207
                }
208
            }
209
        }
210
211
        return $arguments;
212
    }
213
}