Skip to content

PSR4 command classes include #1207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 133 additions & 14 deletions src/Telegram.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');

use Exception;
use InvalidArgumentException;
use Longman\TelegramBot\Commands\AdminCommand;
use Longman\TelegramBot\Commands\Command;
use Longman\TelegramBot\Commands\SystemCommand;
Expand All @@ -29,6 +30,19 @@

class Telegram
{
/**
* Auth name for user commands
*/
const AUTH_USER = 'User';
/**
* Auth name tof system commands
*/
const AUTH_SYSTEM = 'System';
/**
* Auth name for admin commands
*/
const AUTH_ADMIN = 'Admin';

/**
* Version
*
Expand Down Expand Up @@ -71,6 +85,25 @@ class Telegram
*/
protected $commands_paths = [];

/**
* Custom commands class names
* ```
* [
* 'User' => [
* //commandName => className
* 'start' => 'name\space\to\StartCommand',
* ],
* 'Admin' => [], //etc
* ]
* ```
* @var array
*/
protected $commandsClasses = [
self::AUTH_USER => [],
self::AUTH_ADMIN => [],
self::AUTH_SYSTEM => [],
];

/**
* Custom commands objects
*
Expand Down Expand Up @@ -283,6 +316,29 @@ public function getCommandsList(): array
return $commands;
}

/**
* Get classname of predefined commands
* @see commandsClasses
* @param string $auth Auth of command
* @param string $command Command name
*
* @return string|null
*/
public function getCommandClassName(string $auth, string $command): ?string
{
$command = mb_strtolower($command);
$auth = $this->ucFirstUnicode($auth);

if (!empty($this->commandsClasses[$auth][$command])) {
$className = $this->commandsClasses[$auth][$command];
if (class_exists($className)){
return $className;
}
}

return null;
}

/**
* Get an object instance of the passed command
*
Expand All @@ -297,35 +353,39 @@ public function getCommandObject(string $command, string $filepath = ''): ?Comma
return $this->commands_objects[$command];
}

$which = ['System'];
$this->isAdmin() && $which[] = 'Admin';
$which[] = 'User';

foreach ($which as $auth) {
if ($filepath) {
$command_namespace = $this->getFileNamespace($filepath);
} else {
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
$which = [self::AUTH_SYSTEM];
$this->isAdmin() && $which[] = self::AUTH_ADMIN;
$which[] = self::AUTH_USER;

foreach ($which as $auth)
{
if (!($command_class = $this->getCommandClassName($auth, $command)))
{
if ($filepath) {
$command_namespace = $this->getFileNamespace($filepath);
} else {
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
}
$command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command';
}
$command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command';

if (class_exists($command_class)) {
$command_obj = new $command_class($this, $this->update);

switch ($auth) {
case 'System':
case self::AUTH_SYSTEM:
if ($command_obj instanceof SystemCommand) {
return $command_obj;
}
break;

case 'Admin':
case self::AUTH_ADMIN:
if ($command_obj instanceof AdminCommand) {
return $command_obj;
}
break;

case 'User':
case self::AUTH_USER:
if ($command_obj instanceof UserCommand) {
return $command_obj;
}
Expand All @@ -347,7 +407,7 @@ public function getCommandObject(string $command, string $filepath = ''): ?Comma
protected function getFileNamespace(string $src): ?string
{
$content = file_get_contents($src);
if (preg_match('#^namespace\s+(.+?);#m', $content, $m)) {
if (preg_match('#^\s+namespace\s+(.+?);#m', $content, $m)) {
return $m[1];
}

Expand Down Expand Up @@ -716,6 +776,55 @@ public function isDbEnabled(): bool
return $this->mysql_enabled;
}

/**
* Add a single custom commands class
*
* @param string $className Set full classname
* @return Telegram
*/
public function addCommandsClass(string $className): Telegram
{
if (!$className || !class_exists($className))
{
$error = 'Command class name: "' . $className . '" does not exist.';
TelegramLog::error($error);
throw new InvalidArgumentException($error);
}

if (!is_array($this->commandsClasses))
{
$this->commandsClasses = [];
}

if (!is_a($className, Command::class, true)) {
$error = 'Command class is not a base command class';
TelegramLog::error($error);
throw new InvalidArgumentException($error);
}

$commandObject = new $className($this);

$command = $commandObject->getName();
$auth = null;
switch (true) {
case $commandObject->isSystemCommand():
$auth = self::AUTH_SYSTEM;
break;
case $commandObject->isAdminCommand():
$auth = self::AUTH_ADMIN;
break;
case $commandObject->isUserCommand():
$auth = self::AUTH_USER;
break;
}

if ($auth) {
$this->commandsClasses[$auth][$command] = $className;
}

return $this;
}

/**
* Add a single custom commands path
*
Expand Down Expand Up @@ -766,6 +875,16 @@ public function getCommandsPaths(): array
return $this->commands_paths;
}

/**
* Return the list of commands classes
*
* @return array
*/
public function getCommandsClasses(): array
{
return $this->commandsClasses;
}

/**
* Set custom upload path
*
Expand Down
49 changes: 49 additions & 0 deletions tests/Unit/TelegramTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
namespace Longman\TelegramBot\Tests\Unit;

use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
use Exception;
use Longman\TelegramBot\Commands\AdminCommands\WhoisCommand;
use Longman\TelegramBot\Commands\UserCommands\StartCommand;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Exception\TelegramException;
use Longman\TelegramBot\Telegram;
Expand Down Expand Up @@ -133,6 +136,34 @@ public function testAddCustomCommandsPaths(): void
self::assertCount(4, $tg->getCommandsPaths());
}

public function testAddCustomCommandsClass(): void
{
$tg = $this->telegram;
$class = StartCommand::class;
$aClass = WhoisCommand::class;

self::assertCount(3, $tg->getCommandsClasses());

try {
$tg->addCommandsClass('not\exist\Class');
}
catch (\Exception $ex){}
self::assertCount(0, $tg->getCommandsClasses()['User']);

try {
$tg->addCommandsClass('');
}
catch (\Exception $ex){}
self::assertCount(0, $tg->getCommandsClasses()['User']);

$tg->addCommandsClass($class);
self::assertCount(1, $tg->getCommandsClasses()['User']);

$tg->addCommandsClass($aClass);
self::assertCount(1, $tg->getCommandsClasses()['Admin']);

}

public function testSettingDownloadUploadPaths(): void
{
self::assertEmpty($this->telegram->getDownloadPath());
Expand All @@ -152,6 +183,24 @@ public function testGetCommandsList(): void
self::assertNotCount(0, $commands);
}

public function testGetCommandClass(): void
{
$className = StartCommand::class;
$commands = $this->telegram->getCommandsClasses();
self::assertIsArray($commands);
self::assertCount(3, $commands);

$class = $this->telegram->getCommandClassName('user', 'notexist');
self::assertNull($class);

$this->telegram->addCommandsClass($className);
$class = $this->telegram->getCommandClassName('user', 'start');
self::assertNotNull($class);

self::assertSame($className, $class);

}

public function testUpdateFilter(): void
{
$rawUpdate = '{
Expand Down