diff --git a/helfi_navigation.module b/helfi_navigation.module index 274ae3e..a91c42d 100644 --- a/helfi_navigation.module +++ b/helfi_navigation.module @@ -13,6 +13,8 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Utility\Error; +use Drupal\helfi_navigation\ApiAuthorization; +use Drupal\helfi_navigation\ApiManager; use Drupal\menu_link_content\Entity\MenuLinkContent; use Drupal\menu_link_content\MenuLinkContentInterface; use Drupal\system\MenuInterface; @@ -123,7 +125,7 @@ function helfi_navigation_menu_link_content_delete(MenuLinkContentInterface $ent * Create menu update queue item. */ function _helfi_navigation_queue_item(string $menuName, string $langcode, string $action) : void { - if (!\Drupal::service('helfi_navigation.api_authorization')->getAuthorization()) { + if (!Drupal::service(ApiAuthorization::class)->getAuthorization()) { return; } $queue = Drupal::queue('helfi_navigation_menu_queue'); @@ -150,7 +152,7 @@ function helfi_navigation_page_attachments(array &$attachments) : void { $langcode = $defaultLanguageResolver->getCurrentOrFallbackLanguage(); /** @var \Drupal\helfi_navigation\ApiManager $apiManager */ - $apiManager = Drupal::service('helfi_navigation.api_manager'); + $apiManager = Drupal::service(ApiManager::class); try { // Ensure that drupalSettings library is enabled (menu library is not @@ -164,7 +166,7 @@ function helfi_navigation_page_attachments(array &$attachments) : void { ], ]; } - catch (\Exception $e) { + catch (Exception $e) { /** @var \Psr\Log\LoggerInterface $logger */ $logger = Drupal::service('logger.channel.helfi_navigation'); diff --git a/helfi_navigation.services.yml b/helfi_navigation.services.yml index fc6c715..0b545ac 100644 --- a/helfi_navigation.services.yml +++ b/helfi_navigation.services.yml @@ -2,50 +2,25 @@ parameters: helfi_navigation.request_timeout: 15 helfi_navigation.absolute_url_always: null services: + _defaults: + autoconfigure: true + autowire: true + logger.channel.helfi_navigation: parent: logger.channel_base arguments: ['helfi_navigation'] - helfi_navigation.external_menu_tree_builder: - class: Drupal\helfi_navigation\ExternalMenuTreeBuilder - arguments: - - '@helfi_api_base.internal_domain_resolver' - - '@request_stack' + + Drupal\helfi_navigation\ExternalMenuTreeBuilder: ~ + helfi_navigation.api_client: parent: helfi_api_base.api_client_base arguments: - '@logger.channel.helfi_navigation' - { timeout: '%helfi_navigation.request_timeout%' } - helfi_navigation.api_manager: - class: Drupal\helfi_navigation\ApiManager - arguments: - - '@helfi_navigation.api_client' - - '@helfi_api_base.environment_resolver' - - '@helfi_navigation.api_authorization' - helfi_navigation.menu_manager: - class: Drupal\helfi_navigation\MainMenuManager - arguments: - - '@language_manager' - - '@config.factory' - - '@helfi_navigation.api_manager' - - '@helfi_navigation.menu_tree_builder' - - '@account_switcher' - helfi_navigation.menu_tree_builder: - class: Drupal\helfi_navigation\Menu\MenuTreeBuilder - arguments: - - '@entity_type.manager' - - '@helfi_api_base.internal_domain_resolver' - - '@menu.link_tree' - - '@plugin.manager.menu.link' - - '@event_dispatcher' - helfi_navigation.api_authorization: - class: Drupal\helfi_navigation\ApiAuthorization - arguments: - - '@config.factory' - - '@helfi_api_base.vault_manager' - helfi_api_base.absolute_url_menu_tree_builder_subscriber: - class: Drupal\helfi_navigation\EventSubscriber\AbsoluteUrlMenuTreeBuilderLinkSubscriber - arguments: - - '@helfi_api_base.environment_resolver' - - '%helfi_navigation.absolute_url_always%' - tags: - - { name: event_subscriber } + + Drupal\helfi_navigation\ApiManager: ~ + + Drupal\helfi_navigation\MainMenuManager: ~ + Drupal\helfi_navigation\Menu\MenuTreeBuilder: ~ + Drupal\helfi_navigation\ApiAuthorization: ~ + Drupal\helfi_navigation\EventSubscriber\AbsoluteUrlMenuTreeBuilderLinkSubscriber: ~ diff --git a/phpunit.xml b/phpunit.xml index b7bfdd4..2742fc5 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -4,11 +4,9 @@ colors="true" cacheResultFile=".phpunit.cache/test-results" executionOrder="depends,defects" - forceCoversAnnotation="true" beStrictAboutTestsThatDoNotTestAnything="true" beStrictAboutOutputDuringTests="true" beStrictAboutChangesToGlobalState="true" - beStrictAboutCoversAnnotation="true" printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter" failOnRisky="true" failOnWarning="true" diff --git a/src/ApiManager.php b/src/ApiManager.php index 63091cc..707b38f 100644 --- a/src/ApiManager.php +++ b/src/ApiManager.php @@ -11,6 +11,7 @@ use Drupal\helfi_api_base\Cache\CacheKeyTrait; use Drupal\helfi_api_base\Environment\EnvironmentResolverInterface; use Drupal\helfi_api_base\Environment\Project; +use Symfony\Component\DependencyInjection\Attribute\Autowire; /** * Service class for global navigation-related functions. @@ -19,7 +20,14 @@ class ApiManager { public const GLOBAL_MENU_ENDPOINT = '/api/v1/global-menu'; public const MENU_ENDPOINT = '/api/v1/menu'; - public const TTL = 180; + + /** + * Cache menu data for one month. + * + * The response cache is flushed by 'helfi_navigation_menu_queue' + * queue worker. + */ + public const TTL = 2629800; use CacheKeyTrait; @@ -34,7 +42,7 @@ class ApiManager { * The API authorization service. */ public function __construct( - private ApiClient $client, + #[Autowire(service: 'helfi_navigation.api_client')] private ApiClient $client, private readonly EnvironmentResolverInterface $environmentResolver, private readonly ApiAuthorization $apiAuthorization, ) { diff --git a/src/EventSubscriber/AbsoluteUrlMenuTreeBuilderLinkSubscriber.php b/src/EventSubscriber/AbsoluteUrlMenuTreeBuilderLinkSubscriber.php index 8b41bf6..3afa868 100644 --- a/src/EventSubscriber/AbsoluteUrlMenuTreeBuilderLinkSubscriber.php +++ b/src/EventSubscriber/AbsoluteUrlMenuTreeBuilderLinkSubscriber.php @@ -7,6 +7,7 @@ use Drupal\helfi_api_base\Environment\EnvironmentResolverInterface; use Drupal\helfi_api_base\Environment\Project; use Drupal\helfi_navigation\Event\MenuTreeBuilderLink; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -24,7 +25,7 @@ final class AbsoluteUrlMenuTreeBuilderLinkSubscriber implements EventSubscriberI */ public function __construct( private readonly EnvironmentResolverInterface $environmentResolver, - private ?bool $mustBeAbsoluteUrl = NULL, + #[Autowire('%helfi_navigation.absolute_url_always%')] private ?bool $mustBeAbsoluteUrl = NULL, ) { } diff --git a/src/HelfiNavigationServiceProvider.php b/src/HelfiNavigationServiceProvider.php index d8bf62a..108e3c4 100644 --- a/src/HelfiNavigationServiceProvider.php +++ b/src/HelfiNavigationServiceProvider.php @@ -23,7 +23,7 @@ public function register(ContainerBuilder $container) { $modules = $container->getParameter('container.modules'); if (isset($modules['redirect'])) { - $container->register('helfi_navigation.redirect_subscriber', RedirectEventSubscriber::class) + $container->register(RedirectEventSubscriber::class) ->addTag('event_subscriber') ->addArgument(new Reference('redirect.repository')) ->addArgument(new Reference('config.factory')); diff --git a/src/MainMenuManager.php b/src/MainMenuManager.php index ff5185a..416d638 100644 --- a/src/MainMenuManager.php +++ b/src/MainMenuManager.php @@ -10,6 +10,7 @@ use Drupal\Core\Url; use Drupal\helfi_navigation\Menu\MenuTreeBuilder; use Drupal\language\ConfigurableLanguageManagerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; /** * Menu manager service. @@ -31,7 +32,7 @@ class MainMenuManager { * The account switcher service. */ public function __construct( - private readonly ConfigurableLanguageManagerInterface $languageManager, + #[Autowire(service: 'language_manager')] private readonly ConfigurableLanguageManagerInterface $languageManager, private readonly ConfigFactoryInterface $config, private readonly ApiManager $apiManager, private readonly MenuTreeBuilder $menuTreeBuilder, diff --git a/src/Menu/MenuTreeBuilder.php b/src/Menu/MenuTreeBuilder.php index d2d0605..a5ae4d2 100644 --- a/src/Menu/MenuTreeBuilder.php +++ b/src/Menu/MenuTreeBuilder.php @@ -16,7 +16,7 @@ use Drupal\helfi_api_base\Link\InternalDomainResolver; use Drupal\helfi_navigation\Event\MenuTreeBuilderLink; use Drupal\menu_link_content\MenuLinkContentInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Create menu tree from Drupal menu. @@ -34,7 +34,7 @@ final class MenuTreeBuilder { * The 'menu link tree builder' service. * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager * The menu link manager. - * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher + * @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher * The event dispatcher. */ public function __construct( diff --git a/src/Plugin/Block/ExternalMenuBlockBase.php b/src/Plugin/Block/ExternalMenuBlockBase.php index 50093e4..7a3847a 100644 --- a/src/Plugin/Block/ExternalMenuBlockBase.php +++ b/src/Plugin/Block/ExternalMenuBlockBase.php @@ -51,8 +51,8 @@ abstract class ExternalMenuBlockBase extends MenuBlockBase implements ExternalMe */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) : static { $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); - $instance->apiManager = $container->get('helfi_navigation.api_manager'); - $instance->menuTreeBuilder = $container->get('helfi_navigation.external_menu_tree_builder'); + $instance->apiManager = $container->get(ApiManager::class); + $instance->menuTreeBuilder = $container->get(ExternalMenuTreeBuilder::class); $instance->languageManager = $container->get('language_manager'); $instance->defaultLanguageResolver = $container->get('helfi_api_base.default_language_resolver'); return $instance; @@ -88,6 +88,16 @@ public function getCacheContexts() : array { */ abstract protected function getTreeFromResponse(ApiResponse $response) : mixed; + /** + * Gets the request options. + * + * @return array + * The request options. + */ + protected function getRequestOptions() : array { + return []; + } + /** * {@inheritdoc} */ @@ -109,6 +119,7 @@ public function build() : array { $response = $this->apiManager->get( $langcode, $menuId, + $this->getRequestOptions(), ); $menuTree = $this->menuTreeBuilder ->build($this->getTreeFromResponse($response), $this->getOptions()); diff --git a/src/Plugin/Block/MainNavigationMenuBlock.php b/src/Plugin/Block/MainNavigationMenuBlock.php index 7acf806..128c840 100644 --- a/src/Plugin/Block/MainNavigationMenuBlock.php +++ b/src/Plugin/Block/MainNavigationMenuBlock.php @@ -24,6 +24,15 @@ public function getDerivativeId() : string { return 'main'; } + /** + * {@inheritdoc} + */ + protected function getRequestOptions() : array { + return [ + 'query' => 'max-depth=' . $this->getMaxDepth(), + ]; + } + /** * {@inheritdoc} */ diff --git a/src/Plugin/Block/MobileMenuFallbackBlock.php b/src/Plugin/Block/MobileMenuFallbackBlock.php index 138406c..177162e 100644 --- a/src/Plugin/Block/MobileMenuFallbackBlock.php +++ b/src/Plugin/Block/MobileMenuFallbackBlock.php @@ -84,7 +84,7 @@ public static function create( $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); $instance->configFactory = $container->get('config.factory'); $instance->pathMatcher = $container->get('path.matcher'); - $instance->apiManager = $container->get('helfi_navigation.api_manager'); + $instance->apiManager = $container->get(ApiManager::class); $instance->defaultLanguageResolver = $container->get('helfi_api_base.default_language_resolver'); $instance->filterByLanguage = $container->has('menu_block_current_language_tree_manipulator'); $instance->menuLinkManager = $container->get('plugin.manager.menu.link'); diff --git a/src/Plugin/QueueWorker/MenuQueue.php b/src/Plugin/QueueWorker/MenuQueue.php index bd16cb2..7cc77d0 100644 --- a/src/Plugin/QueueWorker/MenuQueue.php +++ b/src/Plugin/QueueWorker/MenuQueue.php @@ -6,7 +6,7 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Queue\QueueWorkerBase; -use Drupal\helfi_api_base\Cache\CacheTagInvalidator; +use Drupal\helfi_api_base\Cache\CacheTagInvalidatorInterface; use Drupal\helfi_api_base\Environment\Project; use Drupal\helfi_navigation\MainMenuManager; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -32,16 +32,16 @@ final class MenuQueue extends QueueWorkerBase implements ContainerFactoryPluginI /** * The cache tag invalidator service. * - * @var \Drupal\helfi_api_base\Cache\CacheTagInvalidator + * @var \Drupal\helfi_api_base\Cache\CacheTagInvalidatorInterface */ - private CacheTagInvalidator $cacheTagInvalidator; + private CacheTagInvalidatorInterface $cacheTagInvalidator; /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) : self { $instance = new self($configuration, $plugin_id, $plugin_definition); - $instance->mainMenuManager = $container->get('helfi_navigation.menu_manager'); + $instance->mainMenuManager = $container->get(MainMenuManager::class); $instance->cacheTagInvalidator = $container->get('helfi_api_base.cache_tag_invalidator'); return $instance; } diff --git a/src/Plugin/rest/resource/GlobalMobileMenu.php b/src/Plugin/rest/resource/GlobalMobileMenu.php index 1c6c83e..f20f32c 100644 --- a/src/Plugin/rest/resource/GlobalMobileMenu.php +++ b/src/Plugin/rest/resource/GlobalMobileMenu.php @@ -69,9 +69,9 @@ public static function create(ContainerInterface $container, array $configuratio $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); $instance->configFactory = $container->get('config.factory'); $instance->languageManager = $container->get('language_manager'); - $instance->apiManager = $container->get('helfi_navigation.api_manager'); + $instance->apiManager = $container->get(ApiManager::class); $instance->environmentResolver = $container->get('helfi_api_base.environment_resolver'); - $instance->mainMenuManager = $container->get('helfi_navigation.menu_manager'); + $instance->mainMenuManager = $container->get(MainMenuManager::class); return $instance; } diff --git a/tests/src/Kernel/MenuSyncTest.php b/tests/src/Kernel/MenuSyncTest.php index 1e9840b..59f5c0a 100644 --- a/tests/src/Kernel/MenuSyncTest.php +++ b/tests/src/Kernel/MenuSyncTest.php @@ -39,7 +39,7 @@ private function getQueue() : QueueInterface { * The menu manager service. */ private function getMenuManager() : MainMenuManager { - return $this->container->get('helfi_navigation.menu_manager'); + return $this->container->get(MainMenuManager::class); } /** @@ -144,7 +144,7 @@ public function testConfigTranslation(string $langcode) : void { ], ]); })); - $this->container->set('helfi_navigation.api_manager', $apiManager); + $this->container->set(ApiManager::class, $apiManager); $this->getMenuManager()->sync($langcode); } @@ -172,7 +172,7 @@ public function testEmptyStatus() : void { $apiManager->expects($this->once()) ->method('update') ->willReturn(new ApiResponse([])); - $this->container->set('helfi_navigation.api_manager', $apiManager); + $this->container->set(ApiManager::class, $apiManager); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Failed to parse entity published state.'); diff --git a/tests/src/Kernel/MenuTreeBuilderTestBase.php b/tests/src/Kernel/MenuTreeBuilderTestBase.php index 857f076..d85ed08 100644 --- a/tests/src/Kernel/MenuTreeBuilderTestBase.php +++ b/tests/src/Kernel/MenuTreeBuilderTestBase.php @@ -52,7 +52,7 @@ protected function setUp(): void { * The menu tree builder service. */ protected function getMenuTreeBuilder() : MenuTreeBuilder { - return $this->container->get('helfi_navigation.menu_tree_builder'); + return $this->container->get(MenuTreeBuilder::class); } /** diff --git a/tests/src/Unit/Plugin/QueueWorker/MenuQueueTest.php b/tests/src/Unit/Plugin/QueueWorker/MenuQueueTest.php index 97cc849..2cc9615 100644 --- a/tests/src/Unit/Plugin/QueueWorker/MenuQueueTest.php +++ b/tests/src/Unit/Plugin/QueueWorker/MenuQueueTest.php @@ -6,6 +6,8 @@ use Drupal\helfi_api_base\Azure\PubSub\PubSubManagerInterface; use Drupal\helfi_api_base\Cache\CacheTagInvalidator; +use Drupal\helfi_api_base\Cache\CacheTagInvalidatorInterface; +use Drupal\helfi_api_base\Environment\Project; use Drupal\helfi_navigation\MainMenuManager; use Drupal\helfi_navigation\Plugin\QueueWorker\MenuQueue; use Drupal\Tests\UnitTestCase; @@ -15,7 +17,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; /** - * @coversDefaultClass \Drupal\helfi_navigation\Plugin\QueueWorker\MenuQueue + * Tests menu queue worker. + * * @group helfi_navigation */ class MenuQueueTest extends UnitTestCase { @@ -33,7 +36,7 @@ class MenuQueueTest extends UnitTestCase { */ public function getSut(ObjectProphecy $menuManager) : MenuQueue { $container = new ContainerBuilder(); - $container->set('helfi_navigation.menu_manager', $menuManager->reveal()); + $container->set(MainMenuManager::class, $menuManager->reveal()); $pubSubManager = $this->prophesize(PubSubManagerInterface::class); $pubSubManager->sendMessage(Argument::any())->willReturn($pubSubManager->reveal()); $cacheTagInvalidator = new CacheTagInvalidator($pubSubManager->reveal()); @@ -42,8 +45,7 @@ public function getSut(ObjectProphecy $menuManager) : MenuQueue { } /** - * @covers ::create - * @covers ::processItem + * Tests invalid data. */ public function testInvalidData() : void { // Make sure sync is not called for invalid data. @@ -54,8 +56,7 @@ public function testInvalidData() : void { } /** - * @covers ::create - * @covers ::processItem + * Tests failed sync. */ public function testQueueException() : void { // Make sure queue doesn't die if ::sync() throws an exception. @@ -67,4 +68,30 @@ public function testQueueException() : void { ->processItem(['menu' => 'main', 'language' => 'fi']); } + /** + * Tests cache invalidation. + */ + public function testCacheInvalidator() : void { + $container = new ContainerBuilder(); + $menuManager = $this->prophesize(MainMenuManager::class); + $menuManager->sync('fi') + ->shouldBeCalled(); + $container->set(MainMenuManager::class, $menuManager->reveal()); + $cacheTagInvalidator = $this->prophesize(CacheTagInvalidatorInterface::class); + $cacheTagInvalidator->invalidateTags([ + 'config:system.menu.main', + 'external_menu_block:main', + 'external_menu:main:fi', + ]) + ->shouldBeCalled(); + $cacheTagInvalidator->invalidateTags([ + 'config:rest.resource.helfi_global_menu_collection', + ], [Project::ETUSIVU]) + ->shouldBeCalled(); + + $container->set('helfi_api_base.cache_tag_invalidator', $cacheTagInvalidator->reveal()); + $sut = MenuQueue::create($container, [], '', []); + $sut->processItem(['menu' => 'main', 'language' => 'fi']); + } + }