Test Setup Failed
Pull Request — master (#480)
by Mohamed
06:34
created

ExaminationStudentsController::doMatch()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 54
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 11
Bugs 4 Features 2
Metric Value
cc 5
eloc 52
c 11
b 4
f 2
nc 5
nop 3
dl 0
loc 54
rs 8.7361

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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