Selaa lähdekoodia

24 апреля

Вадим Королёв 1 vuosi sitten
vanhempi
commit
24ab43d9cb

+ 1 - 4
.env.template

@@ -1,5 +1,2 @@
 TELEGRAMORG_TOKEN=
-db_host=
-db_name=
-db_user=
-db_password=
+dsn=mysqli://user:secret@localhost/mydb

+ 13 - 0
bin/doctrine.php

@@ -0,0 +1,13 @@
+#!/usr/bin/env php
+<?php
+
+use Doctrine\ORM\Tools\Console\ConsoleRunner;
+use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
+use BotKit\Common\Database;
+
+require __DIR__ . '/../src/bootstrap.php';
+
+$em = Database::getEM();
+ConsoleRunner::run(
+    new SingleManagerProvider($em)
+);

+ 41 - 0
bin/employee.csv

@@ -0,0 +1,41 @@
+surname,name,patronymic
+Шешегова,Наталья,Владимировна
+Овчинникова,Ольга,Леонидовна
+Попов,Александр,Александрович
+Маскин,Александр,Сергеевич
+Игнатьева,Наталья,Сергеевна
+Немтинова,Елена,Александровна
+Новикова,Елена,Аркадьевна
+Газизуллина,Альбина,Борисовна
+Бегунова,Светлана,Леонидовна
+Александрова,Ольга,Германовна
+Суворова,Анастасия,Александровна
+Хайрутдинова,Гюзелия,Гаптельнуровна
+Еремеева,Юлия,Николаевна
+Логинова,Елена,Евгеньевна
+Медведев,Михаил,Евгеньевич
+Нигаматзянов,Нурислам,Нургаянович
+Антоненко,Елена,Владимировна
+Воронин,Андрей,Леонидович
+Хуснутдинов,Марсиль,Равильевич
+Матвеева,Людмила,Георгиевна
+Дербышева,Любовь,Валентиновна
+Гарифова,Алмазия,Альферовна
+Мингалеева,Римма,Рифовна
+Пупкова,Алевтина,Валерьевна
+Ильина,Светлана,Анатольевна
+Пивоваров,Сергей,Александрович
+Галимова,Екатерина,Валерьевна
+Поткина,Кристина,Геннадьевна
+Пономарева,Елена,Анатольевна
+Исаков,Равиль,Загидович
+Бондин,Александр,Сергеевич
+Шешегов,Сергей,Алексанрович
+Коралихина,Марина,Юрьевна
+Солоницына,Вера,Станиславовна
+Медянцева,Альбина,Альбертовна
+Пушкарев,Александр,Анатольевич
+Шамсумухаметов,Рамиль,Ильсурович
+Бегунов,Иван,Александрович
+Усова,Жанна,Викторовна
+Шафикова,Елена,Викторовна

+ 177 - 0
bin/periodIds.csv

