From b1157b5616db5c8cf04678a0ae0fb56b14766835 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Fri, 7 Oct 2022 16:58:15 +0200 Subject: [PATCH 1/3] Enable using commands containing underscores --- src/Telegram.php | 63 +++++++++++++++++-- .../CustomTestCommands/DummyAdminCommand.php | 6 +- .../CustomTestCommands/DummySystemCommand.php | 6 +- .../CustomTestCommands/DummyUserCommand.php | 6 +- tests/Unit/TelegramTest.php | 6 +- 5 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/Telegram.php b/src/Telegram.php index 515446ad..0e2df044 100644 --- a/src/Telegram.php +++ b/src/Telegram.php @@ -283,10 +283,9 @@ public function getCommandsList(): array foreach ($files as $file) { //Remove "Command.php" from filename - $command = $this->sanitizeCommand(substr($file->getFilename(), 0, -11)); - $command_name = mb_strtolower($command); + $command = $this->classNameToCommandName(substr($file->getFilename(), 0, -4)); - if (array_key_exists($command_name, $commands)) { + if (array_key_exists($command, $commands)) { continue; } @@ -294,7 +293,7 @@ public function getCommandsList(): array $command_obj = $this->getCommandObject($command, $file->getPathname()); if ($command_obj instanceof Command) { - $commands[$command_name] = $command_obj; + $commands[$command] = $command_obj; } } } catch (Exception $e) { @@ -334,7 +333,7 @@ public function getCommandClassName(string $auth, string $command, string $filep return null; } - $command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command'; + $command_class = $command_namespace . '\\' . $this->commandNameToClassName($command); if (class_exists($command_class)) { return $command_class; @@ -678,7 +677,7 @@ public function executeCommand(string $command): ServerResponse } /** - * Sanitize Command + * @deprecated * * @param string $command * @@ -1285,4 +1284,56 @@ public function getUpdateFilter(): ?callable { return $this->update_filter; } + + /** + * Converts the name of a class into the name of a command. + * + * @param string $class For example FooBarCommand + * + * @return string for example foo_bar. In case of errors, returns an empty string + */ + protected function classNameToCommandName(string $class): string + { + if (!preg_match('/^(.+)Command$/', $class, $matches)) { + return ''; + } + $temp = $matches[1]; + $chunks = []; + $currentUpperCaseLetter = ''; + while ($temp !== '') { + if (!preg_match('/\p{Lu}/u', $temp, $match, PREG_OFFSET_CAPTURE)) { + break; + } + // $match[0][0] contains first upper case character + // $match[0][1] contains the start position (in bytes) of the first upper case character + [$upperCaseLetter, $upperCaseLetterOffset] = $match[0]; + if ($upperCaseLetterOffset > 0) { + $chunks[] = $currentUpperCaseLetter . substr($temp, 0, $upperCaseLetterOffset); + } elseif ($currentUpperCaseLetter !== '') { + $chunks[] = $currentUpperCaseLetter; + } + $temp = substr($temp, $upperCaseLetterOffset + strlen($upperCaseLetter)); + $currentUpperCaseLetter = $upperCaseLetter; + } + $lastChunk = $currentUpperCaseLetter . $temp; + if ($lastChunk !== '') { + $chunks[] = $lastChunk; + } + return implode('_', array_map('mb_strtolower', $chunks)); + } + + /** + * Converts a command name into the name of a class. + * + * @param string $command For example foo_bar + * + * @return string for example FooBarCommand. In case of errors, returns an empty string + */ + protected function commandNameToClassName(string $command): string + { + if ($command === '') { + return ''; + } + return str_replace(' ', '', $this->ucWordsUnicode(str_replace('_', ' ', $command))) . 'Command'; + } } diff --git a/tests/Unit/Commands/CustomTestCommands/DummyAdminCommand.php b/tests/Unit/Commands/CustomTestCommands/DummyAdminCommand.php index 39fe0cf9..b81114d2 100644 --- a/tests/Unit/Commands/CustomTestCommands/DummyAdminCommand.php +++ b/tests/Unit/Commands/CustomTestCommands/DummyAdminCommand.php @@ -16,14 +16,14 @@ use Longman\TelegramBot\Request; /** - * Test "/dummyadmin" command + * Test "/dummy_admin" command */ class DummyAdminCommand extends AdminCommand { /** * @var string */ - protected $name = 'dummyadmin'; + protected $name = 'dummy_admin'; /** * @var string @@ -33,7 +33,7 @@ class DummyAdminCommand extends AdminCommand /** * @var string */ - protected $usage = '/dummyadmin'; + protected $usage = '/dummy_admin'; /** * Command execute method diff --git a/tests/Unit/Commands/CustomTestCommands/DummySystemCommand.php b/tests/Unit/Commands/CustomTestCommands/DummySystemCommand.php index f9689f8b..d9ed5859 100644 --- a/tests/Unit/Commands/CustomTestCommands/DummySystemCommand.php +++ b/tests/Unit/Commands/CustomTestCommands/DummySystemCommand.php @@ -16,14 +16,14 @@ use Longman\TelegramBot\Request; /** - * Test "/dummysystem" command + * Test "/dummy_system" command */ class DummySystemCommand extends SystemCommand { /** * @var string */ - protected $name = 'dummysystem'; + protected $name = 'dummy_system'; /** * @var string @@ -33,7 +33,7 @@ class DummySystemCommand extends SystemCommand /** * @var string */ - protected $usage = '/dummysystem'; + protected $usage = '/dummy_system'; /** * Command execute method diff --git a/tests/Unit/Commands/CustomTestCommands/DummyUserCommand.php b/tests/Unit/Commands/CustomTestCommands/DummyUserCommand.php index 80e4de74..7a20b1ba 100644 --- a/tests/Unit/Commands/CustomTestCommands/DummyUserCommand.php +++ b/tests/Unit/Commands/CustomTestCommands/DummyUserCommand.php @@ -16,14 +16,14 @@ use Longman\TelegramBot\Request; /** - * Test "/dummyuser" command + * Test "/dummy_user" command */ class DummyUserCommand extends UserCommand { /** * @var string */ - protected $name = 'dummyuser'; + protected $name = 'dummy_user'; /** * @var string @@ -33,7 +33,7 @@ class DummyUserCommand extends UserCommand /** * @var string */ - protected $usage = '/dummyuser'; + protected $usage = '/dummy_user'; /** * Command execute method diff --git a/tests/Unit/TelegramTest.php b/tests/Unit/TelegramTest.php index 2a8b916d..58855d91 100644 --- a/tests/Unit/TelegramTest.php +++ b/tests/Unit/TelegramTest.php @@ -170,9 +170,9 @@ public function testAddCustomCommandsClass(): void ]); $command_classes = $tg->getCommandClasses(); - self::assertCount(1, $command_classes['System']); - self::assertCount(1, $command_classes['Admin']); - self::assertCount(1, $command_classes['User']); + self::assertSame(['dummy_system' => 'Dummy\SystemCommands\DummySystemCommand'], $command_classes['System']); + self::assertSame(['dummy_admin' => 'Dummy\AdminCommands\DummyAdminCommand'], $command_classes['Admin']); + self::assertSame(['dummy_user' => 'Dummy\UserCommands\DummyUserCommand'], $command_classes['User']); } public function testSettingDownloadUploadPaths(): void From 63ba67dce93119bd76b621c1b1de6eaf38b0fdcc Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Thu, 27 Oct 2022 16:35:25 +0200 Subject: [PATCH 2/3] Avoid preg_match in Telegram::classNameToCommandName() --- src/Telegram.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Telegram.php b/src/Telegram.php index 0e2df044..ec4ab39e 100644 --- a/src/Telegram.php +++ b/src/Telegram.php @@ -1294,10 +1294,11 @@ public function getUpdateFilter(): ?callable */ protected function classNameToCommandName(string $class): string { - if (!preg_match('/^(.+)Command$/', $class, $matches)) { + // 7 is the length of 'Command' + if (substr($class, -7) !== 'Command') { return ''; } - $temp = $matches[1]; + $temp = substr($class, 0, -7); $chunks = []; $currentUpperCaseLetter = ''; while ($temp !== '') { From 392f9490193abb12ed566d817a33eed4ef800768 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Thu, 27 Oct 2022 16:42:49 +0200 Subject: [PATCH 3/3] Simplify Telegram::classNameToCommandName() --- src/Telegram.php | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/Telegram.php b/src/Telegram.php index ec4ab39e..013f51d2 100644 --- a/src/Telegram.php +++ b/src/Telegram.php @@ -1298,29 +1298,7 @@ protected function classNameToCommandName(string $class): string if (substr($class, -7) !== 'Command') { return ''; } - $temp = substr($class, 0, -7); - $chunks = []; - $currentUpperCaseLetter = ''; - while ($temp !== '') { - if (!preg_match('/\p{Lu}/u', $temp, $match, PREG_OFFSET_CAPTURE)) { - break; - } - // $match[0][0] contains first upper case character - // $match[0][1] contains the start position (in bytes) of the first upper case character - [$upperCaseLetter, $upperCaseLetterOffset] = $match[0]; - if ($upperCaseLetterOffset > 0) { - $chunks[] = $currentUpperCaseLetter . substr($temp, 0, $upperCaseLetterOffset); - } elseif ($currentUpperCaseLetter !== '') { - $chunks[] = $currentUpperCaseLetter; - } - $temp = substr($temp, $upperCaseLetterOffset + strlen($upperCaseLetter)); - $currentUpperCaseLetter = $upperCaseLetter; - } - $lastChunk = $currentUpperCaseLetter . $temp; - if ($lastChunk !== '') { - $chunks[] = $lastChunk; - } - return implode('_', array_map('mb_strtolower', $chunks)); + return mb_strtolower(preg_replace('/(.)(?=[\p{Lu}])/u', '$1_', substr($class, 0, -7))); } /**