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

Logger   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 571
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 16
Bugs 1 Features 6
Metric Value
c 16
b 1
f 6
dl 0
loc 571
rs 8.3396
wmc 44
lcom 1
cbo 3

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
C enhanceLogEntry() 0 47 8
D log() 0 105 10
A eventCollections() 0 10 1
A eventCollection() 0 10 2
B ensureCappedCollection() 0 29 4
B ensureSchema() 0 45 1
B requestEvents() 0 32 3
A templatesCount() 0 3 1
B requestTemplates() 0 38 4
A trackerCollection() 0 3 1
A templateCollection() 0 3 1
B templates() 0 30 6
A templateTypes() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Logger often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Logger, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Drupal\mongodb_watchdog;
4
5
use Drupal\Component\Render\MarkupInterface;
6
use Drupal\Component\Utility\Unicode;
7
use Drupal\Component\Utility\Xss;
8
use Drupal\Core\Config\ConfigFactoryInterface;
9
use Drupal\Core\Logger\LogMessageParserInterface;
10
use Drupal\Core\Logger\RfcLogLevel;
11
use MongoDB\Database;
12
use MongoDB\Driver\Exception\InvalidArgumentException;
13
use MongoDB\Driver\Exception\RuntimeException;
14
use Psr\Log\AbstractLogger;
15
use Symfony\Component\HttpFoundation\RequestStack;
16
17
/**
18
 * Class Logger is a PSR/3 Logger using a MongoDB data store.
19
 *
20
 * @package Drupal\mongodb_watchdog
21
 */
