Completed
Push — master ( 189151...5aefc8 )
by Roberto
18:39 queued 17:09
created

lib.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17
/**
18
 * This file contains the relationship API functions used to interact with the data
19
 * and other Moodle hooks
20
 *
21
 * @package local_relationship
22
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
25
defined('MOODLE_INTERNAL') || die();
26
27
function local_relationship_extend_settings_navigation(navigation_node $navigation) {
28
    global $PAGE;
29
30
    if (is_a($PAGE->context, 'context_coursecat') && has_capability('local/relationship:manage', $PAGE->context)) {
31
        $category_node = $navigation->get('categorysettings');
32
        if ($category_node) {
33
            $category_node->add(
34
                    get_string('pluginname', 'local_relationship'),
35
                    new moodle_url('/local/relationship/index.php', array('contextid' => $PAGE->context->id)),
36
                    navigation_node::TYPE_SETTING,
37
                    null,
38
                    null,
39
                    new pix_icon('relationship', '', 'local_relationship')
40
            );
41
        }
42
    }
43
}
44
45
function local_relationship_cron() {
46
    relationship_uniformly_distribute_members();
47
48
    return true;
49
}
50
51
52
//
53
// TODO: Refactory to "relationship class"
54
//
55
56
function relationship_uniformly_distribute_members($relationshipid = null) {
57
    global $DB;
58
59
    $params = array();
60
    $cond = '';
61
    if (!empty($relationshipid)) {
62
        $params['id'] = $relationshipid;
63
        $cond = 'WHERE rl.id = :id';
64
    }
65
66
    $sql = "SELECT DISTINCT rc.*
67
              FROM {relationship} rl
68
              JOIN {relationship_cohorts} rc
69
                ON (rc.relationshipid = rl.id AND rc.uniformdistribution = 1)
70
              JOIN {relationship_groups} rg
71
                ON (rg.relationshipid = rl.id AND rc.uniformdistribution = 1)
72
              {$cond}";
73
    $rcs = $DB->get_records_sql($sql, $params);
74
    foreach ($rcs AS $rc) {
75
        $params = array('relationshipid' => $rc->relationshipid, 'relationshipcohortid' => $rc->id);
76
        $sql = " SELECT cm.userid
77
                   FROM {relationship_cohorts} rc
78
                   JOIN {cohort} ch
79
                     ON (ch.id = rc.cohortid)
80
                   JOIN {cohort_members} cm
81
                     ON (cm.cohortid = ch.id)
82
              LEFT JOIN {relationship_members} rm
83
                     ON (rm.relationshipcohortid = rc.id AND rm.userid = cm.userid)
84
                  WHERE rc.id = :relationshipcohortid
85
                    AND ISNULL(rm.userid)";
86
        $users = $DB->get_records_sql($sql, $params);
87
88
        relationship_uniformly_distribute_users($rc, array_keys($users));
89
    }
90
}
91
92
function relationship_uniformly_distribute_users($relationshipcohort, $userids) {
93
    global $DB;
94
95
    if (empty($userids)) {
96
        return;
97
    }
98
    $sql = "SELECT rg.id, rg.userlimit, count(DISTINCT rm.userid) as count
99
              FROM {relationship_cohorts} rc
100
              JOIN {relationship_groups} rg
101
                ON (rg.relationshipid = rc.relationshipid AND rg.uniformdistribution = 1)
102
         LEFT JOIN {relationship_members} rm
103
                ON (rm.relationshipgroupid = rg.id AND rm.relationshipcohortid = rc.id)
104
             WHERE rc.id = :relationshipcohortid
105
          GROUP BY rg.id";
106
    $groups = $DB->get_records_sql($sql, array('relationshipcohortid' => $relationshipcohort->id));
107
    if (!empty($groups)) {
108
        foreach ($userids AS $userid) {
109
            $min = 99999999;
110
            $gmin = 0;
111
            foreach ($groups AS $grpid => $grp) {
112
                if ($grp->count < $min && ($grp->userlimit == 0 || $grp->count < $grp->userlimit)) {
113
                    $min = $grp->count;
114
                    $gmin = $grpid;
115
                }
116
            }
117
            if ($gmin == 0) {
118
                break; // there is no group to add member
119
            } else {
120
                relationship_add_member($gmin, $relationshipcohort->id, $userid);
121
                $groups[$gmin]->count++;
122
            }
123
        }
124
    }
125
}
126
127
/**
128
 * Add relationship member
129
 *
130
 * @param $relationshipgroupid
131
 * @param $relationshipcohortid
132
 * @param $userid
133
 * @return int|bool relationship_members id of added member or false if any error occours
134
 * @throws coding_exception
135
 */
