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

mongodb_watchdog/mongodb_watchdog.admin.inc (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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(
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();
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
 * Creates a list of database log administration filters that can be applied.
159
 *
160
 * @return array
0 ignored issues
show
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
 *   Associative array of filters. The top-level keys are used as the form
162
 *   element names for the filters, and the values are arrays with the following
163
 *   elements:
164
 *   - title: Title of the filter.
165
 *   - where: The filter condition.
166
 *   - options: Array of options for the select list for the filter.
167
 */
168
function mongodb_watchdog_filters() {
169
  $filters = array();
170
171
  foreach (_dblog_get_message_types() as $type) {
172
    $types[$type] = t($type);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$types was never initialized. Although not strictly required by PHP, it is generally a good practice to add $types = 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...
173
  }
174
175
  if (!empty($types)) {
176
    $filters['type'] = array(
177
      'title' => t('Type'),
178
      'where' => "w.type = ?",
179
      'options' => $types,
180
    );
181
  }
182
183
  $filters['severity'] = array(
184
    'title' => t('Severity'),
185
    'where' => 'w.severity = ?',
186
    'options' => RfcLogLevel::getLevels(),
187
  );
188
189
  return $filters;
190
}
191
192
/**
193
 * Build the filter form.
194
 *
195
 * @return array
0 ignored issues
show
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...
196
 *   A form array
197
 */
198
function mongodb_watchdog_filter_form($form) {
199
  $filters = mongodb_watchdog_filters();
200
201
  $form['filters'] = array(
202
    '#type' => 'fieldset',
203
    '#title' => t('Filter log messages'),
204
    '#collapsible' => TRUE,
205
    '#collapsed' => empty($_SESSION),
206
    '#attached' => array(
207
      'css' => array(
208
        drupal_get_path('module', 'mongodb_watchdog') . '/mongodb_watchdog.css',
209
    )),
210
  );
211
212 View Code Duplication
  foreach ($filters as $key => $filter) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
213
    $form['filters']['status'][$key] = array(
214
      '#title' => check_plain($filter['title']),
215
      '#type' => 'select',
216
      '#multiple' => TRUE,
217
      '#size' => 8,
218
      '#options' => $filter['options'],
219
    );
220
    if (!empty($_SESSION['mongodb_watchdog_overview_filter'][$key])) {
221
      $form['filters']['status'][$key]['#default_value'] = $_SESSION['mongodb_watchdog_overview_filter'][$key];
222
    }
223
  }
224
225
  $form['filters']['buttons']['submit'] = array(
226
    '#type' => 'submit',
227
    '#value' => t('Filter'),
228
  );
229
  if (!empty($_SESSION['mongodb_watchdog_overview_filter'])) {
230
    $form['filters']['buttons']['reset'] = array(
231
      '#type' => 'submit',
232
      '#value' => t('Reset')
233
    );
234
  }
235
236
  return $form;
237
}
238
239
/**
240
 * Validate result from mongodb_watchdog administration filter form.
241
 */
242
function mongodb_watchdog_filter_form_validate($form, &$form_state) {
243
  if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
244
    form_set_error('type', t('You must select something to filter by.'));
245
  }
246
}
247
248
/**
249
 * Process result from mongodb_watchdog administration filter form.
250
 */
251
function mongodb_watchdog_filter_form_submit($form, &$form_state) {
252
  $op = $form_state['values']['op'];
253
  $filters = mongodb_watchdog_filters();
254
  switch ($op) {
255
    case t('Filter'):
256
      foreach ($filters as $name => $filter) {
257
        if (isset($form_state['values'][$name])) {
258
          $_SESSION['mongodb_watchdog_overview_filter'][$name] = $form_state['values'][$name];
259
        }
260
      }
261
      break;
262
263
    case t('Reset'):
264
      $_SESSION['mongodb_watchdog_overview_filter'] = array();
265
      break;
266
  }
267
  return 'admin/reports/mongodb';
268
}
269
270
/**
271
 * Gets all available filter types.
272
 *
273
 * @return array
274
 *   An array of message type names.
275
 */
