EscolaLMS/Courses

View on GitHub
src/Jobs/CheckFinishedLessons.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php

namespace EscolaLms\Courses\Jobs;

use EscolaLms\Auth\Repositories\Contracts\UserRepositoryContract;
use EscolaLms\Courses\Enum\ProgressStatus;
use EscolaLms\Courses\Events\LessonFinished;
use EscolaLms\Courses\Models\CourseProgress;
use EscolaLms\Courses\Models\Lesson;
use EscolaLms\Courses\Models\Topic;
use EscolaLms\Courses\Models\User;
use EscolaLms\Courses\Repositories\Contracts\TopicRepositoryContract;
use EscolaLms\Courses\ValueObjects\CourseProgressCollection;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;

class CheckFinishedLessons implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $topicId;
    public int $userId;

    public function __construct(int $topicId, int $userId)
    {
        $this->topicId = $topicId;
        $this->userId = $userId;
    }

    public function handle(TopicRepositoryContract $topicRepository, UserRepositoryContract $userRepository): void
    {
        /** @var Topic $topic */
        $topic = $topicRepository->find($this->topicId);
        /** @var User $user */
        $user = $userRepository->find($this->userId);

        if (!$user || !$topic || !$topic->course) {
            return;
        }

        $courseProgressCollection = CourseProgressCollection::make($user, $topic->course);
        $finishedTopicIds = $courseProgressCollection
            ->getProgress()
            ->filter(fn(CourseProgress $courseProgress) => $courseProgress->finished_at && $courseProgress->status === ProgressStatus::COMPLETE)
            ->pluck('topic_id');

        $this->checkLesson($topic->lesson, $finishedTopicIds, $user);
    }

    private function checkLesson(Lesson $lesson, Collection $finishedTopicIds, $user): void
    {
        $topicIds = $this->getAllNestedTopicIds($lesson);

        if ($topicIds->diff($finishedTopicIds)->isEmpty()) {
            event(new LessonFinished($user, $lesson));

            if ($lesson->parentLesson && $lesson->parentLesson->active) {
                $this->checkLesson($lesson->parentLesson, $finishedTopicIds, $user);
            }
        }
    }

    private function getAllNestedTopicIds(Lesson $lesson): Collection
    {
        $topicIds = $lesson->topics->where('active', true)->pluck('id');

        foreach ($lesson->lessons as $childLesson) {
            $topicIds->merge($this->getAllNestedTopicIds($childLesson));
        }

        return $topicIds;
    }
}