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

OverviewController::buildMainTableHeader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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