Skip to content

Commit a15282b

Browse files
authored
Merge pull request #1209 from noplanman/improve-psr4-command-classes
Improve PSR4 command classes
2 parents 6b401cb + bb445a0 commit a15282b

File tree

8 files changed

+286
-138
lines changed

8 files changed

+286
-138
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Exclamation symbols (:exclamation:) note something of importance e.g. breaking c
88
- [:ledger: View file changes][Unreleased][:page_with_curl: DB migration script][unreleased-sql-migration]
99
### Added
1010
- Bot API 5.1 (ChatMember Update types, Improved Invite Links, Voice Chat). (@massadm, @noplanman)
11+
- Method to allow adding command classes directly. (@alligator77, @noplanman)
1112
### Changed
1213
### Deprecated
1314
- `Telegram::handleGetUpdates` method should be passed a `$data` array for parameters.

README.md

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -525,27 +525,7 @@ With [admin commands](#admin-commands) you can manage your channels directly wit
525525

526526
The bot is able to recognise commands in a chat with multiple bots (/command@mybot).
527527

528-
It can execute commands that get triggered by chat events.
529-
530-
Here's the list:
531-
532-
- *StartCommand.php* (A new user starts to use the bot.)
533-
- *NewChatMembersCommand.php* (A new member(s) was added to the group, information about them.)
534-
- *LeftChatMemberCommand.php* (A member was removed from the group, information about them.)
535-
- *NewChatTitleCommand.php* (A chat title was changed to this value.)
536-
- *NewChatPhotoCommand.php* (A chat photo was changed to this value.)
537-
- *DeleteChatPhotoCommand.php* (Service message: the chat photo was deleted.)
538-
- *GroupChatCreatedCommand.php* (Service message: the group has been created.)
539-
- *SupergroupChatCreatedCommand.php* (Service message: the supergroup has been created.)
540-
- *ChannelChatCreatedCommand.php* (Service message: the channel has been created.)
541-
- *MigrateToChatIdCommand.php* (The group has been migrated to a supergroup with the specified identifier.)
542-
- *MigrateFromChatIdCommand.php* (The supergroup has been migrated from a group with the specified identifier.)
543-
- *PinnedMessageCommand.php* (Specified message was pinned.)
544-
545-
- *GenericmessageCommand.php* (Handle any type of message.)
546-
- *GenericCommand.php* (Handle commands that don't exist or to use commands as a variable.)
547-
- Favourite colour? */black, /red*
548-
- Favourite number? */1, /134*
528+
It can also execute commands that get triggered by events, so-called Service Messages.
549529

550530
### Custom Commands
551531

@@ -554,6 +534,18 @@ There is a guide to help you [create your own commands][wiki-create-your-own-com
554534

555535
Also, be sure to have a look at the [example commands][ExampleCommands-folder] to learn more about custom commands and how they work.
556536

537+
You can add your custom commands in different ways:
538+
539+
```php
540+
// Add a folder that contains command files
541+
$telegram->addCommandsPath('/path/to/command/files');
542+
//$telegram->addCommandsPaths(['/path/to/command/files', '/another/path']);
543+
544+
// Add a command directly using the class name
545+
$telegram->addCommandClass(MyCommand::class);
546+
//$telegram->addCommandClasses([MyCommand::class, MyOtherCommand::class]);
547+
```
548+
557549
### Commands Configuration
558550

559551
With this method you can set some command specific parameters, for example:

src/Commands/Command.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@
4343
*/
4444
abstract class Command
4545
{
46+
/**
47+
* Auth level for user commands
48+
*/
49+
public const AUTH_USER = 'User';
50+
51+
/**
52+
* Auth level for system commands
53+
*/
54+
public const AUTH_SYSTEM = 'System';
55+
56+
/**
57+
* Auth level for admin commands
58+
*/
59+
public const AUTH_ADMIN = 'Admin';
60+
4661
/**
4762
* Telegram object
4863
*

src/Telegram.php

Lines changed: 87 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,6 @@
3030

3131
class Telegram
3232
{
33-
/**
34-
* Auth name for user commands
35-
*/
36-
const AUTH_USER = 'User';
37-
/**
38-
* Auth name tof system commands
39-
*/
40-
const AUTH_SYSTEM = 'System';
41-
/**
42-
* Auth name for admin commands
43-
*/
44-
const AUTH_ADMIN = 'Admin';
45-
4633
/**
4734
* Version
4835
*
@@ -86,22 +73,23 @@ class Telegram
8673
protected $commands_paths = [];
8774

8875
/**
89-
* Custom commands class names
76+
* Custom command class names
9077
* ```
9178
* [
92-
* 'User' => [
93-
* //commandName => className
94-
* 'start' => 'name\space\to\StartCommand',
95-
* ],
96-
* 'Admin' => [], //etc
79+
* 'User' => [
80+
* // command_name => command_class
81+
* 'start' => 'name\space\to\StartCommand',
82+
* ],
83+
* 'Admin' => [], //etc
9784
* ]
9885
* ```
86+
*
9987
* @var array
10088
*/
101-
protected $commandsClasses = [
102-
self::AUTH_USER => [],
103-
self::AUTH_ADMIN => [],
104-
self::AUTH_SYSTEM => [],
89+
protected $command_classes = [
90+
Command::AUTH_USER => [],
91+
Command::AUTH_ADMIN => [],
92+
Command::AUTH_SYSTEM => [],
10593
];
10694

10795
/**
@@ -318,22 +306,37 @@ public function getCommandsList(): array
318306

319307
/**
320308
* Get classname of predefined commands
321-
* @see commandsClasses
322-
* @param string $auth Auth of command
323-
* @param string $command Command name
309+
*
310+
* @see command_classes
311+
*
312+
* @param string $auth Auth of command
313+
* @param string $command Command name
314+
* @param string $filepath Path to the command file
324315
*
325316
* @return string|null
326317
*/
327-
public function getCommandClassName(string $auth, string $command): ?string
318+
public function getCommandClassName(string $auth, string $command, string $filepath = ''): ?string
328319
{
329320
$command = mb_strtolower($command);
330-
$auth = $this->ucFirstUnicode($auth);
321+
$auth = $this->ucFirstUnicode($auth);
331322

332-
if (!empty($this->commandsClasses[$auth][$command])) {
333-
$className = $this->commandsClasses[$auth][$command];
334-
if (class_exists($className)){
335-
return $className;
336-
}
323+
// First, check for directly assigned command class.
324+
if ($command_class = $this->command_classes[$auth][$command] ?? null) {
325+
return $command_class;
326+
}
327+
328+
// Start with default namespace.
329+
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
330+
331+
// Check if we can get the namespace from the file (if passed).
332+
if ($filepath && !($command_namespace = $this->getFileNamespace($filepath))) {
333+
return null;
334+
}
335+
336+
$command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command';
337+
338+
if (class_exists($command_class)) {
339+
return $command_class;
337340
}
338341

339342
return null;
@@ -353,43 +356,24 @@ public function getCommandObject(string $command, string $filepath = ''): ?Comma
353356
return $this->commands_objects[$command];
354357
}
355358

356-
$which = [self::AUTH_SYSTEM];
357-
$this->isAdmin() && $which[] = self::AUTH_ADMIN;
358-
$which[] = self::AUTH_USER;
359-
360-
foreach ($which as $auth)
361-
{
362-
if (!($command_class = $this->getCommandClassName($auth, $command)))
363-
{
364-
if ($filepath) {
365-
$command_namespace = $this->getFileNamespace($filepath);
366-
} else {
367-
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
368-
}
369-
$command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command';
370-
}
359+
$which = [Command::AUTH_SYSTEM];
360+
$this->isAdmin() && $which[] = Command::AUTH_ADMIN;
361+
$which[] = Command::AUTH_USER;
362+
363+
foreach ($which as $auth) {
364+
$command_class = $this->getCommandClassName($auth, $command, $filepath);
371365

372-
if (class_exists($command_class)) {
366+
if ($command_class) {
373367
$command_obj = new $command_class($this, $this->update);
374368

375-
switch ($auth) {
376-
case self::AUTH_SYSTEM:
377-
if ($command_obj instanceof SystemCommand) {
378-
return $command_obj;
379-
}
380-
break;
381-
382-
case self::AUTH_ADMIN:
383-
if ($command_obj instanceof AdminCommand) {
384-
return $command_obj;
385-
}
386-
break;
387-
388-
case self::AUTH_USER:
389-
if ($command_obj instanceof UserCommand) {
390-
return $command_obj;
391-
}
392-
break;
369+
if ($auth === Command::AUTH_SYSTEM && $command_obj instanceof SystemCommand) {
370+
return $command_obj;
371+
}
372+
if ($auth === Command::AUTH_ADMIN && $command_obj instanceof AdminCommand) {
373+
return $command_obj;
374+
}
375+
if ($auth === Command::AUTH_USER && $command_obj instanceof UserCommand) {
376+
return $command_obj;
393377
}
394378
}
395379
}
@@ -605,7 +589,7 @@ public function processUpdate(Update $update): ServerResponse
605589
$reason = 'Update denied by update_filter';
606590
try {
607591
$allowed = (bool) call_user_func_array($this->update_filter, [$update, $this, &$reason]);
608-
} catch (\Exception $e) {
592+
} catch (Exception $e) {
609593
$allowed = false;
610594
}
611595

@@ -793,49 +777,54 @@ public function isDbEnabled(): bool
793777
}
794778

795779
/**
796-
* Add a single custom commands class
780+
* Add a single custom command class
781+
*
782+
* @param string $command_class Full command class name
797783
*
798-
* @param string $className Set full classname
799784
* @return Telegram
800785
*/
801-
public function addCommandsClass(string $className): Telegram
786+
public function addCommandClass(string $command_class): Telegram
802787
{
803-
if (!$className || !class_exists($className))
804-
{
805-
$error = 'Command class name: "' . $className . '" does not exist.';
788+
if (!$command_class || !class_exists($command_class)) {
789+
$error = sprintf('Command class "%s" does not exist.', $command_class);
806790
TelegramLog::error($error);
807791
throw new InvalidArgumentException($error);
808792
}
809793

810-
if (!is_array($this->commandsClasses))
811-
{
812-
$this->commandsClasses = [];
813-
}
814-
815-
if (!is_a($className, Command::class, true)) {
816-
$error = 'Command class is not a base command class';
794+
if (!is_a($command_class, Command::class, true)) {
795+
$error = sprintf('Command class "%s" does not extend "%s".', $command_class, Command::class);
817796
TelegramLog::error($error);
818797
throw new InvalidArgumentException($error);
819798
}
820799

821-
$commandObject = new $className($this);
800+
// Dummy object to get data from.
801+
$command_object = new $command_class($this);
822802

823-
$command = $commandObject->getName();
824803
$auth = null;
825-
switch (true) {
826-
case $commandObject->isSystemCommand():
827-
$auth = self::AUTH_SYSTEM;
828-
break;
829-
case $commandObject->isAdminCommand():
830-
$auth = self::AUTH_ADMIN;
831-
break;
832-
case $commandObject->isUserCommand():
833-
$auth = self::AUTH_USER;
834-
break;
835-
}
804+
$command_object->isSystemCommand() && $auth = Command::AUTH_SYSTEM;
805+
$command_object->isAdminCommand() && $auth = Command::AUTH_ADMIN;
806+
$command_object->isUserCommand() && $auth = Command::AUTH_USER;
836807

837808
if ($auth) {
838-
$this->commandsClasses[$auth][$command] = $className;
809+
$command = mb_strtolower($command_object->getName());
810+
811+
$this->command_classes[$auth][$command] = $command_class;
812+
}
813+
814+
return $this;
815+
}
816+
817+
/**
818+
* Add multiple custom command classes
819+
*
820+
* @param array $command_classes List of full command class names
821+
*
822+
* @return Telegram
823+
*/
824+
public function addCommandClasses(array $command_classes): Telegram
825+
{
826+
foreach ($command_classes as $command_class) {
827+
$this->addCommandClass($command_class);
839828
}
840829

841830
return $this;
@@ -892,13 +881,13 @@ public function getCommandsPaths(): array
892881
}
893882

894883
/**
895-
* Return the list of commands classes
884+
* Return the list of command classes
896885
*
897886
* @return array
898887
*/
899-
public function getCommandsClasses(): array
888+
public function getCommandClasses(): array
900889
{
901-
return $this->commandsClasses;
890+
return $this->command_classes;
902891
}
903892

904893
/**
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 Dummy\AdminCommands;
13+
14+
use Longman\TelegramBot\Commands\AdminCommand;
15+
use Longman\TelegramBot\Entities\ServerResponse;
16+
use Longman\TelegramBot\Request;
17+
18+
/**
19+
* Test "/dummyadmin" command
20+
*/
21+
class DummyAdminCommand extends AdminCommand
22+
{
23+
/**
24+
* @var string
25+
*/
26+
protected $name = 'dummyadmin';
27+
28+
/**
29+
* @var string
30+
*/
31+
protected $description = 'Dummy AdminCommand';
32+
33+
/**
34+
* @var string
35+
*/
36+
protected $usage = '/dummyadmin';
37+
38+
/**
39+
* Command execute method
40+
*
41+
* @return mixed
42+
*/
43+
public function execute(): ServerResponse
44+
{
45+
return Request::emptyResponse();
46+
}
47+
}

0 commit comments

Comments
 (0)