Test Setup Failed
Push — master ( ad3b88...b2f2cc )
by Mohamed
15:01 queued 07:46
created

Import::insertOrUpdateSubjects()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
c 0
b 0
f 0
nc 2
nop 3
dl 0
loc 12
rs 9.9
1
<?php
2
3
namespace App\Imports;
4
5
use Exception;
6
use App\Models\User;
7
use Webpatser\Uuid\Uuid;
8
use App\Models\Nationality;
9
use App\Rules\admissionAge;
10
use App\Models\User_contact;
11
use Lsf\UniqueUid\UniqueUid;
12
use App\Models\Identity_type;
13
use App\Models\Security_user;
14
use App\Models\User_identity;
15
use App\Imports\StudentUpdate;
16
use App\Models\Import_mapping;
17
use App\Models\Security_group;
18
use App\Models\User_body_mass;
19
use App\Models\Academic_period;
20
use App\Models\Student_guardian;
21
use App\Models\User_nationality;
22
use App\Models\Institution_class;
23
use App\Models\User_special_need;
24
use App\Mail\StudentCountExceeded;
25
use App\Mail\StudentImportSuccess;
26
use Illuminate\Support\Facades\DB;
27
use App\Models\Area_administrative;
28
use App\Models\Institution_student;
29
use App\Models\Institution_subject;
30
use App\Models\Workflow_transition;
31
use Illuminate\Support\Facades\Log;
32
use Illuminate\Support\Facades\Mail;
33
use Illuminate\Support\Facades\Config;
34
use App\Models\Institution_class_grade;
35
use App\Models\Special_need_difficulty;
36
use Illuminate\Support\Facades\Request;
37
use Maatwebsite\Excel\Concerns\ToModel;
38
use App\Models\Education_grades_subject;
39
use App\Models\Institution_class_student;
40
use App\Models\Institution_class_subject;
41
use Illuminate\Support\Facades\Validator;
42
use Maatwebsite\Excel\Concerns\WithLimit;
43
use Maatwebsite\Excel\Events\AfterImport;
44
use Maatwebsite\Excel\Events\BeforeSheet;
45
use Maatwebsite\Excel\Validators\Failure;
46
use Maatwebsite\Excel\Concerns\Importable;
47
use Maatwebsite\Excel\Concerns\WithEvents;
48
use Maatwebsite\Excel\Events\BeforeImport;
49
use Maatwebsite\Excel\Jobs\AfterImportJob;
50
use App\Models\Institution_subject_student;
51
use Maatwebsite\Excel\Concerns\SkipsErrors;
52
use Maatwebsite\Excel\Concerns\WithMapping;
53
use Maatwebsite\Excel\Concerns\SkipsOnError;
54
use Maatwebsite\Excel\Concerns\WithStartRow;
55
use App\Models\Institution_student_admission;
56
use Maatwebsite\Excel\Concerns\SkipsFailures;
57
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
58
use Maatwebsite\Excel\Concerns\WithHeadingRow;
59
use Maatwebsite\Excel\Concerns\WithValidation;
60
use Maatwebsite\Excel\Concerns\WithBatchInserts;
61
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
62
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
63
use Maatwebsite\Excel\Exceptions\ConcernConflictException;
64
65
class Import
66
{
67
    //Parent class for import script
68
    use Importable,
0 ignored issues
show
introduced by
The trait Maatwebsite\Excel\Concerns\Importable requires some properties which are not provided by App\Imports\Import: $disk, $readerType, $filePath
Loading history...
69
        RegistersEventListeners;
70
71
    public function __construct($file)
72
    {
73
        $this->sheetNames = [];
0 ignored issues
show
Bug Best Practice introduced by
The property sheetNames does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
74
        $this->file = $file;
0 ignored issues
show
Bug Best Practice introduced by
The property file does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
75
        $this->sheetData = [];
0 ignored issues
show
Bug Best Practice introduced by
The property sheetData does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
76
        $this->template = false;
0 ignored issues
show
Bug Best Practice introduced by
The property template does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
77
        $this->worksheet = '';
0 ignored issues
show
Bug Best Practice introduced by
The property worksheet does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
78
        $this->failures = [];
0 ignored issues
show
Bug Best Practice introduced by
The property failures does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
79
        $this->request = new Request;
0 ignored issues
show
Bug Best Practice introduced by
The property request does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
80
        $this->maleStudentsCount = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property maleStudentsCount does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
81
        $this->femaleStudentsCount = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property femaleStudentsCount does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
82
        $this->highestRow = 0;
0 ignored issues
show
Bug Best Practice introduced by
The property highestRow does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
83
        $this->isValidSheet = true;
0 ignored issues
show
Bug Best Practice introduced by
The property isValidSheet does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
84
        $this->uniqueUid = new UniqueUid();
0 ignored issues
show
Bug Best Practice introduced by
The property uniqueUid does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
85
    }
86
87
    public function limit(): int
88
    {
89
        $highestColumn = $this->worksheet->getHighestDataColumn(3);
90
        $higestRow = 0;
91
        for ($row = $this->startRow(); $row <= $this->highestRow; $row++) {
92
            $rowData = $this->worksheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, FALSE);
93
            if (isEmptyRow(reset($rowData))) {
94
                continue;
95
            } else {
96
                $higestRow += 1;
97
            }
98
        }
99
        return $higestRow;
100
    }
