module_matrix-1.0.2/module_matrix.module

module_matrix.module
<?php

/**
 * @file
 * Provides the module implementation for module_matrix.
 *
 * Contains template preprocessing and theme definitions for Views.
 *
 * Filename:     module_matrix.module
 * Website:      https://www.flashwebcenter.com
 * Description:  template.
 * Developer:    Alaa Haddad https://www.alaahaddad.com.
 */

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;

/**
 * Implements hook_help().
 */
function module_matrix_help($route_name, RouteMatchInterface $route_match): ?string {
  if ($route_name === 'help.page.module_matrix') {
    return _module_matrix_helper_render_readme();
  }
  return NULL;
}

/**
 * Helper function to render README.md.
 *
 * @return string
 *   The rendered content of README.md.
 */
function _module_matrix_helper_render_readme(): string {
  $readme_path = __DIR__ . '/README.md';
  $text = file_get_contents($readme_path);

  if ($text === FALSE) {
    return t('README.md file not found.');
  }

  if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
    return '<pre>' . htmlspecialchars($text) . '</pre>';
  }

  // Use the Markdown filter to render the README.
  $filter_manager = \Drupal::service('plugin.manager.filter');
  $settings = \Drupal::config('markdown.settings')->getRawData();
  $filter = $filter_manager->createInstance('markdown', ['settings' => $settings]);
  return $filter->process($text, 'en')->getProcessedText();
}

/**
 * Implements hook_theme_registry_alter().
 */
function module_matrix_theme_registry_alter(array &$theme_registry): void {
  $templates = [
    'system_modules_uninstall' => 'system-modules-uninstall',
    'system_modules_details' => 'system-modules-details',
  ];

  $module_path = \Drupal::service('extension.list.module')->getPath('module_matrix') . '/templates';

  foreach ($templates as $key => $template) {
    if (isset($theme_registry[$key])) {
      $theme_registry[$key]['path'] = $module_path;
      $theme_registry[$key]['template'] = $template;
    }
  }
}

/**
 * Implements hook_preprocess_HOOK() for system_modules_details.
 */
function module_matrix_preprocess_system_modules_details(array &$variables): void {
  // Core uses this for module details.
  $form = $variables['form'];
  $config = \Drupal::config('module_matrix.settings');
  $extension_list = \Drupal::service('extension.list.module')->getList();

  // Get categorized modules (parents and submodules).
  [$parent_modules, $sub_modules] = module_matrix_categorize_modules($extension_list);

  // Enhance module details.
  foreach ($variables['modules'] as &$module) {
    $id = $module['name']['#parents'][1] ?? NULL;
    if ($id && isset($extension_list[$id])) {
      module_matrix_enhance_module($module, $extension_list[$id], $parent_modules, $sub_modules);
    }
  }

  foreach ($variables['modules'] as &$module) {
    // Process "requires" field to style missing/disabled modules.
    if (isset($module['requires']) && is_array($module['requires']) && !empty($module['requires']['#markup'])) {
      $module['requires']['#markup'] = module_matrix_style_dependency_status($module['requires']['#markup']);
    }

    // Process "required_by" field to style missing/disabled modules.
    if (isset($module['required_by']) && is_array($module['required_by']) && !empty($module['required_by']['#markup'])) {
      $module['required_by']['#markup'] = module_matrix_style_dependency_status($module['required_by']['#markup']);
    }
  }

  // Add visibility settings and enabled count to variables.
  $module_options = module_matrix_get_modules_options($config);
  $variables['enabled_count'] = count(array_filter($module_options, fn($value) => $value === TRUE));

  // Merge module options with visibility settings.
  $variables['visibility'] = array_merge($module_options, module_matrix_get_visibility_settings($config));

}

/**
 * Implements hook_preprocess_HOOK() for system_modules_uninstall.
 */
