safedelete-1.0.0/modules/safedelete_menu_report/src/Service/ReportHelper.php

modules/safedelete_menu_report/src/Service/ReportHelper.php
<?php

namespace Drupal\safedelete_menu_report\Service;

use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\Core\Render\Markup;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\node\Entity\NodeType;
use Drupal\node\Entity\Node;
use Drupal\safedelete_menu_report\Service\ReportService;

class ReportHelper {

  use StringTranslationTrait;

  protected EntityTypeManagerInterface $etm;
  protected EntityFieldManagerInterface $fieldManager;
  protected ModerationInformationInterface $moderationInfo;
  protected LanguageManagerInterface $languageManager;
  protected ReportService $reportService;
  protected EntityTypeBundleInfoInterface $bundleInfo;

  public function __construct(EntityTypeManagerInterface $etm, EntityFieldManagerInterface $fieldManager, ModerationInformationInterface $moderationInfo, ReportService $reportService, LanguageManagerInterface $languageManager, EntityTypeBundleInfoInterface $bundleInfo) {
    $this->etm = $etm;
    $this->fieldManager = $fieldManager;
    $this->moderationInfo = $moderationInfo;
    $this->reportService = $reportService;
    $this->languageManager = $languageManager;
    $this->bundleInfo = $bundleInfo;
  }

  private function bundleLabelFromNode(Node $node): string {
    $bundle = $node->bundle();
    $info = $this->bundleInfo->getBundleInfo('node');
    return (string) ($info[$bundle]['label'] ?? $bundle);
  }

  public function alterSafedeleteSettingsForm(array &$form, FormStateInterface $form_state): void {
    $config = \Drupal::configFactory()->getEditable('safedelete_menu_report.settings');

    $form['safedelete_menu_report'] = [
      '#type' => 'details',
      '#title' => $this->t('Safedelete Menu Report'),
      '#open' => TRUE,
      '#tree' => TRUE,
    ];

    // Menus list.
    $menu_storage = $this->etm->getStorage('menu');
    $menus = $menu_storage->loadMultiple();
    if (empty($menus)) {
      $link = Link::fromTextAndUrl($this->t('Safedelete settings'), Url::fromRoute('safedelete.settings'))->toString();
      \Drupal::logger('safedelete_menu_report')->warning(
        'No menus configured. Please configure menus in @link.',
        ['@link' => $link]);
    }
    $menu_options = [];
    foreach ($menus as $menu) {
      $menu_options[$menu->id()] = $menu->label();
    }

    $form['safedelete_menu_report']['menus'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Menus to include in the report'),
      '#options' => $menu_options,
      '#default_value' => array_values($config->get('menus') ?: []),
      '#description' => $this->t('Select one or more menus that the report can target.'),
    ];

    $form['safedelete_menu_report']['moderation_state_wrapper'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'safedelete-menu-report-ms-wrapper'],
    ];

