Issues (109)

src/EoC/Handler/ViewHandler.php (4 issues)

1
<?php
2
3
/**
4
 * @file ViewHandler.php
5
 * @brief This file contains the ViewHandler class.
6
 * @details
7
 * @author Filippo F. Fadda
8
 */
9
10
11
namespace EoC\Handler;
12
13
14
use Lint\Lint;
15
16
17
/**
18
 * @brief This handler let you create a CouchDB view.
19
 * @details Views are the primary tool used for querying and reporting on CouchDB databases. Views are managed by a
20
 * special server. Default server implementation uses JavaScript, that's why you have to write views in JavaScript
21
 * language. This handler instead let you write your views directly in PHP.\n
22
 * If you have specified 'php' as your design document language, this handler makes a syntax check on your map and
23
 * reduce functions.\n
24
 * To create a permanent view, map and reduce functions must first be saved into special design document. Every design
25
 * document has a special `views` attribute, that stores mandatory map function and an optional reduce function. Using
26
 * this handler you can write these functions directly in PHP.\n
27
 * All the views in one design document are indexed whenever any of them gets queried.
28
 * @nosubgrouping
29
 *
30
 * @cond HIDDEN_SYMBOLS
31
 *
32
 * @property string $name     // The view handler name.
33
 * @property string $language // The programming language used to write map and reduce functions.
34
 * @property string $mapFn    // Stores the map function.
35
 * @property string $reduceFn // Stores the reduce function.
36
 *
37
 * @endcond
38
 *
39
 * @todo: Add support for seq_indexed option.
40
 */