136
function relationship_add_member($relationshipgroupid, $relationshipcohortid, $userid) {
137
    global $DB;
138
139
    $params = array('relationshipgroupid' => $relationshipgroupid, 'userid' => $userid, 'relationshipcohortid' => $relationshipcohortid);
140
    if ($DB->record_exists('relationship_members', $params)) {
141
        // No duplicates!
142
        return false;
143
    }
144
145
    $relationshipgroup = $DB->get_record('relationship_groups', array('id' => $relationshipgroupid), '*', MUST_EXIST);
146
    $relationshipcohort = $DB->get_record('relationship_cohorts', array('id' => $relationshipcohortid), '*', MUST_EXIST);
147
    $relationship = $DB->get_record('relationship', array('id' => $relationshipgroup->relationshipid), '*', MUST_EXIST);
148
149
    $record = new stdClass();
150
    $record->relationshipgroupid = $relationshipgroupid;
151
    $record->relationshipcohortid = $relationshipcohortid;
152
    $record->userid = $userid;
153
    $record->timeadded = time();
154
155
    $result = $DB->insert_record('relationship_members', $record);
156
157
    if ($result) {
158
        $record->id = $result;
159
160
        $event = \local_relationship\event\relationshipgroup_member_added::create(array(
161
                'context' => context::instance_by_id($relationship->contextid),
162
                'objectid' => $relationshipgroupid,
163
                'relateduserid' => $userid,
164
                'other' => $relationshipcohort->roleid,
165
        ));
166
        $event->add_record_snapshot('relationship_groups', $relationshipgroup);
167
        $event->add_record_snapshot('relationship', $relationship);
168
        $event->trigger();
169
170
        return $record->id;
171
    }
172
173
    return false;
174
}
175
176
/**
177
 * Remove member from a relationship
178
 *
179
 * @param int $relationshipgroupid
180
 * @param int $relationshipcohortid
181
 * @param int $userid
182
 * @return bool
183
 * @throws coding_exception
184
 */
185
function relationship_remove_member($relationshipgroupid, $relationshipcohortid, $userid) {
186
    global $DB;
187
188
    $params = array('relationshipgroupid' => $relationshipgroupid, 'userid' => $userid, 'relationshipcohortid' => $relationshipcohortid);
189
    $result = $DB->delete_records('relationship_members', $params);
190
191
    if ($result) {
192
        $relationshipgroup = $DB->get_record('relationship_groups', array('id' => $relationshipgroupid), '*', MUST_EXIST);
193
        $relationshipcohort = $DB->get_record('relationship_cohorts', array('id' => $relationshipcohortid), '*', MUST_EXIST);
194
        $relationship = $DB->get_record('relationship', array('id' => $relationshipgroup->relationshipid), '*', MUST_EXIST);
195
196
        $event = \local_relationship\event\relationshipgroup_member_removed::create(array(
197
                'context' => context::instance_by_id($relationship->contextid),
198
                'objectid' => $relationshipgroupid,
199
                'relateduserid' => $userid,
200
                'other' => $relationshipcohort->roleid,
201
        ));
202
        $event->add_record_snapshot('relationship_groups', $relationshipgroup);
203
        $event->add_record_snapshot('relationship', $relationship);
204
        $event->trigger();
205
206
        return true;
207
    }
208
209
    return false;
210
}
211
212
/**
213
 * @param $relationshipid
214
 * @return stdClass $relationship
215
 */
