image_to_media_swapper-2.x-dev/src/Form/ManualSwapQueueForm.php

src/Form/ManualSwapQueueForm.php
<?php

declare(strict_types=1);

namespace Drupal\image_to_media_swapper\Form;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Url;
use Drupal\image_to_media_swapper\BatchProcessorService;
use Drupal\image_to_media_swapper\MediaSwapFormService;
use Drupal\image_to_media_swapper\MediaSwapRecordTableService;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a manual review queue form for image to media swapper.
 */
final class ManualSwapQueueForm extends FormBase {

  /**
   * The batch processor service.
   *
   * @var \Drupal\image_to_media_swapper\BatchProcessorService
   */
  protected BatchProcessorService $batchProcessorService;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The state service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected StateInterface $state;

  /**
   * The route provider service.
   *
   * @var \Drupal\Core\Routing\RouteProviderInterface
   */
  protected RouteProviderInterface $routeProvider;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected AccountProxyInterface $currentUser;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected DateFormatterInterface $dateFormatter;

  /**
   * The media swap form service.
   *
   * @var \Drupal\image_to_media_swapper\MediaSwapFormService
   */
  protected MediaSwapFormService $mediaSwapFormService;

  /**
   * The module handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;

  /**
   * Constructs the form.
   */
  public function __construct(
    RouteProviderInterface $routeProvider,
    EntityTypeManagerInterface $entityTypeManager,
    BatchProcessorService $batchProcessorService,
    StateInterface $state,
    private readonly MediaSwapRecordTableService $tableService,
    AccountProxyInterface $currentUser,
    DateFormatterInterface $dateFormatter,
    MediaSwapFormService $mediaSwapFormService,
    ModuleHandlerInterface $moduleHandler,
  ) {
    $this->batchProcessorService = $batchProcessorService;
    $this->entityTypeManager = $entityTypeManager;
    $this->state = $state;
    $this->routeProvider = $routeProvider;
    $this->currentUser = $currentUser;
    $this->dateFormatter = $dateFormatter;
    $this->mediaSwapFormService = $mediaSwapFormService;
    $this->moduleHandler = $moduleHandler;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    /** @var \Drupal\Core\Routing\RouteProviderInterface $routeProvider */
    $routeProvider = $container->get('router.route_provider');
    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager */
    $entityTypeManager = $container->get('entity_type.manager');
    /** @var \Drupal\image_to_media_swapper\BatchProcessorService $batchProcessorService */
    $batchProcessorService = $container->get('image_to_media_swapper.batch_processor_service');
    /** @var \Drupal\Core\State\StateInterface $drupalState */
    $drupalState = $container->get('state');
    /** @var \Drupal\image_to_media_swapper\MediaSwapRecordTableService $tableService */
    $tableService = $container->get('image_to_media_swapper.table_service');
    /** @var \Drupal\Core\Session\AccountProxyInterface $currentUser */
    $currentUser = $container->get('current_user');
    /** @var \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter */
    $dateFormatter = $container->get('date.formatter');
    /** @var \Drupal\image_to_media_swapper\MediaSwapFormService $mediaSwapFormService */
    $mediaSwapFormService = $container->get('image_to_media_swapper.form_service');
    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler */
    $moduleHandler = $container->get('module_handler');
    return new self(
      $routeProvider,
      $entityTypeManager,
      $batchProcessorService,
      $drupalState,
      $tableService,
      $currentUser,
      $dateFormatter,
      $mediaSwapFormService,
      $moduleHandler,
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'image_to_media_manual_swap_queue_form';
  }

  /**
   * {@inheritdoc}
   *
   * @throws \Exception
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $form['description'] = [
      '#markup' => $this->t('This form allows you to scan content for images and file links, then manually review and process each item individually.'),
    ];

    $form['scan_options'] = [
      '#type' => 'details',
      '#title' => $this->t('Scan Options'),
      '#open' => TRUE,
    ];

    $form['scan_options']['description'] = [
      '#markup' => $this->t('<p>Select text fields to scan for images and file links. Items will be added to a queue for manual review.</p>'),
    ];

    // Get fields with images.
    $imageFields = $this->mediaSwapFormService->getFieldsWithImages();
    if (!empty($imageFields)) {
      $form['scan_options']['image_selector'] = [
        '#type' => 'select',
        '#title' => $this->t('Text field with &lt;img&gt; tags to queue'),
        '#options' => ['' => $this->t('- None -')] + $imageFields,
        '#description' => $this->t('Select a field containing &lt;img&gt; tags to add to the manual review queue.'),
      ];
    }
    // Check if the module linkit is installed.
    if ($this->moduleHandler->moduleExists('linkit')) {
      // Get fields with file links.
      $linkFields = $this->mediaSwapFormService->getFieldsWithFileLinks();
      if (!empty($linkFields)) {
        $form['scan_options']['link_selector'] = [
          '#type' => 'select',
          '#title' => $this->t('Text field with file links to queue'),
          '#options' => ['' => $this->t('- None -')] + $linkFields,
          '#description' => $this->t('Select a field containing &lt;a&gt; tags linking to files to add to the manual review queue.'),
        ];
      }
    }
    else {
      $linkit_url = Url::fromUri('https://www.drupal.org/project/linkit');
      $form['scan_options']['link_selector'] = [
        '#markup' => $this->t('<p><em>The @linkit module is not enabled, so scanning for file links is unavailable.</em></p>', [
          '@linkit' => Link::fromTextAndUrl('Linkit', $linkit_url)
            ->toString(),
        ]
        ),
      ];
    }
    if (empty($imageFields) && empty($linkFields)) {
      $form['scan_options']['no_fields'] = [
        '#markup' => $this->t('<div class="messages messages--status">No text fields with images or file links were found.</div>'),
      ];
    }
    else {
      $form['scan_options']['actions'] = [
        '#type' => 'actions',
        'submit' => [
          '#type' => 'submit',
          '#value' => $this->t('Scan and add to queue'),
          '#submit' => ['::submitScanForm'],
          '#button_type' => 'primary',
        ],
      ];
    }

    // Display pending items that need review.
    $form['pending_items'] = [
      '#type' => 'details',
      '#title' => $this->t('Pending Items'),
      '#open' => TRUE,
    ];

    // Count total pending items.
    $pendingCount = $this->mediaSwapFormService->getPendingItemsCount();

    if ($pendingCount > 0) {
      $form['pending_items']['info'] = [
        '#markup' => $this->t('<p>There are @count items pending review. Process them one by one to convert images and file links to media entities.</p>', [
          '@count' => $pendingCount,
        ]),
      ];
      $form['pending_items']['items'] = $this->tableService->buildTable('-14 day', 20, ['pending']);
    }
    else {
      $form['pending_items']['info'] = [
        '#markup' => $this->t('<p>There are no items pending review.</p>'),
      ];
    }

    // Show recent queue items.
    $form['recent_items'] = $this->tableService->buildTable('-14 day', 20);
    $form['recent_items']['footer'] = [
      '#markup' => Link::createFromRoute($this->t('View all records'),
        'entity.media_swap_record.collection')->toString(),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    // Only check if this is the scan form submission.
    if ($form_state->getTriggeringElement()['#submit'][0] === '::submitScanForm') {
      $image_field = $form_state->getValue('image_selector');
      $link_field = $form_state->getValue('link_selector');

      // At least one field must be selected.
      if (empty($image_field) && empty($link_field)) {
        $form_state->setErrorByName('image_selector', $this->t('Please select at least one field to scan.'));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    // Main submit handler is empty since we use specific submit handlers.
  }

  /**
   * Submit handler for the scan form.
   */
  public function submitScanForm(array &$form, FormStateInterface $form_state): void {
    $image_field = $form_state->getValue('image_selector');
    $link_field = $form_state->getValue('link_selector');
    $totalAdded = 0;

    // Process image field if selected.
    if (!empty($image_field)) {
      $added = $this->mediaSwapFormService->createPendingRecordsForField($image_field, 'images');
      $totalAdded += $added;
      $this->messenger()
        ->addStatus($this->t('Added @count entities with images to the review queue.', [
          '@count' => $added,
        ]));
    }

    // Process link field if selected.
    if (!empty($link_field)) {
      $added = $this->mediaSwapFormService->createPendingRecordsForField($link_field, 'links');
      $totalAdded += $added;
      $this->messenger()
        ->addStatus($this->t('Added @count entities with file links to the review queue.', [
          '@count' => $added,
        ]));
    }

    if ($totalAdded === 0) {
      $this->messenger()
        ->addWarning($this->t('No new items were found to add to the queue.'));
    }
  }

  /**
   * Submit handler for the process all form.
   */
  public function submitProcessAllForm(array &$form, FormStateInterface $form_state): void {
    // Set up a batch process to handle all pending items.
    $pendingRecords = $this->mediaSwapFormService->getPendingRecords();

    if (empty($pendingRecords)) {
      $this->messenger()->addStatus($this->t('No pending items to process.'));
      return;
    }

    $operations = [];
    foreach ($pendingRecords as $record) {
      $operations[] = [
        ['\Drupal\image_to_media_swapper\BatchHandler', 'processRecord'],
        [$record->id()],
      ];
    }

    $batch = [
      'title' => $this->t('Processing queued items...'),
      'operations' => $operations,
      'finished' => [
        '\Drupal\image_to_media_swapper\BatchHandler',
        'batchFinished',
      ],
      'init_message' => $this->t('Starting to process queued items...'),
      'progress_message' => $this->t('Processed @current out of @total.'),
      'error_message' => $this->t('An error occurred during processing.'),
    ];

    batch_set($batch);
  }

  /**
   * Submit handler for the recheck form.
   */
  public function submitRecheckForm(array &$form, FormStateInterface $form_state): void {
    $count = $this->mediaSwapFormService->recheckProcessedItems();
    $this->messenger()
      ->addStatus($this->t('Rechecked @count items and updated their status.', [
        '@count' => $count,
      ]));
  }

}

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

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