AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// 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 <http://www.gnu.org/licenses/>.namespace tool_courserating;use core\output\inplace_editable;use tool_courserating\event\flag_created;use tool_courserating\event\flag_deleted;use tool_courserating\event\rating_created;use tool_courserating\event\rating_deleted;use tool_courserating\event\rating_updated;use tool_courserating\external\summary_exporter;use tool_courserating\local\models\flag;use tool_courserating\local\models\rating;use tool_courserating\local\models\summary;/*** Methods to add/remove ratings** @package tool_courserating* @copyright 2022 Marina Glancy <marina.glancy@gmail.com>* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class api {/*** Add or update user rating** @param int $courseid* @param \stdClass $data* @param int $userid - only for phpunit and behat tests* @return rating*/public static function set_rating(int $courseid, \stdClass $data, int $userid = 0): rating {global $USER;// TODO $userid can only be used in phpunit and behat.$userid = $userid ?: $USER->id;// TODO validate rating is within limits, trim/crop review.$rating = $data->rating;$ratingold = rating::get_record(['userid' => $userid, 'courseid' => $courseid]);if ($ratingold) {$oldrecord = $ratingold->to_record();$r = $ratingold;$review = self::prepare_review($r, $data);$r->set('rating', $rating);$r->set('review', $review);$r->save();$summary = summary::update_rating($courseid, $r, $oldrecord);} else {$r = new rating(0, (object)['userid' => $userid,'courseid' => $courseid,'rating' => $rating,]);$r->set('review', self::prepare_review(null, $data));$r->save();$review = self::prepare_review($r, $data);if ($review !== $r->get('review')) {$r->set('review', $review);$r->save();}$summary = summary::add_rating($courseid, $r);}self::update_course_rating_in_custom_field($summary);if ($ratingold) {rating_updated::create_from_rating($r, $oldrecord)->trigger();} else {rating_created::create_from_rating($r)->trigger();}return $r;}/*** Delete rating and review made by somebody else** @param int $ratingid* @param string|null $reason* @return rating|null*/public static function delete_rating(int $ratingid, string $reason = ''): ?rating {global $DB;if (!$rating = rating::get_record(['id' => $ratingid])) {return null;}$flagcount = $DB->count_records(flag::TABLE, ['ratingid' => $ratingid]);$record = $rating->to_record();$rating->delete();if ($context = \context_course::instance($record->courseid, IGNORE_MISSING)) {// Sometimes it might be called after course is deleted.get_file_storage()->delete_area_files($context->id, 'tool_courserating', 'review', $record->id);}if ($flagcount) {$DB->delete_records(flag::TABLE, ['ratingid' => $record->id]);}$summary = summary::delete_rating($record);self::update_course_rating_in_custom_field($summary);rating_deleted::create_from_rating($record, $flagcount, $reason)->trigger();return $rating;}/*** Update content of the course custom field that displays the rating** @param summary|null $summary* @return void*/protected static function update_course_rating_in_custom_field(?summary $summary) {global $PAGE;if (!$summary || !helper::get_course_rating_field()) {return;}$courseid = $summary->get('courseid');if ($summary->get('ratingmode') == constants::RATEBY_NOONE) {$ratingstr = '';} else {/** @var \tool_courserating\output\renderer $output */$output = $PAGE->get_renderer('tool_courserating');$data = (new summary_exporter(0, $summary))->export($output);$ratingstr = $output->render_from_template('tool_courserating/summary_for_cfield', $data);}if ($data = helper::get_course_rating_data_in_cfield($courseid)) {$data->instance_form_save((object)['id' => $courseid,$data->get_form_element_name() => ['text' => $ratingstr, 'format' => FORMAT_HTML],]);}}/*** Prepare review for storing (store files, convert to html)** @param rating|null $rating* @param \stdClass $data* @return string*/protected static function prepare_review(?rating $rating, \stdClass $data): string {$usehtml = helper::get_setting(constants::SETTING_USEHTML);if ($rating && $usehtml && !rating::review_is_empty($data->review_editor['text'] ?? '')) {$context = \context_course::instance($rating->get('courseid'));$data = file_postupdate_standard_editor($data, 'review', helper::review_editor_options($context), $context,'tool_courserating', 'review', $rating->get('id'));if ($data->reviewformat != FORMAT_HTML) {// We always store reviews as HTML, we don't even store the reviewformat field.// Do not apply filters now, they will be applied during display.return format_text($data->review, $data->reviewformat, ['filter' => false, 'context' => $context]);}return $data->review;} else if (!$usehtml && !rating::review_is_empty($data->review ?? '')) {return $data->review;} else {return '';}}/*** Prepare review to be displayed in a form (copy files to draft area)** @param int $courseid* @return array|array[]*/public static function prepare_rating_for_form(int $courseid): array {global $USER;$rv = ['review_editor' => ['text' => '', 'format' => FORMAT_HTML],'review' => '',];if ($rating = rating::get_record(['userid' => $USER->id, 'courseid' => $courseid])) {$data = $rating->to_record();$rv['rating'] = $data->rating;if (helper::get_setting(constants::SETTING_USEHTML)) {$data->reviewformat = FORMAT_HTML;$context = \context_course::instance($courseid);$data = file_prepare_standard_editor($data, 'review', helper::review_editor_options($context), $context,'tool_courserating', 'review', $data->id);$rv['review_editor'] = $data->review_editor;} else {$rv['review'] = clean_param($data->review, PARAM_TEXT);}return $rv;}return $rv;}/*** Flag somebody else's review** @param int $ratingid* @return flag|null*/public static function flag_review(int $ratingid): ?flag {global $USER;$flag = flag::get_records(['ratingid' => $ratingid, 'userid' => $USER->id]);if ($flag) {return null;}$rating = new rating($ratingid);$flag = new flag(0, (object)['userid' => $USER->id, 'ratingid' => $ratingid]);$flag->save();flag_created::create_from_flag($flag, $rating)->trigger();return $flag;}/*** Revoke a flag on somebody else's review** @param int $ratingid* @return flag|null*/public static function revoke_review_flag(int $ratingid): ?flag {global $USER;$flags = flag::get_records(['ratingid' => $ratingid, 'userid' => $USER->id]);$flag = reset($flags);if (!$flag) {return null;}$rating = new rating($ratingid);$oldrecord = $flag->to_record();$flag->delete();flag_deleted::create_from_flag($oldrecord, $rating)->trigger();return $flag;}/*** Get the flag** @param int $ratingid* @param bool|null $hasflag* @return inplace_editable*/public static function get_flag_inplace_editable(int $ratingid, ?bool $hasflag = null): inplace_editable {global $USER;if (!permission::can_flag_rating($ratingid)) {return new inplace_editable('tool_courserating', 'flag', $ratingid, false, '', 0, '');}if ($hasflag === null) {$hasflag = flag::count_records(['ratingid' => $ratingid, 'userid' => $USER->id]) > 0;}$displayvalue = $hasflag ? get_string('revokeratingflag', 'tool_courserating') :get_string('flagrating', 'tool_courserating');$edithint = $displayvalue;$r = new inplace_editable('tool_courserating', 'flag', $ratingid, true, $displayvalue,$hasflag ? 1 : 0, $edithint);$r->set_type_toggle([0, 1]);return $r;}/*** Re-index all courses, update ratings in the summary table and custom fields** @param int $courseid* @return void*/public static function reindex(int $courseid = 0) {global $DB, $SITE;$percourse = helper::get_setting(constants::SETTING_PERCOURSE);$ratingfield = helper::get_course_rating_field();$ratingmodefield = helper::get_course_rating_mode_field();if (!$ratingfield) {return;}$fields = 'c.id as courseid, d.value as cfield, s.cntall as summarycntall, s.ratingmode as summaryratingmode,(select count(1) from {tool_courserating_rating} r where r.courseid=c.id) as actualcntall ';$join = 'from {course} cleft join {tool_courserating_summary} s on s.courseid = c.idleft join {customfield_field} f on f.shortname = :field1left join {customfield_data} d on d.fieldid = f.id and d.instanceid = c.id ';$params = ['field1' => $ratingfield->get('shortname'),'siteid' => $SITE->id ?? SITEID,];if ($percourse && $ratingmodefield) {// Each course may override whether course ratings are enabled.$fields .= ', dr.intvalue as rateby';$join .= ' left join {customfield_field} fr on fr.shortname = :field2left join {customfield_data} dr on dr.fieldid = fr.id and dr.instanceid = c.id';$params['field2'] = $ratingmodefield->get('shortname');}$sql = "SELECT $fields $join WHERE c.id <> :siteid ";if ($courseid) {$sql .= " AND c.id = :courseid ";$params['courseid'] = $courseid;} else {$sql .= " ORDER BY c.id DESC";}$records = $DB->get_records_sql($sql, $params);foreach ($records as $record) {$record->actualratingmode = helper::get_setting(constants::SETTING_RATINGMODE);if ($percourse && $record->rateby && array_key_exists($record->rateby, constants::rated_courses_options())) {$record->actualratingmode = $record->rateby;}self::reindex_course($record);}}/*** Re-index individual course** @param \stdClass $data contains fields: courseid, cfield, summarycntall, actualcntall* where cfield is the actual value stored in the "course rating" custom course field,* summarycntall - the field tool_courserating_summary.cntall that corresponds to this course,* summaryratingmode - the field tool_courserating_summary.ratingmode that corresponds to this course,* actualcntall - the actual count of ratings for this course (count(*) from tool_courserating_rating)* actualratingmode - what actually must be the rating mode of this course*/protected static function reindex_course(\stdClass $data) {$mustbeempty = $data->actualratingmode == constants::RATEBY_NOONE|| (!$data->actualcntall && !helper::get_setting(constants::SETTING_DISPLAYEMPTY));if ($data->summaryratingmode != $data->actualratingmode) {// Rating mode for this course has changed.$summary = summary::get_for_course($data->courseid);$summary->set('ratingmode', $data->actualratingmode);if ($data->actualratingmode == constants::RATEBY_NOONE) {$summary->reset_all_counters();}$summary->save();}if ($mustbeempty) {// Course rating should not be displayed at all.if (!empty($data->cfield)) {$summary = $summary ?? summary::get_for_course($data->courseid);self::update_course_rating_in_custom_field($summary);}} else {// Update summary and cfield with the data.$summary = $summary ?? summary::get_for_course($data->courseid);$summary->recalculate();self::update_course_rating_in_custom_field($summary);}}/*** Completely delete all data related to a course (i.e. when course is deleted)** @param int $courseid* @return void*/public static function delete_all_data_for_course(int $courseid) {global $DB;$DB->execute('DELETE from {'.flag::TABLE.'} WHERE ratingid IN (SELECT id FROM {'.rating::TABLE.'} WHERE courseid = ?)', [$courseid]);$DB->delete_records(rating::TABLE, ['courseid' => $courseid]);$DB->delete_records(summary::TABLE, ['courseid' => $courseid]);}}