diff --git a/modules/social_features/social_group/social_group.services.yml b/modules/social_features/social_group/social_group.services.yml index df5da7faf0a..81461752ba5 100644 --- a/modules/social_features/social_group/social_group.services.yml +++ b/modules/social_features/social_group/social_group.services.yml @@ -53,5 +53,4 @@ services: social_group.current_group: class: Drupal\social_group\CurrentGroupService arguments: - - '@entity_type.manager' - - '@group.group_route_context' + - '@context.repository' diff --git a/modules/social_features/social_group/src/CurrentGroupService.php b/modules/social_features/social_group/src/CurrentGroupService.php index 45110570478..8a3ccbcb466 100644 --- a/modules/social_features/social_group/src/CurrentGroupService.php +++ b/modules/social_features/social_group/src/CurrentGroupService.php @@ -2,8 +2,7 @@ namespace Drupal\social_group; -use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\Core\Plugin\Context\ContextProviderInterface; +use Drupal\Core\Plugin\Context\ContextRepositoryInterface; use Drupal\group\Entity\GroupInterface; /** @@ -14,33 +13,22 @@ class CurrentGroupService { /** - * The entity type manager. + * The context repository interface. * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface + * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface */ - private EntityTypeManagerInterface $entityTypeManager; - - /** - * The group route context. - * - * @var \Drupal\Core\Plugin\Context\ContextProviderInterface - */ - private ContextProviderInterface $groupRouteContext; + private ContextRepositoryInterface $contextRepository; /** * Constructor. * - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. - * @param \Drupal\Core\Plugin\Context\ContextProviderInterface $group_route_context - * The group route context. + * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository + * The context repository. */ public function __construct( - EntityTypeManagerInterface $entity_type_manager, - ContextProviderInterface $group_route_context, + ContextRepositoryInterface $context_repository, ) { - $this->entityTypeManager = $entity_type_manager; - $this->groupRouteContext = $group_route_context; + $this->contextRepository = $context_repository; } /** @@ -48,29 +36,17 @@ public function __construct( * * @return \Drupal\group\Entity\GroupInterface|null * The current group or NULL. - * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function fromRunTimeContexts(): ?GroupInterface { - $runtime_context = $this->groupRouteContext->getRuntimeContexts([]); - if (isset($runtime_context['group']) === FALSE) { - return NULL; - } + $group_runtime_context = $this->contextRepository->getRuntimeContexts(['@group.group_route_context:group']); - $group = $runtime_context['group']->getContextData()->getValue(); - if ($group instanceof GroupInterface) { - return $group; - } - - if (is_int($group) === TRUE) { - /** @var \Drupal\group\Entity\GroupInterface $loadedGroup */ - $loadedGroup = $this->entityTypeManager - ->getStorage('group')->load($group); - return $loadedGroup; + $group = $group_runtime_context['@group.group_route_context:group']->getContextData()->getValue(); + if ($group === NULL) { + return NULL; } - return NULL; + assert($group instanceof GroupInterface, "The group context resolver returned a context value that is not a GroupInterface instance which violates the services contract."); + return $group; } } diff --git a/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php b/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php index 151be5c59a7..6a909eeef87 100644 --- a/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php +++ b/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php @@ -2,10 +2,8 @@ namespace Drupal\Tests\social_group\Unit; -use Drupal\Core\Entity\EntityStorageInterface; -use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Plugin\Context\ContextInterface; -use Drupal\Core\Plugin\Context\ContextProviderInterface; +use Drupal\Core\Plugin\Context\ContextRepositoryInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\group\Entity\GroupInterface; use Drupal\social_group\CurrentGroupService; @@ -20,142 +18,74 @@ class CurrentGroupServiceTest extends UnitTestCase { /** - * The mocked EntityTypeManagerInterface. + * The mocked context repository interface. * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject + * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject */ - private EntityTypeManagerInterface|MockObject $entityTypeManager; - - /** - * The mocked ContextProviderInterface. - * - * @var \Drupal\Core\Plugin\Context\ContextProviderInterface|\PHPUnit\Framework\MockObject\MockObject - */ - private ContextProviderInterface|MockObject $groupRouteContext; + protected ContextRepositoryInterface|MockObject $contextRepository; /** * The service under test. * * @var \Drupal\social_group\CurrentGroupService */ - private CurrentGroupService $currentGroupService; + protected CurrentGroupService $currentGroupService; /** - * Set up the test case. + * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); + $this->contextRepository = $this->createMock(ContextRepositoryInterface::class); - $this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class); - $this->groupRouteContext = $this->createMock(ContextProviderInterface::class); - - $this->currentGroupService = new CurrentGroupService( - $this->entityTypeManager, - $this->groupRouteContext - ); - } - - /** - * Helper function to create a mock context. - * - * @param mixed $value - * The value returned by typeDataInterface. - * - * @return \Drupal\Core\Plugin\Context\ContextInterface - * The updated mock context. - */ - private function createContextWithValue(mixed $value): ContextInterface { - $typeDataInterface = $this->createMock(TypedDataInterface::class); - $typeDataInterface->expects($this->once()) - ->method('getValue') - ->willReturn($value); - - $context = $this->createMock(ContextInterface::class); - $context->expects($this->once()) - ->method('getContextData') - ->willReturn($typeDataInterface); - - return $context; - } - - /** - * Test that fromRunTimeContexts() returns NULL when no group context is set. - */ - public function testFromRunTimeContextsNoGroupContext(): void { - $this->groupRouteContext - ->expects($this->once()) - ->method('getRuntimeContexts') - ->willReturn([]); - - $group = $this->currentGroupService->fromRunTimeContexts(); - - $this->assertNull($group, 'No group context should return NULL.'); + $this->currentGroupService = new CurrentGroupService($this->contextRepository); } /** - * Test that fromRunTimeContexts() returns a GroupInterface when available. + * Test that fromRunTimeContexts() returns a Group when a group is present. */ public function testFromRunTimeContextsWithGroup(): void { $group = $this->createMock(GroupInterface::class); - $context = $this->createContextWithValue($group); - - $this->groupRouteContext - ->expects($this->once()) - ->method('getRuntimeContexts') - ->willReturn(['group' => $context]); + $this->mockContext($group); + // Call the method and assert the group is returned. $result = $this->currentGroupService->fromRunTimeContexts(); - - $this->assertSame($group, $result, 'Group should be returned when found in context.'); + $this->assertSame($group, $result, 'Group context should return a GroupInterface instance.'); } /** - * Test that fromRunTimeContexts() loads a group by ID. + * Test that fromRunTimeContexts() returns NULL when group is not present. */ - public function testFromRunTimeContextsWithGroupId(): void { - $groupId = 1; - $group = $this->createMock(GroupInterface::class); - - $context = $this->createContextWithValue($groupId); - - $this->groupRouteContext - ->expects($this->once()) - ->method('getRuntimeContexts') - ->willReturn(['group' => $context]); - - $storage = $this->createMock(EntityStorageInterface::class); - $this->entityTypeManager - ->expects($this->once()) - ->method('getStorage') - ->with('group') - ->willReturn($storage); - - $storage - ->expects($this->once()) - ->method('load') - ->with($groupId) - ->willReturn($group); + public function testFromRunTimeContextsWithoutGroup(): void { + $this->mockContext(NULL); + // Call the method and assert NULL is returned. $result = $this->currentGroupService->fromRunTimeContexts(); - - $this->assertSame($group, $result, 'Group should be loaded by ID and returned.'); + $this->assertNull($result, 'Group context should return NULL.'); } /** - * Test that fromRunTimeContexts() returns NULL when no valid group found. + * Mock the context. + * + * @param \PHPUnit\Framework\MockObject\MockObject|\Drupal\group\Entity\GroupInterface|null $group + * The mocked group or NULL. */ - public function testFromRunTimeContextsInvalidGroup(): void { - $invalidValue = 'invalid'; - $context = $this->createContextWithValue($invalidValue); + private function mockContext(MockObject|GroupInterface|NULL $group): void { + $typedData = $this->createMock(TypedDataInterface::class); + $typedData->expects($this->once()) + ->method('getValue') + ->willReturn($group); + + $context = $this->createMock(ContextInterface::class); + $context->expects($this->once()) + ->method('getContextData') + ->willReturn($typedData); - $this->groupRouteContext + $this->contextRepository ->expects($this->once()) ->method('getRuntimeContexts') - ->willReturn(['group' => $context]); - - $result = $this->currentGroupService->fromRunTimeContexts(); - - $this->assertNull($result, 'Invalid group value should return NULL.'); + ->with(['@group.group_route_context:group']) + ->willReturn(['@group.group_route_context:group' => $context]); } } diff --git a/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoBlock.php b/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoBlock.php index 304fb475cf7..e6f1a07676c 100644 --- a/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoBlock.php +++ b/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoBlock.php @@ -25,8 +25,8 @@ class PostPhotoBlock extends PostBlock { */ public function __construct( array $configuration, - $plugin_id, - $plugin_definition, + $plugin_id, + $plugin_definition, EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user, FormBuilderInterface $form_builder, diff --git a/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoProfileBlock.php b/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoProfileBlock.php index 2b65bf6b483..be0d3a57f2b 100644 --- a/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoProfileBlock.php +++ b/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoProfileBlock.php @@ -25,8 +25,8 @@ class PostPhotoProfileBlock extends PostProfileBlock { */ public function __construct( array $configuration, - $plugin_id, - $plugin_definition, + $plugin_id, + $plugin_definition, EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user, FormBuilderInterface $form_builder, diff --git a/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php b/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php index 2672c89a352..fe748b91b07 100644 --- a/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php +++ b/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php @@ -5,7 +5,6 @@ use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountProxyInterface; -use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\hux\Attribute\Alter; use Drupal\social_post\Service\SocialPostHelperInterface; @@ -59,16 +58,12 @@ public function __construct( */ #[Alter('form_post_form')] public function formPostFormAlter(array &$form, FormStateInterface $form_state): void { - $content = $this->socialPostHelper->buildCurrentUserImage(); $form_object = $form_state->getFormObject(); + assert($form_object instanceof ContentEntityForm, 'Expected $form_object to be an instance of ContentEntityForm.'); - if ($form_object instanceof ContentEntityForm === FALSE) { - return; - } - - if ($form_object->getEntity()->isNew() - && $content !== NULL) { - $form['current_user_image'] = $content; + if ($this->socialPostHelper->buildCurrentUserImage() !== NULL + && $form_object->getEntity()->isNew()) { + $form['current_user_image'] = $this->socialPostHelper->buildCurrentUserImage(); } // Reset title display. @@ -77,42 +72,24 @@ public function formPostFormAlter(array &$form, FormStateInterface $form_state): // Set submit button caption to Post instead of Save. $form['actions']['submit']['#value'] = t('Post', [], ['context' => 'Post button']); - if (empty($form['field_post']) || empty($form['field_post']['widget'][0])) { - return; - } - // Default value. - $form = $this->setFormTitleAndPlaceholder($form, t('Say something to the Community')); + $titleAndPlaceholderValue = t('Say something to the Community'); if ($form_state->get('currentGroup') !== NULL) { - $form = $this->setFormTitleAndPlaceholder($form, t('Say something to the group')); + $titleAndPlaceholderValue = t('Say something to the group'); } - // $user_profile = $this->routeMatch->getParameter('user'); $user_profile = $form_state->get('recipientUser'); if ($user_profile !== NULL && $user_profile->id() !== $this->currentUser->id()) { - $form = $this->setFormTitleAndPlaceholder($form, t('Leave a message to @name', [ + $titleAndPlaceholderValue = t('Leave a message to @name', [ '@name' => $user_profile->getDisplayName(), - ])); + ]); } - } - /** - * Set form title and placeholder value. - * - * @param array $form - * The drupal form. - * @param \Drupal\Core\StringTranslation\TranslatableMarkup $displayedValue - * The translatable markup value to display. - * - * @return array - * The updated form title and placeholder. - */ - private function setFormTitleAndPlaceholder(array $form, TranslatableMarkup $displayedValue): array { - $form['field_post']['widget'][0]['#title'] = $displayedValue; - $form['field_post']['widget'][0]['#placeholder'] = $displayedValue; - return $form; + // Set the title and placeholder value. + $form['field_post']['widget'][0]['#title'] = $titleAndPlaceholderValue; + $form['field_post']['widget'][0]['#placeholder'] = $titleAndPlaceholderValue; } } diff --git a/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php b/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php index f93f7123539..fb3fd1498b4 100644 --- a/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php +++ b/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php @@ -50,7 +50,6 @@ class SocialPostFormHooksTest extends UnitTestCase { */ protected SocialPostFormHooks $socialPostFormHooks; - /** * The drupal form. * @@ -59,7 +58,7 @@ class SocialPostFormHooksTest extends UnitTestCase { protected array $form = []; /** - * Setup the test case. + * Set up the test case. */ protected function setUp(): void { parent::setUp(); @@ -73,7 +72,6 @@ protected function setUp(): void { $this->currentUser ); - // Create a mock TranslationInterface. $translation = $this->createMock(TranslationInterface::class); $translation->method('translate') ->willReturnCallback(function ($string, array $args = [], array $options = []) { @@ -81,7 +79,6 @@ protected function setUp(): void { return new TranslatableMarkup($string, $args, $options); }); - // Set up the container with the string_translation service. $container = new ContainerBuilder(); $container->set('string_translation', $translation); \Drupal::setContainer($container); @@ -101,16 +98,11 @@ public function testFormPostFormAlterWithNewPostAndImage(): void { $this->socialPostFormHooks->formPostFormAlter($this->form, $this->formState); - // Check if the user image is added to the form. $this->assertEquals($currentUserImage, $this->form['current_user_image']); - - // Check if submit button caption is set to "Post". $this->assertEquals( new TranslatableMarkup('Post', [], ['context' => 'Post button']), $this->form['actions']['submit']['#value'] ); - - // Check if the title is set correctly. $this->assertEquals( new TranslatableMarkup('Say something to the Community'), $this->form['field_post']['widget'][0]['#title'] @@ -133,16 +125,11 @@ public function testFormPostFormAlterWithCurrentGroup(): void { $this->socialPostFormHooks->formPostFormAlter($this->form, $this->formState); - // Assert that the current user image is set. $this->assertEquals($currentUserImage, $this->form['current_user_image']); - - // Assert that the submit button value is set to "Post". $this->assertEquals( new TranslatableMarkup('Post', [], ['context' => 'Post button']), $this->form['actions']['submit']['#value'] ); - - // Assert the title placeholder value. $this->assertEquals( new TranslatableMarkup('Say something to the group'), $this->form['field_post']['widget'][0]['#title'] @@ -180,19 +167,13 @@ public function testFormPostFormAlterWithRecipientUser(): void { ->method('id') ->willReturn(1); - // Call the form alter hook. $this->socialPostFormHooks->formPostFormAlter($this->form, $this->formState); - // Assert that the current user image is set. $this->assertEquals($currentUserImage, $this->form['current_user_image']); - - // Assert that the submit button value is set to "Post". $this->assertEquals( new TranslatableMarkup('Post', [], ['context' => 'Post button']), $this->form['actions']['submit']['#value'] ); - - // Assert title and placeholder value. $this->assertEquals( new TranslatableMarkup('Leave a message to @name', ['@name' => 'John Doe']), $this->form['field_post']['widget'][0]['#title'] @@ -210,9 +191,8 @@ public function testFormPostFormAlterWithRecipientUser(): void { * The mocked user image. */ private function mockUserImage(): array { - // Mock the SocialPostHelper to return user image. $currentUserImage = ['#markup' => 'User Image']; - $this->socialPostHelper->expects($this->once()) + $this->socialPostHelper ->method('buildCurrentUserImage') ->willReturn($currentUserImage); return $currentUserImage; @@ -221,7 +201,7 @@ private function mockUserImage(): array { /** * Mock content entity form. */ - public function mockContentEntityForm(): void { + private function mockContentEntityForm(): void { $contentEntityForm = $this->createMock(ContentEntityForm::class); $entity = $this->createMock(ContentEntityInterface::class); $entity->expects($this->once())