22
class Logger extends AbstractLogger {
23
  const CONFIG_NAME = 'mongodb_watchdog.settings';
24
25
  const TRACKER_COLLECTION = 'watchdog_tracker';
26
  const TEMPLATE_COLLECTION = 'watchdog';
27
  const EVENT_COLLECTION_PREFIX = 'watchdog_event_';
28
  const EVENT_COLLECTIONS_PATTERN = '^watchdog_event_[[:xdigit:]]{32}$';
29
30
  const LEGACY_TYPE_MAP = [
31
    'typeMap' => [
32
      'array' => 'array',
33
      'document' => 'array',
34
      'root' => 'array',
35
    ],
36
  ];
37
38
  /**
39
   * The logger storage.
40
   *
41
   * @var \MongoDB\Database
42
   */
43
  protected $database;
44
45
  /**
46
   * The limit for the capped event collections.
47
   *
48
   * @var int
49
   */
50
  protected $items;
51
52
  /**
53
   * The minimum logging level.
54
   *
55
   * @var int
56
   */
57
  protected $limit;
58
59
  /**
60
   * The message's placeholders parser.
61
   *
62
   * @var \Drupal\Core\Logger\LogMessageParserInterface
63
   */
64
  protected $parser;
65
66
  /**
67
   * The "requests" setting.
68
   *
69
   * @var int
70
   */
71
  protected $requests;
72
73
  /**
74
   * An array of templates already used in this request.
75
   *
76
   * Used only with request tracking enabled.
77
   *
78
   * @var string[]
79
   */
80
  protected $templates = [];
81
82
  /**
83
   * A sequence number for log events during a request.
84
   *
85
   * @var int
86
   */
87
  protected $sequence = 0;
88
89
  /**
90
   * Logger constructor.
91
   *
92
   * @param \MongoDB\Database $database
93
   *   The database object.
94
   * @param \Drupal\Core\Logger\LogMessageParserInterface $parser
95
   *   The parser to use when extracting message variables.
96
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
97
   *   The core config_factory service.
98
   * @param \Symfony\Component\HttpFoundation\RequestStack $stack
99
   *   The core request_stack service.
100
   */
101
  public function __construct(Database $database, LogMessageParserInterface $parser, ConfigFactoryInterface $config_factory, RequestStack $stack) {
102
    $this->database = $database;
103
    $this->parser = $parser;
104
    $this->requestStack = $stack;
105
106
    $config = $config_factory->get(static::CONFIG_NAME);
107
    $this->limit = $config->get('limit');
108
    $this->items = $config->get('items');
109
    $this->requests = $config->get('requests');
110
    $this->requestTracking = $config->get('request_tracking');
111
  }
112
113
  /**
114
   * Fill in the log_entry function, file, and line.
115
   *
116
   * @param array $log_entry
117
   *   An event information to be logger.
118
   * @param array $backtrace
119
   *   A call stack.
120
   */
121
  protected function enhanceLogEntry(array &$log_entry, array $backtrace) {
122
    // Create list of functions to ignore in backtrace.
123
    static $ignored = array(
124
      'call_user_func_array' => 1,
125
      '_drupal_log_error' => 1,
126
      '_drupal_error_handler' => 1,
127
      '_drupal_error_handler_real' => 1,
128
      'Drupal\mongodb_watchdog\Logger::log' => 1,
129
      'Drupal\Core\Logger\LoggerChannel::log' => 1,
130
      'Drupal\Core\Logger\LoggerChannel::alert' => 1,
131
      'Drupal\Core\Logger\LoggerChannel::critical' => 1,
132
      'Drupal\Core\Logger\LoggerChannel::debug' => 1,
133
      'Drupal\Core\Logger\LoggerChannel::emergency' => 1,
134
      'Drupal\Core\Logger\LoggerChannel::error' => 1,
135
      'Drupal\Core\Logger\LoggerChannel::info' => 1,
136
      'Drupal\Core\Logger\LoggerChannel::notice' => 1,
137
      'Drupal\Core\Logger\LoggerChannel::warning' => 1,
138
    );
139
140
    foreach ($backtrace as $bt) {
141
      if (isset($bt['function'])) {
142
        $function = empty($bt['class']) ? $bt['function'] : $bt['class'] . '::' . $bt['function'];
143
        if (empty($ignored[$function])) {
144
          $log_entry['%function'] = $function;
145
          /* Some part of the stack, like the line or file info, may be missing.
146
           *
147
           * @see http://goo.gl/8s75df
148
           *
149
           * No need to fetch the line using reflection: it would be redundant
150
           * with the name of the function.
151
           */
152
          $log_entry['%line'] = isset($bt['line']) ? $bt['line'] : NULL;
153
          if (empty($bt['file'])) {
154
            $reflected_method = new \ReflectionMethod($function);
155
            $bt['file'] = $reflected_method->getFileName();
156
          }
157
158
          $log_entry['%file'] = $bt['file'];
159
          break;
160
        }
161
        elseif ($bt['function'] == '_drupal_exception_handler') {
162
          $e = $bt['args'][0];
163
          $this->enhanceLogEntry($log_entry, $e->getTrace());
164
        }
165
      }
166
    }
167
  }
168
169
  /**
170
   * {@inheritdoc}
171
   */
172
  public function log($level, $template, array $context = []) {
173
    if ($level > $this->limit) {
174
      return;
175
    }
176
177
    // Convert PSR3-style messages to SafeMarkup::format() style, so they can be
178
    // translated too in runtime.
179
    $message_placeholders = $this->parser->parseMessagePlaceholders($template, $context);
180
181
    // If code location information is all present, as for errors/exceptions,
182
    // then use it to build the message template id.
183
    $type = $context['channel'];
184
    $location_info = [
185
      '%type' => 1,
186
      '@message' => 1,
187
      '%function' => 1,
188
      '%file' => 1,
189
      '%line' => 1,
190
    ];
191
    if (!empty(array_diff_key($location_info, $message_placeholders))) {
192
      $this->enhanceLogEntry($message_placeholders, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10));
193
    }
194
    $file = $message_placeholders['%file'];
195
    $line = $message_placeholders['%line'];
196
    $function = $message_placeholders['%function'];
197
    $key = "${type}:${level}:${file}:${line}:${function}";
198
    $template_id = md5($key);
199
200
    $selector = ['_id' => $template_id];
201
    $update = [
202
      '$inc' => ['count' => 1],
203
      '$set' => [
204
        '_id' => $template_id,
205
        'message' => $template,
206
        'severity' => $level,
207
        'changed' => time(),
208
        'type' => Unicode::substr($context['channel'], 0, 64),
209
      ],
210
    ];
211
    $options = ['upsert' => TRUE];
212
    $template_result = $this->database
213
      ->selectCollection(static::TEMPLATE_COLLECTION)
214
      ->updateOne($selector, $update, $options);
215
216
    // Only insert each template once per request.
217
    if ($this->requestTracking && !isset($this->templates[$template_id])) {
218
      $request_id = $this->requestStack
219
        ->getCurrentRequest()
220
        ->server
221
        ->get('UNIQUE_ID');
222
223
      $this->templates[$template_id] = 1;
224
      $track = [
225
        'request_id' => $request_id,
226
        'template_id' => $template_id,
227
      ];
228
      $this->trackerCollection()->insertOne($track);
229
    }
230
231
    $event_collection = $this->eventCollection($template_id);
232
    if ($template_result->getUpsertedCount()) {
233
      // Capped collections are actually size-based, not count-based, so "items"
234
      // is only a maximum, assuming event documents weigh 1kB, but the actual
235
      // number of items stored may be lower if items are heavier.
236
      // We do not use 'autoindexid' for greater speed, because:
237
      // - it does not work on replica sets,
238
      // - it is deprecated in MongoDB 3.2 and going away in 3.4.
239
      $options = [
240
        'capped' => TRUE,
241
        'size' => $this->items * 1024,
242
        'max' => $this->items,
243
      ];
244
      $this->database->createCollection($event_collection->getCollectionName(), $options);
245
246
      // Do not create this index by default, as its cost is useless if request
247
      // tracking is not enabled.
248
      if ($this->requestTracking) {
249
        $key = ['requestTracking_id' => 1];
250
        $options = ['name' => 'admin-by-request'];
251
        $event_collection->createIndex($key, $options);
252
      }
253
    }
254
255
    foreach ($message_placeholders as &$placeholder) {
256
      if ($placeholder instanceof MarkupInterface) {
0 ignored issues
show
Bug introduced by
The class Drupal\Component\Render\MarkupInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
257
        $placeholder = Xss::filterAdmin($placeholder);
258
      }
259
    }
260
    $event = [
261
      'hostname' => Unicode::substr($context['ip'], 0, 128),
262
      'link' => $context['link'],
263
      'location' => $context['request_uri'],
264
      'referer' => $context['referer'],
265
      'timestamp' => $context['timestamp'],
266
      'user' => ['uid' => $context['uid']],
267
      'variables' => $message_placeholders,
268
    ];
269
    if ($this->requestTracking) {
270
      // Fetch the current request on each event to support subrequest nesting.
271
      $event['requestTracking_id'] = $request_id;
0 ignored issues
show
Bug introduced by
The variable $request_id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
272
      $event['requestTracking_sequence'] = $this->sequence;
273
      $this->sequence++;
274
    }
275
    $event_collection->insertOne($event);
276
  }
