1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-27 05:14:39 +01:00

Add Entities classes

- Make entity property as public
- Add support for objects in getHTML method!
This commit is contained in:
Mahdi 2023-08-30 17:07:14 +03:30
parent a42fe534b2
commit e76146664f
23 changed files with 279 additions and 33 deletions

View File

@ -28,6 +28,7 @@ use danog\MadelineProto\EventHandler\Media\RoundVideo;
use danog\MadelineProto\EventHandler\Media\Sticker;
use danog\MadelineProto\EventHandler\Media\Video;
use danog\MadelineProto\EventHandler\Media\Voice;
use danog\MadelineProto\EventHandler\Message\Entities\MessageEntity;
use danog\MadelineProto\MTProto;
use danog\MadelineProto\ParseMode;
use danog\MadelineProto\StrTools;
@ -97,6 +98,9 @@ abstract class Message extends AbstractMessage
/** Author of the post, if signatures are enabled for messages from channels or forwarded from channels */
public readonly ?string $signature;
/** @var array<MessageEntity> Message [entities](https://core.telegram.org/api/entities) for styled text */
public readonly ?array $entities;
/** @internal */
public function __construct(
MTProto $API,
@ -109,7 +113,9 @@ abstract class Message extends AbstractMessage
$this->forwards = $rawMessage['forwards'] ?? null;
$this->signature = $rawMessage['post_author'] ?? null;
$this->entities = $rawMessage['entities'] ?? null;
$this->entities = isset($rawMessage['entities']) && !empty($entities = $rawMessage['entities'])
? MessageEntity::fromRawEntities($entities)
: null;
$this->message = $rawMessage['message'];
$this->fromScheduled = $rawMessage['from_scheduled'];
$this->viaBotId = $rawMessage['via_bot_id'] ?? null;
@ -118,7 +124,6 @@ abstract class Message extends AbstractMessage
$this->keyboard = isset($rawMessage['reply_markup'])
? Keyboard::fromRawReplyMarkup($rawMessage['reply_markup'])
: null;
if (isset($rawMessage['fwd_from'])) {
$fwdFrom = $rawMessage['fwd_from'];
$this->fwdInfo = new ForwardedInfo(
@ -342,7 +347,6 @@ abstract class Message extends AbstractMessage
protected readonly string $html;
protected readonly string $htmlTelegram;
protected readonly ?array $entities;
/**
* Get an HTML version of the message.

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class BankCard extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Blockquote extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Bold extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class BotCommand extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Cashtag extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Code extends MessageEntity
{
}

View File

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class CustomEmoji extends MessageEntity
{
/** Document ID of the [custom emoji](https://core.telegram.org/api/custom-emoji). */
public readonly int $documentId;
protected function __construct(array $rawEntities)
{
parent::__construct($rawEntities);
$this->documentId = $rawEntities['document_id'];
}
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Email extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Hashtag extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Italic extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Mention extends MessageEntity
{
}

View File

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class MentionName extends MessageEntity
{
/** Identifier of the user that was mentioned */
public readonly int $userId;
protected function __construct(array $rawEntities)
{
parent::__construct($rawEntities);
$this->userId = $rawEntities['user_id'];
}
}

View File

@ -0,0 +1,58 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
use JsonSerializable;
use ReflectionClass;
use ReflectionProperty;
abstract class MessageEntity implements JsonSerializable
{
/** Offset of message entity within message (in UTF-16 code units) */
public readonly int $offset;
/** Length of message entity within message (in UTF-16 code units) */
public readonly int $length;
protected function __construct(array $rawEntities)
{
$this->offset = $rawEntities['offset'];
$this->length = $rawEntities['length'];
}
public static function fromRawEntities(array $entities)
{
$create = static fn (array $entity): MessageEntity => match ($entity['_']) {
'messageEntityMention' => new Mention($entity),
'messageEntityHashtag' => new Hashtag($entity),
'messageEntityBotCommand' => new BotCommand($entity),
'messageEntityEmail' => new Email($entity),
'messageEntityBold' => new Bold($entity),
'messageEntityItalic' => new Italic($entity),
'messageEntityUrl' => new Url($entity),
'messageEntityCode' => new Code($entity),
'messageEntityPre' => new Pre($entity),
'messageEntityTextUrl' => new TextUrl($entity),
'messageEntityMentionName','inputMessageEntityMentionName' => new MentionName($entity),
'messageEntityPhone' => new Phone($entity),
'messageEntityCashtag' => new Cashtag($entity),
'messageEntityUnderline' => new Underline($entity),
'messageEntityStrike' => new Strike($entity),
'messageEntityBlockquote' => new Blockquote($entity),
'messageEntityBankCard' => new BankCard($entity),
'messageEntitySpoiler' => new Spoiler($entity),
'messageEntityCustomEmoji' => new CustomEmoji($entity),
default => new Unknown($entity)
};
return \array_map(fn (array $entity) => $create($entity), $entities);
}
/** @internal */
public function jsonSerialize(): mixed
{
$res = ['_' => static::class];
$refl = new ReflectionClass($this);
foreach ($refl->getProperties(ReflectionProperty::IS_PUBLIC) as $prop) {
$res[$prop->getName()] = $prop->getValue($this);
}
return $res;
}
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Phone extends MessageEntity
{
}

View File

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Pre extends MessageEntity
{
/** Programming language of the code */
public readonly string $language;
protected function __construct(array $rawEntities)
{
parent::__construct($rawEntities);
$this->language = $rawEntities['language'];
}
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Spoiler extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Strike extends MessageEntity
{
}

View File

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class TextUrl extends MessageEntity
{
/** The actual URL */
public readonly string $url;
protected function __construct(array $rawEntities)
{
parent::__construct($rawEntities);
$this->url = $rawEntities['url'];
}
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Underline extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Unknown extends MessageEntity
{
}

View File

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace danog\MadelineProto\EventHandler\Message\Entities;
final class Url extends MessageEntity
{
}

View File

@ -20,6 +20,22 @@ declare(strict_types=1);
namespace danog\MadelineProto;
use danog\MadelineProto\EventHandler\Message\Entities\Blockquote;
use danog\MadelineProto\EventHandler\Message\Entities\Bold;
use danog\MadelineProto\EventHandler\Message\Entities\Code;
use danog\MadelineProto\EventHandler\Message\Entities\CustomEmoji;
use danog\MadelineProto\EventHandler\Message\Entities\Email;
use danog\MadelineProto\EventHandler\Message\Entities\Italic;
use danog\MadelineProto\EventHandler\Message\Entities\Mention;
use danog\MadelineProto\EventHandler\Message\Entities\MentionName;
use danog\MadelineProto\EventHandler\Message\Entities\MessageEntity;
use danog\MadelineProto\EventHandler\Message\Entities\Phone;
use danog\MadelineProto\EventHandler\Message\Entities\Pre;
use danog\MadelineProto\EventHandler\Message\Entities\Spoiler;
use danog\MadelineProto\EventHandler\Message\Entities\Strike;
use danog\MadelineProto\EventHandler\Message\Entities\TextUrl;
use danog\MadelineProto\EventHandler\Message\Entities\Underline;
use danog\MadelineProto\EventHandler\Message\Entities\Url;
use danog\MadelineProto\TL\Conversion\DOMEntities;
use danog\MadelineProto\TL\Conversion\Extension;
use danog\MadelineProto\TL\Conversion\MarkdownEntities;
@ -117,46 +133,46 @@ abstract class StrTools extends Extension
/**
* Convert a message and a set of entities to HTML.
*
* @param list<array{_: string, offset: int, length: int, ...}> $entities
* @param list<MessageEntity> $entities
* @param bool $allowTelegramTags Whether to allow telegram-specific tags like tg-spoiler, tg-emoji, mention links and so on...
*/
public static function entitiesToHtml(string $message, array $entities, bool $allowTelegramTags = false): string
{
$insertions = [];
foreach ($entities as $entity) {
['_' => $type, 'offset' => $offset, 'length' => $length] = $entity;
[$offset, $length] = [$entity->offset, $entity->length];
$insertions[$offset] ??= '';
$insertions[$offset] .= match ($type) {
'messageEntityBold' => '<b>',
'messageEntityItalic' => '<i>',
'messageEntityCode' => '<code>',
'messageEntityPre' => $entity['language'] !== '' ? '<pre language="'.$entity['language'].'">' : '<pre>',
'messageEntityTextUrl' => '<a href="'.$entity['url'].'">',
'messageEntityStrike' => '<s>',
'messageEntityUnderline' => '<u>',
'messageEntityBlockquote' => '<blockquote>',
'messageEntityUrl' => '<a href="'.\htmlspecialchars(self::mbSubstr($message, $offset, $length)).'">',
'messageEntityEmail' => '<a href="mailto:'.\htmlspecialchars(self::mbSubstr($message, $offset, $length)).'">',
'messageEntityPhone' => '<a href="phone:'.\htmlspecialchars(self::mbSubstr($message, $offset, $length)).'">',
'messageEntityMention' => '<a href="https://t.me/'.\htmlspecialchars(self::mbSubstr($message, $offset+1, $length-1)).'">',
'messageEntitySpoiler' => $allowTelegramTags ? '<tg-spoiler>' : '',
'messageEntityCustomEmoji' => $allowTelegramTags ? '<tg-emoji emoji-id="'.$entity['document_id'].'">' : '',
'messageEntityMentionName', 'inputMessageEntityMentionName' => $allowTelegramTags ? '<a href="tg://user?id='.$entity['user_id'].'">' : '',
$insertions[$offset] .= match (true) {
$entity instanceof Bold => '<b>',
$entity instanceof Italic => '<i>',
$entity instanceof Code => '<code>',
$entity instanceof Pre => $entity->language !== '' ? '<pre language="'.$entity->language.'">' : '<pre>',
$entity instanceof TextUrl => '<a href="'.$entity->url.'">',
$entity instanceof Strike => '<s>',
$entity instanceof Underline => '<u>',
$entity instanceof Blockquote => '<blockquote>',
$entity instanceof Url => '<a href="'.\htmlspecialchars(self::mbSubstr($message, $offset, $length)).'">',
$entity instanceof Email => '<a href="mailto:'.\htmlspecialchars(self::mbSubstr($message, $offset, $length)).'">',
$entity instanceof Phone => '<a href="phone:'.\htmlspecialchars(self::mbSubstr($message, $offset, $length)).'">',
$entity instanceof Mention => '<a href="https://t.me/'.\htmlspecialchars(self::mbSubstr($message, $offset+1, $length-1)).'">',
$entity instanceof Spoiler => $allowTelegramTags ? '<tg-spoiler>' : '',
$entity instanceof CustomEmoji => $allowTelegramTags ? '<tg-emoji emoji-id="'.$entity->documentId.'">' : '',
$entity instanceof MentionName => $allowTelegramTags ? '<a href="tg://user?id='.$entity->userId.'">' : '',
default => '',
};
$offset += $length;
$insertions[$offset] = match ($type) {
'messageEntityBold' => '</b>',
'messageEntityItalic' => '</i>',
'messageEntityCode' => '</code>',
'messageEntityPre' => '</pre>',
'messageEntityTextUrl', 'messageEntityUrl', 'messageEntityEmail', 'messageEntityMention', 'messageEntityPhone' => '</a>',
'messageEntityStrike' => '</s>',
'messageEntityUnderline' => '</u>',
'messageEntityBlockquote' => '</blockquote>',
'messageEntitySpoiler' => $allowTelegramTags ? '</tg-spoiler>' : '',
'messageEntityCustomEmoji' => $allowTelegramTags ? "</tg-emoji>" : '',
'messageEntityMentionName', 'inputMessageEntityMentionName' => $allowTelegramTags ? '</a>' : '',
$insertions[$offset] = match (true) {
$entity instanceof Bold => '</b>',
$entity instanceof Italic => '</i>',
$entity instanceof Code => '</code>',
$entity instanceof Pre => '</pre>',
$entity instanceof TextUrl, $entity instanceof Url, $entity instanceof Email, $entity instanceof Mention, $entity instanceof Phone => '</a>',
$entity instanceof Strike => '</s>',
$entity instanceof Underline => '</u>',
$entity instanceof Blockquote => '</blockquote>',
$entity instanceof Spoiler => $allowTelegramTags ? '</tg-spoiler>' : '',
$entity instanceof CustomEmoji => $allowTelegramTags ? "</tg-emoji>" : '',
$entity instanceof MentionName => $allowTelegramTags ? '</a>' : '',
default => '',
} . ($insertions[$offset] ?? '');
}