From f600f904db1d9b17be5e36c3c9f1798720019c10 Mon Sep 17 00:00:00 2001 From: Denis Kolmerschlag Date: Wed, 16 Oct 2024 10:15:39 +0200 Subject: [PATCH 1/6] Replacing social_post_form_post_form_alter with hux approach. --- .../social_group/social_group.services.yml | 6 + .../social_group/src/CurrentGroupService.php | 76 ++++++++++++ .../src/Plugin/Block/PostPhotoBlock.php | 14 ++- .../src/Plugin/Block/PostPhotoGroupBlock.php | 10 +- .../Plugin/Block/PostPhotoProfileBlock.php | 12 +- .../social_post/social_post.module | 39 ------ .../social_post/social_post.services.yml | 11 ++ .../src/Hooks/SocialPostFormHooks.php | 117 ++++++++++++++++++ .../src/Plugin/Block/PostBlock.php | 50 ++++++-- .../src/Plugin/Block/PostGroupBlock.php | 10 +- .../src/Plugin/Block/PostProfileBlock.php | 49 ++------ phpstan-baseline.neon | 25 ---- 12 files changed, 294 insertions(+), 125 deletions(-) create mode 100644 modules/social_features/social_group/src/CurrentGroupService.php create mode 100644 modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php diff --git a/modules/social_features/social_group/social_group.services.yml b/modules/social_features/social_group/social_group.services.yml index be9610d19c8..72b9a3f2161 100644 --- a/modules/social_features/social_group/social_group.services.yml +++ b/modules/social_features/social_group/social_group.services.yml @@ -49,3 +49,9 @@ services: arguments: [] tags: - { name: cache.context } + + social_group.current_group: + class: Drupal\social_group\CurrentGroupService + arguments: + - '@entity_type.manager' + - '@group.group_route_context' diff --git a/modules/social_features/social_group/src/CurrentGroupService.php b/modules/social_features/social_group/src/CurrentGroupService.php new file mode 100644 index 00000000000..45110570478 --- /dev/null +++ b/modules/social_features/social_group/src/CurrentGroupService.php @@ -0,0 +1,76 @@ +entityTypeManager = $entity_type_manager; + $this->groupRouteContext = $group_route_context; + } + + /** + * Get group from runtime contexts. + * + * @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['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; + } + + return NULL; + } + +} 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 8fa39f9a56f..304fb475cf7 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 @@ -5,7 +5,9 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Session\AccountProxyInterface; +use Drupal\social_group\CurrentGroupService; use Drupal\social_post\Plugin\Block\PostBlock; /** @@ -23,12 +25,14 @@ 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, - ModuleHandlerInterface $module_handler + ModuleHandlerInterface $module_handler, + CurrentRouteMatch $route_match, + CurrentGroupService $current_group_service, ) { parent::__construct( $configuration, @@ -37,7 +41,9 @@ public function __construct( $entity_type_manager, $current_user, $form_builder, - $module_handler + $module_handler, + $route_match, + $current_group_service, ); // Override the bundle type. diff --git a/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoGroupBlock.php b/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoGroupBlock.php index a20aeabce57..d6b7e02bc94 100644 --- a/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoGroupBlock.php +++ b/modules/social_features/social_post/modules/social_post_photo/src/Plugin/Block/PostPhotoGroupBlock.php @@ -5,7 +5,9 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Session\AccountProxyInterface; +use Drupal\social_group\CurrentGroupService; use Drupal\social_post\Plugin\Block\PostGroupBlock; /** @@ -28,7 +30,9 @@ public function __construct( EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user, FormBuilderInterface $form_builder, - ModuleHandlerInterface $module_handler + ModuleHandlerInterface $module_handler, + CurrentRouteMatch $route_match, + CurrentGroupService $current_group_service, ) { parent::__construct( $configuration, @@ -37,7 +41,9 @@ public function __construct( $entity_type_manager, $current_user, $form_builder, - $module_handler + $module_handler, + $route_match, + $current_group_service, ); // Override the bundle type. 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 67796d80042..2b65bf6b483 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 @@ -5,7 +5,9 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Session\AccountProxyInterface; +use Drupal\social_group\CurrentGroupService; use Drupal\social_post\Plugin\Block\PostProfileBlock; /** @@ -23,13 +25,14 @@ 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, ModuleHandlerInterface $module_handler, - $account + CurrentRouteMatch $route_match, + CurrentGroupService $current_group_service, ) { parent::__construct( $configuration, @@ -39,7 +42,8 @@ public function __construct( $current_user, $form_builder, $module_handler, - $account + $route_match, + $current_group_service, ); // Override the bundle type. diff --git a/modules/social_features/social_post/social_post.module b/modules/social_features/social_post/social_post.module index 2e9c2d1dacd..293b3ae7484 100644 --- a/modules/social_features/social_post/social_post.module +++ b/modules/social_features/social_post/social_post.module @@ -15,45 +15,6 @@ use Drupal\group\Entity\GroupInterface; use Drupal\group\Entity\Group; use Drupal\user\UserInterface; -/** - * Implements hook_form_FORM_ID_alter(). - */ -function social_post_form_post_form_alter(&$form, FormStateInterface $form_state, $form_id) { - - if ( - $form_state->getFormObject()->getEntity()->isNew() && - ($content = \Drupal::service('social_post.helper')->buildCurrentUserImage()) - ) { - $form['current_user_image'] = $content; - } - - // Reset title display. - $form['field_post']['widget'][0]['#title_display'] = ""; - - // 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])) { - // For posting on the stream on the group stream. - if (!empty(_social_group_get_current_group())) { - $form['field_post']['widget'][0]['#placeholder'] = t('Say something to the group'); - $form['field_post']['widget'][0]['#title'] = t('Say something to the group'); - } - // For the post on a users profile. - elseif (!empty(\Drupal::routeMatch()->getParameter('user')) && \Drupal::routeMatch()->getParameter('user')->id() != \Drupal::currentUser()->id()) { - $user_profile = \Drupal::routeMatch()->getParameter('user'); - $name = $user_profile->getDisplayName(); - $form['field_post']['widget'][0]['#placeholder'] = t('Leave a message to @name', ['@name' => $name]); - $form['field_post']['widget'][0]['#title'] = t('Leave a message to @name', ['@name' => $name]); - } - else { - $title = t('Say something to the Community'); - $form['field_post']['widget'][0]['#title'] = $title; - $form['field_post']['widget'][0]['#placeholder'] = $title; - } - } -} - /** * Implements hook_form_FORM_ID_alter(). * diff --git a/modules/social_features/social_post/social_post.services.yml b/modules/social_features/social_post/social_post.services.yml index b85d22d9036..b0141566756 100644 --- a/modules/social_features/social_post/social_post.services.yml +++ b/modules/social_features/social_post/social_post.services.yml @@ -11,3 +11,14 @@ services: social_post.helper: class: Drupal\social_post\Service\SocialPostHelper arguments: ['@entity_type.manager', '@current_user'] + + + #hooks replacement + social_post.form.hooks: + class: Drupal\social_post\Hooks\SocialPostFormHooks + arguments: + - '@social_post.helper' + - '@current_route_match' + - '@current_user' + tags: + - { name: hooks } diff --git a/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php b/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php new file mode 100644 index 00000000000..59d99604c6e --- /dev/null +++ b/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php @@ -0,0 +1,117 @@ +socialPostHelper = $social_post_helper; + $this->currentUser = $current_user; + } + + /** + * From alter hook: replacement of social_post_form_post_form_alter. + * + * The method definition contains all standard parameters defined by the + * definition of the hook. + * + * @param array $form + * The drupal form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + */ + #[Alter('form_post_form')] + public function formPostFormAlter(array &$form, FormStateInterface $form_state): void { + $content = $this->socialPostHelper->buildCurrentUserImage(); + + if ($form_state->getFormObject() instanceof ContentEntityForm === FALSE) { + return; + } + + if ($form_state->getFormObject()->getEntity()->isNew() + && $content !== NULL) { + $form['current_user_image'] = $content; + } + + // Reset title display. + $form['field_post']['widget'][0]['#title_display'] = ''; + + // 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')); + + if ($form_state->get('currentGroup') !== NULL) { + $form = $this->setFormTitleAndPlaceholder($form, 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()) { + $this->setFormTitleAndPlaceholder($form, 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; + } + +} diff --git a/modules/social_features/social_post/src/Plugin/Block/PostBlock.php b/modules/social_features/social_post/src/Plugin/Block/PostBlock.php index a72ee60e329..fda3b00c0e2 100644 --- a/modules/social_features/social_post/src/Plugin/Block/PostBlock.php +++ b/modules/social_features/social_post/src/Plugin/Block/PostBlock.php @@ -8,8 +8,10 @@ use Drupal\Core\Form\FormBuilderInterface; use Drupal\Core\Form\FormState; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountProxyInterface; +use Drupal\social_group\CurrentGroupService; use Drupal\user\EntityOwnerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -28,49 +30,63 @@ class PostBlock extends BlockBase implements ContainerFactoryPluginInterface { * * @var string */ - public $entityType; + public string $entityType; /** * The bundle. * * @var string */ - public $bundle; + public string $bundle; /** * The form display. * * @var string */ - public $formDisplay; + public string $formDisplay; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ - protected $entityTypeManager; + protected EntityTypeManagerInterface $entityTypeManager; /** * The current user. * * @var \Drupal\Core\Session\AccountProxyInterface */ - protected $currentUser; + protected AccountProxyInterface $currentUser; /** * The form builder. * * @var \Drupal\Core\Form\FormBuilderInterface */ - protected $formBuilder; + protected FormBuilderInterface $formBuilder; /** * The module handler. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ - protected $moduleHandler; + protected ModuleHandlerInterface $moduleHandler; + + /** + * The current rouge match. + * + * @var \Drupal\Core\Routing\CurrentRouteMatch + */ + protected CurrentRouteMatch $routeMatch; + + /** + * The current group service. + * + * @var \Drupal\social_group\CurrentGroupService + */ + protected CurrentGroupService $currentGroupService; /** * PostBlock constructor. @@ -92,6 +108,10 @@ class PostBlock extends BlockBase implements ContainerFactoryPluginInterface { * The form builder. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. + * @param \Drupal\Core\Routing\CurrentRouteMatch $route_match + * The current route match. + * @param \Drupal\social_group\CurrentGroupService $current_group_service + * The current group service. */ public function __construct( array $configuration, @@ -100,7 +120,9 @@ public function __construct( EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user, FormBuilderInterface $form_builder, - ModuleHandlerInterface $module_handler + ModuleHandlerInterface $module_handler, + CurrentRouteMatch $route_match, + CurrentGroupService $current_group_service, ) { parent::__construct($configuration, $plugin_id, $plugin_definition); @@ -111,6 +133,8 @@ public function __construct( $this->currentUser = $current_user; $this->formBuilder = $form_builder; $this->moduleHandler = $module_handler; + $this->routeMatch = $route_match; + $this->currentGroupService = $current_group_service; if ($module_handler->moduleExists('social_post_photo')) { $this->bundle = 'photo'; @@ -128,7 +152,9 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('entity_type.manager'), $container->get('current_user'), $container->get('form_builder'), - $container->get('module_handler') + $container->get('module_handler'), + $container->get('current_route_match'), + $container->get('social_group.current_group'), ); } @@ -170,6 +196,12 @@ public function build() { $form_state = (new FormState())->setFormState([]); $form_state->set('form_display', $display); + + // Add the current group from the runtime context. + $form_state->set('currentGroup', $this->currentGroupService->fromRunTimeContexts()); + // Add recipient user from the url. + $form_state->set('recipientUser', $this->routeMatch->getParameter('user')); + return $this->formBuilder->buildForm($form_object, $form_state); } diff --git a/modules/social_features/social_post/src/Plugin/Block/PostGroupBlock.php b/modules/social_features/social_post/src/Plugin/Block/PostGroupBlock.php index 4e87d085cad..678658bb0c1 100644 --- a/modules/social_features/social_post/src/Plugin/Block/PostGroupBlock.php +++ b/modules/social_features/social_post/src/Plugin/Block/PostGroupBlock.php @@ -5,10 +5,12 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Session\AccountProxyInterface; use Drupal\group\Entity\GroupInterface; +use Drupal\social_group\CurrentGroupService; /** * Provides a 'PostGroupBlock' block. @@ -30,7 +32,9 @@ public function __construct( EntityTypeManagerInterface $entity_type_manager, AccountProxyInterface $current_user, FormBuilderInterface $form_builder, - ModuleHandlerInterface $module_handler + ModuleHandlerInterface $module_handler, + CurrentRouteMatch $route_match, + CurrentGroupService $current_group_service, ) { parent::__construct( $configuration, @@ -39,7 +43,9 @@ public function __construct( $entity_type_manager, $current_user, $form_builder, - $module_handler + $module_handler, + $route_match, + $current_group_service, ); $this->entityType = 'post'; diff --git a/modules/social_features/social_post/src/Plugin/Block/PostProfileBlock.php b/modules/social_features/social_post/src/Plugin/Block/PostProfileBlock.php index 1c264422267..c685c538b77 100644 --- a/modules/social_features/social_post/src/Plugin/Block/PostProfileBlock.php +++ b/modules/social_features/social_post/src/Plugin/Block/PostProfileBlock.php @@ -5,8 +5,9 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormBuilderInterface; +use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Session\AccountProxyInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\social_group\CurrentGroupService; /** * Provides a 'PostProfileBlock' block. @@ -19,27 +20,7 @@ class PostProfileBlock extends PostBlock { /** - * PostProfileBlock constructor. - * - * @param array $configuration - * The plugin configuration, i.e. an array with configuration values keyed - * by configuration option name. The special key 'context' may be used to - * initialize the defined contexts by setting it to an array of context - * values keyed by context names. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. - * @param \Drupal\Core\Session\AccountProxyInterface $current_user - * The current user. - * @param \Drupal\Core\Form\FormBuilderInterface $form_builder - * The form builder. - * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler - * The module handler. - * @param mixed $account - * The user object or user ID. + * {@inheritdoc} */ public function __construct( array $configuration, @@ -49,7 +30,8 @@ public function __construct( AccountProxyInterface $current_user, FormBuilderInterface $form_builder, ModuleHandlerInterface $module_handler, - $account + CurrentRouteMatch $route_match, + CurrentGroupService $current_group_service, ) { parent::__construct( $configuration, @@ -58,7 +40,9 @@ public function __construct( $entity_type_manager, $current_user, $form_builder, - $module_handler + $module_handler, + $route_match, + $current_group_service, ); $this->entityType = 'post'; @@ -67,26 +51,11 @@ public function __construct( // Check if current user is the same as the profile. // In this case use the default form display. + $account = $this->routeMatch->getParameter('user'); $uid = $this->currentUser->id(); if (isset($account) && ($account === $uid || (is_object($account) && $uid === $account->id()))) { $this->formDisplay = 'default'; } } - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('entity_type.manager'), - $container->get('current_user'), - $container->get('form_builder'), - $container->get('module_handler'), - $container->get('current_route_match')->getParameter('user') - ); - } - } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0851ad545fb..c281731f936 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -9714,11 +9714,6 @@ parameters: count: 1 path: modules/social_features/social_post/social_post.install - - - message: "#^Call to an undefined method Drupal\\\\Core\\\\Form\\\\FormInterface\\:\\:getEntity\\(\\)\\.$#" - count: 1 - path: modules/social_features/social_post/social_post.module - - message: "#^Function _social_post_comment_post_comment_form_submit\\(\\) has no return type specified\\.$#" count: 1 @@ -9749,21 +9744,6 @@ parameters: count: 1 path: modules/social_features/social_post/social_post.module - - - message: "#^Function social_post_form_post_form_alter\\(\\) has no return type specified\\.$#" - count: 1 - path: modules/social_features/social_post/social_post.module - - - - message: "#^Function social_post_form_post_form_alter\\(\\) has parameter \\$form with no type specified\\.$#" - count: 1 - path: modules/social_features/social_post/social_post.module - - - - message: "#^Function social_post_form_post_form_alter\\(\\) has parameter \\$form_id with no type specified\\.$#" - count: 1 - path: modules/social_features/social_post/social_post.module - - message: "#^Function social_post_preprocess_activity\\(\\) has no return type specified\\.$#" count: 1 @@ -9829,11 +9809,6 @@ parameters: count: 1 path: modules/social_features/social_post/social_post.module - - - message: "#^Not allowed to call private function _social_group_get_current_group from module social_post\\.$#" - count: 1 - path: modules/social_features/social_post/social_post.module - - message: "#^Cannot call method fetchAll\\(\\) on Drupal\\\\Core\\\\Database\\\\StatementInterface\\|null\\.$#" count: 1 From 74d55627c0c773275014400383e947de82f25280 Mon Sep 17 00:00:00 2001 From: Denis Kolmerschlag Date: Wed, 16 Oct 2024 16:14:59 +0200 Subject: [PATCH 2/6] Fix social_post.services.yml. --- modules/social_features/social_post/social_post.services.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/social_features/social_post/social_post.services.yml b/modules/social_features/social_post/social_post.services.yml index b0141566756..5c2fa3ee597 100644 --- a/modules/social_features/social_post/social_post.services.yml +++ b/modules/social_features/social_post/social_post.services.yml @@ -12,13 +12,11 @@ services: class: Drupal\social_post\Service\SocialPostHelper arguments: ['@entity_type.manager', '@current_user'] - #hooks replacement social_post.form.hooks: class: Drupal\social_post\Hooks\SocialPostFormHooks arguments: - '@social_post.helper' - - '@current_route_match' - '@current_user' tags: - { name: hooks } From f994fc265395cf103abf124508860b003a85321d Mon Sep 17 00:00:00 2001 From: Denis Kolmerschlag Date: Thu, 17 Oct 2024 10:28:51 +0200 Subject: [PATCH 3/6] Fix a bug and add unit test for CUrrentGroupService --- .../Tests/Unit/CurrentGroupServiceTest.php | 161 ++++++++++++ .../src/Hooks/SocialPostFormHooks.php | 9 +- .../src/Test/Unit/SocialPostFormHooksTest.php | 240 ++++++++++++++++++ 3 files changed, 406 insertions(+), 4 deletions(-) create mode 100644 modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php create mode 100644 modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php diff --git a/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php b/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php new file mode 100644 index 00000000000..151be5c59a7 --- /dev/null +++ b/modules/social_features/social_group/src/Tests/Unit/CurrentGroupServiceTest.php @@ -0,0 +1,161 @@ +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.'); + } + + /** + * Test that fromRunTimeContexts() returns a GroupInterface when available. + */ + public function testFromRunTimeContextsWithGroup(): void { + $group = $this->createMock(GroupInterface::class); + $context = $this->createContextWithValue($group); + + $this->groupRouteContext + ->expects($this->once()) + ->method('getRuntimeContexts') + ->willReturn(['group' => $context]); + + $result = $this->currentGroupService->fromRunTimeContexts(); + + $this->assertSame($group, $result, 'Group should be returned when found in context.'); + } + + /** + * Test that fromRunTimeContexts() loads a group by ID. + */ + 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); + + $result = $this->currentGroupService->fromRunTimeContexts(); + + $this->assertSame($group, $result, 'Group should be loaded by ID and returned.'); + } + + /** + * Test that fromRunTimeContexts() returns NULL when no valid group found. + */ + public function testFromRunTimeContextsInvalidGroup(): void { + $invalidValue = 'invalid'; + $context = $this->createContextWithValue($invalidValue); + + $this->groupRouteContext + ->expects($this->once()) + ->method('getRuntimeContexts') + ->willReturn(['group' => $context]); + + $result = $this->currentGroupService->fromRunTimeContexts(); + + $this->assertNull($result, 'Invalid group value should return NULL.'); + } + +} diff --git a/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php b/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php index 59d99604c6e..2672c89a352 100644 --- a/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php +++ b/modules/social_features/social_post/src/Hooks/SocialPostFormHooks.php @@ -60,12 +60,13 @@ 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(); - if ($form_state->getFormObject() instanceof ContentEntityForm === FALSE) { + if ($form_object instanceof ContentEntityForm === FALSE) { return; } - if ($form_state->getFormObject()->getEntity()->isNew() + if ($form_object->getEntity()->isNew() && $content !== NULL) { $form['current_user_image'] = $content; } @@ -90,8 +91,8 @@ public function formPostFormAlter(array &$form, FormStateInterface $form_state): // $user_profile = $this->routeMatch->getParameter('user'); $user_profile = $form_state->get('recipientUser'); if ($user_profile !== NULL - && $user_profile->id() != $this->currentUser->id()) { - $this->setFormTitleAndPlaceholder($form, t('Leave a message to @name', [ + && $user_profile->id() !== $this->currentUser->id()) { + $form = $this->setFormTitleAndPlaceholder($form, t('Leave a message to @name', [ '@name' => $user_profile->getDisplayName(), ])); } diff --git a/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php b/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php new file mode 100644 index 00000000000..f93f7123539 --- /dev/null +++ b/modules/social_features/social_post/src/Test/Unit/SocialPostFormHooksTest.php @@ -0,0 +1,240 @@ +socialPostHelper = $this->createMock(SocialPostHelperInterface::class); + $this->currentUser = $this->createMock(AccountProxyInterface::class); + $this->formState = $this->createMock(FormStateInterface::class); + + $this->socialPostFormHooks = new SocialPostFormHooks( + $this->socialPostHelper, + $this->currentUser + ); + + // Create a mock TranslationInterface. + $translation = $this->createMock(TranslationInterface::class); + $translation->method('translate') + ->willReturnCallback(function ($string, array $args = [], array $options = []) { + // phpcs:ignore + 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); + + $this->form = [ + 'field_post' => ['widget' => [0 => []]], + 'actions' => ['submit' => ['#value' => '']], + ]; + } + + /** + * Test formPostFormAlter with a new post and valid current user image. + */ + public function testFormPostFormAlterWithNewPostAndImage(): void { + $this->mockContentEntityForm(); + $currentUserImage = $this->mockUserImage(); + + $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'] + ); + } + + /** + * Test formPostFormAlter when there's a current group set. + */ + public function testFormPostFormAlterWithCurrentGroup(): void { + $this->mockContentEntityForm(); + $currentUserImage = $this->mockUserImage(); + + $this->formState->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['currentGroup', 2], + ['recipientUser', NULL], + ]); + + $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'] + ); + $this->assertEquals( + new TranslatableMarkup('Say something to the group'), + $this->form['field_post']['widget'][0]['#placeholder'] + ); + } + + /** + * Test formPostFormAlter when it's a private message. + */ + public function testFormPostFormAlterWithRecipientUser(): void { + $this->mockContentEntityForm(); + $currentUserImage = $this->mockUserImage(); + + $recipientUser = $this->createMock(User::class); + + $this->formState->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['currentGroup', NULL], + ['recipientUser', $recipientUser], + ]); + + $recipientUser->expects($this->once()) + ->method('getDisplayName') + ->willReturn('John Doe'); + $recipientUser->expects($this->once()) + ->method('id') + ->willReturn(2); + + $this->currentUser->expects($this->once()) + ->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'] + ); + $this->assertEquals( + new TranslatableMarkup('Leave a message to @name', ['@name' => 'John Doe']), + $this->form['field_post']['widget'][0]['#placeholder'] + ); + } + + /** + * Mock user image. + * + * @return array + * The mocked user image. + */ + private function mockUserImage(): array { + // Mock the SocialPostHelper to return user image. + $currentUserImage = ['#markup' => 'User Image']; + $this->socialPostHelper->expects($this->once()) + ->method('buildCurrentUserImage') + ->willReturn($currentUserImage); + return $currentUserImage; + } + + /** + * Mock content entity form. + */ + public function mockContentEntityForm(): void { + $contentEntityForm = $this->createMock(ContentEntityForm::class); + $entity = $this->createMock(ContentEntityInterface::class); + $entity->expects($this->once()) + ->method('isNew') + ->willReturn(TRUE); + + $contentEntityForm->expects($this->once()) + ->method('getEntity') + ->willReturn($entity); + + $this->formState->expects($this->once()) + ->method('getFormObject') + ->willReturn($contentEntityForm); + } + +} From bd80d1641dfae9b0e8013d249160d5bab17f74cd Mon Sep 17 00:00:00 2001 From: Denis Kolmerschlag Date: Wed, 16 Oct 2024 10:15:39 +0200 Subject: [PATCH 4/6] Replacing social_post_form_post_form_alter with hux approach. From c3bc03099e22813ac67052ddf67a8084c1b6c7bc Mon Sep 17 00:00:00 2001 From: Denis Kolmerschlag Date: Wed, 30 Oct 2024 13:45:59 +0100 Subject: [PATCH 5/6] Updates following PR comments. --- .../src/Plugin/views/display/FilterBlock.php | 2 +- .../social_group/social_group.services.yml | 7 +- .../social_group/src/CurrentGroupService.php | 52 ++----- .../Tests/Unit/CurrentGroupServiceTest.php | 138 +++++------------- .../src/Plugin/Block/PostPhotoBlock.php | 4 +- .../Plugin/Block/PostPhotoProfileBlock.php | 4 +- .../social_post/social_post.services.yml | 5 + .../src/Hooks/SocialPostFormHooks.php | 45 ++---- .../src/Test/Unit/SocialPostFormHooksTest.php | 26 +--- phpstan-baseline.neon | 5 - 10 files changed, 75 insertions(+), 213 deletions(-) diff --git a/modules/social_features/social_activity/modules/social_activity_filter/src/Plugin/views/display/FilterBlock.php b/modules/social_features/social_activity/modules/social_activity_filter/src/Plugin/views/display/FilterBlock.php index 513a8d001af..115c7015452 100755 --- a/modules/social_features/social_activity/modules/social_activity_filter/src/Plugin/views/display/FilterBlock.php +++ b/modules/social_features/social_activity/modules/social_activity_filter/src/Plugin/views/display/FilterBlock.php @@ -214,7 +214,7 @@ public static function processFilterTags(array &$element, FormStateInterface $fo /** * Handles switching the available terms based on the selected vocabulary. */ - public static function updateTagsOptions($form, FormStateInterface $form_state) { + public static function updateTagsOptions(array $form, FormStateInterface $form_state) { // Check if there is triggered parent of element. if ($triggered = $form_state->getTriggeringElement()) { diff --git a/modules/social_features/social_group/social_group.services.yml b/modules/social_features/social_group/social_group.services.yml index 72b9a3f2161..f109a4e915d 100644 --- a/modules/social_features/social_group/social_group.services.yml +++ b/modules/social_features/social_group/social_group.services.yml @@ -50,8 +50,7 @@ services: tags: - { name: cache.context } - social_group.current_group: + Drupal\social_group\CurrentGroupService: class: Drupal\social_group\CurrentGroupService - arguments: - - '@entity_type.manager' - - '@group.group_route_context' + autowire: true + social_group.current_group: '@Drupal\social_group\CurrentGroupService' 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/social_post.services.yml b/modules/social_features/social_post/social_post.services.yml index 5c2fa3ee597..e9e0a330a00 100644 --- a/modules/social_features/social_post/social_post.services.yml +++ b/modules/social_features/social_post/social_post.services.yml @@ -20,3 +20,8 @@ services: - '@current_user' tags: - { name: hooks } + + Drupal\social_post\Hooks\SocialPostFormHooks: + class: Drupal\social_post\Hooks\SocialPostFormHooks + autowire: true + social_post.form.hooks: '@Drupal\social_post\Hooks\SocialPostFormHooks' 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()) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c281731f936..d7b0c8e5d8c 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2808,11 +2808,6 @@ parameters: count: 1 path: modules/social_features/social_activity/modules/social_activity_filter/src/Plugin/views/display/FilterBlock.php - - - message: "#^Method Drupal\\\\social_activity_filter\\\\Plugin\\\\views\\\\display\\\\FilterBlock\\:\\:updateTagsOptions\\(\\) has parameter \\$form with no type specified\\.$#" - count: 1 - path: modules/social_features/social_activity/modules/social_activity_filter/src/Plugin/views/display/FilterBlock.php - - message: "#^Offset '\\#parents' does not exist on array\\|null\\.$#" count: 2 From ea038d7d9759ee7fddae77e2845a517a698111f3 Mon Sep 17 00:00:00 2001 From: Denis Kolmerschlag Date: Mon, 18 Nov 2024 16:33:44 +0100 Subject: [PATCH 6/6] Update autowiring to ensure currentGroupService exists during installation --- .../social_features/social_group/social_group.services.yml | 3 +-- modules/social_features/social_post/social_post.info.yml | 7 ++++--- .../social_post/src/Plugin/Block/PostBlock.php | 2 +- social.info.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/social_features/social_group/social_group.services.yml b/modules/social_features/social_group/social_group.services.yml index f109a4e915d..f334336f281 100644 --- a/modules/social_features/social_group/social_group.services.yml +++ b/modules/social_features/social_group/social_group.services.yml @@ -51,6 +51,5 @@ services: - { name: cache.context } Drupal\social_group\CurrentGroupService: - class: Drupal\social_group\CurrentGroupService + social_group.current_group_service: '@Drupal\social_group\CurrentGroupService' autowire: true - social_group.current_group: '@Drupal\social_group\CurrentGroupService' diff --git a/modules/social_features/social_post/social_post.info.yml b/modules/social_features/social_post/social_post.info.yml index 018f17b0bf5..8b27dc98d8a 100644 --- a/modules/social_features/social_post/social_post.info.yml +++ b/modules/social_features/social_post/social_post.info.yml @@ -5,13 +5,14 @@ core_version_requirement: ^9 || ^10 dependencies: - drupal:block - drupal:comment - - social:dropdown - drupal:field - - group:group - drupal:options - - social:social_comment - drupal:text - drupal:user - drupal:views + - group:group - social:activity_creator + - social:dropdown + - social:social_comment + - social:social_group package: Social diff --git a/modules/social_features/social_post/src/Plugin/Block/PostBlock.php b/modules/social_features/social_post/src/Plugin/Block/PostBlock.php index fda3b00c0e2..b748dc04498 100644 --- a/modules/social_features/social_post/src/Plugin/Block/PostBlock.php +++ b/modules/social_features/social_post/src/Plugin/Block/PostBlock.php @@ -154,7 +154,7 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('form_builder'), $container->get('module_handler'), $container->get('current_route_match'), - $container->get('social_group.current_group'), + $container->get(CurrentGroupService::class), ); } diff --git a/social.info.yml b/social.info.yml index 0e62eecf57e..204dc99adcd 100644 --- a/social.info.yml +++ b/social.info.yml @@ -18,9 +18,9 @@ dependencies: - color:color - improved_theme_settings:improved_theme_settings # Open Social + - social:social_group - social:social_activity - social:social_core - - social:social_group - social:social_swiftmail - social:social_user