277
278
  /**
279
   * List the event collections.
280
   *
281
   * @return \MongoDB\Collection[]
282
   *   The collections with a name matching the event pattern.
283
   */
284
  public function eventCollections() {
285
    echo static::EVENT_COLLECTIONS_PATTERN;
286
    $options = [
287
      'filter' => [
288
        'name' => ['$regex' => static::EVENT_COLLECTIONS_PATTERN],
289
      ],
290
    ];
291
    $result = iterator_to_array($this->database->listCollections($options));
292
    return $result;
293
  }
294
295
  /**
296
   * Return a collection, given its template id.
297
   *
298
   * @param string $template_id
299
   *   The string representation of a template \MongoId.
300
   *
301
   * @return \MongoDB\Collection
302
   *   A collection object for the specified template id.
303
   */
304
  public function eventCollection($template_id) {
305
    $collection_name = static::EVENT_COLLECTION_PREFIX . $template_id;
306
    if (!preg_match('/' . static::EVENT_COLLECTIONS_PATTERN . '/', $collection_name)) {
307
      throw new InvalidArgumentException(t('Invalid watchdog template id `@id`.', [
308
        '@id' => $collection_name,
309
      ]));
310
    }
311
    $collection = $this->database->selectCollection($collection_name);
312
    return $collection;
313
  }
314
315
  /**
316
   * Ensure a collection is capped with the proper size.
317
   *
318
   * @param string $name
319
   *   The collection name.
320
   * @param int $size
321
   *   The collection size cap.
322
   *
323
   * @return \MongoDB\Collection
324
   *   The collection, usable for additional commands like index creation.
325
   *
326
   * @TODO support sharded clusters: convertToCapped does not support them.
327
   *
328
   * @see https://docs.mongodb.com/manual/reference/command/convertToCapped
329
   *
330
   * Note that MongoDB 3.2 still misses a propert exists() command, which is the
331
   * reason for the weird try/catch logic.
332
   *
333
   * @see https://jira.mongodb.org/browse/SERVER-1938
334
   */