@@ -0,0 +1,177 @@
+ID_PGROUP,NAME,YEAR1,YEAR2,COURSE_NUM,WEEK_NUM1,WEEK_NUM2,ID_PGROUPPERIOD
+91,ИС,2020,2023,1,1,17,509
+91,ИС,2020,2023,1,20,41,510
+91,ИС,2020,2023,2,1,15,511
+91,ИС,2020,2023,2,23,42,512
+91,ИС,2020,2023,3,1,12,513
+91,ИС,2020,2023,3,20,37,514
+91,ИС,2020,2023,4,1,15,515
+92,МО,2020,2022,1,1,17,552
+92,МО,2020,2022,1,20,39,553
+92,МО,2020,2022,2,1,9,550
+92,МО,2020,2022,2,22,33,551
+92,МО,2020,2022,3,1,25,666
+93,ТО,2020,2023,1,1,17,523
+93,ТО,2020,2023,1,20,41,524
+93,ТО,2020,2023,2,1,17,525
+93,ТО,2020,2023,2,23,42,526
+93,ТО,2020,2023,3,1,17,528
+93,ТО,2020,2023,3,23,33,529
+93,ТО,2020,2023,4,1,24,527
+94,ТМ,2020,2023,1,1,17,530
+94,ТМ,2020,2023,1,20,41,531
+94,ТМ,2020,2023,2,1,16,532
+94,ТМ,2020,2023,2,23,37,533
+94,ТМ,2020,2023,3,1,15,535
+94,ТМ,2020,2023,3,23,38,536
+94,ТМ,2020,2023,4,1,21,534
+95,ЭЛ,2020,2023,1,1,17,516
+95,ЭЛ,2020,2023,1,20,41,517
+95,ЭЛ,2020,2023,2,1,17,518
+95,ЭЛ,2020,2023,2,23,39,519
+95,ЭЛ,2020,2023,3,1,17,521
+95,ЭЛ,2020,2023,3,23,39,522
+95,ЭЛ,2020,2023,4,1,23,520
+96,ТП,2020,2023,1,1,17,546
+96,ТП,2020,2023,1,20,41,548
+96,ТП,2020,2023,2,22,39,544
+96,ТП,2020,2023,2,1,16,547
+96,ТП,2020,2023,3,1,15,545
+96,ТП,2020,2023,3,23,34,549
+96,ТП,2020,2023,4,1,20,676
+97,СП,2020,2023,1,1,17,537
+97,СП,2020,2023,1,20,41,538
+97,СП,2020,2023,2,1,15,539
+97,СП,2020,2023,2,23,43,540
+97,СП,2020,2023,3,1,15,542
+97,СП,2020,2023,3,23,38,543
+97,СП,2020,2023,4,1,21,541
+99,СП2,2020,2023,1,1,2,558
+99,СП2,2020,2023,2,1,2,616
+99,СП2,2020,2023,3,1,2,669
+99,СП2,2020,2023,4,1,2,712
+101,ИС,2021,2024,1,1,17,572
+101,ИС,2021,2024,1,20,41,573
+101,ИС,2021,2024,2,1,15,574
+101,ИС,2021,2024,2,23,42,575
+101,ИС,2021,2024,3,1,12,576
+101,ИС,2021,2024,3,23,38,577
+101,ИС,2021,2024,4,1,20,578
+102,ОС,2021,2023,1,1,17,609
+102,ОС,2021,2023,1,20,39,613
+102,ОС,2021,2023,2,1,15,664
+102,ОС,2021,2023,2,22,35,675
+102,ОС,2021,2023,3,1,14,680
+103,СВ,2021,2023,1,1,17,608
+103,СВ,2021,2023,1,20,39,614
+103,СВ,2021,2023,2,1,14,665
+103,СВ,2021,2023,2,22,34,674
+103,СВ,2021,2023,3,1,13,679
+104,СП,2021,2024,1,1,17,565
+104,СП,2021,2024,1,20,41,566
+104,СП,2021,2024,2,1,11,567
+104,СП,2021,2024,2,23,43,568
+104,СП,2021,2024,3,1,15,570
+104,СП,2021,2024,3,23,38,571
+104,СП,2021,2024,4,1,21,569
+105,ТМ,2021,2024,1,1,17,579
+105,ТМ,2021,2024,1,20,41,580
+105,ТМ,2021,2024,2,1,16,581
+105,ТМ,2021,2024,2,23,37,582
+105,ТМ,2021,2024,3,1,15,584
+105,ТМ,2021,2024,3,23,38,585
+105,ТМ,2021,2024,4,1,21,583
+106,ТО,2021,2024,1,1,17,586
+106,ТО,2021,2024,1,20,41,587
+106,ТО,2021,2024,2,1,17,588
+106,ТО,2021,2024,2,23,42,589
+106,ТО,2021,2024,3,1,17,591
+106,ТО,2021,2024,3,23,38,592
+106,ТО,2021,2024,4,1,21,590
+107,ЭЛ,2021,2024,1,1,17,593
+107,ЭЛ,2021,2024,1,20,41,594
+107,ЭЛ,2021,2024,2,1,17,595
+107,ЭЛ,2021,2024,2,23,39,596
+107,ЭЛ,2021,2024,3,1,17,598
+107,ЭЛ,2021,2024,3,23,38,599
+107,ЭЛ,2021,2024,4,1,21,597
+108,СПП,2021,2024,1,1,17,600
+108,СПП,2021,2024,1,20,41,601
+108,СПП,2021,2024,2,1,15,602
+108,СПП,2021,2024,2,23,38,603
+108,СПП,2021,2024,3,1,16,605
+108,СПП,2021,2024,3,23,38,606
+108,СПП,2021,2024,4,1,21,604
+109,ЭЛ2,2021,2024,1,1,2,611
+109,ЭЛ2,2021,2024,2,1,2,668
+109,ЭЛ2,2021,2024,3,1,2,708
+110,ИС,2022,2025,1,1,17,619
+110,ИС,2022,2025,1,20,41,620
+110,ИС,2022,2025,2,1,15,621
+110,ИС,2022,2025,2,23,42,622
+110,ИС,2022,2025,3,1,17,623
+110,ИС,2022,2025,3,23,38,624
+110,ИС,2022,2025,4,1,20,625
+112,МО,2022,2024,1,1,17,661
+112,МО,2022,2024,1,20,36,673
+112,МО,2022,2024,2,1,10,705
+112,МО,2022,2024,2,22,38,706
+113,ЭМ,2022,2024,1,1,17,662
+113,ЭМ,2022,2024,1,20,38,672
+113,ЭМ,2022,2024,2,1,14,707
+114,ТО,2022,2025,1,1,17,647
+114,ТО,2022,2025,1,20,41,648
+114,ТО,2022,2025,2,1,17,649
+114,ТО,2022,2025,2,23,38,650
+114,ТО,2022,2025,3,1,16,652
+114,ТО,2022,2025,3,23,38,653
+114,ТО,2022,2025,4,1,21,651
+115,СП,2022,2025,1,1,17,626
+115,СП,2022,2025,1,20,41,627
+115,СП,2022,2025,2,1,11,628
+115,СП,2022,2025,2,23,38,629
+115,СП,2022,2025,3,1,16,631
+115,СП,2022,2025,3,23,38,632
+115,СП,2022,2025,4,1,21,630
+116,ТМ,2022,2025,1,1,17,640
+116,ТМ,2022,2025,1,20,41,641
+116,ТМ,2022,2025,2,1,16,642
+116,ТМ,2022,2025,2,23,37,643
+116,ТМ,2022,2025,3,1,16,645
+116,ТМ,2022,2025,3,23,38,646
+116,ТМ,2022,2025,4,1,21,644
+117,ЭЛ,2022,2025,1,1,17,654
+117,ЭЛ,2022,2025,1,20,41,655
+117,ЭЛ,2022,2025,2,1,17,656
+117,ЭЛ,2022,2025,2,23,38,657
+117,ЭЛ,2022,2025,3,1,16,659
+117,ЭЛ,2022,2025,3,23,38,660
+117,ЭЛ,2022,2025,4,1,21,658
+119,СП2,2022,2025,1,1,2,667
+119,СП2,2022,2025,2,1,2,713
+120,СПП,2022,2025,1,1,17,633
+120,СПП,2022,2025,1,20,41,634
+120,СПП,2022,2025,2,1,15,635
+120,СПП,2022,2025,2,23,38,636
+120,СПП,2022,2025,3,1,16,638
+120,СПП,2022,2025,3,23,38,639
+120,СПП,2022,2025,4,1,21,637
+121,БУ2,2022,2024,1,1,2,671
+121,БУ2,2022,2024,2,1,2,709
+122,ИС,2023,2026,1,1,17,681
+122,ИС,2023,2026,1,20,43,682
+123,НС,2023,2025,1,1,17,704
+124,ОС,2023,2024,1,1,17,703
+125,ПК,2023,2026,1,1,17,687
+125,ПК,2023,2026,1,20,43,688
+126,СВ,2023,2024,1,1,17,701
+127,СП,2023,2026,1,1,17,695
+127,СП,2023,2026,1,20,43,696
+128,ТМ,2023,2026,1,1,17,699
+128,ТМ,2023,2026,1,20,43,700
+129,ТО,2023,2026,1,1,17,683
+129,ТО,2023,2026,1,20,43,684
+130,ЭЛ,2023,2026,1,1,17,691
+130,ЭЛ,2023,2026,1,20,43,692
+131,ЭЛ2,2023,2026,1,1,2,710
+132,БУ2,2023,2025,1,1,2,711

+ 94 - 0
bin/seed.php

