1<?php
2
3/* Copyright (c) 2015 Richard Klees <richard.klees@concepts-and-training.de> Extended GPL, see docs/LICENSE */
4/* Copyright (c) 2019 Stefan Hecken <stefan.hecken@concepts-and-training.de> Extended GPL, see docs/LICENSE */
5
6declare(strict_types = 1);
7
8class ilStudyProgrammeSettingsDBRepository implements ilStudyProgrammeSettingsRepository
9{
10    /**
11     * @var array
12     */
13    protected static $cache = [];
14
15    /**
16     * @var ilDBInterface
17     */
18    protected $db;
19
20    const TABLE = 'prg_settings';
21
22    const FIELD_OBJ_ID = 'obj_id';
23    const FIELD_SUBTYPE_ID = 'subtype_id';
24    const FIELD_STATUS = 'status';
25    const FIELD_LP_MODE = 'lp_mode';
26    const FIELD_POINTS = 'points';
27    const FIELD_LAST_CHANGED = 'last_change';
28    const FIELD_DEADLINE_PERIOD = 'deadline_period';
29    const FIELD_DEADLINE_DATE = 'deadline_date';
30    const FIELD_VALIDITY_QUALIFICATION_DATE = 'vq_date';
31    const FIELD_VALIDITY_QUALIFICATION_PERIOD = 'vq_period';
32    const FIELD_VQ_RESTART_PERIOD = 'vq_restart_period';
33    const FIELD_RM_NOT_RESTARTED_BY_USER_DAY = 'rm_nr_by_usr_days';
34    const FIELD_PROC_ENDS_NOT_SUCCESSFUL = 'proc_end_no_success';
35    const FIELD_SEND_RE_ASSIGNED_MAIL = "send_re_assigned_mail";
36    const FIELD_SEND_INFO_TO_RE_ASSIGN_MAIL = "send_info_to_re_assign_mail";
37    const FIELD_SEND_RISKY_TO_FAIL_MAIL = "send_risky_to_fail_mail";
38
39    public function __construct(ilDBInterface $db)
40    {
41        $this->db = $db;
42    }
43
44    /**
45     * @inheritdoc
46     * @throws ilException
47     */
48    public function createFor(int $obj_id) : ilStudyProgrammeSettings
49    {
50        $type_settings = new \ilStudyProgrammeTypeSettings(
51            ilStudyProgrammeSettings::DEFAULT_SUBTYPE
52        );
53        $assessment_settings = new \ilStudyProgrammeAssessmentSettings(
54            ilStudyProgrammeSettings::DEFAULT_POINTS,
55            ilStudyProgrammeSettings::STATUS_DRAFT
56        );
57        $deadline_settings = new \ilStudyProgrammeDeadlineSettings(null, null);
58        $validity_of_achieved_qualification_settings =
59            new \ilStudyProgrammeValidityOfAchievedQualificationSettings(null, null, null)
60        ;
61        $automail = new \ilStudyProgrammeAutoMailSettings(false, null, null);
62
63        $prg = new ilStudyProgrammeSettings(
64            $obj_id,
65            $type_settings,
66            $assessment_settings,
67            $deadline_settings,
68            $validity_of_achieved_qualification_settings,
69            $automail
70        );
71
72        $this->insertDB(
73            $obj_id,
74            ilStudyProgrammeSettings::DEFAULT_SUBTYPE,
75            ilStudyProgrammeSettings::STATUS_DRAFT,
76            ilStudyProgrammeSettings::MODE_UNDEFINED,
77            ilStudyProgrammeSettings::DEFAULT_POINTS,
78            (new DateTime())->format(ilStudyProgrammeSettings::DATE_TIME_FORMAT),
79            0,
80            ilStudyProgrammeSettings::NO_VALIDITY_OF_QUALIFICATION_PERIOD,
81            ilStudyProgrammeSettings::NO_RESTART,
82            null,
83            null,
84            null,
85            null
86        );
87
88        $prg = $prg->setLPMode(ilStudyProgrammeSettings::MODE_UNDEFINED);
89        self::$cache[$obj_id] = $prg;
90        return $prg;
91    }
92
93    /**
94     * @inheritdoc
95     * @throws ilException
96     */
97    public function read(int $obj_id) : ilStudyProgrammeSettings
98    {
99        if (!array_key_exists($obj_id, self::$cache)) {
100            self::$cache[$obj_id] = $this->loadDB($obj_id);
101        }
102        return self::$cache[$obj_id];
103    }
104
105    /**
106     * @inheritdoc
107     */
108    public function update(ilStudyProgrammeSettings $settings) : void
109    {
110        $deadline_period = $settings->getDeadlineSettings()->getDeadlinePeriod();
111        if (is_null($deadline_period)) {
112            $deadline_period = 0;
113        }
114
115        $deadline_date = $settings->getDeadlineSettings()->getDeadlineDate();
116        if (!is_null($deadline_date)) {
117            $deadline_date = $deadline_date->format(ilStudyProgrammeSettings::DATE_TIME_FORMAT);
118        }
119
120        $vq_date = $settings->getValidityOfQualificationSettings()->getQualificationDate();
121        if (!is_null($vq_date)) {
122            $vq_date = $vq_date->format(ilStudyProgrammeSettings::DATE_TIME_FORMAT);
123        }
124
125        $qp = $settings->getValidityOfQualificationSettings()->getQualificationPeriod();
126        if (is_null($qp)) {
127            $qp = 0;
128        }
129
130        $rp = $settings->getValidityOfQualificationSettings()->getRestartPeriod();
131        if (is_null($rp)) {
132            $rp = 0;
133        }
134
135        $this->updateDB(
136            $settings->getObjId(),
137            $settings->getTypeSettings()->getTypeId(),
138            $settings->getAssessmentSettings()->getStatus(),
139            $settings->getLPMode(),
140            $settings->getAssessmentSettings()->getPoints(),
141            $settings->getLastChange()->format(ilStudyProgrammeSettings::DATE_TIME_FORMAT),
142            $deadline_period,
143            $qp,
144            $rp,
145            $deadline_date,
146            $vq_date,
147            $settings->getAutoMailSettings()->getReminderNotRestartedByUserDays(),
148            $settings->getAutoMailSettings()->getProcessingEndsNotSuccessfulDays(),
149            $settings->getAutoMailSettings()->getSendReAssignedMail(),
150            false,
151            false
152        );
153        self::$cache[$settings->getObjId()] = $settings;
154    }
155
156    /**
157     * @inheritdoc
158     */
159    public function delete(ilStudyProgrammeSettings $settings) : void
160    {
161        unset(self::$cache[$settings->getObjId()]);
162        $this->deleteDB($settings->getObjId());
163    }
164
165    /**
166     * @inheritdoc
167     * @throws ilException
168     */
169    public function loadByType(int $type_id) : array
170    {
171        $q = 'SELECT ' . self::FIELD_SUBTYPE_ID
172            . '	,' . self::FIELD_STATUS
173            . '	,' . self::FIELD_POINTS
174            . '	,' . self::FIELD_LP_MODE
175            . '	,' . self::FIELD_LAST_CHANGED
176            . '	,' . self::FIELD_OBJ_ID
177            . '	,' . self::FIELD_DEADLINE_PERIOD
178            . '	,' . self::FIELD_DEADLINE_DATE
179            . '	,' . self::FIELD_VALIDITY_QUALIFICATION_PERIOD
180            . '	,' . self::FIELD_VALIDITY_QUALIFICATION_DATE
181            . '	,' . self::FIELD_VQ_RESTART_PERIOD
182            . ', ' . self::FIELD_SEND_RE_ASSIGNED_MAIL
183            . ', ' . self::FIELD_SEND_INFO_TO_RE_ASSIGN_MAIL
184            . ', ' . self::FIELD_SEND_RISKY_TO_FAIL_MAIL
185            . '	FROM ' . self::TABLE
186            . '	WHERE ' . self::FIELD_SUBTYPE_ID . ' = ' . $this->db->quote($type_id, 'integer');
187        $res = $this->db->query($q);
188        $return = [];
189        while ($rec = $this->db->fetchAssoc($res)) {
190            $return[] = $this->createByRow($rec);
191        }
192        return $return;
193    }
194
195
196    public function loadIdsByType(int $type_id) : array
197    {
198        return [];
199    }
200
201    protected function insertDB(
202        int $obj_id,
203        int $subtype_id,
204        int $status,
205        int $lp_mode,
206        int $points,
207        string $last_change,
208        int $deadline_period,
209        int $vq_period,
210        int $vq_restart_period,
211        string $deadline_date = null,
212        string $vq_date = null,
213        int $rm_nr_by_usr_days = null,
214        int $proc_end_no_success = null,
215        bool $send_re_assigned_mail = false,
216        bool $send_info_to_re_assign_mail = false,
217        bool $send_risky_to_fail_mail = false
218    ) {
219        $this->db->insert(
220            self::TABLE,
221            [
222                self::FIELD_OBJ_ID => ['integer', $obj_id],
223                self::FIELD_SUBTYPE_ID => ['integer', $subtype_id],
224                self::FIELD_STATUS => ['integer', $status],
225                self::FIELD_POINTS => ['integer', $points],
226                self::FIELD_LP_MODE => ['integer', $lp_mode],
227                self::FIELD_LAST_CHANGED => ['timestamp', $last_change],
228                self::FIELD_DEADLINE_PERIOD => ['integer', $deadline_period],
229                self::FIELD_DEADLINE_DATE => ['timestamp', $deadline_date],
230                self::FIELD_VALIDITY_QUALIFICATION_DATE => ['timestamp', $vq_date],
231                self::FIELD_VALIDITY_QUALIFICATION_PERIOD => ['integer', $vq_period],
232                self::FIELD_VQ_RESTART_PERIOD => ['integer', $vq_restart_period],
233                self::FIELD_RM_NOT_RESTARTED_BY_USER_DAY => ['integer', $rm_nr_by_usr_days],
234                self::FIELD_PROC_ENDS_NOT_SUCCESSFUL => ['integer', $proc_end_no_success],
235                self::FIELD_SEND_RE_ASSIGNED_MAIL => ['integer', $send_re_assigned_mail],
236                self::FIELD_SEND_INFO_TO_RE_ASSIGN_MAIL => ['integer', $send_info_to_re_assign_mail],
237                self::FIELD_SEND_RISKY_TO_FAIL_MAIL => ['integer', $send_risky_to_fail_mail]
238            ]
239        );
240    }
241
242    /**
243     * @throws ilException
244     * @thorws LogicException
245     */
246    protected function loadDB(int $obj_id) : ilStudyProgrammeSettings
247    {
248        $rec = $this->db->fetchAssoc(
249            $this->db->query(
250                'SELECT ' . self::FIELD_SUBTYPE_ID
251                . ', ' . self::FIELD_STATUS
252                . ', ' . self::FIELD_POINTS
253                . ', ' . self::FIELD_LP_MODE
254                . ', ' . self::FIELD_LAST_CHANGED
255                . ', ' . self::FIELD_OBJ_ID
256                . ', ' . self::FIELD_DEADLINE_PERIOD
257                . ', ' . self::FIELD_DEADLINE_DATE
258                . ', ' . self::FIELD_VALIDITY_QUALIFICATION_PERIOD
259                . ', ' . self::FIELD_VALIDITY_QUALIFICATION_DATE
260                . ', ' . self::FIELD_VQ_RESTART_PERIOD
261                . ', ' . self::FIELD_RM_NOT_RESTARTED_BY_USER_DAY
262                . ', ' . self::FIELD_PROC_ENDS_NOT_SUCCESSFUL
263                . ', ' . self::FIELD_SEND_RE_ASSIGNED_MAIL
264                . ', ' . self::FIELD_SEND_INFO_TO_RE_ASSIGN_MAIL
265                . ', ' . self::FIELD_SEND_RISKY_TO_FAIL_MAIL
266                . '	FROM ' . self::TABLE
267                . '	WHERE ' . self::FIELD_OBJ_ID . ' = ' . $this->db->quote($obj_id, 'integer')
268            )
269        );
270        if (!$rec) {
271            throw new LogicException('invaid obj_id to load: ' . $obj_id);
272        }
273        return $this->createByRow($rec);
274    }
275
276    /**
277     * @throws ilException
278     */
279    protected function createByRow(array $row) : ilStudyProgrammeSettings
280    {
281        $type_settings = new \ilStudyProgrammeTypeSettings(
282            ilStudyProgrammeSettings::DEFAULT_SUBTYPE
283        );
284        $assessment_settings = new \ilStudyProgrammeAssessmentSettings(
285            ilStudyProgrammeSettings::DEFAULT_POINTS,
286            ilStudyProgrammeSettings::STATUS_DRAFT
287        );
288        $deadline_settings = new \ilStudyProgrammeDeadlineSettings(null, null);
289        $validity_of_achieved_qualification_settings =
290            new \ilStudyProgrammeValidityOfAchievedQualificationSettings(null, null, null)
291        ;
292        $automail = new \ilStudyProgrammeAutoMailSettings(false, null, null);
293
294        $prg = new ilStudyProgrammeSettings(
295            (int) $row[self::FIELD_OBJ_ID],
296            $type_settings,
297            $assessment_settings,
298            $deadline_settings,
299            $validity_of_achieved_qualification_settings,
300            $automail
301        );
302
303        $return = $prg
304            ->setLPMode((int) $row[self::FIELD_LP_MODE])
305            ->setLastChange(DateTime::createFromFormat(
306                ilStudyProgrammeSettings::DATE_TIME_FORMAT,
307                $row[self::FIELD_LAST_CHANGED]
308            ))
309        ;
310
311        $type = $return->getTypeSettings();
312        $type = $type->withTypeId((int) $row['subtype_id']);
313        $return = $return->withTypeSettings($type);
314
315        $points = $return->getAssessmentSettings();
316        $points = $points->withPoints((int) $row['points'])->withStatus((int) $row['status']);
317        $return = $return->withAssessmentSettings($points);
318
319        $deadline = $return->getDeadlineSettings();
320        if ($row[self::FIELD_DEADLINE_DATE] !== null) {
321            $deadline = $deadline->withDeadlineDate(DateTime::createFromFormat(
322                ilStudyProgrammeSettings::DATE_TIME_FORMAT,
323                $row[self::FIELD_DEADLINE_DATE]
324            ))
325            ;
326        } else {
327            $deadline_period = (int) $row[self::FIELD_DEADLINE_PERIOD];
328            if ($deadline_period == -1) {
329                $deadline_period = null;
330            }
331            $deadline = $deadline->withDeadlinePeriod($deadline_period);
332        }
333        $return = $return->withDeadlineSettings($deadline);
334
335        $vqs = $return->getValidityOfQualificationSettings();
336        if ($row[self::FIELD_VALIDITY_QUALIFICATION_DATE] !== null) {
337            $vqs = $vqs->withQualificationDate(
338                DateTime::createFromFormat(
339                    ilStudyProgrammeSettings::DATE_TIME_FORMAT,
340                    $row[self::FIELD_VALIDITY_QUALIFICATION_DATE]
341            )
342            );
343        } else {
344            $qualification_period = (int) $row[self::FIELD_VALIDITY_QUALIFICATION_PERIOD];
345            if ($qualification_period == -1) {
346                $qualification_period = null;
347            }
348            $vqs = $vqs->withQualificationPeriod($qualification_period);
349        }
350        $restart_period = (int) $row[self::FIELD_VQ_RESTART_PERIOD];
351        if ($restart_period == -1) {
352            $restart_period = null;
353        }
354        $vqs = $vqs->withRestartPeriod($restart_period);
355        $return = $return->withValidityOfQualificationSettings($vqs);
356
357        $rm_nr_by_usr_days = $row[self::FIELD_RM_NOT_RESTARTED_BY_USER_DAY];
358        if (!is_null($rm_nr_by_usr_days)) {
359            $rm_nr_by_usr_days = (int) $rm_nr_by_usr_days;
360        }
361        $proc_end_no_success = $row[self::FIELD_PROC_ENDS_NOT_SUCCESSFUL];
362        if (!is_null($proc_end_no_success)) {
363            $proc_end_no_success = (int) $proc_end_no_success;
364        }
365
366        return $return->withAutoMailSettings(
367            new \ilStudyProgrammeAutoMailSettings(
368                (bool) $row[self::FIELD_SEND_RE_ASSIGNED_MAIL],
369                $rm_nr_by_usr_days,
370                $proc_end_no_success
371            )
372        );
373    }
374
375    /**
376     * @throws LogicException
377     */
378    protected function deleteDB(int $obj_id)
379    {
380        if (!$this->checkExists($obj_id)) {
381            throw new LogicException('invaid obj_id to delete: ' . $obj_id);
382        }
383        $this->db->manipulate(
384            'DELETE FROM ' . self::TABLE
385            . ' WHERE ' . self::FIELD_OBJ_ID . ' = ' . $this->db->quote($obj_id, 'integer')
386        );
387    }
388
389    /**
390     * @pthrows LogicException
391     */
392    protected function updateDB(
393        int $obj_id,
394        int $subtype_id,
395        int $status,
396        int $lp_mode,
397        int $points,
398        string $last_change,
399        int $deadline_period,
400        int $vq_period,
401        int $vq_restart_period,
402        string $deadline_date = null,
403        string $vq_date = null,
404        int $rm_nr_by_usr_days = null,
405        int $proc_end_no_success = null,
406        bool $send_re_assigned_mail = false,
407        bool $send_info_to_re_assign_mail = false,
408        bool $send_risky_to_fail_mail = false
409    ) {
410        if (!$this->checkExists($obj_id)) {
411            throw new LogicException('invalid obj_id to update: ' . $obj_id);
412        }
413        $where = [
414            self::FIELD_OBJ_ID => [
415                'integer',
416                $obj_id
417            ]
418        ];
419
420        $values = [
421            self::FIELD_SUBTYPE_ID => [
422                'integer',
423                $subtype_id
424            ],
425            self::FIELD_STATUS => [
426                'integer',
427                $status
428            ],
429            self::FIELD_LP_MODE => [
430                'integer',
431                $lp_mode
432            ],
433            self::FIELD_POINTS => [
434                'integer',
435                $points
436            ],
437            self::FIELD_LAST_CHANGED => [
438                'timestamp',
439                $last_change
440            ],
441            self::FIELD_DEADLINE_PERIOD => [
442                'integer',
443                $deadline_period
444            ],
445            self::FIELD_DEADLINE_DATE => [
446                'timestamp',
447                $deadline_date
448            ],
449            self::FIELD_VALIDITY_QUALIFICATION_PERIOD => [
450                'integer',
451                $vq_period
452            ],
453            self::FIELD_VALIDITY_QUALIFICATION_DATE => [
454                'timestamp',
455                $vq_date
456            ],
457            self::FIELD_VQ_RESTART_PERIOD => [
458                'integer',
459                $vq_restart_period
460            ],
461            self::FIELD_RM_NOT_RESTARTED_BY_USER_DAY => [
462                'integer',
463                $rm_nr_by_usr_days
464            ],
465            self::FIELD_PROC_ENDS_NOT_SUCCESSFUL => [
466                'integer',
467                $proc_end_no_success
468            ],
469            self::FIELD_SEND_RE_ASSIGNED_MAIL => [
470                'integer',
471                $send_re_assigned_mail
472            ],
473            self::FIELD_SEND_INFO_TO_RE_ASSIGN_MAIL => [
474                'integer',
475                $send_info_to_re_assign_mail
476            ],
477            self::FIELD_SEND_RISKY_TO_FAIL_MAIL => [
478                'integer',
479                $send_risky_to_fail_mail
480            ]
481        ];
482
483        $this->db->update(self::TABLE, $values, $where);
484    }
485
486    protected function checkExists(int $obj_id)
487    {
488        $rec = $this->db->fetchAssoc(
489            $this->db->query(
490                'SELECT ' . self::FIELD_OBJ_ID
491                . '	FROM ' . self::TABLE
492                . '	WHERE ' . self::FIELD_OBJ_ID . ' = ' . $this->db->quote($obj_id, 'integer')
493            )
494        );
495        if ($rec) {
496            return true;
497        }
498        return false;
499    }
500
501    public static function clearCache()
502    {
503        self::$cache = [];
504    }
505}
506