You are here

class ProjectCollector in Upgrade Status 8

Same name and namespace in other branches
  1. 8.3 src/ProjectCollector.php \Drupal\upgrade_status\ProjectCollector
  2. 8.2 src/ProjectCollector.php \Drupal\upgrade_status\ProjectCollector

Collects projects collated for the purposes of upgrade status.

Hierarchy

Expanded class hierarchy of ProjectCollector

1 file declares its use of ProjectCollector
UpgradeStatusForm.php in src/Form/UpgradeStatusForm.php
1 string reference to 'ProjectCollector'
upgrade_status.services.yml in ./upgrade_status.services.yml
upgrade_status.services.yml
1 service uses ProjectCollector
upgrade_status.project_collector in ./upgrade_status.services.yml
Drupal\upgrade_status\ProjectCollector

File

src/ProjectCollector.php, line 14

Namespace

Drupal\upgrade_status
View source
class ProjectCollector implements ProjectCollectorInterface {
  use StringTranslationTrait;

  /**
   * The list of available modules.
   *
   * @var \Drupal\Core\Extension\ModuleExtensionList
   */
  protected $moduleExtensionList;

  /**
   * The theme handler.
   *
   * @var \Drupal\Core\Extension\ThemeHandler
   */
  protected $themeHandler;

  /**
   * The list of available profiles.
   *
   * @var \Drupal\Core\Extension\ProfileExtensionList
   */
  protected $profileExtensionList;

  /**
   * A list of allowed extension types.
   *
   * @var array
   */
  protected $allowedTypes = [
    'module',
    'theme',
    'profile',
  ];

  /**
   * Constructs a \Drupal\upgrade_status\ProjectCollector.
   *
   * @param \Drupal\Core\Extension\ModuleExtensionList $module_extension_list
   *   The module extension list service.
   * @param \Drupal\Core\Extension\ThemeHandler $theme_handler
   *   The theme extension handler service.
   * @param \Drupal\Core\Extension\ProfileExtensionList $profile_extension_list
   *   The profile extension handler service.
   */
  public function __construct(ModuleExtensionList $module_extension_list, ThemeHandler $theme_handler, ProfileExtensionList $profile_extension_list) {
    $this->moduleExtensionList = $module_extension_list;
    $this->themeHandler = $theme_handler;
    $this->profileExtensionList = $profile_extension_list;
  }

  /**
   * {@inheritdoc}
   */
  public function collectProjects() {
    $projects = [
      'custom' => [],
      'contrib' => [],
    ];
    $modules = $this->moduleExtensionList
      ->reset()
      ->getList();
    $themes = $this->themeHandler
      ->rebuildThemeData();
    $profiles = $this->profileExtensionList
      ->getList();
    $extensions = array_merge($modules, $themes, $profiles);
    unset($modules, $themes, $profiles);

    /** @var \Drupal\Core\Extension\Extension $extension */
    foreach ($extensions as $key => $extension) {
      if ($extension->origin === 'core') {

        // Ignore core extensions for the sake of upgrade status.
        continue;
      }
      if ($extension
        ->getType() !== 'profile' && $extension->status === 0) {

        // Ignore disabled extensions.
        continue;
      }

      // If the project is already specified in this extension, use that.
      $project = isset($extension->info['project']) ? $extension->info['project'] : '';
      if (array_key_exists($project, $projects['custom']) || array_key_exists($project, $projects['contrib'])) {

        // If we already have a representative of this project in the list,
        // don't add this extension.
        // @todo Make sure to use the extension with the shortest file path.
        continue;
      }

      // For extensions that are not in core and no project was specified,
      // they are assumed to be custom code. Drupal.org packages contrib
      // extensions with a project key and composer packages also include it.
      if (empty($project)) {
        $projects['custom'][$key] = $extension;
        continue;
      }
      if ($project === 'drupal') {

        // Ensure to omit all core related extension from the list.
        continue;
      }

      // @todo should this use $project as the key?
      $projects['contrib'][$key] = $extension;
    }

    // Collate custom extensions to projects, removing sub-extensions.
    $projects['custom'] = $this
      ->collateCustomExtensionsIntoProjects($projects['custom']);
    return $projects;
  }

  /**
   * Finds topmost custom extension for each extension and keeps only that.
   *
   * @param \Drupal\Core\Extension\Extension[] $projects
   *   List of all enabled custom extensions.
   *
   * @return \Drupal\Core\Extension\Extension[]
   *   List of custom extensions, with only the topmost custom extension left
   *   for each extension that has a parent extension.
   */
  protected function collateCustomExtensionsIntoProjects(array $projects) {
    foreach ($projects as $name_a => $data_a) {
      $subpath_a = $data_a->subpath . '/';
      $subpath_a_length = strlen($subpath_a);
      foreach ($projects as $name_b => $data_b) {
        $subpath_b = $data_b->subpath;

        // If the extension is not the same but the beginning of paths match,
        // remove this extension from the list as it is part of another one.
        if ($name_b != $name_a && substr($subpath_b, 0, $subpath_a_length) === $subpath_a) {
          unset($projects[$name_b]);
        }
      }
    }
    return $projects;
  }

  /**
   * {@inheritdoc}
   */
  public function loadProject(string $type, string $project_machine_name) {
    if (!in_array($type, $this->allowedTypes)) {
      throw new InvalidArgumentException($this
        ->t('Type must be either module or theme.'));
    }
    if ($type === 'module') {
      return $this->moduleExtensionList
        ->get($project_machine_name);
    }
    if ($type === 'profile') {
      return $this->profileExtensionList
        ->get($project_machine_name);
    }
    return $this->themeHandler
      ->getTheme($project_machine_name);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ProjectCollector::$allowedTypes protected property A list of allowed extension types.
ProjectCollector::$moduleExtensionList protected property The list of available modules.
ProjectCollector::$profileExtensionList protected property The list of available profiles.
ProjectCollector::$themeHandler protected property The theme handler.
ProjectCollector::collateCustomExtensionsIntoProjects protected function Finds topmost custom extension for each extension and keeps only that.
ProjectCollector::collectProjects public function Collect projects of installed modules grouped by custom and contrib. Overrides ProjectCollectorInterface::collectProjects
ProjectCollector::loadProject public function Returns a single extension based on type and machine name. Overrides ProjectCollectorInterface::loadProject
ProjectCollector::__construct public function Constructs a \Drupal\upgrade_status\ProjectCollector.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.