You are here

FlaggingCollectionBulkForm.php in Flag Lists 4.0.x

File

src/Plugin/views/field/FlaggingCollectionBulkForm.php
View source
<?php

namespace Drupal\flag_lists\Plugin\views\field;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\views\Plugin\views\field\BulkForm;
use Drupal\flag_lists\Controller\ActionLinkController;

/**
 * Defines a flagging Collection operations bulk form element.
 *
 * Note that actions are not used but instead the ActionLinks.
 *
 * @ViewsField("flagging_collection_bulk_form")
 */
class FlaggingCollectionBulkForm extends BulkForm {

  /**
   * Flag Lists Service injected.
   *
   * @var \Drupal\flag_lists\FlagListsService
   */
  private $flagListsService;

  /**
   * Flag Service injected.
   *
   * @var \Drupal\flag\FlagService
   */
  private $flagService;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, MessengerInterface $messenger, EntityRepositoryInterface $entity_repository) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $language_manager, $messenger);
    $this->entityManager = $entity_type_manager;
    $this->actionStorage = $entity_type_manager
      ->getStorage('action');
    $this->languageManager = $language_manager;
    $this->messenger = $messenger;
    $this->entityRepository = $entity_repository;
    $this->flagListsService = \Drupal::service('flaglists');
    $this->flagService = \Drupal::service('flag');
  }

  /**
   * {@inheritdoc}
   */
  protected function emptySelectedMessage() {
    return $this
      ->t('Please select one or more Entities to work on.');
  }

  /**
   * {@inheritdoc}
   */
  protected function getBulkOptions($filtered = TRUE) {

    // Remove all existing actions and replace with our own.
    $options = [];
    $all_options['flag'] = $this
      ->t('Flag the entities in the list');
    $all_options['unflag'] = $this
      ->t('Unflag the entities in the list');
    foreach ($all_options as $id => $action) {
      if ($filtered) {
        $in_selected = in_array($id, $this->options['selected_actions']);

        // If the field is configured to include only the selected actions,
        // skip actions that were not selected.
        if ($this->options['include_exclude'] == 'include' && !$in_selected) {
          continue;
        }
        elseif ($this->options['include_exclude'] == 'exclude' && $in_selected) {
          continue;
        }
      }
      $options[$id] = $all_options[$id];
    }
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function viewsForm(&$form, FormStateInterface $form_state) {
    parent::viewsForm($form, $form_state);
    $form['header'][$this->options['id']]['action']['#title'] = $this
      ->t('Flag action');
    $options = [
      '0' => '- Create Flagging Collection -',
    ];
    foreach ($this->flagListsService
      ->getUsersFlaggingCollections() as $entity_id => $entity) {

      // Check for right Flagging Collection is done during Validation.
      $options[$entity_id] = $entity
        ->getName();
    }
    $form['header'][$this->options['id']]['flaglist'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Use this Flagging Collection'),
      '#options' => $options,
    ];
    $form['header'][$this->options['id']]['newlistFieldSet'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('New Flagging Collection'),
      '#states' => [
        'visible' => [
          ':input[name="flaglist"]' => [
            'value' => '0',
          ],
        ],
      ],
    ];
    $form['header'][$this->options['id']]['newlistFieldSet']['newlist'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Name'),
      '#states' => [
        'visible' => [
          ':input[name="flaglist"]' => [
            'value' => '0',
          ],
        ],
      ],
    ];
    $options = [];
    foreach ($this->flagListsService
      ->getAllFlagForList() as $list_id => $list) {
      $options[$list_id] = $list
        ->get('label');

      // Dig out if this is the right template.
    }
    $form['header'][$this->options['id']]['newlistFieldSet']['template'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Template flag'),
      '#options' => $options,
      '#states' => [
        'visible' => [
          ':input[name="flaglist"]' => [
            'value' => '0',
          ],
        ],
      ],
    ];
    $options = [];
    $count = 0;
    foreach ($this->flagListsService
      ->getAllFlaggingCollectionTypes() as $list_id => $list) {
      $options[$list_id] = $list
        ->get('label');
      $count = $count + 1;
    }
    $count > 1 ? $form['header'][$this->options['id']]['newlistFieldSet']['type'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Flagging Collection Type'),
      '#options' => $options,
    ] : ($form['header'][$this->options['id']]['newlistFieldSet']['type'] = [
      '#type' => 'hidden',
      '#title' => $this
        ->t('Flagging Collection Type'),
      '#value' => array_key_first($options),
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function viewsFormSubmit(&$form, FormStateInterface $form_state) {
    if ($form_state
      ->get('step') == 'views_form_views_form') {
      $user_input = $form_state
        ->getUserInput();
      $baseFlag = $this->flagListsService
        ->getFlagForListById($user_input['template'])
        ->getBaseFlag();
      if ($user_input['flaglist'] == 0) {

        // Create a new flaglist with name $newlist.
        // No cleaning of input?
        $id = strtolower($user_input['newlist']);
        $id = preg_replace("/[^a-z0-9_]/", "_", $id);
        $template = [
          'id' => $id,
          'name' => $user_input['newlist'],
          'type' => $user_input['type'],
        ];
        $flaggingCollection = $this->entityTypeManager
          ->getStorage('flagging_collection')
          ->create($template);
        $flaggingCollection
          ->setBaseFlag($user_input['template']);
        $flaggingCollection
          ->setRelatedFlag($baseFlag);
        $flaggingCollection
          ->save();
        $flag = $flaggingCollection
          ->getRelatedFlag();
        $flagList = $flaggingCollection
          ->id();
      }
      else {
        $flag = $this->flagListsService
          ->getFlaggingCollectionById($user_input['flaglist'])
          ->getRelatedFlag();
        $flagList = $user_input['flaglist'];
      }

      // Find the entities to execute the action on.
      $selected = array_filter($user_input[$this->options['id']]);
      $entities = [];
      $count = 0;
      foreach ($selected as $bulk_form_key) {
        $entity = $this
          ->loadEntityFromBulkFormKey($bulk_form_key);

        // Skip execution if current entity does not exist.
        if (empty($entity)) {
          continue;
        }
        if ($user_input['action'] == 'flag' && !empty($this->flagListsService
          ->getFlagListItemIds($flag
          ->id(), $flagList, $entity
          ->id()))) {

          // Skip execution if the entity is already in the collection.
          continue;
        }
        elseif ($user_input['action'] == 'unflag' && empty($this->flagListsService
          ->getFlagListItemIds($flag
          ->id(), $flagList, $entity
          ->id()))) {

          // Skip execution if the entity isn't in the collection.
          continue;
        }
        $count++;
        $entities[$bulk_form_key] = $entity;
      }

      // If there were entities selected but the action isn't allowed on any of
      // them, we don't need to do anything further.
      if (!$count) {

        // Maybe call the parent?
        // parent::viewsFormSubmit($form, $form_state).
        return;
      }

      // Execute the action via its link.
      //
      // Due to the following
      // https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Action%21ActionInterface.php/interface/ActionInterface/8.9.x
      // it is not implemented as an Action as it might break Drupal 9.
      foreach ($entities as $entity_id => $entity) {
        $actionLink = new ActionLinkController(\Drupal::service('flag'), $this->flagListsService, \Drupal::service('renderer'));
        switch ($user_input['action']) {
          case 'flag':
            $actionLink
              ->flag($flag, $entity
              ->id(), $flagList);
            break;
          case 'unflag':
            $actionLink
              ->unflag($flag, $entity
              ->id(), $flagList);
            break;
          default:
            break;
        }
      }
      $this->messenger
        ->addStatus($this
        ->formatPlural($count, '@count entity affected in %flaglists.', '@count entities affected in %flaglist.', [
        '%flaglist' => $this->flagListsService
          ->getFlaggingCollectionById($flagList)
          ->getName(),
      ]));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function viewsFormValidate(&$form, FormStateInterface $form_state) {
    if ($form_state
      ->getValue('flaglist') == 0 && empty($form_state
      ->getValue('newlist')) && $form_state
      ->getValue('action') == 'flag') {

      // A new Flagging Collection must have a name.
      $form_state
        ->setErrorByName('newlist', $this
        ->t('Please set a name for the new Flagging Collection.'));
    }
    if (!empty($form_state
      ->getValue('newlist'))) {
      $listName = $this->flagListsService
        ->getFlaggingCollectionIdByName($form_state
        ->getValue('newlist'));
      if (!empty($listName)) {

        // The new name must not already exist.
        $form_state
          ->setErrorByName('newlist', $this
          ->t('The new Flagging Collection name exists already.'));
      }
    }
    if ($form_state
      ->getValue('flaglist') == 0 && $form_state
      ->getvalue('action') != 'flag') {

      // It is only possible to unflag from existing Collections.
      $form_state
        ->setErrorByName('flaglist', $this
        ->t('Please select an existing Flagging Collection.'));
    }
    $selected = $form_state
      ->getValue($this->options['id']);
    if (empty($selected) || empty(array_filter($selected))) {

      // The action must have some target Entities.
      $form_state
        ->setErrorByName('', $this
        ->emptySelectedMessage());
    }
    $user_input = $form_state
      ->getUserInput();
    if ($user_input['flaglist'] != 0) {

      // This is an existing flag.
      $flagEntityType = $this->flagListsService
        ->getFlaggingCollectionById($user_input['flaglists'])
        ->getRelatedFlag()
        ->get('entity_type');
    }
    else {

      // This is a just created flag.
      $flagEntityType = $this->flagService
        ->getFlagById($user_input['template'])
        ->get('entity_type');
    }
    foreach ($selected as $bulk_form_key) {

      // Skip execution if current entity does not exist.
      if (empty($bulk_form_key)) {
        continue;
      }
      $entity = $this
        ->loadEntityFromBulkFormKey($bulk_form_key);
      if ($entity
        ->getEntityTypeId() != $flagEntityType) {

        // Flagging Collection Entitiy must match the Listed ones.
        $form_state
          ->setErrorByName('flaglist', $this
          ->t('Incorrect target Flagging Collection chosen for the listed entity type.'));
      }
    }
  }

}

Classes

Namesort descending Description
FlaggingCollectionBulkForm Defines a flagging Collection operations bulk form element.