216
function relationship_get_relationship($relationshipid) {
217
    global $DB;
218
219
    $relationship = $DB->get_record('relationship', array('id' => $relationshipid), '*', MUST_EXIST);
220
    $relationship->tags = core_tag_tag::get_item_tags_array('relationship', 'relationship', $relationshipid  );
221
222
    return $relationship;
223
}
224
225
/**
226
 * Add new relationship.
227
 *
228
 * @param stdClass $relationship
229
 * @return int|bool new relationship id or false if any error occours
230
 * @throws coding_exception
231
 */
232
function relationship_add_relationship($relationship) {
233
    global $DB;
234
235
    if (!isset($relationship->name)) {
236
        throw new coding_exception('Missing relationship name in relationship_add_relationship().');
237
    }
238
    $relationship->name = trim($relationship->name);
239
240
    if (!isset($relationship->idnumber)) {
241
        $relationship->idnumber = null;
242
    }
243
244
    if (!isset($relationship->description)) {
245
        $relationship->description = '';
246
    }
247
248
    if (!isset($relationship->descriptionformat)) {
249
        $relationship->descriptionformat = FORMAT_HTML;
250
    }
251
252
    if (empty($relationship->component)) {
253
        $relationship->component = '';
254
    }
255
256
    if (!isset($relationship->timecreated)) {
257
        $relationship->timecreated = time();
258
    }
259
260
    if (!isset($relationship->timemodified)) {
261
        $relationship->timemodified = $relationship->timecreated;
262
    }
263
264
    $result = $DB->insert_record('relationship', $relationship);
265
266
    if ($result) {
267
        $relationship->id = $result;
268
        tag_set('relationship', $relationship->id, $relationship->tags);
269
270
        $event = \local_relationship\event\relationship_created::create(array(
271
                'context' => context::instance_by_id($relationship->contextid),
272
                'objectid' => $relationship->id,
273
        ));
274
        $event->add_record_snapshot('relationship', $relationship);
275
        $event->trigger();
276
277
        return $relationship->id;
278
    }
279
280
    return false;
281
}
282
283
/**
284
 * Update existing relationship
285
 *
286
 * @param sstdClass $relationship
287
 * @return void
288
 */
289
function relationship_update_relationship($relationship) {
290
    global $DB;
291
292
    $relationship->timemodified = time();
293
    $result = $DB->update_record('relationship', $relationship);
294
295
    if ($result) {
296
        tag_set('relationship', $relationship->id, $relationship->tags);
297
298
        $event = \local_relationship\event\relationship_updated::create(array(
299
                'context' => context::instance_by_id($relationship->contextid),
300
                'objectid' => $relationship->id,
301
        ));
302
        $event->add_record_snapshot('relationship', $relationship);
303
        $event->trigger();
304
305
        return true;
306
    }
307
308
    return false;
309
}
310
311
/**
312
 * Delete relationship
313
 * @param stdClass $relationship
314
 * @return bool
0 ignored issues
show
Should the return type not be boolean|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
315
 * @throws coding_exception
316
 * @throws dml_transaction_exception
317
 */
318
function relationship_delete_relationship($relationship) {
319
    global $DB;
320
321
    $cohorts = $DB->get_records('relationship_cohorts', array('relationshipid' => $relationship->id));
322
323
    if(count($cohorts) == 0) {
324
325
        $relationshipgroups = $DB->get_records('relationship_groups', array('relationshipid' => $relationship->id));
326
        foreach ($relationshipgroups AS $g) {
327
            relationship_delete_group($g);
328
        }
329
330
        try {
331
            $transaction = $DB->start_delegated_transaction();
332
333
334
335
            $DB->delete_records('relationship_cohorts', array('relationshipid' => $relationship->id));
336
337
            $tags = core_tag_tag::get_item_tags_array('relationship', 'relationship', $relationship->id);
338
            if (count($tags) > 0) {
339
                tag_delete(array_keys($tags));
340
            }
341
342
            $DB->delete_records('relationship', array('id' => $relationship->id));
343
344
            $transaction->allow_commit();
345
        } catch (Exception $e) {
346
            $transaction->rollback($e);
347
348
            return false;
349
        }
350
351
        $event = \local_relationship\event\relationship_deleted::create(array(
352
            'context' => context::instance_by_id($relationship->contextid),
353
            'objectid' => $relationship->id,
354
        ));
355
        $event->add_record_snapshot('relationship', $relationship);
356
        $event->trigger();
357
358
        return true;
359
    } else {
360
        return -1;
361
    }
362
}
363
364
//
365
// Relationship Cohorts
366
//
367
368
/**
369
 * Cohorts related to a relationship
370
 *
371
 * @param $relationshipid
372
 * @param bool $full load full cohort and roles data
373
 * @return array
374
 * @throws coding_exception
375
 */
