From d48e491144e8a5fd59a7d811923e9ac2774c6b1d Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 17 Mar 2025 08:26:45 +0000 Subject: [PATCH] Create events for prepare_body hooks --- src/Core/Hooks/HookEventBridge.php | 22 +++++++++ src/Event/ArrayFilterEvent.php | 20 +++++++++ src/Model/Item.php | 45 ++++++++++++++----- tests/Unit/Core/Hooks/HookEventBridgeTest.php | 29 ++++++++++++ tests/Unit/Event/ArrayFilterEventTest.php | 4 ++ 5 files changed, 108 insertions(+), 12 deletions(-) diff --git a/src/Core/Hooks/HookEventBridge.php b/src/Core/Hooks/HookEventBridge.php index 251c462929..8d53df417f 100644 --- a/src/Core/Hooks/HookEventBridge.php +++ b/src/Core/Hooks/HookEventBridge.php @@ -48,6 +48,10 @@ final class HookEventBridge ArrayFilterEvent::INSERT_POST_LOCAL_END => 'post_local_end', ArrayFilterEvent::INSERT_POST_REMOTE => 'post_remote', ArrayFilterEvent::INSERT_POST_REMOTE_END => 'post_remote_end', + ArrayFilterEvent::PREPARE_POST_START => 'prepare_body_init', + ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT => 'prepare_body_content_filter', + ArrayFilterEvent::PREPARE_POST => 'prepare_body', + ArrayFilterEvent::PREPARE_POST_END => 'prepare_body_final', ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'photo_upload_form', ArrayFilterEvent::NETWORK_TO_NAME => 'network_to_name', ArrayFilterEvent::CONVERSATION_START => 'conversation_start', @@ -106,6 +110,10 @@ final class HookEventBridge ArrayFilterEvent::INSERT_POST_LOCAL_END => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_REMOTE => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_REMOTE_END => 'onArrayFilterEvent', + ArrayFilterEvent::PREPARE_POST_START => 'onPreparePostStartEvent', + ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT => 'onArrayFilterEvent', + ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent', + ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent', ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_TO_NAME => 'onArrayFilterEvent', ArrayFilterEvent::CONVERSATION_START => 'onArrayFilterEvent', @@ -163,6 +171,20 @@ final class HookEventBridge ); } + /** + * Map the PREPARE_POST_START event to `prepare_body_init` hook + */ + public static function onPreparePostStartEvent(ArrayFilterEvent $event): void + { + $data = $event->getArray(); + + $item = (array) $data['item'] ?? []; + + $data['item'] = static::callHook($event->getName(), $item); + + $event->setArray($data); + } + /** * Map the OEMBED_FETCH_END event to `oembed_fetch_url` hook */ diff --git a/src/Event/ArrayFilterEvent.php b/src/Event/ArrayFilterEvent.php index 51719e7de9..f29acad952 100644 --- a/src/Event/ArrayFilterEvent.php +++ b/src/Event/ArrayFilterEvent.php @@ -34,6 +34,26 @@ final class ArrayFilterEvent extends Event public const INSERT_POST_REMOTE_END = 'friendica.data.insert_post_remote_end'; + /** + * item array before any work + */ + public const PREPARE_POST_START = 'friendica.data.prepare_post_start'; + + /** + * before first bbcode to html + */ + public const PREPARE_POST_FILTER_CONTENT = 'friendica.data.prepare_post_filter_content'; + + /** + * after first bbcode to html + */ + public const PREPARE_POST = 'friendica.data.prepare_post'; + + /** + * after attach icons and blockquote special case handling (spoiler, author) + */ + public const PREPARE_POST_END = 'friendica.data.prepare_post_end'; + public const PHOTO_UPLOAD_FORM = 'friendica.data.photo_upload_form'; public const NETWORK_TO_NAME = 'friendica.data.network_to_name'; diff --git a/src/Model/Item.php b/src/Model/Item.php index d2169d3156..6c8be7528e 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -3058,16 +3058,22 @@ class Item * @return string item body html * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException - * @hook prepare_body_init item array before any work - * @hook prepare_body_content_filter ('item'=>item array, 'filter_reasons'=>string array) before first bbcode to html - * @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html - * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author) */ public static function prepareBody(array &$item, bool $attach = false, bool $is_preview = false, bool $only_cache = false): string { - $appHelper = DI::appHelper(); - $uid = DI::userSession()->getLocalUserId(); - Hook::callAll('prepare_body_init', $item); + $appHelper = DI::appHelper(); + $uid = DI::userSession()->getLocalUserId(); + $eventDispatcher = DI::eventDispatcher(); + + $hook_data = [ + 'item' => $item, + ]; + + $hook_data = $eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_START, $hook_data), + )->getArray(); + + $item = $hook_data['item'] ?? $item; // In order to provide theme developers more possibilities, event items // are treated differently. @@ -3186,7 +3192,11 @@ class Item 'item' => $item, 'filter_reasons' => $filter_reasons ]; - Hook::callAll('prepare_body_content_filter', $hook_data); + + $hook_data = $eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT, $hook_data), + )->getArray(); + $filter_reasons = $hook_data['filter_reasons']; unset($hook_data); } @@ -3205,7 +3215,11 @@ class Item 'preview' => $is_preview, 'filter_reasons' => $filter_reasons ]; - Hook::callAll('prepare_body', $hook_data); + + $hook_data = $eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST, $hook_data), + )->getArray(); + $s = $hook_data['html']; unset($hook_data); @@ -3257,9 +3271,16 @@ class Item $s = HTML::applyContentFilter($s, $filter_reasons); - $hook_data = ['item' => $item, 'html' => $s]; - Hook::callAll('prepare_body_final', $hook_data); - return $hook_data['html']; + $hook_data = [ + 'item' => $item, + 'html' => $s, + ]; + + $hook_data = $eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_END, $hook_data), + )->getArray(); + + return (string) $hook_data['html'] ?? $s; } /** diff --git a/tests/Unit/Core/Hooks/HookEventBridgeTest.php b/tests/Unit/Core/Hooks/HookEventBridgeTest.php index 325aefb742..17291539a7 100644 --- a/tests/Unit/Core/Hooks/HookEventBridgeTest.php +++ b/tests/Unit/Core/Hooks/HookEventBridgeTest.php @@ -37,6 +37,10 @@ class HookEventBridgeTest extends TestCase ArrayFilterEvent::INSERT_POST_LOCAL_END => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_REMOTE => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_REMOTE_END => 'onArrayFilterEvent', + ArrayFilterEvent::PREPARE_POST_START => 'onPreparePostStartEvent', + ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT => 'onArrayFilterEvent', + ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent', + ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent', ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_TO_NAME => 'onArrayFilterEvent', ArrayFilterEvent::CONVERSATION_START => 'onArrayFilterEvent', @@ -183,6 +187,28 @@ class HookEventBridgeTest extends TestCase HookEventBridge::onCollectRoutesEvent($event); } + public function testOnPreparePostStartEventCallsHookWithCorrectValue(): void + { + $event = new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_START, ['item' => ['id' => -1]]); + + $reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook'); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue(null, function (string $name, array $data): array { + $this->assertSame('prepare_body_init', $name); + $this->assertSame(['id' => -1], $data); + + return ['id' => 123]; + }); + + HookEventBridge::onPreparePostStartEvent($event); + + $this->assertSame( + ['item' => ['id' => 123]], + $event->getArray(), + ); + } + public function testOnOembedFetchEndEventCallsHookWithCorrectValue(): void { $event = new ArrayFilterEvent(ArrayFilterEvent::OEMBED_FETCH_END, ['url' => 'original_url']); @@ -318,6 +344,9 @@ class HookEventBridgeTest extends TestCase [ArrayFilterEvent::INSERT_POST_LOCAL_END, 'post_local_end'], [ArrayFilterEvent::INSERT_POST_REMOTE, 'post_remote'], [ArrayFilterEvent::INSERT_POST_REMOTE_END, 'post_remote_end'], + [ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT, 'prepare_body_content_filter'], + [ArrayFilterEvent::PREPARE_POST, 'prepare_body'], + [ArrayFilterEvent::PREPARE_POST_END, 'prepare_body_final'], [ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'photo_upload_form'], [ArrayFilterEvent::NETWORK_TO_NAME, 'network_to_name'], [ArrayFilterEvent::CONVERSATION_START, 'conversation_start'], diff --git a/tests/Unit/Event/ArrayFilterEventTest.php b/tests/Unit/Event/ArrayFilterEventTest.php index 7c124f0b33..5af49e9fb8 100644 --- a/tests/Unit/Event/ArrayFilterEventTest.php +++ b/tests/Unit/Event/ArrayFilterEventTest.php @@ -34,6 +34,10 @@ class ArrayFilterEventTest extends TestCase [ArrayFilterEvent::INSERT_POST_LOCAL_END, 'friendica.data.insert_post_local_end'], [ArrayFilterEvent::INSERT_POST_REMOTE, 'friendica.data.insert_post_remote'], [ArrayFilterEvent::INSERT_POST_REMOTE_END, 'friendica.data.insert_post_remote_end'], + [ArrayFilterEvent::PREPARE_POST_START, 'friendica.data.prepare_post_start'], + [ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT, 'friendica.data.prepare_post_filter_content'], + [ArrayFilterEvent::PREPARE_POST, 'friendica.data.prepare_post'], + [ArrayFilterEvent::PREPARE_POST_END, 'friendica.data.prepare_post_end'], [ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'friendica.data.photo_upload_form'], [ArrayFilterEvent::NETWORK_TO_NAME, 'friendica.data.network_to_name'], [ArrayFilterEvent::CONVERSATION_START, 'friendica.data.conversation_start'],