101
102
    public function validateColumns($column, $existingColumns)
0 ignored issues
show
Unused Code introduced by
The parameter $existingColumns is not used and could be removed. ( Ignorable by Annotation )

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

102
    public function validateColumns($column, /** @scrutinizer ignore-unused */ $existingColumns)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
103
    {
104
        $columns = Config::get('excel.columns');
105
        $error = \Illuminate\Validation\ValidationException::withMessages([]);
106
        $this->failures = [];
0 ignored issues
show
Bug Best Practice introduced by
The property failures does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
107
        if (($column !== "") && (!in_array($column, $columns))) {
108
            $this->isValidSheet = false;
0 ignored issues
show
Bug Best Practice introduced by
The property isValidSheet does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
109
            $this->error[] = 'Unsupported column found ,remove:' . $column;
0 ignored issues
show
Bug Best Practice introduced by
The property error does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
110
            $this->failure = new Failure(3, 'remark', $this->error, [null]);
0 ignored issues
show
Bug Best Practice introduced by
The property failure does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
111
            $this->failures = new \Maatwebsite\Excel\Validators\ValidationException($error, [$this->failure]);
112
        }
113
        if (is_object($this->failures)) {
114
            throw $this->failures;
115
        }
116
    }
117
118
    public function validateColumnsToMap($existingColumns)
119
    {
120
        $columns = Config::get('excel.columns');
121
        $optional_columns = Config::get('excel.optional_columns');
122
        $columns = array_diff ($columns,$optional_columns);
123
        $error = \Illuminate\Validation\ValidationException::withMessages([]);
124
        $this->failures = [];
0 ignored issues
show
Bug Best Practice introduced by
The property failures does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
125
        foreach ($columns as  $column) {
126
                if (($column !== "") && (!in_array($column, $existingColumns))) {
127
                    $this->isValidSheet = false;
0 ignored issues
show
Bug Best Practice introduced by
The property isValidSheet does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
128
                    $this->error[] = 'Missing Column :' . $column . ' Not found';
0 ignored issues
show
Bug Best Practice introduced by
The property error does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
129
                    $this->failure = new Failure(3, 'remark', $this->error, [null]);
0 ignored issues
show
Bug Best Practice introduced by
The property failure does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
130
                    $this->failures = new \Maatwebsite\Excel\Validators\ValidationException($error, [$this->failure]);
131
                }
132
        }
133
        if (is_object($this->failures)) {
134
            throw $this->failures;
135
        }
136
    }
137
138
139
140
    public function batchSize(): int
141
    {
142
        $highestColumn = $this->worksheet->getHighestDataColumn(3);
143
        $higestRow = 1;
144
        for ($row = $this->startRow(); $row <= $this->highestRow; $row++) {
145
            $rowData = $this->worksheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, FALSE);
146
            if (isEmptyRow(reset($rowData))) {
147
                continue;
148
            } else {
149
                $higestRow += 1;
150
            }
151
        }
152
        if ($higestRow == 0) {
0 ignored issues
show
introduced by
The condition $higestRow == 0 is always false.
Loading history...
153
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return integer. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
154
        } else {
155
            return $higestRow;
156
        }
157
    }
158
159
160
    public function startRow(): int
161
    {
162
        return 3;
163
    }
164
165
    public function headingRow(): int
166
    {
167
        return 2;
168
    }
169
170
171
    protected function formateDate($row, $column, $format = 'Y-m-d')
172
    {
173
        try {
174
            if (!empty($row[$column]) && ($row[$column] !== null)) {
175
                switch (gettype($row[$column])) {
176
                    case 'string':
177
                        $row[$column] = preg_replace('/[^A-Za-z0-9\-]/', '-', $row[$column]);
178
                        $row[$column] = date($format, strtotime($row[$column])); //date($row[$column]);
179
                        $row[$column] =  \Carbon\Carbon::createFromFormat($format, $row[$column]);
180
                        break;
181
                    case 'double';
182
                        $row[$column] =  \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($row[$column]);
183
                        break;
184
                }
185
            }
186
            return $row;
187
        } catch (Exception $e) {
188
            $error = \Illuminate\Validation\ValidationException::withMessages([]);
189
            $failure = new Failure(3, 'remark', [0 => 'Template is not valid for upload, use the template given in the system ' . $row[$column] . ' Not a valid date formate'], [null]);
190
            $failures = [0 => $failure];
191
            throw new \Maatwebsite\Excel\Validators\ValidationException($error, $failures);
192
        }
193
    }