    if (isset($form['actions']['submit'])) {
      $form['actions']['submit']['#submit'][] = [static::class, 'settingsSubmit'];
    }
  }

  public static function ajaxModerationRefresh(array &$form, FormStateInterface $form_state) {
    return $form['safedelete_menu_report']['moderation_state_wrapper'];
  }

  public static function settingsSubmit(array $form, FormStateInterface $form_state): void {
    $values = (array) $form_state->getValue('safedelete_menu_report');
    $menus = array_values(array_filter($values['menus'] ?? [], fn($v) => !empty($v)));

    \Drupal::configFactory()->getEditable('safedelete_menu_report.settings')
      ->set('menus', $menus)
      ->save();
  }

  public function buildReportRows(string $menu_name): array {
    $lang = $this->languageManager->getCurrentLanguage();
    $langcode = $lang->getId();

    // Fetch flat rows from the ReportService (parent-disabled + published children).
    $records = $this->reportService->findDisabledParentsWithPublishedChildren($menu_name, $langcode);

    // Group by parent_nid → collect children per parent.
    $groups = [];
    $parent_nids = [];
    $child_nids = [];
    foreach ($records as $r) {
      $pid = (int) ($r['parent_nid'] ?? 0);
      $cid = (int) ($r['child_nid'] ?? 0);
      if (!$pid || !$cid) {
        continue;
      }
      if (!isset($groups[$pid])) {
        $groups[$pid] = [
          'parent' => [
            'nid' => $pid,
            'type' => (string) ($r['parent_type'] ?? ''),
            'published' => (int) ($r['parent_node_published'] ?? 0),
            'enabled' => (int) ($r['parent_enabled'] ?? 0),
          ],
          'children' => [],
        ];
      }
      $groups[$pid]['children'][$cid] = [
        'nid' => $cid,
        'enabled' => (int) ($r['child_enabled'] ?? 0),
      ];
      $parent_nids[$pid] = $pid;
      $child_nids[$cid] = $cid;
    }

    if (!$groups) {
      return [];
    }

    // Sort parents numerically by parent_nid (keys of $groups).
    uksort($groups, static function ($a, $b) {
      return (int) $a <=> (int) $b;
    });

    /** @var \Drupal\node\NodeInterface[] $parents */
    $parents = $this->etm->getStorage('node')->loadMultiple($parent_nids);
    /** @var \Drupal\node\NodeInterface[] $children */
    $children = $this->etm->getStorage('node')->loadMultiple($child_nids);

    $rows = [];
    foreach ($groups as $pid => $group) {
      $pnode = $parents[$pid] ?? NULL;
      if (!$pnode) {
        // Defensive: if parent node couldn't be loaded, skip the group.
        continue;
      }

      // Build parent link to Edit form (language aware).
      $parent_link = Link::fromTextAndUrl(
        $pnode->label() . ' (nid ' . $pnode->id() . ')',
        Url::fromRoute('entity.node.edit_form', ['node' => $pnode->id()], ['language' => $lang])
      )->toString();

      // Render parent row — keep columns compatible with previous table shape.
      // Columns example (adjust to your headers order):
      // [ Parent, (placeholder), Parent type, Parent published, Parent menu link enabled, (placeholder) ]
      $rows[] = [
        $parent_link,
        $pnode->id(),
        $this->bundleLabelFromNode($pnode),
        $group['parent']['published'] ? $this->t('Published') : $this->t('Unpublished'),
        $group['parent']['enabled'] ? $this->t('Enabled') : $this->t('Disabled'),
      ];

      // Build child <ul> for this parent (children sorted by nid asc).
      ksort($group['children'], SORT_NUMERIC);
      $lis = [];
      foreach ($group['children'] as $cinfo) {
        $cnode = $children[$cinfo['nid']] ?? NULL;
        if (!$cnode) {
          continue;
        }
        $child_link = Link::fromTextAndUrl(
          $cnode->label() . ' (nid ' . $cnode->id() . ')',
          Url::fromRoute('entity.node.edit_form', ['node' => $cnode->id()], ['language' => $lang])
        )->toString();
        // Optionally show child link enabled/disabled state.
        $suffix = ' — ' . $this->bundleLabelFromNode($cnode);
        $lis[] = '<li>' . $child_link . $suffix . '</li>';
      }

      $warning = $this->t('Warning, these children need a new parent, please update their parent menu item selection in the node edit form.');
      $child_html = '<div class="safedelete-warning">'
        . '<strong>⚠ ' . $warning . '</strong>'
        . '<ul>' . implode('', $lis) . '</ul>'
        . '</div>';

      // Determine how many columns the table has (match your controller’s header).
      $colspan = 4; // If your header has 6 columns total: 1 (parent) + 5 remaining

      $rows[] = [
        '', // First column intentionally empty under the parent label
        [
          'data' => Markup::create($child_html),
          'colspan' => $colspan,
          'class' => ['safedelete-report-children-cell'],
        ],
        // No more cells; colspan covers the rest.
      ];
      // Also mark the whole row, so CSS can target it.
      $end = count($rows) - 1;
      $rows[$end]['#attributes']['class'][] = 'safedelete-report-children-row';

    }

    return $rows;

  }

}

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

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