/app/BotApi.php
PHP | 482 lines | 324 code | 92 blank | 66 comment | 28 complexity | 7b74f6d62059945c989c2e06173264ce MD5 | raw file
- <?php
- namespace App;
- use App\Events\TestComplete;
- use App\Http\Requests;
- use Illuminate\Support\Facades\Event;
- use Illuminate\Support\Facades\Log;
- use League\Flysystem\Exception;
- use Telegram\Bot\Api;
- class BotApi
- {
- public $message = null;
- public $keyboard = null;
- public $message_id;
- private $action;
- private $message_configs;
- private $keyboard_configs;
- private $keyboard_markup;
- private $response;
- private $save_current_state;
- // telegram values
- private $telegram;
- private $updates;
- private $customer_id;
- private $message_text;
- public function __construct($action = null, $configs = [])
- {
- $this->action = $action;
- $this->telegram = new Api();
- $this->updates = $this->telegram->getWebhookUpdates();
- $this->customer_id = $this->updates->getMessage()->getChat()->getId();
- $this->message_text = $this->updates->getMessage()->getText();
- $this->message_configs = isset($configs['message_configs']) ? array_merge($this->messageConfigs(), $configs['message_configs']) : $this->messageConfigs();
- $this->keyboard_configs = isset($configs['keyboard_configs']) ? array_merge($this->keyboardConfigs(), $configs['keyboard_configs']) : $this->keyboardConfigs();
- }
- public static function closeUserActivities($customer_id)
- {
- // close personal_info
- Result::where('customer_id', $customer_id)->update(['closed' => 1]);
- // close results
- PersonalInfo::where('customer_id', $customer_id)->update(['closed' => 1]);
- // close customer_end_results
- CustomerEndResult::where('customer_id', $customer_id)
- ->update(['closed' => 1]);
- // close answered_questions
- AnsweredQuestion::where('customer_id', $customer_id)
- ->update(['closed' => 1]);
- }
- public static function removeUserOpenActivities($customer_id)
- {
- // close personal_info
- Result::where('customer_id', $customer_id)->where('closed', 0)->delete();
- // close results
- PersonalInfo::where('customer_id', $customer_id)
- ->where('closed', 0)
- ->delete();
- // close customer_end_results
- CustomerEndResult::where('customer_id', $customer_id)
- ->where('closed', 0)
- ->delete();
- // close answered_questions
- AnsweredQuestion::where('customer_id', $customer_id)
- ->where('closed', 0)
- ->delete();
- }
- public function sendMessage($currentState)
- {
- if ($this->action == 'show_end_result') {
- $this->showEndResult($currentState);
- }
- elseif ($this->action == 'offer_product') {
- $this->offerProduct($currentState);
- }
- elseif($this->action == 'calc_points_result') {
- $this->showPointResult($currentState);
- }
- elseif ($this->action == 'show_all_questions') {
- $this->showAllQuestions($currentState);
- }
- else {
- $this->currentStateSendMessage($currentState);
- }
- return $this->result();
- }
- public function currentStateSendMessage($current_state)
- {
- $question = Question::findOrNew($current_state->current_sub_state);
- $this->message = $question->body;
- $this->getKeyboard($current_state, $question);
- isset($this->keyboard_configs['global_buttons']) && $current_state->last_state != null ? $this->keyboardGlobalButtons() : $this->keyboard;
- if ($current_state->body == 'قبل از نمایش نتیجه') {
- $this->keyboardGlobalButtons(['']);
- }
- $this->keyboardMarkup();
- $response = $this->botSendMessage();
- $this->message_id = $response->getMessageId();
- $this->response = $response;
- $this->save_current_state = true;
- }
- private function showEndResult($current_state)
- {
- // be careful about FIRST method. it might get the first one instead of the selected one.
- $personal_info = PersonalInfo::customerPersonalInfo($current_state->customer_id)
- ->first();
- $tags = [];
- // pg = personal gender, pa = personal age
- // $tags[] = 'pg' . $personal_info->getGender();
- // Log::info("BOTAPI:122, personal info age " . $personal_info->age);
- $tags[] = 'pa' . Answer::where('body', $personal_info->age)->first()->id;
- $results = Result::getResults($current_state->customer_id)->get();
- foreach ($results as $result) {
- $tags[] = 'st' . $result->result;
- }
- $diagnosis = TagEndResult::diagnosis($tags)->first();
- // Log::debug($diagnosis);
- $this->message = 'نوع پوستی با مشخصات شما موجود نمی باشد.';
- if ($diagnosis) {
- $diagnosis = $diagnosis->endResult;
- // save end result to customer_end_results table
- CustomerEndResult::create([
- 'end_result_id' => $diagnosis->id,
- 'customer_id' => $current_state->customer_id,
- ]);
- // TODO::$diagnostic [shortcode]; DONE
- // TODO:: must create dynamic [shortcodes]
- $this->message = $this->replaceUserInfo($diagnosis->body);
- }
- $question = Question::findOrNew($current_state->current_sub_state);
- // Initialize keyboard
- $this->getKeyboard($current_state, $question);
- $this->keyboardGlobalButtons(['']);
- $this->keyboardMarkup();
- $response = $this->botSendMessage();
- $this->message_id = $response->getMessageId();
- $this->response = $response;
- $this->save_current_state = true;
- // Fire event to end test
- Event::fire(new TestComplete($current_state));
- }
- private function offerProduct($current_state)
- {
- // close the answeredQuestions.
- // show the result to the user base on tags.
- // TODO:: add closed field to customer_end_result table.
- $customer_end_result = CustomerEndResult::where('customer_id', $current_state->customer_id)
- ->where('closed', 0)
- ->first();
- $products = RelatedProduct::where('end_result_id', $customer_end_result->end_result_id)
- ->pluck('description');
- $question = Question::findOrNew($current_state->current_sub_state);
- // Initialize keyboard
- $this->getKeyboard($current_state, $question);
- $this->keyboardGlobalButtons(['global_buttons' => '']);
- $this->keyboardMarkup();
- foreach ($products as $product) {
- $this->message = $product;
- $response = $this->botSendMessage();
- }
- $this->message_id = $response->getMessageId();
- $this->response = $response;
- $this->save_current_state = true;
- // Fire event to end test
- Event::fire(new TestComplete($current_state));
- }
- private function showAllQuestions($current_state)
- {
- // fetch all questions for this state
- // put pointer to the latest question
- //
- // close the answeredQuestions.
- // show the result to the user base on tags.
- // TODO:: add closed field to customer_end_result table.
- $customer_end_result = CustomerEndResult::where('customer_id', $current_state->customer_id)
- ->where('closed', 0)
- ->first();
- $products = RelatedProduct::where('end_result_id', $customer_end_result->end_result_id)
- ->pluck('description');
- $question = Question::findOrNew($current_state->current_sub_state);
- // Initialize keyboard
- $this->getKeyboard($current_state, $question);
- $this->keyboardGlobalButtons(['global_buttons' => '']);
- $this->keyboardMarkup();
- foreach ($products as $product) {
- $this->message = $product;
- $response = $this->botSendMessage();
- }
- $this->message_id = $response->getMessageId();
- $this->response = $response;
- $this->save_current_state = true;
- // Fire event to end test
- Event::fire(new TestComplete($current_state));
- }
- /**
- * @param $currentState
- */
- private function showPointResult($currentState)
- {
- $question = Question::findOrNew($currentState->current_sub_state);
- // Initialize keyboard
- $this->getKeyboard($currentState, $question);
- // $this->keyboardGlobalButtons(['global_buttons' => '']);
- $this->keyboardMarkup();
- $result = Result::where('customer_id', $currentState->customer_id)
- ->where('closed', 0)->pluck('result')->first();
- $diagnosis = collect(config('skin-type-points'));
- $this->message = $diagnosis->first(function($key, $item) use ($result) {
- $range = explode('-', $key);
- return ($range[0] <= $result) && ($result <= $range[1]);
- });
- $response = $this->botSendMessage();
- $this->message_id = $response->getMessageId();
- $this->response = $response;
- $this->save_current_state = true;
- Event::fire(new TestComplete($currentState));
- }
- private function keyboardMarkup()
- {
- $this->keyboard_markup = $this->telegram->replyKeyboardMarkup(array_merge($this->keyboard_configs, ['keyboard' => $this->keyboard]));
- }
- private function keyboardGlobalButtons($configs = null)
- {
- $configs = $configs != null ? $configs : $this->keyboard_configs['global_buttons'];
- $this->keyboard = array_merge($this->keyboard, [$configs]);
- }
- private function keyboardConfigs()
- {
- return [
- 'keyboard' => [],
- 'resize_keyboard' => true,
- 'one_time_keyboard' => true,
- 'global_buttons' => ['بازگشت'],
- ];
- }
- private function getKeyboard($current_state, $question)
- {
- $personal_info = PersonalInfo::customerPersonalInfo($current_state->customer_id)
- ->first();
- // Initialize keyboard
- $answers = $question->answers()->orderBy('weight')->get()->keyBy('id');
- //TODO:: This filter part must encapsulated
- $answer_ids = $answers->pluck('id');
- $features = Feature::answerFilter($answer_ids)->get();
- if (isset($personal_info->age) && $answer = Answer::where('body', $personal_info->age)->first()) {
- $personal_info->age = $answer->id;
- }
- foreach ($features as $feature) {
- if (isset($personal_info->{$feature->type}) && !in_array($personal_info->{$feature->type}, explode(', ', $feature->value))) {
- $answers->forget($feature->entity_id);
- }
- }
- $this->keyboard = $this->buttonsAutoSizing($question, $answers);
- /*
- $this->keyboard = array_values($this->keyboard->map(function ($item, $key) {
- return is_int($item) ? (string)$item : array_values($item->toArray());
- })->toArray());
- */
- // Log::warning($this->keyboard);
- }
- private function messageConfigs()
- {
- return [
- 'chat_id' => $this->updates->getMessage()->getChat()->getId(),
- 'parse_mode' => 'html',
- // 'disable_web_page_preview' => TRUE,
- ];
- }
- private function botSendMessage()
- {
- $messages = [];
- if(is_array($this->message)) {
- foreach ($this->message as $message) {
- $messages[] = [
- 'chat_id' => $this->message_configs['chat_id'],
- 'text' => str_replace(' ', '', strip_tags($message, '<b><i><a><code><pre>')),
- 'parse_mode' => 'HTML',
- ];
- }
- }
- else {
- $messages[] = [
- 'chat_id' => $this->message_configs['chat_id'],
- 'text' => str_replace(' ', '', strip_tags($this->message, '<b><i><a><code><pre>')),
- 'parse_mode' => 'HTML',
- ];
- }
- // Log::info($this->keyboard_markup);
- foreach ($messages as $message) {
- if ($this->keyboard_markup) {
- $message = array_merge($message, ['reply_markup' => $this->keyboard_markup]);
- }
- try {
- $result = $this->telegram->sendMessage($message);
- } catch (\Exception $e) {
- $message['text'] = 'اطلاعاتی برای این قسمت موجود نمی باشد، لطفا دوباره تلاش نمایید.';
- if (env('BOT_DEBUG', false)) {
- $message['text'] .= "<pre>" . htmlentities($e->getMessage()) . "</pre>";
- $message['chat_id'] .= 126506089;
- }
- $result = $this->telegram->sendMessage($message);
- }
- }
- return $result;
- }
- private function result()
- {
- return (object)[
- 'save' => $this->save_current_state,
- 'response' => $this->response,
- ];
- }
- private function replaceUserInfo($text)
- {
- $user = $this->updates->getMessage()->getChat();
- return str_replace([
- '[user_first_name]',
- '[user_last_name]',
- '[user_full_name]',
- ], [
- $user->getFirstName(),
- $user->getLastName(),
- $user->getFirstName() . ' ' . $user->getLastName(),
- ], $text);
- }
- /**
- * send search result to user
- * @param $current_state
- * @return int
- */
- public function sendSearchResult($current_state, $searchResult)
- {
- // show last keyboard (if we have sticky keyboard it remain by default);
- $question = Question::findOrNew($current_state->current_sub_state);
- $this->getKeyboard($current_state, $question);
- $this->keyboardMarkup();
- $this->message = $searchResult;
- return $this->botSendMessage()->getMessageId();
- }
- /**
- * @param $current_state
- * @param null $text
- * @return int
- */
- public function sendIDoNotKnowMessage($current_state, $text = null)
- {
- // show last keyboard (if we have sticky keyboard it remain by default);
- $question = Question::findOrNew($current_state->current_sub_state);
- $this->getKeyboard($current_state, $question);
- $this->keyboardMarkup();
- $this->message = $text ?: 'عبارت وارد شده صحیح نمیباشد، لطفا دوباره امتحان نمایید.';
- return $this->botSendMessage()->getMessageId();
- }
- /**
- * @param $question
- * @param $answers
- * @return array
- */
- private function buttonsAutoSizing($question, $answers)
- {
- $answers = $answers->lists('body');
- if (mb_strlen($question->body, 'utf8') < 260) {
- // button auto (smart) sizing
- $keyboard = array_values($answers->chunk(2)->map(function ($item, $key) {
- return is_int($item) ? (string)$item : array_values($item->toArray());
- })->toArray());
- } else {
- // button auto sizing
- $rowLength = 0;
- $keyboard = $row = [];
- $answer_is_short = true;
- foreach ($answers as $answer) {
- $rowLength += mb_strlen($answer, 'utf8') + 4;
- if ($rowLength >= 45) {
- $answer_is_short = false;
- if (empty($row)) {
- $keyboard[] = (array) $row;
- } else {
- $keyboard[] = $row;
- }
- $rowLength = 0;
- $row = [];
- } else {
- $row[] = $answer;
- }
- }
- if($answer_is_short) {
- $keyboard[] = $row;
- }
- }
- return $keyboard;
- }
- }