Completed
Pull Request — 8.x-2.x (#5)
by Frédéric G.
03:20
created

modules/mongodb_watchdog/mongodb_watchdog.admin.inc::mongodb_watchdog_event()   F

Complexity

Conditions 10
Paths 288

Size

Total Lines 101
Code Lines 80

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 80
c 2
b 0
f 0
nc 288
nop 1
dl 0
loc 101
rs 3.1304

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
 * @file
4
 *   Administrative page callbacks for the Database Logging module.
5
 */
6
7
use Drupal\Core\Logger\RfcLogLevel;
8
9
/**
10
 * Display watchdogs entry details in MongoDB.
11
 *
12
 * @param array $dblog
13
 */
14
function mongodb_watchdog_event($dblog) {
15
  $severity = watchdog_severity_levels();
16
  $rows = array(
17
    array(
18
      array('data' => t('Type'), 'header' => TRUE),
19
      t($dblog['type']),
20
    ),
21
    array(
22
      array('data' => t('Severity'), 'header' => TRUE),
23
      $severity[$dblog['severity']],
24
    ),
25
    array(
26
      array('data' => t('Function'), 'header' => TRUE),
27
      isset($dblog['function']) ? $dblog['function'] : '',
28
    ),
29
    array(
30
      array('data' => t('File'), 'header' => TRUE),
31
      isset($dblog['file']) ? $dblog['file'] : '',
32
    ),
33
    array(
34
      array('data' => t('Line'), 'header' => TRUE),
35
      isset($dblog['line']) ? $dblog['line'] : '',
36
    ),
37
    array(
38
      array('data' => t('Count'), 'header' => TRUE),
39
      isset($dblog['count']) ? $dblog['count'] : '',
40
    ),
41
  );
42
  $build['reports'] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$build was never initialized. Although not strictly required by PHP, it is generally a good practice to add $build = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
43
    '#type' => 'markup',
44
    '#markup' => l(t('Return to log report'), 'admin/reports/mongodb'),
45
  );
46
  $build['mongodb_watchdog_event_table']['header'] = array(
47
    '#theme' => 'table',
48
    '#rows' => $rows,
49
    '#attributes' => array('class' => array('dblog-event')),
50
  );
51
  // @todo: the count is unreliable, so just get the actual number of entries.
52
//$total = min($dblog['count'], variable_get('mongodb_watchdog_items', 10000));
53
  $collection = mongodb_collection(variable_get('mongodb_watchdog', 'watchdog'));
54
  $collection = $collection->db->selectCollection('watchdog_event_' . $dblog['_id']);
55
  $total = $collection->count();
56
  $limit = 20;
57
  $pagenumber = mongodb_watchdog_pager_init(0, $limit, $total);
58
  $result = $collection
59
    ->find()
60
    ->skip($pagenumber * $limit)
61
    ->limit($limit)
62
    ->sort(array('$natural' => -1));
63
  $severity = watchdog_severity_levels();
0 ignored issues
show
Unused Code introduced by
$severity is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
64
  $rows = array();
65
  $header = array(
66
    array('data' => t('Date'), 'header' => TRUE),
67
    array('data' => t('User'), 'header' => TRUE),
68
    array('data' => t('Location'), 'header' => TRUE),
69
    array('data' => t('Referrer'), 'header' => TRUE),
70
    array('data' => t('Hostname'), 'header' => TRUE),
71
    array('data' => t('Message'), 'header' => TRUE),
72
    array('data' => t('Operations'), 'header' => TRUE),
73
  );
74
  foreach ($result as $event) {
75
    if (isset($event['wd-user'])) {
76
      $account = $event['wd-user'];
77
      unset($event['wd-user']);
78
      $ip = $dblog['ip'];
79
      $request_uri = $dblog['request_uri'];
80
      $referer = $dblog['referer'];
81
      $link = $dblog['link'];
82
      $dblog['variables'] = $event;
83
    }
84
    else {
85
      $account = $event['user'];
86
      $ip = $event['ip'];
87
      $request_uri = $event['request_uri'];
88
      $referer = $event['referer'];
89
      $link = $event['link'];
90
      $dblog['variables'] = $event['variables'];
91
    }
92
    $rows[] = array(
93
      format_date($event['timestamp'], 'short'),
94
      l($account['name'], 'user/' . $account['uid']),
95
      $request_uri ? l(truncate_utf8(basename(($request_uri)), 20), $request_uri) : '',
96
      $referer ? l(truncate_utf8(basename(($referer)), 20), $referer) : '',
97
      check_plain($ip),
98
      _mongodb_watchdog_format_message($dblog),
99
      $link,
100
    );
101
  }
102
  $build['mongodb_watchdog_event_table']['messages'] = array(
103
    '#theme' => 'table',
104
    '#header' => $header,
105
    '#rows' => $rows,
106
  );
107
  if ($total > $limit) {
108
    $build['mongodb_watchdog_event_table']['pager'] = array(
109
      '#theme' => 'pager',
110
    );
111
112
  }
113
  return $build;
114
}
115
116
/**
117
 * Initialize the global pager variables for use in a mongodb_watchdog event list.
118
 *
119
 * @param int $element
120
 * @param int $limit
121
 * @param int $total
122
 * 
123
 * @return int
124
 */