41
final class ViewHandler extends DesignHandler {
42
  const MAP_REGEX = '/function\s*\(\s*\$doc\)\s*use\s*\(\$emit\)\s*\{[\W\w]*\};\z/m';
43
  const MAP_DEFINITION = "function(\$doc) use (\$emit) { ... };";
44
45
  const REDUCE_REGEX = '/function\s*\(\s*\$keys\s*,\s*\$values\,\s*\$rereduce\)\s*\{[\W\w]*\};\z/m';
46
  const REDUCE_DEFINITION = "function(\$keys, \$values, \$rereduce) { ... };";
47
48
  private $options = [];
49
50
  /** @name Properties */
51
  //!@{
0 ignored issues
show
Unused Code Comprehensibility introduced by
100% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
52
53
  //! The view handler name.
54
  private $name;
55
56
  /**
57
   * @brief The programming language used to write map and reduce functions.
58
   * @details This property is used mainly by the Couch::queryTempView() method. In fact, the language is taken from
59
   * the design document where your map and reduce functions have been stored.
60
   */
61
  private $language = "";
62
63
  /**
64
   * @brief Stores the map function.
65
   * @details Contains the function implementation provided by the user. You can have multiple views in a design document
66
   * and for every single view you can have only one map function. The map function is a closure.
67
   * The closure must be declared like:
68
   @code
69
     function($doc) use ($emit) {
70
       ...
71
72
       $emit($key, $value);
73
     };
74
   @endcode
75
   * To emit your record you must call the `$emit` closure.
76
   */
77
  private $mapFn = "";
78
79
  /**
80
   * @brief Stores the reduce function.
81
   * @details Contains the function implementation provided by the user. You can have multiple views in a design document
82
   * and for every single view you can have only one reduce function. The reduce function is a closure.
83
   * The closure must be declared like:
84
   @code
85
     function($keys, $values, $rereduce) {
86
       ...
87
88
     };
89
   @endcode
90
   */
91
  private $reduceFn = "";
92
93
  //!@}
0 ignored issues
show
Unused Code Comprehensibility introduced by
100% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
94
95
96
  /**
97
   * @brief Creates a ViewHandler class instance.
98
   * @param[in] string $name Handler name.
99
   * @param[in] string $language (optional) The map/reduce functions' language.
100
   */
101
  public function __construct($name, $language = "php") {
102
    $this->setName($name);
103
    $this->setLanguage($language);
104
  }
105
106
107
  //! @cond HIDDEN_SYMBOLS
108
109
  public function getName() {
110
    return $this->name;
111
  }
112
113
114
  public function setName($value) {
115
    $this->name = (string)$value;
116
  }
117
118
119
  public function setLanguage($value) {
120
    $this->language = (string)$value;
121
  }
122
123
124
  public static function getSection() {
125
    return 'views';
126
  }
127
128
  //! @endcond
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
129
130
131
  /**
132
   * @brief Resets the options.
133
   */
134
  public function reset() {
135
    unset($this->options);
136
    $this->options = [];
137
138
    $this->mapFn = "";
139
    $this->reduceFn = "";
140
  }
141
142
143
  public function isConsistent() {
144
    return (!empty($this->name) && !empty($this->mapFn)) ? TRUE : FALSE;
145
  }
146
147
148
  /**
149
   * @brief Checks the function definition against a regular expression and use PHP lint to find syntax errors.
150
   * @param[in] string $fnImpl The function's implementation.
151
   * @param[in] string $fnDef The function prototype.
152
   * @param[in] string $fnRegex The regular expression to check the function correctness.
153
   */
154
  public static function checkFn($fnImpl, $fnDef, $fnRegex) {
155
    Lint::checkSourceCode($fnImpl);
156
157
    if (!preg_match($fnRegex, $fnImpl))
158
      throw new \Exception("The \$closure must be defined like: $fnDef");
159
  }
160
161
162
  public function asArray() {
163
    $view = [];
164
    $view['map'] = $this->mapFn;
165
166
    if (!empty($this->language))
167
      $view['language'] = $this->language;
168
169
    if (!empty($this->reduceFn))
170
      $view['reduce'] = $this->reduceFn;
171
172
    if (!empty($this->options))
173
      $view['options'] = $this->options;
174
175
    return $view;
176
  }
177
178
179
  /**
180
   * @brief Makes documents' local sequence numbers available to map functions as a '_local_seq' document property.
181
   */
182
  public function includeLocalSeq() {
183
    $this->options['local_seq'] = 'true';
184
  }
185
186
187
  /**
188
   * @brief Causes map functions to be called on design documents as well as regular documents.
189
   */
190
  public function includeDesignDocs() {
191
    $this->options['include_design'] = 'true';
192
  }
193
194
195
  /**
196
   * @brief Sets the reduce function to the built-in `_count` function provided by CouchDB.
197
   * @details The built-in `_count` reduce function will be probably the most common reduce function you'll use.
198
   * This function returns the number of mapped values in the set.
199
   */
200
  public function useBuiltInReduceFnCount() {
201
    $this->reduceFn = "_count";
202
  }
203
204
205
  /**
206
   * @brief Sets the reduce function to the built-in `_sum` function provided by CouchDB.
207
   * @details The built-in `_sum` reduce function will return a sum of mapped values. As with all reductions, you
208
   * can either get a sum of all values grouped by keys or part of keys. You can control this behaviour when you query
209
   * the view, using an instance of ViewQueryOpts class, in particular with methods ViewQueryOpts::groupResults() and
210
   * ViewQueryOpts::setGroupLevel().
211
   * @warning The built-in `_sum` reduce function requires all mapped values to be numbers.
212
   */
213
  public function useBuiltInReduceFnSum() {
214
    $this->reduceFn = "_sum";
215
  }
216
217
218
  /**
219
   * @brief Sets the reduce function to the built-in `_stats` function provided by CouchDB.
220
   * @details The built-in `_stats` reduce function returns an associative array containing the sum, count, minimum,
221
   * maximum, and sum over all square roots of mapped values.
222
   */
223
  public function useBuiltInReduceFnStats() {
224
    $this->reduceFn = "_stats";
225
  }
226
227
228
  //! @cond HIDDEN_SYMBOLS
229
230
  public function getMapFn() {
231
    return $this->mapFn;
232
  }
233
234
235
  public function setMapFn($value) {
236
    $fn = stripslashes((string)$value);
237
238
    if ($this->language == "php")
239
      self::checkFn($fn, self::MAP_DEFINITION, self::MAP_REGEX);
240
241
    $this->mapFn = $fn;
242
  }
243
244
245
  public function getReduceFn() {
246
    return $this->reduceFn;
247
  }
248
249
250
  public function setReduceFn($value) {
251
    $fn = stripslashes((string)$value);
252
253
    if ($this->language == "php")
254
      self::checkFn($fn, self::REDUCE_DEFINITION, self::REDUCE_REGEX);
255
256
    $this->reduceFn = $fn;
257
  }
258
259
  //! @endcond
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
260
261
}