diff --git a/src/Rest/Helpers/Emoji/EmojiBuilder.php b/src/Rest/Helpers/Emoji/EmojiBuilder.php index 10258ae..cd8562a 100644 --- a/src/Rest/Helpers/Emoji/EmojiBuilder.php +++ b/src/Rest/Helpers/Emoji/EmojiBuilder.php @@ -73,10 +73,25 @@ public function get(): array return $this->data; } + /** + * The emoji as a reaction endpoint takes it. + * + * A custom emoji is "name:id". A standard one is the character itself, + * percent encoded, and may be held under either key: fromPart() puts it in + * name, because that is where Discord sends it in a reaction event, while + * setId() has long been the documented way to write one by hand. + * + * @see https://discord.com/developers/docs/resources/channel#create-reaction + */ public function __toString(): string { - return isset($this->data['name']) - ? $this->data['name'] . ':' . $this->data['id'] - : urlencode($this->data['id']); + $id = $this->data['id'] ?? null; + $name = $this->data['name'] ?? null; + + if ($id !== null && $name !== null) { + return $name . ':' . $id; + } + + return rawurlencode((string) ($name ?? $id)); } } diff --git a/tests/Rest/Helpers/Emoji/EmojiBuilderTest.php b/tests/Rest/Helpers/Emoji/EmojiBuilderTest.php index 6447041..e423a93 100644 --- a/tests/Rest/Helpers/Emoji/EmojiBuilderTest.php +++ b/tests/Rest/Helpers/Emoji/EmojiBuilderTest.php @@ -53,6 +53,38 @@ public function testCreateEmojiFromIdAndName(): void $this->assertEquals('name:12345', (string) $emojiBuilder); } + /** + * A reaction event carries a standard emoji as its name with no id, which + * is what fromPart() copies across. Rendering that as "✅:" — with the id + * missing entirely — made every reaction on a standard emoji a malformed + * request, and warned about an undefined key on the way out. + */ + public function testCreateEmojiFromNameAlone(): void + { + $emojiBuilder = new EmojiBuilder(); + $emojiBuilder->setName('✅'); + + $this->assertEquals(rawurlencode('✅'), (string) $emojiBuilder); + } + + public function testAStandardEmojiFromAReactionEventIsRenderedForTheEndpoint(): void + { + $emoji = new Emoji(); + $emoji->name = '❌'; + $emoji->id = null; + + $this->assertEquals(rawurlencode('❌'), (string) EmojiBuilder::fromPart($emoji)); + } + + public function testACustomEmojiFromAReactionEventKeepsBothHalves(): void + { + $emoji = new Emoji(); + $emoji->name = 'apex'; + $emoji->id = '12345'; + + $this->assertEquals('apex:12345', (string) EmojiBuilder::fromPart($emoji)); + } + #[DataProvider('getFromPartProvider')] public function testGetFromPart(Emoji $emoji, array $result): void {