You are here

class EntityFlagType in Flag 8.4

Provides a flag type for all entity types.

Base entity flag handler.

Plugin annotation


@FlagType(
  id = "entity",
  title = @Translation("Flag Type Entity"),
  deriver = "Drupal\flag\Plugin\Derivative\EntityFlagTypeDeriver"
)

Hierarchy

Expanded class hierarchy of EntityFlagType

3 files declare their use of EntityFlagType
AccessDenied.php in tests/modules/flag_test_plugins/src/Plugin/Flag/AccessDenied.php
AccessGranted.php in tests/modules/flag_test_plugins/src/Plugin/Flag/AccessGranted.php
flag.module in ./flag.module
The Flag module.

File

src/Plugin/Flag/EntityFlagType.php, line 29

Namespace

Drupal\flag\Plugin\Flag
View source
class EntityFlagType extends FlagTypeBase {
  use StringTranslationTrait;

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

  /**
   * The entity type defined in plugin definition.
   *
   * @var string
   */
  protected $entityType = '';

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, TranslationInterface $string_translation) {
    $this->entityType = $plugin_definition['entity_type'];
    $this->entityTypeManager = $entity_type_manager;
    parent::__construct($configuration, $plugin_id, $plugin_definition, $module_handler, $string_translation);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('module_handler'), $container
      ->get('entity_type.manager'), $container
      ->get('string_translation'));
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    $options = parent::defaultConfiguration();
    $options += [
      // Output the flag in the entity links.
      // This is empty for now and will get overridden for different
      // entities.
      // @see hook_entity_view().
      'show_in_links' => [],
      // Output the flag as individual fields.
      'show_as_field' => TRUE,
      // Add a checkbox for the flag in the entity form.
      // @see hook_field_attach_form().
      'show_on_form' => FALSE,
      'show_contextual_link' => FALSE,
      // Additional permissions to expose.
      'extra_permissions' => [],
    ];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form['display']['show_as_field'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Display link as field'),
      '#description' => $this
        ->t('Show the flag link as a field, which can be ordered among other entity elements in the "Manage display" settings for the entity type.'),
      '#default_value' => $this
        ->showAsField(),
    ];

    /*
    if (empty($entity_info['fieldable'])) {
      $form['display']['show_as_field']['#disabled'] = TRUE;
      $form['display']['show_as_field']['#description'] = $this->t("This entity type is not fieldable.");
    }
    */
    $form['display']['show_on_form'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Display checkbox on entity edit form'),
      '#default_value' => $this
        ->showOnForm(),
      '#weight' => 5,
    ];

    // We use FieldAPI to put the flag checkbox on the entity form, so therefore
    // require the entity to be fielable. Since this is a potential DX
    // headscratcher for a developer wondering where this option has gone,
    // we disable it and explain why.

    /*
    if (empty($entity_info['fieldable'])) {
      $form['display']['show_on_form']['#disabled'] = TRUE;
      $form['display']['show_on_form']['#description'] = $this->t('This is only possible on entities which are fieldable.');
    }
    */
    $form['display']['show_contextual_link'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Display in contextual links'),
      '#default_value' => $this
        ->showContextualLink(),
      '#description' => $this
        ->t("Note that not all entity types support contextual links.\n        <br/>\n        <strong>Warning: </strong>Due to how contextual links are cached on frontend\n        we have to set max-age as 0 for entity cache if\n        user has access to contextual links and to this flag. This means that\n        those users will get no cache hits for render elements rendering flaggable\n        entities with contextual links."),
      '#access' => $this->moduleHandler
        ->moduleExists('contextual'),
      '#weight' => 10,
    ];

    // Add checkboxes to show flag link on each entity view mode.
    $options = [];
    $defaults = [];

    /* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_service */
    $entity_display_service = \Drupal::service('entity_display.repository');
    $view_modes = $entity_display_service
      ->getViewModes($this->entityType);
    foreach ($view_modes as $name => $view_mode) {
      $options[$name] = $this
        ->t('Display on @name view mode', [
        '@name' => $view_mode['label'],
      ]);
      if ($this
        ->showInLinks($name)) {
        $defaults[$name] = $name;
      }
    }
    $form['display']['show_in_links'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('Display in entity links'),
      '#description' => $this
        ->t('Show the flag link with the other links on the entity.'),
      '#options' => $options,
      '#default_value' => $defaults,
      '#weight' => 15,
    ];
    $form['access']['extra_permissions'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('Expose additional permissions'),
      '#options' => $this
        ->getExtraPermissionsOptions(),
      '#default_value' => $this->configuration['extra_permissions'],
      '#description' => $this
        ->t("Provides permissions with finer levels of access for this flag."),
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    parent::submitConfigurationForm($form, $form_state);
    $this->configuration['show_in_links'] = array_filter($form_state
      ->getValue('show_in_links'));
    $this->configuration['show_as_field'] = $form_state
      ->getValue('show_as_field');
    $this->configuration['show_on_form'] = $form_state
      ->getValue('show_on_form');
    $this->configuration['show_contextual_link'] = $form_state
      ->getValue('show_contextual_link');
    $this->configuration['extra_permissions'] = $form_state
      ->getValue('extra_permissions');
  }

  /**
   * Return the show in links setting given a view mode.
   *
   * @param string $name
   *   The name of the view mode.
   *
   * @return bool
   *   TRUE if the flag should appear in the entity links for the view mode.
   */
  public function showInLinks($name) {
    if (!empty($this->configuration['show_in_links'][$name])) {
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Returns the show as field setting.
   *
   * @return bool
   *   TRUE if the flag should appear as a psudofield, FALSE otherwise.
   */
  public function showAsField() {
    return $this->configuration['show_as_field'];
  }

  /**
   * Returns the show on form setting.
   *
   * @return bool
   *   TRUE if the flag should appear on the entity form, FALSE otherwise.
   */
  public function showOnForm() {
    return $this->configuration['show_on_form'];
  }

  /**
   * Determines if the given form operation is add or edit.
   *
   * @param string $operation
   *   The form operation.
   *
   * @return bool
   *   Returns TRUE if the operation is an add edit operation.
   */
  public function isAddEditForm($operation) {
    return in_array($operation, [
      'default',
      'edit',
    ]);
  }

  /**
   * Returns the show on contextual link setting.
   *
   * @return bool
   *   TRUE if the flag should appear in contextual links, FALSE otherwise.
   */
  public function showContextualLink() {
    return $this->configuration['show_contextual_link'];
  }

  /**
   * {@inheritdoc}
   */
  protected function getExtraPermissionsOptions() {
    $options = parent::getExtraPermissionsOptions();
    if ($this
      ->isFlaggableOwnable()) {
      $options['owner'] = $this
        ->t("Permissions based on ownership of the flaggable item. For example, only allow users to flag items they own.");
    }
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function actionPermissions(FlagInterface $flag) {
    $permissions = parent::actionPermissions($flag);

    // Define additional permissions.
    if ($this
      ->hasExtraPermission('owner')) {
      $permissions += $this
        ->getExtraPermissionsOwner($flag);
    }
    return $permissions;
  }

  /**
   * Defines permissions for the 'owner' set of additional action permissions.
   *
   * @param \Drupal\flag\FlagInterface $flag
   *   The flag object.
   *
   * @return array
   *   An array of permissions.
   */
  protected function getExtraPermissionsOwner(FlagInterface $flag) {
    $permissions['flag ' . $flag
      ->id() . ' own items'] = [
      'title' => $this
        ->t('Flag %flag_title own items', [
        '%flag_title' => $flag
          ->label(),
      ]),
    ];
    $permissions['unflag ' . $flag
      ->id() . ' own items'] = [
      'title' => $this
        ->t('Unflag %flag_title own items', [
        '%flag_title' => $flag
          ->label(),
      ]),
    ];
    $permissions['flag ' . $flag
      ->id() . ' other items'] = [
      'title' => $this
        ->t("Flag %flag_title others' items", [
        '%flag_title' => $flag
          ->label(),
      ]),
    ];
    $permissions['unflag ' . $flag
      ->id() . ' other items'] = [
      'title' => $this
        ->t("Unflag %flag_title others' items", [
        '%flag_title' => $flag
          ->label(),
      ]),
    ];
    return $permissions;
  }

  /**
   * {@inheritdoc}
   */
  public function actionAccess($action, FlagInterface $flag, AccountInterface $account, EntityInterface $flaggable = NULL) {
    $access = parent::actionAccess($action, $flag, $account, $flaggable);
    if ($flaggable instanceof EntityOwnerInterface && $this
      ->hasExtraPermission('owner')) {

      // Own items.
      $permission = $action . ' ' . $flag
        ->id() . ' own items';
      $own_permission_access = AccessResult::allowedIfHasPermission($account, $permission)
        ->addCacheContexts([
        'user',
      ]);
      $account_match_access = AccessResult::allowedIf($account
        ->id() == $flaggable
        ->getOwnerId());
      $own_access = $own_permission_access
        ->andIf($account_match_access);
      $access = $access
        ->orIf($own_access);

      // Others' items.
      $permission = $action . ' ' . $flag
        ->id() . ' other items';
      $others_permission_access = AccessResult::allowedIfHasPermission($account, $permission)
        ->addCacheContexts([
        'user',
      ]);
      $account_mismatch_access = AccessResult::allowedIf($account
        ->id() != $flaggable
        ->getOwnerId());
      $others_access = $others_permission_access
        ->andIf($account_mismatch_access);
      $access = $access
        ->orIf($others_access);
    }
    return $access;
  }

  /**
   * Determines if the flaggable associated with the flag supports ownership.
   *
   * @return boolean
   *   TRUE if the flaggable supports ownership.
   */
  protected function isFlaggableOwnable() {
    $entity_type_id = $this->entityType;

    // Get the entity type from the entity type manager.
    $entity_type = $this->entityTypeManager
      ->getDefinition($entity_type_id);

    // Only if the flaggable entities can be owned.
    if ($entity_type
      ->entityClassImplements(EntityOwnerInterface::class)) {
      return TRUE;
    }
    return FALSE;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityFlagType::$entityType protected property The entity type defined in plugin definition.
EntityFlagType::$entityTypeManager protected property The entity type manager.
EntityFlagType::actionAccess public function Checks whether a user has permission to flag/unflag or not. Overrides FlagTypeBase::actionAccess 3
EntityFlagType::actionPermissions public function Returns the permissions available to this flag type. Overrides FlagTypeBase::actionPermissions 1
EntityFlagType::buildConfigurationForm public function Provides a form for this action link plugin settings. Overrides FlagTypeBase::buildConfigurationForm 1
EntityFlagType::create public static function Creates an instance of the plugin. Overrides FlagTypeBase::create
EntityFlagType::defaultConfiguration public function Gets default configuration for this plugin. Overrides FlagTypeBase::defaultConfiguration 1
EntityFlagType::getExtraPermissionsOptions protected function Defines options for extra permissions. Overrides FlagTypeBase::getExtraPermissionsOptions 2
EntityFlagType::getExtraPermissionsOwner protected function Defines permissions for the 'owner' set of additional action permissions. 1
EntityFlagType::isAddEditForm public function Determines if the given form operation is add or edit. 1
EntityFlagType::isFlaggableOwnable protected function Determines if the flaggable associated with the flag supports ownership. 1
EntityFlagType::showAsField public function Returns the show as field setting.
EntityFlagType::showContextualLink public function Returns the show on contextual link setting.
EntityFlagType::showInLinks public function Return the show in links setting given a view mode.
EntityFlagType::showOnForm public function Returns the show on form setting.
EntityFlagType::submitConfigurationForm public function Handles the form submit for this action link plugin. Overrides FlagTypeBase::submitConfigurationForm 1
EntityFlagType::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides FlagTypeBase::__construct
FlagTypeBase::$moduleHandler protected property The module handler.
FlagTypeBase::calculateDependencies public function
FlagTypeBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
FlagTypeBase::hasExtraPermission protected function Determines whether the flag is set to have the extra permissions set.
FlagTypeBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
FlagTypeBase::validateConfigurationForm public function Handles the validation for the action link plugin settings form. Overrides PluginFormInterface::validateConfigurationForm
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.