527 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			527 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
// This file is part of the Studyplan plugin for Moodle
 | 
						|
//
 | 
						|
// Moodle is free software: you can redistribute it and/or modify
 | 
						|
// it under the terms of the GNU General Public License as published by
 | 
						|
// the Free Software Foundation, either version 3 of the License, or
 | 
						|
// (at your option) any later version.
 | 
						|
//
 | 
						|
// Moodle is distributed in the hope that it will be useful,
 | 
						|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
// GNU General Public License for more details.
 | 
						|
//
 | 
						|
// You should have received a copy of the GNU General Public License
 | 
						|
// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
/**
 | 
						|
 *
 | 
						|
 * @package    local_treestudyplan
 | 
						|
 * @copyright  2023 P.M. Kuipers
 | 
						|
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
						|
 */
 | 
						|
 | 
						|
namespace local_treestudyplan;
 | 
						|
defined('MOODLE_INTERNAL') || die();
 | 
						|
 | 
						|
require_once($CFG->libdir.'/externallib.php');
 | 
						|
 | 
						|
class studyitem {
 | 
						|
 | 
						|
    public const COMPETENCY = 'competency';
 | 
						|
    public const COURSE = 'course';
 | 
						|
    public const JUNCTION = 'junction';
 | 
						|
    public const BADGE = 'badge';
 | 
						|
    public const FINISH = 'finish';
 | 
						|
    public const START = 'start';
 | 
						|
    public const INVALID = 'invalid';
 | 
						|
 | 
						|
    public const TABLE = "local_treestudyplan_item";
 | 
						|
 | 
						|
    private static $STUDYITEMCACHE = [];
 | 
						|
    private $r; // Holds database record.
 | 
						|
    private $id;
 | 
						|
 | 
						|
    private $courseinfo = null;
 | 
						|
    private $studyline;
 | 
						|
    private $aggregator;
 | 
						|
 | 
						|
    public function context(): \context {
 | 
						|
        return $this->studyline->context();
 | 
						|
    }
 | 
						|
 | 
						|
    public function studyline(): studyline {
 | 
						|
        return $this->studyline;
 | 
						|
    }
 | 
						|
 | 
						|
    public function conditions() {
 | 
						|
        return $this->r->conditions;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function findById($id): self {
 | 
						|
        if (!array_key_exists($id, self::$STUDYITEMCACHE)) {
 | 
						|
            self::$STUDYITEMCACHE[$id] = new self($id);
 | 
						|
        }
 | 
						|
        return self::$STUDYITEMCACHE[$id];
 | 
						|
    }
 | 
						|
 | 
						|
    public function __construct($id) {
 | 
						|
        global $DB;
 | 
						|
        $this->id = $id;
 | 
						|
        $this->r = $DB->get_record(self::TABLE, ['id' => $id], "*", MUST_EXIST);
 | 
						|
 | 
						|
        $this->studyline = studyline::findById($this->r->line_id);
 | 
						|
        $this->aggregator = $this->studyline()->studyplan()->aggregator();
 | 
						|
    }
 | 
						|
 | 
						|
    public function id() {
 | 
						|
        return $this->id;
 | 
						|
    }
 | 
						|
 | 
						|
    public function slot() {
 | 
						|
        return $this->r->slot;
 | 
						|
    }
 | 
						|
 | 
						|
    public function layer() {
 | 
						|
        return $this->r->layer;
 | 
						|
    }
 | 
						|
 | 
						|
    public function type() {
 | 
						|
        return $this->r->type;
 | 
						|
    }
 | 
						|
 | 
						|
    public function courseid() {
 | 
						|
        return $this->r->course_id;
 | 
						|
    }
 | 
						|
 | 
						|
    public static function exists($id) {
 | 
						|
        global $DB;
 | 
						|
        return is_numeric($id) && $DB->record_exists(self::TABLE, array('id' => $id));
 | 
						|
    }
 | 
						|
 | 
						|
    public static function editor_structure($value=VALUE_REQUIRED) {
 | 
						|
        return new \external_single_structure([
 | 
						|
            "id" => new \external_value(PARAM_INT, 'id of study item'),
 | 
						|
            "type" => new \external_value(PARAM_TEXT, 'shortname of study item'),
 | 
						|
            "conditions" => new \external_value(PARAM_TEXT, 'conditions for completion'),
 | 
						|
            "slot" => new \external_value(PARAM_INT, 'slot in the study plan'),
 | 
						|
            "layer" => new \external_value(PARAM_INT, 'layer in the slot'),
 | 
						|
            "span"         => new \external_value(PARAM_INT, 'how many periods the item spans'),
 | 
						|
            "course" => courseinfo::editor_structure(VALUE_OPTIONAL),
 | 
						|
            "badge" => badgeinfo::editor_structure(VALUE_OPTIONAL),
 | 
						|
            "continuation_id" => new \external_value(PARAM_INT, 'id of continued item'),
 | 
						|
            "connections" => new \external_single_structure([
 | 
						|
                'in' => new \external_multiple_structure(studyitemconnection::structure()),
 | 
						|
                'out' => new \external_multiple_structure(studyitemconnection::structure()),
 | 
						|
            ]),
 | 
						|
        ]);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public function editor_model() {
 | 
						|
        return $this->generate_model("editor");
 | 
						|
    }
 | 
						|
 | 
						|
    private function generate_model($mode) {
 | 
						|
        // Mode parameter is used to geep this function for both editor model and export model.
 | 
						|
        // (Export model results in fewer parameters on children, but is otherwise basically the same as this function).
 | 
						|
        global $DB;
 | 
						|
 | 
						|
        $model = [
 | 
						|
            'id' => $this->r->id, // Id is needed in export model because of link references.
 | 
						|
            'type' => $this->isValid() ? $this->r->type : self::INVALID,
 | 
						|
            'conditions' => $this->r->conditions,
 | 
						|
            'slot' => $this->r->slot,
 | 
						|
            'layer' => $this->r->layer,
 | 
						|
            'span' => $this->r->span,
 | 
						|
            'continuation_id' => $this->r->continuation_id,
 | 
						|
            'connections' => [
 | 
						|
                "in" => [],
 | 
						|
                "out" => [],
 | 
						|
            ]
 | 
						|
        ];
 | 
						|
        if ($mode == "export") {
 | 
						|
            // Remove slot and layer.
 | 
						|
            unset($model["slot"]);
 | 
						|
            unset($model["layer"]);
 | 
						|
            unset($model["continuation_id"]);
 | 
						|
            $model["connections"] = []; // In export mode, connections is just an array of outgoing connections.
 | 
						|
            if (!isset($this->r->conditions)) {
 | 
						|
                unset($model["conditions"]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Add course link if available.
 | 
						|
        $ci = $this->getcourseinfo();
 | 
						|
        if (isset($ci)) {
 | 
						|
            if ($mode == "export") {
 | 
						|
                $model['course'] = $ci->shortname();
 | 
						|
            } else {
 | 
						|
                $model['course'] = $ci->editor_model($this, $this->aggregator->usecorecompletioninfo());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Add badge info if available.
 | 
						|
        if (is_numeric($this->r->badge_id) && $DB->record_exists('badge', array('id' => $this->r->badge_id))) {
 | 
						|
            $badge = new \core_badges\badge($this->r->badge_id);
 | 
						|
            $badgeinfo = new badgeinfo($badge);
 | 
						|
            if ($mode == "export") {
 | 
						|
                $model['badge'] = $badgeinfo->name();
 | 
						|
            } else {
 | 
						|
                // Also supply a list of linked users, so the badgeinfo can give stats on .
 | 
						|
                // The amount issued, related to this studyplan.
 | 
						|
                $studentids = $this->studyline()->studyplan()->find_linked_userids();
 | 
						|
                $model['badge'] = $badgeinfo->editor_model($studentids);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($mode == "export") {
 | 
						|
            // Also export gradables.
 | 
						|
            $gradables = gradeinfo::list_studyitem_gradables($this);
 | 
						|
            if (count($gradables) > 0) {
 | 
						|
                $model["gradables"] = [];
 | 
						|
                foreach ($gradables as $g) {
 | 
						|
                    $model["gradables"][] = $g->export_model();;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Add incoming and outgoing connection info.
 | 
						|
        $connout = studyitemconnection::find_outgoing($this->id);
 | 
						|
 | 
						|
        if ($mode == "export") {
 | 
						|
            foreach ($connout as $c) {
 | 
						|
                $model["connections"][] = $c->to_id();
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            foreach ($connout as $c) {
 | 
						|
                $model['connections']['out'][$c->to_id()] = $c->model();
 | 
						|
            }
 | 
						|
            $connin = studyitemconnection::find_incoming($this->id);
 | 
						|
            foreach ($connin as $c) {
 | 
						|
                $model['connections']['in'][$c->from_id()] = $c->model();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $model;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public static function add($fields, $import=false) {
 | 
						|
        global $DB;
 | 
						|
        $addable = ['line_id', 'type', 'layer', 'conditions', 'slot',
 | 
						|
                    'competency_id', 'course_id', 'badge_id', 'continuation_id', 'span'];
 | 
						|
        $info = [ 'layer' => 0, ];
 | 
						|
        foreach ($addable as $f) {
 | 
						|
            if (array_key_exists($f, $fields)) {
 | 
						|
                $info[$f] = $fields[$f];
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $id = $DB->insert_record(self::TABLE, $info);
 | 
						|
        $item = self::findById($id);
 | 
						|
        if ($item->type() == self::COURSE) {
 | 
						|
            // Signal the studyplan that a course has been added so it can be marked for csync cascading.
 | 
						|
            $item->studyline()->studyplan()->mark_csync_changed();
 | 
						|
        }
 | 
						|
        return $item;
 | 
						|
    }
 | 
						|
 | 
						|
    public function edit($fields) {
 | 
						|
        global $DB;
 | 
						|
        $editable = ['conditions', 'course_id', 'continuation_id', 'span'];
 | 
						|
 | 
						|
        $info = ['id' => $this->id, ];
 | 
						|
        foreach ($editable as $f) {
 | 
						|
            if (array_key_exists($f, $fields) && isset($fields[$f])) {
 | 
						|
                $info[$f] = $fields[$f];
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $DB->update_record(self::TABLE, $info);
 | 
						|
        // Reload record after edit.
 | 
						|
        $this->r = $DB->get_record(self::TABLE, ['id' => $this->id], "*", MUST_EXIST);
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    public function isValid() {
 | 
						|
        // Check if referenced courses, badges and/or competencies still exist.
 | 
						|
        if ($this->r->type == static::COURSE) {
 | 
						|
            return courseinfo::exists($this->r->course_id);
 | 
						|
        } else if ($this->r->type == static::BADGE) {
 | 
						|
            return badgeinfo::exists($this->r->badge_id);
 | 
						|
        } else {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function delete($force=false) {
 | 
						|
        global $DB;
 | 
						|
 | 
						|
        // Check if this item is referenced in a START item.
 | 
						|
        if ($force) {
 | 
						|
            // Clear continuation id from any references to this item.
 | 
						|
            $records = $DB->get_records(self::TABLE, ['continuation_id' => $this->id]);
 | 
						|
            foreach ($records as $r) {
 | 
						|
                $r->continuation_id = 0;
 | 
						|
                $DB->update_record(self::TABLE, $r);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($DB->count_records(self::TABLE, ['continuation_id' => $this->id]) > 0) {
 | 
						|
            return success::fail('Cannot remove: item is referenced by another item');
 | 
						|
        } else {
 | 
						|
            // Delete al related connections to this item.
 | 
						|
            studyitemconnection::clear($this->id);
 | 
						|
            // Delete all grade inclusion references to this item.
 | 
						|
            $DB->delete_records("local_treestudyplan_gradeinc", ['studyitem_id' => $this->id]);
 | 
						|
            // Delete the item itself.
 | 
						|
            $DB->delete_records(self::TABLE, ['id' => $this->id]);
 | 
						|
 | 
						|
            return success::success();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /************************
 | 
						|
     *                      *
 | 
						|
     * reorder_studyitems   *
 | 
						|
     *                      *
 | 
						|
     ************************/
 | 
						|
 | 
						|
    public static function reorder($resequence) {
 | 
						|
        global $DB;
 | 
						|
 | 
						|
        foreach ($resequence as $sq) {
 | 
						|
            $DB->update_record(self::TABLE, [
 | 
						|
                'id' => $sq['id'],
 | 
						|
                'line_id' => $sq['line_id'],
 | 
						|
                'slot' => $sq['slot'],
 | 
						|
                'layer' => $sq['layer'],
 | 
						|
            ]);
 | 
						|
        }
 | 
						|
 | 
						|
        return success::success();
 | 
						|
    }
 | 
						|
 | 
						|
    public static function find_studyline_children(studyline $line) {
 | 
						|
        global $DB;
 | 
						|
        $list = [];
 | 
						|
        $ids = $DB->get_fieldset_select(self::TABLE, "id", "line_id = :line_id ORDER BY layer", ['line_id' => $line->id()]);
 | 
						|
        foreach ($ids as $id) {
 | 
						|
            $item = self::findById($id, $line);
 | 
						|
            $list[] = $item;
 | 
						|
        }
 | 
						|
        return $list;
 | 
						|
    }
 | 
						|
 | 
						|
    private static function link_structure($value=VALUE_REQUIRED) {
 | 
						|
        return new \external_single_structure([
 | 
						|
            "id" => new \external_value(PARAM_INT, 'id of study item'),
 | 
						|
            "type" => new \external_value(PARAM_TEXT, 'type of study item'),
 | 
						|
            "completion" => completion::structure(),
 | 
						|
            "studyline" => new \external_value(PARAM_TEXT, 'reference label of studyline'),
 | 
						|
            "studyplan" => new \external_value(PARAM_TEXT, 'reference label of studyplan'),
 | 
						|
        ], 'basic info of referenced studyitem', $value);
 | 
						|
    }
 | 
						|
 | 
						|
    private function link_model($userid) {
 | 
						|
        global $DB;
 | 
						|
        $line = $DB->get_record(studyline::TABLE, ['id' => $this->r->line_id]);
 | 
						|
        $plan = $DB->get_record(studyplan::TABLE, ['id' => $line->studyplan_id]);
 | 
						|
 | 
						|
        return  [
 | 
						|
            "id" => $this->r->id,
 | 
						|
            "type" => $this->r->type,
 | 
						|
            "completion" => $this->completion($userid),
 | 
						|
            "studyline" => $line->name(),
 | 
						|
            "studyplan" => $plan->name(),
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    public static function user_structure($value=VALUE_REQUIRED) {
 | 
						|
        return new \external_single_structure([
 | 
						|
            "id"            => new \external_value(PARAM_INT, 'id of study item'),
 | 
						|
            "type"          => new \external_value(PARAM_TEXT, 'type of study item'),
 | 
						|
            "completion"    => new \external_value(PARAM_TEXT, 'completion state (incomplete|progress|completed|excellent)'),
 | 
						|
            "slot"          => new \external_value(PARAM_INT, 'slot in the study plan'),
 | 
						|
            "layer"         => new \external_value(PARAM_INT, 'layer in the slot'),
 | 
						|
            "span"         => new \external_value(PARAM_INT, 'how many periods the item spans'),
 | 
						|
            "course"        => courseinfo::user_structure(VALUE_OPTIONAL),
 | 
						|
            "badge"         => badgeinfo::user_structure(VALUE_OPTIONAL),
 | 
						|
            "continuation"  => self::link_structure(VALUE_OPTIONAL),
 | 
						|
            "connections" => new \external_single_structure([
 | 
						|
                'in' => new \external_multiple_structure(studyitemconnection::structure()),
 | 
						|
                'out' => new \external_multiple_structure(studyitemconnection::structure()),
 | 
						|
            ]),
 | 
						|
        ], 'Study item info', $value);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public function user_model($userid) {
 | 
						|
        global $CFG, $DB;
 | 
						|
 | 
						|
        $model = [
 | 
						|
            'id' => $this->r->id,
 | 
						|
            'type' => $this->r->type,
 | 
						|
            'completion' => completion::label($this->completion($userid)),
 | 
						|
            'slot' => $this->r->slot,
 | 
						|
            'layer' => $this->r->layer,
 | 
						|
            'span' => $this->r->span,
 | 
						|
            'connections' => [
 | 
						|
                "in" => [],
 | 
						|
                "out" => [],
 | 
						|
            ]
 | 
						|
        ];
 | 
						|
 | 
						|
        // Add badge info if available.
 | 
						|
        if (badgeinfo::exists($this->r->badge_id)) {
 | 
						|
            $badge = new \core_badges\badge($this->r->badge_id);
 | 
						|
            $badgeinfo = new badgeinfo($badge);
 | 
						|
            $model['badge'] = $badgeinfo->user_model($userid);
 | 
						|
        }
 | 
						|
 | 
						|
        // Add continuation_info if available.
 | 
						|
        if (self::exists($this->r->continuation_id)) {
 | 
						|
            $citem = self::findById($this->r->continuation_id);
 | 
						|
            $model['continuation'] = $citem->link_model($userid);
 | 
						|
        }
 | 
						|
 | 
						|
        // Add course if available.
 | 
						|
        if (courseinfo::exists($this->r->course_id)) {
 | 
						|
            $cinfo = $this->getcourseinfo();
 | 
						|
            $model['course'] = $cinfo->user_model($userid, $this->aggregator->usecorecompletioninfo());
 | 
						|
        }
 | 
						|
 | 
						|
        // Add incoming and outgoing connection info.
 | 
						|
        $connout = studyitemconnection::find_outgoing($this->id);
 | 
						|
        foreach ($connout as $c) {
 | 
						|
            $model['connections']['out'][$c->to_id()] = $c->model();
 | 
						|
        }
 | 
						|
        $connin = studyitemconnection::find_incoming($this->id);
 | 
						|
        foreach ($connin as $c) {
 | 
						|
            $model['connections']['in'][$c->from_id()] = $c->model();
 | 
						|
        }
 | 
						|
 | 
						|
        return $model;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public function getcourseinfo() {
 | 
						|
        if (empty($this->courseinfo) && courseinfo::exists($this->r->course_id)) {
 | 
						|
            $this->courseinfo = new courseinfo($this->r->course_id, $this);
 | 
						|
        }
 | 
						|
        return $this->courseinfo;
 | 
						|
    }
 | 
						|
 | 
						|
    private function completion($userid) {
 | 
						|
        global $DB;
 | 
						|
 | 
						|
        if ($this->isValid()) {
 | 
						|
            if (strtolower($this->r->type) == 'course') {
 | 
						|
                // Determine competency by competency completion.
 | 
						|
                $courseinfo = $this->getcourseinfo();
 | 
						|
                return $this->aggregator->aggregate_course($courseinfo, $this, $userid);
 | 
						|
            } else if (strtolower($this->r->type) =='start') {
 | 
						|
                // Does not need to use aggregator.
 | 
						|
                // Either true, or the completion of the reference.
 | 
						|
                if (self::exists($this->r->continuation_id)) {
 | 
						|
                    $citem = self::findById($this->r->continuation_id);
 | 
						|
                    return $citem->completion($userid);
 | 
						|
                } else {
 | 
						|
                    return completion::COMPLETED;
 | 
						|
                }
 | 
						|
            } else if (in_array(strtolower($this->r->type), ['junction', 'finish'])) {
 | 
						|
                // Completion of the linked items, according to the rule.
 | 
						|
                $incompleted = [];
 | 
						|
                // Retrieve incoming connections.
 | 
						|
                $incoming = $DB->get_records(studyitemconnection::TABLE, ['to_id' => $this->r->id]);
 | 
						|
                foreach ($incoming as $conn) {
 | 
						|
                    $item = self::findById($conn->from_id);
 | 
						|
                    $incompleted[] = $item->completion($userid);
 | 
						|
                }
 | 
						|
                return $this->aggregator->aggregate_junction($incompleted, $this, $userid);
 | 
						|
            } else if (strtolower($this->r->type) =='badge') {
 | 
						|
                global $DB;
 | 
						|
                // Badge awarded.
 | 
						|
                if (badgeinfo::exists($this->r->badge_id)) {
 | 
						|
                    $badge = new \core_badges\badge($this->r->badge_id);
 | 
						|
                    if ($badge->is_issued($userid)) {
 | 
						|
                        if ($badge->can_expire()) {
 | 
						|
                            // Get the issued badges and check if any of them have not expired yet.
 | 
						|
                            $badgesissued = $DB->get_records("badge_issued",
 | 
						|
                                                             ["badge_id" => $this->r->badge_id,
 | 
						|
                                                              "user_id" => $userid]);
 | 
						|
                            $notexpired = false;
 | 
						|
                            $now = time();
 | 
						|
                            foreach ($badgesissued as $bi) {
 | 
						|
                                if ($bi->dateexpire == null || $bi->dateexpire > $now) {
 | 
						|
                                    $notexpired = true;
 | 
						|
                                    break;
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                            return ($notexpired) ? completion::COMPLETED : completion::INCOMPLETE;
 | 
						|
                        } else {
 | 
						|
                            return completion::COMPLETED;
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        return completion::INCOMPLETE;
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    return completion::INCOMPLETE;
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                // Return incomplete for other types.
 | 
						|
                return completion::INCOMPLETE;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            // Return incomplete for other types.
 | 
						|
            return completion::INCOMPLETE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function duplicate($newline) {
 | 
						|
        global $DB;
 | 
						|
        // Clone the database fields.
 | 
						|
        $fields = clone $this->r;
 | 
						|
        // Set new line id.
 | 
						|
        unset($fields->id);
 | 
						|
        $fields->line_id = $newline->id();
 | 
						|
        // Create new record with the new data.
 | 
						|
        $id = $DB->insert_record(self::TABLE, (array)$fields);
 | 
						|
        $new = self::findById($id, $newline);
 | 
						|
 | 
						|
        // Copy the grading info if relevant.
 | 
						|
        $gradables = gradeinfo::list_studyitem_gradables($this);
 | 
						|
        foreach ($gradables as $g) {
 | 
						|
            gradeinfo::include_grade($g->getGradeitem()->id, $new->id(), true);
 | 
						|
        }
 | 
						|
        return $new;
 | 
						|
    }
 | 
						|
 | 
						|
    public function export_model() {
 | 
						|
        return $this->generate_model("export");
 | 
						|
    }
 | 
						|
 | 
						|
    public static function import_item($model) {
 | 
						|
        unset($model["course_id"]);
 | 
						|
        unset($model["competency_id"]);
 | 
						|
        unset($model["badge_id"]);
 | 
						|
        unset($model["continuation_id"]);
 | 
						|
        if (isset($model["course"])) {
 | 
						|
            $model["course_id"] = courseinfo::id_from_shortname(($model["course"]));
 | 
						|
        }
 | 
						|
        if (isset($model["badge"])) {
 | 
						|
            $model["badge_id"] = badgeinfo::id_from_name(($model["badge"]));
 | 
						|
        }
 | 
						|
 | 
						|
        $item = self::add($model, true);
 | 
						|
 | 
						|
        if (isset($model["course_id"])) {
 | 
						|
            // Attempt to import the gradables.
 | 
						|
            foreach ($model["gradables"] as $gradable) {
 | 
						|
                gradeinfo::import($item, $gradable);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $item;
 | 
						|
    }
 | 
						|
 | 
						|
}
 |