Message::getFullCommand()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 12
ccs 3
cts 3
cp 1
crap 3
rs 10
1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot\Entities;
13
14
use Longman\TelegramBot\Entities\Games\Game;
15
use Longman\TelegramBot\Entities\Payments\Invoice;
16
use Longman\TelegramBot\Entities\Payments\SuccessfulPayment;
17
use Longman\TelegramBot\Entities\TelegramPassport\PassportData;
18
19
/**
20
 * Class Message
21
 *
22
 * Represents a message
23
 *
24
 * @link https://core.telegram.org/bots/api#message
25
 *
26
 * @method int                                    getMessageId()                              Unique message identifier
27
 * @method User                                   getFrom()                                   Optional. Sender, can be empty for messages sent to channels
28
 * @method Chat                                   getSenderChat()                             Optional. Sender of the message, sent on behalf of a chat. The channel itself for channel messages. The supergroup itself for messages from anonymous group administrators. The linked channel for messages automatically forwarded to the discussion group
29
 * @method int                                    getDate()                                   Date the message was sent in Unix time
30
 * @method Chat                                   getChat()                                   Conversation the message belongs to
31
 * @method User                                   getForwardFrom()                            Optional. For forwarded messages, sender of the original message
32
 * @method Chat                                   getForwardFromChat()                        Optional. For messages forwarded from a channel, information about the original channel
33
 * @method int                                    getForwardFromMessageId()                   Optional. For forwarded channel posts, identifier of the original message in the channel
34
 * @method string                                 getForwardSignature()                       Optional. For messages forwarded from channels, signature of the post author if present
35
 * @method string                                 getForwardSenderName()                      Optional. Sender's name for messages forwarded from users who disallow adding a link to their account in forwarded messages
36
 * @method int                                    getForwardDate()                            Optional. For forwarded messages, date the original message was sent in Unix time
37
 * @method ReplyToMessage                         getReplyToMessage()                         Optional. For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply.
38
 * @method User                                   getViaBot()                                 Optional. Bot through which the message was sent
39
 * @method int                                    getEditDate()                               Optional. Date the message was last edited in Unix time
40
 * @method string                                 getMediaGroupId()                           Optional. The unique identifier of a media message group this message belongs to
41
 * @method string                                 getAuthorSignature()                        Optional. Signature of the post author for messages in channels
42
 * @method MessageEntity[]                        getEntities()                               Optional. For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text
43
 * @method MessageEntity[]                        getCaptionEntities()                        Optional. For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear in the caption
44
 * @method Audio                                  getAudio()                                  Optional. Message is an audio file, information about the file
45
 * @method Document                               getDocument()                               Optional. Message is a general file, information about the file
46
 * @method Animation                              getAnimation()                              Optional. Message is an animation, information about the animation. For backward compatibility, when this field is set, the document field will also be set
47
 * @method Game                                   getGame()                                   Optional. Message is a game, information about the game.
48
 * @method PhotoSize[]                            getPhoto()                                  Optional. Message is a photo, available sizes of the photo
49
 * @method Sticker                                getSticker()                                Optional. Message is a sticker, information about the sticker
50
 * @method Video                                  getVideo()                                  Optional. Message is a video, information about the video
51
 * @method Voice                                  getVoice()                                  Optional. Message is a voice message, information about the file
52
 * @method VideoNote                              getVideoNote()                              Optional. Message is a video note message, information about the video
53
 * @method string                                 getCaption()                                Optional. Caption for the document, photo or video, 0-200 characters
54
 * @method Contact                                getContact()                                Optional. Message is a shared contact, information about the contact
55
 * @method Location                               getLocation()                               Optional. Message is a shared location, information about the location
56
 * @method Venue                                  getVenue()                                  Optional. Message is a venue, information about the venue
57
 * @method Poll                                   getPoll()                                   Optional. Message is a native poll, information about the poll
58
 * @method Dice                                   getDice()                                   Optional. Message is a dice with random value, 1-6 for “🎲” and “🎯” base emoji, 1-5 for “🏀” and “⚽” base emoji, 1-64 for “🎰” base emoji
59
 * @method User[]                                 getNewChatMembers()                         Optional. A new member(s) was added to the group, information about them (one of this members may be the bot itself)
60
 * @method User                                   getLeftChatMember()                         Optional. A member was removed from the group, information about them (this member may be the bot itself)
61
 * @method string                                 getNewChatTitle()                           Optional. A chat title was changed to this value
62
 * @method PhotoSize[]                            getNewChatPhoto()                           Optional. A chat photo was changed to this value
63
 * @method MessageAutoDeleteTimerChanged          getMessageAutoDeleteTimerChanged()          Optional. Service message: auto-delete timer settings changed in the chat
64
 * @method bool                                   getDeleteChatPhoto()                        Optional. Service message: the chat photo was deleted
65
 * @method bool                                   getGroupChatCreated()                       Optional. Service message: the group has been created
66
 * @method bool                                   getSupergroupChatCreated()                  Optional. Service message: the supergroup has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a supergroup when it is created. It can only be found in reply_to_message if someone replies to a very first message in a directly created supergroup.
67
 * @method bool                                   getChannelChatCreated()                     Optional. Service message: the channel has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel.
68
 * @method int                                    getMigrateToChatId()                        Optional. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
69
 * @method int                                    getMigrateFromChatId()                      Optional. The supergroup has been migrated from a group with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
70
 * @method Message                                getPinnedMessage()                          Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply.
71
 * @method Invoice                                getInvoice()                                Optional. Message is an invoice for a payment, information about the invoice.
72
 * @method SuccessfulPayment                      getSuccessfulPayment()                      Optional. Message is a service message about a successful payment, information about the payment.
73
 * @method string                                 getConnectedWebsite()                       Optional. The domain name of the website on which the user has logged in.
74
 * @method PassportData                           getPassportData()                           Optional. Telegram Passport data
75
 * @method ProximityAlertTriggered                getProximityAlertTriggered()                Optional. Service message. A user in the chat triggered another user's proximity alert while sharing Live Location.
76
 * @method VoiceChatStarted                       getVoiceChatStarted()                       Optional. Service message: voice chat started
77
 * @method VoiceChatEnded                         getVoiceChatEnded()                         Optional. Service message: voice chat ended
78
 * @method VoiceChatParticipantsInvited           getVoiceChatParticipantsInvited()           Optional. Service message: new participants invited to a voice chat
79
 * @method InlineKeyboard                         getReplyMarkup()                            Optional. Inline keyboard attached to the message. login_url buttons are represented as ordinary url buttons.
80 11
 */