276
function _mongodb_watchdog_get_message_types() {
277
  // As of version 1.0.1, the PHP driver doesn't expose the 'distinct' command.
278
  $collection = mongodb_collection(variable_get('mongodb_watchdog', 'watchdog'));
279
  $result = $collection->db->command(array('distinct' => $collection->getName(), 'key' => 'type'));
280
  return $result['values'];
281
}
282
283
/**
284
 * Return form for mongodb_watchdog clear button.
285
 *
286
 * @ingroup forms
287
 * @see dblog_clear_log_submit()
288
 *
289
 * @return array
0 ignored issues
show
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...
290
 *   A form array.
291
 */
292
function mongodb_watchdog_clear_log_form($form) {
293
  $form['mongodb_watchdog_clear'] = array(
294
    '#type' => 'fieldset',
295
    '#title' => t('Clear log messages'),
296
    '#description' => t('This will permanently remove the log messages from the database.'),
297
    '#collapsible' => TRUE,
298
    '#collapsed' => TRUE,
299
  );
300
301
  $form['mongodb_watchdog_clear']['clear'] = array(
302
    '#type' => 'submit',
303
    '#value' => t('Clear log messages'),
304
    '#submit' => array('mongodb_watchdog_clear_log_submit'),
305
  );
306
307
  return $form;
308
}
309
310
/**
311
 * Submit callback: clear database with log messages.
312
 */
313
function mongodb_watchdog_clear_log_submit() {
314
  try {
315
    // Drop the watchdog collection.
316
    $collection = mongodb_collection(variable_get('mongodb_watchdog', 'watchdog'));
317
    $collection->db->dropCollection($collection->getName());
318
319
    // Recreate the indexes.
320
    module_load_include('install', 'mongodb_watchdog');
321
    mongodb_watchdog_ensure_indexes();
322
323
    // Drop the event collections.
324
    foreach ($collection->db->listCollections() as $table) {
325
      $parts = explode('.', $table);
326
      if (substr($parts[1], 0, 15) == 'watchdog_event_') {
327
        $collection->db->dropCollection($table);
328
      }
329
    }
330
331
    drupal_set_message(t('MongoDB log cleared.'));
332
  }
333
  catch (Exception $e) {
334
    drupal_set_message(t('An error occured while clearing the MongoDB log.'), 'error');
335
  }
336
}
337
338
/**
339
 * Build a MongoDB query based on the selected filters.
340
 *
341
 * Refer to the @link https://jira.mongodb.org/browse/PHP-1051 Mongo Issue regarding the $in value @endlink
342
 * Refer to the @link https://jira.mongodb.org/browse/PHP-104 Mongo Issue regarding numeric keys on objects @endlink
343
 * @return array
344
 *   An array to build a MongoDB query.
345
 */
346
function mongodb_watchdog_build_filter_query() {
347
  if (empty($_SESSION['mongodb_watchdog_overview_filter'])) {
348
    return array();
349
  }
350
351
  // Build query.
352
  $where = $args = array();
353
  $types = $_SESSION['mongodb_watchdog_overview_filter']['type'] ? $_SESSION['mongodb_watchdog_overview_filter']['type'] : NULL;
354
  $severities = $_SESSION['mongodb_watchdog_overview_filter']['severity'] ? $_SESSION['mongodb_watchdog_overview_filter']['severity'] : NULL;
355
356
  $find = array();
357
  if ($types) {
358
    $find['type'] = array('$in' => array_values($types));
359
  }
360
  if ($severities) {
361
    // MongoDB is picky about types, ensure the severities are all integers.
362
    $find['severity'] = array('$in' => array_values(array_map('intval', $severities)));
363
  }
364
  return $find;
365
}
366