You are here

flag_lists.module in Flag Lists 4.0.x

Contains flag_lists.module.

File

flag_lists.module
View source
<?php

/**
 * @file
 * Contains flag_lists.module.
 */
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\flag\FlagInterface;
use Drupal\flag_lists\FlagTracker;

/**
 * Implements hook_help().
 */
function flag_lists_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {

    // Main module help for the flag_lists module.
    case 'help.page.flag_lists':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Flag Lists module handle collections (lists) of Flags.') . '</p>';
      $output .= '<p>' . t('When the Flag Lists module is installed a reasonable set of default configuration items are loaded. They are a default Flag collection for the entity type "node" and a connected bundle for the same. Also a page view and a block to show flag lists items are configured. The page view is activated by default but the block need to be added by hand.') . '</p>';
      $output .= '<p>' . t('In short, to use the Flag Lists module do the following:') . '</p>';
      $output .= '<ul><li>';
      $output .= t('Go to <a href=":flagging_collection"><em>My Flagging Collections</em></a>', [
        ':flagging_collection' => Url::fromRoute('entity.flagging_collection.collection')
          ->toString(),
      ]);
      $output .= '</li><li>';
      $output .= t('Click <a href=":add"><em>Add Flagging collection</em></a>', [
        ':add' => Url::fromRoute('entity.flagging_collection.add_page')
          ->toString(),
      ]);
      $output .= '</li><li>';
      $output .= t('Name the list and save it');
      $output .= '</li><li>';
      $output .= t("Now a link to add the entity to the Flag list is seen on the entities that the Flag List is connected with. By default these are all node's. If you need a Flag List for another entity a Flag must be created and marked as a Flag List template.");
      $output .= '</li></ul>';
      $url = Url::fromUri('https://www.drupal.org/docs/8/modules/flag-lists');
      $link = Link::fromTextAndUrl('Flag Lists', $url);
      $output .= '<p>';
      $output .= t('More detailed information on the usage of this module can be found on the Drupal documentation site under') . ' ';
      $output .= $link
        ->toString();
      $output .= '</p>';
      return $output;
    case 'entity.flag_for_list.collection':
      $output = '';
      $output .= '<h3>' . t('Templates for Flagging Collections') . '</h3>';
      $output .= '<p>' . t('The <em>Templates</em> you see here are the <em>Flags</em> you have marked as being available for usage as <em>templates for Flagging Collections</em> when you created the <em>Flag</em>.') . '</p>';
      $output .= '<p>' . t('All entities that match the specific combination of "Entity" and "Bundles" in the list below will have the <em>Flagging Collection</em> attached to them if the user created a <em>Flagging Collection</em> based on that Template.') . '</p>';
      $output .= '<p>' . t('The template chosen decide the feel, look and behaviour of the <em>Flagging Collection</em>.') . '</p>';
      return $output;
    case 'entity.flagging_collection.collection':
      $output = '';
      $output .= '<h3>' . t('Flagging Collections') . '</h3>';
      $output .= '<p>' . t('Below are all your accessible Flagging collections on this system.') . '</p>';
      return $output;
    case 'entity.flagging_collection_type.collection':
      $output = '';
      $output .= '<h3>' . t('Flag Collection Types') . '</h3>';
      $output .= '<p>' . t('Create and configure your Flag Collection Types. The Collection types will decide how your Flag Collections are presented and what field they will have') . '</p>';
      $output .= '<p>' . t('If you want to have extra field for each flagged item this is set under the corresponding <a href="@flag">flag</a>.', [
        '@flag' => Url::fromRoute('entity.flag.collection')
          ->toString(),
      ]) . '</p>';
      return $output;
    case 'entity.flag_list_item.collection':
      $output = '';
      $output .= '<h3>' . t('Flag List Item handling') . '</h3>';
      $output .= '<p>' . t('This page is <em>only</em> for fixing problems after importing flag list items from an earlier release of Drupal. It might be needed to delete some entries after an unsuccesful import. Please note that if some items needs to be deleted this indicates that something else has gone very wrong before the import of the old flag lists.') . '</p>';
      $output .= '<p>' . t('If you see only "Exist" in the "Entity exists?" column then everything is OK with your Flag lists.') . '</p>';
      return $output;
    default:
  }
}

/**
 * Implements hook_theme().
 */
