Completed
Push — 8.x-2.x ( 0f1fa4...cba9bd )
by Frédéric G.
03:05
created

TopController::topSort()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 5
rs 9.4285
1
<?php
2
3
namespace Drupal\mongodb_watchdog\Controller;
4
5
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
6
use Drupal\mongodb_watchdog\Logger;
7
use MongoDB\BSON\Javascript;
8
use MongoDB\Collection;
9
use MongoDB\Database;
10
use Psr\Log\LoggerInterface;
11
use Symfony\Component\DependencyInjection\ContainerInterface;
12
13
/**
14
 * Class TopController implements the Top403/Top404 controllers.
15
 */
16
class TopController implements ContainerInjectionInterface {
17
18
  /**
19
   * The database holding the logger collections.
20
   *
21
   * @var \MongoDB\Database
22
   */
23
  protected $db;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
24
25
  /**
26
   * The logger channel service, used to log events.
27
   *
28
   * @var \Psr\Log\LoggerInterface
29
   */
30
  protected $logger;
31
32
  /**
33
   * The concrete logger instance, used to access data.
34
   *
35
   * @var \Drupal\mongodb_watchdog\Logger
36
   */
37
  protected $watchdog;
38
39
  /**
40
   * TopController constructor.
41
   *
42
   * @param \Psr\Log\LoggerInterface $logger
43
   *   The logger channel service, to log errors occurring.
44
   * @param \Drupal\mongodb_watchdog\Logger $watchdog
45
   *   The MongoDB Logger service, to load the events.
46
   * @param \MongoDB\Database $db
47
   *   Needed because there is no group() command in phplib yet.
48
   *
49
   * @see https://jira.mongodb.org/browse/PHPLIB-177
50
   */
51
  public function __construct(LoggerInterface $logger, Logger $watchdog, Database $db) {
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
52
    $this->db = $db;
53
    $this->logger = $logger;
54
    $this->watchdog = $watchdog;
55
  }
56
57
  /**
58
   * The controller for /admin/reports/mongodb/access-denied.
59
   *
60
   * @return array
61
   *   A render array.
62
   */
63
  public function top403() {
64
    $ret = $this->top('access denied');
65
    return $ret;
66
  }
67
68
  /**
69
   * The controller for /admin/reports/mongodb/page-not-found.
70
   *
71
   * @return array
72
   *   A render array.
73
   */
74
  public function top404() {
75
    $ret = $this->top('page not found');
76
    return $ret;
77
  }
78
79
  /**
80
   * Command wrapper for missing MongoDB group() implementation in PHPlib.
81
   *
82
   * @param \MongoDB\Collection $collection
83
   *   The collection on which to perform the command.
84
   * @param object $key
85
   *   The grouping key.
86
   * @param object $cond
87
   *   The condition.
88
   * @param string $reduce
89
   *   The reducer function: must be valid JavaScript code.
90
   * @param object $initial
91
   *   The initial document.
92
   *
93
   * @return array|void
94
   *   Void in case of error, otherwise an array with the following keys:
95
   *   - waitedMS: time spent waiting
96
   *   - retval: an array of command results, containing at least the key
97
   *   - count: the total number of documents matched
98
   *   - keys: the number of different keys, normally matching count(retval)
99
   *   - ok: 1.0 in case of success.
100
   */
101
  public function group(Collection $collection, $key, $cond, $reduce, $initial) {
102
    $options = [
103
      'typeMap' => [
104
        'array' => 'array',
105
        'document' => 'array',
106
        'root' => 'array',
107
      ],
108
    ];
109
110
    $cursor = $this->db->command([
111
      'group' => [
112
        'ns' => $collection->getCollectionName(),
113
        'key' => $key,
114
        'cond' => $cond,
115
        'initial' => $initial,
116
        '$reduce' => new Javascript($reduce),
117
      ],
118
    ], $options);
119
120
    $ret = $cursor->toArray();
121
    $ret = reset($ret);
122
    return $ret;
123
  }
124
125
  /**
126
   * Callback for usort() to sort top entries returned from a group query.
127
   *
128
   * @param array $x
129
   *   The first value to compare.
130
   * @param array $y
131
   *   The second value to compare.
132
   *
133
   * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
134
   *   The comparison result.
135
   *
136
   * @see \Drupal\mongodb_watchdog\Controller\TopController::top()
137
   */
138
  protected function topSort(array $x, array $y) {
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $x. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $y. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
139
    $cx = $x['count'];
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $cx. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
140
    $cy = $y['count'];
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $cy. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
141
    return $cy - $cx;
142
  }
143
144
  /**
145
   * Generic controller for admin/reports/mongodb/<top report>.
146
   *
147
   * @return array
148
   *   A render array.
149
   */
150
  protected function top($type) {
151
    $ret = [];
152
    $type_param = ['%type' => $type];
153
    $limit = 50;
154
155
    // Safety net.
156
    $types = [
157
      'page not found',
158
      'access denied',
159
    ];
160
    if (!in_array($type, $types)) {
161
      $error = t('Unknown top report type: %type', $type_param);
162
      drupal_set_message($error, 'error');
163
      $this->logger->warning('Unknown top report type: %type', $type_param);
164
      $ret = [
165
        '#markup' => '',
166
      ];
167
      return $ret;
168
    }
169
170
    // Find _id for the error type.
171
    $template_collection = $this->watchdog->templateCollection();
172
    $template = $template_collection->findOne(['type' => $type], ['_id']);
173
174
    // Method findOne() will return NULL if no row is found.
175
    $ret['empty'] = array(
176
      '#markup' => t('No "%type" message found', $type_param),
177
      '#prefix' => '<div class="mongodb-watchdog-message">',
178
      '#suffix' => '</div>',
179
    );
180
    if (empty($template)) {
181
      return $ret;
182
    }
183
184
    // Find occurrences of error type.
185
    $collection_name = $template['_id'];
186
    $event_collection = $this->watchdog->eventCollection($collection_name);
187
188
    $key = ['variables.@uri' => 1];
189
    $cond = [];
190
    $reduce = <<<EOT
191
function (doc, accumulator) { 
192
  accumulator.count++; 
193
}
194
EOT;
195
    $initial = ['count' => 0];
196
    $counts = $this->group($event_collection, $key, $cond, $reduce, $initial);
197
198
    if (empty($counts['ok'])) {
199
      return $ret;
200
    }
201
202
    $counts = $counts['retval'];
203
    usort($counts, [$this, 'topSort']);
204
    $counts = array_slice($counts, 0, $limit);
205
206
    $header = array(
207
      t('#'),
208
      t('Paths'),
209
    );
210
    $rows = array();
211
    foreach ($counts as $count) {
212
      $rows[] = array(
213
        $count['count'],
214
        $count['variables.@uri'],
215
      );
216
    }
217
218
    $ret = array(
219
      '#theme' => 'table',
220
      '#header' => $header,
221
      '#rows' => $rows,
222
    );
223
    return $ret;
224
  }
225
226
  /**
227
   * {@inheritdoc}
228
   */
229
  public static function create(ContainerInterface $container) {
230
    /** @var \Psr\Log\LoggerInterface $logger */
231
    $logger = $container->get('logger.factory')->get('mongodb_watchdog');
232
233
    /** @var \Drupal\mongodb_watchdog\Logger $watchdog */
234
    $watchdog = $container->get('mongodb.logger');
235
236
    /** @var \MongoDB\Database $db */
237
    $db = $container->get('mongodb.watchdog_storage');
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
238
    return new static($logger, $watchdog, $db);
239
  }
240
241
}
0 ignored issues
show
Coding Style introduced by
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
242