@@ -0,0 +1,94 @@
+#!/usr/bin/env php
+<?php
+
+// Загружает первоначальные данные в БД
+// Аргументы:
+// 1. Год поступления первого курса
+// 2. Путь к файлу .CSV, где хранятся id семестров avers
+// 3. Путь к файлу .CSV, где хранятся все работники техникума, которых нужно
+// добавить
+
+use BotKit\Common\Database;
+use BotKit\Entities;
+
+require __DIR__ . '/../src/bootstrap.php';
+
+$em = Database::getEM();
+$start_year = $argv[1];
+$avers_period_path = $argv[2];
+$employee_path = $argv[3];
+
+// --Специальности и группы--
+$spec_names = ["СП","ТО","ТМ","ИС","ЭЛ","ПК","ОС","МО","ЭМ","НС","СВ","ТП"];
+foreach ($spec_names as $spec_name) {
+    // Для каждой специальности создаётся запись специальности и 4 курса
+    $spec = new Entities\CollegeSpec();
+    $spec->setName($spec_name);
+    $em->persist($spec);
+
+    for ($i = 1; $i < 5; $i++) {
+        $group = new Entities\CollegeGroup();
+        $group->setSpec($spec);
+        $group->setEnrollmentYear($start_year + $i - 1);
+        $em->persist($group);
+    }
+}
+
+$em->flush();
+
+// --Аверс--
+$av_data = file($avers_period_path);
+for ($y = 1; $y < count($av_data); $y++) {
+    $row = explode(",", $av_data[$y]);
+
+    // --Определяем какая группа имеется ввиду в этой строке--
+    // Специальность
+    $target_spec = $em->getRepository(Entities\CollegeSpec::class)->findOneBy([
+        'name' => $row[1]
+    ]);
+
+    if ($target_spec === null) {
+        // Не будем разбираться -- просто игнорируем
+        continue;
+    }
+
+    $target_enrolled_at = $row[2]; // Когда зачислилась
+    $target_group = $em->getRepository(Entities\CollegeGroup::class)->findOneBy([
+        'spec' => $target_spec,
+        'enrollment_year' => $target_enrolled_at
+    ]);
+
+    // --Определение номера семестра--
+    // Если WEEK_NUM1 - 1, то это начало нового учебного года, в одном году
+    // два семестра.
+    // Тем самым, номер семестра = ...
+    if ($row[5] == 1) {
+        // ... COURSE_NUM * 2 - 1
+        $ord_num = $row[4] * 2 - 1;
+    } else {
+        // ... COURSE_NUM * 2
+        $ord_num = $row[4] * 2;
+    }
+
+    // --Создаём запись--
+    $period = new Entities\Period();
+    $period->setGroup($target_group);
+    $period->setOrdNumber($ord_num);
+    $period->setAversId(trim($row[7]));
+    $em->persist($period);
+}
+
+$employee_data = file($employee_path);
+for ($y = 1; $y < count($employee_data); $y++) {
+    $row = explode(",", $employee_data[$y]);
+
+    $employee = new Entities\Employee();
+    $employee->setSurname($row[0]);
+    $employee->setName($row[1]);
+    $employee->setPatronymic($row[2]);
+    $em->persist($employee);
+}
+
+$em->flush();
+
+echo "Старт базы данных проведён успешно!";

+ 4 - 1
composer.json

