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

OverviewController::build()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 16
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
 * 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 core logger channel, to log intervening events.
61
   *
62
   * @var \Psr\Log\LoggerInterface
63
   */
64
  protected $logger;
65
66
  /**
67
   * The module handler service.
68
   *
69
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
70
   */
71
  protected $moduleHandler;
72
73
  /**
74
   * The length of the disk path to DRUPAL_ROOT.
75
   *
76
   * @var int
77
   *
78
   * @see \Drupal\mongodb_watchdog\Controller\OverviewController::getEventSource()
79
   */
80
  protected $rootLength;
81
82
  /**
83
   * The MongoDB logger, to load events.
84
   *
85
   * @var \Drupal\mongodb_watchdog\Logger
86
   */
87
  protected $watchdog;
88
89
  /**
90
   * Controller constructor.
91
   *
92
   * @param \Psr\Log\LoggerInterface $logger
93
   *   The logger service, to log intervening events.
94
   * @param \Drupal\mongodb_watchdog\Logger $watchdog
95
   *   The MongoDB logger, to load stored events.
96
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
97
   *   A module handler.
98
   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
99
   *   The form builder service.
100
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
101
   *   The core date_formatter service.
102
   * @param \Drupal\Core\Config\ImmutableConfig $config
103
   *   The module configuration.
104
   */
105
  public function __construct(
106
    LoggerInterface $logger,
107
    Logger $watchdog,
108
    ModuleHandlerInterface $module_handler,
109
    FormBuilderInterface $form_builder,
110
    DateFormatterInterface $date_formatter,
111
    ImmutableConfig $config) {
112
    parent::__construct($config);
113
    $this->dateFormatter = $date_formatter;
114
    $this->formBuilder = $form_builder;
115
    $this->logger = $logger;
116
    $this->moduleHandler = $module_handler;
117
    $this->watchdog = $watchdog;
118
119
    // Add terminal "/".
120
    $this->rootLength = Unicode::strlen(DRUPAL_ROOT);
121
122
  }
123
124
  /**
125
   * Controller.
126
   *
127
   * @return array
128
   *   A render array.
129
   */
130
  public function build(Request $request) {
131
    $page = $this->setupPager($request);
132
133
    $ret = [
134
      'filter_form' => $this->formBuilder->getForm('Drupal\mongodb_watchdog\Form\OverviewFilterForm'),
135
      'rows' => $this->buildRows($page),
136
      'pager' => [
137
        '#type' => 'pager',
138
      ],
139
      '#attached' => [
140
        'library' => ['mongodb_watchdog/styling'],
141
      ],
142
    ];
143
144
    return $ret;
145
  }
146
147
  /**
148
   * Build a table from the event rows.
149
   *
150
   * @param int $page
151
   *   The number of the page to display.
152
   *
153
   * @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...
154
   *   A render array.
155
   */
156
  public function buildRows($page) {
157
    $header = [
158
      t('#'),
159
      t('Latest'),
160
      t('Severity'),
161
      t('Type'),
162
      t('Message'),
163
      t('Source'),
164
    ];
165
    $rows = [];
166
    $levels = RfcLogLevel::getLevels();
167
    $filters = $_SESSION[OverviewFilterForm::SESSION_KEY] ?? NULL;
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
168
    $skip = $page * $this->itemsPerPage;
169
    $limit = $this->itemsPerPage;
170
    $cursor = $this->watchdog->templates($filters['type'] ?? [], $filters['severity'] ?? [], $skip, $limit);
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
171
172
    /** @var \Drupal\mongodb_watchdog\EventTemplate $template */
173
    foreach ($cursor as $template) {
174
      $row = [];
175
      $row[] = $template->count;
176
      $row[] = $this->dateFormatter->format($template->changed, 'short');
177
      $row[] = [
178
        'class' => static::SEVERITY_CLASSES[$template->severity],
179
        'data' => $levels[$template->severity],
180
      ];
181
      $row[] = $template->type;
182
      $row[] = $this->getEventLink($template);
183
      $row[] = [
184
        'data' => $this->getEventSource($template, $row),
185
      ];
186
187
      $rows[] = $row;
188
    }
189
190
    return [
191
      '#type' => 'table',
192
      '#header' => $header,
193
      '#rows' => $rows,
194
    ];
195
  }
196
197
  /**
198
   * {@inheritdoc}
199
   */
