Розробка освітньої платформи (LMS) на 1С-Bitrix
1С-Bitrix — не перший вибір для LMS. Є Moodle, Teachable, GetCourse. Але компанії обирають Bitrix, коли вже є сайт на ньому, потрібна єдина авторизація з корпоративним порталом або інтернет-магазином, і немає бажання підтримувати кілька систем. У такому випадку Bitrix цілком справляється: інфоблоки для зберігання курсів, групи користувачів для доступу, агенти для прогресу, платіжний модуль для монетизації.
Архітектура зберігання даних
LMS на Bitrix будується на комбінації інфоблоків і HighLoad-блоків (HL-блоки, таблиці через D7 ORM).
Інфоблоки:
| Інфоблок | Код | Призначення |
|---|---|---|
| Курси | lms_courses |
Основні сутності курсів |
| Уроки | lms_lessons |
Уроки всередині курсу |
| Тести | lms_quizzes |
Завдання та тести |
HL-блоки (через ORM):
// Прогрес користувача
class UserProgressTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'b_hl_lms_user_progress'; }
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new IntegerField('USER_ID'),
new IntegerField('COURSE_ID'), // ID елементу інфоблоку курсу
new IntegerField('LESSON_ID'), // ID елементу інфоблоку уроку
new EnumField('STATUS', ['values' => ['NOT_STARTED', 'IN_PROGRESS', 'COMPLETED']]),
new IntegerField('PROGRESS_PERCENT'), // 0–100
new DatetimeField('STARTED_AT'),
new DatetimeField('COMPLETED_AT'),
new IntegerField('TIME_SPENT_SEC'), // Час на урок
];
}
}
// Записи на курс (enrollment)
class CourseEnrollmentTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'b_hl_lms_enrollment'; }
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new IntegerField('USER_ID'),
new IntegerField('COURSE_ID'),
new EnumField('STATUS', ['values' => ['ACTIVE', 'COMPLETED', 'EXPIRED', 'REFUNDED']]),
new DatetimeField('ENROLLED_AT'),
new DatetimeField('EXPIRES_AT'), // NULL = безстроково
new FloatField('PAID_AMOUNT'),
new IntegerField('ORDER_ID'), // Прив'язка до замовлення модуля sale
];
}
}
Структура курсу та уроків
Курс — елемент інфоблоку lms_courses з властивостями:
| Властивість | Код | Тип |
|---|---|---|
| Категорія | CATEGORY |
Список |
| Тривалість | DURATION_HOURS |
Число |
| Рівень | LEVEL |
Список (Початківець/Середній/Експерт) |
| Тип доступу | ACCESS_TYPE |
Список (Безкоштовний/Платний/За підпискою) |
| Група доступу | ACCESS_GROUP_ID |
Число (ID групи b_group) |
| Сертифікат | HAS_CERTIFICATE |
Прапор |
Урок — елемент інфоблоку lms_lessons, прив'язаний до курсу через властивість COURSE_ID. Порядок уроків — через SORT. Тип контенту уроку (LESSON_TYPE): Відео / Текст / Тест / Вебінар.
Доступ до курсу
Доступ контролюється через групи користувачів Bitrix. Кожен курс має свою групу (b_group). Після оплати або запису користувач додається до групи:
class EnrollmentService
{
public function enroll(int $userId, int $courseId): void
{
$course = \CIBlockElement::GetByID($courseId)->GetNext();
$groupId = (int)$course['PROPERTY_ACCESS_GROUP_ID_VALUE'];
if ($groupId) {
$currentGroups = \CUser::GetUserGroup($userId);
if (!in_array($groupId, $currentGroups)) {
$currentGroups[] = $groupId;
\CUser::SetUserGroup($userId, $currentGroups);
}
}
CourseEnrollmentTable::add([
'USER_ID' => $userId,
'COURSE_ID' => $courseId,
'STATUS' => 'ACTIVE',
'ENROLLED_AT' => new \Bitrix\Main\Type\DateTime(),
]);
}
}
Доступ до сторінок курсу обмежується на рівні PHP:
// На початку сторінки уроку
$enrollment = CourseEnrollmentTable::getList([
'filter' => [
'USER_ID' => $USER->GetID(),
'COURSE_ID' => $courseId,
'STATUS' => 'ACTIVE',
],
])->fetch();
if (!$enrollment) {
LocalRedirect('/courses/' . $courseSlug . '/buy/');
}
Відстеження прогресу
Прогрес фіксується при кількох умовах залежно від типу уроку:
-
Відео: трекінг через подію
timeupdateплеєра, позначка «переглянуто» при проходженні 80% відео. - Текст: позначка при прокручуванні до кінця сторінки (IntersectionObserver на останній абзац).
- Тест: при успішній здачі (бал ≥ прохідному порогу).
// AJAX-ендпоінт фіксації прогресу
// POST /local/ajax/lms_progress.php
$lessonId = (int)$_POST['lesson_id'];
$courseId = (int)$_POST['course_id'];
$userId = $USER->GetID();
$percent = min(100, (int)$_POST['percent']);
$existing = UserProgressTable::getList([
'filter' => ['USER_ID' => $userId, 'LESSON_ID' => $lessonId],
])->fetch();
if ($existing) {
if ($percent > $existing['PROGRESS_PERCENT']) {
UserProgressTable::update($existing['ID'], [
'PROGRESS_PERCENT' => $percent,
'STATUS' => $percent >= 100 ? 'COMPLETED' : 'IN_PROGRESS',
'COMPLETED_AT' => $percent >= 100 ? new \Bitrix\Main\Type\DateTime() : null,
]);
}
} else {
UserProgressTable::add([
'USER_ID' => $userId,
'COURSE_ID' => $courseId,
'LESSON_ID' => $lessonId,
'STATUS' => $percent >= 100 ? 'COMPLETED' : 'IN_PROGRESS',
'PROGRESS_PERCENT' => $percent,
'STARTED_AT' => new \Bitrix\Main\Type\DateTime(),
'COMPLETED_AT' => $percent >= 100 ? new \Bitrix\Main\Type\DateTime() : null,
]);
}
Тестування та квізи
Питання тесту — елементи інфоблоку lms_quizzes з властивостями: тип питання (одиночний вибір, множинний, текстова відповідь), варіанти відповідей (JSON у властивості-рядку), правильна відповідь, вага питання.
Результати тестування — HL-блок b_hl_lms_quiz_attempt:
CREATE TABLE b_hl_lms_quiz_attempt (
ID SERIAL PRIMARY KEY,
USER_ID INTEGER,
QUIZ_ID INTEGER,
SCORE INTEGER, -- набрані бали
MAX_SCORE INTEGER, -- максимум
PASSED BOOLEAN,
ANSWERS_JSON TEXT, -- JSON з відповідями користувача
CREATED_AT TIMESTAMP
);
Сертифікати
При завершенні курсу (всі уроки COMPLETED) — генерація PDF-сертифіката через бібліотеку FPDF або TCPDF:
class CertificateGenerator
{
public function generate(int $userId, int $courseId): string
{
$user = \CUser::GetByID($userId)->Fetch();
$course = \CIBlockElement::GetByID($courseId)->GetNext();
$pdf = new \TCPDF();
$pdf->AddPage('L'); // Landscape
$pdf->setImageScale(1.25);
// Фонове зображення сертифіката
$pdf->Image('/local/templates/lms/img/certificate_bg.jpg', 0, 0, 297, 210);
// ПІБ
$pdf->SetFont('dejavusans', 'B', 32);
$pdf->SetXY(50, 90);
$pdf->Cell(200, 20, $user['LAST_NAME'] . ' ' . $user['NAME'], 0, 0, 'C');
// Назва курсу
$pdf->SetFont('dejavusans', '', 18);
$pdf->SetXY(50, 120);
$pdf->Cell(200, 10, $course['NAME'], 0, 0, 'C');
$filename = 'certificate_' . $userId . '_' . $courseId . '.pdf';
$path = '/upload/certificates/' . $filename;
$pdf->Output($_SERVER['DOCUMENT_ROOT'] . $path, 'F');
return $path;
}
}
Терміни розробки
| Варіант | Склад | Термін |
|---|---|---|
| Базова LMS | Курси, уроки, прогрес, доступ за групами | 15–20 днів |
| З тестами та сертифікатами | + Квізи, генерація PDF | 20–30 днів |
| Повна платформа | + Оплата, підписки, аналітика, вебінари | 35–50 днів |







