PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.0.93
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.0.93
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / Modules / Course / Services / CourseHelper.php

CourseHelper.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 1.0.93, at Modules/Course/Services/CourseHelper.php

409 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\Modules\Course\Services;
4
5 use FluentCommunity\App\Models\Activity;
6 use FluentCommunity\App\Models\Meta;
7 use FluentCommunity\App\Models\Reaction;
8 use FluentCommunity\App\Models\SpaceUserPivot;
9 use FluentCommunity\App\Models\Term;
10 use FluentCommunity\App\Services\CustomSanitizer;
11 use FluentCommunity\App\Services\Helper;
12 use FluentCommunity\Framework\Support\Arr;
13 use FluentCommunity\Modules\Course\Model\Course;
14 use FluentCommunity\Modules\Course\Model\CourseLesson;
15
16 class CourseHelper
17 {
18 public static function getCourseProgressTrack($courseId, $userId = null)
19 {
20 $isEnrolled = self::isEnrolled($courseId, $userId);
21
22 return [
23 'completed_lessons' => $isEnrolled ? self::getCompletedLessonIds($courseId, $userId) : [],
24 'isEnrolled' => $isEnrolled,
25 'progress' => $isEnrolled ? self::getCourseProgress($courseId, $userId) : 0,
26 ];
27 }
28
29 public static function isEnrolled($courseId, $userId = null)
30 {
31 if (!$userId) {
32 $userId = get_current_user_id();
33 }
34
35 if (!$userId) {
36 return false;
37 }
38
39 return SpaceUserPivot::where('space_id', $courseId)
40 ->where('user_id', $userId)
41 ->exists();
42 }
43
44 public static function getCourseEnrollment($courseId, $userId = null)
45 {
46 if (!$userId) {
47 $userId = get_current_user_id();
48 }
49
50 if (!$userId) {
51 return null;
52 }
53
54 return SpaceUserPivot::where('space_id', $courseId)
55 ->where('user_id', $userId)
56 ->first();
57
58 }
59
60 public static function getCoursePublishedLessonIds($courseId)
61 {
62 static $counts = [];
63
64 if (isset($counts[$courseId])) {
65 return $counts[$courseId];
66 }
67
68 $counts[$courseId] = CourseLesson::where('space_id', $courseId)
69 ->where('status', 'published')
70 ->pluck('id')
71 ->toArray();
72
73 return $counts[$courseId];
74 }
75
76 public static function getCourseProgress($courseId, $userId = null)
77 {
78 if (!$userId) {
79 $userId = get_current_user_id();
80 }
81
82 if (!$userId) {
83 return 0;
84 }
85
86 $lessonIds = self::getCoursePublishedLessonIds($courseId);
87
88 if (!$lessonIds) {
89 return 0;
90 }
91
92 $completedLessons = Reaction::where('user_id', $userId)
93 ->whereIn('object_id', $lessonIds)
94 ->where('object_type', 'lesson_completed')
95 ->where('type', 'completed')
96 ->count();
97
98 if (!$completedLessons) {
99 return 0;
100 }
101
102 $result = floor(($completedLessons / count($lessonIds)) * 100);
103
104 if (!$result) {
105 return 0;
106 }
107
108 if ($result > 100) {
109 return 100;
110 }
111
112 return $result;
113
114 }
115
116 public static function getCompletedLessonIds($courseId, $userId = null)
117 {
118 if (!$userId) {
119 $userId = get_current_user_id();
120 }
121
122 if (!$userId) {
123 return [];
124 }
125
126 return Reaction::where('user_id', $userId)
127 ->where('parent_id', $courseId)
128 ->where('object_type', 'lesson_completed')
129 ->where('type', 'completed')
130 ->pluck('object_id')
131 ->toArray();
132 }
133
134 public static function overallCourseProgressAverage($course)
135 {
136 $lessonsCount = CourseLesson::where('space_id', $course->id)
137 ->where('status', 'published')
138 ->count();
139
140 if (!$lessonsCount) {
141 return 0;
142 }
143
144 $allCompletedCount = Reaction::where('object_type', 'lesson_completed')
145 ->where('type', 'completed')
146 ->where('parent_id', $course->id)
147 ->count();
148
149 $studentsCount = $course->students_count ? $course->students_count : $course->students()->count();
150
151 if (!$studentsCount) {
152 return 0;
153 }
154
155 // calculate the average of all students
156 return ceil(($allCompletedCount / ($studentsCount * $lessonsCount)) * 100);
157 }
158
159 public static function updateLessonCompletion($lesson, $userId, $state = 'completed')
160 {
161 $reaction = Reaction::where('user_id', $userId)
162 ->where('object_id', $lesson->id)
163 ->where('object_type', 'lesson_completed')
164 ->first();
165
166 if ($reaction) {
167 if ($state != 'completed') {
168 $reaction->type = 'incomplete';
169 $reaction->save();
170 } else {
171 $reaction->type = 'completed';
172 $reaction->save();
173 }
174 return true;
175 }
176
177 Reaction::create([
178 'user_id' => $userId,
179 'object_id' => $lesson->id,
180 'object_type' => 'lesson_completed',
181 'parent_id' => $lesson->space_id,
182 'type' => 'completed'
183 ]);
184
185 do_action('fluent_community/lesson_completed', $lesson, $userId);
186
187 return true;
188 }
189
190 public static function getCourseMeta($key, $default = false, $withModel = false)
191 {
192 $meta = Meta::where('meta_key', $key)
193 ->where('object_type', 'course')
194 ->first();
195
196 if ($withModel) {
197 return $meta;
198 }
199
200 return $meta ? $meta->value : $default;
201 }
202
203 public static function updateCourseMeta($key, $value)
204 {
205 $meta = Meta::where('meta_key', $key)
206 ->where('object_type', 'course')
207 ->first();
208
209 if ($meta) {
210 $meta->update([
211 'value' => $value
212 ]);
213 return $meta;
214 }
215
216 return Meta::create([
217 'meta_key' => $key,
218 'value' => $value,
219 'object_type' => 'course'
220 ]);
221 }
222
223 public static function completeCourse($course, $userId)
224 {
225 $exists = Activity::where('feed_id', $course->id) // we are using feed_id as it's indexed in the DB
226 ->where('user_id', $userId)
227 ->where('action_name', 'course_completed')
228 ->exists();
229
230 if ($exists) {
231 return false;
232 }
233
234 Activity::create([
235 'feed_id' => $course->id,
236 'user_id' => $userId,
237 'action_name' => 'course_completed'
238 ]);
239
240 do_action('fluent_community/course/completed', $course, $userId);
241
242 return true;
243 }
244
245 public static function enrollCourse($course, $userId = null, $by = 'self')
246 {
247 return Helper::addToSpace($course, $userId, 'student', $by);
248 }
249
250 public static function enrollCourses($courseIds, $userId = null, $by = 'self')
251 {
252 if (!$userId) {
253 $userId = get_current_user_id();
254 }
255
256 $enrolledCourseIds = [];
257
258 foreach ($courseIds as $courseId) {
259 $course = Course::find($courseId);
260 if ($course) {
261 if (self::enrollCourse($course, $userId, $by)) {
262 $enrolledCourseIds[] = $courseId;
263 }
264 }
265 }
266
267 return $enrolledCourseIds;
268 }
269
270 public static function leaveCourse($course, $userId = null, $by = 'self')
271 {
272 if (!$userId) {
273 $userId = get_current_user_id();
274 }
275
276 if (!self::isEnrolled($course->id, $userId)) {
277 return false;
278 }
279
280 SpaceUserPivot::where('user_id', $userId)->where('space_id', $course->id)->delete();
281
282 do_action('fluent_community/course/left', $course, $userId, $by);
283
284 return true;
285 }
286
287 public static function leaveCourses($courseIds, $userId = null, $by = 'self')
288 {
289 if (!$userId) {
290 $userId = get_current_user_id();
291 }
292
293 $processedCourseIds = [];
294
295 foreach ($courseIds as $courseId) {
296 $course = Course::find($courseId);
297 if ($course) {
298 if (self::leaveCourse($course, $userId, $by)) {
299 $processedCourseIds[] = $courseId;
300 }
301 }
302
303 }
304
305 return $processedCourseIds;
306 }
307
308 public static function getEnrolledCourseIds($userId = null)
309 {
310 if (!$userId) {
311 $userId = get_current_user_id();
312 }
313
314 if (!$userId) {
315 return [];
316 }
317
318 return SpaceUserPivot::where('user_id', $userId)
319 ->where('role', 'student')
320 ->pluck('space_id')
321 ->toArray();
322
323 }
324
325 public static function getSectionAccessDate($section, $courseType, $enrollment = null)
326 {
327 if ($courseType == 'slef_paced') {
328 return null;
329 }
330
331 if ($courseType == 'scheduled') {
332 return $section->scheduled_at;
333 }
334
335 // This is for structured course
336 if (!$enrollment) {
337 return null;
338 }
339
340 $accessAfterEnrollment = $section->reactions_count;
341
342 return gmdate('Y-m-d H:i:s', strtotime($enrollment->created_at) + $accessAfterEnrollment * 86400);
343 }
344
345 public static function sanitizeLessonMeta($meta)
346 {
347 $validFields = [
348 'enable_comments',
349 'enable_media',
350 'media',
351 'video_length',
352 ];
353
354 $meta = Arr::only($meta, $validFields);
355
356 $yesNoFields = ['enable_comments', 'enable_media'];
357
358 foreach ($yesNoFields as $field) {
359 $meta[$field] = Arr::get($meta, $field, 'no') == 'yes' ? 'yes' : 'no';
360 }
361
362 if (Arr::get($meta, 'enable_media') == 'yes') {
363 if ($media = Arr::get($meta, 'media', [])) {
364 $media = array_filter([
365 'type' => sanitize_text_field(Arr::get($media, 'type', '')),
366 'url' => sanitize_url(Arr::get($media, 'url', '')),
367 'content_type' => sanitize_text_field(Arr::get($media, 'content_type', '')),
368 'provider' => sanitize_url(Arr::get($media, 'provider', '')),
369 'title' => sanitize_text_field(Arr::get($media, 'title', '')),
370 'author_name' => sanitize_text_field(Arr::get($media, 'author_name', '')),
371 'html' => CustomSanitizer::sanitizeRichText(Arr::get($media, 'html', '')),
372 ]);
373 $meta['media'] = $media;
374 }
375 } else {
376 $meta['media'] = [
377 'provider' => ''
378 ];
379 }
380
381 $numericFields = ['video_length'];
382
383 foreach ($numericFields as $field) {
384 $meta[$field] = absint(Arr::get($meta, $field, 0));
385 }
386
387 return $meta;
388 }
389
390 public static function getCourseCategories()
391 {
392 $terms = Term::whereHas('base_spaces', function ($q) {
393 $q->where('type', 'course');
394 })->get();
395
396 $formattedTerms = [];
397
398 foreach ($terms as $term) {
399 $formattedTerms[] = [
400 'id' => $term->id,
401 'title' => $term->title,
402 'slug' => $term->slug
403 ];
404 }
405
406 return $formattedTerms;
407 }
408 }
409