function module_matrix_preprocess_system_modules_uninstall(array &$variables): void {
  $config = \Drupal::config('module_matrix.settings');
  $variables['visibility'] = module_matrix_get_visibility_settings($config);
  foreach ($variables['modules'] as &$module) {
    // Process "required_by" field for uninstall page.
    if (isset($module['required_by']) && is_array($module['required_by']) && !empty($module['required_by']['#markup'])) {
      $module['required_by']['#markup'] = module_matrix_style_dependency_status($module['required_by']['#markup']);
    }
  }
}

/**
 * Styles dependency status indicators.
 *
 * Wraps (missing), (disabled), and (enabled) indicators in styled spans.
 *
 * @param string|\Drupal\Core\StringTranslation\TranslatableMarkup $dependency_list
 *   The dependency list string or renderable markup.
 *
 * @return \Drupal\Core\Render\Markup
 *   Styled dependency list with wrapped status indicators.
 */
function module_matrix_style_dependency_status(string|TranslatableMarkup $dependency_list): Markup {
  // Convert to string if it's a TranslatableMarkup object.
  $list_string = (string) $dependency_list;

  // Define status patterns and their replacement styles.
  $replacements = [
    // Missing modules - red, bold, with background.
    '/\(missing\)/i' => '<span class="admin-missing">(missing)</span>',

    // Disabled modules - orange, bold, with background.
    '/\(disabled\)/i' => '<span class="admin-disabled">(disabled)</span>',

    // Enabled modules - subtle green (optional).
    '/\(enabled\)/i' => '<span class="admin-enabled">(enabled)</span>',
  ];

  // Apply all replacements using regex for case-insensitive matching.
  foreach ($replacements as $pattern => $replacement) {
    $list_string = preg_replace($pattern, $replacement, $list_string);
  }

  // Return as Markup to allow HTML rendering.
  return Markup::create($list_string);
}

/**
 * Retrieves module options settings for templates.
 */
function module_matrix_get_modules_options($config): array {
  return [
    // These are enabled by default to ensure they appear on first install.
    'module_description' => TRUE,
    'module_machine_name' => $config->get('module_machine_name') ?? TRUE,
    'module_version' => $config->get('module_version') ?? TRUE,
    'module_lifecycle' => $config->get('module_lifecycle') ?? TRUE,
    'module_requires' => $config->get('module_requires') ?? TRUE,
    'module_required_by' => $config->get('module_required_by') ?? TRUE,
    'module_status' => $config->get('module_status') ?? TRUE,
    'module_project' => $config->get('module_project') ?? TRUE,
    'module_mtime' => $config->get('module_mtime') ?? TRUE,
    'module_subpath' => $config->get('module_subpath') ?? TRUE,
    'module_stability' => $config->get('module_stability') ?? TRUE,
    'module_links' => $config->get('module_links') ?? TRUE,
    'module_issue_link' => $config->get('module_issue_link') ?? TRUE,
    'module_usage_link' => $config->get('module_usage_link') ?? TRUE,
  ];
}

/**
 * Retrieves visibility settings for the template.
 */
function module_matrix_get_visibility_settings($config): array {
  return [
    // These are disabled by default but prevent null errors in templates.
    'compact_layout' => $config->get('compact_layout') ?? FALSE,
    'scrollable_sidebar' => $config->get('scrollable_sidebar') ?? FALSE,
    'layout' => $config->get('layout') ?? 'left',
    'disable_library' => $config->get('disable_library') ?? FALSE,
    'grid_layout' => $config->get('grid_layout') ?? FALSE,
    'style_mode' => $config->get('style_mode') ?? 'light',
    'accent_color' => $config->get('accent_color') ?? 'neutral',
  ];
}

/**
 * Categorizes modules into parent modules and submodules.
 */
function module_matrix_categorize_modules(array $extension_list): array {
  $parent_modules = [];
  $sub_modules = [];

  foreach ($extension_list as $machine_name => $extension) {
    $subpath = $extension->getPath();
    $parts = explode('/', $subpath);

    if (count($parts) >= 3 && $parts[0] === 'modules' && $parts[1] === 'contrib') {
      $project_name = $parts[2];

      if (count($parts) === 3) {
        $parent_modules[$machine_name] = [
          'project_name' => $project_name,
          'name' => $extension->info['name'] ?? $machine_name,
        ];
      }
      else {
        $sub_modules[$machine_name] = [
          'subpath' => $subpath,
          'project_name' => $project_name,
        ];
      }
    }
  }

  return [$parent_modules, $sub_modules];
}

/**
 * Enhances a single module with additional data, links, and submodule messages.
 */
function module_matrix_enhance_module(array &$module, $extension, array $parent_modules, array $sub_modules): void {
  $subpath = $extension->getPath();
  $parts = explode('/', $subpath);
  $project_name = $parts[2] ?? NULL;

  // Initialize module attributes.
  $package_name = $extension->info['package'] ?? 'Other';
  $stability = module_matrix_get_stability($extension->info['version'] ?? '');
  $lifecycle = $extension->info['lifecycle'] ?? 'Unknown';

  // Build links and submodule message.
  $issue_link = NULL;
  $usage_link = NULL;
  $submodule_message = NULL;

  if (isset($parent_modules[$module['name']['#parents'][1]])) {
    // Parent module.
    $issue_link = Url::fromUri("https://www.drupal.org/node/add/project-issue/{$project_name}")->toString();
    $usage_link = Url::fromUri("https://www.drupal.org/project/usage/{$project_name}")->toString();
  }
  elseif (isset($sub_modules[$module['name']['#parents'][1]])) {
    // Submodule: Find its parent.
    foreach ($parent_modules as $parent_data) {
      if ($parent_data['project_name'] === $project_name) {
        $submodule_message = "This is a submodule for the parent module: {$parent_data['name']}.";
        $issue_link = Url::fromUri("https://www.drupal.org/node/add/project-issue/{$parent_data['project_name']}")->toString();
        $usage_link = Url::fromUri("https://www.drupal.org/project/usage/{$parent_data['project_name']}")->toString();
        break;
      }
    }
  }

  // Add data to the module.
  $module += [
    'package' => $package_name,
    'lifecycle' => $lifecycle,
    'status' => $module['status'] ?? (\Drupal::service('module_handler')->moduleExists($module['name']['#parents'][1]) ? 1 : 0),
    'weight' => $module['weight'] ?? $extension->weight ?? 'N/A',
    'project' => $project_name,
    'mtime' => $module['mtime'] ?? (!empty($extension->info['mtime']) ? date('Y-m-d H:i:s', $extension->info['mtime']) : 'Unknown'),
    'stability' => $stability,
    'subpath' => $subpath,
    'issue_link' => $issue_link,
    'usage_link' => $usage_link,
    'submodule_message' => $submodule_message,
  ];
}

/**
 * Determines the stability of a module version.
 */