376
function relationship_get_cohorts($relationshipid, $full = true) {
377
    global $DB;
378
379
    $cohorts = $DB->get_records('relationship_cohorts', array('relationshipid' => $relationshipid));
380
    if ($full) {
381
        foreach ($cohorts AS $ch) {
382
            $ch->cohort = $DB->get_record('cohort', array('id' => $ch->cohortid));
383
            if ($role = $DB->get_record('role', array('id' => $ch->roleid))) {
384
                $ch->role_name = role_get_name($role);
385
            } else {
386
                $ch->role_name = false;
387
            }
388
        }
389
    }
390
391
    return $cohorts;
392
}
393
394
/**
395
 * Get a specific relationshipcohort by ID
396
 *
397
 * @param $relationshipcohortid
398
 * @param bool $full load full cohort and roles data
399
 * @return mixed
400
 * @throws coding_exception
401
 */
402
function relationship_get_cohort($relationshipcohortid, $full = true) {
403
    global $DB;
404
405
    $cohort = $DB->get_record('relationship_cohorts', array('id' => $relationshipcohortid), '*', MUST_EXIST);
406
    if ($full) {
407
        $cohort->cohort = $DB->get_record('cohort', array('id' => $cohort->cohortid));
408
        if ($role = $DB->get_record('role', array('id' => $cohort->roleid))) {
409
            $cohort->role_name = role_get_name($role);
410
        } else {
411
            $cohort->role_name = false;
412
        }
413
    }
414
415
    return $cohort;
416
}
417
418
/**
419
 * Add a relationshipcohort
420
 *
421
 * @param $relationshipcohort
422
 * @return bool|int
423
 */
424
function relationship_add_cohort($relationshipcohort) {
425
    global $DB;
426
427
    if (!isset($relationshipcohort->timecreated)) {
428
        $relationshipcohort->timecreated = time();
429
    }
430
    if (!isset($relationshipcohort->timemodified)) {
431
        $relationshipcohort->timemodified = $relationshipcohort->timecreated;
432
    }
433
434
    $relationshipcohort->id = $DB->insert_record('relationship_cohorts', $relationshipcohort);
435
436
    return $relationshipcohort->id;
437
}
438
439
/**
440
 * Update a specific relationshipcohort
441
 *
442
 * @param $relationshipcohort
443
 * @return bool
444
 */
445
function relationship_update_cohort($relationshipcohort) {
446
    global $DB;
447
448
    $relationshipcohort->timemodified = time();
449
450
    return $DB->update_record('relationship_cohorts', $relationshipcohort);
451
}
452
453
/**
454
 * Delete a specific relationshipcohort
455
 *
456
 * @param $relationshipcohort
457
 * @return bool
458
 */
459
function relationship_delete_cohort($relationshipcohort) {
460
    global $DB;
461
    $members = $DB->get_records('relationship_members', array('relationshipcohortid' => $relationshipcohort->id));
462
    foreach ($members as $m) {
463
        relationship_remove_member($m->relationshipgroupid, $m->relationshipcohortid, $m->userid);
464
    }
465
466
    return $DB->delete_records('relationship_cohorts', array('id' => $relationshipcohort->id));
467
}
468
469
//
470
// Relationship Groups
471
//
472
473
/**
474
 * Get groups from a relationship
475
 * @param $relationshipid
476
 * @return array
477
 */
