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

OverviewController::overviewRows()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 40
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 30
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 40
rs 8.8571

1 Method

Rating   Name   Duplication   Size   Complexity  
B OverviewController::getEventSource() 0 38 6
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
   * @param \Symfony\Component\HttpFoundation\Request $request
113
   *   The current request.
114
   *
115
   * @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...
116
   *   A render array.
117
   */
118 View Code Duplication
  public function build(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...
119
    $top = $this->getTop();
120
121
    $rows = $this->getRowData($request);
122
    $main = empty($rows)
123
      ? [
124
        '#markup' => t('No event found in logger.'),
125
        '#prefix' => '<div class="mongodb_watchdog__message">',
126
        '#suffix' => '</div>',
127
      ]
128
      : $this->buildMainTable($rows);
129
130
    $ret = $this->buildDefaults($main, $top);
131
    return $ret;
132
  }
133
134
  /**
135
   * Build the main table.
136
   *
137
   * @param \Drupal\mongodb_watchdog\EventTemplate[] $rows
138
   *   The template data.
139
   *
140
   * @return array<string,string|array>
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|\Dru...y<string,array|string>>.

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...
141
   *   A render array for the main table.
142
   */
143 View Code Duplication
  protected function buildMainTable(array $rows) {
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...
144
    $ret = [
145
      '#type' => 'table',
146
      '#header' => $this->buildMainTableHeader(),
147
      '#rows' => $this->buildMainTableRows($rows),
148
    ];
149
    return $ret;
150
  }
151
152
  /**
153
   * Build the main table header.
154
   *
155
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup[]
156
   *   A table header array.
157
   */
158
  protected function buildMainTableHeader() {
159
    $header = [
160
      t('#'),
161
      t('Latest'),
162
      t('Severity'),
163
      t('Type'),
164
      t('Message'),
165
      t('Source'),
166
    ];
167
168
    return $header;
169
  }
170
171
  /**
172
   * Build the main table rows.
173
   *
174
   * @param \Drupal\mongodb_watchdog\EventTemplate[] $templates
175
   *   The template data.
176
   *
177
   * @return array<string,array|string>
178
   *   A render array for a table.
179
   */
180
  public function buildMainTableRows(array $templates) {
181
    $rows = [];
182
    $levels = RfcLogLevel::getLevels();
183
184
    foreach ($templates as $template) {
185
      $row = [];
186
      $row[] = $template->count;
187
      $row[] = $this->dateFormatter->format($template->changed, 'short');
188
      $row[] = [
189
        'class' => static::SEVERITY_CLASSES[$template->severity],
190
        'data' => $levels[$template->severity],
191
      ];
192
      $row[] = $template->type;
193
      $row[] = $this->getEventLink($template);
194
      $row[] = [
195
        'data' => $this->getEventSource($template, $row),
196
      ];
197
198
      $rows[] = $row;
199
    }
200
201
    return $rows;
202
  }
203
204
  /**
205
   * {@inheritdoc}
206
   */
207
  public static function create(ContainerInterface $container) {
208
    /** @var \Psr\Log\LoggerInterface $logger */
209
    $logger = $container->get('logger.channel.mongodb_watchdog');
210
211
    /** @var \Drupal\mongodb_watchdog\Logger $watchdog */
212
    $watchdog = $container->get('mongodb.logger');
213
214
    /** @var \Drupal\Core\Config\ImmutableConfig $config */
215
    $config = $container->get('config.factory')->get('mongodb_watchdog.settings');
216
217
    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
218
    $date_formatter = $container->get('date.formatter');
219
220
    /** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
221
    $form_builder = $container->get('form_builder');
222
223
    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
224
    $module_handler = $container->get('module_handler');
225
226
    return new static($logger, $watchdog, $config, $module_handler, $form_builder, $date_formatter);
227
  }
228
229
  /**
230
   * Build the link to the event or top report for the event template.
231
   *
232
   * @param \Drupal\mongodb_watchdog\EventTemplate $template
233
   *   The event template for which to buildl the link.
234
   *
235
   * @return string
236
   *   An internal link in string form.
237
   */
238
  protected function getEventLink(EventTemplate $template) {
239
    switch ($template->type) {
240
      case 'page not found':
241
        $cell = Link::createFromRoute(t('( Top 404 )'), 'mongodb_watchdog.reports.top404');
242
        break;
243
244
      case 'access denied':
245
        $cell = Link::createFromRoute(t('( Top 403 )'), 'mongodb_watchdog.reports.top403');
246
        break;
247
248
      // Limited-length message.
249
      default:
250
        $message = Unicode::truncate(strip_tags(SafeMarkup::format($template->message, [])), 56, TRUE, TRUE);
251
        $cell = Link::createFromRoute($message, 'mongodb_watchdog.reports.detail', [
252
          'event_template' => $template->_id,
253
        ]);
254
        break;
255
    }
256
257
    return $cell;
258
  }
259
260
  /**
261
   * Get the location in source code where the event was logged.
262
   *
263
   * @param \Drupal\mongodb_watchdog\EventTemplate $template
264
   *   The template for which to find a source location.
265
   *
266
   * @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...
267
   *   A render array for the source location, possibly empty or wrong.
268
   */
269
  protected function getEventSource(EventTemplate $template) {
270
    $cell = ['#markup' => ''];
271
272
    if (in_array($template->type, TopController::TYPES)) {
273
      return $cell;
274
    }
275
276
    $event_collection = $this->watchdog->eventCollection($template->_id);
277
    $event = $event_collection->findOne([], static::EVENT_TYPE_MAP);
278
    if (!($event instanceof Event)) {
279
      return $cell;
280
    }
281
282
    $file = $event->variables['%file'] ?? '';
283
    if ($file && strncmp($file, DRUPAL_ROOT, $this->rootLength) === 0) {
284
      $hover = Unicode::substr($file, $this->rootLength + 1);
285
      $file = Unicode::truncate(basename($file), 30);
286
    }
287
    else {
288
      $hover = NULL;
289
    }
290
291
    $line = $event->variables['%line'] ?? NULL;
292
    $cell = [
293
      '#type' => 'html_tag',
294
      '#tag' => 'span',
295
      '#value' => "${file}#${line}",
296
    ];
297
298
    if ($hover) {
299
      $cell['#attributes'] = [
300
        'class' => 'mongodb_watchdog__code_path',
301
        'title' => $hover,
302
      ];
303
    }
304
305
    return $cell;
306
  }
307
308
  /**
309
   * Obtain the data from the logger.
310
   *
311
   * @param \Symfony\Component\HttpFoundation\Request $request
312
   *   The current request. Needed for paging.
313
   *
314
   * @return \Drupal\mongodb_watchdog\EventTemplate[]
315
   *   The data array.
316
   */
317
  protected function getRowData(Request $request) {
318
    $count = $this->watchdog->templatesCount();
319
    $page = $this->setupPager($request, $count);
320
    $skip = $page * $this->itemsPerPage;
321
    $filters = $_SESSION[OverviewFilterForm::SESSION_KEY] ?? NULL;
322
323
    $limit = $this->itemsPerPage;
324
    $rows = $this->watchdog
325
      ->templates($filters['type'] ?? [], $filters['severity'] ?? [], $skip, $limit)
326
      ->toArray();
327
328
    return $rows;
329
  }
330
331
  /**
332
   * Return the top element.
333
   *
334
   * @return array
335
   *   A render array for the top filter form.
336
   */
337
  protected function getTop() {
338
    $top = $this->formBuilder->getForm('Drupal\mongodb_watchdog\Form\OverviewFilterForm');
339
    return $top;
340
  }
341
342
}
343