Loading src/Plugin/Block/MenuSlideshowRefSlidesBlock.php +105 −98 Original line number Diff line number Diff line Loading @@ -12,6 +12,9 @@ use Drupal\Core\Menu\MenuActiveTrail; use Drupal\Core\Menu\MenuLinkManager; use Drupal\menu_link_content\MenuLinkContentInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use \Drupal\media\Entity\Media; use Drupal\Component\Uuid\Uuid; /** * Provides a 'DROWL Header Slides Menu Slideshow Slide Block (Page Width)' Block. Loading @@ -24,6 +27,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class MenuSlideshowRefSlidesBlock extends BlockBase implements ContainerFactoryPluginInterface { const MENU_LINK_CONTENT_ENTITY_TYPE = 'menu_link_content'; /** * The entity type manager object. * Loading Loading @@ -98,144 +103,146 @@ class MenuSlideshowRefSlidesBlock extends BlockBase implements ContainerFactoryP * {@inheritdoc} */ public function build() { $activeTrailMenuLinkEntity = $this->determineActiveTrailMenuLinkEntity(); if (!empty($activeTrailMenuLinkEntity)) { $mediaSlideshowEntity = $this->determineActiveTrailMediaHeaderSlideEntity(); if (!empty($mediaSlideshowEntity)) { /** * @var \Drupal\media_entity\Entity\Media $mediaSlideshowEntity * @var $mediaSlideshowEntity \Drupal\media\Entity\Media */ $mediaSlideshowEntity = $this->determineMenuLinkMediaSlideshowEntity($activeTrailMenuLinkEntity); if (!empty($mediaSlideshowEntity) && $mediaSlideshowEntity->access('view')) { // Return the rendered media entity: $build = $this->entityTypeManager->getViewBuilder('media')->view($mediaSlideshowEntity); $build = \Drupal::entityTypeManager()->getViewBuilder('media')->view($mediaSlideshowEntity, $this->view_mode); return $build; } } return NULL; return null; } /** * {@inheritdoc} */ public function getCacheContexts() { // Every new route this block will rebuild. return Cache::mergeContexts(parent::getCacheContexts(), ['route']); //Every new route this block will rebuild return Cache::mergeContexts(parent::getCacheContexts(), array('route')); } /** * Returns the Media slideshow entity from the given menu link. * * @param \Drupal\menu_link_content\MenuLinkContentInterface $menuLinkEntity * The menu link entity. * Returns the currently active MenuLinkContent entity. * * @return \Drupal\media_entity\Entity\Media * The media slideshow entity. * @return \Drupal\media\Entity\Media|null */ protected function determineMenuLinkMediaSlideshowEntity(MenuLinkContentInterface $menuLinkEntity = NULL) { if (empty($menuLinkEntity)) { return NULL; protected function determineActiveTrailMediaHeaderSlideEntity(): ?Media { // Cache per site call: $menuActiveLinkEntity = &drupal_static(__FUNCTION__, null); if (isset($menuActiveLinkEntity)) { return $menuActiveLinkEntity ?: null; } if ($menuLinkEntity->hasField('field_slideshow_ref')) { $candidateMenuLinkIds = $this->determineActiveTrailsMenuLinkIds(); $i = 0; foreach ($candidateMenuLinkIds as $key => $candidateMenuLinkId) { $menuLinkContentEntity = $this->getMenuLinkContentEntityFromUuidString($candidateMenuLinkId); if (!empty($menuLinkContentEntity) && $menuLinkContentEntity->hasField('field_slideshow_ref')) { /** * @var \Drupal\media_entity\Entity\Media $mediaSlideshowEntity * @var $mediaSlideshowEntity \Drupal\media\Entity\Media */ $mediaSlideshowEntity = $menuLinkEntity->field_slideshow_ref->entity; $mediaSlideshowEntity = $menuLinkContentEntity->field_slideshow_ref->entity; if (!empty($mediaSlideshowEntity)) { // ONLY return the entity if it's the currently displayed // menu item or has field_slideshow_inherit enabled! // Other menu items are wrong! if ($i == 0) { // This is the menu item of the node itself return $mediaSlideshowEntity; } elseif ($menuLinkContentEntity->hasField('field_slideshow_inherit')) { // The parent menu item has a field_slideshow_inherit field. /** * @var $inheritFromParent boolean */ $inheritFromParent = !empty($menuLinkContentEntity->get('field_slideshow_inherit')->value); if ($inheritFromParent) { // Inherit from parent is enabled. Return the parent as slideshow provider: return $mediaSlideshowEntity; } } } } // Has no own slideshow selected - check for parent inheritance: return $this->determineMenuLinkMediaSlideshowEntity($this->determineParentMenuLink($menuLinkEntity)); $i++; } return null; } /** * Returns the parent menu item from the given $menuLinkEntity. * Returns an array of all active trail menu link UUIDs, starting * with the current node, up to front as last item, as they may contain * a header slideshow selection with field_slideshow_inherit enabled. * * @param \Drupal\menu_link_content\MenuLinkContentInterface $menuLinkEntity * The menu link entity. * This allows to travel up the list, until such an entry is found or * we can be sure there's no such entry. * * @return \Drupal\menu_link_content\MenuLinkContentInterface * The parent menu link entity. * @return array */ protected function determineParentMenuLink(MenuLinkContentInterface $menuLinkEntity = NULL) { if (empty($menuLinkEntity)) { return NULL; protected function determineActiveTrailsMenuLinkIds(): array { $searchInMenus = \Drupal::config('drowl_header_slides.settings')->get('menus'); $activeTrailIds = []; if (!empty($searchInMenus)) { foreach ($searchInMenus as $menu_id) { $activeTrailIds = $this->menuActiveTrail->getActiveTrailIds($menu_id); // Return the first found active trail. // @todo This should be improved, perhaps better merge candidates // from all selected menus? (But in 90% this is enough). if (!empty($activeTrailIds) && (count($activeTrailIds) > 1 || !empty(reset($activeTrailIds)))) { // IMPORTANT: $activeTrailIds[''] is also returned for empty results // with an empty array, so wo have to sort that out! // Check if the currently viewed entity has a menu item itself, // otherwise it will not appear in the trail, but we have to indicate // this with an empty first entry in the $activeTrailIds // to show we're returning parent entities. $menuActiveLink = $this->menuActiveTrail->getActiveLink($menu_id); if (empty($menuActiveLink)) { // Prepend this placeholder value to the results to count all // other results as parent items and upper methods can see that // there's no direct / own menu item returned: array_unshift($activeTrailIds, 'ONLY-PARENT-ITEMS-FOUND-PLACEHOLDER'); } // Load the parent menu id: /** * @var string $parentMenuLinkEntityId */ $parentMenuLinkEntityId = $menuLinkEntity->getParentId(); if (!empty($parentMenuLinkEntityId)) { /** * @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent */ $parentMenuLinkManagerInstance = $this->menuLinkManager->createInstance($parentMenuLinkEntityId); /** * @var string $parentMenuLinkManagerInstanceDerivateId */ $parentMenuLinkManagerInstanceDerivateId = $parentMenuLinkManagerInstance->getDerivativeId(); // Load the parent menu_item entity. /** * @var \Drupal\menu_item_extras\Entity\MenuItemExtrasMenuLinkContent $parentMenuLinkEntity */ $parentMenuLinkEntity = $this->entityRepository ->loadEntityByUuid('menu_link_content', $parentMenuLinkManagerInstanceDerivateId); if (!empty($parentMenuLinkEntity) && $parentMenuLinkEntity->hasField('field_slideshow_inherit')) { // The parent menu item has a field_slideshow_inherit field. /** * @var boolean $inheritFromParent */ $inheritFromParent = !empty($parentMenuLinkEntity->get('field_slideshow_inherit')->value); if ($inheritFromParent) { // Inherit from parent is enabled. Return the parent as slideshow // provider: return $parentMenuLinkEntity; break; } } } return NULL; return $activeTrailIds; } /** * Returns the currently active MenuLinkContent entity. * Returns the menu_link_content entity from the given $uuidString. * * @return \Drupal\menu_link_content\MenuLinkContentInterface * The currently active MenuLinkContent entity. * @param string $uuidString * The UUID string, for example menu_link_content:6887e19d-4426-47e3-afa9 * @return \Drupal\menu_link_content\MenuLinkContentInterface|null */ protected function determineActiveTrailMenuLinkEntity() { // Cache per site call: $menuActiveLinkEntity = &drupal_static(__FUNCTION__, NULL); if (isset($menuActiveLinkEntity)) { return $menuActiveLinkEntity ?? NULL; } $config = $this->configFactory->get('drowl_header_slides.settings'); $searchInMenus = $config->get('menus'); $menuActiveLink = NULL; if (!empty($searchInMenus)) { foreach ($searchInMenus as $menu) { // Hint: Drupal treats the first menu with an active link // as the matching menu, whatever we do... Our // current workaround is to only use the selected menu(s). // It Would be better to sort the menus for evaluation and check // them in the configured order, // IF they contain a drowl_header_slide reference. $menuActiveLink = $this->menuActiveTrail->getActiveLink($menu); break; } private function getMenuLinkContentEntityFromUuidString(string $uuidString): ?MenuLinkContentInterface { $parts = explode(':', $uuidString); // Skip if one part is empty: if (empty($parts[0]) || empty($parts[1])) { return null; } if (empty($menuActiveLink)) { return NULL; $pluginId = $parts[0]; $uuid = $parts[1]; // Skip if the item has no valid UUID: if (!Uuid::isValid($uuid)) { return null; } $menuActiveLinkUuid = $menuActiveLink->getDerivativeId(); if (empty($menuActiveLinkUuid)) { return NULL; if (is_a($pluginId[0], MenuLinkContentInterface::class)) { throw new \Exception('Entity of type menu_link_content expected, but was "' . $parts[0] . '"'); } $menuActiveLinkEntity = $this->entityRepository ->loadEntityByUuid('menu_link_content', $menuActiveLinkUuid); $menuActiveLinkEntity = $this->entityRepository->loadEntityByUuid(self::MENU_LINK_CONTENT_ENTITY_TYPE, $parts[1]); if (!empty($menuActiveLinkEntity)) { return $menuActiveLinkEntity; } return NULL; return null; } } Loading
src/Plugin/Block/MenuSlideshowRefSlidesBlock.php +105 −98 Original line number Diff line number Diff line Loading @@ -12,6 +12,9 @@ use Drupal\Core\Menu\MenuActiveTrail; use Drupal\Core\Menu\MenuLinkManager; use Drupal\menu_link_content\MenuLinkContentInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use \Drupal\media\Entity\Media; use Drupal\Component\Uuid\Uuid; /** * Provides a 'DROWL Header Slides Menu Slideshow Slide Block (Page Width)' Block. Loading @@ -24,6 +27,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class MenuSlideshowRefSlidesBlock extends BlockBase implements ContainerFactoryPluginInterface { const MENU_LINK_CONTENT_ENTITY_TYPE = 'menu_link_content'; /** * The entity type manager object. * Loading Loading @@ -98,144 +103,146 @@ class MenuSlideshowRefSlidesBlock extends BlockBase implements ContainerFactoryP * {@inheritdoc} */ public function build() { $activeTrailMenuLinkEntity = $this->determineActiveTrailMenuLinkEntity(); if (!empty($activeTrailMenuLinkEntity)) { $mediaSlideshowEntity = $this->determineActiveTrailMediaHeaderSlideEntity(); if (!empty($mediaSlideshowEntity)) { /** * @var \Drupal\media_entity\Entity\Media $mediaSlideshowEntity * @var $mediaSlideshowEntity \Drupal\media\Entity\Media */ $mediaSlideshowEntity = $this->determineMenuLinkMediaSlideshowEntity($activeTrailMenuLinkEntity); if (!empty($mediaSlideshowEntity) && $mediaSlideshowEntity->access('view')) { // Return the rendered media entity: $build = $this->entityTypeManager->getViewBuilder('media')->view($mediaSlideshowEntity); $build = \Drupal::entityTypeManager()->getViewBuilder('media')->view($mediaSlideshowEntity, $this->view_mode); return $build; } } return NULL; return null; } /** * {@inheritdoc} */ public function getCacheContexts() { // Every new route this block will rebuild. return Cache::mergeContexts(parent::getCacheContexts(), ['route']); //Every new route this block will rebuild return Cache::mergeContexts(parent::getCacheContexts(), array('route')); } /** * Returns the Media slideshow entity from the given menu link. * * @param \Drupal\menu_link_content\MenuLinkContentInterface $menuLinkEntity * The menu link entity. * Returns the currently active MenuLinkContent entity. * * @return \Drupal\media_entity\Entity\Media * The media slideshow entity. * @return \Drupal\media\Entity\Media|null */ protected function determineMenuLinkMediaSlideshowEntity(MenuLinkContentInterface $menuLinkEntity = NULL) { if (empty($menuLinkEntity)) { return NULL; protected function determineActiveTrailMediaHeaderSlideEntity(): ?Media { // Cache per site call: $menuActiveLinkEntity = &drupal_static(__FUNCTION__, null); if (isset($menuActiveLinkEntity)) { return $menuActiveLinkEntity ?: null; } if ($menuLinkEntity->hasField('field_slideshow_ref')) { $candidateMenuLinkIds = $this->determineActiveTrailsMenuLinkIds(); $i = 0; foreach ($candidateMenuLinkIds as $key => $candidateMenuLinkId) { $menuLinkContentEntity = $this->getMenuLinkContentEntityFromUuidString($candidateMenuLinkId); if (!empty($menuLinkContentEntity) && $menuLinkContentEntity->hasField('field_slideshow_ref')) { /** * @var \Drupal\media_entity\Entity\Media $mediaSlideshowEntity * @var $mediaSlideshowEntity \Drupal\media\Entity\Media */ $mediaSlideshowEntity = $menuLinkEntity->field_slideshow_ref->entity; $mediaSlideshowEntity = $menuLinkContentEntity->field_slideshow_ref->entity; if (!empty($mediaSlideshowEntity)) { // ONLY return the entity if it's the currently displayed // menu item or has field_slideshow_inherit enabled! // Other menu items are wrong! if ($i == 0) { // This is the menu item of the node itself return $mediaSlideshowEntity; } elseif ($menuLinkContentEntity->hasField('field_slideshow_inherit')) { // The parent menu item has a field_slideshow_inherit field. /** * @var $inheritFromParent boolean */ $inheritFromParent = !empty($menuLinkContentEntity->get('field_slideshow_inherit')->value); if ($inheritFromParent) { // Inherit from parent is enabled. Return the parent as slideshow provider: return $mediaSlideshowEntity; } } } } // Has no own slideshow selected - check for parent inheritance: return $this->determineMenuLinkMediaSlideshowEntity($this->determineParentMenuLink($menuLinkEntity)); $i++; } return null; } /** * Returns the parent menu item from the given $menuLinkEntity. * Returns an array of all active trail menu link UUIDs, starting * with the current node, up to front as last item, as they may contain * a header slideshow selection with field_slideshow_inherit enabled. * * @param \Drupal\menu_link_content\MenuLinkContentInterface $menuLinkEntity * The menu link entity. * This allows to travel up the list, until such an entry is found or * we can be sure there's no such entry. * * @return \Drupal\menu_link_content\MenuLinkContentInterface * The parent menu link entity. * @return array */ protected function determineParentMenuLink(MenuLinkContentInterface $menuLinkEntity = NULL) { if (empty($menuLinkEntity)) { return NULL; protected function determineActiveTrailsMenuLinkIds(): array { $searchInMenus = \Drupal::config('drowl_header_slides.settings')->get('menus'); $activeTrailIds = []; if (!empty($searchInMenus)) { foreach ($searchInMenus as $menu_id) { $activeTrailIds = $this->menuActiveTrail->getActiveTrailIds($menu_id); // Return the first found active trail. // @todo This should be improved, perhaps better merge candidates // from all selected menus? (But in 90% this is enough). if (!empty($activeTrailIds) && (count($activeTrailIds) > 1 || !empty(reset($activeTrailIds)))) { // IMPORTANT: $activeTrailIds[''] is also returned for empty results // with an empty array, so wo have to sort that out! // Check if the currently viewed entity has a menu item itself, // otherwise it will not appear in the trail, but we have to indicate // this with an empty first entry in the $activeTrailIds // to show we're returning parent entities. $menuActiveLink = $this->menuActiveTrail->getActiveLink($menu_id); if (empty($menuActiveLink)) { // Prepend this placeholder value to the results to count all // other results as parent items and upper methods can see that // there's no direct / own menu item returned: array_unshift($activeTrailIds, 'ONLY-PARENT-ITEMS-FOUND-PLACEHOLDER'); } // Load the parent menu id: /** * @var string $parentMenuLinkEntityId */ $parentMenuLinkEntityId = $menuLinkEntity->getParentId(); if (!empty($parentMenuLinkEntityId)) { /** * @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent */ $parentMenuLinkManagerInstance = $this->menuLinkManager->createInstance($parentMenuLinkEntityId); /** * @var string $parentMenuLinkManagerInstanceDerivateId */ $parentMenuLinkManagerInstanceDerivateId = $parentMenuLinkManagerInstance->getDerivativeId(); // Load the parent menu_item entity. /** * @var \Drupal\menu_item_extras\Entity\MenuItemExtrasMenuLinkContent $parentMenuLinkEntity */ $parentMenuLinkEntity = $this->entityRepository ->loadEntityByUuid('menu_link_content', $parentMenuLinkManagerInstanceDerivateId); if (!empty($parentMenuLinkEntity) && $parentMenuLinkEntity->hasField('field_slideshow_inherit')) { // The parent menu item has a field_slideshow_inherit field. /** * @var boolean $inheritFromParent */ $inheritFromParent = !empty($parentMenuLinkEntity->get('field_slideshow_inherit')->value); if ($inheritFromParent) { // Inherit from parent is enabled. Return the parent as slideshow // provider: return $parentMenuLinkEntity; break; } } } return NULL; return $activeTrailIds; } /** * Returns the currently active MenuLinkContent entity. * Returns the menu_link_content entity from the given $uuidString. * * @return \Drupal\menu_link_content\MenuLinkContentInterface * The currently active MenuLinkContent entity. * @param string $uuidString * The UUID string, for example menu_link_content:6887e19d-4426-47e3-afa9 * @return \Drupal\menu_link_content\MenuLinkContentInterface|null */ protected function determineActiveTrailMenuLinkEntity() { // Cache per site call: $menuActiveLinkEntity = &drupal_static(__FUNCTION__, NULL); if (isset($menuActiveLinkEntity)) { return $menuActiveLinkEntity ?? NULL; } $config = $this->configFactory->get('drowl_header_slides.settings'); $searchInMenus = $config->get('menus'); $menuActiveLink = NULL; if (!empty($searchInMenus)) { foreach ($searchInMenus as $menu) { // Hint: Drupal treats the first menu with an active link // as the matching menu, whatever we do... Our // current workaround is to only use the selected menu(s). // It Would be better to sort the menus for evaluation and check // them in the configured order, // IF they contain a drowl_header_slide reference. $menuActiveLink = $this->menuActiveTrail->getActiveLink($menu); break; } private function getMenuLinkContentEntityFromUuidString(string $uuidString): ?MenuLinkContentInterface { $parts = explode(':', $uuidString); // Skip if one part is empty: if (empty($parts[0]) || empty($parts[1])) { return null; } if (empty($menuActiveLink)) { return NULL; $pluginId = $parts[0]; $uuid = $parts[1]; // Skip if the item has no valid UUID: if (!Uuid::isValid($uuid)) { return null; } $menuActiveLinkUuid = $menuActiveLink->getDerivativeId(); if (empty($menuActiveLinkUuid)) { return NULL; if (is_a($pluginId[0], MenuLinkContentInterface::class)) { throw new \Exception('Entity of type menu_link_content expected, but was "' . $parts[0] . '"'); } $menuActiveLinkEntity = $this->entityRepository ->loadEntityByUuid('menu_link_content', $menuActiveLinkUuid); $menuActiveLinkEntity = $this->entityRepository->loadEntityByUuid(self::MENU_LINK_CONTENT_ENTITY_TYPE, $parts[1]); if (!empty($menuActiveLinkEntity)) { return $menuActiveLinkEntity; } return NULL; return null; } }