PageRenderTime 21ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/common/components/telegram/Parser.php

https://gitlab.com/jafari/resana
PHP | 299 lines | 212 code | 26 blank | 61 comment | 13 complexity | 73c696c1fbff2b1165dc509cf92dc7eb MD5 | raw file
  1. <?php
  2. /**
  3. * @link http://www.noghteh.ir/
  4. * @copyright Copyright (c) 2015 Noghteh
  5. * @license http://www.noghteh.ir/license/
  6. */
  7. namespace common\components\telegram;
  8. use Yii;
  9. use yii\base\Model;
  10. use airani\telegram\TelegramBot;
  11. use common\models\ChannelMember;
  12. use common\models\Chat as ChatModel;
  13. use common\components\telegram\types\Chat;
  14. use common\components\telegram\types\Update;
  15. /**
  16. * TelegramParser
  17. * Parse telegram requests
  18. *
  19. * @property array $commandPatterns
  20. * @property array $commands
  21. * @property \common\models\Bot $bot
  22. * @property Update $update
  23. * @property ChannelMember $channelMember
  24. * @property ChatModel $chatModel
  25. *
  26. * @author Ali Irani <ali@irani.im>
  27. */
  28. class Parser extends Model
  29. {
  30. public $bot;
  31. private $_update;
  32. private $_commands;
  33. /**
  34. * Set data cache
  35. * @param $key
  36. * @param $value
  37. * @param int $duration
  38. * @param null $dependency
  39. * @return bool
  40. */
  41. public function cacheSet($key, $value, $duration = 60, $dependency = null)
  42. {
  43. return Yii::$app->cache->set('telegram:' . $key, $value, $duration, $dependency);
  44. }
  45. /**
  46. * Returns data cache by key
  47. * @param $key
  48. * @return mixed
  49. */
  50. public function cacheGet($key)
  51. {
  52. return Yii::$app->cache->get('telegram:' . $key);
  53. }
  54. /**
  55. * Delete Cache
  56. * @param $key
  57. * @return mixed
  58. */
  59. public function cacheDelete($key)
  60. {
  61. return Yii::$app->cache->delete('telegram:' . $key);
  62. }
  63. public function getUpdate()
  64. {
  65. return $this->_update;
  66. }
  67. public function setUpdate($params)
  68. {
  69. $this->_update = new Update($params);
  70. }
  71. /**
  72. * Parse telegram request
  73. */
  74. public function parse()
  75. {
  76. $this->saveChat();
  77. if ($this->update->baseMessage->isLeftChat()) {
  78. $this->leftGroup();
  79. } elseif ($this->update->baseMessage->isNewChat()) {
  80. $this->activateChat();
  81. }
  82. $this->parseCommands();
  83. }
  84. /**
  85. * Returns chat model object
  86. * @return null|static
  87. */
  88. public function getChatModel()
  89. {
  90. $message = $this->update->baseMessage;
  91. $chatId = $message->migrate_to_chat_id ?: $message->chat->id;
  92. /** @var ChatModel $chat */
  93. if ($chatAttr = $this->cacheGet("chat:$chatId")) {
  94. $chat = new ChatModel($chatAttr);
  95. $chat->setOldAttributes($chatAttr);
  96. return $chat;
  97. }
  98. if ($chat = ChatModel::findOne(['chat_id' => $chatId])) {
  99. $this->cacheSet("chat:$chatId", $chat->attributes);
  100. }
  101. return $chat;
  102. }
  103. /**
  104. * Returns Channel Member model object
  105. * @return ChannelMember
  106. */
  107. public function getChannelMember()
  108. {
  109. $chatId = $this->update->baseMessage->chat->id;
  110. /** @var ChannelMember $channelMember */
  111. if ($channelMemberAttr = $this->cacheGet("channelMember:$chatId")) {
  112. $channelMember = new ChannelMember($channelMemberAttr);
  113. $channelMember->setOldAttributes($channelMemberAttr);
  114. return $channelMember;
  115. }
  116. $channelMember = ChannelMember::findOne([
  117. 'channel_id' => $this->bot->channel_id,
  118. 'member_id' => $this->chatModel->member_id
  119. ]);
  120. if ($channelMember) {
  121. $this->cacheSet("channelMember:$chatId", $channelMember->attributes);
  122. }
  123. return $channelMember;
  124. }
  125. /**
  126. * Save chat
  127. * @return bool
  128. */
  129. public function saveChat()
  130. {
  131. if (($chat = $this->chatModel) === null) {
  132. $message = $this->update->baseMessage;
  133. $chatId = $message->migrate_to_chat_id ?: $message->chat->id;
  134. $chat = new ChatModel([
  135. 'chat_id' => $chatId,
  136. 'name' => $message->chat->name,
  137. 'username' => $message->chat->username ?: '',
  138. 'type' => self::getChatTypesId()[$message->chat->type],
  139. ]);
  140. if ($chat->save() === false) {
  141. Yii::error(['message' => 'Save new chat failed.', 'errors' => $chat->errors], __METHOD__);
  142. return false;
  143. }
  144. }
  145. if (($this->channelMember) === null) {
  146. $channelMember = new ChannelMember([
  147. 'channel_id' => $this->bot->channel_id,
  148. 'member_id' => $chat->member_id,
  149. ]);
  150. if ($channelMember->save() === false) {
  151. Yii::error(['message' => 'Save new channel member failed.', 'errors' => $channelMember->errors], __METHOD__);
  152. return false;
  153. }
  154. }
  155. return true;
  156. }
  157. /**
  158. * Check message with available commands and execute appropriate command
  159. * @return bool
  160. */
  161. public function parseCommands()
  162. {
  163. $textWords = explode(' ', $this->update->baseMessage->text);
  164. if (empty($textWords)) {
  165. return false;
  166. }
  167. $text = $this->getResponseCommand() ?: strtolower($textWords[0]);
  168. $patterns = $this->commandPatterns;
  169. foreach ([$text, $this->update->baseMessage->text] as $pattern) {
  170. $commandIndex = array_search($pattern, $patterns, false);
  171. if ($commandIndex !== false) {
  172. $command = $this->getCommands()[$commandIndex];
  173. $command->run();
  174. return true;
  175. }
  176. }
  177. return false;
  178. }
  179. /**
  180. * Returns all available commands
  181. * @return array
  182. */
  183. public function getCommands()
  184. {
  185. if ($this->_commands) {
  186. return $this->_commands;
  187. }
  188. $path = Yii::getAlias('@common/components/telegram/commands');
  189. $namespace = '\common\components\telegram\commands';
  190. $files = glob($path.'/*.php');
  191. $commands = [];
  192. foreach ($files as $file) {
  193. if (preg_match('/.*\/([\w]+Command).php/', $file, $matches)) {
  194. $className = $namespace . '\\' . $matches[1];
  195. $commands[] = new $className(['bot' => $this->bot, 'update' => $this->update]);
  196. }
  197. }
  198. $this->_commands = $commands;
  199. return $commands;
  200. }
  201. /**
  202. * Returns patterns of available commands
  203. * @return array
  204. */
  205. public function getCommandPatterns()
  206. {
  207. $commands = $this->getCommands();
  208. if (count($commands) === 0) {
  209. return [];
  210. }
  211. $patterns = [];
  212. foreach ($commands as $command) {
  213. $patterns[] = $command->getPattern();
  214. }
  215. return $patterns;
  216. }
  217. /**
  218. * Returns response command if is set
  219. * @return mixed | null
  220. */
  221. public function getResponseCommand()
  222. {
  223. $response = Yii::$app->cache->get('reply:' . $this->update->baseMessage->chat->id);
  224. return isset($response['command']) ? $response['command'] : null;
  225. }
  226. /**
  227. * Change channel member status to the left group
  228. * @return bool
  229. */
  230. public function leftGroup()
  231. {
  232. if ($this->channelMember) {
  233. $chatId = $this->update->baseMessage->chat->id;
  234. $this->cacheDelete("channelMember:$chatId");
  235. return $this->channelMember->leftGroup() ? true : false;
  236. }
  237. return false;
  238. }
  239. /**
  240. * Change channel member status to active
  241. * @return bool
  242. */
  243. public function activateChat()
  244. {
  245. if ($this->channelMember) {
  246. $chatId = $this->update->baseMessage->chat->id;
  247. $this->cacheDelete("channelMember:$chatId");
  248. return $this->channelMember->activate() ? true : false;
  249. }
  250. return false;
  251. }
  252. /**
  253. * Returns types id of chat model
  254. * @return array
  255. */
  256. public static function getChatTypesId()
  257. {
  258. return [
  259. Chat::TYPE_CHANNEL => ChatModel::TYPE_CHANNEL,
  260. Chat::TYPE_PRIVATE => ChatModel::TYPE_USER,
  261. Chat::TYPE_GROUP => ChatModel::TYPE_GROUP,
  262. Chat::TYPE_SUPER_GROUP => ChatModel::TYPE_SUPER_GROUP,
  263. ];
  264. }
  265. }