mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-44316 core_tag: changed the API to accept a contextid and component
This commit is contained in:
parent
8dfc4d9c58
commit
cc033d48b5
@ -1468,7 +1468,8 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
// Add the one being restored
|
||||
$tags[] = $data->rawname;
|
||||
// Send all the tags back to the course
|
||||
tag_set('course', $this->get_courseid(), $tags);
|
||||
tag_set('course', $this->get_courseid(), $tags, 'core',
|
||||
context_course::instance($this->get_courseid())->id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3279,6 +3280,9 @@ abstract class restore_activity_structure_step extends restore_structure_step {
|
||||
*/
|
||||
class restore_create_categories_and_questions extends restore_structure_step {
|
||||
|
||||
/** @var array $cachecategory store the categories */
|
||||
protected $cachedcategory = array();
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
$category = new restore_path_element('question_category', '/question_categories/question_category');
|
||||
@ -3384,7 +3388,7 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
// step will be in charge of restoring all the question files
|
||||
}
|
||||
|
||||
protected function process_question_hint($data) {
|
||||
protected function process_question_hint($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
@ -3448,7 +3452,7 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
$newquestion = $this->get_new_parentid('question');
|
||||
|
||||
if (!empty($CFG->usetags)) { // if enabled in server
|
||||
// TODO: This is highly inneficient. Each time we add one tag
|
||||
// TODO: This is highly inefficient. Each time we add one tag
|
||||
// we fetch all the existing because tag_set() deletes them
|
||||
// so everything must be reinserted on each call
|
||||
$tags = array();
|
||||
@ -3459,8 +3463,13 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
}
|
||||
// Add the one being restored
|
||||
$tags[] = $data->rawname;
|
||||
// Get the category, so we can then later get the context.
|
||||
$categoryid = $this->get_new_parentid('question_category');
|
||||
if (empty($this->cachedcategory) || $this->cachedcategory->id != $categoryid) {
|
||||
$this->cachedcategory = $DB->get_record('question_categories', array('id' => $categoryid));
|
||||
}
|
||||
// Send all the tags back to the question
|
||||
tag_set('question', $newquestion, $tags);
|
||||
tag_set('question', $newquestion, $tags, 'core_question', $this->cachedcategory->contextid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1215,7 +1215,7 @@ abstract class restore_dbops {
|
||||
$usertag = (object)$usertag;
|
||||
$tags[] = $usertag->rawname;
|
||||
}
|
||||
tag_set('user', $newuserid, $tags);
|
||||
tag_set('user', $newuserid, $tags, 'core', $newuserctxid);
|
||||
}
|
||||
|
||||
// Process preferences
|
||||
|
@ -84,7 +84,8 @@ if ($externalblogform->is_cancelled()){
|
||||
|
||||
$newexternal->id = $DB->insert_record('blog_external', $newexternal);
|
||||
blog_sync_external_entries($newexternal);
|
||||
tag_set('blog_external', $newexternal->id, explode(',', $data->autotags));
|
||||
tag_set('blog_external', $newexternal->id, explode(',', $data->autotags), 'core',
|
||||
context_user::instance($newexternal->userid)->id);
|
||||
|
||||
break;
|
||||
|
||||
@ -102,7 +103,8 @@ if ($externalblogform->is_cancelled()){
|
||||
$external->timemodified = time();
|
||||
|
||||
$DB->update_record('blog_external', $external);
|
||||
tag_set('blog_external', $external->id, explode(',', $data->autotags));
|
||||
tag_set('blog_external', $external->id, explode(',', $data->autotags), 'core',
|
||||
context_user::instance($newexternal->userid)->id);
|
||||
|
||||
} else {
|
||||
print_error('wrongexternalid', 'blog');
|
||||
|
@ -254,7 +254,7 @@ function blog_sync_external_entries($externalblog) {
|
||||
|
||||
// Set tags
|
||||
if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) {
|
||||
tag_set('post', $id, $tags);
|
||||
tag_set('post', $id, $tags, 'core', context_user::instance($externalblog->userid)->id);
|
||||
}
|
||||
} else {
|
||||
$newentry->id = $postid;
|
||||
|
@ -260,7 +260,7 @@ class blog_entry implements renderable {
|
||||
$this->add_associations();
|
||||
}
|
||||
|
||||
tag_set('post', $this->id, $this->tags);
|
||||
tag_set('post', $this->id, $this->tags, 'core', context_user::instance($this->userid)->id);
|
||||
|
||||
// Trigger an event for the new entry.
|
||||
$event = \core\event\blog_entry_created::create(array(
|
||||
@ -303,7 +303,7 @@ class blog_entry implements renderable {
|
||||
|
||||
// Update record.
|
||||
$DB->update_record('post', $entry);
|
||||
tag_set('post', $entry->id, $entry->tags);
|
||||
tag_set('post', $entry->id, $entry->tags, 'core', context_user::instance($this->userid)->id);
|
||||
|
||||
$event = \core\event\blog_entry_updated::create(array(
|
||||
'objectid' => $entry->id,
|
||||
@ -327,7 +327,7 @@ class blog_entry implements renderable {
|
||||
// Get record to pass onto the event.
|
||||
$record = $DB->get_record('post', array('id' => $this->id));
|
||||
$DB->delete_records('post', array('id' => $this->id));
|
||||
tag_set('post', $this->id, array());
|
||||
tag_set('post', $this->id, array(), 'core', context_user::instance($this->userid)->id);
|
||||
|
||||
$event = \core\event\blog_entry_deleted::create(array(
|
||||
'objectid' => $this->id,
|
||||
@ -434,7 +434,7 @@ class blog_entry implements renderable {
|
||||
}
|
||||
}
|
||||
|
||||
tag_set('post', $this->id, $tags);
|
||||
tag_set('post', $this->id, $tags, 'core', context_user::instance($this->userid)->id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1703,6 +1703,9 @@ function course_delete_module($cmid) {
|
||||
$DB->delete_records('course_completion_criteria', array('moduleinstance' => $cm->id,
|
||||
'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY));
|
||||
|
||||
// Delete the tag instances.
|
||||
$DB->delete_records('tag_instance', array('component' => 'mod_' . $modulename, 'contextid' => $modcontext->id));
|
||||
|
||||
// Delete the context.
|
||||
context_helper::delete_instance(CONTEXT_MODULE, $cm->id);
|
||||
|
||||
|
@ -29,6 +29,7 @@ global $CFG;
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
require_once($CFG->dirroot . '/course/tests/fixtures/course_capability_assignment.php');
|
||||
require_once($CFG->dirroot . '/enrol/imsenterprise/tests/imsenterprise_test.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
class core_course_courselib_testcase extends advanced_testcase {
|
||||
|
||||
@ -1366,28 +1367,40 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
// Generate an assignment with due date (will generate a course event).
|
||||
$assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id));
|
||||
|
||||
$cm = get_coursemodule_from_instance('assign', $assign->id);
|
||||
// Get the module context.
|
||||
$modcontext = context_module::instance($assign->cmid);
|
||||
|
||||
// Verify context exists.
|
||||
$this->assertInstanceOf('context_module', context_module::instance($cm->id, IGNORE_MISSING));
|
||||
$this->assertInstanceOf('context_module', $modcontext);
|
||||
|
||||
// Add some tags to this assignment.
|
||||
tag_set('assign', $assign->id, array('Tag 1', 'Tag 2', 'Tag 3'), 'mod_assign', $modcontext->id);
|
||||
|
||||
// Confirm the tag instances were added.
|
||||
$this->assertEquals(3, $DB->count_records('tag_instance', array('component' => 'mod_assign', 'contextid' =>
|
||||
$modcontext->id)));
|
||||
|
||||
// Verify event assignment event has been generated.
|
||||
$eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign'));
|
||||
$this->assertEquals(1, $eventcount);
|
||||
|
||||
// Run delete..
|
||||
course_delete_module($cm->id);
|
||||
course_delete_module($assign->cmid);
|
||||
|
||||
// Verify the context has been removed.
|
||||
$this->assertFalse(context_module::instance($cm->id, IGNORE_MISSING));
|
||||
$this->assertFalse(context_module::instance($assign->cmid, IGNORE_MISSING));
|
||||
|
||||
// Verify the course_module record has been deleted.
|
||||
$cmcount = $DB->count_records('course_modules', array('id' => $cm->id));
|
||||
$cmcount = $DB->count_records('course_modules', array('id' => $assign->cmid));
|
||||
$this->assertEmpty($cmcount);
|
||||
|
||||
// Verify event assignment events have been removed.
|
||||
$eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign'));
|
||||
$this->assertEmpty($eventcount);
|
||||
|
||||
// Verify the tag instances were deleted.
|
||||
$this->assertEquals(0, $DB->count_records('tag_instance', array('component' => 'mod_assign', 'contextid' =>
|
||||
$modcontext->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,6 +231,9 @@ function uninstall_plugin($type, $name) {
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_component_files($component);
|
||||
|
||||
// Delete all tag instances for this component.
|
||||
$DB->delete_records('tag_instance', array('component' => $component));
|
||||
|
||||
// Finally purge all caches.
|
||||
purge_all_caches();
|
||||
|
||||
|
@ -4214,7 +4214,7 @@ function delete_user(stdClass $user) {
|
||||
// TODO: remove from cohorts using standard API here.
|
||||
|
||||
// Remove user tags.
|
||||
tag_set('user', $user->id, array());
|
||||
tag_set('user', $user->id, array(), 'core', $usercontext->id);
|
||||
|
||||
// Unconditionally unenrol from all courses.
|
||||
enrol_user_delete($user);
|
||||
|
@ -331,6 +331,9 @@ function question_delete_question($questionid) {
|
||||
question_bank::get_qtype($question->qtype, false)->delete_question(
|
||||
$questionid, $question->contextid);
|
||||
|
||||
// Delete all tag instances.
|
||||
$DB->delete_records('tag_instance', array('component' => 'core_question', 'itemid' => $question->id));
|
||||
|
||||
// Now recursively delete all child questions
|
||||
if ($children = $DB->get_records('question',
|
||||
array('parent' => $questionid), '', 'id, qtype')) {
|
||||
@ -435,7 +438,7 @@ function question_delete_course_category($category, $newcategory, $feedback=true
|
||||
|
||||
// Check to see if there were any questions that were kept because
|
||||
// they are still in use somehow, even though quizzes in courses
|
||||
// in this category will already have been deteted. This could
|
||||
// in this category will already have been deleted. This could
|
||||
// happen, for example, if questions are added to a course,
|
||||
// and then that course is moved to another category (MDL-14802).
|
||||
$questionids = $DB->get_records_menu('question',
|
||||
@ -474,12 +477,17 @@ function question_delete_course_category($category, $newcategory, $feedback=true
|
||||
}
|
||||
|
||||
} else {
|
||||
// Move question categories ot the new context.
|
||||
// Move question categories to the new context.
|
||||
if (!$newcontext = context_coursecat::instance($newcategory->id)) {
|
||||
return false;
|
||||
}
|
||||
$DB->set_field('question_categories', 'contextid', $newcontext->id,
|
||||
array('contextid'=>$context->id));
|
||||
|
||||
// Update the contextid for any tag instances for questions in the old context.
|
||||
$DB->set_field('tag_instance', 'contextid', $newcontext->id, array('component' => 'core_question',
|
||||
'contextid' => $context->id));
|
||||
|
||||
$DB->set_field('question_categories', 'contextid', $newcontext->id, array('contextid' => $context->id));
|
||||
|
||||
if ($feedback) {
|
||||
$a = new stdClass();
|
||||
$a->oldplace = $context->get_context_name();
|
||||
@ -611,6 +619,10 @@ function question_move_questions_to_category($questionids, $newcategoryid) {
|
||||
$DB->set_field_select('question', 'category', $newcategoryid,
|
||||
"parent $questionidcondition", $params);
|
||||
|
||||
// Update the contextid for any tag instances that may exist for these questions.
|
||||
$DB->set_field_select('tag_instance', 'contextid', $newcontextid,
|
||||
"component = 'core_question' AND itemid $questionidcondition", $params);
|
||||
|
||||
// TODO Deal with datasets.
|
||||
|
||||
// Purge these questions from the cache.
|
||||
@ -641,6 +653,13 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
|
||||
question_bank::notify_question_edited($questionid);
|
||||
}
|
||||
|
||||
if ($questionids) {
|
||||
// Update the contextid for any tag instances that may exist for these questions.
|
||||
list($questionids, $params) = $DB->get_in_or_equal(array_keys($questionids));
|
||||
$DB->set_field_select('tag_instance', 'contextid', $newcontextid,
|
||||
"component = 'core_question' AND itemid $questionids", $params);
|
||||
}
|
||||
|
||||
$subcatids = $DB->get_records_menu('question_categories',
|
||||
array('parent' => $categoryid), '', 'id,1');
|
||||
foreach ($subcatids as $subcatid => $notused) {
|
||||
|
@ -26,8 +26,13 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
// Get the necessary files to perform backup and restore.
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
|
||||
/**
|
||||
* Unit tests for (some of) ../questionlib.php.
|
||||
@ -35,7 +40,16 @@ require_once($CFG->libdir . '/questionlib.php');
|
||||
* @copyright 2006 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_questionlib_testcase extends basic_testcase {
|
||||
class core_questionlib_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*
|
||||
* This is executed before running any test in this file.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
public function test_question_reorder_qtypes() {
|
||||
$this->assertEquals(
|
||||
@ -70,4 +84,118 @@ class core_questionlib_testcase extends basic_testcase {
|
||||
|
||||
$this->assertEquals(-0.1428571, match_grade_options($gradeoptions, -0.15, 'nearest'));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function tests that the functions responsible for moving questions to
|
||||
* different contexts also updates the tag instances associated with the questions.
|
||||
*/
|
||||
public function test_altering_tag_instance_context() {
|
||||
global $CFG, $DB;
|
||||
|
||||
// Set to admin user.
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create two course categories - we are going to delete one of these later and will expect
|
||||
// all the questions belonging to the course in the deleted category to be moved.
|
||||
$coursecat1 = $this->getDataGenerator()->create_category();
|
||||
$coursecat2 = $this->getDataGenerator()->create_category();
|
||||
|
||||
// Create a couple of categories and questions.
|
||||
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$questioncat1 = $questiongenerator->create_question_category(array('contextid' =>
|
||||
context_coursecat::instance($coursecat1->id)->id));
|
||||
$questioncat2 = $questiongenerator->create_question_category(array('contextid' =>
|
||||
context_coursecat::instance($coursecat2->id)->id));
|
||||
$question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id));
|
||||
$question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id));
|
||||
$question3 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id));
|
||||
$question4 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id));
|
||||
|
||||
// Now lets tag these questions.
|
||||
tag_set('question', $question1->id, array('tag 1', 'tag 2'), 'core_question', $questioncat1->contextid);
|
||||
tag_set('question', $question2->id, array('tag 3', 'tag 4'), 'core_question', $questioncat1->contextid);
|
||||
tag_set('question', $question3->id, array('tag 5', 'tag 6'), 'core_question', $questioncat2->contextid);
|
||||
tag_set('question', $question4->id, array('tag 7', 'tag 8'), 'core_question', $questioncat2->contextid);
|
||||
|
||||
// Test moving the questions to another category.
|
||||
question_move_questions_to_category(array($question1->id, $question2->id), $questioncat2->id);
|
||||
|
||||
// Test that all tag_instances belong to one context.
|
||||
$this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat2->contextid)));
|
||||
|
||||
// Test moving them back.
|
||||
question_move_questions_to_category(array($question1->id, $question2->id), $questioncat1->id);
|
||||
|
||||
// Test that all tag_instances are now reset to how they were initially.
|
||||
$this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat1->contextid)));
|
||||
$this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat2->contextid)));
|
||||
|
||||
// Now test moving a whole question category to another context.
|
||||
question_move_category_to_context($questioncat1->id, $questioncat1->contextid, $questioncat2->contextid);
|
||||
|
||||
// Test that all tag_instances belong to one context.
|
||||
$this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat2->contextid)));
|
||||
|
||||
// Now test moving them back.
|
||||
question_move_category_to_context($questioncat1->id, $questioncat2->contextid,
|
||||
context_coursecat::instance($coursecat1->id)->id);
|
||||
|
||||
// Test that all tag_instances are now reset to how they were initially.
|
||||
$this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat1->contextid)));
|
||||
$this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat2->contextid)));
|
||||
|
||||
// Now we want to test deleting the course category and moving the questions to another category.
|
||||
question_delete_course_category($coursecat1, $coursecat2, false);
|
||||
|
||||
// Test that all tag_instances belong to one context.
|
||||
$this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question',
|
||||
'contextid' => $questioncat2->contextid)));
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create some question categories and questions in this course.
|
||||
$questioncat = $questiongenerator->create_question_category(array('contextid' =>
|
||||
context_course::instance($course->id)->id));
|
||||
$question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id));
|
||||
$question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id));
|
||||
|
||||
// Add some tags to these questions.
|
||||
tag_set('question', $question1->id, array('tag 1', 'tag 2'), 'core_question', $questioncat->contextid);
|
||||
tag_set('question', $question2->id, array('tag 1', 'tag 2'), 'core_question', $questioncat->contextid);
|
||||
|
||||
// Create a course that we are going to restore the other course to.
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create backup file and save it to the backup location.
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2);
|
||||
$bc->execute_plan();
|
||||
$results = $bc->get_results();
|
||||
$file = $results['backup_destination'];
|
||||
$fp = get_file_packer();
|
||||
$filepath = $CFG->dataroot . '/temp/backup/test-restore-course';
|
||||
$file->extract_to_pathname($fp, $filepath);
|
||||
$bc->destroy();
|
||||
unset($bc);
|
||||
|
||||
// Now restore the course.
|
||||
$rc = new restore_controller('test-restore-course', $course2->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, 2, backup::TARGET_NEW_COURSE);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
|
||||
// Get the created question category.
|
||||
$restoredcategory = $DB->get_record('question_categories', array('contextid' => context_course::instance($course2->id)->id),
|
||||
'*', MUST_EXIST);
|
||||
|
||||
// Check that there are two questions in the restored to course's context.
|
||||
$this->assertEquals(2, $DB->count_records('question', array('category' => $restoredcategory->id)));
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ JavaSript:
|
||||
* New "Time spent waiting for the database" performance metric displayed along with the
|
||||
other MDL_PERF vars; the change affects both the error logs and the vars displayed in
|
||||
the page footer.
|
||||
* Changes in the tag API. The component and contextid are now saved when assigning tags to an item. Please see
|
||||
tag/upgrade.txt for more information.
|
||||
|
||||
=== 2.6 ===
|
||||
|
||||
|
@ -165,7 +165,10 @@ class restore_wiki_activity_structure_step extends restore_activity_structure_st
|
||||
|
||||
$tag = $data->rawname;
|
||||
$itemid = $this->get_new_parentid('wiki_page');
|
||||
tag_set_add('wiki_pages', $itemid, $tag);
|
||||
$wikiid = $this->get_new_parentid('wiki');
|
||||
|
||||
$cm = get_coursemodule_from_instance('wiki', $wikiid);
|
||||
tag_set_add('wiki_pages', $itemid, $tag, 'mod_wiki', context_module::instance($cm->id)->id);
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
|
@ -2035,7 +2035,7 @@ class page_wiki_save extends page_wiki_edit {
|
||||
|
||||
if ($save && $data) {
|
||||
if (!empty($CFG->usetags)) {
|
||||
tag_set('wiki_pages', $this->page->id, $data->tags);
|
||||
tag_set('wiki_pages', $this->page->id, $data->tags, 'mod_wiki', $this->modcontext->id);
|
||||
}
|
||||
|
||||
$message = '<p>' . get_string('saving', 'wiki') . '</p>';
|
||||
|
@ -108,6 +108,9 @@
|
||||
<testsuite name="core_notes">
|
||||
<directory suffix="_test.php">notes/tests</directory>
|
||||
</testsuite>
|
||||
<testsuite name="core_tag">
|
||||
<directory suffix="_test.php">tag/tests</directory>
|
||||
</testsuite>
|
||||
<testsuite name="core_rating">
|
||||
<directory suffix="_test.php">rating/tests</directory>
|
||||
</testsuite>
|
||||
|
@ -424,7 +424,7 @@ class qformat_default {
|
||||
|
||||
if (!empty($CFG->usetags) && isset($question->tags)) {
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
tag_set('question', $question->id, $question->tags);
|
||||
tag_set('question', $question->id, $question->tags, 'core_question', $question->context);
|
||||
}
|
||||
|
||||
if (!empty($result->error)) {
|
||||
|
@ -238,7 +238,10 @@ if ($mform->is_cancelled()) {
|
||||
/// whence it came. (Where we are moving to is validated by the form.)
|
||||
list($newcatid, $newcontextid) = explode(',', $fromform->category);
|
||||
if (!empty($question->id) && $newcatid != $question->category) {
|
||||
$contextid = $newcontextid;
|
||||
question_require_capability_on($question, 'move');
|
||||
} else {
|
||||
$contextid = $category->contextid;
|
||||
}
|
||||
|
||||
// Ensure we redirect back to the category the question is being saved into.
|
||||
@ -248,7 +251,7 @@ if ($mform->is_cancelled()) {
|
||||
if (!empty($question->id)) {
|
||||
question_require_capability_on($question, 'edit');
|
||||
} else {
|
||||
require_capability('moodle/question:add', context::instance_by_id($newcontextid));
|
||||
require_capability('moodle/question:add', context::instance_by_id($contextid));
|
||||
if (!empty($fromform->makecopy) && !$question->formoptions->cansaveasnew) {
|
||||
print_error('nopermissions', '', '', 'edit');
|
||||
}
|
||||
@ -258,7 +261,7 @@ if ($mform->is_cancelled()) {
|
||||
// A wizardpage from multipe pages questiontype like calculated may not
|
||||
// allow editing the question tags, hence the isset($fromform->tags) test.
|
||||
require_once($CFG->dirroot.'/tag/lib.php');
|
||||
tag_set('question', $question->id, $fromform->tags);
|
||||
tag_set('question', $question->id, $fromform->tags, 'core_question', $contextid);
|
||||
}
|
||||
|
||||
// Purge this question from the cache.
|
||||
|
@ -250,7 +250,7 @@ function coursetag_store_keywords($tags, $courseid, $userid=0, $tagtype='officia
|
||||
tag_type_set($tagid, $tagtype);
|
||||
|
||||
//tag_instance entry
|
||||
tag_assign('course', $courseid, $tagid, $ordering, $userid);
|
||||
tag_assign('course', $courseid, $tagid, $ordering, $userid, 'core', context_course::instance($courseid)->id);
|
||||
|
||||
//logging - note only for user added tags
|
||||
if ($tagtype == 'default' and $myurl != '') {
|
||||
|
@ -141,7 +141,7 @@ if ($tagnew = $tagform->get_data()) {
|
||||
}
|
||||
|
||||
//updated related tags
|
||||
tag_set('tag', $tagnew->id, explode(',', trim($tagnew->relatedtags)));
|
||||
tag_set('tag', $tagnew->id, explode(',', trim($tagnew->relatedtags)), 'core', $systemcontext);
|
||||
//print_object($tagnew); die();
|
||||
|
||||
redirect($CFG->wwwroot.'/tag/index.php?tag='.rawurlencode($tag->name)); // must use $tag here, as the name isn't in the edit form
|
||||
|
88
tag/lib.php
88
tag/lib.php
@ -31,10 +31,10 @@
|
||||
*
|
||||
* BASIC INSTRUCTIONS :
|
||||
* - to "tag a blog post" (for example):
|
||||
* tag_set('post', $blog_post->id, $array_of_tags);
|
||||
* tag_set('post', $blog_post->id, $array_of_tags, 'core', $thecontext);
|
||||
*
|
||||
* - to "remove all the tags on a blog post":
|
||||
* tag_set('post', $blog_post->id, array());
|
||||
* tag_set('post', $blog_post->id, array(), 'core', $thecontext);
|
||||
*
|
||||
* Tag set will create tags that need to be created.
|
||||
*
|
||||
@ -107,17 +107,20 @@ define('TAG_RELATED_CORRELATED', 2);
|
||||
*
|
||||
* This function is meant to be fed the string coming up from the user interface, which contains all tags assigned to a record.
|
||||
*
|
||||
* @package core_tag
|
||||
* @package core_tag
|
||||
* @category tag
|
||||
* @access public
|
||||
* @param string $record_type the type of record to tag ('post' for blogs, 'user' for users, 'tag' for tags, etc.)
|
||||
* @param int $record_id the id of the record to tag
|
||||
* @param array $tags the array of tags to set on the record. If given an empty array, all tags will be removed.
|
||||
* @return bool|null
|
||||
* @access public
|
||||
* @param string $record_type the type of record to tag ('post' for blogs, 'user' for users, 'tag' for tags, etc.)
|
||||
* @param int $record_id the id of the record to tag
|
||||
* @param array $tags the array of tags to set on the record. If given an empty array, all tags will be removed.
|
||||
* @param string|null $component the component that was tagged
|
||||
* @param int|null $contextid the context id of where this tag was assigned
|
||||
* @return bool|null
|
||||
*/
|
||||
function tag_set($record_type, $record_id, $tags) {
|
||||
function tag_set($record_type, $record_id, $tags, $component = null, $contextid = null) {
|
||||
|
||||
static $in_recursion_semaphore = false; // this is to prevent loops when tagging a tag
|
||||
|
||||
if ( $record_type == 'tag' && !$in_recursion_semaphore) {
|
||||
$current_tagged_tag_name = tag_get_name($record_id);
|
||||
}
|
||||
@ -162,13 +165,13 @@ function tag_set($record_type, $record_id, $tags) {
|
||||
$tag_current_id = $new_tag[$clean_tag];
|
||||
}
|
||||
|
||||
tag_assign($record_type, $record_id, $tag_current_id, $ordering);
|
||||
tag_assign($record_type, $record_id, $tag_current_id, $ordering, 0, $component, $contextid);
|
||||
|
||||
// if we are tagging a tag (adding a manually-assigned related tag), we
|
||||
// need to create the opposite relationship as well.
|
||||
if ( $record_type == 'tag' && !$in_recursion_semaphore) {
|
||||
$in_recursion_semaphore = true;
|
||||
tag_set_add('tag', $tag_current_id, $current_tagged_tag_name);
|
||||
tag_set_add('tag', $tag_current_id, $current_tagged_tag_name, $component, $contextid);
|
||||
$in_recursion_semaphore = false;
|
||||
}
|
||||
}
|
||||
@ -177,14 +180,17 @@ function tag_set($record_type, $record_id, $tags) {
|
||||
/**
|
||||
* Adds a tag to a record, without overwriting the current tags.
|
||||
*
|
||||
* @package core_tag
|
||||
* @package core_tag
|
||||
* @category tag
|
||||
* @access public
|
||||
* @param string $record_type the type of record to tag ('post' for blogs, 'user' for users, etc.)
|
||||
* @param int $record_id the id of the record to tag
|
||||
* @param string $tag the tag to add
|
||||
* @access public
|
||||
* @param string $record_type the type of record to tag ('post' for blogs, 'user' for users, etc.)
|
||||
* @param int $record_id the id of the record to tag
|
||||
* @param string $tag the tag to add
|
||||
* @param string|null $component the component that was tagged
|
||||
* @param int|null $contextid the context id of where this tag was assigned
|
||||
* @return bool|null
|
||||
*/
|
||||
function tag_set_add($record_type, $record_id, $tag) {
|
||||
function tag_set_add($record_type, $record_id, $tag, $component = null, $contextid = null) {
|
||||
|
||||
$new_tags = array();
|
||||
foreach( tag_get_tags($record_type, $record_id) as $current_tag ) {
|
||||
@ -192,20 +198,23 @@ function tag_set_add($record_type, $record_id, $tag) {
|
||||
}
|
||||
$new_tags[] = $tag;
|
||||
|
||||
return tag_set($record_type, $record_id, $new_tags);
|
||||
return tag_set($record_type, $record_id, $new_tags, $component, $contextid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a tag from a record, without overwriting other current tags.
|
||||
*
|
||||
* @package core_tag
|
||||
* @package core_tag
|
||||
* @category tag
|
||||
* @access public
|
||||
* @param string $record_type the type of record to tag ('post' for blogs, 'user' for users, etc.)
|
||||
* @param int $record_id the id of the record to tag
|
||||
* @param string $tag the tag to delete
|
||||
* @access public
|
||||
* @param string $record_type the type of record to tag ('post' for blogs, 'user' for users, etc.)
|
||||
* @param int $record_id the id of the record to tag
|
||||
* @param string $tag the tag to delete
|
||||
* @param string|null $component the component that was tagged
|
||||
* @param int|null $contextid the context id of where this tag was assigned
|
||||
* @return bool|null
|
||||
*/
|
||||
function tag_set_delete($record_type, $record_id, $tag) {
|
||||
function tag_set_delete($record_type, $record_id, $tag, $component = null, $contextid = null) {
|
||||
|
||||
$new_tags = array();
|
||||
foreach( tag_get_tags($record_type, $record_id) as $current_tag ) {
|
||||
@ -214,7 +223,7 @@ function tag_set_delete($record_type, $record_id, $tag) {
|
||||
}
|
||||
}
|
||||
|
||||
return tag_set($record_type, $record_id, $new_tags);
|
||||
return tag_set($record_type, $record_id, $new_tags, $component, $contextid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -774,17 +783,24 @@ function tag_add($tags, $type="default") {
|
||||
* Assigns a tag to a record; if the record already exists, the time and ordering will be updated.
|
||||
*
|
||||
* @package core_tag
|
||||
* @access private
|
||||
* @param string $record_type the type of the record that will be tagged
|
||||
* @param int $record_id the id of the record that will be tagged
|
||||
* @param string $tagid the tag id to set on the record.
|
||||
* @param int $ordering the order of the instance for this record
|
||||
* @param int $userid (optional) only required for course tagging
|
||||
* @return bool true on success, false otherwise
|
||||
* @access private
|
||||
* @param string $record_type the type of the record that will be tagged
|
||||
* @param int $record_id the id of the record that will be tagged
|
||||
* @param string $tagid the tag id to set on the record.
|
||||
* @param int $ordering the order of the instance for this record
|
||||
* @param int $userid (optional) only required for course tagging
|
||||
* @param string|null $component the component that was tagged
|
||||
* @param int|null $contextid the context id of where this tag was assigned
|
||||
* @return bool true on success, false otherwise
|
||||
*/
|
||||
function tag_assign($record_type, $record_id, $tagid, $ordering, $userid = 0) {
|
||||
function tag_assign($record_type, $record_id, $tagid, $ordering, $userid = 0, $component = null, $contextid = null) {
|
||||
global $DB;
|
||||
|
||||
if ($component === null || $contextid === null) {
|
||||
debugging('You should specify the component and contextid of the item being tagged in your call to tag_assign.',
|
||||
DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
if ( $tag_instance_object = $DB->get_record('tag_instance', array('tagid'=>$tagid, 'itemtype'=>$record_type, 'itemid'=>$record_id, 'tiuserid'=>$userid), 'id')) {
|
||||
$tag_instance_object->ordering = $ordering;
|
||||
$tag_instance_object->timemodified = time();
|
||||
@ -792,11 +808,15 @@ function tag_assign($record_type, $record_id, $tagid, $ordering, $userid = 0) {
|
||||
} else {
|
||||
$tag_instance_object = new StdClass;
|
||||
$tag_instance_object->tagid = $tagid;
|
||||
$tag_instance_object->component = $component;
|
||||
$tag_instance_object->itemid = $record_id;
|
||||
$tag_instance_object->itemtype = $record_type;
|
||||
$tag_instance_object->contextid = $contextid;
|
||||
$tag_instance_object->ordering = $ordering;
|
||||
$tag_instance_object->timemodified = time();
|
||||
$tag_instance_object->timecreated = time();
|
||||
$tag_instance_object->timemodified = $tag_instance_object->timecreated;
|
||||
$tag_instance_object->tiuserid = $userid;
|
||||
|
||||
return $DB->insert_record('tag_instance', $tag_instance_object);
|
||||
}
|
||||
}
|
||||
|
146
tag/tests/taglib_test.php
Normal file
146
tag/tests/taglib_test.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Tag related unit tests.
|
||||
*
|
||||
* @package core_tag
|
||||
* @category test
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/tag/lib.php');
|
||||
|
||||
class core_tag_taglib_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*
|
||||
* This is executed before running any test in this file.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the tag_set function.
|
||||
*/
|
||||
public function test_tag_set() {
|
||||
global $DB;
|
||||
|
||||
// Create a course to tag.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create the tag and tag instance.
|
||||
tag_set('course', $course->id, array('A random tag'), 'core', context_course::instance($course->id)->id);
|
||||
|
||||
// Get the tag instance that should have been created.
|
||||
$taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
|
||||
$this->assertEquals('core', $taginstance->component);
|
||||
$this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
|
||||
|
||||
// Now call the tag_set function without specifying the component or contextid and
|
||||
// ensure the function debugging is called.
|
||||
tag_set('course', $course->id, array('Another tag'));
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the tag_set_add function.
|
||||
*/
|
||||
public function test_tag_set_add() {
|
||||
global $DB;
|
||||
|
||||
// Create a course to tag.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create the tag and tag instance.
|
||||
tag_set_add('course', $course->id, 'A random tag', 'core', context_course::instance($course->id)->id);
|
||||
|
||||
// Get the tag instance that should have been created.
|
||||
$taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
|
||||
$this->assertEquals('core', $taginstance->component);
|
||||
$this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
|
||||
|
||||
// Remove the tag we just created.
|
||||
$tag = $DB->get_record('tag', array('rawname' => 'A random tag'));
|
||||
tag_delete($tag->id);
|
||||
|
||||
// Now call the tag_set_add function without specifying the component or
|
||||
// contextid and ensure the function debugging is called.
|
||||
tag_set_add('course', $course->id, 'Another tag');
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the tag_set_delete function.
|
||||
*/
|
||||
public function test_tag_set_delete() {
|
||||
global $DB;
|
||||
|
||||
// Create a course to tag.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create the tag and tag instance we are going to delete.
|
||||
tag_set_add('course', $course->id, 'A random tag', 'core', context_course::instance($course->id)->id);
|
||||
|
||||
// Call the tag_set_delete function.
|
||||
tag_set_delete('course', $course->id, 'a random tag', 'core', context_course::instance($course->id)->id);
|
||||
|
||||
// Now check that there are no tags or tag instances.
|
||||
$this->assertEquals(0, $DB->count_records('tag'));
|
||||
$this->assertEquals(0, $DB->count_records('tag_instance'));
|
||||
|
||||
// Recreate the tag and tag instance.
|
||||
tag_set_add('course', $course->id, 'A random tag', 'core', context_course::instance($course->id)->id);
|
||||
|
||||
// Now call the tag_set_delete function without specifying the component or
|
||||
// contextid and ensure the function debugging is called.
|
||||
tag_set_delete('course', $course->id, 'A random tag');
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the tag_assign function.
|
||||
*/
|
||||
public function test_tag_assign() {
|
||||
global $DB;
|
||||
|
||||
// Create a course to tag.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create the tag.
|
||||
$tag = $this->getDataGenerator()->create_tag();
|
||||
|
||||
// Tag the course with the tag we created.
|
||||
tag_assign('course', $course->id, $tag->id, 0, 0, 'core', context_course::instance($course->id)->id);
|
||||
|
||||
// Get the tag instance that should have been created.
|
||||
$taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
|
||||
$this->assertEquals('core', $taginstance->component);
|
||||
$this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
|
||||
|
||||
// Now call the tag_assign function without specifying the component or
|
||||
// contextid and ensure the function debugging is called.
|
||||
tag_assign('course', $course->id, $tag->id, 0, 0);
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
This files describes API changes in tagging, information provided
|
||||
here is intended especially for developers.
|
||||
|
||||
=== 2.7 ===
|
||||
|
||||
* The functions tag_set, tag_set_add, tag_set_delete and tag_assign now expect the component
|
||||
and contextid of the item being tagged.
|
||||
|
||||
=== 2.6 ===
|
||||
|
||||
More cleanup was done to tag cloud sorting which involved some API changes, see MDL_39800
|
||||
|
@ -21,6 +21,7 @@ if (!confirm_sesskey()) {
|
||||
print_error('sesskey');
|
||||
}
|
||||
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
|
||||
switch ($action) {
|
||||
case 'addinterest':
|
||||
@ -28,7 +29,7 @@ switch ($action) {
|
||||
$tag = tag_get_name($id);
|
||||
}
|
||||
|
||||
tag_set_add('user', $USER->id, $tag);
|
||||
tag_set_add('user', $USER->id, $tag, 'core', $usercontext->id);
|
||||
|
||||
redirect($CFG->wwwroot.'/tag/index.php?tag='. rawurlencode($tag));
|
||||
break;
|
||||
@ -38,7 +39,7 @@ switch ($action) {
|
||||
$tag = tag_get_name($id);
|
||||
}
|
||||
|
||||
tag_set_delete('user', $USER->id, $tag);
|
||||
tag_set_delete('user', $USER->id, $tag, 'core', $usercontext->id);
|
||||
|
||||
redirect($CFG->wwwroot.'/tag/index.php?tag='. rawurlencode($tag));
|
||||
break;
|
||||
|
@ -174,7 +174,7 @@ function useredit_update_trackforums($user, $usernew) {
|
||||
* @param array $interests
|
||||
*/
|
||||
function useredit_update_interests($user, $interests) {
|
||||
tag_set('user', $user->id, $interests);
|
||||
tag_set('user', $user->id, $interests, 'core', context_user::instance($user->id)->id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user