200
  public static function create(ContainerInterface $container) {
201
    /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
202
    $date_formatter = $container->get('date.formatter');
203
204
    /** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
205
    $form_builder = $container->get('form_builder');
206
207
    /** @var \Psr\Log\LoggerInterface $logger */
208
    $logger = $container->get('logger.channel.mongodb_watchdog');
209
210
    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
211
    $module_handler = $container->get('module_handler');
212
213
    /** @var \Drupal\mongodb_watchdog\Logger $logger */
214
    $watchdog = $container->get('mongodb.logger');
215
216
    /** @var \Drupal\Core\Config\ImmutableConfig $config */
217
    $config = $container->get('config.factory')->get('mongodb_watchdog.settings');
218
219
    return new static($logger, $watchdog, $module_handler, $form_builder, $date_formatter, $config);
220
  }
221
222
  /**
223
   * Build the link to the event or top report for the event template.
224
   *
225
   * @param \Drupal\mongodb_watchdog\EventTemplate $template
226
   *   The event template for which to buildl the link.
227
   *
228
   * @return string
229
   *   An internal link in string form.
230
   */
231
  protected function getEventLink(EventTemplate $template) {
232
    switch ($template->type) {
233
      case 'page not found':
1 ignored issue
show
introduced by
Expected 1 space before ":"; 0 found
Loading history...
234
        $cell = Link::createFromRoute(t('( Top 404 )'), 'mongodb_watchdog.reports.top404');
235
        break;
236
237
      case 'access denied':
1 ignored issue
show
introduced by
Expected 1 space before ":"; 0 found
Loading history...
238
        $cell = Link::createFromRoute(t('( Top 403 )'), 'mongodb_watchdog.reports.top403');
239
        break;
240
241
      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...
242
        // Limited-length message.
243
        $message = Unicode::truncate(strip_tags(SafeMarkup::format($template->message, [])), 56, TRUE, TRUE);
244
        $cell = Link::createFromRoute($message, 'mongodb_watchdog.reports.detail', [
245
          'event_template' => $template->_id,
246
        ]);
247
        break;
248
    }
249
250
    return $cell;
251
  }
252
253
  /**
254
   * Get the location in source code where the event was logged.
255
   *
256
   * @param \Drupal\mongodb_watchdog\EventTemplate $template
257
   *   The template for which to find a source location.
258
   *
259
   * @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...
260
   *   A render array for the source location, possibly empty or wrong.
261
   */
262
  protected function getEventSource(EventTemplate $template) {
263
    if (in_array($template->type, TopController::TYPES)) {
264
      return '';
265
    }
266
267
    $event_collection = $this->watchdog->eventCollection($template->_id);
268
    $event = $event_collection->findOne([], static::EVENT_TYPE_MAP);
269
    if (!($event instanceof Event)) {
270
      return '';
271
    }
272
273
    $file = $event->variables['%file'] ?? '';
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
274
    if ($file && strncmp($file, DRUPAL_ROOT, $this->rootLength) === 0) {
275
      $hover = Unicode::substr($file, $this->rootLength + 1);
276
      $file = Unicode::truncate(basename($file), 30);
277
    }
278
    else {
279
      $hover = NULL;
280
    }
281
282
    $line = $event->variables['%line'] ?? NULL;
1 ignored issue
show
introduced by
Expected 1 space after "?"; 0 found
Loading history...
283
    $cell = [
284
      '#type' => 'html_tag',
285
      '#tag' => 'span',
286
      '#value' => "${file}#${line}",
287
    ];
288
289
    if ($hover) {
290
      $cell['#attributes'] = [
291
        'class' => 'mongodb_watchdog__code_path',
292
        'title' => $hover,
293
      ];
294
    }
295
296
    return $cell;
297
  }
298
299
  /**
300
   * Set up the templates pager.
301
   *
302
   * @param \Symfony\Component\HttpFoundation\Request $request
303
   *   The current request.
304
   *
305
   * @return int
306
   *   The number of the page to display, starting at 0.
307
   */
308 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...
309
    $count = $this->watchdog->templatesCount();
310
    $height = $this->itemsPerPage;
311
    pager_default_initialize($count, $height);
312
313
    $page = intval($request->query->get('page'));
314
    if ($page < 0) {
315
      $page = 0;
316
    }
317
    else {
318
      $page_max = intval(min(ceil($count / $height), PHP_INT_MAX) - 1);
319
      if ($page > $page_max) {
320
        $page = $page_max;
321
      }
322
    }
323
324
    return $page;
325
  }
326
327
}
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...
328