You are here

protected function UpgradeStatusForm::buildProjectList in Upgrade Status 8.2

Same name and namespace in other branches
  1. 8.3 src/Form/UpgradeStatusForm.php \Drupal\upgrade_status\Form\UpgradeStatusForm::buildProjectList()
  2. 8 src/Form/UpgradeStatusForm.php \Drupal\upgrade_status\Form\UpgradeStatusForm::buildProjectList()

Builds a list and status summary of projects.

Parameters

\Drupal\Core\Extension\Extension[] $projects: Array of extensions representing projects.

bool $isContrib: (Optional) Whether the list to be produced is for contributed projects.

Return value

array Build array.

1 call to UpgradeStatusForm::buildProjectList()
UpgradeStatusForm::buildForm in src/Form/UpgradeStatusForm.php
Form constructor.

File

src/Form/UpgradeStatusForm.php, line 292

Class

UpgradeStatusForm

Namespace

Drupal\upgrade_status\Form

Code

protected function buildProjectList(array $projects, bool $isContrib = FALSE) {
  $counters = [
    'not-scanned' => 0,
    'no-known-error' => 0,
    'known-errors' => 0,
    'known-warnings' => 0,
    'known-error-projects' => 0,
    'known-warning-projects' => 0,
  ];
  $header = [
    'project' => [
      'data' => $this
        ->t('Project'),
      'class' => 'project-label',
    ],
  ];
  if ($isContrib) {
    $header['update'] = [
      'data' => $this
        ->t('Available update'),
      'class' => 'update-info',
    ];
  }
  $header['status'] = [
    'data' => $this
      ->t('Status'),
    'class' => 'status-info',
  ];
  $build['uninstalled'] = $build['installed'] = [
    '#type' => 'tableselect',
    '#header' => $header,
    '#weight' => 20,
    '#options' => [],
  ];
  $build['uninstalled']['#weight'] = '40';
  $update_check_for_uninstalled = $this
    ->config('update.settings')
    ->get('check.disabled_extensions');
  foreach ($projects as $name => $extension) {

    // Always use a fresh service. An injected service could get stale results
    // because scan result saving happens in different HTTP requests for most
    // cases (when analysis was successful).
    $scan_result = \Drupal::service('keyvalue')
      ->get('upgrade_status_scan_results')
      ->get($name);
    $info = $extension->info;
    $label = $info['name'] . (!empty($info['version']) ? ' ' . $info['version'] : '');
    $state = empty($extension->status) ? 'uninstalled' : 'installed';
    $update_cell = [
      'class' => 'update-info',
      'data' => $isContrib ? $this
        ->t('Up to date') : '',
    ];
    $label_cell = [
      'data' => [
        'label' => [
          '#type' => 'html_tag',
          '#tag' => 'label',
          '#value' => $label,
          '#attributes' => [
            'for' => 'edit-' . ($isContrib ? 'contrib' : 'custom') . '-data-data-' . str_replace('_', '-', $name),
          ],
        ],
      ],
      'class' => 'project-label',
    ];
    if ($isContrib) {
      $projectUpdateData = $this->releaseStore
        ->get($name);
      if (!isset($projectUpdateData['releases']) || is_null($projectUpdateData['releases'])) {
        $update_cell = [
          'class' => 'update-info',
          'data' => $update_check_for_uninstalled ? $this
            ->t('Not available') : $this
            ->t('Not checked'),
        ];
      }
      else {
        $latestRelease = reset($projectUpdateData['releases']);
        $latestVersion = $latestRelease['version'];
        if ($info['version'] !== $latestVersion) {
          $link = $projectUpdateData['link'] . '/releases/' . $latestVersion;
          $update_cell = [
            'class' => 'update-info',
            'data' => [
              '#type' => 'link',
              '#title' => $latestVersion,
              '#url' => Url::fromUri($link),
            ],
          ];
        }
      }
    }

    // If this project was not found in our keyvalue storage, it is not yet scanned, report that.
    if (empty($scan_result)) {
      $build[$state]['#options'][$name] = [
        '#attributes' => [
          'class' => [
            'not-scanned',
            'project-' . $name,
          ],
        ],
        'project' => $label_cell,
        'update' => $update_cell,
        'status' => [
          'class' => 'status-info',
          'data' => $this
            ->t('Not scanned'),
        ],
      ];
      $counters['not-scanned']++;
      continue;
    }

    // Unpack JSON of deprecations to display results.
    $report = json_decode($scan_result, TRUE);
    if (!empty($report['plans'])) {
      $label_cell['data']['plans'] = [
        '#type' => 'markup',
        '#markup' => '<div>' . $report['plans'] . '</div>',
      ];
    }
    if (isset($report['data']['totals'])) {
      $project_error_count = $report['data']['totals']['file_errors'];
    }
    else {
      $project_error_count = 0;
    }

    // If this project had no known issues found, report that.
    if ($project_error_count === 0) {
      $build[$state]['#options'][$name] = [
        '#attributes' => [
          'class' => [
            'no-known-error',
            'project-' . $name,
          ],
        ],
        'project' => $label_cell,
        'update' => $update_cell,
        'status' => [
          'class' => 'status-info',
          'data' => $this
            ->t('No known errors'),
        ],
      ];
      $counters['no-known-error']++;
      continue;
    }

    // Finally this project had errors found, display them.
    $error_label = [];
    $error_class = 'known-warnings';
    if (!empty($report['data']['totals']['upgrade_status_split']['error'])) {
      $counters['known-errors'] += $report['data']['totals']['upgrade_status_split']['error'];
      $counters['known-error-projects']++;
      $error_class = 'known-errors';
      $error_label[] = $this
        ->formatPlural($report['data']['totals']['upgrade_status_split']['error'], '@count error', '@count errors');
    }
    if (!empty($report['data']['totals']['upgrade_status_split']['warning'])) {
      $counters['known-warnings'] += $report['data']['totals']['upgrade_status_split']['warning'];
      $counters['known-warning-projects']++;
      $error_label[] = $this
        ->formatPlural($report['data']['totals']['upgrade_status_split']['warning'], '@count warning', '@count warnings');
    }

    // If the project was declared Drupal 9 compatible (info and composer
    // files), than use that to visually display it as such. We still list
    // errors but they may be false positives or results of workaround code.
    if (!empty($report['data']['totals']['upgrade_status_split']['declared_ready'])) {
      $error_class = 'no-known-error';
    }
    $build[$state]['#options'][$name] = [
      '#attributes' => [
        'class' => [
          $error_class,
          'project-' . $name,
        ],
      ],
      'project' => $label_cell,
      'update' => $update_cell,
      'status' => [
        'class' => 'status-info',
        'data' => [
          '#type' => 'link',
          '#title' => join(', ', $error_label),
          '#url' => Url::fromRoute('upgrade_status.project', [
            'type' => $extension
              ->getType(),
            'project_machine_name' => $name,
          ]),
          '#attributes' => [
            'class' => [
              'use-ajax',
            ],
            'data-dialog-type' => 'modal',
            'data-dialog-options' => Json::encode([
              'width' => 1024,
              'height' => 568,
            ]),
          ],
        ],
      ],
    ];
  }
  if (!$isContrib) {

    // If the list is not for contrib, remove the update placeholder.
    $states = [
      'installed',
      'uninstalled',
    ];
    foreach ($states as $state) {
      foreach ($build[$state]['#options'] as $name => &$row) {
        if (is_array($row)) {
          unset($row['update']);
        }
      }
    }
  }
  if (empty($build['uninstalled']['#options'])) {
    unset($build['uninstalled']);
  }
  else {

    // Add a specific intro section to uninstalled extensions.
    $check_info = '';
    if ($isContrib) {

      // Contrib extensions that are uninstalled may not get available updates info.
      $enable_check = Url::fromRoute('update.settings', [], [
        'query' => $this->destination
          ->getAsArray(),
      ])
        ->toString();
      if (!empty($update_check_for_uninstalled)) {
        $check_info = ' ' . $this
          ->t('Available update checking for uninstalled extensions is enabled.');
      }
      else {
        $check_info = ' ' . $this
          ->t('Available update checking for uninstalled extensions is disabled. (<a href="@enable">Enable</a>)', [
          '@enable' => $enable_check,
        ]);
      }
    }
    $build['uninstalled_intro'] = [
      '#weight' => 30,
      [
        '#type' => 'markup',
        '#markup' => '<h3>' . $this
          ->t('Uninstalled extensions') . '</h3>',
      ],
      [
        '#type' => 'markup',
        '#markup' => '<div>' . $this
          ->t('Consider if you need these uninstalled extensions at all. A limited set of checks may also be run on uninstalled extensions.') . $check_info . '</div>',
      ],
    ];
  }
  if (empty($build['installed']['#options'])) {
    unset($build['installed']);
  }
  $summary = [];
  if ($counters['known-errors'] > 0) {
    $summary[] = [
      'type' => $this
        ->formatPlural($counters['known-errors'], '1 error', '@count errors'),
      'class' => 'error',
      'message' => $this
        ->formatPlural($counters['known-error-projects'], 'Found in one project.', 'Found in @count projects.'),
    ];
  }
  if ($counters['known-warnings'] > 0) {
    $summary[] = [
      'type' => $this
        ->formatPlural($counters['known-warnings'], '1 warning', '@count warnings'),
      'class' => 'warning',
      'message' => $this
        ->formatPlural($counters['known-warning-projects'], 'Found in one project.', 'Found in @count projects.'),
    ];
  }
  if ($counters['no-known-error'] > 0) {
    $summary[] = [
      'type' => $this
        ->formatPlural($counters['no-known-error'], '1 checked', '@count checked'),
      'class' => 'checked',
      'message' => $this
        ->t('No known errors found.'),
    ];
  }
  if ($counters['not-scanned'] > 0) {
    $summary[] = [
      'type' => $this
        ->formatPlural($counters['not-scanned'], '1 not scanned', '@count not scanned'),
      'class' => 'not-scanned',
      'message' => $this
        ->t('Scan to find errors.'),
    ];
  }
  $build['summary'] = [
    '#theme' => 'upgrade_status_summary_counter',
    '#summary' => $summary,
  ];
  return $build;
}