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

OverviewController::getEventSource()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 23
nc 6
nop 1
dl 0
loc 36
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\mongodb_watchdog\Controller;
4
5
use Drupal\Component\Utility\SafeMarkup;
6
use Drupal\Component\Utility\Unicode;
7
use Drupal\Core\Config\ImmutableConfig;
8
use Drupal\Core\Datetime\DateFormatterInterface;
9
use Drupal\Core\Extension\ModuleHandlerInterface;
10
use Drupal\Core\Form\FormBuilderInterface;
11
use Drupal\Core\Link;
12
use Drupal\Core\Logger\RfcLogLevel;
13
use Drupal\mongodb_watchdog\Event;
14
use Drupal\mongodb_watchdog\EventTemplate;
15
use Drupal\mongodb_watchdog\Form\OverviewFilterForm;
16
use Drupal\mongodb_watchdog\Logger;
17
use Psr\Log\LogLevel;
18
use Psr\Log\LoggerInterface;
19
use Symfony\Component\DependencyInjection\ContainerInterface;
20
use Symfony\Component\HttpFoundation\Request;
21
22
/**
23
 * Class OverviewController provides the main MongoDB Watchdog report page.
24
 */
25
class OverviewController extends ControllerBase {
26
  const EVENT_TYPE_MAP = [
27
    'typeMap' => [
28
      'array' => 'array',
29
      'document' => 'array',
30
      'root' => 'Drupal\mongodb_watchdog\Event',
31
    ],
32
  ];
33
  const SEVERITY_PREFIX = 'mongodb_watchdog__severity_';
34
  const SEVERITY_CLASSES = [
35
    RfcLogLevel::DEBUG => self::SEVERITY_PREFIX . LogLevel::DEBUG,
36
    RfcLogLevel::INFO => self::SEVERITY_PREFIX . LogLevel::INFO,
37
    RfcLogLevel::NOTICE => self::SEVERITY_PREFIX . LogLevel::NOTICE,
38
    RfcLogLevel::WARNING => self::SEVERITY_PREFIX . LogLevel::WARNING,
39
    RfcLogLevel::ERROR => self::SEVERITY_PREFIX . LogLevel::ERROR,
40
    RfcLogLevel::CRITICAL => self::SEVERITY_PREFIX . LogLevel::CRITICAL,
41
    RfcLogLevel::ALERT => self::SEVERITY_PREFIX . LogLevel::ALERT,
42
    RfcLogLevel::EMERGENCY => self::SEVERITY_PREFIX . LogLevel::EMERGENCY,
43
  ];
44
45
  /**
46
   * The core date.formatter service.
47
   *
48
   * @var \Drupal\Core\Datetime\DateFormatterInterface
49
   */
50
  protected $dateFormatter;
51
52
  /**
53
   * The form builder service.
54
   *
55
   * @var \Drupal\Core\Form\FormBuilderInterface
56
   */
57
  protected $formBuilder;
58
59
  /**
60
   * The module handler service.
61
   *
62
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
63
   */
64
  protected $moduleHandler;
65
66
  /**
67
   * The length of the disk path to DRUPAL_ROOT.
68
   *
69
   * @var int
70
   *
71
   * @see \Drupal\mongodb_watchdog\Controller\OverviewController::getEventSource()
72
   */
73
  protected $rootLength;
74
75
  /**
76
   * Controller constructor.
77
   *
78
   * @param \Psr\Log\LoggerInterface $logger
79
   *   The logger service, to log intervening events.
80
   * @param \Drupal\mongodb_watchdog\Logger $watchdog
81
   *   The MongoDB logger, to load stored events.
82
   * @param \Drupal\Core\Config\ImmutableConfig $config
83
   *   The module configuration.
84
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
85
   *   A module handler.
86
   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
87
   *   The form builder service.
88
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
89
   *   The core date_formatter service.
90
   */
91
  public function __construct(
92
    LoggerInterface $logger,
93
    Logger $watchdog,
94
    ImmutableConfig $config,
95
    ModuleHandlerInterface $module_handler,
96
    FormBuilderInterface $form_builder,
97
    DateFormatterInterface $date_formatter) {
98
    parent::__construct($logger, $watchdog, $config);
99
100
    $this->dateFormatter = $date_formatter;
101
    $this->formBuilder = $form_builder;
102
    $this->moduleHandler = $module_handler;
103
104
    // Add terminal "/".
105
    $this->rootLength = Unicode::strlen(DRUPAL_ROOT);
106
107
  }
108
109
  /**
110
   * Controller.
111
   *
112
   * @return array
113
   *   A render array.
114
   */
115
  public function build(Request $request) {
116
    $page = $this->setupPager($request);
117
118
    $ret = [
119
      'filter_form' => $this->formBuilder->getForm('Drupal\mongodb_watchdog\Form\OverviewFilterForm'),
120
      'rows' => $this->buildRows($page),
121
      'pager' => [
122
        '#type' => 'pager',
123
      ],
124
      '#attached' => [
125
        'library' => ['mongodb_watchdog/styling'],
126
      ],
127
    ];
128
129
    return $ret;
130
  }
131
132
  /**
133
   * Build a table from the event rows.
134
   *
135
   * @param int $page
136
   *   The number of the page to display.
137
   *
138
   * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,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...
139
   *   A render array.
140
   */
141
  public function buildRows($page) {
142
    $header = [
143
      t('#'),
144
      t('Latest'),
145
      t('Severity'),
146
      t('Type'),
147
      t('Message'),
148
      t('Source'),
149
    ];
150
    $rows = [];
151
    $levels = RfcLogLevel::getLevels();
152
    $filters = $_SESSION[OverviewFilterForm::SESSION_KEY] ?? NULL;
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
153
    $skip = $page * $this->itemsPerPage;
154
    $limit = $this->itemsPerPage;
155
    $cursor = $this->watchdog->templates($filters['type'] ?? [], $filters['severity'] ?? [], $skip, $limit);
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
156
157
    /** @var \Drupal\mongodb_watchdog\EventTemplate $template */
158
    foreach ($cursor as $template) {
159
      $row = [];
160
      $row[] = $template->count;
161
      $row[] = $this->dateFormatter->format($template->changed, 'short');
162
      $row[] = [
163
        'class' => static::SEVERITY_CLASSES[$template->severity],
164
        'data' => $levels[$template->severity],
165
      ];
166
      $row[] = $template->type;
167
      $row[] = $this->getEventLink($template);
168
      $row[] = [
169
        'data' => $this->getEventSource($template, $row),
170
      ];
171
172
      $rows[] = $row;
173
    }
174
175
    $ret = [
176
      '#type' => 'table',
177
      '#header' => $header,
178
      '#rows' => $rows,
179
    ];
180
181
    return $ret;
182
  }
183
184
  /**
185
   * {@inheritdoc}
186
   */
187
  public static function create(ContainerInterface $container) {
188
    /** @var \Psr\Log\LoggerInterface $logger */
189
    $logger = $container->get('logger.channel.mongodb_watchdog');
190
191
    /** @var \Drupal\mongodb_watchdog\Logger $watchdog */
192
    $watchdog = $container->get('mongodb.logger');
193
194
    /** @var \Drupal\Core\Config\ImmutableConfig $config */
195
    $config = $container->get('config.factory')->get('mongodb_watchdog.settings');
196
197
    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
198
    $date_formatter = $container->get('date.formatter');
199
200
    /** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
201
    $form_builder = $container->get('form_builder');
202
203
    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
204
    $module_handler = $container->get('module_handler');
205
206
    return new static($logger, $watchdog, $config, $module_handler, $form_builder, $date_formatter);
207
  }
208
209
  /**
210
   * Build the link to the event or top report for the event template.
211
   *
212
   * @param \Drupal\mongodb_watchdog\EventTemplate $template
213
   *   The event template for which to buildl the link.
214
   *
215
   * @return string
216
   *   An internal link in string form.
217
   */
218
  protected function getEventLink(EventTemplate $template) {
219
    switch ($template->type) {
220
      case 'page not found':
1 ignored issue
show
introduced by
Expected 1 space before ":"; 0 found
Loading history...
221
        $cell = Link::createFromRoute(t('( Top 404 )'), 'mongodb_watchdog.reports.top404');
222
        break;
223
224
      case 'access denied':
1 ignored issue
show
introduced by
Expected 1 space before ":"; 0 found
Loading history...
225
        $cell = Link::createFromRoute(t('( Top 403 )'), 'mongodb_watchdog.reports.top403');
226
        break;
227
228
      default:
1 ignored issue
show
Coding Style introduced by
Blank lines are not allowed after DEFAULT statements
Loading history...
introduced by
Expected 1 space before ":"; 0 found
Loading history...
229
        // Limited-length message.
230
        $message = Unicode::truncate(strip_tags(SafeMarkup::format($template->message, [])), 56, TRUE, TRUE);
231
        $cell = Link::createFromRoute($message, 'mongodb_watchdog.reports.detail', [
232
          'event_template' => $template->_id,
233
        ]);
234
        break;
235
    }
236
237
    return $cell;
238
  }
239
240
  /**
241
   * Get the location in source code where the event was logged.
242
   *
243
   * @param \Drupal\mongodb_watchdog\EventTemplate $template
244
   *   The template for which to find a source location.
245
   *
246
   * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be string|array<string,string|array>?

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...
247
   *   A render array for the source location, possibly empty or wrong.
248
   */
249
  protected function getEventSource(EventTemplate $template) {
250
    if (in_array($template->type, TopController::TYPES)) {
251
      return '';
252
    }
253
254
    $event_collection = $this->watchdog->eventCollection($template->_id);
255
    $event = $event_collection->findOne([], static::EVENT_TYPE_MAP);
256
    if (!($event instanceof Event)) {
257
      return '';
258
    }
259
260
    $file = $event->variables['%file'] ?? '';
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
261
    if ($file && strncmp($file, DRUPAL_ROOT, $this->rootLength) === 0) {
262
      $hover = Unicode::substr($file, $this->rootLength + 1);
263
      $file = Unicode::truncate(basename($file), 30);
264
    }
265
    else {
266
      $hover = NULL;
267
    }
268
269
    $line = $event->variables['%line'] ?? NULL;
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
270
    $cell = [
271
      '#type' => 'html_tag',
272
      '#tag' => 'span',
273
      '#value' => "${file}#${line}",
274
    ];
275
276
    if ($hover) {
277
      $cell['#attributes'] = [
278
        'class' => 'mongodb_watchdog__code_path',
279
        'title' => $hover,
280
      ];
281
    }
282
283
    return $cell;
284
  }
285
286
  /**
287
   * Set up the pager.
288
   *
289
   * @param \Symfony\Component\HttpFoundation\Request $request
290
   *   The current request.
291
   *
292
   * @return int
293
   *   The number of the page to display, starting at 0.
294
   */
295 View Code Duplication
  public function setupPager(Request $request) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
296
    $count = $this->watchdog->templatesCount();
297
    $height = $this->itemsPerPage;
298
    pager_default_initialize($count, $height);
299
300
    $page = intval($request->query->get('page'));
301
    if ($page < 0) {
302
      $page = 0;
303
    }
304
    else {
305
      $page_max = intval(min(ceil($count / $height), PHP_INT_MAX) - 1);
306
      if ($page > $page_max) {
307
        $page = $page_max;
308
      }
309
    }
310
311
    return $page;
312
  }
313
314
}
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...
315