QueryCommand::execute()   F
last analyzed

Complexity

Conditions 25
Paths > 20000

Size

Total Lines 118
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 118
rs 2
c 0
b 0
f 0
cc 25
eloc 67
nc 1048576
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @file QueryCommand.php
5
 * @brief This file contains the QueryCommand class.
6
 * @details
7
 * @author Filippo F. Fadda
8
 */
9
10
11
namespace EoC\CLI\Command;
12
13
14
use Symfony\Component\Console\Input\InputArgument;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
use EoC\Opt\ViewQueryOpts;
20
21
22
/**
23
 * @brief Query a view and outputs the result.
24
 * @nosubgrouping
25
 * @todo Fix a bug when read map and reduce from file.
26
 */
27
class QueryCommand extends AbstractCommand {
28
29
30
  /**
31
   * @brief Configures the command.
32
   */
33
  protected function configure() {
34
    $this->setName("query");
35
    $this->setDescription("Queries a view and outputs the result");
36
37
    $this->addArgument("design-doc/view-name",
38
      InputArgument::REQUIRED,
39
      <<<'DESC'
40
The design document name followed by the view you want query
41
In case of a temporary view, use: _temp_view --map=map.txt --reduce=reduce.txt.
42
The files map.txt and reduce.txt must contains the map and reduce functions implementation.
43
DESC
44
    );
45
46
    $this->addArgument("keys",
47
      InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
48
      <<<'DESC'
49
Used to retrieve just the view rows matching that set of keys
50
Rows are returned in the order of the specified keys.
51
Combining this feature with --include-docs results in the so-called multi-document-fetch feature.
52
Keys must be separated by a space.
53
The value is treated as string unless you specify a type for it.
54
Supported types are string, integer, float and boolean.
55
The argument type can be specified using the syntax %b/false. The slash is followed by the value.
56
    %s - the argument is treated as a string.
57
    %b - the argument is treated as a boolean.
58
    %i - the argument is treated as an integer.
59
    %f - the argument is treated as a float.
60
DESC
61
   );
62
63
    // General options.
64
    $this->addOption("key",
65
      NULL,
66
      InputOption::VALUE_REQUIRED,
67
      <<<'DESC'
68
Returns only documents that match the specified key
69
The value is treated as string unless you specify a type for it.
70
Supported types are string, integer, float and boolean.
71
The argument type can be specified using the syntax %b/false. The slash is followed by the value.
72
    %s - the argument is treated as a string.
73
    %b - the argument is treated as a boolean.
74
    %i - the argument is treated as an integer.
75
    %f - the argument is treated as a float.
76
DESC
77
    );
78
79
    $this->addOption("startkey",
80
      NULL,
81
      InputOption::VALUE_REQUIRED,
82
      <<<'DESC'
83
Defines the first key to be included in the range
84
In case the key is a string, it must be quoted with double quotes and escaped, like --startkey=mykey.
85
To provide a complex key, instead, you must use --startkey=[book,{}].
86
The {} symbol is a wildcard used in JavaScript to create an empty object.
87
Don't put a space between the values of your complex key, because the console will consider them like new arguments.
88
If your key contains a space, remember to backspace it like follows: --startkey=[my\ book,{}].
89
The value is treated as string unless you specify a type for it.
90
Supported types are string, integer, float and boolean.
91
The argument type can be specified using the syntax %b/false. The slash is followed by the value.
92
    %s - the argument is treated as a string.
93
    %b - the argument is treated as a boolean.
94
    %i - the argument is treated as an integer.
95
    %f - the argument is treated as a float.
96
DESC
97
    );
98
99
    $this->addOption("endkey",
100
      NULL,
101
      InputOption::VALUE_REQUIRED,
102
      <<<'DESC'
103
Defines the last key to be included in the range
104
The value is treated as string unless you specify a type for it.
105
Supported types are string, interger, float and boolean.
106
The argument type can be specified using the syntax %b/false. The slash is followed by the value.
107
    %s - the argument is treated as a string.
108
    %b - the argument is treated as a boolean.
109
    %i - the argument is treated as an integer.
110
    %f - the argument is treated as a float.          
111
DESC
112
    );
113
114
    $this->addOption("startkey-docid",
115
      NULL,
116
      InputOption::VALUE_REQUIRED,
117
      "Sets the ID of the document with which to start the range");
118
119
    $this->addOption("endkey-docid",
120
      NULL,
121
      InputOption::VALUE_REQUIRED,
122
      "Sets the ID of the document with which to end the range");
123
124
    $this->addOption("limit",
125
      NULL,
126
      InputOption::VALUE_REQUIRED,
127
      "Limit the number of results");
128
129
    $this->addOption("group-results",
130
      NULL,
131
      InputOption::VALUE_NONE,
132
      "Results should be grouped");
133
134
    $this->addOption("group-level",
135
      NULL,
136
      InputOption::VALUE_REQUIRED,
137
      "Level at which documents should be grouped");
138
139
    $this->addOption("do-not-reduce",
140
      NULL,
141
      InputOption::VALUE_NONE,
142
      "Even if a reduce function is defined for the view, doesn't call it");
143
144
    $this->addOption("include-docs",
145
      NULL,
146
      InputOption::VALUE_NONE,
147
      "Includes documents in the output");
148
149
    $this->addOption("exclude-results",
150
      NULL,
151
      InputOption::VALUE_NONE,
152
      "Don't get any data, but all meta-data for this View; the number of documents in this View for example");
153
154
    $this->addOption("exclude-endkey",
155
      NULL,
156
      InputOption::VALUE_NONE,
157
      "Tells CouchDB to not include end key in the result");
158
159
    $this->addOption("reverse-order",
160
      NULL,
161
      InputOption::VALUE_NONE,
162
      "Reverses order of results");
163
164
    $this->addOption("skip",
165
      NULL,
166
      InputOption::VALUE_REQUIRED,
167
      "Skips the defined number of documents");
168
169
    $this->addOption("include-conflicts",
170
      NULL,
171
      InputOption::VALUE_NONE,
172
      "Includes conflict documents");
173
174
    $this->addOption("include-missing-keys",
175
      NULL,
176
      InputOption::VALUE_NONE,
177
      "Includes all the rows, even if a match for a key is not found");
178
179
180
    // Temporary view options.
181
    $this->addOption("map",
182
      NULL,
183
      InputOption::VALUE_REQUIRED,
184
      "Load map function from this file; to be used with _temp_view only, ignored otherwise");
185
186
    $this->addOption("reduce",
187
      NULL,
188
      InputOption::VALUE_REQUIRED,
189
      "Load reduce function from this file; to be used with _temp_view only, ignored otherwise");
190
191
    $this->addOption("language",
192
      NULL,
193
      InputOption::VALUE_REQUIRED,
194
      "The language used to implement the map and reduce functions; if no specified, PHP assumed");
195
  }
196
197
198
  /**
199
   * @brief Executes the command.
200
   */
201
  protected function execute(InputInterface $input, OutputInterface $output) {
202
    $couch = $this->getConnection();
203
204
    $view = $input->getArgument('design-doc/view-name');
205
206
    if ($input->getArgument('keys')) {
207
      $args = $input->getArgument('keys');
208
209
      $keys = [];
210
      foreach ($args as $key)
211
        $keys[] = $this->castArg($key, FALSE);
0 ignored issues
show
Unused Code introduced by
The call to QueryCommand::castArg() has too many arguments starting with FALSE.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
212
    }
213
    else
214
      $keys = NULL;
215
216
    // Sets the options.
217
    $opts = new ViewQueryOpts();
218
219
    // Key.
220
    if ($key = $input->getOption('key'))
221
      $opts->setKey($this->castArg($key));
222
223
    // Start key.
224
    if ($startkey = $input->getOption('startkey'))
225
      $opts->setStartKey($this->castArg($startkey));
226
227
    // End key.
228
    if ($endkey = $input->getOption('endkey'))
229
      $opts->setEndKey($this->castArg($endkey));
230
231
    // Start doc id.
232
    if ($docId = $input->getOption('startkey-docid'))
233
      $opts->setStartDocId($docId);
234
235
    // End doc id.
236
    if ($docId = $input->getOption('endkey-docid'))
237
      $opts->setEndDocId($docId);
238
239
    // Limit.
240
    $limit = (int)$input->getOption('limit');
241
    if ($limit > 0)
242
      $opts->setLimit($limit);
243
244
    // Group results.
245
    if ($input->getOption('group-results'))
246
      $opts->groupResults();
247
248
    // Sets group level.
249
    $level = (int)$input->getOption('group-level');
250
    if ($level > 0)
251
      $opts->setGroupLevel($level);
252
253
    // Do not reduce.
254
    if ($input->getOption('do-not-reduce'))
255
      $opts->doNotReduce();
256
257
    // Includes docs.
258
    if ($input->getOption('include-docs'))
259
      $opts->includeDocs();
260
261
    // Excludes results.
262
    if ($input->getOption('exclude-results'))
263
      $opts->excludeResults();
264
265
    // Excludes endkey.
266
    if ($input->getOption('exclude-endkey'))
267
      $opts->excludeEndKey();
268
269
    // Reverses order of results.
270
    if ($input->getOption('reverse-order'))
271
      $opts->reverseOrderOfResults();
272
273
    // Skips the defined number of documents.
274
    $skip = (int)$input->getOption('skip');
275
    if ($skip > 0)
276
      $opts->skipDocs($skip);
277
278
    // Includes conflicts.
279
    if ($input->getOption('include-conflicts'))
280
      $opts->includeConflicts();
281
282
    // Includes missing keys.
283
    if ($input->getOption('include-missing-keys'))
284
      $opts->includeMissingKeys();
285
286
    if ($view == "_temp_view") {
287
288
      // Map and reduce functions.
289
      if ($fileName = $input->getOption('map')) {
290
        $map = file_get_contents($fileName);
291
292
        if ($fileName = $input->getOption('reduce'))
293
          $reduce = file_get_contents($fileName);
294
        else
295
          $reduce = "";
296
297
        $language = $input->getOption('language');
298
        if (empty($language))
299
          $language = "php";
300
      }
301
      else
302
        throw new \InvalidArgumentException("You didn't provided the map function.");
303
304
      print_r($couch->queryTempView($this->getDatabase(), $map, $reduce, $keys, $opts, $language));
305
    }
306
    elseif ($view == "_all_docs") {
307
      print_r($couch->queryAllDocs($this->getDatabase(), $keys, $opts));
308
    }
309
    else {
310
      $names = explode('/', $view, 2);
311
312
      if (count($names) == 2)
313
        print_r($couch->queryView($this->getDatabase(), $names[0], $names[1], $keys, $opts));
314
      else
315
        throw new \InvalidArgumentException("You have to specify design-doc/view-name.");
316
    }
317
318
  }
319
320
}