335
  public function ensureCappedCollection($name, $size) {
336
    try {
337
      $stats = $this->database->command([
338
        'collStats' => $name,
339
      ], static::LEGACY_TYPE_MAP)->toArray()[0];
340
    }
341
    catch (RuntimeException $e) {
0 ignored issues
show
Bug introduced by
The class MongoDB\Driver\Exception\RuntimeException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
342
      // 59 is expected if the collection was not found. Other values are not.
343
      if ($e->getCode() !== 59) {
344
        throw $e;
345
      }
346
347
      $this->database->createCollection($name);
348
      $stats = $this->database->command([
349
        'collStats' => $name,
350
      ], static::LEGACY_TYPE_MAP)->toArray()[0];
351
    }
352
353
    $collection = $this->database->selectCollection($name);
354
    if (!empty($stats['capped'])) {
355
      return $collection;
356
    }
357
358
    $this->database->command([
359
      'convertToCapped' => $name,
360
      'size' => $size,
361
    ]);
362
    return $collection;
363
  }
364
365
  /**
366
   * Ensure indexes are set on the collections and tracker collection is capped.
367
   *
368
   * First index is on <line, timestamp> instead of <function, line, timestamp>,
369
   * because we write to this collection a lot, and the smaller index on two
370
   * numbers should be much faster to create than one with a string included.
371
   */
372
  public function ensureSchema() {
373
    $trackerCollection = $this->ensureCappedCollection(static::TRACKER_COLLECTION, $this->requests * 1024);
1 ignored issue
show
introduced by
Variable "trackerCollection" is camel caps format. do not use mixed case (camelCase), use lower case and _
Loading history...
374
    $indexes = [
375
      [
376
        'name' => 'tracker-request',
377
        'key' => ['request_id' => 1],
378
      ],
379
    ];
380
    $trackerCollection->createIndexes($indexes);
1 ignored issue
show
introduced by
Variable "trackerCollection" is camel caps format. do not use mixed case (camelCase), use lower case and _
Loading history...
381
382
    $indexes = [
383
      // Index for adding/updating increments.
384
      [
385
        'name' => 'for-increments',
386
        'key' => ['line' => 1, 'changed' => -1],
387
      ],
388
389
      // Index for overview page without filters.
390
      [
391
        'name' => 'overview-no-filters',
392
        'key' => ['changed' => -1],
393
      ],
394
395
      // Index for overview page filtering by type.
396
      [
397
        'name' => 'overview-by-type',
398
        'key' => ['type' => 1, 'changed' => -1],
399
      ],
400
401
      // Index for overview page filtering by severity.
402
      [
403
        'name' => 'overview-by-severity',
404
        'key' => ['severity' => 1, 'changed' => -1],
405
      ],
406
407
      // Index for overview page filtering by type and severity.
408
      [
409
        'name' => 'overview-by-both',
410
        'key' => ['type' => 1, 'severity' => 1, 'changed' => -1],
411
      ],
412
    ];
413
414
    $this->templateCollection()->createIndexes($indexes);
415
416
  }
417
418
  /**
419
   * Return the events having occurred during a given request.
420
   *
421
   * @param string $unsafe_request_id
422
   *   The raw request_id.
423
   *
424
   * @return array<\Drupal\mongodb_watchdog\EventTemplate\Drupal\mongodb_watchdog\Event[]>
425
   *   An array of [template, event] arrays, ordered by occurrence order.
426
   */
427
  public function requestEvents($unsafe_request_id) {
428
    $templates = $this->requestTemplates($unsafe_request_id);
429
    $request_id = "$unsafe_request_id";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $unsafe_request_id instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
430
    $selector = ['requestTracking_id' => $request_id];
431
    $events = [];
432
    $options = [
433
      'typeMap' => [
434
        'array' => 'array',
435
        'document' => 'array',
436
        'root' => '\Drupal\mongodb_watchdog\Event',
437
      ],
438
    ];
439
440
    /**
441
     * @var string $template_id
442
     * @var \Drupal\mongodb_watchdog\EventTemplate $template
443
     */
444
    foreach ($templates as $template_id => $template) {
445
      $event_collection = $this->eventCollection($template_id);
446
      $cursor = $event_collection->find($selector, $options);
447
      /** @var \Drupal\mongodb_watchdog\Event $event */
448
      foreach ($cursor as $event) {
449
        $events[$event->requestTracking_sequence] = [
450
          $template,
451
          $event,
452
        ];
453
      }
454
    }
455
456
    ksort($events);
457
    return $events;
458
  }