478
function relationship_get_groups($relationshipid) {
479
    global $DB;
480
481
    $sql = "SELECT rg.*, (SELECT count(*)
482
                            FROM {relationship_members}
483
                           WHERE relationshipgroupid = rg.id) as size
484
              FROM {relationship_groups} rg
485
             WHERE rg.relationshipid = :relationshipid
486
          GROUP BY rg.id
487
          ORDER BY name";
488
489
    return $DB->get_records_sql($sql, array('relationshipid' => $relationshipid));
490
}
491
492
/**
493
 * Add a relationshipgroup
494
 *
495
 * @param $relationshipgroup
496
 * @return bool|int
497
 * @throws coding_exception
498
 */
499
function relationship_add_group($relationshipgroup) {
500
    global $DB;
501
502
    $relationshipgroup->name = trim($relationshipgroup->name);
503
    if (!isset($relationshipgroup->timecreated)) {
504
        $relationshipgroup->timecreated = time();
505
    }
506
    if (!isset($relationshipgroup->timemodified)) {
507
        $relationshipgroup->timemodified = $relationshipgroup->timecreated;
508
    }
509
510
    $relationship = $DB->get_record('relationship', array('id' => $relationshipgroup->relationshipid), '*', MUST_EXIST);
511
    $result = $DB->insert_record('relationship_groups', $relationshipgroup);
512
513
    if ($result) {
514
        $relationshipgroup->id = $result;
515
516
        $event = \local_relationship\event\relationshipgroup_created::create(array(
517
                'context' => context::instance_by_id($relationship->contextid),
518
                'objectid' => $relationshipgroup->id,
519
        ));
520
        $event->add_record_snapshot('relationship_groups', $relationshipgroup);
521
        $event->add_record_snapshot('relationship', $relationship);
522
        $event->trigger();
523
    }
524
525
    return $result;
526
}
527
528
/**
529
 * Update a relationshipgroup
530
 *
531
 * @param $relationshipgroup
532
 * @return bool
533
 * @throws coding_exception
534
 */
535
function relationship_update_group($relationshipgroup) {
536
    global $DB;
537
538
    $relationshipgroup->timemodified = time();
539
    if (isset($relationshipgroup->name)) {
540
        $relationshipgroup->name = trim($relationshipgroup->name);
541
    }
542
    $result = $DB->update_record('relationship_groups', $relationshipgroup);
543
544
    if ($result) {
545
        $relationship = $DB->get_record('relationship', array('id' => $relationshipgroup->relationshipid), '*', MUST_EXIST);
546
547
        $event = \local_relationship\event\relationshipgroup_updated::create(array(
548
                'context' => context::instance_by_id($relationship->contextid),
549
                'objectid' => $relationshipgroup->id,
550
        ));
551
        $event->add_record_snapshot('relationship_groups', $relationshipgroup);
552
        $event->add_record_snapshot('relationship', $relationship);
553
        $event->trigger();
554
    }
555
556
    return $result;
557
}
558
559
/**
560
 * @param $relationshipgroup
561
 * @return bool
562
 * @throws coding_exception
563
 * @throws dml_transaction_exception
564
 */
565
function relationship_delete_group($relationshipgroup) {
566
    global $DB;
567
568
    try {
569
        $transaction = $DB->start_delegated_transaction();
570
571
        $relationship = $DB->get_record('relationship', array('id' => $relationshipgroup->relationshipid), '*', MUST_EXIST);
572
        $DB->delete_records('relationship_members', array('relationshipgroupid' => $relationshipgroup->id));
573
        $DB->delete_records('relationship_groups', array('id' => $relationshipgroup->id));
574
575
        $transaction->allow_commit();
576
    } catch (Exception $e) {
577
        $transaction->rollback($e);
578
579
        return false;
580
    }
581
582
    $event = \local_relationship\event\relationshipgroup_deleted::create(array(
583
            'context' => context::instance_by_id($relationship->contextid),
584
            'objectid' => $relationshipgroup->id,
585
    ));
586
    $event->add_record_snapshot('relationship_groups', $relationshipgroup);
587
    $event->add_record_snapshot('relationship', $relationship);
588
    $event->trigger();
589
590
    return true;
591
}
592