contacts-8.x-1.x-dev/modules/group/src/Plugin/Block/ContactOrgRelationshipFormBlock.php
modules/group/src/Plugin/Block/ContactOrgRelationshipFormBlock.php
<?php
namespace Drupal\contacts_group\Plugin\Block;
use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityFormBuilderInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Form\FormBuilder;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\contacts\Dashboard;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\group\Plugin\Group\Relation\GroupRelationTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Provides an Organisation relationship form block.
*
* @Block(
* id = "contacts_org_relationship_form",
* deriver = "Drupal\contacts_group\Plugin\Derivative\GroupRelationTypeDeriver",
* category = @Translation("Dashboard Blocks"),
* context_definitions = {
* "user" = @ContextDefinition("entity:user",
* label = @Translation("User")
* ),
* },
* )
*/
class ContactOrgRelationshipFormBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* Provides constants.
*
* Constants to help the block determine which end of the relationship has
* been provided to the form.
*/
const PROVIDES_GROUP = 'group';
const PROVIDES_CONTENT = 'content';
private const PROVIDES_LEGACY = [
'member' => self::PROVIDES_CONTENT,
];
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity form builder.
*
* @var \Drupal\Core\Entity\EntityFormBuilderInterface
*/
protected $formBuilder;
/**
* The current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* The Contacts Dashboard helper.
*
* @var \Drupal\contacts\Dashboard
*/
protected $dashboard;
/**
* The group content enabler plugin manager.
*
* @var \Drupal\group\Plugin\Group\Relation\GroupRelationTypeManagerInterface
*/
protected $groupRelationTypeManager;
/**
* Constructs a new ContactOrgRelationshipFormBlock object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param string $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityFormBuilderInterface $form_builder
* The entity form builder.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\contacts\Dashboard $dashboard
* The contacts dashboard helper.
* @param \Drupal\group\Plugin\Group\Relation\GroupRelationTypeManagerInterface $group_relation_type_manager
* The group relation type manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFormBuilderInterface $form_builder, RequestStack $request_stack, Dashboard $dashboard, GroupRelationTypeManagerInterface $group_relation_type_manager) {
// For blocks saved prior to move to multiple enablers, copy member_roles
// over to content_roles and trigger a deprecation.
if (!empty($configuration['member_roles'])) {
@trigger_error("Configuration 'member_roles' is deprecated in contacts:8.x-1.0 and is removed from contacts:2.0.0. Use 'content_roles' instead.", \E_USER_DEPRECATED);
$configuration['content_roles'] = $configuration['member_roles'];
unset($configuration['member_roles']);
}
// That change also switched from 'member' to 'content', so trigger a
// deprecation and fix tweak the configuration.
if (isset(self::PROVIDES_LEGACY[$configuration['provides']])) {
$old_value = $configuration['provides'];
$configuration['provides'] = self::PROVIDES_LEGACY[$configuration['provides']];
@trigger_error("Configuration '{$old_value}' is deprecated in contacts:8.x-1.0 and is removed from contacts:2.0.0. Use '{$configuration['provides']}' instead.", \E_USER_DEPRECATED);
}
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->formBuilder = $form_builder;
$this->request = $request_stack->getCurrentRequest();
$this->dashboard = $dashboard;
$this->groupRelationTypeManager = $group_relation_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('entity.form_builder'),
$container->get('request_stack'),
$container->get('contacts.dashboard'),
$container->get('group_relation_type.manager')
);
}
/**
* Get the id of the group relation type.
*
* @return string
* The plugin id of the group relation type.
*/
protected function getGroupRelationType() {
return $this->getPluginDefinition()['group_relation_type'];
}
/**
* Get the query key.
*
* This is down to allow multiple block on the same page with different
* enablers.
*
* @return string
* The query key to distinguish this block.
*/
protected function getQueryKey() {
return $this->configuration['query_key'];
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration(): array {
return [
'query_key' => $this->getPluginDefinition()['group_relation_type'] . '--org',
'provides' => static::PROVIDES_CONTENT,
'content_roles' => [],
'organisation_roles' => [],
'show_add' => TRUE,
'add_title' => NULL,
] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
protected function blockAccess(AccountInterface $account) {
/** @var \Drupal\user\UserInterface $user */
$user = $this->getContextValue('user');
if ($this->configuration['provides'] != static::PROVIDES_GROUP || $user->hasRole('crm_org')) {
return AccessResult::allowed();
}
else {
return AccessResult::forbidden();
}
}
/**
* {@inheritdoc}
*/
public function label() {
$relationship = $this->getGroupRelationship();
if (!$relationship) {
// If a label is set, we may as well use it.
return ($this->configuration['label']) ?? '';
}
switch ($this->configuration['provides']) {
case static::PROVIDES_CONTENT:
$entity = $relationship->getGroup();
break;
case static::PROVIDES_GROUP:
$entity = $relationship->getEntity();
break;
}
return $entity ? $entity->label() : $this->t('Add relationship');
}
/**
* Get the URL for the block.
*
* @return \Drupal\Core\Url
* The URL.
*/
protected function getUrl() {
// If this is the dashboard, get the full page URL.
if ($this->dashboard->isDashboard()) {
return $this->dashboard->getFullUrl();
}
// Otherwise use the current URL.
return Url::fromRoute('<current>', [
'user' => $this->getContextValue('user')->id(),
]);
}
/**
* {@inheritdoc}
*/
public function build() {
// If we have a param, show the form.
if ($relationship = $this->getGroupRelationship()) {
return $this->buildForm($relationship);
}
// Otherwise show the add link.
$build = [];
$url = $this->getUrl();
$query = $url->getOption('query');
$query[$this->getQueryKey()] = 'add';
$url->setOption('query', $query);
if ($this->configuration['show_add']) {
$build['add'] = [
'#type' => 'link',
'#title' => $this->t('Add @relation_type relationship', [
'@relation_type' => $this->getGroupRelationType(),
]),
'#url' => $url,
'#attributes' => [
'class' => ['button'],
],
];
if ($this->configuration['provides'] == static::PROVIDES_GROUP) {
if ($content_roles = $this->configuration['content_roles']) {
$filter_indiv = in_array('crm_indiv', $content_roles);
$filter_orgs = in_array('crm_org', $content_roles);
if ($filter_indiv && !$filter_orgs) {
$build['add']['#title'] = $this->t('Add member');
}
elseif ($filter_orgs && !$filter_indiv) {
$build['add']['#title'] = $this->t('Add member organisation');
}
}
}
else {
$build['add']['#title'] = $this->t('Add organisation');
}
if ($this->configuration['add_title']) {
$build['add']['#title'] = $this->configuration['add_title'];
}
}
return $build;
}
/**
* Create a new group for the user context.
*
* @return \Drupal\group\Entity\GroupRelationshipInterface|false
* The group relationship entity or FALSE if there isn't one
* or we were unable to load it.
*
* @throws \Drupal\Component\Plugin\Exception\ContextException
* Thrown if a the relationship isn't valid for the user context.
*/
protected function getGroupRelationship() {
$relationship = $this->request->query->get($this->getQueryKey());
if (!$relationship) {
return FALSE;
}
elseif ($relationship == 'add') {
/** @var \Drupal\group\Entity\GroupType $group_type */
$group_type = $this->entityTypeManager
->getStorage('group_type')
->load('contacts_org');
$plugin = $group_type->getPlugin($this->getGroupRelationType());
$values = [
'type' => $group_type->id() . '-' . $plugin->getRelationTypeId(),
];
$user = $this->getContextValue('user');
if ($this->configuration['provides'] == static::PROVIDES_CONTENT) {
$values['entity_id'] = $user;
}
else {
$values['gid'] = $user->group;
}
return $this->entityTypeManager
->getStorage(_contacts_group_get_group_relationship_entity_type_id())
->create($values);
}
else {
/** @var \Drupal\group\Entity\GroupRelationshipInterface $group_relationship */
$group_relationship = $this->entityTypeManager
->getStorage(_contacts_group_get_group_relationship_entity_type_id())
->load($relationship);
if (!$group_relationship) {
$this->messenger()->addMessage($this->t('Unable to find the relationship to edit.'), 'error');
return FALSE;
}
if ($group_relationship->bundle() !== 'contacts_org-' . $this->getGroupRelationType()) {
$this->messenger()->addError($this->t('Invalid relationship type.'));
return FALSE;
}
$expected_id = $this->configuration['provides'] == static::PROVIDES_CONTENT ?
$group_relationship->getEntity()->id() :
$group_relationship->getGroup()->contacts_org->target_id;
if ($this->getContextValue('user')->id() != $expected_id) {
throw new ContextException('Invalid context for relationship.');
}
return $group_relationship;
}
}
/**
* Build the membership form.
*
* @param \Drupal\group\Entity\GroupRelationshipInterface $group_relationship
* The group relationship entity to edit or a new one for creation.
*
* @return array
* The form render array.
*/
protected function buildForm(GroupRelationshipInterface $group_relationship) {
// Manually build our action and redirect.
$query = $this->request->query->all();
// @see \Drupal\Core\Form\FormBuilder::buildFormAction.
unset($query[FormBuilder::AJAX_FORM_REQUEST], $query[MainContentViewSubscriber::WRAPPER_FORMAT]);
// Build our URLs.
unset($query[$this->getQueryKey()]);
$redirect = $this->getUrl()
->setOption('query', $query);
// Get the form render array with the right redirect and action.
$form = $this->formBuilder->getForm($group_relationship, 'contacts-org', [
'redirect' => $redirect,
'content_roles' => $this->configuration['content_roles'],
'organisation_roles' => $this->configuration['organisation_roles'],
]);
// Add a cancel to take us back to the page.
$form['actions']['cancel'] = [
'#type' => 'link',
'#title' => $this->t('Cancel'),
'#attributes' => ['class' => ['button']],
'#url' => $redirect,
'#weight' => 99,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm(
$form,
$form_state
);
$form['provides'] = [
'#type' => 'select',
'#title' => $this->t('Provided End'),
'#description' => $this->t('Which end of the relationship is provided; the group or the member?'),
'#options' => [
static::PROVIDES_GROUP => $this->t('Group'),
static::PROVIDES_CONTENT => $this->t('Member'),
],
'#default_value' => $this->configuration['provides'],
];
$form['add_title'] = [
'#type' => 'textfield',
'#title' => $this->t('Add Link Text'),
'#description' => $this->t('What should the add link say?'),
'#default_value' => $this->configuration['add_title'],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
parent::submitConfigurationForm(
$form,
$form_state
);
$this->configuration['provides'] = $form_state->getValue('provides');
$this->configuration['add_title'] = $form_state->getValue('add_title');
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() {
/** @var \Drupal\group\Plugin\Group\Relation\GroupRelationTypeInterface $relation_type */
$relation_type = $this->groupRelationTypeManager->createInstance($this->getGroupRelationType(), [
'group_type_id' => 'contacts_org',
]);
if ($relation_type instanceof DependentPluginInterface) {
return $relation_type->calculateDependencies();
}
else {
return [
'module' => [$relation_type->getProvider()],
];
}
}
}
