group_content_menu-8.x-1.0-rc3/group_content_menu.module
group_content_menu.module
<?php
/**
* @file
* Provides a group content menu entity type.
*/
use Drupal\content_translation\ContentTranslationHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Hook\Attribute\LegacyHook;
use Drupal\Core\Hook\Attribute\LegacyModuleImplementsAlter;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\group\Entity\GroupInterface;
use Drupal\group\Entity\GroupType;
use Drupal\group\Entity\Storage\GroupRelationshipTypeStorageInterface;
use Drupal\group\Plugin\Group\Relation\GroupRelationTypeManagerInterface;
use Drupal\group_content_menu\Access\GroupMenuItemTranslateAccessHandler;
use Drupal\group_content_menu\Entity\GroupContentMenuType;
use Drupal\group_content_menu\GroupContentMenuInterface;
use Drupal\group_content_menu\NodeFormAlter;
use Drupal\group_content_menu\TranslationSuggestions;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\node\NodeInterface;
use Drupal\tmgmt\JobInterface;
/**
* Implements hook_theme().
*/
function group_content_menu_theme() {
return [
'group_content_menu' => [
'render element' => 'elements',
],
'menu__group_menu' => [
'base hook' => 'menu',
'variables' => ['items' => [], 'attributes' => []],
],
];
}
/**
* Implements hook_theme_registry_alter().
*/
function group_content_menu_theme_registry_alter(array &$theme_registry): void {
// Add a variable to the "menu" theme hook in order to pass custom values from
// GroupMenuBlock::build. Those custom values are used to generate additional
// theme hook suggestions in the "group_content_menu_theme_suggestions_menu"
// hook below.
$theme_registry['menu']['variables']['group_content_menu'] = [];
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function group_content_menu_theme_suggestions_menu(array $variables): array {
$suggestions = [];
// If this variable is not set, do not modify any suggestion—the themed
// element must not be a group content menu.
if (empty($variables['group_content_menu'])) {
return $suggestions;
}
$suggestions[] = 'menu__group_menu';
[
'menu_name' => $menu_name,
'theme_hook_suggestion' => $theme_hook_suggestion,
'group_content_menu_type' => $group_content_menu_type,
] = $variables['group_content_menu'];
if (!empty($group_content_menu_type)) {
$suggestions[] = 'menu__group_menu__' . strtr($group_content_menu_type, '-', '_');
}
if (!empty($menu_name)) {
$suggestions[] = 'menu__' . strtr($menu_name, '-', '_');
}
if (!empty($theme_hook_suggestion)) {
$suggestions[] = 'menu__group_menu__' . $theme_hook_suggestion;
}
return $suggestions;
}
/**
* Prepares variables for group content menu templates.
*
* Default template: group-content-menu.html.twig.
*
* @param array $variables
* An associative array containing:
* - elements: An associative array containing the group content menu
* information and any fields attached to the entity.
* - attributes: HTML attributes for the containing element.
*/
function template_preprocess_group_content_menu(array &$variables) {
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
}
/**
* Implements hook_entity_operation().
*/
function group_content_menu_entity_operation($entity) {
$operations = [];
if ($entity->getEntityTypeId() == 'group' && \Drupal::moduleHandler()->moduleExists('views')) {
if ($entity->hasPermission('access group content menu overview', \Drupal::currentUser())) {
$operations['menus'] = [
'title' => t('Menus'),
'weight' => 20,
'url' => Url::fromRoute('entity.group_content_menu.collection', ['group' => $entity->id()]),
];
}
}
return $operations;
}
/**
* Implements hook_module_implements_alter().
*/
#[LegacyModuleImplementsAlter]
function group_content_menu_module_implements_alter(&$implementations, $hook) {
// Make sure our hook_node_form_alter runs after the menu_ui module.
if ($hook === 'form_alter' && isset($implementations['group_content_menu'])) {
$group_content_menu = $implementations['group_content_menu'];
unset($implementations['group_content_menu']);
$implementations['group_content_menu'] = $group_content_menu;
}
// Make sure our hook_node_form_alter runs after the menu_link_content module.
if ($hook === 'entity_predelete' && isset($implementations['group_content_menu'])) {
$group_content_menu = $implementations['group_content_menu'];
unset($implementations['group_content_menu']);
$implementations['group_content_menu'] = $group_content_menu;
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
#[LegacyModuleImplementsAlter]
function group_content_menu_form_node_form_alter(&$form, FormStateInterface $form_state) {
\Drupal::service('group_content_menu.node_form_alter')
->alter($form, $form_state);
}
/**
* Implements hook_ENTITY_TYPE_insert().
*/
function group_content_menu_group_insert(EntityInterface $entity) {
$plugins = group_content_menu_get_plugins_per_group($entity);
// If there are no group menus enabled, bail.
if (!$plugins) {
return;
}
$relationship_type_storage = \Drupal::entityTypeManager()->getStorage('group_relationship_type');
assert($relationship_type_storage instanceof GroupRelationshipTypeStorageInterface);
foreach ($plugins as $plugin) {
$group_type_configuration = $plugin->getConfiguration();
$auto_create_group_menu = $group_type_configuration['auto_create_group_menu'];
if (!$auto_create_group_menu) {
continue;
}
$group_content_type = GroupContentMenuType::load($plugin->getDerivativeId());
$group_menu = \Drupal::entityTypeManager()->getStorage('group_content_menu')->create([
'label' => $group_content_type->label(),
'bundle' => $plugin->getDerivativeId(),
]);
$group_menu->save();
// Add menu link for group if enabled.
$auto_create_home_link = $group_type_configuration['auto_create_home_link'];
if ($auto_create_home_link) {
$menu_name = GroupContentMenuInterface::MENU_PREFIX . $group_menu->id();
$menu_link = \Drupal::entityTypeManager()->getStorage('menu_link_content')->create([
'title' => $group_type_configuration['auto_create_home_link_title'],
'link' => [
'uri' => 'internal:/group/' . $entity->id(),
],
'menu_name' => $menu_name,
]);
$menu_link->save();
}
$group_relationship = \Drupal::entityTypeManager()->getStorage('group_relationship')->create([
'type' => $relationship_type_storage->getRelationshipTypeId($entity->bundle(), $plugin->getPluginId()),
'gid' => $entity->id(),
'label' => $group_content_type->label(),
'entity_id' => $group_menu,
]);
$group_relationship->save();
}
}
/**
* Implements hook_entity_predelete().
*/
#[LegacyHook]
function group_content_menu_entity_predelete(EntityInterface $entity): void {
\Drupal::service('group_content_menu.hooks')->entityPredelete($entity);
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function group_content_menu_group_delete(EntityInterface $entity) {
// Remove the group menu and recursively its links on group deletion.
foreach (group_content_menu_get_menus_per_group($entity) as $group_relationship) {
$group_relationship->getEntity()->delete();
}
}
/**
* Get group content menus per group.
*
* @param \Drupal\group\Entity\GroupInterface $group
* The group.
*
* @return \Drupal\group\Entity\GroupRelationshipInterface[]
* The related group contents.
*/
function group_content_menu_get_menus_per_group(GroupInterface $group) {
$plugins = group_content_menu_get_plugins_per_group($group);
$instances = [];
foreach (array_keys($plugins) as $plugin_id) {
$instances[] = \Drupal::entityTypeManager()->getStorage('group_relationship')->loadByGroup($group, $plugin_id);
}
return $instances ? array_merge(...$instances) : [];
}
/**
* Get group content menu plugins per group.
*
* @param \Drupal\group\Entity\GroupInterface $group
* The group.
*
* @return \Drupal\group\Plugin\Group\Relation\GroupRelationInterface[]
* The group menu plugins.
*/
function group_content_menu_get_plugins_per_group(GroupInterface $group) {
$group_type = GroupType::load($group->bundle());
$plugin_manager = \Drupal::service('group_relation_type.manager');
assert($plugin_manager instanceof GroupRelationTypeManagerInterface);
$installed = $plugin_manager->getInstalled($group_type);
return array_filter($installed->getIterator()->getArrayCopy(), static function ($plugin_id) {
return strpos($plugin_id, 'group_content_menu:') === 0;
}, ARRAY_FILTER_USE_KEY);
}
/**
* Returns the definition for a menu link for the given node.
*
* @param \Drupal\node\NodeInterface $node
* The node entity.
* @param array $menu_names
* The menu names.
*
* @return array
* An array that contains default values for the menu link form.
*/
function group_content_menu_get_menu_link_default(NodeInterface $node, array $menu_names) {
/** @var \Drupal\node\NodeTypeInterface $node_type */
$node_type = $node->type->entity;
$menu_name = strtok($node_type->getThirdPartySetting('menu_ui', 'parent', 'main:'), ':');
$defaults = [
'entity_id' => 0,
'id' => '',
'title' => '',
'title_max_length' => 128,
'description' => '',
'description_max_length' => 128,
'menu_name' => $menu_name,
'parent' => '',
'weight' => 0,
];
if (empty($menu_names)) {
// No menu is yet available.
return $defaults;
}
if ($node->id()) {
$query = \Drupal::entityQuery('menu_link_content')
->condition('link.uri', 'entity:node/' . $node->id())
->condition('menu_name', $menu_names, 'IN')
->sort('id', 'ASC')
->accessCheck(TRUE)
->range(0, 1);
$result = $query->execute();
$id = !empty($result) ? reset($result) : FALSE;
if ($id) {
$menu_link = MenuLinkContent::load($id);
$menu_link = \Drupal::service('entity.repository')->getTranslationFromContext($menu_link);
$defaults = [
'entity_id' => $menu_link->id(),
'id' => $menu_link->getPluginId(),
'title' => $menu_link->getTitle(),
'title_max_length' => $menu_link->getFieldDefinitions()['title']->getSetting('max_length'),
'description' => $menu_link->getDescription(),
'description_max_length' => $menu_link->getFieldDefinitions()['description']->getSetting('max_length'),
'menu_name' => $menu_link->getMenuName(),
'parent' => $menu_link->getParentId(),
'weight' => $menu_link->getWeight(),
];
}
}
return $defaults;
}
/**
* Implements hook_entity_type_alter().
*/
function group_content_menu_entity_type_alter(array &$entity_types) {
if (isset($entity_types['menu_link_content']) && $entity_types['menu_link_content']->getHandlerClass('translation') === ContentTranslationHandler::class) {
$entity_types['menu_link_content']->setHandlerClass('translation', GroupMenuItemTranslateAccessHandler::class);
}
}
/**
* Implements hook_tmgmt_source_suggestions().
*/
function group_content_menu_tmgmt_source_suggestions(array $items, JobInterface $job): array {
return \Drupal::classResolver(TranslationSuggestions::class)
->suggestions($items, $job);
}