125
function mongodb_watchdog_pager_init($element, $limit, $total) {
126
  global $pager_page_array, $pager_total, $pager_total_items;
127
128
  // Initialize pager, see pager.inc.
129
  $page = isset($_GET['page']) ? $_GET['page'] : '';
130
  $pager_page_array = explode(',', $page);
131
  if (!isset($pager_page_array[$element])) {
132
    $pager_page_array[$element] = 0;
133
  }
134
  $pager_total_items[$element] = $total;
135
  $pager_total[$element] = ceil($pager_total_items[$element] / $limit);
136
  $pager_page_array[$element] = max(0, min((int) $pager_page_array[$element], ((int) $pager_total[$element]) - 1));
137
  return isset($pager_page_array[$element]) ? $pager_page_array[$element] : 0;
138
}
139
140
/**
141
 * Formats a log message for display.
142
 *
143
 * @param $dblog
144
 *   An object with at least the message and variables properties
145
 *
146
 * @return string
147
 */
148
function _mongodb_watchdog_format_message($dblog) {
149
  // Legacy messages and user specified text
150
  if (!isset($dblog['variables'])) {
151
    return $dblog['message'];
152
  }
153
  // Message to translate with injected variables
154
  return t($dblog['message'], $dblog['variables']);
155
}
156
157
/**
158
 * Build the filter form.
159
 *
160
 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
161
 *   A form array
162
 */
163
function mongodb_watchdog_filter_form($form) {
164
  $filters = mongodb_watchdog_filters();
165
166
  $form['filters'] = array(
167
    '#type' => 'fieldset',
168
    '#title' => t('Filter log messages'),
169
    '#collapsible' => TRUE,
170
    '#collapsed' => empty($_SESSION),
171
    '#attached' => array(
172
      'css' => array(
173
        drupal_get_path('module', 'mongodb_watchdog') . '/mongodb_watchdog.css',
174
    )),
175
  );
176
177
  foreach ($filters as $key => $filter) {
178
    $form['filters']['status'][$key] = array(
179
      '#title' => check_plain($filter['title']),
180
      '#type' => 'select',
181
      '#multiple' => TRUE,
182
      '#size' => 8,
183
      '#options' => $filter['options'],
184
    );
185
    if (!empty($_SESSION['mongodb_watchdog_overview_filter'][$key])) {
186
      $form['filters']['status'][$key]['#default_value'] = $_SESSION['mongodb_watchdog_overview_filter'][$key];
187
    }
188
  }
189
190
  $form['filters']['buttons']['submit'] = array(
191
    '#type' => 'submit',
192
    '#value' => t('Filter'),
193
  );
194
  if (!empty($_SESSION['mongodb_watchdog_overview_filter'])) {
195
    $form['filters']['buttons']['reset'] = array(
196
      '#type' => 'submit',
197
      '#value' => t('Reset')
198
    );
199
  }
200
201
  return $form;
202
}
203
204
/**
205
 * Validate result from mongodb_watchdog administration filter form.
206
 */
207
function mongodb_watchdog_filter_form_validate($form, &$form_state) {
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
208
  if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
209
    form_set_error('type', t('You must select something to filter by.'));
210
  }
211
}
212
213
/**
214
 * Process result from mongodb_watchdog administration filter form.
215
 */