@@ -10,7 +10,10 @@
         }
     ],
     "require": {
-        "vlucas/phpdotenv": "^5.6"
+        "vlucas/phpdotenv": "^5.6",
+        "doctrine/orm": "^3.1",
+        "doctrine/dbal": "^4.0",
+        "symfony/cache": "^7.0"
     },
     "autoload": {
         "psr-4": {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1156 - 9
composer.lock


+ 9 - 17
index.php

@@ -3,7 +3,7 @@ namespace BotKit;
 
 // Файл, на который поступают запросы
 
-require_once __DIR__.'/src/bootstrap.php';
+require_once __DIR__ . '/src/bootstrap.php';
 use BotKit\Common\Bot;
 use BotKit\Common\Commands;
 use BotKit\Common\Message;
@@ -26,7 +26,6 @@ $bot->onCallback(CallbackType::SelectGroupCourse, function($e, $u, $driver) {
     // Переносим полученные параметры в новую клавиатуру
     // А так же изменяем сообщение
     $params = $e->getParams();
-    
     $driver->editMessage(
         $e->getMessageID(),
         Message::create("Выбери группу")
@@ -34,12 +33,14 @@ $bot->onCallback(CallbackType::SelectGroupCourse, function($e, $u, $driver) {
     );
 });
 
+/*
 // Выбор непосредственно группы
-$bot->onCallback(CallbackType::SelectGroup, 'BotKit\Common\Commands::handleGroupSelection');
+$bot->onCallback(CallbackType::SelectGroup, 'BotKit\Common\Commands::handleGroupSelection'); */
 
 // Просмотр условий использования
 $bot->onCallback(CallbackType::TOS, 'BotKit\Common\Commands::showTermsOfService');
 
+/*
 // Ввод логина и пароля при регистрации
 $bot->onCallback(CallbackType::EnterCredentials, 'BotKit\Common\Commands::enterCredentials');
 
@@ -48,25 +49,16 @@ $bot->on(
     PlainMessageEvent::class,
     function ($e, $u, $driver) { return $u->getState() == State::NoResponse; },
     function($e, $u, $driver) {}
-);
+);*/
 
 // Начало диалога
 $bot->onCommand('/start', 'BotKit\Common\Commands::helloWorld');
-$bot->on(
-    PlainMessageEvent::class,
-    function ($e, $u, $driver) { return $u->getState() == State::HelloWorld; },
-    "BotKit\Common\Commands::helloWorld"
-);
+$bot->onPlainMessage(State::HelloWorld, "BotKit\Common\Commands::helloWorld");
 
 // Выбор типа аккаунта
-$bot->on(
-    PlainMessageEvent::class,
-    function ($e, $u, $driver) {
-        return $u->getState() == State::RegSelectType;
-    },
-    "BotKit\Common\Commands::handleSelectType"
-);
+$bot->onPlainMessage(State::RegSelectType, "BotKit\Common\Commands::handleSelectType");
 
+/*
 // Ввод пароля при регистрации
 $bot->on(
     PlainMessageEvent::class,
@@ -74,7 +66,7 @@ $bot->on(
         return $u->getState() == State::RegLogin;
     },
     "BotKit\Common\Commands::handleRegLogin"
-);
+); */
 
 // План "Б"
 $bot->onEvent(UnknownEvent::class, "BotKit\Common\Commands::unknownEvent");

+ 13 - 6
src/Common/Bot.php

@@ -8,6 +8,7 @@ use BotKit\Models\UserModel;
 use BotKit\Events\PlainMessageEvent;
 use BotKit\Events\CallbackEvent;
 use BotKit\Enums\CallbackType;
+use BotKit\Enums\State;
 
 class Bot {
 
@@ -57,11 +58,9 @@ class Bot {
         call_user_func_array($callback, $final_params);
 
         // Сохранение пользователя...
-        if ($user->hasChanged()) {
-            // Бот изменил пользователя, сохраняем его данные
-            UserModel::updateObject($user->getDbObject());
-            $this->driver->onUserSave($user);
-        }
+        $em = Database::getEM();
+        $em->flush();
+        $this->driver->onUserSave($user);
 
         // Завершение работы драйвера...
         $this->driver->onProcessEnd();
@@ -85,7 +84,6 @@ class Bot {
         }
 
         // Проверка условия события
-        // TODO: добавить параметры команды
         $check_params = [
             'e' => $this->event,
             'u' => $this->event->getUser(),
@@ -162,6 +160,15 @@ class Bot {
         $this->processRequest($responseCallback, []);
     }
 
+    // Подключает обработчик текстового для состояния пользователя
+    public function onPlainMessage(State $required_state, callable $callback) {
+        if (!$this->event->getUser()->inState($required_state)) {
+            // Требуемое состояние у пользователя не обнаружено
+            return;
+        }
+        $this->processRequest($callback, []);
+    }
+
     // Все условия не прошли, вызываем план Б
     public function fallback(callable $callback) {
         $this->processRequest($callback, []);

+ 6 - 5
src/Common/Commands.php

@@ -28,7 +28,6 @@ class Commands {
         $driver->editMessage(
             $e->getMessageID(),
             Message::create("[Условия использования]")
-            ->withImage(ImageAttachment::fromUrl('https://images.wallpaperscraft.ru/image/single/pustynia_peski_diuny_1207604_800x1200.jpg'))
         );
     }
 
@@ -39,7 +38,7 @@ class Commands {
         switch ($intent) {
             case GroupSelect::Register:
                 // Группа выбрана, зарегистрирован студент
-                StudentModel::create($u['id'], $params['group_id'], 0);
+                Models\StudentModel::create($u['id'], $params['group_id'], 0);
                 
                 $driver->editMessage(
                     $e->getMessageID(),
@@ -123,19 +122,21 @@ class Commands {
     }
 
     // Обработка ввода логина при регистрации
+    /*
     public static function handleRegLogin($e, $u, $driver) {
         $student = Models\StudentModel::where([
             ['user_id', '=', $u['id']]
         ])[0];
 
-        $driver->varDump("Student", $student);
+        $student[
     }
+    */
 
     public static function fallback($e, $u, $driver) {
-        $driver->sendMessage($u, Message::create("Функционал не реализован"));
+        $driver->sendMessage($u, Message::create("[Fallback]: Ни один обработчик не сработал. Сообщите об этом сообщении администратору"));
     }
 
     public static function unknownEvent($e, $u, $driver) {
-        $driver->sendMessage($u, Message::create("Неизвестное событие"));
+        $driver->sendMessage($u, Message::create("[Fallback]: Неизвестное событие. Сообщите об этом сообщении администратору"));
     }
 }

+ 28 - 23
src/Common/Database.php

@@ -1,44 +1,49 @@
 <?php
 // Класс работы с БД
-// Этот файл может быть изменён разработчиком
 
 namespace BotKit\Common;
+use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Tools\DsnParser;
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\ORMSetup;
 
 class Database {
     private static $db;
     private $connection;
+    private $entity_manager;
     
-    private function __construct($dsn, $user, $password) {
-        // https://mariadb.com/resources/blog/developer-quickstart-php-data-objects-and-mariadb/
-        $options = [
-            \PDO::ATTR_EMULATE_PREPARES   => false,
-            \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
-            \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
-        ];
-        $this->connection = new \PDO($dsn, $user, $password);
+    private function __construct($dsn) {
+        // Подключение к БД
+        $dsnParser = new DsnParser();
+        $connection_params = $dsnParser->parse($_ENV['dsn']);
+        $this->connection = DriverManager::getConnection($connection_params);
+
+        // Получение менеджера сущностей
+        $config = ORMSetup::createAttributeMetadataConfiguration(
+            paths: array(rootdir.'src/Entities'),
+            isDevMode: true,
+        );
+        $this->entity_manager = new EntityManager($this->connection, $config);
     }
 
     // Инициализирует БД
-    public static function init($host=null,$db_name=null,$user=null,$password=null): void {
-
-        $host       = $host     ? $host     : $_ENV['db_host'];
-        $db_name    = $db_name  ? $db_name  : $_ENV['db_name'];
-        $user       = $user     ? $user     : $_ENV['db_user'];
-        $password   = $password ? $password : $_ENV['db_password'];
+    public static function init($dsn): void {
+        self::$db = new Database($dsn);
+    }
 
+    // Возвращает ссылку на $connection
+    public static function getConnection() {
         if (self::$db == null) {
-            self::$db = new Database(
-                "mysql:host=".$host.";dbname=".$db_name.";charset=utf8mb4",
-                $user,
-                $password
-            );
+            self::init($_ENV['dsn']);
         }
+        return self::$db->connection;
     }
 
-    public static function getConnection() {
+    // Возвращает ссылку на $entity_manager
+    public static function getEM() {
         if (self::$db == null) {
-            self::init();
+            self::init($_ENV['dsn']);
         }
-        return self::$db->connection;
+        return self::$db->entity_manager;
     }
 }

+ 0 - 66
src/Common/EventData.php

@@ -1,66 +0,0 @@
-<?php
-// Класс события
-
-namespace BotKit\Common;
-
-class EventData {
-
-	// Текст сообщения (если присутствует)
-	private string $text;
-
-	// Данные, которые были получены непосредственно сервером
-	private $payload;
-
-	// Тип события
-	private int $event_type;
-
-	// Тип обратного вызова (если событие - обратный вызов)
-	private int $callback_type;
-
-	// Данные обратного вызова (если событие - обратный вызов)
-	private array $callback_data;
-
-	public function __construct(
-		$text,
-		$payload,
-		$event_type,
-		$callback_type=CallbackType::None,
-		$callback_data = []
-	)
-	{
-		$this->text = $text;
-		$this->payload = $payload;
-		$this->event_type = $event_type;
-		$this->callback_type = $callback_type;
-		$this->callback_data = $callback_data;
-	}
-
-	// Возвращает объект $payload
-	public function getPayload() {
-		return $this->payload;
-	}
-
-	// Возвращает тип события
-	public function getEventType() : int {
-		return $this->event_type;
-	}
-
-	// Возвращает текст
-	public function getText() : string {
-		return $this->text;
-	}
-
-	// Сравнивает текст с параметром
-	public function textIs(string $to_compare) : bool {
-		return $to_compare == $this->text;
-	}
-
-	public function getCallbackType() : int {
-		return $this->callback_type;
-	}
-
-	public function getCallbackData() {
-		return $this->callback_data;
-	}
-	
-}

+ 0 - 81
src/Common/User.php

@@ -1,81 +0,0 @@
-<?php
-// Класс пользователя бота
-
-namespace BotKit\Common;
-
-use BotKit\Enums\State;
-use BotKit\Models\Model;
-
-class User implements \ArrayAccess {
-    
-    private $platform_id;       // ID на платформе
-    private State $state;       // Состояние
-    private ?string $nick;      // Короткий идентификатор пользователя
-    private array $dbobj;       // Модель из БД
-    private bool $is_changed;   // Изменено ли состояние
-
-    public function __construct(
-        $platform_id,
-        State $state,
-        ?string $nick,
-        array $dbobj
-    )
-    {
-        $this->platform_id = $platform_id;
-        $this->state = $state;
-        $this->nick = $nick;
-        $this->dbobj = $dbobj;
-        $this->is_changed = false;
-    }
-
-    public function getPlatformID() {
-        return $this->platform_id;
-    }
-
-    public function getNick() : ?string {
-        return $this->nick;
-    }
-
-    public function getDbObject() : array {
-        return $this->dbobj;
-    }
-
-    public function getState() : State {
-        return $this->state;
-    }
-
-    public function hasChanged() : bool {
-        return $this->is_changed;
-    }
-
-    // Устанавливает состояние
-    // состояние будет отображаться в $this->state прежде чем пользователь
-    // не будет сохранён
-    public function setState(State $state) : void {
-        $this->state = $state;
-        $this['state'] = $state->value;
-    }
-
-    #region Реализация ArrayAccess
-    public function offsetSet($offset, $value): void {
-        $this->is_changed = true;
-        if (is_null($offset)) {
-            $this->dbobj[] = $value;
-        } else {
-            $this->dbobj[$offset] = $value;
-        }
-    }
-
-    public function offsetExists($offset): bool {
-        return isset($this->dbobj[$offset]);
-    }
-
-    public function offsetUnset($offset): void {
-        unset($this->dbobj[$offset]);
-    }
-
-    public function offsetGet($offset) : mixed {
-        return isset($this->dbobj[$offset]) ? $this->dbobj[$offset] : null;
-    }
-    #endregion
-}

+ 4 - 1
src/Drivers/Driver.php

@@ -3,10 +3,10 @@
 
 namespace BotKit\Drivers;
 
-use BotKit\Common\User;
 use BotKit\Common\Chat;
 use BotKit\Common\Message;
 use BotKit\Common\EventData;
+use BotKit\Entities\User;
 use BotKit\Events\Event;
 use BotKit\Events\PlainMessageEvent;
 
@@ -49,4 +49,7 @@ interface Driver {
 
     // Событие сохранения пользователя
     public function onUserSave(User $user) : void;
+
+    // Вывод отладочного сообщения
+    public function varDump(string $title, $variable) : void;
 }

+ 62 - 60
src/Drivers/TestDriver.php

@@ -9,7 +9,6 @@ use BotKit\Events\UnknownEvent;
 use BotKit\Events\CallbackEvent;
 use BotKit\Events\MemberJoinedEvent;
 use BotKit\Events\MemberLeftEvent;
-use BotKit\Common\User;
 use BotKit\Common\Chat;
 use BotKit\Common\Message;
 use BotKit\Common\Database;
@@ -19,9 +18,10 @@ use BotKit\Enums\Platform;
 use BotKit\Enums\State;
 use BotKit\Enums\KeyboardButtonColor;
 use BotKit\Enums\CallbackType;
-use BotKit\Models\UserModel;
 use BotKit\KeyboardButtons\CallbackButton;
 
+use BotKit\Entities;
+
 class TestDriver implements Driver {
     // Платформа бота
     private Platform $platform;
@@ -29,48 +29,41 @@ class TestDriver implements Driver {
     // Буфер действий
     private array $actions = [];
 
+    // Состояние пользвателя при начале обработки запроса
+    private State $start_user_state;
+
     public function __construct() {
         $this->platform = Platform::Test;
     }
 
-    #region Driver
+    #region Driver implementation
 
     public function forThis() : bool {
         return true;
     }
 
-    public function onSelected() : void {
-        set_error_handler([$this, "errorHandler"], E_ALL);
-        set_exception_handler([$this, "exceptionHandler"]);
-    }
-
-    public function onProcessStart() : void {
-    }
-
-    public function onProcessEnd() : void {
-        $this->echoActions();
-    }
-
     public function getEvent() : Event {
         $data = json_decode(file_get_contents("php://input"), true);
-        $db = Database::getConnection();
-
+        $em = Database::getEM();
         $details = $data['details'];
         $chat = new Chat(42);
 
         // Интерфейс тестов запрашивает установку состояния
         if ($data['type'] == 'stateSet') {
             $user = $this->getUser($details['userID']);
-            $user->setState(State::from($details['stateID']));
+            $user->setStateByInt($details['stateID']);
 
-            // Сохраняем пользователя вручную
-            UserModel::updateObject($user->getDbObject());
-            
+            // Сохраняем пользователя
+            $em->persist($user);
+            $em->flush();
+
+            // Оповещение об изменении
             $this->actions[] = [
                 "action" => "info",
                 "title" => "Состояние пользователя изменено вручную",
-                "body" => "Новое состояние: ".serialize($user->getState())
+                "body" => "Новое состояние: ".$user->getStateName()
             ];
+            
             // Дальнейшая обработка не требуется, завершаем выполнение здесь
             $this->echoActions();
         }
@@ -90,10 +83,9 @@ class TestDriver implements Driver {
 
         if ($data['type'] == 'callback') {
             // Обратный вызов
-            $user = $this->getUser($details['userId']);
             return new CallbackEvent(
                 $details['msgId'],
-                $user,
+                $user = $this->getUser($details['userId']),
                 $chat,
                 CallbackType::from($details['callbackType']),
                 $details['params']
@@ -102,13 +94,11 @@ class TestDriver implements Driver {
 
         if ($data['type'] == 'botKitMsg') {
             // Обычное текстовое сообщение
-            $user = $this->getUser($details['userID']);
-            $text = $details['text'];
             return new PlainMessageEvent(
                 $details['id'],
-                $user,
+                $this->getUser($details['userID']),
                 $chat,
-                $text,
+                $details['text'],
                 []
             );
         }
@@ -116,6 +106,18 @@ class TestDriver implements Driver {
         return new UnknownEvent();
     }
 
+    public function onSelected() : void {
+        set_error_handler([$this, "errorHandler"], E_ALL);
+        set_exception_handler([$this, "exceptionHandler"]);
+    }
+
+    public function onProcessStart() : void {
+    }
+
+    public function onProcessEnd() : void {
+        $this->echoActions();
+    }
+
     public function reply(PlainMessageEvent $e, Message $msg, bool $empathise = true) {
         if ($empathise) {
             $reply_to_id = $e->getMessageID();
@@ -125,7 +127,7 @@ class TestDriver implements Driver {
         $this->sendInternal($msg, $reply_to_id);
     }
 
-    public function sendMessage(User $u, Message $msg) {
+    public function sendMessage(Entities\User $u, Message $msg) {
         $this->sendInternal($msg, -1);
     }
 
@@ -141,16 +143,21 @@ class TestDriver implements Driver {
         $this->sendInternal($msg, -1);
     }
 
-    public function getUserNick(User $u) : string {
+    public function getUserNick(Entities\User $u) : string {
         return $u->getNick();
     }
 
-    public function onUserSave(User $user) : void {
-        $this->actions[] = [
-            "action" => "info",
-            "title" => "Состояние пользователя изменено",
-            "body" => "Новое состояние: ".serialize($user->getState())
-        ];
+    public function onUserSave(Entities\User $user) : void {
+        $end_state = $user->getState();
+        if ($this->start_user_state != $end_state) {
+            // Если вначале пользователь был в одном состоянии, а в конце
+            // в другом, уведомляем об этом
+            $this->actions[] = [
+                "action" => "info",
+                "title" => "Состояние пользователя изменено",
+                "body" => "Новое состояние: ".serialize($end_state)
+            ];
+        }
     }
     
     #endregion
@@ -221,8 +228,6 @@ class TestDriver implements Driver {
 
     // Отправляет сообщение
     private function sendInternal(Message $msg, int $reply_to_id) : void {
-        
-
         $this->actions[] = [
             "action" => "newMessage",
             "message" => $this->getMessageData($msg, $reply_to_id)
@@ -315,7 +320,7 @@ class TestDriver implements Driver {
     }
 
     // Информация о переменной
-    public function varDump(string $title, $variable) {
+    public function varDump(string $title, $variable) : void {
         ob_start();
         var_dump($variable);
         $info = ob_get_clean();
@@ -327,30 +332,27 @@ class TestDriver implements Driver {
     }
 
     // Возвращает объект пользвателя
-    public function getUser($userID) : User {
+    public function getUser($userID) : Entities\User {
         // Получение объекта из БД
-        $obj = UserModel::where([
-            ['platform_id', '=', $userID],
-            ['platform', '=', $this->platform->value]
-        ])[0];
-
-        if ($obj === false) {
-            // Пользователя нет в БД
-            $obj = UserModel::create(
-                $userID,
-                $this->platform->value,
-                State::HelloWorld->value
-            );
+        $em = Database::getEM();
+
+        // Искать по id_on_platform
+        $user = $em->getRepository(Entities\User::class)
+            ->findOneBy([
+                'id_on_platform' => $userID,
+                'platform_id' => $this->platform->value
+            ]);
+
+        if ($user == null) {
+            // Пользователя нет в БД, создаём
+            $user = new Entities\User();
+            $user->setIdOnPlatform($userID);
+            $user->setPlatformId($this->platform->value);
+            $em->persist($user);
+            $em->flush();
         }
 
-        $state_obj = State::from($obj['state']);
-
-        $user = new User(
-            $userID,
-            $state_obj,
-            "Test username",
-            $obj
-        );
+        $this->start_user_state = $user->getState();
 
         return $user;
     }

+ 40 - 0
src/Entities/CollegeGroup.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity(repositoryClass: CollegeGroupRepository::class)]
+#[ORM\Table(name: 'college_group')]
+class CollegeGroup {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Год поступления в техникум
+    #[ORM\Column(type: 'integer')]
+    private int $enrollment_year;
+
+    // Специальность группы
+    #[ORM\ManyToOne(CollegeSpec::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private CollegeSpec $spec;
+
+    public function getID() {
+        return $this->id;
+    }
+
+    public function getSpec() {
+        return $this->spec;
+    }
+
+    public function setSpec(CollegeSpec $spec) {
+        $this->spec = $spec;
+    }
+
+    public function setEnrollmentYear(int $year) {
+        $this->enrollment_year = $year;
+    }
+}

+ 27 - 0
src/Entities/CollegeGroupRepository.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace BotKit\Entities;
+
+use Doctrine\ORM\EntityRepository;
+
+class CollegeGroupRepository extends EntityRepository {
+
+    // Возвращает группы по курсу
+    public function getAllGroupsByCourse(int $course_num) {
+        // Определяем текущий год и месяц
+        $current_year = (int)date('Y');
+        $current_month = (int)date('m');
+
+        // Определяем год поступления группы в соответствии с требуемым курсом
+        // и текущим годом
+        if ($current_month > 8) {
+            // Сейчас начало учебного года
+            $target_year = $current_year - $course_num + 1;
+        } else {
+            // Сейчас конец учебного года
+            $target_year = $current_year - $course_num;
+        }
+
+        return $this->findBy(['enrollment_year' => $target_year]);
+    }
+}

+ 32 - 0
src/Entities/CollegeSpec.php

@@ -0,0 +1,32 @@
+<?php
+namespace BotKit\Entities;
+
+// Специальность групп
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'college_spec')]
+class CollegeSpec {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Имя группы
+    #[ORM\Column(type: 'string', length: 8)]
+    private string $name;
+
+    public function getID() {
+        return $this->id;
+    }
+
+    public function getName() {
+        return $this->name;
+    }
+
+    public function setName($name) {
+        $this->name = $name;
+    }
+}

+ 39 - 0
src/Entities/Employee.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'employee')]
+class Employee {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Фамилия
+    #[ORM\Column(type: 'string', length: 50)]
+    private string $surname;
+
+    // Имя
+    #[ORM\Column(type: 'string', length: 50)]
+    private string $name;
+
+    // Отчество
+    #[ORM\Column(type: 'string', length: 50, nullable: true)]
+    private ?string $patronymic = null;
+
+    public function setSurname(string $surname) : void {
+        $this->surname = $surname;
+    }
+
+    public function setName(string $name) : void {
+        $this->name = $name;
+    }
+
+    public function setPatronymic(string $patronymic) : void {
+        $this->patronymic = $patronymic;
+    }
+}

+ 27 - 0
src/Entities/ImageCache.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'image_cache')]
+class ImageCache {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Тип изображения (оценки/расписание/...) 
+    #[ORM\Column(type: 'integer')]
+    private int $image_type;
+
+    // Ключ
+    #[ORM\Column(type: 'integer')]
+    private int $search;
+
+    // Значение
+    #[ORM\Column(type: 'string', length: 64)]
+    private string $value;
+}

+ 39 - 0
src/Entities/Pair.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'pair')]
+class Pair {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Для какого расписания
+    #[ORM\ManyToOne(Schedule::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private Schedule $schedule;
+
+    // Время проведения
+    #[ORM\Column(type: 'time', name: 'ptime')]
+    private \Datetime $time;
+
+    // Название пары
+    #[ORM\ManyToOne(PairName::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private PairName $pair_name;
+
+    // Кто проводит пару
+    #[ORM\ManyToOne(Employee::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private Employee $teacher;
+
+    // Место проведения
+    #[ORM\ManyToOne(PairPlace::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private PairPlace $place;
+}

+ 19 - 0
src/Entities/PairName.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'pair_name')]
+class PairName {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Название пары
+    #[ORM\Column(type: 'string', length: 255)]
+    private string $name;
+}

+ 19 - 0
src/Entities/PairPlace.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'pair_place')]
+class PairPlace {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Имя места проведения пары
+    #[ORM\Column(type: 'string', length: 255)]
+    private string $name;
+}

+ 42 - 0
src/Entities/Period.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace BotKit\Entities;
+
+// Семестр обучения
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'period')]
+class Period {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Группа для этой записи
+    #[ORM\ManyToOne(targetEntity: CollegeGroup::class)]
+    #[ORM\JoinColumn(nullable: false, name: 'group_id')]
+    private CollegeGroup $group;
+
+    // Номер семестра
+    #[ORM\Column(type: 'integer')]
+    private int $ord_number;
+
+    // ID семестра в системе АВЕРС
+    #[ORM\Column(type: 'integer')]
+    private int $avers_id;
+
+    public function setGroup(CollegeGroup $group) {
+        $this->group = $group;
+    }
+
+    public function setOrdNumber(int $ord_number) {
+        $this->ord_number = $ord_number;
+    }
+
+    public function setAversId(int $avers_id) {
+        $this->avers_id = $avers_id;
+    } 
+}

+ 23 - 0
src/Entities/Schedule.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'schedule')]
+class Schedule {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Группа, связанная с расписанием
+    #[ManyToOne(CollegeGroup::class)]
+    private CollegeGroup $group;
+
+    // День расписания
+    #[ORM\Column(type: 'date')]
+    private \DateTime $day;
+}

+ 37 - 0
src/Entities/Student.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'student')]
+class Student {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Связанный пользователь
+    #[ORM\OneToOne(User::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private User $user;
+
+    // Группа студента
+    #[ORM\ManyToOne(CollegeGroup::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private CollegeGroup $group;
+    
+    // Логин от АВЕРС
+    #[ORM\Column(type: 'string', length: 64, nullable: true)]
+    private ?string $avers_login = null;
+
+    // Пароль от АВЕРС
+    #[ORM\Column(type: 'string', length: 255, nullable: true)]
+    private ?string $avers_password = null;
+
+    // Отчислен ли студент
+    #[ORM\Column(type: 'boolean')]
+    private bool $expelled = false;
+}

+ 24 - 0
src/Entities/Teacher.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'teacher')]
+class Teacher {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // Связанный пользователь
+    #[ORM\OneToOne(User::class)]
+    #[ORM\JoinColumn(nullable: false)]
+    private User $user;
+
+    // Связанный сотрудник
+    #[ORM\ManyToOne(Employee::class)]
+    private ?Employee $employee = null;
+}

+ 62 - 0
src/Entities/User.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace BotKit\Entities;
+
+use BotKit\Enums\State;
+use Doctrine\ORM\Mapping as ORM;
+
+#[ORM\Entity]
+#[ORM\Table(name: 'user')]
+class User {
+    #[ORM\Id]
+    #[ORM\Column(type: 'integer')]
+    #[ORM\GeneratedValue]
+    private int|null $id = null;
+
+    // ID на платформе
+    #[ORM\Column(type: 'integer')]
+    private int $id_on_platform;
+
+    // ID платформы
+    #[ORM\Column(type: 'integer')]
+    private int $platform_id;
+
+    // Состояние пользователя
+    #[ORM\Column(type: 'integer')]
+    private int $state = State::HelloWorld->value;
+
+    // Устанавливает ID на платформе
+    public function setIdOnPlatform($id_on_platform) : void {
+        $this->id_on_platform = $id_on_platform;
+    }
+
+    // Устанавливает ID платформы
+    public function setPlatformId($platform_id) : void {
+        $this->platform_id = $platform_id;
+    }
+
+    // Устанавливает состояние через перечисление
+    public function setState(State $new_state) : void {
+        $this->state = $new_state->value;
+    }
+
+    // Возвращает состояние
+    public function getState() : State {
+        return State::from($this->state);
+    }
+
+    // Устанавливает состояние через int
+    public function setStateByInt(int $new_stateID) : void {
+        $this->state = $new_stateID;
+    }
+
+    // Возвращает название состояния в котором находится пользователь
+    public function getStateName() : string {
+        return serialize(State::from($this->state));
+    }
+
+    // Возвращает true если состояние пользователя совпадает со $state
+    public function inState(State $state) : bool {
+        return $state->value == $this->state;
+    }
+}

+ 1 - 1
src/Events/CallbackEvent.php

@@ -1,7 +1,7 @@
 <?php
 namespace BotKit\Events;
 
-use BotKit\Common\User;
+use BotKit\Entities\User;
 use BotKit\Common\Chat;
 use BotKit\Enums\CallbackType;
 

+ 1 - 1
src/Events/Event.php

@@ -3,7 +3,7 @@ namespace BotKit\Events;
 
 // Класс события
 
-use BotKit\Common\User;
+use BotKit\Entities\User;
 
 class Event {
     protected User $user;

+ 1 - 1
src/Events/PlainMessageEvent.php

@@ -1,7 +1,7 @@
 <?php
 namespace BotKit\Events;
 
-use BotKit\Common\User;
+use BotKit\Entities\User;
 use BotKit\Common\Chat;
 
 class PlainMessageEvent extends Event {

+ 11 - 5
src/Keyboards/SelectGroupNameKeyboard.php

@@ -8,7 +8,8 @@ use BotKit\KeyboardButtons\CallbackButton;
 use BotKit\Enums\KeyboardButtonColor;
 use BotKit\Enums\CallbackType;
 
-use BotKit\Models\CollegeGroupModel;
+use BotKit\Entities;
+use BotKit\Common\Database;
 
 class SelectGroupNameKeyboard extends Keyboard {
 	#region Драйвер-зависимые свойства
@@ -18,25 +19,30 @@ class SelectGroupNameKeyboard extends Keyboard {
 	public $inline=true;
 	#endregion
 
-	public function __construct($intent, $course) {
+	public function __construct($intent, int $course) {
 		// $intent - дополнительное значение для типа обратного вызова
 		// Обозначает что необходимо выполнить после того, как будет выбрана
 		// специальность
 
 		// $course - курс, выбранный ранее
 		
+        $em = Database::getEM();
 		$this->layout = [];
-		$groups = CollegeGroupModel::getByCourse($course);
+
+        // Искать по году зачисления
+        $groups = $em
+			->getRepository(Entities\CollegeGroup::class)
+			->getAllGroupsByCourse($course);
 
 		$row_item_count = 0;
 		$row = [];
 
 		foreach ($groups as $group) {
 			$row[] = new CallbackButton(
-				$group['name'],
+				$group->getName(),
 				CallbackType::SelectGroup,
 				KeyboardButtonColor::None,
-				['group_id' => $group['id'], 'intent' => $intent]
+				['group_id' => $group->getID(), 'intent' => $intent]
 			);
 
 			// Только 3 кнопки на ряд

+ 0 - 3
src/Models/.gitignore

@@ -1,3 +0,0 @@
-*
-!.gitignore
-!Model.php

+ 0 - 56
src/Models/Model.php

@@ -1,56 +0,0 @@
-<?php
-// Класс работы с моделями
-// Только для наследования
-
-namespace BotKit\Models;
-
-use BotKit\Common\Database;
-
-class Model {
-    protected static $allowed_columns;
-
-    protected static function allowedColumnsSQL() {
-        return implode(',', static::$allowed_columns);
-    }
-
-    // Возвращает все записи из таблицы
-    public static function all() {
-        $db = Database::getConnection();
-        return $db->query("SELECT ".static::allowedColumnsSQL()." FROM ".static::$table_name);
-    }
-
-    // Поиск по ID
-    public static function find($id) {
-        $db = Database::getConnection();
-        $stm = $db->prepare("SELECT ".static::allowedColumnsSQL()." FROM ".static::$table_name. " WHERE id=:id");
-        $stm->bindValue(':id', $id);
-        $stm->execute();
-        return $stm->fetch();
-    }
-
-    // Возвращает записи по условиям
-    // Все условия должны быть истины, т. к. для построения запроса используется 'AND'
-    public static function where($conditions) {
-        $db = Database::getConnection();
-
-        // Построение текста условий
-        $conditions_sql = '';
-        $first_condition = true;
-        foreach ($conditions as $condition) {
-            if ($first_condition == false) {
-                $conditions_sql .= " AND ";
-            }
-            $conditions_sql .= $condition[0].$condition[1].':'.$condition[0];
-            $first_condition = false;
-        }
-
-        $stm = $db->prepare(
-            "SELECT ".static::allowedColumnsSQL()." FROM ".static::$table_name." WHERE ".$conditions_sql
-        );
-        foreach ($conditions as $condition) {
-            $stm->bindValue(":".$condition[0], $condition[2]);
-        }
-        $stm->execute();
-        return $stm->fetchAll();
-    }
-}

+ 6 - 2
src/bootstrap.php

@@ -1,10 +1,14 @@
 <?php
 
-// Общий файл инициализации
+// --Общий файл инициализации--
+// bootstrap.php
 
+// Константы
 define('rootdir', __DIR__.'/../');
 
+// Автозагрузка через composer
 require_once rootdir."vendor/autoload.php";
 
+// Загрузка .env файла
 $dotenv = \Dotenv\Dotenv::createImmutable(rootdir);
-$dotenv->load();
+$dotenv->load();

+ 0 - 3
tools/ModelGeneratorTable.php

@@ -53,9 +53,6 @@ class ModelGeneratorTable {
             $max_column_length = max(mb_strlen($column_name), $max_column_length);
 
             $create_params .= "\$$column_name";
-            if ($column->isNullable()) {
-                $create_params .= '=null';
-            }
 
             $object_binds .= "        \$statement->bindValue(':$column_name', \$object['$column_name']);\n";
             $params_binds .= "        \$statement->bindValue(':$column_name', \$$column_name);\n";

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä