[2.x] fix(mentions): prevent deleted fallback for unsynced posts during formatting#4824
Merged
imorland merged 4 commits intoJul 23, 2026
Merged
Conversation
…matting During the Saving/Revised lifecycle (such as editing a post), the mentions pivot tables may not be fully synced or accessible before the API serializes the response. When formatContent() or unparse() is called, the fallback logic in the formatting classes was attempting to execute a relationship pivot query ($context->mentionsPosts()->find()) if the relation wasn't eager loaded. Because the pivot table was not completely synced, this query failed, causing the formatter to incorrectly resolve valid mentions to the deleted_text fallback. This fix removes the pivot table constraint when the relationship is not eagerly loaded, directly querying the underlying model instead. This also resolves an N+1 query bottleneck when unparsing posts without eager loaded mentions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `editing_a_post_with_deleted_author_that_has_a_mention_works` tests were incorrectly submitting a `PATCH` payload with the exact same content as the unparsed original post text. Because the text was identical, Flarum correctly optimized away the `Revised` event, which meant the database pivot tables were never synced and the test failed on the database assertion. This fixes the test by actually mutating the content string during the edit, ensuring the `Revised` event is fired and the pivot tables are populated so they can be properly asserted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `deleted_tag_mentions_relation_unparse_and_render_as_expected` test verified that a post mentioning a Tag (ID 3) would render as `[deleted]` if the relationship pivot row was missing, despite Tag 3 actually existing in the database fixtures. Because we fixed the format logic to correctly query the base table when the pivot is empty, Flarum rightfully discovers that Tag 3 still exists and refuses to render it as deleted if it isn't eager-loaded. This commit fixes the test by changing the mention to target Tag ID 999 (which truly does not exist in the database fixtures), ensuring the deleted rendering logic is accurately tested against an actually missing tag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9 tasks
Add a regression test asserting that reading $post->content in a Saving listener resolves mentions to the real entity rather than the [deleted]/ [unknown] fallback, for both new and edited posts. Fails against the pre-fix pivot-query behaviour, passes with the fix.
imorland
approved these changes
Jul 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4823
Changes proposed in this pull request:
This PR modifies all
Format*MentionsandUnparse*Mentionsclasses to:relationLoaded), executing 0 queries.Post::query()->find()) rather than querying the pivot table if the relation isn't loaded.This completely bypasses the pivot table requirement during text evaluation, allowing the formatters to accurately retrieve display names for edited posts.
This bug also caused false positives in the Flarum test suite:
editing_a_post_with_deleted_author_that_has_a_mention_works: The test edited a post by sending the exact same text that the post already had. Because the brokenunparse()method previously evaluated the old post content as[deleted], Flarum thought the content had changed and dispatched theRevisedevent. Withunparse()fixed, Flarum correctly recognizes the text did not change and skips theRevisedevent, causing the test's pivot table assertion to fail. This PR updates the test payloads to actually mutate the content so that theRevisedevent fires properly.deleted_tag_mentions_relation_unparse_and_render_as_expected: The test verified that a post mentioning a Tag would render as[deleted]if the pivot row was missing, despite the Tag actually existing in the database fixtures. Before our format fixes, Flarum wrongly rendered this as deleted because it strictly trusted the empty pivot table. With our format logic fixed, Flarum rightfully discovers the Tag still exists and refuses to render it as deleted, causing the test to fail. This PR updates the test to target a genuinely non-existent Tag ID (999) to accurately test the deleted fallback.Output of
$post->contentContent use to test:
Output:
Also tested with email notification which relates to #3454, but was not able to reproduce the issue, the username is showing correctly before and after the fix:
Necessity
Confirmed
composer test).Required changes: