Adiciona sub-módulo site_tools_group_helpers

Fornece um plugin EntityReferenceSelection que restringe campos de
referência a grupos aos grupos dos quais o usuário atual é membro.
Inclui troca automática para o widget options_select ao configurar o
handler, e remoção do #required em target_bundles para campos que
referenciam group, permitindo deixar o tipo de grupo em branco.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 08:08:42 -03:00
parent 75574b01f7
commit a6e6fd3125
4 changed files with 197 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
name: 'Site Tools — Group Helpers'
type: module
description: 'Utilitários reutilizáveis para integração com o módulo Group.'
core_version_requirement: ^10.3 || ^11
package: Custom
dependencies:
- site_tools:site_tools
- group:group

View File

@@ -0,0 +1,27 @@
<?php
/**
* @file
* Install hooks for site_tools_group_helpers.
*/
declare(strict_types=1);
/**
* Implements hook_install().
*
* Applies the options_select widget to any entity_reference field already
* configured to use the site_tools_group_helpers selection handler, for
* example after a config import followed by module installation.
*/
function site_tools_group_helpers_install(): void {
$field_configs = \Drupal::entityTypeManager()
->getStorage('field_config')
->loadByProperties(['field_type' => 'entity_reference']);
foreach ($field_configs as $field_config) {
if ($field_config->getSetting('handler') === 'site_tools_group_helpers') {
_site_tools_group_helpers_set_widget($field_config, 'options_select', []);
}
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* @file
* Module hooks for site_tools_group_helpers.
*/
declare(strict_types=1);
use Drupal\Core\Form\FormStateInterface;
use Drupal\field\FieldConfigInterface;
/**
* Implements hook_form_FORM_ID_alter() for field_config_edit_form.
*
* Removes the #required constraint from the target_bundles checkboxes when
* the field references the 'group' entity type, allowing the selection to be
* left empty (= any group type) regardless of which handler is active.
*/
function site_tools_group_helpers_form_field_config_edit_form_alter(array &$form, FormStateInterface $form_state): void {
$field = $form_state->getFormObject()->getEntity();
if ($field->getFieldStorageDefinition()->getSetting('target_type') !== 'group') {
return;
}
$target_bundles = &$form['settings']['handler']['handler_settings']['target_bundles'] ?? NULL;
if ($target_bundles !== NULL) {
$target_bundles['#required'] = FALSE;
}
}
/**
* Implements hook_field_config_update().
*
* When a field switches to the site_tools_group_helpers selection handler,
* automatically updates all its form displays to use the options_select widget.
* When it switches away, reverts to entity_reference_autocomplete.
*/
function site_tools_group_helpers_field_config_update(FieldConfigInterface $field_config): void {
$handler = $field_config->getSetting('handler');
$original_handler = $field_config->original?->getSetting('handler');
if ($handler === $original_handler) {
return;
}
if ($handler === 'site_tools_group_helpers') {
_site_tools_group_helpers_set_widget($field_config, 'options_select', []);
}
elseif ($original_handler === 'site_tools_group_helpers') {
_site_tools_group_helpers_set_widget($field_config, 'entity_reference_autocomplete', [
'match_operator' => 'CONTAINS',
'match_limit' => 10,
'size' => 60,
'placeholder' => '',
]);
}
}
/**
* Updates the widget type for a field across all its form displays.
*
* @param \Drupal\field\FieldConfigInterface $field_config
* The field config entity.
* @param string $widget_type
* The widget plugin ID to apply.
* @param array $settings
* The widget settings to apply.
*/
function _site_tools_group_helpers_set_widget(FieldConfigInterface $field_config, string $widget_type, array $settings): void {
$entity_type_id = $field_config->getTargetEntityTypeId();
$bundle = $field_config->getTargetBundle();
$field_name = $field_config->getName();
$form_displays = \Drupal::entityTypeManager()
->getStorage('entity_form_display')
->loadByProperties([
'targetEntityType' => $entity_type_id,
'bundle' => $bundle,
]);
foreach ($form_displays as $form_display) {
$component = $form_display->getComponent($field_name);
if ($component === NULL) {
continue;
}
$form_display->setComponent($field_name, [
'type' => $widget_type,
'weight' => $component['weight'],
'region' => $component['region'] ?? 'content',
'settings' => $settings,
'third_party_settings' => $component['third_party_settings'] ?? [],
]);
$form_display->save();
}
}

View File

@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace Drupal\site_tools_group_helpers\Plugin\EntityReferenceSelection;
use Drupal\Core\Entity\Attribute\EntityReferenceSelection;
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\group\Entity\GroupMembership;
/**
* Restricts group selection to groups where the current user is a member.
*
* Use this handler on any entity_reference field that targets the 'group'
* entity type when only the groups the current user belongs to should appear
* as options. Users with no memberships will see an empty list.
*/
#[EntityReferenceSelection(
id: 'site_tools_group_helpers',
label: new TranslatableMarkup('Member groups (current user)'),
entity_types: ['group'],
group: 'site_tools_group_helpers',
weight: 0,
)]
class MemberGroupSelection extends DefaultSelection {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
// Allow leaving group types empty (= any type), matching the behaviour
// of the default selection handler.
if (isset($form['target_bundles'])) {
$form['target_bundles']['#required'] = FALSE;
}
return $form;
}
/**
* {@inheritdoc}
*/
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
$query = parent::buildEntityQuery($match, $match_operator);
$memberships = GroupMembership::loadByUser($this->currentUser);
if (empty($memberships)) {
// User has no memberships — return an empty result set.
$query->condition('id', 0, '=');
return $query;
}
$gids = array_map(fn($m) => $m->getGroupId(), $memberships);
$query->condition('id', $gids, 'IN');
return $query;
}
}