From 9939c3b61e962b0aadae2c7376900e5d92145a76 Mon Sep 17 00:00:00 2001 From: bahriddin Date: Tue, 23 Aug 2022 15:06:13 +0500 Subject: [PATCH] Initial --- .gitignore | 4 + App.php | 36 +++++++++ Commands/HelloCommand.php | 47 +++++++++++ Commands/StartCommand.php | 49 ++++++++++++ Config/BotConfig.php | 14 ++++ Config/Database/pgsql.sql | 113 +++++++++++++++++++++++++++ Config/DbConfig.php | 30 +++++++ Enums/StatusEnum.php | 24 ++++++ Locales/en.php | 9 +++ Models/BaseModel.php | 8 ++ Models/ModelInterface.php | 10 +++ Models/User.php | 55 +++++++++++++ Repositories/BaseRepository.php | 70 +++++++++++++++++ Repositories/RepositoryInterface.php | 20 +++++ Repositories/UserRepository.php | 111 ++++++++++++++++++++++++++ Services/BaseService.php | 8 ++ Services/ServiceInterface.php | 8 ++ Services/UserService.php | 49 ++++++++++++ composer.json | 22 ++++++ index.php | 47 +++++++++++ 20 files changed, 734 insertions(+) create mode 100644 .gitignore create mode 100644 App.php create mode 100644 Commands/HelloCommand.php create mode 100644 Commands/StartCommand.php create mode 100644 Config/BotConfig.php create mode 100644 Config/Database/pgsql.sql create mode 100644 Config/DbConfig.php create mode 100644 Enums/StatusEnum.php create mode 100644 Locales/en.php create mode 100644 Models/BaseModel.php create mode 100644 Models/ModelInterface.php create mode 100644 Models/User.php create mode 100644 Repositories/BaseRepository.php create mode 100644 Repositories/RepositoryInterface.php create mode 100644 Repositories/UserRepository.php create mode 100644 Services/BaseService.php create mode 100644 Services/ServiceInterface.php create mode 100644 Services/UserService.php create mode 100644 composer.json create mode 100644 index.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e6d1772 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +vendor +.idea +composer.lock +*.local.* \ No newline at end of file diff --git a/App.php b/App.php new file mode 100644 index 0000000..49335ce --- /dev/null +++ b/App.php @@ -0,0 +1,36 @@ +userService = new UserService(); + parent::__construct($telegram, $update); + } + + public function execute(): ServerResponse + { + + $chat_id = $this->getMessage()->getChat()->getId(); + $user = $this->userService->getByChatId($chat_id); + if ($user === null) { + return Request::sendMessage([ + 'chat_id' => $chat_id, + 'text' => App::$i18n->get("Please, send /start command!"), + ]); + } + $user->step = 'hello'; + $this->userService->update($user); + + return Request::sendMessage([ + 'chat_id' => $chat_id, + 'text' => App::$i18n->get("Hello"), + ]); + } +} \ No newline at end of file diff --git a/Commands/StartCommand.php b/Commands/StartCommand.php new file mode 100644 index 0000000..c48b0e3 --- /dev/null +++ b/Commands/StartCommand.php @@ -0,0 +1,49 @@ +userService = new UserService(); + parent::__construct(telegram: $telegram, update: $update); + } + + public function execute(): ServerResponse + { + $chat_id = $this->getMessage()->getChat()->getId(); + $user = $this->userService->getByChatId($chat_id); + if ($user === null) { + $this->userService->create( + chat_id: $chat_id, + step: 'start', + ); + return Request::sendMessage([ + 'chat_id' => $chat_id, + 'text' => App::$i18n->get("Hello"), + ]); + } + $user->step = 'start'; + $this->userService->update($user); + return Request::sendMessage([ + 'chat_id' => $chat_id, + 'text' => App::$i18n->get("Home"), + ]); + } +} \ No newline at end of file diff --git a/Config/BotConfig.php b/Config/BotConfig.php new file mode 100644 index 0000000..d305817 --- /dev/null +++ b/Config/BotConfig.php @@ -0,0 +1,14 @@ +schema . ':' . + 'host=' . $this->host . ';' . + 'port=' . $this->port . ';' . + 'dbname=' . $this->dbname . ';', + username: $this->username, + password: $this->password, + ); + } +} \ No newline at end of file diff --git a/Enums/StatusEnum.php b/Enums/StatusEnum.php new file mode 100644 index 0000000..7f63365 --- /dev/null +++ b/Enums/StatusEnum.php @@ -0,0 +1,24 @@ + 'ACTIVE', + StatusEnum::INACTIVE => 'INACTIVE', + StatusEnum::DELETED => 'DELETED', + }; + } +} diff --git a/Locales/en.php b/Locales/en.php new file mode 100644 index 0000000..75eb8f0 --- /dev/null +++ b/Locales/en.php @@ -0,0 +1,9 @@ + 'en', + 'language' => 'English', + 'Hello' => 'Hello', + 'Home' => 'Home', + 'Please, send /start command!' => 'Please, send /start command!', +]; \ No newline at end of file diff --git a/Models/BaseModel.php b/Models/BaseModel.php new file mode 100644 index 0000000..c240ad5 --- /dev/null +++ b/Models/BaseModel.php @@ -0,0 +1,8 @@ +id = $id; + $model->is_new = false; + } + $model->chat_id = $chat_id; + $model->step = $step; + $model->language = $language; + $model->status = $status->label(); + $model->created_at = $created_at; + return $model; + } + + public function attributes(): array + { + return [ + 'id' => $this->id, + 'chat_id' => $this->chat_id, + 'step' => $this->step, + 'language' => $this->language, + 'status' => $this->status, + 'created_at' => $this->created_at, + ]; + } + + public static function tableName(): string + { + return 'user'; + } +} \ No newline at end of file diff --git a/Repositories/BaseRepository.php b/Repositories/BaseRepository.php new file mode 100644 index 0000000..ab54931 --- /dev/null +++ b/Repositories/BaseRepository.php @@ -0,0 +1,70 @@ + $value) { + if (empty($value)) { + continue; + } + $params[':' . $key] = $value; + $keys .= ', "' . $key . '"'; + $values .= ', :' . $key; + } + $sql = 'INSERT INTO "' . $tableName . '" (' . ltrim($keys, ', ') . ') VALUES (' . ltrim($values, ', ') . ')'; + $stmt = App::$database::$pdo->prepare($sql); + $stmt->execute($params); + } + + protected function _update($tableName, $columns, $conditions): void + { + $values = ''; + $params = []; + $conditionSql = ''; + foreach ($conditions as $key => $value) { + $conditionSql.= ', ' . $key . ' = :' . $key; + $params[':' . $key] = $value; + } + foreach ($columns as $key => $value) { + if (empty($value)) { + continue; + } + $params[':' . $key] = $value; + $values .= ', "' . $key . '" = :' . $key; + } + $sql = 'UPDATE "' . $tableName . '" SET ' . ltrim($values, ', ') . ' WHERE ' . ltrim($conditionSql, ', '); + $stmt = App::$database::$pdo->prepare($sql); + $stmt->execute($params); + } +} \ No newline at end of file diff --git a/Repositories/RepositoryInterface.php b/Repositories/RepositoryInterface.php new file mode 100644 index 0000000..3cc8b3d --- /dev/null +++ b/Repositories/RepositoryInterface.php @@ -0,0 +1,20 @@ +beforeDelete(); + $this->afterDelete(); + } + + public function save(User|RepositoryInterface $model): void + { + $this->beforeSave(); + if ($model->is_new) { + $this->_insert(User::tableName(), $model->attributes()); + $model->id = App::$database::$pdo->lastInsertId(); + $model->is_new = false; + } else { + $columns = $model->attributes(); + unset($columns['id']); + $this->_update(User::tableName(), $columns, [ + 'id' => $model->id, + ]); + } + $this->afterSave(); + } + + public function getById(int $id): ?User + { + return $this->getOneBy([ + 'id' => $id, + ]); + } + + private function getOneBy(array $conditions, string $select = '*'): ?User + { + $stmt = $this->createSelectQuery($conditions, $select); + $stmt->execute(); + $fetched = $stmt->fetch(PDO::FETCH_ASSOC); + if (empty($fetched)) { + return null; + } + return User::create( + chat_id: $fetched['chat_id'], + id: $fetched['id'], + step: $fetched['step'], + language: $fetched['language'], + created_at: $fetched['created_at'], + status: StatusEnum::from($fetched['status']), + ); + } + + private function createSelectQuery(array $conditions, string $select): PDOStatement|false + { + $conditionSql = ''; + foreach ($conditions as $key => $value) { + $conditionSql .= $key . ' = :' . $key; + } + if (empty($select)) { + $select = '*'; + } + $sql = 'SELECT ' . $select . ' FROM "' . User::tableName() . '" WHERE ' . $conditionSql; + $stmt = App::$database::$pdo->prepare($sql); + foreach ($conditions as $key => $value) { + $stmt->bindParam(":" . $key, $value); + } + return $stmt; + } + + public function getByChatId(int $chat_id): ?User + { + return $this->getOneBy([ + 'chat_id' => $chat_id, + ]); + } + + private function getManyBy(array $conditions, string $select = '*'): array + { + $stmt = $this->createSelectQuery($conditions, $select); + $stmt->execute(); + $fetched = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (empty($fetched)) { + return []; + } + $result = []; + foreach ($fetched as $item) { + $result[] = User::create( + chat_id: $item['chat_id'], + id: $item['id'], + step: $item['step'], + language: $item['language'], + created_at: $item['created_at'], + status: $item['status'], + ); + } + return $result; + } +} \ No newline at end of file diff --git a/Services/BaseService.php b/Services/BaseService.php new file mode 100644 index 0000000..ea02284 --- /dev/null +++ b/Services/BaseService.php @@ -0,0 +1,8 @@ +userRepository = new UserRepository(); + } + + public function create( + int $chat_id, + ?string $step = null, + ?string $language = null, + StatusEnum $status = StatusEnum::ACTIVE, + ) + { + $user = User::create( + chat_id: $chat_id, + step: $step, + language: $language, + created_at: time(), + status: $status, + ); + $this->userRepository->save($user); + } + + public function getById(int $id): ?User + { + return $this->userRepository->getById($id); + } + + public function getByChatId(int $chat_id): ?User + { + return $this->userRepository->getByChatId($chat_id); + } + + public function update(User $user) + { + $this->userRepository->save($user); + } +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..e0e7fe4 --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "require": { + "php": ">=8.1", + "ext-pdo": "*", + "ext-json": "*", + "longman/telegram-bot": "^0.78.0", + "mrmuminov/php-i18n": "^1.3" + }, + "autoload": { + "psr-4": { + "Enums\\": "Enums\\", + "Config\\": "Config\\", + "Models\\": "Models\\", + "Services\\": "Services\\", + "Commands\\": "Commands\\", + "Repositories\\": "Repositories\\" + }, + "files": [ + "App.php" + ] + } +} diff --git a/index.php b/index.php new file mode 100644 index 0000000..6861fb7 --- /dev/null +++ b/index.php @@ -0,0 +1,47 @@ +" + ), + bot: new BotConfig( + bot_api_token: '', + bot_username: '', + webhook_url: "", + ), + i18n: new I18n([ + 'path' => __DIR__ . '/Locales', + 'languages' => ['en'], + 'language' => 'en', + ]), + debug: true, +)); + +if (App::$debug) { + ini_set('display_errors', 1); + error_reporting(E_ALL); +} + +try { + $telegram = new Telegram(App::$bot->bot_api_token, App::$bot->bot_username); + + $telegram->addCommandClasses([ + StartCommand::class, + HelloCommand::class, + ]); + + $telegram->handle(); +} catch (TelegramException $e) { + +} \ No newline at end of file