public function ScanResultFormatter::formatResult in Upgrade Status 8
Same name and namespace in other branches
- 8.3 src/ScanResultFormatter.php \Drupal\upgrade_status\ScanResultFormatter::formatResult()
- 8.2 src/ScanResultFormatter.php \Drupal\upgrade_status\ScanResultFormatter::formatResult()
Format results output for an extension.
Return value
array Build array.
File
- src/
ScanResultFormatter.php, line 94
Class
- ScanResultFormatter
- Format scan results for display or export.
Namespace
Drupal\upgrade_statusCode
public function formatResult(Extension $extension) {
$result = $this
->getRawResult($extension);
$info = $extension->info;
$label = $info['name'] . (!empty($info['version']) ? ' ' . $info['version'] : '');
// This project was not yet scanned or the scan results were removed.
if (empty($result)) {
return [
'#title' => $label,
'data' => [
'#type' => 'markup',
'#markup' => $this
->t('No deprecation scanning data available.'),
],
];
}
if (isset($result['data']['totals'])) {
$project_error_count = $result['data']['totals']['file_errors'];
}
else {
$project_error_count = 0;
}
$build = [
'#title' => $label,
'date' => [
'#type' => 'markup',
'#markup' => '<div class="list-description">' . $this
->t('Scanned on @date.', [
'@date' => $this->dateFormatter
->format($result['date']),
]) . '</div>',
'#weight' => -10,
],
];
if (!empty($result['plans'])) {
$build['plans'] = [
'#type' => 'markup',
'#markup' => '<div class="list-description">' . $result['plans'] . '</div>',
'#weight' => 50,
];
}
// If this project had no known issues found, report that.
if ($project_error_count === 0) {
$build['data'] = [
'#type' => 'markup',
'#markup' => $this
->t('No known issues found.'),
'#weight' => 5,
];
return $build;
}
// Otherwise prepare list of errors in a table.
$table = [
'#type' => 'table',
'#attributes' => [
'class' => [
'upgrade-status-summary',
],
],
'#header' => [
'status' => $this
->t('Status'),
'filename' => $this
->t('File name'),
'line' => $this
->t('Line'),
'issue' => $this
->t('Error'),
],
'#weight' => 100,
];
$hasFixNow = FALSE;
foreach ($result['data']['files'] as $filepath => $errors) {
foreach ($errors['messages'] as $error) {
// Remove the Drupal root directory and allow paths and namespaces to wrap.
// Emphasize filename as it may show up in the middle of the info.
$short_path = str_replace(DRUPAL_ROOT . '/', '', $filepath);
$short_path = str_replace('/', '​/​', $short_path);
if (strpos($short_path, 'in context of')) {
$short_path = preg_replace('!/([^/]+)( \\(in context of)!', '/<strong>\\1</strong>\\2', $short_path);
$short_path = str_replace('\\', '​\\​', $short_path);
}
else {
$short_path = preg_replace('!/([^/]+)$!', '/<strong>\\1</strong>', $short_path);
}
// @todo could be more accurate with reflection but not sure it is even possible as the reflected
// code may not be in the runtime at this point (eg. functions in include files)
// see https://www.php.net/manual/en/reflectionfunctionabstract.getfilename.php
// see https://www.php.net/manual/en/reflectionclass.getfilename.php
// Link to documentation for a function in this specific Drupal version.
$api_version = preg_replace('!^(8\\.\\d+)\\..+$!', '\\1', \Drupal::VERSION) . '.x';
$api_link = 'https://api.drupal.org/api/drupal/' . $api_version . '/search/';
$formatted_error = preg_replace('!deprecated function ([^(]+)\\(\\)!', 'deprecated function <a target="_blank" href="' . $api_link . '\\1">\\1()</a>', $error['message']);
// Replace deprecated class links.
if (preg_match('!class (Drupal\\\\.+)\\.( |$)!', $formatted_error, $found)) {
if (preg_match('!Drupal\\\\([a-z_0-9A-Z]+)\\\\(.+)$!', $found[1], $namespace)) {
$path_parts = explode('\\', $namespace[2]);
$class = array_pop($path_parts);
if (in_array($namespace[1], [
'Component',
'Core',
])) {
$class_file = 'core!lib!Drupal!' . $namespace[1];
}
elseif (in_array($namespace[1], [
'KernelTests',
'FunctionalTests',
'FunctionalJavascriptTests',
'Tests',
])) {
$class_file = 'core!tests!Drupal!' . $namespace[1];
}
else {
$class_file = 'core!modules!' . $namespace[1] . '!src';
}
if (count($path_parts)) {
$class_file .= '!' . join('!', $path_parts);
}
$class_file .= '!' . $class . '.php';
$api_link = 'https://api.drupal.org/api/drupal/' . $class_file . '/class/' . $class . '/' . $api_version;
$formatted_error = str_replace($found[1], '<a target="_blank" href="' . $api_link . '">' . $found[1] . '</a>', $formatted_error);
}
}
// Allow error messages to wrap.
$formatted_error = str_replace('\\', '​\\​', $formatted_error);
$error_class = 'known-warnings';
$level_label = $this
->t('Check manually');
if (!empty($error['upgrade_status_category'])) {
if ($error['upgrade_status_category'] == 'ignore') {
$level_label = $this
->t('Ignore');
$error_class = 'known-ignore';
}
elseif ($error['upgrade_status_category'] == 'later') {
$level_label = $this
->t('Fix later');
}
elseif (in_array($error['upgrade_status_category'], [
'safe',
'old',
])) {
$level_label = $this
->t('Fix now');
$error_class = 'known-errors';
$hasFixNow = TRUE;
}
}
$table[] = [
'#attributes' => [
'class' => [
$error_class,
],
],
'status' => [
'#type' => 'markup',
'#markup' => $level_label,
'#wrapper_attributes' => [
'class' => [
'status-info',
],
],
],
'filename' => [
'#type' => 'markup',
'#markup' => $short_path,
],
'line' => [
'#type' => 'markup',
'#markup' => $error['line'],
],
'issue' => [
'#type' => 'markup',
'#markup' => $formatted_error,
],
];
}
}
$summary = [];
if (!empty($result['data']['totals']['upgrade_status_split']['error'])) {
$summary[] = $this
->formatPlural($result['data']['totals']['upgrade_status_split']['error'], '@count error found.', '@count errors found.');
}
if (!empty($result['data']['totals']['upgrade_status_split']['warning'])) {
$summary[] = $this
->formatPlural($result['data']['totals']['upgrade_status_split']['warning'], '@count warning found.', '@count warnings found.');
}
if ($hasFixNow) {
if (!empty($extension->info['project'])) {
$summary[] = $this
->t('Items categorized "Fix now" are uses of deprecated APIs from community unsupported core versions.');
}
else {
$summary[] = $this
->t('Items categorized "Fix now" are uses of deprecated APIs in custom code from current or older Drupal core version.');
}
}
$build['summary'] = [
'#type' => '#markup',
'#markup' => '<div class="list-description">' . join(' ', $summary) . '</div>',
'#weight' => 5,
];
$build['data'] = $table;
$build['export'] = [
'#type' => 'link',
'#title' => $this
->t('Export as HTML'),
'#name' => 'export',
'#url' => Url::fromRoute('upgrade_status.export', [
'type' => $extension
->getType(),
'project_machine_name' => $extension
->getName(),
'format' => 'html',
]),
'#attributes' => [
'class' => [
'button',
'button--primary',
],
],
'#weight' => 200,
];
$build['export_ascii'] = [
'#type' => 'link',
'#title' => $this
->t('Export as ASCII'),
'#name' => 'export_ascii',
'#url' => Url::fromRoute('upgrade_status.export', [
'type' => $extension
->getType(),
'project_machine_name' => $extension
->getName(),
'format' => 'ascii',
]),
'#attributes' => [
'class' => [
'button',
'button--primary',
],
],
'#weight' => 200,
];
return $build;
}