diff --git a/CHANGELOG.md b/CHANGELOG.md index a2ff9f4a9..5c4181fa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Exclamation symbols (:exclamation:) note something of importance e.g. breaking c - `TelegramLog::$always_log_request_and_response` parameter to force output of the request and response data to the debug log, also for successful requests ### Changed - [:exclamation:][unreleased-bc-static-method-entityescapemarkdown] Made `Entity::escapeMarkdown` static, to not require an `Entity` object. +- Allow custom namespacing for commands. (@Jonybang) ### Deprecated ### Removed ### Fixed diff --git a/src/Telegram.php b/src/Telegram.php index c2fc18fa5..ece740e37 100644 --- a/src/Telegram.php +++ b/src/Telegram.php @@ -15,7 +15,10 @@ defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands'); use Exception; +use Longman\TelegramBot\Commands\AdminCommand; use Longman\TelegramBot\Commands\Command; +use Longman\TelegramBot\Commands\SystemCommand; +use Longman\TelegramBot\Commands\UserCommand; use Longman\TelegramBot\Entities\ServerResponse; use Longman\TelegramBot\Entities\Update; use Longman\TelegramBot\Exception\TelegramException; @@ -68,6 +71,13 @@ class Telegram */ protected $commands_paths = []; + /** + * Custom commands objects + * + * @var array + */ + protected $commands_objects = []; + /** * Current Update object * @@ -262,7 +272,7 @@ public function getCommandsList() require_once $file->getPathname(); - $command_obj = $this->getCommandObject($command); + $command_obj = $this->getCommandObject($command, $file->getPathname()); if ($command_obj instanceof Command) { $commands[$command_name] = $command_obj; } @@ -279,25 +289,68 @@ public function getCommandsList() * Get an object instance of the passed command * * @param string $command + * @param string $filepath * * @return Command|null */ - public function getCommandObject($command) + public function getCommandObject($command, $filepath = null) { $which = ['System']; $this->isAdmin() && $which[] = 'Admin'; $which[] = 'User'; foreach ($which as $auth) { - $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command'; - if (class_exists($command_namespace)) { - return new $command_namespace($this, $this->update); + if ($filepath) { + $command_namespace = $this->getFileNamespace($filepath); + } else { + $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands'; + } + $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': + if ($command_obj instanceof SystemCommand) { + return $command_obj; + } + break; + + case 'Admin': + if ($command_obj instanceof AdminCommand) { + return $command_obj; + } + break; + + case 'User': + if ($command_obj instanceof UserCommand) { + return $command_obj; + } + break; + } } } return null; } + /** + * Get namespace from php file by src path + * + * @param string $src (absolute path to file) + * + * @return string ("Longman\TelegramBot\Commands\SystemCommands" for example) + */ + protected function getFileNamespace($src) + { + $content = file_get_contents($src); + if (preg_match('#^namespace\s+(.+?);$#sm', $content, $m)) { + return $m[1]; + } + return null; + } + /** * Set custom input string for debug purposes * @@ -484,7 +537,7 @@ public function processUpdate(Update $update) //Make sure we have an up-to-date command list //This is necessary to "require" all the necessary command files! - $this->getCommandsList(); + $this->commands_objects = $this->getCommandsList(); //If all else fails, it's a generic message. $command = self::GENERIC_MESSAGE_COMMAND; @@ -533,8 +586,13 @@ public function processUpdate(Update $update) */ public function executeCommand($command) { - $command = mb_strtolower($command); - $command_obj = $this->getCommandObject($command); + $command = mb_strtolower($command); + + if (isset($this->commands_objects[$command])) { + $command_obj = $this->commands_objects[$command]; + } else { + $command_obj = $this->getCommandObject($command); + } if (!$command_obj || !$command_obj->isEnabled()) { //Failsafe in case the Generic command can't be found @@ -907,7 +965,7 @@ protected function ucwordsUnicode($str, $encoding = 'UTF-8') protected function ucfirstUnicode($str, $encoding = 'UTF-8') { return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding) - . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding); + . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding); } /**