Test Setup Failed
Pull Request — master (#461)
by Mohamed
06:20
created

ExaminationStudentsController::index()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 2
b 0
f 0
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::select('nsid')
165
                ->whereNotNull('nsid')
166
                ->distinct('nsid')
0 ignored issues
show
Unused Code introduced by
The call to Illuminate\Database\Query\Builder::distinct() has too many arguments starting with 'nsid'. ( Ignorable by Annotation )

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

166
                ->/** @scrutinizer ignore-call */ distinct('nsid')

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

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