/** * Creates the mail queue and runs query to obtain list of posts that should * be mailed. * @param bool $tracetimes True if it should call mtrace to display * performance information */ function __construct($tracetimes) { global $CFG; $this->time = time(); $this->forum = null; $this->discussion = null; $this->storedrecord = null; $this->postcount = 0; // Check if an earlier run got aborted. In that case we mark all // messages as mailed anyway because it's better to skip some than // to send out double-posts. if ($pending = get_config('forumng', $this->get_pending_flag_name())) { $this->mark_mailed($pending); } // Note that we are mid-run set_config($this->get_pending_flag_name(), $this->time, 'forumng'); $querychunk = $this->get_query_chunk($this->time); if (!($this->rs = get_recordset_sql($sql = "\nSELECT\n " . forum_utils::select_forum_fields('f') . ",\n " . forum_utils::select_discussion_fields('fd') . ",\n " . forum_utils::select_post_fields('discussionpost') . ",\n " . forum_utils::select_post_fields('fp') . ",\n " . forum_utils::select_post_fields('reply') . ",\n " . forum_utils::select_course_module_fields('cm') . ",\n " . forum_utils::select_context_fields('x') . ",\n " . forum_utils::select_username_fields('u', true) . ",\n " . forum_utils::select_username_fields('eu') . ",\n " . forum_utils::select_username_fields('replyu') . ",\n " . forum_utils::select_username_fields('replyeu') . ",\n " . forum_utils::select_course_fields('c') . ",\n clonecm.id AS cloneid\n{$querychunk}\nORDER BY\n clonecm.course, f.id, fd.id, fp.id"))) { throw new forum_exception("Mail queue query failed"); } }
/** * Internal function. Queries for posts. * @param string $where Where clause (fp is alias for post table) * @param string $order Sort order; the default is fp.id - note this is preferable * to fp.timecreated because it works correctly if there are two posts in * the same second * @param bool $ratings True if ratings should be included in the query * @param bool $flags True if flags should be included in the query * @param bool $effectivesubjects True if the query should include the * (complicated!) logic to obtain the 'effective subject'. This may result * in additional queries afterward for posts which are very deeply nested. * @param int $userid 0 = current user (at present this is only used for * flags) * @return array Resulting posts as array of Moodle records, empty array * if none */ static function query_posts($where, $order = 'fp.id', $ratings = true, $flags = false, $effectivesubjects = false, $userid = 0, $joindiscussion = false, $discussionsubject = false, $limitfrom = '', $limitnum = '') { global $CFG, $USER; $userid = forum_utils::get_real_userid($userid); // We include ratings if these are enabled, otherwise save the database // some effort and don't bother if ($ratings) { $ratingsquery = ",\n(SELECT AVG(rating) FROM {$CFG->prefix}forumng_ratings\n WHERE postid=fp.id) AS averagerating,\n(SELECT COUNT(1) FROM {$CFG->prefix}forumng_ratings\n WHERE postid=fp.id) AS numratings,\n(SELECT rating FROM {$CFG->prefix}forumng_ratings\n WHERE postid=fp.id AND userid={$USER->id}) AS ownrating"; } else { $ratingsquery = ''; } if ($flags) { $flagsjoin = "\n LEFT JOIN {$CFG->prefix}forumng_flags ff ON ff.postid = fp.id AND ff.userid = {$userid}"; $flagsquery = ",ff.flagged"; } else { $flagsjoin = ''; $flagsquery = ''; } if ($joindiscussion) { $discussionjoin = "\n INNER JOIN {$CFG->prefix}forumng_discussions fd ON fp.discussionid = fd.id"; $discussionquery = ',' . forum_utils::select_discussion_fields('fd'); if ($discussionsubject) { $discussionjoin .= "\n INNER JOIN {$CFG->prefix}forumng_posts fdfp ON fd.postid = fdfp.id"; $discussionquery .= ', fdfp.subject AS fd_subject'; } } else { $discussionjoin = ''; $discussionquery = ''; } if ($effectivesubjects) { $maxdepth = self::PARENTPOST_DEPTH_PER_QUERY; $subjectsjoin = ''; $subjectsquery = ", p{$maxdepth}.parentpostid AS nextparent "; for ($depth = 2; $depth <= $maxdepth; $depth++) { $subjectsquery .= ", p{$depth}.subject AS s{$depth}, p{$depth}.deleted AS d{$depth}"; $prev = 'p' . ($depth - 1); if ($prev == 'p1') { $prev = 'fp'; } $subjectsjoin .= "LEFT JOIN {$CFG->prefix}forumng_posts p{$depth}\n ON p{$depth}.id = {$prev}.parentpostid "; } } else { $subjectsjoin = ''; $subjectsquery = ''; } // Retrieve posts from discussion with incorporated user information // and ratings info if specified $results = forum_utils::get_records_sql("\nSELECT\n fp.*,\n " . forum_utils::select_username_fields('u') . ",\n " . forum_utils::select_username_fields('eu') . ",\n " . forum_utils::select_username_fields('du') . "\n {$ratingsquery}\n {$flagsquery}\n {$subjectsquery}\n {$discussionquery}\nFROM\n {$CFG->prefix}forumng_posts fp\n INNER JOIN {$CFG->prefix}user u ON fp.userid=u.id\n LEFT JOIN {$CFG->prefix}user eu ON fp.edituserid=eu.id\n LEFT JOIN {$CFG->prefix}user du ON fp.deleteuserid=du.id \n {$discussionjoin}\n {$flagsjoin}\n {$subjectsjoin}\nWHERE\n {$where}\nORDER BY\n {$order}\n", $limitfrom, $limitnum); if ($effectivesubjects) { // Figure out the effective subject for each result foreach ($results as $result) { $got = false; if ($result->subject !== null) { $result->effectivesubject = $result->subject; $got = true; continue; } for ($depth = 2; $depth <= $maxdepth; $depth++) { $var = "s{$depth}"; $var2 = "d{$depth}"; if (!$got && $result->{$var} !== null && $result->{$var2} == 0) { $result->effectivesubject = get_string('re', 'forumng', $result->{$var}); $got = true; } unset($result->{$var}); unset($result->{$var2}); } if (!$got) { // Do extra queries to pick up subjects for posts where it // was unknown within the default depth. We can use the // 'nextparent' to get the ID of the parent post of the last // one that we checked already $result->effectivesubject = self::inner_get_recursive_subject($result->nextparent); } } } return $results; }