drupalorg-1.0.x-dev/src/Utilities/CoreCompatibility.php

src/Utilities/CoreCompatibility.php
<?php

namespace Drupal\drupalorg\Utilities;

use Drupal\drupalorg\Traits\UpdateXML;
use Drupal\node\Entity\Node;
use Requtize\SemVerConverter\SemVerConverter;

/**
 * Utility functions to calculate and populate the core_compatibility values.
 */
class CoreCompatibility {

  use UpdateXML;

  /**
   * Max core version supported for cases where constraints are ">=".
   *
   * @var string
   */
  const MAX_CORE_SUPPORTED = 12;

  /**
   * Calculate the core compatibility limits for modules.
   *
   * @param int $updated_since_timestamp
   *   Calculate only for projects with releases newer than this timestamp.
   */
  public static function calculateNewCoreCompatibilities($updated_since_timestamp = NULL) {
    $memory_cache = \Drupal::service('entity.memory_cache');
    $memory_cache_clear_counter = 0;
    $ids = is_null($updated_since_timestamp) ?
      self::getAllProjectIds() :
      self::getProjectsWithReleasesNewerThan($updated_since_timestamp);

    foreach ($ids as $id) {
      $project = Node::load($id);
      if ($project->hasField('field_project_machine_name')) {
        $machine_name = $project->get('field_project_machine_name')->getValue()[0]['value'] ?? NULL;
        if (
          $machine_name &&
          $project->hasField('field_core_semver_minimum') &&
          $project->hasField('field_core_semver_maximum')
        ) {
          $min = $project->get('field_core_semver_minimum')->getValue()[0]['value'] ?? PHP_INT_MAX;
          $max = $project->get('field_core_semver_maximum')->getValue()[0]['value'] ?? PHP_INT_MIN;

          $releases = self::getProjectInformation($machine_name);
          if (!empty($releases)) {
            $releases = $releases['releases']['release'] ?? [];
            foreach ($releases as $release) {
              $core_compatibility = $release['core_compatibility'] ?? FALSE;
              if (!empty($core_compatibility)) {
                $range = self::getSemverRange($core_compatibility);
                if (!empty($range)) {
                  $min = ($range['min'] < $min) ? $range['min'] : $min;
                  $max = ($range['max'] > $max) ? $range['max'] : $max;
                }
                else {
                  \Drupal::logger('drupalorg')
                    ->warning('@core_compatibility is an invalid version constraint found in a release in @project project.', [
                      '@project' => $machine_name,
                      '@core_compatibility' => $core_compatibility,
                    ]);
                }
              }
            }
          }

          if ($min != PHP_INT_MAX && $max != PHP_INT_MIN) {
            $project
              ->set('field_core_semver_minimum', $min)
              ->set('field_core_semver_maximum', $max)
              ->save();
          }
        }
      }

      // Reset the cache in order to free memory as we progress.
      $memory_cache_clear_counter++;
      if ($memory_cache_clear_counter > 100) {
        $memory_cache->deleteAll();
        $memory_cache_clear_counter = 0;
      }
    }
  }

  /**
   * Return all (published and full) project ids.
   *
   * @return array
   *   List of IDs.
   */
  protected static function getAllProjectIds(): array {
    return \Drupal::entityQuery('node')
      ->accessCheck(FALSE)
      ->condition('type', 'project_module')
      ->condition('field_project_type', 'full')
      ->condition('field_project_has_releases', 1)
      ->execute();
  }

  /**
   * Get projects with recent releases.
   *
   * @param int $timestamp
   *   Time to check from.
   *
   * @return array
   *   List of projects that match the condition.
   */
  protected static function getProjectsWithReleasesNewerThan(int $timestamp): array {
    if (empty($timestamp)) {
      return self::getAllProjectIds();
    }

    $release_ids = \Drupal::entityQuery('node')
      ->accessCheck(FALSE)
      ->condition('type', 'project_release')
      ->exists('field_packaged_git_sha1')
      ->condition('created', $timestamp, '>')
      ->execute();
    $project_ids = [];
    $chunks = array_chunk($release_ids, 100);
    foreach ($chunks as $chunk) {
      $releases = Node::loadMultiple($chunk);
      foreach ($releases as $release) {
        $project_id = $release->get('field_release_project')->getValue();
        if (!empty($project_id[0]['target_id'])) {
          $id = $project_id[0]['target_id'];
          $project_ids[$id] = $id;
        }
      }
    }

    return $project_ids;
  }

  /**
   * Calculates the upper and lower end supported by a semver string.
   *
   * @param string $semver_value
   *   Value to check.
   *
   * @return array
   *   Min and max supported values, if found.
   */
  protected static function getSemverRange($semver_value): array {
    $cache = \Drupal::cache();
    $cache_key = 'drupalorg:core_compatibility_range:' . md5($semver_value);
    if ($result = $cache->get($cache_key)) {
      return $result->data;
    }

    $result = [];
    try {
      $limits = (new SemVerConverter())->convert($semver_value);
      if (!empty($limits)) {
        $lower_end = $limits[0];
        $min = $lower_end['from'][0];
        if ($min == 0) {
          // SemVerConverter lower bound when the constraint is "<".
          // Make it 8000000 as we're using the default 3 zeroes, 3 sections.
          $min = 8000000;
        }

        $upper_end = array_pop($limits);
        $max = $upper_end['to'][0];
        if ($max == 999999999999) {
          // SemVerConverter upper bound when the constraint is ">=".
          // Make it X999999 as we're using the default 3 zeroes, 3 sections.
          $max = (int) (self::MAX_CORE_SUPPORTED . '999999');
        }

        $result = [
          'min' => $min,
          'max' => $max,
        ];
      }
    }
    catch (\Throwable $e) {
      \Drupal::logger('drupalorg')
        ->warning('Invalid version constraint @version.', [
          '@version' => $semver_value,
        ]);
    }

    $cache->set($cache_key, $result);
    return $result;
  }

}

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

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