File "LessonNotificationService.php"

Full Path: /home/trinadezambia/public_html/admin_panel/app/Services/LessonNotificationService.php
File size: 6.34 KB
MIME-type: text/x-php
Charset: utf-8

<?php

declare(strict_types=1);

namespace App\Services;

use App\Jobs\BulkNotificationsJobv3_0_0;
use App\Models\ClassSubject;
use App\Models\Lesson;
use App\Models\Students;
use App\Models\Subject;
use Illuminate\Support\Facades\Log;

final class LessonNotificationService
{
    public function __construct(
        private readonly CachingService $cache
    ) {}

    /**
     * Send optimized push notifications to relevant students and guardians.
     *
     * @param Lesson $lesson
     * @param array $sectionIds
     * @param int $subjectId
     * @param string $action 'created' or 'updated'
     */
    public function send(Lesson $lesson, array $sectionIds, int $subjectId, string $action = 'created'): void
    {
        try {
            $sessionYear = $this->cache->getSessionYear();
            if (!$sessionYear) {
                return;
            }

            // 1. Resolve ClassSubjects for these sections and subject
            $classSubjects = ClassSubject::whereIn('class_id', function ($query) use ($sectionIds) {
                $query->select('class_id')
                    ->from('class_sections')
                    ->whereIn('id', $sectionIds);
            })
                ->where('subject_id', $subjectId)
                ->where('session_year_id', $sessionYear->id)
                ->get();

            if ($classSubjects->isEmpty()) {
                return;
            }

            // 2. Map sections to their ClassSubject models
            // Note: Different sections might belong to different classes, hence different class_subject records.
            $sectionToClassSubject = [];
            $compulsorySectionIds = [];
            $electivePairs = [];

            // We need to know which class each section belongs to
            $sections = \App\Models\ClassSection::whereIn('id', $sectionIds)->get(['id', 'class_id']);
            $classToSubject = $classSubjects->keyBy('class_id');

            foreach ($sections as $section) {
                $cs = $classToSubject->get($section->class_id);
                if ($cs) {
                    $sectionToClassSubject[$section->id] = $cs;
                    if ($cs->type === 'Compulsory') {
                        $compulsorySectionIds[] = $section->id;
                    } else {
                        $electivePairs[] = [
                            'class_section_id' => $section->id,
                            'class_subject_id' => $cs->id
                        ];
                    }
                }
            }

            // 3. Build optimized student query
            $studentsQuery = Students::query()
                ->whereIn('class_section_id', $sectionIds)
                ->where('session_year_id', $sessionYear->id);

            $studentsQuery->where(function ($q) use ($compulsorySectionIds, $electivePairs) {
                $hasCondition = false;

                if (!empty($compulsorySectionIds)) {
                    $q->whereIn('class_section_id', $compulsorySectionIds);
                    $hasCondition = true;
                }

                if (!empty($electivePairs)) {
                    $method = $hasCondition ? 'orWhereIn' : 'whereIn';
                    $q->$method('user_id', function ($sub) use ($electivePairs) {
                        $sub->select('student_id')
                            ->from('student_subjects')
                            ->where(function ($inner) use ($electivePairs) {
                                foreach ($electivePairs as $pair) {
                                    $inner->orWhere(function ($c) use ($pair) {
                                        $c->where('class_section_id', $pair['class_section_id'])
                                            ->where('class_subject_id', $pair['class_subject_id']);
                                    });
                                }
                            });
                    });
                }
            });

            $students = $studentsQuery->get(['id', 'user_id', 'guardian_id', 'class_section_id']);

            if ($students->isEmpty()) {
                return;
            }

            // 4. Prepare data for BulkNotificationsJob
            $subject = Subject::find($subjectId);
            $subjectName = $subject->name ?? 'Subject';
            $subjectType = $subject->type ?? '';

            $title = 'Lesson Alert !!!';
            $body = "New study material $action for lesson " . $lesson->name . " in subject " . $subjectName . ($subjectType ? " - $subjectType" : "");

            $userIds = [];
            $studentMap = []; // user_id => student_id
            $guardianMap = []; // user_id => [student_ids]
            $sectionMap = []; // section_id => class_subject_id

            foreach ($sectionToClassSubject as $sectionId => $cs) {
                $sectionMap[$sectionId] = $cs->id;
            }

            foreach ($students as $student) {
                if ($student->user_id) {
                    $userIds[] = $student->user_id;
                    $studentMap[$student->user_id] = $student->id;
                }

                if ($student->guardian_id) {
                    $userIds[] = $student->guardian_id;
                    if (!isset($guardianMap[$student->guardian_id])) {
                        $guardianMap[$student->guardian_id] = [];
                    }
                    $guardianMap[$student->guardian_id][] = $student->id;
                }
            }

            $userIds = array_unique($userIds);

            $customData = [
                'internal' => [
                    'student_map' => $studentMap,
                    'guardian_map' => $guardianMap,
                    'section_map' => $sectionMap,
                ],
                'payload' => [
                    'lesson_id' => $lesson->id,
                    'subject_id' => $subjectId,
                ]
            ];

            // 5. Dispatch Job
            BulkNotificationsJobv3_0_0::dispatch(
                (int) $lesson->school_id, // Lesson should have school_id or we get it from Auth
                $userIds,
                $title,
                $body,
                'lesson',
                $customData
            );
        } catch (\Throwable $e) {
            Log::error('LessonNotificationService Error: ' . $e->getMessage(), [
                'lesson_id' => $lesson->id,
                'stack' => $e->getTraceAsString()
            ]);
        }
    }
}