459
460
  /**
461
   * Return the number of event templates.
462
   */
463
  public function templatesCount() {
464
    return $this->templateCollection()->count([]);
465
  }
466
467
    /**
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 2 spaces, found 4
Loading history...
468
   * Return an array of templates uses during a given request.
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
469
   *
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
470
   * @param string $unsafe_request_id
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
471
   *   A request "unique_id".
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
472
   *
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
473
   * @return array
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
474
   *   An array of EventTemplate instances.
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
475
   */
0 ignored issues
show
Coding Style introduced by
Expected 5 space(s) before asterisk; 3 found
Loading history...
476
  public function requestTemplates($unsafe_request_id) {
477
    $request_id = "${unsafe_request_id}";
478
    $selector = [
479
      'request_id' => $request_id,
480
    ];
481
482
    $cursor = $this
483
      ->trackerCollection()
484
      ->find($selector, static::LEGACY_TYPE_MAP + [
485
        'projection' => [
486
          '_id' => 0,
487
          'template_id' => 1
488
        ]
489
      ]);
490
    $template_ids = [];
491
    foreach ($cursor as $request) {
492
      $template_ids[] = $request['template_id'];
493
    }
494
    if (empty($template_ids)) {
495
      return [];
496
    }
497
498
    $selector = ['_id' => ['$in' => $template_ids]];
499
    $options = [
500
      'typeMap' => [
501
        'array' => 'array',
502
        'document' => 'array',
503
        'root' => '\Drupal\mongodb_watchdog\EventTemplate',
504
      ],
505
    ];
506
    $templates = [];
507
    $cursor = $this->templateCollection()->find($selector, $options);
508
    /** @var \Drupal\mongodb_watchdog\EventTemplate $template */
509
    foreach ($cursor as $template) {
510
      $templates[$template->_id] = $template;
511
    }
512
    return $templates;
513
  }
514
515
  /**
516
   * Return the request events tracker collection.
517
   *
518
   * @return \MongoDB\Collection
519
   *   The collection.
520
   */
521
  public function trackerCollection() {
522
    return $this->database->selectCollection(static::TRACKER_COLLECTION);
523
  }
524
525
  /**
526
   * Return the event templates collection.
527
   *
528
   * @return \MongoDB\Collection
529
   *   The collection.
530
   */
531
  public function templateCollection() {
532
    return $this->database->selectCollection(static::TEMPLATE_COLLECTION);
533
  }
534
535
  /**
536
   * Return templates matching type and level criteria.
537
   *
538
   * @param string[] $types
539
   *   An array of EventTemplate types. May be a hash.
540
   * @param string[]|int[] $levels
541
   *   An array of severity levels.
542
   * @param int $skip
543
   *   The number of templates to skip before the first one displayed.
544
   * @param int $limit
545
   *   The maximum number of templates to return.
546
   *
547
   * @return \MongoDB\Driver\Cursor
548
   *   A query result for the templates.
549
   */
550
  public function templates(array $types = [], array $levels = [], $skip = 0, $limit = 0) {
551
    $selector = [];
552
    if (!empty($types)) {
553
      $selector['type'] = ['$in' => array_values($types)];
554
    }
555
    if (!empty($levels) && count($levels) !== count(RfcLogLevel::getLevels())) {
556
      // Severity levels come back from the session as strings, not integers.
557
      $selector['severity'] = ['$in' => array_values(array_map('intval', $levels))];
558
    }
559
    $options = [
560
      'sort' => [
561
        'count' => -1,
562
        'changed' => -1,
563
      ],
564
      'typeMap' => [
565
        'array' => 'array',
566
        'document' => 'array',
567
        'root' => '\Drupal\mongodb_watchdog\EventTemplate',
568
      ],
569
    ];
570
    if ($skip) {
571
      $options['skip'] = $skip;
572
    }
573
    if ($limit) {
574
      $options['limit'] = $limit;
575
    }
576
577
    $cursor = $this->templateCollection()->find($selector, $options);
578
    return $cursor;
579
  }
580
581
  /**
582
   * Return the template types actually present in storage.
583
   *
584
   * @return string[]
585
   *   An array of distinct EventTemplate types.
586
   */
587
  public function templateTypes() {
588
    $ret = $this->templateCollection()->distinct('type');
589
    return $ret;
590
  }
591
592
}
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...
593