81
class Message extends Entity
82
{
83 11
    /**
84
     * {@inheritdoc}
85
     */
86
    protected function subEntities(): array
87
    {
88
        return [
89
            'from'                              => User::class,
90
            'sender_chat'                       => Chat::class,
91
            'chat'                              => Chat::class,
92
            'forward_from'                      => User::class,
93
            'forward_from_chat'                 => Chat::class,
94
            'reply_to_message'                  => ReplyToMessage::class,
95
            'via_bot'                           => User::class,
96
            'entities'                          => [MessageEntity::class],
97
            'caption_entities'                  => [MessageEntity::class],
98
            'audio'                             => Audio::class,
99
            'document'                          => Document::class,
100
            'animation'                         => Animation::class,
101
            'game'                              => Game::class,
102
            'photo'                             => [PhotoSize::class],
103
            'sticker'                           => Sticker::class,
104
            'video'                             => Video::class,
105
            'voice'                             => Voice::class,
106
            'video_note'                        => VideoNote::class,
107
            'contact'                           => Contact::class,
108
            'location'                          => Location::class,
109
            'venue'                             => Venue::class,
110
            'poll'                              => Poll::class,
111
            'dice'                              => Dice::class,
112
            'new_chat_members'                  => [User::class],
113
            'left_chat_member'                  => User::class,
114
            'new_chat_photo'                    => [PhotoSize::class],
115
            'message_auto_delete_timer_changed' => MessageAutoDeleteTimerChanged::class,
116
            'pinned_message'                    => __CLASS__,
117
            'invoice'                           => Invoice::class,
118
            'successful_payment'                => SuccessfulPayment::class,
119
            'passport_data'                     => PassportData::class,
120
            'proximity_alert_triggered'         => ProximityAlertTriggered::class,
121
            'voice_chat_started'                => VoiceChatStarted::class,
122
            'voice_chat_ended'                  => VoiceChatEnded::class,
123 2
            'voice_chat_participants_invited'   => VoiceChatParticipantsInvited::class,
124
            'reply_markup'                      => InlineKeyboard::class,
125 2
        ];
126 2
    }
127 2
128
    /**
129
     * return the entire command like /echo or /echo@bot1 if specified
130 2
     *
131 2
     * @return string|null
132
     */
133
    public function getFullCommand(): ?string
134 2
    {
135
        $text = $this->getProperty('text');
136
        if (strpos($text, '/') !== 0) {
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type null; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

136
        if (strpos(/** @scrutinizer ignore-type */ $text, '/') !== 0) {
Loading history...
137
            return null;
138
        }
139
140
        $no_EOL   = strtok($text, PHP_EOL);
141
        $no_space = strtok($text, ' ');
142 2
143
        //try to understand which separator \n or space divide /command from text
144 2
        return strlen($no_space) < strlen($no_EOL) ? $no_space : $no_EOL;
145
    }
146
147
    /**
148 2
     * Get command
149 2
     *
150 2
     * @return string|null
151
     */
152 2
    public function getCommand(): ?string
153
    {
154
        if ($command = $this->getProperty('command')) {
155 2
            return $command;
156 2
        }
157
158 2
        $full_command = $this->getFullCommand();
159
        if (strpos($full_command, '/') !== 0) {
0 ignored issues
show
Bug introduced by
It seems like $full_command can also be of type null; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

159
        if (strpos(/** @scrutinizer ignore-type */ $full_command, '/') !== 0) {
Loading history...
160
            return null;
161 1
        }
162
        $full_command = substr($full_command, 1);
0 ignored issues
show
Bug introduced by
It seems like $full_command can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
        $full_command = substr(/** @scrutinizer ignore-type */ $full_command, 1);
Loading history...
163 1
164
        //check if command is followed by bot username
165
        $split_cmd = explode('@', $full_command);
166
        if (!isset($split_cmd[1])) {
167
            //command is not followed by name
168
            return $full_command;
169
        }
170
171
        if (strtolower($split_cmd[1]) === strtolower($this->getBotUsername())) {
172
            //command is addressed to me
173
            return $split_cmd[0];
174
        }
175
176 9
        return null;
177
    }
178 9
179
    /**
180 9
     * For text messages, the actual UTF-8 text of the message, 0-4096 characters.
181 1
     *
182 1
     * @param bool $without_cmd
183
     *
184
     * @return string|null
185 1
     */
186
    public function getText($without_cmd = false): ?string
187
    {
188 9
        $text = $this->getProperty('text');
189
190
        if ($without_cmd && $command = $this->getFullCommand()) {
191
            if (strlen($command) + 1 < strlen($text)) {
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type null; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

191
            if (strlen($command) + 1 < strlen(/** @scrutinizer ignore-type */ $text)) {
Loading history...
192
                return substr($text, strlen($command) + 1);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

192
                return substr(/** @scrutinizer ignore-type */ $text, strlen($command) + 1);
Loading history...
193
            }
194
195
            return '';
196
        }
197
198
        return $text;
199
    }
200
201
    /**
202
     * Bot added in chat
203
     *
204
     * @return bool
205
     */
206
    public function botAddedInChat(): bool
207
    {
208
        foreach ($this->getNewChatMembers() as $member) {
0 ignored issues
show
Bug introduced by
The method getNewChatMembers() does not exist on Longman\TelegramBot\Entities\Message. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
        foreach ($this->/** @scrutinizer ignore-call */ getNewChatMembers() as $member) {
Loading history...
209
            if ($member instanceof User && $member->getUsername() === $this->getBotUsername()) {
210
                return true;
211
            }
212 1
        }
213
214
        return false;
215 1
    }
216
217
    /**
218
     * Detect type based on properties.
219
     *
220
     * @return string
221
     */
222
    public function getType(): string
223
    {
224
        $types = [
225
            'text',
226
            'audio',
227
            'animation',
228
            'document',
229
            'game',
230
            'photo',
231
            'sticker',
232
            'video',
233
            'voice',
234
            'video_note',
235
            'contact',
236
            'location',
237
            'venue',
238
            'poll',
239
            'new_chat_members',
240
            'left_chat_member',
241
            'new_chat_title',
242
            'new_chat_photo',
243
            'delete_chat_photo',
244
            'group_chat_created',
245
            'supergroup_chat_created',
246
            'channel_chat_created',
247 1
            'message_auto_delete_timer_changed',
248 1
            'migrate_to_chat_id',
249 1
            'migrate_from_chat_id',
250 1
            'pinned_message',
251 1
            'invoice',
252
            'successful_payment',
253
            'passport_data',
254 1
            'proximity_alert_triggered',
255
            'voice_chat_started',
256
            'voice_chat_ended',
257
            'voice_chat_participants_invited',
258 1
            'reply_markup',
259
        ];
260
261
        $is_command = strlen($this->getCommand()) > 0;
0 ignored issues
show
Bug introduced by
It seems like $this->getCommand() can also be of type null; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

261
        $is_command = strlen(/** @scrutinizer ignore-type */ $this->getCommand()) > 0;
Loading history...
262
        foreach ($types as $type) {
263
            if ($this->getProperty($type) !== null) {
264
                if ($is_command && $type === 'text') {
265
                    return 'command';
266
                }
267
268
                return $type;
269
            }
270
        }
271
272
        return 'message';
273
    }
274
}
275