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

src/Controller/OverviewController.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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