Test Setup Failed
Pull Request — master (#461)
by Mohamed
07:12 queued 46s
created

ExaminationStudentsController::setIsTakingExam()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 17
c 2
b 0
f 0
nc 5
nop 1
dl 0
loc 23
rs 9.3888
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use Session;
6
use App\Models\Institution;
7
use Illuminate\Http\Request;
8
use App\Models\Security_user;
9
use App\Models\Academic_period;
10
use App\Models\Education_grade;
11
use App\Models\Institution_class;
12
use App\Models\Institution_shift;
13
use App\Notifications\ExportReady;
14
use Illuminate\Support\Facades\DB;
15
use App\Models\Examination_student;
16
use App\Models\Institution_student;
17
use Illuminate\Support\Facades\Log;
18
use Illuminate\Support\Facades\Storage;
19
use Illuminate\Support\Facades\Response;
20
use App\Models\Institution_class_student;
21
use App\Exports\ExaminationStudentsExport;
22
use App\Imports\ExaminationStudentsImport;
23
use App\Models\Institution_student_admission;
24
25
class ExaminationStudentsController extends Controller
26
{
27
    public function __construct($year = 2019, $grade = 'G5')
28
    {
29
        $this->year = $year;
0 ignored issues
show
Bug Best Practice introduced by
The property year does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
30
        $this->grade = $grade;
0 ignored issues
show
Bug Best Practice introduced by
The property grade does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
31
        $this->student = new Security_user();
0 ignored issues
show
Bug Best Practice introduced by
The property student does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
32
        $this->examination_student = new Examination_student();
0 ignored issues
show
Bug Best Practice introduced by
The property examination_student does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
33
        $this->academic_period =  Academic_period::where('code', '=', $this->year)->first();
0 ignored issues
show
Bug Best Practice introduced by
The property academic_period does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
34
        $this->education_grade = Education_grade::where('code', '=', $this->grade)->first();
0 ignored issues
show
Bug Best Practice introduced by
The property education_grade does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
35
        $this->output = new \Symfony\Component\Console\Output\ConsoleOutput();
0 ignored issues
show
Bug Best Practice introduced by
The property output does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
36
    }
37
38
    public function index()
39
    {
40
        return view('uploadcsv');
41
    }
42
43
    public function uploadFile(Request $request)
44
    {
45
46
        if ($request->input('submit') != null) {
47
48
            $file = $request->file('file');
49
50
            // File Details
51
            $filename = 'exams_students.csv';
52
            $extension = $file->getClientOriginalExtension();
53
            $fileSize = $file->getSize();
54
55
            // Valid File Extensions
56
            $valid_extension = array("csv");
57
58
            // 20MB in Bytes
59
            $maxFileSize = 30971520;
60
61
            // Check file extension
62
            if (in_array(strtolower($extension), $valid_extension)) {
63
64
                // Check file size
65
                if ($fileSize <= $maxFileSize) {
66
67
                    // File upload location
68
                    Storage::disk('local')->putFileAs(
69
                        'examination/',
70
                        $file,
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type Illuminate\Http\UploadedFile[] and array; however, parameter $file of Illuminate\Filesystem\Fi...temAdapter::putFileAs() does only seem to accept Illuminate\Http\File|Illuminate\Http\UploadedFile, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
                        /** @scrutinizer ignore-type */ $file,
Loading history...
71
                        $filename
72
                    );
73
                    Session::flash('message', 'File upload successfully!');
74
                    // Redirect to index
75
                } else {
76
                    Session::flash('message', 'File too large. File must be less than 20MB.');
77
                }
78
            } else {
79
                Session::flash('message', 'Invalid File Extension.');
80
            }
81
        }
82
        return redirect()->action('ExaminationStudentsController@index');
83
    }
84
85
    /**
86
     * Import students data to the Examinations table 
87
     *
88
     * @return void
89
     */
90
    public static function callOnClick()
91
    {
92
        // Import CSV to Database
93
        $excelFile = "/examination/exams_students.csv";
94
95
        $import = new ExaminationStudentsImport();
96
        try {
97
            $import->import($excelFile, 'local', \Maatwebsite\Excel\Excel::CSV);
98
            if ($import->failures()->count() > 0) {
99
                $errors = $import->failures();
100
                $columns =  [
101
                    'remarks',
102
                    'st_no',
103
                    'stu_no',
104
                    "f_name",
105
                    "medium",
106
                    "gender",
107
                    "b_date",
108
                    "a_income",
109
                    "schoolid",
110
                    "spl_need",
111
                    "pvt_address",
112
                    "disability_type",
113
                    "disability",
114
                    "sp_center"
115
                ];
116
117
                $file = 'examination/errors.csv';
118
                Storage::put($file, implode(',', $columns));
119
120
                foreach ($errors as $error) {
121
                    Storage::append($file, implode(':', $error->errors()) . ',' . implode(',', $error->values()));
122
                }
123
            }
124
        } catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
125
        }
126
    }
127
128
    /**
129
     * Iterate over existing student's data
130
     *
131
     * @return void
132
     */
133
    public  function doMatch($offset, $limit, $mode)
134
    {
135
        $students = [];
136
        switch ($mode) {
137
            case 'duplicate':
138
                $students =  DB::table('examination_students as es')
139
                    ->select(DB::raw('count(*) as total'), 'e2.*')
140
                    ->join('examination_students as e2', 'es.nsid','e2.nsid')
141
                    ->having('total', '>', 1)
142
                    ->groupBy('e2.st_no')
143
                    ->orderBy('e2.st_no')
144
                    ->offset($offset)
145
                    ->limit($limit)
146
                    ->get()->toArray();
147
                $students = (array) json_decode(json_encode($students));
148
                $this->output->writeln(count($students) . 'students remaining duplicate');
149
                array_walk($students, array($this, 'clone'));
150
                $this->output->writeln('All are generated');
151
                break;
152
            case 'empty';
153
                $students = Examination_student::whereNull('nsid')
154
                    ->orWhere('nsid','<>','')
155
                    ->offset($offset)
156
                    ->limit($limit)
157
                    ->get()->toArray();
158
                $students = (array) json_decode(json_encode($students));
159
                $this->output->writeln(count($students) . 'students remaining empty');
160
                array_walk($students, array($this, 'clone'));
161
                $this->output->writeln('All are generated');
162
                break;
163
            case 'count':
164
                $count = Examination_student::distinct('nsid')
165
                ->count();
166
                $all = Examination_student::select('nsid')
167
                    ->count();
168
                $this->output->writeln( $all. 'Total Unique nsid are: ' .$count);
169
                break;
170
            default:
171
                $students = Examination_student::offset($offset)
172
                    ->limit($limit)
173
                    ->get()->toArray();
174
                $students = (array) json_decode(json_encode($students));
175
                $this->output->writeln(count($students) . 'students remaining empty');
176
                array_walk($students, array($this, 'clone'));
177
                $this->output->writeln('All are generated');
178
        }
179
    }
180
181
    /**
182
     * Set Examination values
183
     *
184
     * @param array $students
185
     * @return array
186
     */
187
    public function setIsTakingExam($students)
188
    {
189
        $students['taking_g5_exam'] = false;
190
        $students['taking_ol_exam'] = false;
191
        $students['taking_al_exam'] = false;
192
        switch ($this->education_grade->code) {
0 ignored issues
show
Bug introduced by
The property code does not seem to exist on App\Models\Education_grade. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
193
            case 'G5':
194
                $students['taking_g5_exam'] = true;
195
                break;
196
            case 'G4':
197
                $students['taking_g5_exam'] = true;
198
                break;
199
            case 'G10':
200
                $students['taking_ol_exam'] = true;
201
                break;
202
            case 'G11':
203
                $students['taking_ol_exam'] = true;
204
                break;
205
            // case preg_match('13', $this->education_grade->code):
206
            //     $students['taking_al_exam'] = true;
207
            //     break;
208
        }
209
        return $students;
210
    }
211
212
213
    /**
214
     * Main function to merge the student's to SIS
215
     *
216
     * @param array $student
217
     * @return void
218
     */
219
    public function clone($student)
220
    {
221
        $student = (array)json_decode(json_encode($student));
222
        //get student matching with same dob and gender
223
224
        $matchedStudent = $this->getMatchingStudents($student);
225
226
        // if the first match missing do complete insertion
227
        $institution = Institution::where('code', '=', $student['schoolid'])->first();
228
229
        if (!is_null($institution)) {
230
231
            // ge the class lists to belong the school
232
            $institutionClass = Institution_class::where(
233
                [
234
                    'institution_id' => $institution->id,
235
                    'academic_period_id' => $this->academic_period->id,
236
                    'education_grade_id' => $this->education_grade->id
237
                ]
238
            )->join('institution_class_grades', 'institution_classes.id', 'institution_class_grades.institution_class_id')->get()->toArray();
239
240
            // set search variables 
241
            $admissionInfo = [
242
                'instituion_class' => $institutionClass,
243
                'instituion' => $institution,
244
                'education_grade' =>  $this->education_grade,
245
                'academic_period' => $this->academic_period
246
            ];
247
248
            // if no matching found
249
            if (empty($matchedStudent)) {
250
                $sis_student = $this->student->insertExaminationStudent($student);
251
252
                //TODO implement insert student to admission table
253
                $student['id'] = $sis_student['id'];
254
                $sis_student['student_id'] =  $student['id'];
255
256
                $student = $this->setIsTakingExam($student);
257
                if (count($institutionClass) == 1) {
258
                    $admissionInfo['instituion_class'] = $institutionClass[0];
259
                    Institution_student::createExaminationData($student, $admissionInfo);
260
                    Institution_student_admission::createExaminationData($student, $admissionInfo);
261
                    Institution_class_student::createExaminationData($student, $admissionInfo);
262
                } else {
263
                    Institution_student_admission::createExaminationData($student, $admissionInfo);
264
                    Institution_student::createExaminationData($student, $admissionInfo);
265
                }
266
                $this->updateStudentId($student, $sis_student);
267
                // update the matched student's data    
268
            } else {
269
                $student = $this->setIsTakingExam($student);
270
                $studentData = $this->student->updateExaminationStudent($student, $matchedStudent);
271
                $matchedStudent = array_merge((array) $student, $matchedStudent);
272
                $studentData = array_merge((array) $matchedStudent, $studentData);
273
                Institution_student::updateExaminationData($studentData, $admissionInfo);
274
                $this->updateStudentId($student, $studentData);
275
            }
276
        } else {
277
278
            $this->output->writeln('Student ' . $student['st_no'] . ' not imorted' . $student['f_name']);
279
        }
280
    }
281
282
    /**
283
     * This function is implemented similar_text search algorithm 
284
     * to get the most matching name with the existing students
285
     * data set
286
     *
287
     * @param array $student
288
     * @return array
289
     */
290
    public function getMatchingStudents($student)
291
    {
292
        /**
293
         */
294
        $sis_student = $this->student->getMatches($student);
295
        $doe_students =  Examination_student::where('gender',$student['gender'])
296
            ->where('b_date',$student['b_date'])
297
            ->where('schoolid',$student['schoolid'])
298
            ->count();
299
        $count = $this->student->getStudentCount($student);
300
301
        $studentData = [];
302
        $sis_users  = (array) json_decode(json_encode($sis_student), true);
303
        // if the same gender same DOE has more than one 
304
        if(($doe_students > 1) || ($count > 1)){
305
            $studentData = $this->searchSimilarName($student, $sis_users,false);
306
        }else{
307
            $studentData = $this->searchSimilarName($student, $sis_users);
308
        }   
309
        return $studentData;
310
    }
311
312
    /**
313
     * Search most matching name
314
     *
315
     * @param array $student
316
     * @param array $sis_students
317
     * @return array
318
     */
319
    public function searchSimilarName($student, $sis_students,$surname_search = true)
320
    {
321
        $highest = [];
322
        $minDistance = 0;
323
        $matches = [];
324
        $data = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
325
        foreach ($sis_students as $key => $value) {
326
            similar_text(strtoupper($value['first_name']), (strtoupper($student['f_name'])), $percentage);
327
            $distance = levenshtein(strtoupper($student['f_name']), strtoupper($value['first_name']));
328
            $value['rate'] = $percentage;
329
            switch (true) {
330
                case $value['rate'] == 100;
331
                    $highest = $value;
332
                    break;
333
                case (($distance <= 2) && ($distance < $minDistance));
334
                    $highest = $value;
335
                    $minDistance = $distance;
336
            }
337
        }
338
339
        if($surname_search){
340
            if (empty($highest)) {
341
                foreach ($sis_students as $key => $value) {
342
                    //search name with last name
343
                    similar_text(strtoupper(get_l_name($student['f_name'])), strtoupper(get_l_name($value['first_name'])), $percentage);
344
                    $value['rate'] = $percentage;
345
                    switch (true) {
346
                        case ($value['rate'] == 100);
347
                            $highest = $value;
348
                            $matches[] = $value;
349
                            break;
350
                    }
351
                }
352
            }
353
        }
354
355
        if(count($matches)>1){
356
            $highest =  $this->searchSimilarName($student, $sis_students,false);
357
        }
358
359
        return $highest;
360
    }
361
362
    /**
363
     * Generate new NSID for students
364
     *
365
     * @param array $student
366
     * @param array $sis_student
367
     * @return void
368
     */
369
    public function updateStudentId($student, $sis_student)
370
    {
371
        try {
372
            $student['nsid'] =  $sis_student['openemis_no'];
373
            // add new NSID to the examinations data set
374
            unset($student['id']);
375
            unset($student['taking_g5_exam']);
376
            unset($student['taking_al_exam']);
377
            unset($student['taking_ol_exam']);
378
            unset($student['total']);
379
            $this->examination_student->where('st_no', $student['st_no'])->update($student);
380
            unset($student['st_no']);
381
            $this->output->writeln('Updated  to NSID' . $sis_student['openemis_no']);
382
        } catch (\Exception $th) {
383
            dd($th);
384
            $this->output->writeln('error');
385
            Log::error($th);
386
        }
387
    }
388
389
    /**
390
     * export the all data with NSID
391
     *
392
     * @return void
393
     */
394
    public function export()
395
    {
396
        $adminUser = Security_user::where('username', 'admin')->first();
397
        try {
398
            (new ExaminationStudentsExport)->store('examination/student_data_with_nsid.'.time().'.csv');
399
            (new ExportReady($adminUser));
400
        } catch (\Throwable $th) {
401
            //throw $th;
402
            dd($th);
403
        }
404
        return back()->withSuccess('Export started!');
0 ignored issues
show
Bug Best Practice introduced by
The expression return back()->withSuccess('Export started!') also could return the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type void.
Loading history...
405
    }
406
407
    public function downloadErrors()
408
    {
409
410
        $file_path = storage_path() . '/app/examination/errors.csv';
411
        return Response::download($file_path);
412
    }
413
414
    public function downloadProcessedFile()
415
    {
416
        $file_path = storage_path() . '/app/examination/student_data_with_nsid.csv';
417
        return Response::download($file_path);
418
    }
419
}
420