mirror of
https://gitlab.unicamp.br/infimecc_drupal11_modules/site_users.git
synced 2026-03-08 01:17:41 -03:00
Implementa hook_site_tools_share_links() para fornecer os links do campo field_user_social_links ao ShareLinksBlock quando em página de perfil de usuário. Adiciona site_tools como dependência do módulo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
409 lines
13 KiB
Plaintext
409 lines
13 KiB
Plaintext
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Módulo Site Users - customizações de usuários do site.
|
|
*/
|
|
|
|
use Drupal\Core\Access\AccessResult;
|
|
use Drupal\Core\Entity\EntityInterface;
|
|
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
|
use Drupal\Core\Field\FieldDefinitionInterface;
|
|
use Drupal\Core\Field\FieldItemListInterface;
|
|
use Drupal\Core\Form\FormStateInterface;
|
|
use Drupal\Core\Session\AccountInterface;
|
|
use Drupal\Core\Url;
|
|
use Drupal\field\FieldConfigInterface;
|
|
use Drupal\media\MediaInterface;
|
|
use Drupal\site_users\Plugin\Field\FieldType\SocialLinkItem;
|
|
use Drupal\user\UserInterface;
|
|
|
|
/**
|
|
* Implements hook_theme().
|
|
*/
|
|
function site_users_theme($existing, $type, $theme, $path) {
|
|
return [
|
|
'user__full' => [
|
|
'template' => 'user--full',
|
|
'base hook' => 'user',
|
|
],
|
|
'site_users_info_block' => [
|
|
'template' => 'site-user-info-block',
|
|
'variables' => [
|
|
'user_info' => [],
|
|
'user' => NULL,
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Implements hook_theme_suggestions_HOOK_alter() for user templates.
|
|
*/
|
|
function site_users_theme_suggestions_user_alter(array &$suggestions, array $variables) {
|
|
$view_mode = $variables['elements']['#view_mode'] ?? 'default';
|
|
$suggestions[] = 'user__' . $view_mode;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_entity_field_access().
|
|
*/
|
|
function site_users_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) {
|
|
// Apenas para entidade user.
|
|
if ($field_definition->getTargetEntityTypeId() !== 'user') {
|
|
return AccessResult::neutral();
|
|
}
|
|
|
|
// Apenas campos configuráveis (não campos base como name, mail, status).
|
|
if (!($field_definition instanceof FieldConfigInterface)) {
|
|
return AccessResult::neutral();
|
|
}
|
|
|
|
$field_name = $field_definition->getName();
|
|
|
|
// Campos de referência a mídia usam lógica de fotos.
|
|
if ($field_definition->getType() === 'entity_reference'
|
|
&& $field_definition->getSetting('target_type') === 'media') {
|
|
return site_users_check_photo_field_access($operation, $account, $items, $field_name);
|
|
}
|
|
|
|
return site_users_check_profile_field_access($operation, $account, $items, $field_name);
|
|
}
|
|
|
|
/**
|
|
* Verifica acesso aos campos de perfil.
|
|
*/
|
|
function site_users_check_profile_field_access($operation, AccountInterface $account, ?FieldItemListInterface $items = NULL, string $field_name = '') {
|
|
// Administradores têm acesso total.
|
|
if ($account->hasPermission('administer site_users settings')) {
|
|
return AccessResult::allowed()->cachePerPermissions();
|
|
}
|
|
|
|
// Determinar se é o próprio usuário.
|
|
$is_own = FALSE;
|
|
if ($items) {
|
|
$entity = $items->getEntity();
|
|
$is_own = ($entity->id() == $account->id());
|
|
}
|
|
|
|
if ($operation === 'view') {
|
|
if ($account->hasPermission('view any user profile fields')) {
|
|
return AccessResult::allowed()->cachePerPermissions();
|
|
}
|
|
// Sem entidade disponível, defer.
|
|
if (!$items) {
|
|
return AccessResult::neutral();
|
|
}
|
|
if ($is_own && $account->hasPermission('view own user profile fields')) {
|
|
return AccessResult::allowed()->cachePerPermissions()->cachePerUser();
|
|
}
|
|
if (!$is_own) {
|
|
return AccessResult::forbidden()->cachePerPermissions()->cachePerUser();
|
|
}
|
|
return AccessResult::neutral()->cachePerUser();
|
|
}
|
|
|
|
if ($operation === 'edit') {
|
|
if ($account->hasPermission('edit any user profile fields')) {
|
|
return AccessResult::allowed()->cachePerPermissions();
|
|
}
|
|
// Sem entidade disponível, defer.
|
|
if (!$items) {
|
|
return AccessResult::neutral();
|
|
}
|
|
if ($is_own) {
|
|
// Campo habilitado na config?
|
|
$config = \Drupal::config('site_users.settings');
|
|
$field_enabled = $config->get('user_editable_fields.' . $field_name) ?? TRUE;
|
|
if ($field_enabled) {
|
|
return AccessResult::allowed()->cachePerPermissions()->cachePerUser()->addCacheTags(['config:site_users.settings']);
|
|
}
|
|
return AccessResult::forbidden()->cachePerPermissions()->cachePerUser()->addCacheTags(['config:site_users.settings']);
|
|
}
|
|
return AccessResult::forbidden()->cachePerPermissions()->cachePerUser();
|
|
}
|
|
|
|
return AccessResult::neutral();
|
|
}
|
|
|
|
/**
|
|
* Verifica acesso ao campo de fotos.
|
|
*/
|
|
function site_users_check_photo_field_access($operation, AccountInterface $account, ?FieldItemListInterface $items = NULL, string $field_name = '') {
|
|
// Administradores têm acesso total.
|
|
if ($account->hasPermission('administer site_users settings')) {
|
|
return AccessResult::allowed()->cachePerPermissions();
|
|
}
|
|
|
|
// Determinar se é o próprio usuário.
|
|
$is_own = FALSE;
|
|
if ($items) {
|
|
$entity = $items->getEntity();
|
|
$is_own = ($entity->id() == $account->id());
|
|
}
|
|
|
|
if ($operation === 'view') {
|
|
if ($account->hasPermission('view any user profile fields')) {
|
|
return AccessResult::allowed()->cachePerPermissions();
|
|
}
|
|
if (!$items) {
|
|
return AccessResult::neutral();
|
|
}
|
|
if ($is_own && $account->hasPermission('view own user profile fields')) {
|
|
return AccessResult::allowed()->cachePerPermissions()->cachePerUser();
|
|
}
|
|
if (!$is_own) {
|
|
return AccessResult::forbidden()->cachePerPermissions()->cachePerUser();
|
|
}
|
|
return AccessResult::neutral()->cachePerUser();
|
|
}
|
|
|
|
if ($operation === 'edit') {
|
|
if ($account->hasPermission('manage user photos')) {
|
|
return AccessResult::allowed()->cachePerPermissions();
|
|
}
|
|
if (!$items) {
|
|
return AccessResult::neutral();
|
|
}
|
|
if ($is_own) {
|
|
$config = \Drupal::config('site_users.settings');
|
|
$field_enabled = $config->get('user_editable_fields.' . $field_name) ?? TRUE;
|
|
if ($field_enabled) {
|
|
return AccessResult::allowed()->cachePerPermissions()->cachePerUser()->addCacheTags(['config:site_users.settings']);
|
|
}
|
|
return AccessResult::forbidden()->cachePerPermissions()->cachePerUser()->addCacheTags(['config:site_users.settings']);
|
|
}
|
|
return AccessResult::forbidden()->cachePerPermissions()->cachePerUser();
|
|
}
|
|
|
|
return AccessResult::neutral();
|
|
}
|
|
|
|
/**
|
|
* Implements hook_form_FORM_ID_alter() for user_form.
|
|
*/
|
|
function site_users_form_user_form_alter(&$form, FormStateInterface $form_state, $form_id) {
|
|
if (isset($form['field_user_photos'])) {
|
|
$form['#validate'][] = 'site_users_validate_photos_count';
|
|
_site_users_add_default_photo_selector($form, $form_state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_form_FORM_ID_alter() for user_register_form.
|
|
*/
|
|
function site_users_form_user_register_form_alter(&$form, FormStateInterface $form_state, $form_id) {
|
|
if (isset($form['field_user_photos'])) {
|
|
$form['#validate'][] = 'site_users_validate_photos_count';
|
|
_site_users_add_default_photo_selector($form, $form_state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona o seletor de foto padrão ao formulário.
|
|
*/
|
|
function _site_users_add_default_photo_selector(&$form, FormStateInterface $form_state) {
|
|
/** @var \Drupal\user\UserInterface $user */
|
|
$user = $form_state->getFormObject()->getEntity();
|
|
|
|
// Obter fotos atuais do usuário.
|
|
$photos = [];
|
|
if ($user->hasField('field_user_photos') && !$user->get('field_user_photos')->isEmpty()) {
|
|
foreach ($user->get('field_user_photos')->referencedEntities() as $media) {
|
|
if ($media instanceof MediaInterface) {
|
|
$photos[$media->id()] = $media->label();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Obter foto padrão atual.
|
|
$default_photo_id = NULL;
|
|
if ($user->hasField('field_user_default_photo') && !$user->get('field_user_default_photo')->isEmpty()) {
|
|
$default_photo_id = $user->get('field_user_default_photo')->target_id;
|
|
}
|
|
|
|
// Adicionar seletor de foto padrão após o campo de fotos.
|
|
$form['default_photo_selector'] = [
|
|
'#type' => 'container',
|
|
'#weight' => $form['field_user_photos']['#weight'] + 0.5 ?? 15,
|
|
'#states' => [
|
|
'visible' => [
|
|
':input[name="field_user_photos[selection]"]' => ['filled' => TRUE],
|
|
],
|
|
],
|
|
];
|
|
|
|
if (!empty($photos)) {
|
|
$form['default_photo_selector']['field_user_default_photo_select'] = [
|
|
'#type' => 'radios',
|
|
'#title' => t('Default photo'),
|
|
'#description' => t('Select the main profile photo.'),
|
|
'#options' => $photos,
|
|
'#default_value' => $default_photo_id,
|
|
];
|
|
}
|
|
else {
|
|
$form['default_photo_selector']['field_user_default_photo_select'] = [
|
|
'#type' => 'item',
|
|
'#title' => t('Default photo'),
|
|
'#markup' => t('Add photos to select one as default.'),
|
|
];
|
|
}
|
|
|
|
// Adicionar submit handler para salvar a foto padrão.
|
|
$form['actions']['submit']['#submit'][] = '_site_users_save_default_photo';
|
|
}
|
|
|
|
/**
|
|
* Submit handler para salvar a foto padrão selecionada.
|
|
*/
|
|
function _site_users_save_default_photo(&$form, FormStateInterface $form_state) {
|
|
$selected_photo = $form_state->getValue('field_user_default_photo_select');
|
|
|
|
/** @var \Drupal\user\UserInterface $user */
|
|
$user = $form_state->getFormObject()->getEntity();
|
|
|
|
if ($user->hasField('field_user_default_photo')) {
|
|
$user->set('field_user_default_photo', $selected_photo);
|
|
$user->save();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validação customizada para quantidade máxima de fotos.
|
|
*/
|
|
function site_users_validate_photos_count(&$form, FormStateInterface $form_state) {
|
|
$photos = $form_state->getValue('field_user_photos');
|
|
|
|
if (empty($photos)) {
|
|
return;
|
|
}
|
|
|
|
// Contar fotos selecionadas (ignorar valores vazios).
|
|
$count = 0;
|
|
foreach ($photos as $delta => $photo) {
|
|
if (is_numeric($delta) && !empty($photo['target_id'])) {
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
// Obter limite configurado.
|
|
$config = \Drupal::config('site_users.settings');
|
|
$max_count = $config->get('photos.max_count') ?? 5;
|
|
|
|
if ($count > $max_count) {
|
|
$form_state->setErrorByName('field_user_photos', t('You can add a maximum of @max photos. Currently @count photos are selected.', [
|
|
'@max' => $max_count,
|
|
'@count' => $count,
|
|
]));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_ENTITY_TYPE_presave() for user entities.
|
|
*/
|
|
function site_users_user_presave(UserInterface $user) {
|
|
// Garantir consistência da foto padrão.
|
|
if (!$user->hasField('field_user_photos') || !$user->hasField('field_user_default_photo')) {
|
|
return;
|
|
}
|
|
|
|
// Obter IDs das fotos atuais.
|
|
$photo_ids = [];
|
|
foreach ($user->get('field_user_photos')->getValue() as $item) {
|
|
if (!empty($item['target_id'])) {
|
|
$photo_ids[] = $item['target_id'];
|
|
}
|
|
}
|
|
|
|
// Obter foto padrão atual.
|
|
$default_photo_id = $user->get('field_user_default_photo')->target_id;
|
|
|
|
// Se não há fotos, limpar foto padrão.
|
|
if (empty($photo_ids)) {
|
|
$user->set('field_user_default_photo', NULL);
|
|
return;
|
|
}
|
|
|
|
// Se a foto padrão não está entre as fotos, selecionar a primeira.
|
|
if (empty($default_photo_id) || !in_array($default_photo_id, $photo_ids)) {
|
|
$user->set('field_user_default_photo', $photo_ids[0]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_site_tools_share_links().
|
|
*/
|
|
function site_users_site_tools_share_links(): array {
|
|
$user = \Drupal::routeMatch()->getParameter('user');
|
|
|
|
if (!($user instanceof UserInterface)) {
|
|
return [];
|
|
}
|
|
|
|
if (!$user->hasField('field_user_social_links') || $user->get('field_user_social_links')->isEmpty()) {
|
|
return [];
|
|
}
|
|
|
|
$links = [];
|
|
$networks = SocialLinkItem::getNetworks();
|
|
|
|
foreach ($user->get('field_user_social_links') as $delta => $item) {
|
|
if ($item->isEmpty()) {
|
|
continue;
|
|
}
|
|
|
|
$network_label = $networks[$item->network] ?? $item->network;
|
|
|
|
$links['social_' . $item->network] = [
|
|
'content' => [
|
|
'#type' => 'link',
|
|
'#title' => $network_label,
|
|
'#url' => Url::fromUri($item->url),
|
|
'#attributes' => [
|
|
'class' => ['social-link', 'social-link--' . $item->network],
|
|
'target' => '_blank',
|
|
'rel' => 'noopener noreferrer',
|
|
],
|
|
],
|
|
'weight' => $delta,
|
|
'provider' => 'site_users',
|
|
];
|
|
}
|
|
|
|
return $links;
|
|
}
|
|
|
|
/**
|
|
* Obtém a foto padrão de um usuário.
|
|
*
|
|
* @param \Drupal\user\UserInterface $user
|
|
* O usuário.
|
|
*
|
|
* @return \Drupal\media\MediaInterface|null
|
|
* A entidade de mídia da foto padrão, ou NULL se não houver.
|
|
*/
|
|
function site_users_get_default_photo(UserInterface $user): ?MediaInterface {
|
|
if (!$user->hasField('field_user_default_photo') || !$user->hasField('field_user_photos')) {
|
|
return NULL;
|
|
}
|
|
|
|
// Tentar obter a foto padrão configurada.
|
|
if (!$user->get('field_user_default_photo')->isEmpty()) {
|
|
$default_photo = $user->get('field_user_default_photo')->entity;
|
|
if ($default_photo instanceof MediaInterface) {
|
|
return $default_photo;
|
|
}
|
|
}
|
|
|
|
// Fallback: retornar a primeira foto disponível.
|
|
if (!$user->get('field_user_photos')->isEmpty()) {
|
|
$first_photo = $user->get('field_user_photos')->first()->entity;
|
|
if ($first_photo instanceof MediaInterface) {
|
|
return $first_photo;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|