function flag_lists_theme($existing, $type, $theme, $path) {
  $theme = [];

  // Used for viewing flagging collections.
  $theme['flagging_collection'] = [
    'render element' => 'elements',
    'file' => 'flagging_collection.page.inc',
    'template' => 'flagging_collection',
  ];
  $theme['flagging_collection_content_add_list'] = [
    'render element' => 'content',
    'variables' => [
      'content' => NULL,
    ],
    'file' => 'flagging_collection.page.inc',
  ];

  // Not used in a normal flag_list_item implementation.
  $theme['flag_lists'] = [
    'render element' => 'children',
  ];

  // Used when creating flag and flag links.
  // The difference between flag and flag lists is handled in the twig.
  $theme['flag'] = [
    'template' => 'flag_list_flag',
    'base hook' => 'flag',
  ];
  return $theme;
}

/**
 * Implements hook_theme_registry_alter().
 */
function flag_lists_theme_registry_alter(&$theme_registry) {

  // Prepare for the flagging collection as a variable.
  $theme_registry['flag']['variables']['flagging_collection'] = NULL;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function flag_lists_theme_suggestions_flagging_collection(array $variables) {

  // Prepare for different presentations of different flagging collections.
  $suggestions = [];
  $entity = $variables['elements']['#flagging_collection'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
  $suggestions[] = 'flagging_collection__' . $sanitized_view_mode;
  $suggestions[] = 'flagging_collection__' . $entity
    ->bundle();
  $suggestions[] = 'flagging_collection__' . $entity
    ->bundle() . '__' . $sanitized_view_mode;
  $suggestions[] = 'flagging_collection__' . $entity
    ->id();
  $suggestions[] = 'flagging_collection__' . $entity
    ->id() . '__' . $sanitized_view_mode;
  return $suggestions;
}

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 *
 * A try to implement separate theming for flagging collection flag links.
 */
function flag_lists_theme_suggestions_flag_alter(array &$suggestions, array $variables) {

  // A different template for flag origin from flag lists.
  $suggestions[] = 'flag__flag_lists';
}

/**
 * Implements hook_form_alter().
 */
function flag_lists_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $flagListsService = \Drupal::service('flaglists');

  // Change form id here.
  if (in_array($form_id, [
    'flag_add_form',
    'flag_edit_form',
  ])) {
    $form['fl_fieldset'] = [
      '#type' => 'details',
      '#open' => TRUE,
      '#title' => t('Flagging Collection Template'),
      '#description' => t('Flagging Collections are lists / collections of flags grouped together. By marking this flag as a <em>Flagging Collection Template</em> the flag will be made available as a template flag for the Flag lists module. The settings above will then affect how the <em>Flagging Collection link</em> will be presented on each entity. This is just like the normal flag functionality.'),
      '#tree' => FALSE,
      '#weight' => 60,
      '#prefix' => '<div id="link-type-settings-wrapper">',
      '#suffix' => '</div>',
    ];

    // Check if this flag already is a Flag list Template
    // i.e. has a FlagForList.
    $isFlagForList = FALSE;
    if (!empty($form['#flag']
      ->id())) {
      $flagListsService = \Drupal::service('flaglists');
      $flag_template = $flagListsService
        ->getFlagForListById($form['#flag']
        ->id());
      $isFlagForList = !empty($flag_template);
    }
    $form['fl_fieldset']['flag_lists_flag'] = [
      '#type' => 'checkbox',
      '#title' => t('Flagging Collection Template'),
      '#description' => t('Will this flag be used as a template flag for Flagging Collections?'),
      '#default_value' => $isFlagForList,
      '#disabled' => $isFlagForList,
      '#weight' => '0',
    ];
    $form['actions']['submit']['#submit'][] = 'flag_lists_save_submit';
  }
  elseif ($form_id == 'flag_add_page') {

    // Remove our own entities in order to avoid recursion.
    unset($form['flag_entity_type']['#options']['entity:flag_list_item']);
    unset($form['flag_entity_type']['#options']['entity:flagging_collection']);
  }
}

/**
 * Form submission handler for the 'save' action.
 *
 * @param array $form
 *   An associative array containing the structure of the form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 */
function flag_lists_save_submit(array &$form, FormStateInterface $form_state) {
  if ($form_state
    ->getValue('flag_lists_flag')) {
    $flagListsService = \Drupal::service('flaglists');
    if (empty($form['#flag']
      ->id())) {

      // This is a new Flag and Flag List Template.
      FlagTracker::save($form, $form_state);
    }
    elseif (!empty($flagTemplate = $flagListsService
      ->getFlagForListById($form['#flag']
      ->id()))) {

      // The Flag has already a Flag For List.
      FlagTracker::update($form, $form_state, $flagTemplate);
    }
    else {

      // Existing Flag without a Flag For List.
      FlagTracker::save($form, $form_state);
    }
  }
}

/**
 * Implements hook_data_type_info_alter().
 */
function flag_lists_flag_link_type_info_alter(&$variables) {
  if (isset($variables['route_name']) && strpos($variables['route_name'], 'admin') !== FALSE) {
  }
}

/**
 * Implements hook_flag_action_access().
 */
function flag_lists_flag_action_access($action, FlagInterface $flag, AccountInterface $account, EntityInterface $flaggable = NULL) {

  // If this is a flag list and we have flag list access,
  // also provide access to the flag.
  // Allow both users flag and the corresponding template.
  // Currently only the users flag lists are accepted.
  // This needs to corrected to allow also global lists.
  $flagListsService = Drupal::service('flaglists');
  $flagLists = $flagListsService
    ->getAllFlaggingCollections();
  foreach ($flagLists as $flagList) {
    if ($flag
      ->id() == $flagList
      ->getRelatedFlag()
      ->id()) {
      if ($flagList
        ->getBaseFlag()
        ->isGlobal()) {

        // The flag list is global.
        return AccessResult::allowedIfHasPermission($account, 'access global flag lists');
      }
      elseif ($flagList
        ->getOwnerId() == $account
        ->id()) {

        // The flag list is owned by current user.
        return AccessResult::allowedIfHasPermission($account, 'view own flag lists');
      }
      else {

        // The user is allowed to see all flag lists.
        return AccessResult::allowedIfHasPermission($account, 'view flag lists');
      }
    }
  }

  // Check for access for the used template as well.
  $flagTemplates = $flagListsService
    ->getAllFlagForList();
  foreach ($flagTemplates as $flagTemplate) {
    if ($flag
      ->id() == $flagTemplate
      ->id()) {

      // This is one of the template flags.
      // But is it global?
      $baseFlag = Drupal::service('flag')
        ->getFlagById($flagTemplate
        ->getBaseFlag());
      if ($baseFlag
        ->isGlobal()) {
        return AccessResult::allowedIfHasPermission($account, 'access global flag lists');
      }
      else {
        return AccessResult::allowedIfHasPermissions($account, [
          'administer flag lists',
          'view own flag lists',
          'view flag lists',
        ], 'OR');
      }
    }
  }
  return AccessResult::neutral();
}

/**
 * Implements hook_entity_type_alter().
 */
function flag_lists_entity_type_alter(array &$entity_types) {

  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['flag']
    ->setListBuilderClass('Drupal\\flag_lists\\FlagListsFlagListBuilder');
}

/**
 * Implements hook_entity_extra_field_info_alter().
 */
function flag_lists_entity_extra_field_info_alter(&$info) {
  $flagListsService = \Drupal::service('flaglists');
  $config = \Drupal::config('flag_lists.settings');
  if ($config
    ->get('hide_collections_in_displays')) {
    $flaggingCollections = $flagListsService
      ->getAllFlaggingCollections();
    foreach ($flaggingCollections as $collection) {
      if ($relatedFlag = $collection
        ->getRelatedFlag()) {
        $entityType = $relatedFlag
          ->getFlaggableEntityTypeId();
        $bundles = $relatedFlag
          ->getApplicableBundles();
        foreach ($bundles as $bundle) {
          unset($info[$entityType][$bundle]['display']['flag_' . $relatedFlag
            ->id()]);
        }
      }
    }
  }
  if ($config
    ->get('hide_templates_in_displays')) {
    $flagService = \Drupal::service('flag');
    $flagForLists = $flagListsService
      ->getAllFlagForList();
    foreach ($flagForLists as $template) {
      if ($baseFlag = $template
        ->getBaseFlag()) {
        if (!empty($flag = $flagService
          ->getFlagById($baseFlag))) {
          $entityType = $flag
            ->getFlaggableEntityTypeId();
          $bundles = $flag
            ->getApplicableBundles();
          foreach ($bundles as $bundle) {
            unset($info[$entityType][$bundle]['display']['flag_' . $flag
              ->id()]);
          }
        }
      }
    }
  }
}