Skip to content

Commit 6b401cb

Browse files
authored
Merge pull request #1207 from isn-lab/master
PSR4 command classes include
2 parents cb9868e + 8365717 commit 6b401cb

File tree

2 files changed

+182
-14
lines changed

2 files changed

+182
-14
lines changed

src/Telegram.php

Lines changed: 133 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
1616

1717
use Exception;
18+
use InvalidArgumentException;
1819
use Longman\TelegramBot\Commands\AdminCommand;
1920
use Longman\TelegramBot\Commands\Command;
2021
use Longman\TelegramBot\Commands\SystemCommand;
@@ -29,6 +30,19 @@
2930

3031
class 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
*

tests/Unit/TelegramTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
namespace Longman\TelegramBot\Tests\Unit;
1313

1414
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
15+
use Exception;
16+
use Longman\TelegramBot\Commands\AdminCommands\WhoisCommand;
17+
use Longman\TelegramBot\Commands\UserCommands\StartCommand;
1518
use Longman\TelegramBot\Entities\Update;
1619
use Longman\TelegramBot\Exception\TelegramException;
1720
use Longman\TelegramBot\Telegram;
@@ -133,6 +136,34 @@ public function testAddCustomCommandsPaths(): void
133136
self::assertCount(4, $tg->getCommandsPaths());
134137
}
135138

139+
public function testAddCustomCommandsClass(): void
140+
{
141+
$tg = $this->telegram;
142+
$class = StartCommand::class;
143+
$aClass = WhoisCommand::class;
144+
145+
self::assertCount(3, $tg->getCommandsClasses());
146+
147+
try {
148+
$tg->addCommandsClass('not\exist\Class');
149+
}
150+
catch (\Exception $ex){}
151+
self::assertCount(0, $tg->getCommandsClasses()['User']);
152+
153+
try {
154+
$tg->addCommandsClass('');
155+
}
156+
catch (\Exception $ex){}
157+
self::assertCount(0, $tg->getCommandsClasses()['User']);
158+
159+
$tg->addCommandsClass($class);
160+
self::assertCount(1, $tg->getCommandsClasses()['User']);
161+
162+
$tg->addCommandsClass($aClass);
163+
self::assertCount(1, $tg->getCommandsClasses()['Admin']);
164+
165+
}
166+
136167
public function testSettingDownloadUploadPaths(): void
137168
{
138169
self::assertEmpty($this->telegram->getDownloadPath());
@@ -152,6 +183,24 @@ public function testGetCommandsList(): void
152183
self::assertNotCount(0, $commands);
153184
}
154185

186+
public function testGetCommandClass(): void
187+
{
188+
$className = StartCommand::class;
189+
$commands = $this->telegram->getCommandsClasses();
190+
self::assertIsArray($commands);
191+
self::assertCount(3, $commands);
192+
193+
$class = $this->telegram->getCommandClassName('user', 'notexist');
194+
self::assertNull($class);
195+
196+
$this->telegram->addCommandsClass($className);
197+
$class = $this->telegram->getCommandClassName('user', 'start');
198+
self::assertNotNull($class);
199+
200+
self::assertSame($className, $class);
201+
202+
}
203+
155204
public function testUpdateFilter(): void
156205
{
157206
$rawUpdate = '{

0 commit comments

Comments
 (0)