deprecation_status-8.x-3.x-dev/src/Controller/ChartController.php

src/Controller/ChartController.php
<?php

namespace Drupal\deprecation_status\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\deprecation_status\DataSource;

class ChartController extends ControllerBase {

  public function chartPage() {
    $build = ['#cache' => ['tags' => ['deprecation_status']]];
    $build['chartjs'] = [
      '#children' =>
        '<script src="https://cdn.jsdelivr.net/npm/moment@2.24.0/moment.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>

        <script>
        const verticalLinePlugin = {
          getLinePosition: function (chart, pointIndex) {
              const meta = chart.getDatasetMeta(0); // first dataset is used to discover X coordinate of a point
              const data = meta.data;
              return data[pointIndex.index]._model.x;
          },
          renderVerticalLine: function (chartInstance, pointIndex) {
              const lineLeftOffset = this.getLinePosition(chartInstance, pointIndex);
              const scale = chartInstance.scales[\'y-axis-0\'];
              const context = chartInstance.chart.ctx;

              // render vertical line
              context.beginPath();
              context.strokeStyle = \'#48494b\';
              context.moveTo(lineLeftOffset, scale.top);
              context.lineTo(lineLeftOffset, scale.bottom - 20);
              context.setLineDash([3, 3]);
              context.lineWidth = 2;
              context.stroke();

              // write label
              var width = ctx.measureText(pointIndex.label).width;
              context.fillStyle = "#f5f5f5";
              context.fillRect(lineLeftOffset - 2 - width/2 - 4, scale.bottom - 19, width + 8, 19);
              context.fillStyle = "#48494b";
              context.textAlign = \'center\';
              context.fillText(pointIndex.label, lineLeftOffset - 2, scale.bottom - 10);
          },

          afterDatasetsDraw: function (chart, easing) {
              if (chart.config.markerLines) {
                  chart.config.markerLines.forEach(pointIndex => this.renderVerticalLine(chart, pointIndex));
              }
          }
          };

          Chart.plugins.register(verticalLinePlugin);</script>',

    ];

    return $build + $this->graphProjectsAndErrors() /*+ $this->graph10Deprecations()*/;
  }

  public function graphProjectsAndErrors() {

    $markers = "{label: 'Drupal 9.4', index: 8}, {label: 'Drupal 10.0', index: 31}, {label: 'Drupal 10.1', index: 47}";

    // "#5EBF69", "#E0E552", "#FDBD65", "#F9A148", "#F56E44", "#F12D36"
    $breakdown_legend = [
      'Stable, congrats' => ['#005F73', 2, 1],
      'Improve stability of the release' => ['#0A9396', 1, 1],
      'Make tagged release available' => ['#94D2BD', 0, 1],
      'Fix info.yml/composer.json errors found' => ['#E9D8A6', 3, 1],
      'Run Rector to fix all errors' => ['#EE9B00', 4, 1],
      'Run Rector to fix some errors' => ['#CA6702', 5, 1],
      'Manually review and fix errors' => ['#BB3E03', 6, 1],
      'Resolve pre-scanning errors' => ['#9B2226', 7, 9],
    ];
    $groups = "'Top 50', 'Top 100', 'Top200', 'Top 500', 'Top 1000', 'All'";

    // Read project segment data.
    $data = [];
    $file = fopen(DataSource::getFullPath('next_steps_specific_segments.csv'), 'r');
    $i = 0;
    while ($line = fgetcsv($file, 0, ";")) {
      if ($i != 0) {
        $segment = array_shift($line);
        $sum = array_sum($line);
        if ($segment == '10000') {
          $groups = str_replace("'All'", "'All (" . $sum . ")'", $groups);
        }
        $items = [];
        foreach($breakdown_legend as $label => $structure) {
          $items[] = array_sum(array_slice($line, $structure[1], $structure[2]));
        }
        $row = [];
        foreach($items as $item) {
          $row[] = round($item/($sum/100), 2);
        }
        $data[] = $row;
      }
      $i++;
    }
    fclose($file);

    $datasets = [];
    $i = 0;
    foreach($breakdown_legend as $label => $structure) {
      $raw = '{label: "'. $label . '", data: [';
      foreach($data as $values) {
        $raw .= $values[$i] . ',';
      }
      $datasets[] = trim($raw, ',') . '], backgroundColor: "' . $structure[0] . '"}';
      $i++;
    }
    $datasets = join(',', $datasets);

    $build['breakdown_segments'] = [
      '#markup' => '<h2>Percentage of contributed projects by next step in usage groups</h2><p>Larger groups include results for smaller usage groups.</p>',
      '#children' => <<<PROJECTSEND
  <canvas id="SegmentsStatus"></canvas>
  <script type="text/javascript">
  var ctx = document.getElementById('SegmentsStatus').getContext('2d');
  var chart = new Chart(ctx, {
    type: 'bar',
    data: {
      labels: [$groups],
      datasets: [$datasets]
    },
    options: {
      aspectRatio: window.innerWidth < 800 ? 1 : 2,
      scales: {
        xAxes: [{
          stacked: true
        }],
        yAxes: [{
          stacked: true,
          ticks: { max: 100 }
        }]
      }
    }
  });
</script>
PROJECTSEND
    ];

    // =========================================================================

    $project_graphs = [
      '_200' => 'Top 200 drupal.org contributed projects by next step over time',
      '' => 'All drupal.org contributed projects by next step over time',
    ];
    foreach ($project_graphs as $graph_key => $graph_label) {

      // Read historic project data.
      $projects = [];
      $legend = [];
      $file = fopen(DataSource::getFullPath('next_steps_specific' . $graph_key . '.csv'), 'r');
      $i = 0;
      while ($line = fgetcsv($file, 0, ";")) {
        if ($i != 0) {
          $time = array_shift($line);
          $items = [];
          foreach($breakdown_legend as $label => $structure) {
            $projects[$label][$time] = array_sum(array_slice($line, $structure[1], $structure[2]));
          }
        }
        $i++;
      }
      fclose($file);

      $datasets = [];
      foreach($projects as $label => $dataset) {
        $raw = '{label: "'. $label . '", data: [';
        foreach($dataset as $time => $value) {
          $raw .= '{x: new Date(' . $time . '*1000), y: ' . $value . '},';
        }
        $raw = trim($raw, ',') . ']';
        if (isset($breakdown_legend[$label])) {
          $raw .= ', borderColor: "' . $breakdown_legend[$label][0] . '", backgroundColor: "' . $breakdown_legend[$label][0] . '"';
        }
        $raw .= '}';
        $datasets[] = $raw;
      }
      $datasets = join(',', $datasets);

      $build[$graph_key . '_projects'] = [
        '#markup' => '<h2>' . $graph_label . '</h2><p>Projects have errors that can be <a href="https://www.drupal.org/project/rector">automatically fixed with drupal-rector</a>.</p>',
        '#children' => <<<PROJECTSEND
  <canvas id="{$graph_key}ProjectStatus"></canvas>
  <script type="text/javascript">
  var ctx = document.getElementById('{$graph_key}ProjectStatus').getContext('2d');
  var chart = new Chart(ctx, {
    type: 'line',
    data: {
      datasets: [$datasets]
    },
    options: {
      aspectRatio: window.innerWidth < 800 ? 1 : 2,
      scales: {
        xAxes: [{
          type: 'time',
          time: {
            unit: 'week',
            max: new Date('2023-12-31')
          }
        }],
        yAxes: [{
          stacked: true,
          ticks: {
            beginAtZero: true
          }
        }]
      }
    },
    markerLines: [$markers]
  });
</script>
PROJECTSEND
      ];
    }

    // =========================================================================

    $count_graphs = [
      '_200' => 'Top 200 drupal.org contributed projects by error counts over time',
      '' => 'All drupal.org contributed projects by error counts over time',
    ];
    foreach ($count_graphs as $graph_key => $graph_label) {

      // Read historic count data.
      $projects = [];
      $legend = [];
      $file = fopen(DataSource::getFullPath('error_counts' . $graph_key . '.csv'), 'r');
      $i = 0;
      while ($line = fgetcsv($file, 0, ";")) {
        if ($i == 0) {
          $legend = $line;
          array_shift($legend);
        }
        else {
          $time = array_shift($line);
          foreach($legend as $index => $label) {
            $projects[$label][$time] = $line[$index];
          }
        }
        $i++;
      }
      fclose($file);

      $breakdown_colors = [
        'No errors' => "#264653",
        'Less than 5' => "#2A9D8F",
        'Less than 10' => "#E9C46A",
        '10 or more' => "#F4A261",
        'Pre-scanning errors' => "#E76F51",
      ];

      $datasets = [];
      foreach($projects as $label => $dataset) {
        $raw = '{label: "'. $label . '", data: [';
        foreach($dataset as $time => $value) {
          $raw .= '{x: new Date(' . $time . '*1000), y: ' . $value . '},';
        }
        $raw = trim($raw, ',') . ']';
        if (isset($breakdown_colors[$label])) {
          $raw .= ', borderColor: "' . $breakdown_colors[$label] . '", backgroundColor: "' . $breakdown_colors[$label] . '"';
        }
        $raw .= '}';
        $datasets[] = $raw;
      }
      $datasets = join(',', $datasets);

      $build[$graph_key . '_counts'] = [
        '#markup' => '<h2>' . $graph_label . '</h2><p>Number of projects by how many errors are in them. No results for projects with pre-scanning errors, counting them as one each for this chart.</p>',
        '#children' => <<<PROJECTSEND
  <canvas id="{$graph_key}CountStatus"></canvas>
  <script type="text/javascript">
  var ctx = document.getElementById('{$graph_key}CountStatus').getContext('2d');
  var chart = new Chart(ctx, {
    type: 'line',
    data: {
      datasets: [$datasets]
    },
    options: {
      aspectRatio: window.innerWidth < 800 ? 1 : 2,
      scales: {
        xAxes: [{
          type: 'time',
          time: {
            unit: 'week',
            max: new Date('2023-12-31')
          }
        }],
        yAxes: [{
          stacked: true,
          ticks: {
            beginAtZero: true
          }
        }]
      }
    },
    markerLines: [$markers]
  });
</script>
PROJECTSEND
      ];
    }

    // =========================================================================

    $type_graphs = [
      '_200' => 'Top 200 drupal.org contributed projects\' errors by fixability over time',
      '' => 'All drupal.org contributed projects\'s errors by fixability over time',
    ];
    foreach ($type_graphs as $graph_key => $graph_label) {

      $type_legend = [
        'Info.yml or composer.json' => '#e9d8a6',
        'Drupal API, rector covered' => '#fdae61',
        'Drupal API, not rector covered' => '#f46d43',
        'Symfony API' => '#d73027',
        'Twig API' => '#a50026',
        'PHPUnit API' => '#e0f3f8',
        'Guzzle API' => '#abd9e9',
        'Frontend API' => '#74add1',
        'Other problem' => '#4575b4',
        'Parse error' => '#313695',
      ];

      // Read historic error data.
      $errors = [];
      $legend = [];
      $file = fopen(DataSource::getFullPath('error_types' . $graph_key . '.csv'), 'r');
      $i = 0;
      while ($line = fgetcsv($file, 0, ";")) {
        if ($i == 0) {
          $legend = $line;
          array_shift($legend);
        }
        else {
          $time = array_shift($line);
          foreach($legend as $index => $label) {
            $errors[$label][$time] = $line[$index];
          }
        }
        $i++;
      }
      fclose($file);

      $datasets = [];
      foreach($errors as $label => $dataset) {
        $raw = '{label: "'. $label . '", data: [';
        foreach($dataset as $time => $value) {
          $raw .= '{x: new Date(' . $time . '*1000), y: ' . $value . '},';
        }
        $raw = trim($raw, ',') . ']';
        if (!empty($type_legend[$label])) {
          $raw .= ', borderColor: "' . $type_legend[$label] . '", backgroundColor: "' . $type_legend[$label] . '"';
        }
        $raw .= '}';
        $datasets[] = $raw;
      }
      $datasets = join(',', $datasets);

      $build[$graph_key . '_errors'] = [
        '#markup' => '<h2>' . $graph_label . '</h2><p><a href="https://www.drupal.org/project/rector">Use drupal-rector</a> to fix rector-covered errors. <a href="https://www.drupal.org/project/rector">Help expand rector coverage</a> to make all our lives easier.</p>',
        '#children' => <<<ERRORSEND
  <canvas id="{$graph_key}ErrorStatus"></canvas>
  <script type="text/javascript">
  var ctx = document.getElementById('{$graph_key}ErrorStatus').getContext('2d');
  var chart = new Chart(ctx, {
    type: 'line',
    data: {
      datasets: [$datasets]
    },
    options: {
      aspectRatio: window.innerWidth < 800 ? 1 : 2,
      scales: {
        xAxes: [{
          type: 'time',
          time: {
            unit: 'week',
            max: new Date('2023-12-31')
          }
        }],
        yAxes: [{
          stacked: true,
          ticks: {
            beginAtZero: true
          }
        }]
      }
    },
    markerLines: [$markers]
  });
</script>
ERRORSEND
      ];
    }

    return $build;
  }

  public function graph10Deprecations() {
    // git checkout `git rev-list -1 --before="February 28 2022" 10.0.x`

    // $ grep -r "@deprecated" core --exclude-dir=node_modules | wc -l
    // $ grep -r "@deprecated" core --exclude-dir=node_modules | grep -o "11.0.0" | wc -l

    // $ grep -ro "E_USER_DEPRECATED" core --exclude-dir=node_modules | wc -l
    // $ grep -r "E_USER_DEPRECATED" core --exclude-dir=node_modules | grep -o "11.0.0" | wc -l

    // Read historic core deprecation count data.
    $at_deprecated = '';
    $e_user_deprecated = '';
    $file = fopen(DataSource::getFullPath('core_deprecation_count.csv'), 'r');
    $i = 0;
    while ($line = fgetcsv($file, 0, ";")) {
      // Skip the header row.
      if ($i > 0) {
        $at_deprecated .= '{x: new Date("' . $line[0] . '"), y: ' . $line[1] . '},';
        $e_user_deprecated .= '{x: new Date("' . $line[0] . '"), y: ' . $line[2] . '},';
      }
      $i++;
    }
    fclose($file);
    $at_deprecated = trim($at_deprecated, ',');
    $e_user_deprecated = trim($e_user_deprecated, ',');

    $build['core'] = [
      '#markup' => '<h2><a href="https://api.drupal.org/api/drupal/deprecated/9.4.x">Deprecated APIs</a> are removed from the Drupal 10 branch.</h2><p>Tracking based on @deprecated and E_USER_DEPRECATED mentions in Drupal 10 core for illustration, even though there are some other ways to deprecate things (libraries, extensions, etc).</p>',
      '#children' => <<<COREEND
  <canvas id="coreDeprecated"></canvas>
  <script type="text/javascript">
  var ctx = document.getElementById('coreDeprecated').getContext('2d');
  var chart = new Chart(ctx, {
    type: 'line',
    data: {
      datasets: [{
        label: 'Drupal core @deprecated mentions',
        borderColor: "#FDC70F",
        borderWidth: 4,
        data: [$at_deprecated],
        cubicInterpolationMode: 'monotone',
        fill: false,
        pointRadius: 4,
        pointHoverRadius: 10,
        pointBackgroundColor: "#FDC70F",
      },
      {
        label: 'Drupal core E_USER_DEPRECATED mentions',
        borderColor: "#1F72B2",
        borderWidth: 4,
        data: [$e_user_deprecated],
        cubicInterpolationMode: 'monotone',
        fill: false,
        pointRadius: 4,
        pointHoverRadius: 10,
        pointBackgroundColor: "#1F72B2",
      }]
    },
    options: {
      scales: {
        xAxes: [{
          type: 'time',
          time: {
            unit: 'week',
            max: new Date('2023-12-31')
          }
        }],
        yAxes: [{
          ticks: {
            beginAtZero: true
          }
        }]
      }
    }
  });
</script>
COREEND
    ];

    return $build;
  }

}

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

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