1515defined ('TB_BASE_COMMANDS_PATH ' ) || define ('TB_BASE_COMMANDS_PATH ' , TB_BASE_PATH . '/Commands ' );
1616
1717use Exception ;
18+ use InvalidArgumentException ;
1819use Longman \TelegramBot \Commands \AdminCommand ;
1920use Longman \TelegramBot \Commands \Command ;
2021use Longman \TelegramBot \Commands \SystemCommand ;
2930
3031class Telegram
3132{
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+
3246 /**
3347 * Version
3448 *
@@ -71,6 +85,25 @@ class Telegram
7185 */
7286 protected $ commands_paths = [];
7387
88+ /**
89+ * Custom commands class names
90+ * ```
91+ * [
92+ * 'User' => [
93+ * //commandName => className
94+ * 'start' => 'name\space\to\StartCommand',
95+ * ],
96+ * 'Admin' => [], //etc
97+ * ]
98+ * ```
99+ * @var array
100+ */
101+ protected $ commandsClasses = [
102+ self ::AUTH_USER => [],
103+ self ::AUTH_ADMIN => [],
104+ self ::AUTH_SYSTEM => [],
105+ ];
106+
74107 /**
75108 * Custom commands objects
76109 *
@@ -283,6 +316,29 @@ public function getCommandsList(): array
283316 return $ commands ;
284317 }
285318
319+ /**
320+ * Get classname of predefined commands
321+ * @see commandsClasses
322+ * @param string $auth Auth of command
323+ * @param string $command Command name
324+ *
325+ * @return string|null
326+ */
327+ public function getCommandClassName (string $ auth , string $ command ): ?string
328+ {
329+ $ command = mb_strtolower ($ command );
330+ $ auth = $ this ->ucFirstUnicode ($ auth );
331+
332+ if (!empty ($ this ->commandsClasses [$ auth ][$ command ])) {
333+ $ className = $ this ->commandsClasses [$ auth ][$ command ];
334+ if (class_exists ($ className )){
335+ return $ className ;
336+ }
337+ }
338+
339+ return null ;
340+ }
341+
286342 /**
287343 * Get an object instance of the passed command
288344 *
@@ -297,35 +353,39 @@ public function getCommandObject(string $command, string $filepath = ''): ?Comma
297353 return $ this ->commands_objects [$ command ];
298354 }
299355
300- $ which = ['System ' ];
301- $ this ->isAdmin () && $ which [] = 'Admin ' ;
302- $ which [] = 'User ' ;
303-
304- foreach ($ which as $ auth ) {
305- if ($ filepath ) {
306- $ command_namespace = $ this ->getFileNamespace ($ filepath );
307- } else {
308- $ command_namespace = __NAMESPACE__ . '\\Commands \\' . $ auth . 'Commands ' ;
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 ' ;
309370 }
310- $ command_class = $ command_namespace . '\\' . $ this ->ucFirstUnicode ($ command ) . 'Command ' ;
311371
312372 if (class_exists ($ command_class )) {
313373 $ command_obj = new $ command_class ($ this , $ this ->update );
314374
315375 switch ($ auth ) {
316- case ' System ' :
376+ case self :: AUTH_SYSTEM :
317377 if ($ command_obj instanceof SystemCommand) {
318378 return $ command_obj ;
319379 }
320380 break ;
321381
322- case ' Admin ' :
382+ case self :: AUTH_ADMIN :
323383 if ($ command_obj instanceof AdminCommand) {
324384 return $ command_obj ;
325385 }
326386 break ;
327387
328- case ' User ' :
388+ case self :: AUTH_USER :
329389 if ($ command_obj instanceof UserCommand) {
330390 return $ command_obj ;
331391 }
@@ -347,7 +407,7 @@ public function getCommandObject(string $command, string $filepath = ''): ?Comma
347407 protected function getFileNamespace (string $ src ): ?string
348408 {
349409 $ content = file_get_contents ($ src );
350- if (preg_match ('#^namespace\s+(.+?);#m ' , $ content , $ m )) {
410+ if (preg_match ('#^\s+ namespace\s+(.+?);#m ' , $ content , $ m )) {
351411 return $ m [1 ];
352412 }
353413
@@ -732,6 +792,55 @@ public function isDbEnabled(): bool
732792 return $ this ->mysql_enabled ;
733793 }
734794
795+ /**
796+ * Add a single custom commands class
797+ *
798+ * @param string $className Set full classname
799+ * @return Telegram
800+ */
801+ public function addCommandsClass (string $ className ): Telegram
802+ {
803+ if (!$ className || !class_exists ($ className ))
804+ {
805+ $ error = 'Command class name: " ' . $ className . '" does not exist. ' ;
806+ TelegramLog::error ($ error );
807+ throw new InvalidArgumentException ($ error );
808+ }
809+
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 ' ;
817+ TelegramLog::error ($ error );
818+ throw new InvalidArgumentException ($ error );
819+ }
820+
821+ $ commandObject = new $ className ($ this );
822+
823+ $ command = $ commandObject ->getName ();
824+ $ 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+ }
836+
837+ if ($ auth ) {
838+ $ this ->commandsClasses [$ auth ][$ command ] = $ className ;
839+ }
840+
841+ return $ this ;
842+ }
843+
735844 /**
736845 * Add a single custom commands path
737846 *
@@ -782,6 +891,16 @@ public function getCommandsPaths(): array
782891 return $ this ->commands_paths ;
783892 }
784893
894+ /**
895+ * Return the list of commands classes
896+ *
897+ * @return array
898+ */
899+ public function getCommandsClasses (): array
900+ {
901+ return $ this ->commandsClasses ;
902+ }
903+
785904 /**
786905 * Set custom upload path
787906 *
0 commit comments