216
function mongodb_watchdog_filter_form_submit($form, &$form_state) {
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
217
  $op = $form_state['values']['op'];
218
  $filters = mongodb_watchdog_filters();
219
  switch ($op) {
220
    case t('Filter'):
221
      foreach ($filters as $name => $filter) {
222
        if (isset($form_state['values'][$name])) {
223
          $_SESSION['mongodb_watchdog_overview_filter'][$name] = $form_state['values'][$name];
224
        }
225
      }
226
      break;
227
228
    case t('Reset'):
229
      $_SESSION['mongodb_watchdog_overview_filter'] = array();
230
      break;
231
  }
232
  return 'admin/reports/mongodb';
233
}
234
235
/**
236
 * Gets all available filter types.
237
 *
238
 * @return array
239
 *   An array of message type names.
240
 */
241
function _mongodb_watchdog_get_message_types() {
242
  // As of version 1.0.1, the PHP driver doesn't expose the 'distinct' command.
243
  $collection = mongodb_collection(variable_get('mongodb_watchdog', 'watchdog'));
244
  $result = $collection->db->command(array('distinct' => $collection->getName(), 'key' => 'type'));
0 ignored issues
show
Bug introduced by
The method getName does only exist in MongoCollection, but not in MongoDebugCollection and MongoDummy.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
245
  return $result['values'];
246
}
247
248
/**
249
 * Return form for mongodb_watchdog clear button.
250
 *
251
 * @ingroup forms
252
 * @see dblog_clear_log_submit()
253
 *
254
 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
255
 *   A form array.
256
 */
257
function mongodb_watchdog_clear_log_form($form) {
258
  $form['mongodb_watchdog_clear'] = array(
259
    '#type' => 'fieldset',
260
    '#title' => t('Clear log messages'),
261
    '#description' => t('This will permanently remove the log messages from the database.'),
262
    '#collapsible' => TRUE,
263
    '#collapsed' => TRUE,
264
  );
265
266
  $form['mongodb_watchdog_clear']['clear'] = array(
267
    '#type' => 'submit',
268
    '#value' => t('Clear log messages'),
269
    '#submit' => array('mongodb_watchdog_clear_log_submit'),
270
  );
271
272
  return $form;
273
}
274
275
/**
276
 * Submit callback: clear database with log messages.
277
 */
278
function mongodb_watchdog_clear_log_submit() {
279
  try {
280
    // Drop the watchdog collection.
281
    $collection = mongodb_collection(variable_get('mongodb_watchdog', 'watchdog'));
282
    $collection->db->dropCollection($collection->getName());
0 ignored issues
show
Bug introduced by
The method getName does only exist in MongoCollection, but not in MongoDebugCollection and MongoDummy.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
283
284
    // Recreate the indexes.
285
    module_load_include('install', 'mongodb_watchdog');
286
    mongodb_watchdog_ensure_indexes();
287
288
    // Drop the event collections.
289
    foreach ($collection->db->listCollections() as $table) {
290
      $parts = explode('.', $table);
291
      if (substr($parts[1], 0, 15) == 'watchdog_event_') {
292
        $collection->db->dropCollection($table);
293
      }
294
    }
295
296
    drupal_set_message(t('MongoDB log cleared.'));
297
  }
298
  catch (Exception $e) {
299
    drupal_set_message(t('An error occured while clearing the MongoDB log.'), 'error');
300
  }
301
}
302
303
/**
304
 * Build a MongoDB query based on the selected filters.
305
 *
306
 * Refer to the @link https://jira.mongodb.org/browse/PHP-1051 Mongo Issue regarding the $in value @endlink
307
 * Refer to the @link https://jira.mongodb.org/browse/PHP-104 Mongo Issue regarding numeric keys on objects @endlink
308
 * @return array
309
 *   An array to build a MongoDB query.
310
 */
311
function mongodb_watchdog_build_filter_query() {
312
  if (empty($_SESSION['mongodb_watchdog_overview_filter'])) {
313
    return array();
314
  }
315
316
  // Build query.
317
  $where = $args = array();
0 ignored issues
show
Unused Code introduced by
$args is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Unused Code introduced by
$where is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
318
  $types = $_SESSION['mongodb_watchdog_overview_filter']['type'] ? $_SESSION['mongodb_watchdog_overview_filter']['type'] : NULL;
319
  $severities = $_SESSION['mongodb_watchdog_overview_filter']['severity'] ? $_SESSION['mongodb_watchdog_overview_filter']['severity'] : NULL;
320
321
  $find = array();
322
  if ($types) {
323
    $find['type'] = array('$in' => array_values($types));
324
  }
325
  if ($severities) {
326
    // MongoDB is picky about types, ensure the severities are all integers.
327
    $find['severity'] = array('$in' => array_values(array_map('intval', $severities)));
328
  }
329
  return $find;
330
}
331