Completed
Push — 8.x-2.x ( 74e505...ec080d )
by Frédéric G.
03:07
created

OverviewController   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 316
Duplicated Lines 11.71 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 37
loc 316
rs 10
wmc 19
lcom 1
cbo 5

10 Methods

Rating   Name   Duplication   Size   Complexity  
A build() 11 11 2
A buildMainTable() 9 9 1
A buildMainTableHeader() 0 12 1
A buildMainTableRows() 0 23 2
A create() 0 21 1
A getEventLink() 0 21 3
B getEventSource() 0 38 6
A getRowData() 0 14 1
A getTop() 0 4 1
A __construct() 17 17 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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