PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/dev/makebig.php

https://github.com/NigelCunningham/moodle-mod_forumng
PHP | 465 lines | 322 code | 76 blank | 67 comment | 34 complexity | d9a9401d64d62180be56c501d027d4da MD5 | raw file
  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.
  13. //
  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/>.
  16. /**
  17. * Developer test tool to construct a big forum. Maybe doesn't work.
  18. * @package mod
  19. * @subpackage forumng
  20. * @copyright 2011 The Open University
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. // Note: As a development test tool, this script is English-only.
  24. require_once('../../../config.php');
  25. require_once($CFG->libdir.'/formslib.php');
  26. require_once($CFG->dirroot.'/mod/forumng/lib.php');
  27. require_once($CFG->dirroot.'/mod/forumng/mod_forumng.php');
  28. require_once($CFG->dirroot.'/mod/forumng/mod_forumng_exception.php');
  29. require_login();
  30. require_capability('moodle/site:config', context_system::instance());
  31. if (!debugging('', DEBUG_DEVELOPER)) {
  32. error('Available only in debug mode');
  33. }
  34. /**
  35. * Returns random numbers with some kind of nice distribution that is mainly
  36. * low then tails off, but ends up averaging at the mean. The number is never
  37. * less than 1.
  38. * @param int $mean Mean value
  39. * @return int Random number
  40. */
  41. function my_random($mean) {
  42. $mean-=0.5; // Because we add 1, but also do floor. Note that I tested this
  43. // function over a fair number of runs; it appears to get
  44. // the correct mean.
  45. return floor((mt_rand(0, 1000)/1000) * (mt_rand(0, 1000)/1000) * 4.0 * $mean)+1;
  46. }
  47. /**
  48. * Returns true if a percentage chance comes off.
  49. * @param float $percent Percentage value. May be floating-point.
  50. * @return bool True if the chance hits.
  51. */
  52. function my_random_percentage($percent) {
  53. $value = 100.0 * mt_rand() / (mt_getrandmax()+1);
  54. return ($value < $percent);
  55. }
  56. function get_post_text() {
  57. // 660 is the current mean number of bytes for a forum post text on Learn.
  58. $length = my_random(660);
  59. $text = '';
  60. for ($i=0;$i<$length;$i++) {
  61. $text .= '0';
  62. if (my_random_percentage(20)) {
  63. $text .= ' ';
  64. }
  65. }
  66. return $text;
  67. }
  68. function make_post($discussion, &$allposts, &$userids, $ratingpercent) {
  69. // Make reply
  70. static $index = 0;
  71. $index++;
  72. $replyto = $allposts[rand(0, count($allposts)-1)];
  73. $newpostid = $replyto->reply(
  74. my_random_percentage(25) ? 'Reply '.$index : null,
  75. get_post_text(), FORMAT_HTML,
  76. array(), false, $userids[mt_rand(0, count($userids)-1)], false);
  77. $newpost = mod_forumng_post::get_from_id($newpostid, mod_forumng::CLONE_DIRECT);
  78. $allposts[] = $newpost;
  79. // Add ratings
  80. for ($i=0; $i<count($userids); $i++) {
  81. if (my_random_percentage($ratingpercent)) {
  82. $newpost->rate(2, $userids[$i]);
  83. }
  84. }
  85. }
  86. function make_discussion($forum, $posts, $readusers, &$userids, $ratingpercent) {
  87. set_time_limit(200);
  88. // Make discussion
  89. static $index = 0;
  90. $index++;
  91. list($discussionid, $postid) = $forum->create_discussion(null,
  92. 'Discussion '.$index, get_post_text(), FORMAT_HTML, array(), false,
  93. 0, 0, false, false, $userids[mt_rand(0, count($userids)-1)], false);
  94. $discussion = mod_forumng_discussion::get_from_id($discussionid, mod_forumng::CLONE_DIRECT);
  95. // Make posts
  96. $count = my_random($posts)-1;
  97. $allposts = array($discussion->get_root_post());
  98. for ($i=0;$i<$count;$i++) {
  99. make_post($discussion, $allposts, $userids, $ratingpercent);
  100. }
  101. // Mark the discussion read if requested
  102. if ($readusers > 0) {
  103. $now = time();
  104. for ($i = 0; $i<$readusers; $i++) {
  105. $discussion->mark_read($now, $userids[$i]);
  106. }
  107. }
  108. // Progress
  109. print '.';
  110. }
  111. function make_forumng($courseid, $starttime, $discussions, $posts,
  112. $readpercent, $readusers, &$userids, $subscribepercent, $ratingpercent) {
  113. global $DB;
  114. $section = $DB->get_record('course_sections', array('course' => $courseid, 'section' => 0),
  115. '*', MUST_EXIST);
  116. $transaction = $DB->start_delegated_transaction();
  117. // Create course modules record
  118. $mod = new stdClass;
  119. $mod->course = $courseid;
  120. $mod->module = $DB->get_field('modules', 'id', array('name' => 'forumng'));
  121. $mod->section = $section->section; // was $section->id; logical but incorrect!
  122. $mod->added = $starttime;
  123. $mod->visible = 1;
  124. // course_modules and course_sections each contain a reference
  125. // to each other, so we have to update one of them twice.
  126. // Note: This is unbelievable!!! $mod->section MUST BE section number (not id)
  127. // Adds course_module with section number, add_mod_to_section uses
  128. // section number (& course id) to get section id, which is returned
  129. // course module record then updated to replace section number by id!!!
  130. if (! $mod->coursemodule = add_course_module($mod) ) {
  131. throw new Exception("Could not add a new course module");
  132. }
  133. if (! $sectionid = add_mod_to_section($mod) ) {
  134. throw new Exception("Could not add the new course module to that section");
  135. }
  136. // Create forum object
  137. $forumng = new stdClass;
  138. static $index = 0;
  139. $index++;
  140. $forumng->name = 'Perf test '.date('Ymd H:j', $starttime).' '.$index;
  141. $forumng->course = $courseid;
  142. $forumng->section = $section;
  143. $forumng->cmidnumber = $mod->coursemodule;
  144. if (!($forumng->id = forumng_add_instance($forumng))) {
  145. throw new dml_exception('Failed to add forum');
  146. }
  147. // Mark cm object as owning it
  148. $updatemod = new stdClass;
  149. $updatemod->id = $mod->coursemodule;
  150. $updatemod->instance = $forumng->id;
  151. $updatemod->section = $sectionid;
  152. $DB->update_record('course_modules', $updatemod);
  153. // Make it be random users included in the forum
  154. shuffle($userids);
  155. // OK, forum is created. Let's make discussions
  156. $forum = mod_forumng::get_from_id($forumng->id, mod_forumng::CLONE_DIRECT);
  157. $count = my_random($discussions);
  158. for ($i=0;$i<$count;$i++) {
  159. make_discussion($forum, $posts,
  160. my_random_percentage($readpercent) ? $readusers : 0, $userids,
  161. $ratingpercent);
  162. }
  163. // Add subscribe users
  164. set_time_limit(200);
  165. for ($i=0; $i<$readusers; $i++) {
  166. if (my_random_percentage($subscribepercent)) {
  167. $forum->subscribe($userids[$i]);
  168. }
  169. }
  170. $transaction->allow_commit();
  171. }
  172. function wipe_forumng($cm) {
  173. global $DB;
  174. $transaction = $DB->start_delegated_transaction();
  175. // Tell forum to delete itself
  176. if (!forumng_delete_instance($cm->instance)) {
  177. throw new Exception("Could not delete forum instance {$cm->instance}");
  178. }
  179. // Delete course_module entry
  180. $DB->delete_records('course_modules', array('id' => $cm->id));
  181. // Update section
  182. if (!delete_mod_from_section($cm->id, $cm->section)) {
  183. throw new Exception("Could not delete module {$cm->id} from section {$cm->section}");
  184. }
  185. $transaction->allow_commit();
  186. }
  187. function make_forums($courseid, $count, $discussions, $posts,
  188. $readpercent, $readusers, $subscribepercent, $ratingpercent) {
  189. global $DB;
  190. // Require course to exist
  191. $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
  192. // Get all course users
  193. $context = context_course::instance($courseid);
  194. $rs = $DB->get_recordset_sql("
  195. SELECT
  196. DISTINCT userid
  197. FROM
  198. {role_assignments}
  199. WHERE
  200. contextid = ?", array($context->id));
  201. $userids = array();
  202. foreach ($rs as $record) {
  203. $userids[] = $record->userid;
  204. }
  205. $rs->close();
  206. if ($readusers > count($userids)) {
  207. throw new moodle_exception('error_makebig', 'forumng', '', (object)array(
  208. 'users' => count($userids), 'readusers' => $readusers));
  209. }
  210. // Create forums
  211. print "<h3>Making $count forums</h3><pre>";
  212. $time = time();
  213. for ($i=0;$i<$count;$i++) {
  214. make_forumng($courseid, $time, $discussions, $posts,
  215. $readpercent, $readusers, $userids, $subscribepercent,
  216. $ratingpercent);
  217. print 'X';
  218. if (($i+1)%20==0) {
  219. print " (".($i+1).")\n";
  220. }
  221. flush();
  222. }
  223. print "</pre>";
  224. rebuild_course_cache($courseid);
  225. }
  226. function wipe_forums($courseid) {
  227. global $DB;
  228. // Get list of course-module IDs
  229. $forumngid = $DB->get_field('modules', 'id', array('name' => 'forumng'));
  230. $cms = $DB->get_records_sql("
  231. SELECT
  232. id, course, instance, section
  233. FROM
  234. {course_modules} cm
  235. WHERE
  236. cm.module = ? AND cm.course = ?", array($forumngid, $courseid));
  237. $count = count($cms);
  238. print "<h3>Wiping $count forums</h3><pre>";
  239. $time = time();
  240. $i = 0;
  241. foreach ($cms as $cm) {
  242. wipe_forumng($cm);
  243. print '.';
  244. if (($i+1)%20==0) {
  245. print " (".($i+1).")\n";
  246. }
  247. flush();
  248. $i++;
  249. }
  250. print "</pre>";
  251. rebuild_course_cache($courseid);
  252. }
  253. function make_student($courseid, $username) {
  254. global $DB;
  255. // Create user record
  256. $user = new StdClass;
  257. $user->username = $username;
  258. $user->lastname = $username;
  259. $user->email = $username . '@somewhere';
  260. $user->emailstop = 1;
  261. $user->firstname = 'Ms';
  262. $user->auth = 'manual';
  263. $user->password = md5('apple');
  264. $user->id = $DB->insert_record('user', $user);
  265. // Assign to course
  266. $context = context_course::instance($courseid);
  267. static $roleid;
  268. if (!$roleid) {
  269. $roleid = $DB->get_field('role', 'id', array('shortname' => 'student'));
  270. }
  271. if (!role_assign($roleid, $user->id, 0, $context->id)) {
  272. throw new Exception('Failed to assign role');
  273. }
  274. }
  275. function make_students($courseid, $count) {
  276. print "<h3>Making $count students</h3><pre>";
  277. $time = time();
  278. $transaction = $DB->start_delegated_transaction();
  279. for ($i=0;$i<$count;$i++) {
  280. make_student($courseid, $time.'_'.$i);
  281. print '.';
  282. if (($i+1)%20==0) {
  283. print " (".($i+1).")\n";
  284. }
  285. flush();
  286. }
  287. $transaction->allow_commit();
  288. print "</pre>";
  289. }
  290. class make_big_form extends moodleform {
  291. function definition() {
  292. global $CFG;
  293. $mform =& $this->_form;
  294. $mform->addElement('header', 'h1', 'Test course');
  295. $mform->addElement('text', 'course', 'Course ID');
  296. $mform->setType('course', PARAM_INT);
  297. $mform->addElement('header', 'h1', 'Create forums');
  298. $mform->addElement('text', 'forums', 'Number of forums');
  299. $mform->setType('forums', PARAM_INT);
  300. $mform->setDefault('forums', 10);
  301. $mform->addElement('text', 'readusers', 'Number of users reading each forum');
  302. $mform->setType('readusers', PARAM_INT);
  303. $mform->setDefault('readusers', 1000);
  304. $mform->addElement('text', 'discussions', 'Number of discussions per forum (avg)');
  305. $mform->setType('discussions', PARAM_NUMBER);
  306. $mform->setDefault('discussions', 100);
  307. $mform->addElement('text', 'posts', 'Number of posts per discussion (avg)');
  308. $mform->setType('posts', PARAM_NUMBER);
  309. $mform->setDefault('posts', 10);
  310. $mform->addElement('text', 'readpercent',
  311. '% of recent discussions (that include read data)');
  312. $mform->setType('readpercent', PARAM_NUMBER);
  313. $mform->setDefault('readpercent', 10);
  314. $mform->addElement('text', 'subscribepercent', '% of users who subscribe');
  315. $mform->setType('subscribepercent', PARAM_NUMBER);
  316. $mform->setDefault('subscribepercent', 50);
  317. $mform->addElement('text', 'ratingpercent', '% chance of each user rating each post');
  318. $mform->setType('ratingpercent', PARAM_NUMBER);
  319. $mform->setDefault('ratingpercent', 0.1);
  320. $mform->addElement('submit', 'submitcreate', 'Create forums');
  321. $mform->addElement('header', 'h2', 'Wipe all forums');
  322. $mform->addElement('text', 'confirm', 'Are you sure? (Type yes)');
  323. $mform->setType('text', PARAM_ALPHA);
  324. $mform->addElement('submit', 'submitwipe', 'Wipe forums');
  325. $mform->addElement('header', 'h2', 'Create course students');
  326. $mform->addElement('text', 'students', 'Number of students to create');
  327. $mform->setType('students', PARAM_INT);
  328. $mform->setDefault('students', 100);
  329. $mform->addElement('submit', 'submitstudents', 'Make new students');
  330. }
  331. }
  332. $mform = new make_big_form();
  333. print_header('Make big forums', 'Make big forums');
  334. // Standard moodleform if statement.
  335. if ($mform->is_cancelled()) {
  336. // Don't think this will ever happen, but do nothing.
  337. } else if ($fromform = $mform->get_data()) {
  338. if (isset($fromform->submitcreate)) {
  339. make_forums($fromform->course, $fromform->forums,
  340. $fromform->discussions, $fromform->posts, $fromform->readpercent,
  341. $fromform->readusers, $fromform->subscribepercent,
  342. $fromform->ratingpercent);
  343. // TODO Ratings aren't done yet!!
  344. }
  345. else if (isset($fromform->submitwipe)) {
  346. if (required_param('confirm', PARAM_ALPHA) != 'yes') {
  347. error('You didn\'t type yes to confirm the wipe.');
  348. }
  349. wipe_forums($fromform->course);
  350. }
  351. else if (isset($fromform->submitstudents)) {
  352. make_students($fromform->course, $fromform->students);
  353. }
  354. }
  355. print '<h3>Current counts</h3><ul>';
  356. print '<li>Forums: <strong>' . $DB->count_records('forumng') . '</strong></li>';
  357. print '<li>Discussions: <strong>' . $DB->count_records('forumng_discussions') . '</strong></li>';
  358. print '<li>Posts: <strong>' . $DB->count_records('forumng_posts') . '</strong></li>';
  359. print '<li>User/discussion read data: <strong>' .
  360. $DB->count_records('forumng_read') . '</strong></li>';
  361. print '<li>User/forum subscriptions: <strong>' .
  362. $DB->count_records('forumng_subscriptions') . '</strong></li>';
  363. print '<li>User/post ratings: <strong>' .
  364. $DB->count_records('forumng_ratings') . '</strong></li>';
  365. print '</ul>';
  366. function show_maximum_per($label, $of, $per, $url) {
  367. global $CFG, $DB;
  368. $results = $DB->get_records_sql("
  369. SELECT $per AS field, COUNT(1) AS count
  370. FROM {" . $of . "}
  371. GROUP BY $per
  372. ORDER BY 2 DESC", 0, 1);
  373. $result = $results ? reset($results)
  374. : (object)array('field'=>0, 'count'=>0);
  375. $displayurl = str_replace('$$', $result->field, $url);
  376. print "<li>$label: <strong>$result->count</strong>
  377. (<a href='$CFG->wwwroot$displayurl'>id=$result->field</a>)</li>";
  378. }
  379. print '<h3>Maximums</h3><ul>';
  380. show_maximum_per('Forums per course', 'forumng', 'course', '/course/view.php?id=$$');
  381. show_maximum_per('Discussions per forum', 'forumng_discussions', 'forumngid',
  382. '/mod/forumng/view.php?id=$$');
  383. show_maximum_per('Subscriptions per forum', 'forumng_subscriptions',
  384. 'forumngid', '/mod/forumng/view.php?id=$$');
  385. show_maximum_per('Posts per discussion', 'forumng_posts', 'discussionid',
  386. '/mod/forumng/discuss.php?id=$$');
  387. print '</ul>';
  388. $mform->display();
  389. print_footer();