Merge branch 'MDL-73245-master' of https://github.com/cameron1729/moodle
[moodle.git] / competency / classes / evidence.php
blobb6725680dac6ef8e58053d5f4e0344b6cc7d867c
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.
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/>.
17 /**
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();
28 use coding_exception;
29 use context;
30 use context_user;
31 use lang_string;
32 use moodle_exception;
33 use stdClass;
35 /**
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. */
47 const ACTION_LOG = 0;
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;
53 /**
54 * Return the definition of the properties of this model.
56 * @return array
58 protected static function define_properties() {
59 return array(
60 'usercompetencyid' => array(
61 'type' => PARAM_INT
63 'contextid' => array(
64 'type' => PARAM_INT
66 'action' => array(
67 'type' => PARAM_INT,
68 'choices' => array(self::ACTION_LOG, self::ACTION_COMPLETE, self::ACTION_OVERRIDE)
70 'actionuserid' => array(
71 'type' => PARAM_INT,
72 'default' => null,
73 'null' => NULL_ALLOWED
75 'descidentifier' => array(
76 'type' => PARAM_STRINGID
78 'desccomponent' => array(
79 'type' => PARAM_COMPONENT
81 'desca' => array(
82 'type' => PARAM_RAW,
83 'default' => null,
84 'null' => NULL_ALLOWED
86 'url' => array(
87 'type' => PARAM_URL,
88 'default' => null,
89 'null' => NULL_ALLOWED
91 'grade' => array(
92 'type' => PARAM_INT,
93 'default' => null,
94 'null' => NULL_ALLOWED
96 'note' => array(
97 'type' => PARAM_NOTAGS,
98 'default' => null,
99 'null' => NULL_ALLOWED
105 * Return the competency linked to this.
107 * @return competency
109 public function get_competency() {
110 return user_competency::get_competency_by_usercompetencyid($this->get('usercompetencyid'));
114 * Return the evidence's context.
116 * @return context
118 public function get_context() {
119 return context::instance_by_id($this->get('contextid'));
123 * Convenience method to get the description $a.
125 * @return mixed
127 protected function get_desca() {
128 $value = $this->raw_get('desca');
129 if ($value !== null) {
130 $value = json_decode($value);
132 return $value;
136 * Convenience method to get the description.
138 * @return lang_string
140 public function get_description() {
141 return new lang_string($this->get('descidentifier'), $this->get('desccomponent'), $this->get_desca());
145 * Convenience method to set the description $a.
147 * @param mixed $value
148 * @return mixed
150 protected function set_desca($value) {
151 if ($value !== null) {
152 if (!is_scalar($value) && !is_array($value) && !($value instanceof stdClass)) {
153 throw new coding_exception('$a format not supported.');
155 $value = json_encode($value);
157 $this->raw_set('desca', $value);
161 * Convenience method handling moodle_urls.
163 * @param null|string|moodle_url $url The URL.
165 protected function set_url($url) {
166 if ($url instanceof \moodle_url) {
167 $url = $url->out(false);
169 $this->raw_set('url', $url);
173 * Validate the action user ID.
175 * @param int $value A user ID.
176 * @return true|lang_string
178 protected function validate_actionuserid($value) {
179 if ($value !== null && !\core_user::is_real_user($value)) {
180 return new lang_string('invaliddata', 'error');
182 return true;
186 * Validate the context ID.
188 * @param int $value
189 * @return true|lang_string
191 protected function validate_contextid($value) {
192 try {
193 context::instance_by_id($value);
194 } catch (moodle_exception $e) {
195 // That does not look good...
196 return new lang_string('invaliddata', 'error');
198 return true;
202 * Validate the description $a.
204 * @param string $value
205 * @return true|lang_string
207 protected function validate_desca($value) {
208 if ($value === null) {
209 return true;
212 $desc = json_decode($value);
213 if ($desc === null && json_last_error() !== JSON_ERROR_NONE) {
214 return new lang_string('invaliddata', 'error');
217 return true;
221 * Validate the description identifier.
223 * Only validate string existence during create. If the string is removed later on we should
224 * not prevent this model from being updated. Alternatively we could check if the string has
225 * changed before performing the check but this overhead is not required for now.
226 * An evidence should usually never be updated anyway.
228 * @param string $value
229 * @return true|lang_string
231 protected function validate_descidentifier($value) {
232 if (!$this->get('id') && !get_string_manager()->string_exists($value, $this->get('desccomponent'))) {
233 return new lang_string('invalidevidencedesc', 'core_competency');
236 return true;
240 * Validate the grade.
242 * For performance reason we do not validate that the grade is a valid item of the
243 * scale associated with the competency or framework.
245 * @param int $value The value.
246 * @return true|lang_string
248 protected function validate_grade($value) {
249 if ($value !== null && $value <= 0) {
250 return new lang_string('invalidgrade', 'core_competency');
253 $action = $this->get('action');
254 if ($value === null && $action == self::ACTION_COMPLETE) {
255 return new lang_string('invalidgrade', 'core_competency');
257 } else if ($value !== null && $action == self::ACTION_LOG) {
258 return new lang_string('invalidgrade', 'core_competency');
261 if ($value !== null) {
262 // TODO MDL-52243 Use a core method to validate the grade_scale item.
263 // Check if grade exist in the scale item values.
264 $competency = $this->get_competency();
265 if (!array_key_exists($value - 1, $competency->get_scale()->scale_items)) {
266 return new lang_string('invalidgrade', 'core_competency');
270 return true;
274 * Validate the user competency.
276 * @param int $value
277 * @return true|lang_string
279 protected function validate_usercompetencyid($value) {
280 if (!user_competency::record_exists($value)) {
281 return new lang_string('invaliddata', 'error');
283 return true;
287 * Whether the current user can delete an evidence in the context of a user.
289 * @param int $userid The user ID the evidence belongs to.
290 * @return bool
292 public static function can_delete_user($userid) {
293 return has_capability('moodle/competency:evidencedelete', context_user::instance($userid));
297 * Load a list of records in a context for a user competency.
299 * @param int $usercompetencyid The id of the user competency.
300 * @param context $context Context to filter the evidence list.
301 * @param string $sort The field from the evidence table to sort on.
302 * @param string $order The sort direction
303 * @param int $skip Limitstart.
304 * @param int $limit Number of rows to return.
306 * @return \core_competency\persistent[]
308 public static function get_records_for_usercompetency($usercompetencyid,
309 \context $context,
310 $sort = '',
311 $order = 'ASC',
312 $skip = 0,
313 $limit = 0) {
314 global $DB;
316 $params = array(
317 'usercompid' => $usercompetencyid,
318 'path' => $context->path . '/%',
319 'contextid' => $context->id
322 if (!empty($sort)) {
323 $sort = ' ORDER BY e.' . $sort . ' ' . $order . ', e.id ASC';
324 } else {
325 $sort = ' ORDER BY e.id ASC';
328 $sql = 'SELECT e.*
329 FROM {' . static::TABLE . '} e
330 JOIN {context} c ON c.id = e.contextid
331 WHERE (c.path LIKE :path OR c.id = :contextid)
332 AND e.usercompetencyid = :usercompid
333 ' . $sort;
334 $records = $DB->get_records_sql($sql, $params, $skip, $limit);
335 $instances = array();
337 foreach ($records as $record) {
338 $newrecord = new static(0, $record);
339 array_push($instances, $newrecord);
341 return $instances;