source: iPeer/app/models/course.php @ aeda818

3.1.xdevhotfixpagodaboxticket463
Last change on this file since aeda818 was aeda818, checked in by Michael Tang <michael.tang@…>, 6 years ago

fixed invalid index bugs

rubrics basic result page - invalid index - probably the structure

of the data has been changed

#437 on trac

  • Property mode set to 100644
File size: 18.9 KB
Line 
1<?php
2/**
3 * Course
4 *
5 * @uses AppModel
6 * @package   CTLT.iPeer
7 * @author    Pan Luo <pan.luo@ubc.ca>
8 * @copyright 2012 All rights reserved.
9 * @license   MIT {@link http://www.opensource.org/licenses/MIT}
10 */
11class Course extends AppModel
12{
13    const FILTER_PERMISSION_SUPERADMIN = 0;
14    const FILTER_PERMISSION_FACULTY = 1;
15    const FILTER_PERMISSION_OWNER = 2;
16    const FILTER_PERMISSION_ENROLLED = 3;
17
18    public $name = 'Course';
19    public $displayField = 'full_name';
20
21    public $actsAs = array('ExtendAssociations', 'Containable', 'Habtamable', 'Traceable');
22
23    public $hasMany = array(
24        'Group' => array(
25            'className'   => 'Group',
26            'conditions'  => array('Group.record_status = "A"'),
27            'order'       => 'Group.created DESC',
28            'foreignKey'  => 'course_id',
29            'dependent'   => true,
30            'exclusive'   => false,
31            'finderSql'   => ''
32        ),
33        'Event' => array(
34            'className'   => 'Event',
35            'conditions'  => 'Event.record_status = "A"',
36            'order'       => 'Event.created DESC',
37            'foreignKey'  => 'course_id',
38            'dependent'   => true,
39            'exclusive'   => false,
40            'finderSql'   => ''
41        ),
42        'Survey' => array(
43            'className'   => 'Survey',
44            'conditions'  => '',
45            'order'       => '',
46            'foreignKey'  => 'course_id',
47            'dependent'   => true,
48            'exclusive'   => false,
49            'finderSql'   => ''
50        )
51    );
52
53    public $hasAndBelongsToMany = array(
54        'Instructor' => array(
55            'className'    =>  'User',
56            'joinTable'    =>  'user_courses',
57            'foreignKey'   =>  'course_id',
58            'associationForeignKey'    =>  'user_id',
59            'conditions'   =>  '',
60            'order'        =>  '',
61            'limit'        => '',
62            'unique'       => true,
63            'finderQuery'  => '',
64            'deleteQuery'  => '',
65            'dependent'    => false,
66        ),
67        'Tutor' => array(
68            'className'    =>  'User',
69            'joinTable'    =>  'user_tutors',
70            'foreignKey'   =>  'course_id',
71            'associationForeignKey'    =>  'user_id',
72            'conditions'   =>  '',
73            'order'        =>  '',
74            'limit'        => '',
75            'unique'       => true,
76            'finderQuery'  => '',
77            'deleteQuery'  => '',
78            'dependent'    => false,
79        ),
80        'Enrol' => array(
81            'className'    =>  'User',
82            'joinTable'    =>  'user_enrols',
83            'foreignKey'   =>  'course_id',
84            'associationForeignKey'    =>  'user_id',
85            'conditions'   =>  /*'Enrol.role = "S"'*/'',
86            'order'        =>  '',
87            'limit'        => '',
88            'unique'       => true,
89            'finderQuery'  => '',
90            'deleteQuery'  => '',
91            'dependent'    => false,
92        ),
93        'Department' => array(
94            'joinTable' => 'course_departments'
95        ),
96    );
97
98    /* Record Status - Active, Inactive */
99    const STATUS_ACTIVE = 'A';
100    const STATUS_INACTIVE = 'I';
101    public $STATUS = array(
102        self::STATUS_ACTIVE => 'Active',
103        self::STATUS_INACTIVE => 'Inactive'
104    );
105
106    public $validate = array (
107        'course' => array (
108            'courseRule1' => array(
109                'rule' => 'isUnique',
110                'message' => 'A course with this name already exists',
111            ),
112            'courseRule2' => array(
113                'rule' => 'notEmpty',
114                'message' => 'The course name is required.'
115            )
116        )
117    );
118
119    /**
120     * For some reason, HABTM fields can't be validated with $validate.
121     * So this is a workaround, make sure courses have at least 1
122     * department selected.
123     *
124     * Disable this for now as it is ok for a course doesn't have department
125     * Only super admin and instructors in the course have access to it
126     * */
127    /*public function beforeValidate() {
128        if (array_key_exists('Department', $this->data) &&
129            empty($this->data['Department']['Department'])) {
130            // make sure this model fails when saving without department
131            $this->invalidate('Department');
132            // make the error message appear in the right place
133            $this->Department->invalidate('Department',
134                'Please select a department.');
135        }
136    }*/
137
138    /**
139     * __construct
140     *
141     * @param bool $id    id
142     * @param bool $table table
143     * @param bool $ds    data source
144     *
145     * @access protected
146     * @return void
147     */
148    function __construct($id = false, $table = null, $ds = null)
149    {
150        parent::__construct($id, $table, $ds);
151        $this->virtualFields['student_count'] = sprintf('SELECT count(*) as count FROM user_enrols as enrol WHERE enrol.course_id = %s.id', $this->alias);
152        $this->virtualFields['full_name'] = sprintf('CONCAT(%s.course, " - ", %s.title)', $this->alias, $this->alias);
153
154    }
155
156    /**
157     * Delete instructor from a course
158     *
159     * @param unknown_type $course_id course id
160     * @param unknown_type $user_id   user id
161     *
162     * @access public
163     * @return void
164     */
165    function deleteInstructor($course_id, $user_id)
166    {
167        $this->habtmDelete('Instructor', $course_id, $user_id);
168    }
169
170    /**
171     * Add instructor to a course
172     *
173     * @param unknown_type $course_id course id
174     * @param unknown_type $user_id   user i/
175     *
176     * @access public
177     * @return void
178     */
179    function addInstructor($course_id, $user_id)
180    {
181        $this->habtmAdd('Instructor', $course_id, $user_id);
182    }
183
184    /**
185     * Get inactive courses
186     *
187     * @return list of inactive courses
188     */
189    function getInactiveCourses()
190    {
191        return $this->find('all', array('conditions' => array('record_status' => 'I')));
192    }
193
194    /**
195     * prepData
196     *
197     * @param bool $data data
198     *
199     * @access public
200     * @return void
201     */
202    function prepData($data=null)
203    {
204        if (empty($data['data']['Course']['record_status'])) {
205            $data['data']['Course']['record_status'] = $data['form']['record_status'];
206        }
207
208        if (!empty($data['form']['self_enroll'])) {
209            $data['data']['Course']['self_enroll'] = "on";
210        } else {
211            $data['data']['Course']['self_enroll'] = "off";
212        }
213
214        for ($i=1; $i<=$data['data']['Course']['count']; $i++) {
215            $data['data']['Course']['instructor_id'.$i] = isset($data['form']['instructor_id'.$i])? $data['form']['instructor_id'.$i] : '';
216        }
217
218        return $data;
219    }
220
221    /**
222     * Get course name by id
223     *
224     * @param unknown_type $id course id
225     *
226     * @return course name
227     */
228    function getCourseName($id)
229    {
230        $tmp = $this->read(null, $id);
231        return $tmp['Course']['course'];
232    }
233
234    /**
235     * Delete course and all related items
236     *
237     * @param int $id id
238     *
239     * @access public
240     * @return void
241     */
242    function deleteAll($id = null)
243    {
244        //delete self
245        if ($this->delete($id)) {
246            //delete user course,user enrol handled by hasMany
247            //$events = $this->Event->find('all', array('conditions' => array('course_id' => $id)));
248            $this->Event->deleteAll(array('course_id' => $id));
249        }
250    }
251
252    /**
253     * Get course data by course name
254     *
255     * @param unknown_type $course course name
256     * @param unknown_type $params search params
257     *
258     * @return course data
259     */
260    function getCourseByCourse($course, $params =null)
261    {
262        return $this->find('all', array_merge(array('conditions' => array('course' => $course)), $params));
263    }
264
265    /**
266     * Get course data by instructor id
267     *
268     * @param mixed $instructorId instructor id
269     * @param bool  $type         type
270     * @param int   $contain      contained models
271     * @param array $conditions   conditions for find
272     *
273     * @return course data
274     */
275    function getCourseByInstructor($instructorId, $type = 'all', $contain = array(), $conditions = array())
276    {
277        $contain = array_merge(array('Instructor'), $contain);
278        /*if ($type == 'list') {
279            $fields = array('Course.full_name');
280        }*/
281
282        // we need two queries to find the courses. becuase if we specifiy the instructor id condition
283        // we can only get one instructor with the id we specified. If the course has more than one
284        // instructor, we will fail to retrieve them.
285
286        // find course ids first
287        $courses = $this->find(
288            'all',
289            array(
290                'conditions' => array('Instructor.id' => $instructorId),
291                'contain' => array('Instructor')
292            )
293        );
294
295        $courseIds = Set::extract('/Course/id', $courses);
296        if (array_key_exists('id', $conditions)) {
297            if (is_array($conditions['id'])) {
298                $conditions['id'] = array_intersect($conditions['id'], $courseIds);
299            } else {
300                if (!in_array($conditions['id'], $courseIds)) {
301                    return false;
302                }
303            }
304        } else {
305            $conditions['id'] = $courseIds;
306        }
307        // find courses with instructor and other models specified in contain
308        $courses = $this->find($type, array('conditions' => $conditions, 'contain' => $contain));
309
310        return $courses;
311    }
312
313    /**
314     * Get course data by instructor id
315     *
316     * @param unknown_type $instructorId instructor id
317     *
318     * @return course data
319     */
320    function getListByInstructor($instructorId)
321    {
322        return $this->getCourseByInstructor($instructorId, 'list');
323    }
324
325    /**
326     * Get course data by student id
327     *
328     * @param mixed $instructorId instructor id
329     * @param bool  $type         type
330     * @param int   $contain      contained models
331     * @param array $conditions   conditions for find
332     *
333     * @return course data
334     */
335    function getCourseByStudent($studentId, $type = 'all', $contain = array(), $conditions = array())
336    {
337        $contain = array_merge(array('Enrol'), $contain);
338        /*if ($type == 'list') {
339            $fields = array('Course.full_name');
340        }*/
341
342        // we need two queries to find the courses. becuase if we specifiy the student id condition
343        // we can only get one student with the id we specified. If the course has more than one
344        // student, we will fail to retrieve them.
345
346        // find course ids first
347        $courses = $this->find(
348            'all',
349            array(
350                'conditions' => array('Enrol.id' => $studentId),
351                'contain' => array('Enrol')
352            )
353        );
354
355        $courseIds = Set::extract('/Course/id', $courses);
356        if (array_key_exists('id', $conditions)) {
357            if (is_array($conditions['id'])) {
358                $conditions['id'] = array_intersect($conditions['id'], $courseIds);
359            } else {
360                if (!in_array($conditions['id'], $courseIds)) {
361                    return false;
362                }
363            }
364        } else {
365            $conditions['id'] = $courseIds;
366        }
367        // find courses with student and other models specified in contain
368        $courses = $this->find($type, array('conditions' => $conditions, 'contain' => $contain));
369
370        return $courses;
371    }
372    /**
373     * enrolStudents enrol student to a course
374     *
375     * @param mixed $ids      id array of the students
376     * @param mixed $courseId the course the students are enrolled into. If null,
377     * read the current id in the course object
378     *
379     * @access public
380     * @return boolean true for success, false for failed.
381     */
382    function enrolStudents($ids, $courseId = null)
383    {
384        if (null == $courseId) {
385            $courseId = $this->id;
386        }
387
388        if (null == $courseId) {
389            return false;
390        }
391
392        return $this->habtmAdd('Enrol', $courseId, $ids);
393    }
394
395    /**
396     * Get course data by departments
397     *
398     * @param array  $departments array of departments
399     * @param string $findType    find type
400     *
401     * @return course data
402     */
403    function getByDepartments($departments, $findType)
404    {
405        $this->CourseDepartment = Classregistry::init('CourseDepartment');
406
407        $courses = array();
408
409        foreach ($departments as $department) {
410            $dp_id = $department['Department']['id'];
411            $cd = $this->CourseDepartment->find('all', array('conditions' => array('department_id' => $dp_id)));
412            foreach ($cd as $course) {
413                array_push($courses, $course['CourseDepartment']['course_id']);
414            }
415        }
416        $ret = $this->find($findType, array('conditions' => array('Course.id' => $courses)));
417
418        return $ret;
419    }
420
421    /**
422     * getByDepartmentIds get course belongs to departments
423     *
424     * @param mixed  $departmentIds id or array of ids
425     * @param string $findType      find type
426     * @param mixed  $options       options for find
427     *
428     * @access public
429     * @return void
430     */
431    function getByDepartmentIds($departmentIds, $findType = "all", $options = array())
432    {
433        $options['conditions']['Department.id'] = $departmentIds;
434        if(isset($options['contain'])) {
435                $options['contain'] = array_merge(array('Department'), $options['contain']);
436        } else {
437                $options['contain'] = array('Department');
438        }
439        if ($findType == 'list') {
440            $courses = $this->find('all', $options);
441            return Set::combine($courses, '{n}.'.$this->alias.'.id', '{n}.'.$this->alias.'.'.$this->displayField);
442        }
443        return $this->find($findType, $options);
444    }
445
446    /**
447     * getCourseList
448     *
449     * @access public
450     * @return void
451     */
452    function getCourseList()
453    {
454        $this->displayField = 'course';
455        return $this->find('list', array(
456            'conditions' => array()
457        ));
458    }
459
460    /**
461     * getCourseById
462     *
463     * @param mixed $courseId course id
464     *
465     * @access public
466     * @return void
467     */
468    function getCourseById($courseId)
469    {
470        return $this->find('first', array(
471            'conditions' => array('Course.id' => $courseId),
472            'contain' => false
473        ));
474    }
475
476    /**
477     * getCourseById
478     *
479     * @param mixed $courseId course id
480     *
481     * @access public
482     * @return void
483     */
484    function getCourseWithInstructorsById($courseId)
485    {
486        return $this->find('first', array(
487            'conditions' => array('Course.id' => $courseId),
488            'contain' => 'Instructor'
489        ));
490    }
491
492    /**
493     * getCourseWithEnrolmentById
494     *
495     * @param mixed $courseId
496     *
497     * @access public
498     * @return void
499     */
500    function getCourseWithEnrolmentById($courseId)
501    {
502        $course = $this->find('first', array(
503            'conditions' => array('Course.id' => $courseId),
504            'contain' => array(
505                'Enrol' => array(
506                    'fields' => array('id', 'username', 'full_name', 'email', 'student_no')
507                )
508            )
509        ));
510
511        // some clean up
512        foreach ($course['Enrol'] as $key => $student) {
513            unset($course['Enrol'][$key]['UserEnrol']);
514        }
515
516        return $course;
517    }
518
519    /**
520     * getCourseIdByGroup get the course by group id
521     *
522     * @param mixed $groupId
523     *
524     * @access public
525     * @return object course object
526     */
527    function getCourseByGroupId($groupId)
528    {
529        $courseId = $this->Group->field('course_id', array('id' => $groupId));
530        if (!$courseId) {
531            return array();
532        }
533        return $this->find('first', array('conditions' => array('Course.id' => $courseId)));
534    }
535
536    /**
537     * getCoursesByUserIdFilterPermission
538     *
539     * @param int    $userId     user id
540     * @param mixed  $permission filter permission
541     * @param string $type       find type
542     * @param array  $options    find options
543     *
544     * @access protected
545     * @return void
546     */
547    protected function getCoursesByUserIdFilterPermission($userId, $permission, $type = 'all', $options = array())
548    {
549        switch($permission) {
550        case Course::FILTER_PERMISSION_SUPERADMIN:
551            $courses = $this->find($type, $options);
552            break;
553        case Course::FILTER_PERMISSION_FACULTY:
554            $departmentIds = $this->Department->getIdsByUserId($userId);
555            $courses = $this->getByDepartmentIds($departmentIds, $type, $options);
556            break;
557        case Course::FILTER_PERMISSION_OWNER:
558            $options = array_merge(array('contain' => array(), 'conditions' => array()), $options);
559            $courses = $this->getCourseByInstructor($userId, $type, $options['contain'], $options['conditions']);
560            break;
561        case Course::FILTER_PERMISSION_ENROLLED:
562            $options = array_merge(array('contain' => array(), 'conditions' => array()), $options);
563            $courses = $this->getCourseByStudent($userId, $type, $options['contain'], $options['conditions']);
564            break;
565        default:
566            return array();
567        }
568
569        return $courses;
570    }
571
572    /**
573     * getAccessibleCourses get all active course that the user has access to
574     *
575     * @param int    $userId     user id
576     * @param mixed  $permission filter permission
577     * @param string $type       find type
578     * @param array  $options    find options
579     *
580     * @access public
581     * @return void
582     */
583    function getAccessibleCourses($userId, $permission, $type = 'all', $options = array())
584    {
585        $default = array('conditions' => array('record_status' => 'A'));
586        $options = array_merge($default, $options);
587        return $this->getCoursesByUserIdFilterPermission($userId, $permission, $type, $options);
588    }
589
590    /**
591     * getAllAccessibleCourses get all course that the user has access to,
592     * including inactive ones
593     *
594     * @param int    $userId     user id
595     * @param mixed  $permission filter permission
596     * @param string $type       find type
597     * @param array  $options    find options
598     *
599     * @access public
600     * @return void
601     */
602    function getAllAccessibleCourses($userId, $permission, $type = 'all', $options = array())
603    {
604        return $this->getCoursesByUserIdFilterPermission($userId, $permission, $type, $options);
605    }
606
607    /**
608     * getAccessibleCourseById get one course by course id, if user do not have
609     * access to the course, return false.
610     *
611     * @param int   $courseId   course id
612     * @param int   $userId     user id
613     * @param mixed $permission filter permission
614     * @param array $contain    contain relationship
615     *
616     * @access public
617     * @return void
618     */
619    function getAccessibleCourseById($courseId, $userId,  $permission, $contain = array())
620    {
621        return $this->getAccessibleCourses($userId, $permission, 'first', array('conditions' => array($this->alias.'.id' => $courseId), 'contain' => $contain));
622    }
623}
Note: See TracBrowser for help on using the repository browser.