View source
<?php
namespace Drupal\flag\Plugin\Flag;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\flag\FlagType\FlagTypeBase;
use Drupal\flag\FlagInterface;
use Drupal\user\EntityOwnerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class EntityFlagType extends FlagTypeBase {
use StringTranslationTrait;
protected $entityTypeManager;
protected $entityType = '';
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);
}
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'));
}
public function defaultConfiguration() {
$options = parent::defaultConfiguration();
$options += [
'show_in_links' => [],
'show_as_field' => TRUE,
'show_on_form' => FALSE,
'show_contextual_link' => FALSE,
'extra_permissions' => [],
];
return $options;
}
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(),
];
$form['display']['show_on_form'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Display checkbox on entity edit form'),
'#default_value' => $this
->showOnForm(),
'#weight' => 5,
];
$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,
];
$options = [];
$defaults = [];
$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;
}
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');
}
public function showInLinks($name) {
if (!empty($this->configuration['show_in_links'][$name])) {
return TRUE;
}
return FALSE;
}
public function showAsField() {
return $this->configuration['show_as_field'];
}
public function showOnForm() {
return $this->configuration['show_on_form'];
}
public function isAddEditForm($operation) {
return in_array($operation, [
'default',
'edit',
]);
}
public function showContextualLink() {
return $this->configuration['show_contextual_link'];
}
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;
}
public function actionPermissions(FlagInterface $flag) {
$permissions = parent::actionPermissions($flag);
if ($this
->hasExtraPermission('owner')) {
$permissions += $this
->getExtraPermissionsOwner($flag);
}
return $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;
}
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')) {
$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);
$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;
}
protected function isFlaggableOwnable() {
$entity_type_id = $this->entityType;
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
if ($entity_type
->entityClassImplements(EntityOwnerInterface::class)) {
return TRUE;
}
return FALSE;
}
}