194
195
196
    protected function mapFields($row)
197
    {
198
199
        $keys = array_keys($row);
200
201
        $this->validateColumnsToMap($keys);
202
        array_walk($keys, array($this, 'validateColumns'));
203
        $row = $this->formateDate($row, 'date_of_birth_yyyy_mm_dd');
204
        $row = $this->formateDate($row, 'bmi_date_yyyy_mm_dd');
205
        $row = $this->formateDate($row, 'start_date_yyyy_mm_dd');
206
        $row = $this->formateDate($row, 'fathers_date_of_birth_yyyy_mm_dd');
207
        $row = $this->formateDate($row, 'mothers_date_of_birth_yyyy_mm_dd');
208
        $row = $this->formateDate($row, 'guardians_date_of_birth_yyyy_mm_dd');
209
210
        $row['admission_no'] =  str_pad($row['admission_no'], 4, '0', STR_PAD_LEFT);
211
      
212
        if (array_key_exists('identity_type', $row)) {
213
        if ($row['identity_type'] == 'BC' && (!empty($row['birth_divisional_secretariat'])) && ($row['identity_number'] !== null) && $row['date_of_birth_yyyy_mm_dd'] !== null) {
214
            $row['identity_number'] =  str_pad($row['identity_number'], 4, '0', STR_PAD_LEFT);
215
            // dd(($row['date_of_birth_yyyy_mm_dd']));
216
            $BirthDivision = Area_administrative::where('name', 'like', '%' . $row['birth_divisional_secretariat'] . '%')->where('area_administrative_level_id', '=', 5)->first();
217
            if ($BirthDivision !== null) {
218
                $BirthArea = Area_administrative::where('name', 'like', '%' . $row['birth_registrar_office_as_in_birth_certificate'] . '%')
219
                    ->where('parent_id', '=', $BirthDivision->id)->first();
220
                if ($BirthArea !== null) {
221
                    $row['identity_number'] = $BirthArea->id . '' . $row['identity_number'] . '' . substr($row['date_of_birth_yyyy_mm_dd']->format("yy"), -2) . '' . $row['date_of_birth_yyyy_mm_dd']->format("m");
222
                }
223
            }
224
225
        }
226
    }
227
        return $row;
228
    }
229
230
    protected function checkKeys($key, $count, $row)
231
    {
232
        if (array_key_exists($key, $row)) {
233
            return true;
234
        } else {
235
            $error = \Illuminate\Validation\ValidationException::withMessages([]);
236
            $failure = new Failure($count, 'remark', [0 => 'Template is not valid for upload, use the template given in the system ' . $key, ' Is missing form the template'], [null]);
237
            $failures = [0 => $failure];
238
            new \Maatwebsite\Excel\Validators\ValidationException($error, $failures);
239
        };
240
    }
241
242
243
    public function array(array $array)
244
    {
245
        $this->sheetData[] = $array;
0 ignored issues
show
Bug Best Practice introduced by
The property sheetData does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
246
    }
247
248
    /**
249
     * @param mixed $row
250
     * @return array
251
     * @throws \Exception
252
     */
253
    public function map($row): array
254
    {
255
        $row = $this->mapFields($row);
256
        return $row;
257
    }
258
259
260
    public function validateClass()
261
    {
262
263
        $institutionClass = Institution_class::find($this->file['institution_class_id']);
264
        $totalMaleStudents = $institutionClass->total_male_students;
0 ignored issues
show
Bug introduced by
The property total_male_students does not seem to exist on App\Models\Institution_class. 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...
265
        $totalFemaleStudents = $institutionClass->total_female_students;
0 ignored issues
show
Bug introduced by
The property total_female_students does not seem to exist on App\Models\Institution_class. 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...
266
        $totalStudents = $totalMaleStudents + $totalFemaleStudents;
267
268
        $exceededStudents = ($totalStudents + $this->limit()) > $institutionClass->no_of_students ? true : false;
0 ignored issues
show
Bug introduced by
The property no_of_students does not seem to exist on App\Models\Institution_class. 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...
269
        if ($exceededStudents == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
270
            $error = \Illuminate\Validation\ValidationException::withMessages([]);
271
            $failure = new Failure(3, 'remark', ['Class student count exceeded! Max number of students is' . $institutionClass->no_of_students], [null]);
272
            $failures = [0 => $failure];
273
            throw new \Maatwebsite\Excel\Validators\ValidationException($error, $failures);
274
            Log::info('email-sent', [$this->file]);
0 ignored issues
show
Unused Code introduced by
Illuminate\Support\Facad...t', array($this->file)) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
275
        } else {
276
            return true;
277
        }
278
    }