function module_matrix_get_stability(string $version): string {
  if (str_contains($version, "-dev")) {
    return 'dev';
  }
  elseif (str_contains($version, "-alpha")) {
    return 'alpha';
  }
  elseif (str_contains($version, "-beta")) {
    return 'beta';
  }
  elseif (str_contains($version, "-rc")) {
    return 'rc';
  }
  return 'stable';
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function module_matrix_form_system_modules_alter(array &$form, FormStateInterface $form_state, $form_id): void {
  // Remove the 'container' wrapper explicitly if it's part of the render array.
  // Adjust module packages and elements similar to module_filter.
  if (isset($form['modules']) && is_array($form['modules'])) {
    foreach (Element::children($form['modules']) as $package_name) {
      $package = &$form['modules'][$package_name];

      // Modify the package-level details element.
      if (isset($package['#type']) && $package['#type'] === 'details') {
        $package['#type'] = 'container';
        unset($package['#open']);
        $package['#attributes']['class'][] = 'module-package-wrapper';
      }
    }
  }

  $form['intro_message'] = [
    '#type' => 'markup',
    '#markup' => '<p>' . t('<a href=":layout_url" target="_blank"><span class="material-icons" aria-hidden="true">settings</span> Adjust layout and options</a>', [
      ':layout_url' => Url::fromRoute('module_matrix.settings_form')->toString(),
    ]) . '</p>',
  // Ensures it appears at the top.
    '#weight' => -100,
    '#prefix' => '<div class="intro-message-class">',
    '#suffix' => '</div>',
  ];

  $form['filters'] = [
    '#type' => 'fieldset',

    '#attributes' => [
      'class' => ['module-matrix-filters'],
    ],
  ];

  // Add the text filter field.
  $form['filters']['text'] = [
    '#type' => 'textfield',
    '#title' => t('Search Modules'),
    '#placeholder' => t('Enter module name or description'),
    '#attributes' => [
      'class' => ['form-control'],
    ],
  ];

  // Add the status filter container.
  $form['filters']['status'] = [
    '#type' => 'container',
    '#attributes' => ['class' => ['module-matrix-status', 'form-item']],
    'checkboxes' => [
      '#type' => 'checkboxes',
      '#title' => t('Filter by status'),
      '#options' => [
        '1' => t('Enabled'),
        '0' => t('Disabled'),
        'unavailable' => t('Unavailable'),
      ],
      '#default_value' => [],
      '#attributes' => [
        'class' => ['form-checkboxes', 'enable-filter'],
      ],
    ],
  ];

  // Add the lifecycle filter container.
  $form['filters']['lifecycle'] = [
    '#type' => 'container',
    '#attributes' => ['class' => ['module-matrix-lifecycle', 'form-item']],
    'checkboxes' => [
      '#type' => 'checkboxes',
      '#title' => t('Filter by lifecycle'),
      '#options' => [
        'stable' => t('Stable'),
        'deprecated' => t('Deprecated'),
        'experimental' => t('Experimental'),
        'obsolete' => t('Obsolete'),
      ],
      '#default_value' => [],
      '#attributes' => [
        'class' => ['form-checkboxes', 'lifecycle-filter'],
      ],
    ],
  ];

  // Add the stability filter container.
  $form['filters']['stability'] = [
    '#type' => 'container',
    '#attributes' => ['class' => ['module-matrix-stability', 'form-item']],
    'checkboxes' => [
      '#type' => 'checkboxes',
      '#title' => t('Filter by stability'),
      '#options' => [
        'stable' => t('Stable'),
        'rc' => t('Release Candidate'),
        'beta' => t('Beta'),
        'alpha' => t('Alpha'),
        'dev' => t('Development'),
      ],
      '#default_value' => [],
      '#attributes' => [
        'class' => ['form-checkboxes', 'stability-filter'],
      ],
    ],
  ];

  // Add the reset button.
  $form['filters']['reset'] = [
    '#type' => 'button',
    '#value' => t('Reset'),
    '#attributes' => [
      'id' => 'reset-filters',
  // Adding Drupal button classes.
      'class' => ['button', 'reset-button', 'form-button'],
    ],
  ];

}

/**
 * Implements hook_theme_suggestions_fieldset_alter().
 */
function module_matrix_theme_suggestions_fieldset_alter(array &$suggestions, array $variables) {
  // Get the current route name.
  $route_name = \Drupal::routeMatch()->getRouteName();

  // Apply only on 'admin/modules' and 'module_matrix.settings_form'.
  if (in_array($route_name, ['system.modules_list',
    'module_matrix.settings_form',
  ])) {
    $suggestions[] = 'fieldset__module_matrix';
  }
}

/**
 * Implements hook_theme().
 */
function module_matrix_theme($existing, $type, $theme, $path) {
  return [
    'fieldset__module_matrix' => [
      'base hook' => 'fieldset',
      'template' => 'fieldset--module-matrix',
      'path' => $path . '/templates',
    ],
  ];
}

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

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