2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Evidence persistent file.
20 * @package core_competency
21 * @copyright 2015 Frédéric Massart - FMCorz.net
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 namespace core_competency;
26 defined('MOODLE_INTERNAL') || die();
36 * Evidence persistent class.
38 * @package core_competency
39 * @copyright 2015 Frédéric Massart - FMCorz.net
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 class evidence extends persistent {
44 const TABLE = 'competency_evidence';
46 /** Action logging. */
48 /** Action rating a competency when no rating is set. */
49 const ACTION_COMPLETE = 2;
50 /** Action rating a competency. */
51 const ACTION_OVERRIDE = 3;
54 * Return the definition of the properties of this model.
58 protected static function define_properties() {
60 'usercompetencyid' => array(
68 'choices' => array(self::ACTION_LOG, self::ACTION_COMPLETE, self::ACTION_OVERRIDE)
70 'actionuserid' => array(
73 'null' => NULL_ALLOWED
75 'descidentifier' => array(
76 'type' => PARAM_STRINGID
78 'desccomponent' => array(
79 'type' => PARAM_COMPONENT
84 'null' => NULL_ALLOWED
89 'null' => NULL_ALLOWED
94 'null' => NULL_ALLOWED
97 'type' => PARAM_NOTAGS,
99 'null' => NULL_ALLOWED
105 * Return the competency linked to this.
109 public function get_competency() {
110 return user_competency::get_competency_by_usercompetencyid($this->get_usercompetencyid());
114 * Convenience method to get the description $a.
118 public function get_desca() {
119 $value = $this->get('desca');
120 if ($value !== null) {
121 $value = json_decode($value);
127 * Convenience method to get the description.
129 * @return lang_string
131 public function get_description() {
132 return new lang_string($this->get('descidentifier'), $this->get('desccomponent'), $this->get_desca());
136 * Convenience method to set the description $a.
138 * @param mixed $value
141 public function set_desca($value) {
142 if ($value !== null) {
143 if (!is_scalar($value) && !is_array($value) && !($value instanceof stdClass)) {
144 throw new coding_exception('$a format not supported.');
146 $value = json_encode($value);
148 $this->set('desca', $value);
152 * Convenience method handling moodle_urls.
154 * @param null|string|moodle_url $url The URL.
156 public function set_url($url) {
157 if ($url instanceof \moodle_url) {
158 $url = $url->out(false);
160 $this->set('url', $url);
164 * Validate the action user ID.
166 * @param int $value A user ID.
167 * @return true|lang_string
169 protected function validate_actionuserid($value) {
170 if ($value !== null && !\core_user::is_real_user($value)) {
171 return new lang_string('invaliddata', 'error');
177 * Validate the context ID.
180 * @return true|lang_string
182 protected function validate_contextid($value) {
184 context::instance_by_id($value);
185 } catch (moodle_exception $e) {
186 // That does not look good...
187 return new lang_string('invaliddata', 'error');
193 * Validate the description $a.
195 * @param string $value
196 * @return true|lang_string
198 protected function validate_desca($value) {
199 if ($value === null) {
203 $desc = json_decode($value);
204 if ($desc === null && json_last_error() !== JSON_ERROR_NONE) {
205 return new lang_string('invaliddata', 'error');
212 * Validate the description identifier.
214 * Only validate string existence during create. If the string is removed later on we should
215 * not prevent this model from being updated. Alternatively we could check if the string has
216 * changed before performing the check but this overhead is not required for now.
217 * An evidence should usually never be updated anyway.
219 * @param string $value
220 * @return true|lang_string
222 protected function validate_descidentifier($value) {
223 if (!$this->get_id() && !get_string_manager()->string_exists($value, $this->get('desccomponent'))) {
224 return new lang_string('invalidevidencedesc', 'core_competency');
231 * Validate the grade.
233 * For performance reason we do not validate that the grade is a valid item of the
234 * scale associated with the competency or framework.
236 * @param int $value The value.
237 * @return true|lang_string
239 protected function validate_grade($value) {
240 if ($value !== null && $value <= 0) {
241 return new lang_string('invalidgrade', 'core_competency');
244 $action = $this->get('action');
245 if ($value === null && $action == self::ACTION_COMPLETE) {
246 return new lang_string('invalidgrade', 'core_competency');
248 } else if ($value !== null && $action == self::ACTION_LOG) {
249 return new lang_string('invalidgrade', 'core_competency');
252 if ($value !== null) {
253 // TODO MDL-52243 Use a core method to validate the grade_scale item.
254 // Check if grade exist in the scale item values.
255 $competency = $this->get_competency();
256 if (!array_key_exists($value - 1, $competency->get_scale()->scale_items)) {
257 return new lang_string('invalidgrade', 'core_competency');
265 * Validate the user competency.
268 * @return true|lang_string
270 protected function validate_usercompetencyid($value) {
271 if (!user_competency::record_exists($value)) {
272 return new lang_string('invaliddata', 'error');
278 * Whether the current user can delete an evidence in the context of a user.
280 * @param int $userid The user ID the evidence belongs to.
283 public static function can_delete_user($userid) {
284 return has_capability('moodle/competency:evidencedelete', context_user::instance($userid));
288 * Load a list of records in a context for a user competency.
290 * @param int $usercompetencyid The id of the user competency.
291 * @param context $context Context to filter the evidence list.
292 * @param string $sort The field from the evidence table to sort on.
293 * @param string $order The sort direction
294 * @param int $skip Limitstart.
295 * @param int $limit Number of rows to return.
297 * @return \core_competency\persistent[]
299 public static function get_records_for_usercompetency($usercompetencyid,
308 'usercompid' => $usercompetencyid,
309 'path' => $context->path . '/%',
310 'contextid' => $context->id
314 $sortcolumns = explode(',', $sort);
315 array_walk($sortcolumns, function(&$sortcolumn, $key, $order) {
316 $sortcolumn = trim($sortcolumn) . ' ' . $order;
318 $sort = ' ORDER BY e.' . implode(', e.', $sortcolumns);
322 FROM {' . static::TABLE . '} e
323 JOIN {context} c ON c.id = e.contextid
324 WHERE (c.path LIKE :path OR c.id = :contextid)
325 AND e.usercompetencyid = :usercompid
327 $records = $DB->get_records_sql($sql, $params, $skip, $limit);
328 $instances = array();
330 foreach ($records as $record) {
331 $newrecord = new static(0, $record);
332 array_push($instances, $newrecord);