279
280
    public function getNode()
281
    {
282
        return $this->file['node'];
283
    }
284
285
    /**
286
     * @param array $options
287
     * @return string
288
     */
289
    public  function getUniqueOpenemisId($options = [])
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

289
    public  function getUniqueOpenemisId(/** @scrutinizer ignore-unused */ $options = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
290
    {
291
        return Uuid::generate(4);
292
    }
293
294
295
    protected function updateSubjectCount($subject)
296
    {
297
        $totalStudents = Institution_subject_student::getStudentsCount($subject['institution_subject_id']);
298
        Institution_subject::where(['id' => $subject['institution_subject_id']])
299
            ->update([
300
                'total_male_students' => $totalStudents['total_male_students'],
301
                'total_female_students' => $totalStudents['total_female_students']
302
            ]);
303
    }
304
305
306
    /**
307
     *
308
     */
309
    protected function setStudentSubjects($subject)
310
    {
311
        return [
312
            'id' => (string) Uuid::generate(4),
313
            'student_id' => $this->student->student_id,
314
            'institution_class_id' => $this->student->institution_class_id,
315
            'institution_subject_id' => $subject['institution_subject_id'],
316
            'institution_id' => $this->student->institution_id,
317
            'academic_period_id' => $this->student->academic_period_id,
318
            'education_subject_id' => $subject['institution_subject']['education_subject_id'],
319
            'education_grade_id' => $this->student->education_grade_id,
320
            'student_status_id' => 1,
321
            'created_user_id' => $this->file['security_user_id'],
322
            'created' => now()
323
        ];
324
    }
325
326
    protected function insertSubject($subject)
327
    {
328
        if (!Institution_subject_student::isDuplicated($subject)) {
329
            Institution_subject_student::updateOrInsert($subject);
330
        }
331
        $this->updateSubjectCount($subject);
332
    }
333
334
    public function createOrUpdateGuardian($row,$student,$param){
335
        if (!empty($row[$param.'s_full_name']) && ($row[$param.'s_date_of_birth_yyyy_mm_dd'] !== null)) {
336
            $guardian = Security_user::createOrUpdateGuardianProfile($row, $param, $this->file);
337
            if (!is_null($guardian)) {
338
                Security_user::where('id', '=', $guardian->id)
339
                    ->update(['is_guardian' => 1]);
340
                $guardian['guardian_relation_id'] = $this->setRelation($param,$guardian);
341
                Student_guardian::createStudentGuardian($student, $guardian, $this->file['security_user_id']);
342
            }      
343
        } 
344
    }
345
346
    protected function setRelation($param,$guardian){
0 ignored issues
show
Unused Code introduced by
The parameter $guardian is not used and could be removed. ( Ignorable by Annotation )

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

346
    protected function setRelation($param,/** @scrutinizer ignore-unused */ $guardian){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
347
        switch($param){
348
            case 'father':
349
                return 1;
350
            case 'mother':  
351
                return 2;  
352
            case 'guardian':
353
                return 3;    
354
        }
355
    }
356
357
    protected function setGender($row){
358
        switch ($row['gender_mf']) {
359
            case 'M':
360
                $row['gender_mf'] = 1;
361
                $this->maleStudentsCount += 1;
362
                break;
363
            case 'F':
364
                $row['gender_mf'] = 2;
365
                $this->femaleStudentsCount += 1;
366
                break;
367
        }
368
        return $row;
369
    }
370
371
    protected function insertOrUpdateSubjects($row,$student,$institution){
372
        $mandatorySubject = Institution_class_subject::getMandatorySubjects($this->file['institution_class_id']);
373
                $subjects = getMatchingKeys($row);
374
                $optionalSubjects =  Institution_class_subject::getStudentOptionalSubject($subjects, $student, $row, $institution);
375
                $allSubjects = array_merge_recursive($optionalSubjects, $mandatorySubject);
376
                if (!empty($allSubjects)) {
377
                    $allSubjects = unique_multidim_array($allSubjects, 'institution_subject_id');
378
                    $this->student = $student;
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...
379
                    $allSubjects = array_map(array($this,'setStudentSubjects'),$allSubjects);
380
                    $allSubjects = unique_multidim_array($allSubjects, 'education_subject_id');
381
                    array_walk($allSubjects,array($this,'insertSubject'));
382
                    array_walk($allSubjects, array($this, 'updateSubjectCount'));
383
                }
384
    }
385
}
386