deprecation_status-8.x-3.x-dev/src/Form/SingleProjectForm.php

src/Form/SingleProjectForm.php
<?php

namespace Drupal\deprecation_status\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Url;
use Drupal\Core\Utility\TableSort;
use Drupal\deprecation_status\DataSource;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class SingleProjectForm extends FormBase {

  /**
   * Stored sorting criteria.
   *
   * @type int
   */
  protected $column;

  /**
   * Stored sorting criteria ('asc' or 'desc').
   *
   * @type string
   */
  protected $sort;

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'deprecation_status_project_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $machine_name = NULL) {
    // Find this single project if present.
    $project = [];
    $file = fopen(DataSource::getFullPath('projects_detail.csv'), 'r');
    $i = 0;
    while ($line = fgetcsv($file, 0, ";")) {
      // Skip the header row.
      if ($i > 0 && strpos($line[0], $machine_name . ' ') === 0) {
        $project = $line;
        break;
      }
      $i++;
    }
    fclose($file);

    // Throw a 404 if this project was not found.
    if (empty($project)) {
      throw new NotFoundHttpException();
    }

    // "Name and release";"General next step";"Specific next step";
    // "Project type";"Usage count";"Top X by usage";
    // "Highest compatible stability level";"Highest compatible stability version";
    // "Total errors";"Total parse errors";"Total deprecated API uses";
    // "Drupal API, rector covered";"Drupal API, not rector covered";
    // "Symfony API";"Twig API";"PHPUnit API";"Guzzle API";"Frontend API";
    // "Info.yml or composer.json";"Other problem";"Drupal 8 API deprecations";
    // "Upgrade plan";"Rector patchfile";"Pre-scan error log";Maintainers

    $form['#cache']['tags'][] = 'deprecation_status';
    $form['machine_name'] = [
      '#type' => 'value',
      '#value' => $machine_name,
    ];
    $form['#attached']['library'][] = 'deprecation_status/deprecation_status.lists';
    $form['#title'] = $this->t('@name Drupal 10 deprecation details', ['@name' => $project[0]]);
    $form['#attached'] = ['library' => ['deprecation_status/deprecation_status.lists']];

    // Add high level summary table.
    list($machine_name) = explode(' ', $project[0]);
    $columns = [
      'name' => 'Name and release',
      'type' => 'Project type',
      'projects' => 'Usage count',
      'top' => 'Top X project by usage',
      'maintainers' => 'Maintainers',
    ];
    $form['summary'] = [
      '#type' => 'table',
      '#header' => $columns,
      '#rows' => [
        [
          [
            'data' => [
              '#type' => 'markup',
              '#markup' => '<a href="https://drupal.org/project/' . $machine_name . '">' . $project[0] . '</a>',
            ]
          ],
          $project[3],
          $project[4],
          $project[5],
          $project[24]
        ]
      ],
    ];

    // Read the errors related to this project.
    // "Occurence count";"Affected project count";"Occurs in a top X project by usage";
    // Category;Error;"List of projects [group] (occurences)"
    $errors = [];
    $file = fopen(DataSource::getFullPath('errors_detail.csv'), 'r');
    $i = 0;
    while ($line = fgetcsv($file, 0, ";")) {
      // Skip the header row.
      if ($i > 0) {
        $this_project_count = 0;
        $error_projects = explode(', ', $line[5]);
        foreach ($error_projects as $error_project) {
          if (strpos($error_project, $machine_name . ' ') === 0) {
            if (preg_match('!\((\d+)\)$!', $error_project, $count)) {
              $this_project_count = (int) $count[1];
            }
          }
        }
        if ($this_project_count > 0) {
          $errors[] = [$this_project_count, $line[0], $line[1], $line[3], $line[4], $i - 1];
        }
      }
      $i++;
    }
    fclose($file);

    $file = fopen(DataSource::getFullPath('next_steps_help.csv'), 'r');
    $step_help = '';
    $i = 0;
    while ($line = fgetcsv($file, 0, ";")) {
      if ($i > 0) {
        if ($line[0] == '-- ' . $project[2]) {
          $step_help = $line[1];
          break;
        }
      }
      $i++;
    }
    fclose($file);

    $project_class = 'warning';
    if ($project[1] == 'Resolve pre-scanning errors') {
      $project_class = 'unknown';
    }
    elseif ($project[1] == 'Release as Drupal 10-ready') {
      $project_class = 'passed';
    }
    elseif (in_array($project[2], ['Run Rector to fix all errors', 'Run Rector to fix some errors', 'Manually review and fix errors'])) {
      $project_class = 'error';
    }

    $next_step_columns = [
      'status' => 'Status',
      'next_step' => 'Next step',
      'help' => 'Instructions',
      'issues' => 'Drupal.org issues',
    ];
    $form['next_step'] = [
      '#type' => 'table',
      '#header' => $next_step_columns,
      '#attributes' => ['class' => ['single-project-table']],
    ];
    $issue_link = '<a href="https://drupal.org/project/issues/search/' . $machine_name . '?issue_tags=Drupal+10+compatibility">Drupal 10 compatibility issues</a>';
    $row = [
      '#attributes' => ['class' => ['item-' . $project_class]],
      'status' => ['data' => ['#markup' => '<span class="category">' . $project[1] . '</span>']],
      'next_step' => ['data' => ['#markup' => $project[2]]],
      'help' => ['data' => ['#markup' => $step_help]],
      'issues' => ['data' => ['#markup' => $issue_link]],
    ];
    if ($project[1] == 'Resolve pre-scanning errors') {
      $form['next_step']['#header']['link'] = 'Error log';
      $row['link'] = [
        'data' => [
          '#markup' => '<a href="' . $project[23] . '">' . $this->t('Read the error log') . '</a>',
        ],
      ];
    }
    $form['next_step'][] = $row;

    $form['data_info'] = DataSource::getDataInfo();

    // If there are pre-scanning errors or no errors, no need to display
    // an error list/filter since it would always be empty.
    if ($project_class == 'unknown' || $project_class == 'passed') {
      return $form;
    }

    $form['filters'] = [
      '#type' => 'details',
      '#title' => $this->t('Filter errors'),
      '#attributes' => ['class' => ['container-inline']],
      '#open' => TRUE,
    ];
    $form['filters']['error'] = [
      '#title' => 'Error',
      '#type' => 'textfield',
      '#default_value' => @$_GET['error'],
      '#attributes' => ['placeholder' => "Use *, eg. '*Entity*'"],
      '#size' => 20,
    ];
    $form['filters']['category'] = [
      '#title' => 'Category',
      '#type' => 'select',
      '#options' => [
        'Info.yml or composer.json' => 'Info.yml or composer.json',
        'Drupal API, rector covered' => 'Drupal API, rector covered',
        'Drupal API, not rector covered' => 'Drupal API, not rector covered',
        'Symfony API' => 'Symfony API',
        'Twig API' => 'Twig API',
        'PHPUnit API' => 'PHPUnit API',
        'Guzzle API' => 'Guzzle API',
        'Frontend API' => 'Frontend API',
        'Other problem' => 'Other problem',
        'Parse error' => 'Parse error'
      ],
      '#default_value' => @$_GET['category'],
      '#required' => FALSE,
      '#empty_option' => '- No filter -',
    ];
    $form['filters']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];

    // Add error listing table.
    $columns = [
      'occurrence_project' => 'Occurrence in project',
      'occurrence_all' => 'All occurrences',
      'projects' => 'Affected projects',
      'category' => 'Category',
      'error' => 'Error',
    ];
    // Add sorting information to columns.
    $i = 0;
    foreach ($columns as $name => &$column) {
      $column = ['data' => $column, 'field' => $i];
      $i++;
    }
    // Sort by occurrences descending initially.
    $columns['occurrence_project']['sort'] = 'desc';

    $form['errors'] = [
      '#type' => 'table',
      '#header' => $columns,
      '#empty' => t('No matching errors found. Adjust filters.'),
    ];

    $errors = $this->tableFilter($errors);

    // Sort the data array based on query tablesort information.
    $order = TableSort::getOrder($columns, \Drupal::request());
    $this->column = $order['sql'];
    $this->sort = TableSort::getSort($columns, \Drupal::request());
    uasort($errors, [$this, 'tableSort']);

    foreach ($errors as $error) {
      $i = $error[5];
      $error = array_slice($error, 0, 5);

      $error_class = 'warning';
      if ($error[3] == 'Drupal API, rector covered') {
        $error_class = 'passed';
      }
      elseif ($error[3] == 'Parse error') {
        $error_class = 'error';
      }
      elseif ($error[3] == 'Other problem') {
        $error_class = 'unknown';
      }
      $row = [
        '#attributes' => ['class' => ['item-' . $error_class]],
        'occurrence_project' => ['#type' => 'markup', '#markup' => $error[0]],
        'occurrence_all' => ['#type' => 'markup', '#markup' => $error[1]],
        'projects' => [
          'data' => [
            '#type' => 'link',
            '#title' => $error[2],
            '#url' => Url::fromRoute('deprecation_status.error', ['error_index' => $i]),
          ],
        ],
        'category' => ['#type' => 'markup', '#markup' =>  '<span class="category">' . $error[3] . '</span>'],
        'message' => ['#type' => 'markup', '#markup' => DataSource::formatError($error[4])],
      ];
      $form['errors'][] = $row;
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $keys = ['error', 'category'];
    $submitted = $form_state->getValues();
    $query = [];
    foreach ($keys as $key) {
      if (!empty($submitted[$key])) {
        $query[$key] = $submitted[$key];
      }
    }
    $form_state->setRedirect('deprecation_status.project', ['machine_name' => $submitted['machine_name']], ['query' => $query]);
  }

  /**
   * Custom table sorting based on stored sorting criteria.
   */
  protected function tableSort($a, $b) {
    if ($a[$this->column] == $b[$this->column]) {
      return 0;
    }
    $cmp = ($a[$this->column] < $b[$this->column]) ? -1 : 1;
    return ($this->sort == 'desc') ? $cmp * -1 : $cmp;
  }

  /**
   * Custom table filter based on form values.
   */
  protected function tableFilter($errors) {
    $keys = ['error', 'category'];
    foreach ($keys as $key) {
      $$key = @$_GET[$key];
    }

    // Process error message matching for preg_match() later.
    $message = '';
    if (!empty($error)) {
      $parts = explode('*', trim($error));
      $processed_parts = [];
      foreach ($parts as $part) {
        $processed_parts[] = preg_quote($part, '!');
      }
      $message = join('.*', $processed_parts);
    }

    $filtered = [];
    foreach ($errors as $index => $error) {
      // Assume this row is a match.
      $match = TRUE;

      // Go through each filter and if the row is still a match, see if this
      // filter will invalidate it.
      if (!empty($message) && $match) {
        $match = preg_match("!^$message$!", $error[4]);
      }
      if (!empty($category) && $match) {
        $match = ($error[3] == $category);
      }

      // If the row was still a match, continue.
      if ($match) {
        $filtered[] = $error;
      }
    }
    return $filtered;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc