Merge branch 'MDL-49231-master' of git://github.com/jleyva/moodle
This commit is contained in:
@@ -1277,6 +1277,19 @@ $services = array(
|
||||
'mod_wiki_get_wikis_by_courses',
|
||||
'mod_wiki_view_wiki',
|
||||
'mod_wiki_view_page',
|
||||
'mod_glossary_view_glossary',
|
||||
'mod_glossary_view_entry',
|
||||
'mod_glossary_get_entries_by_letter',
|
||||
'mod_glossary_get_entries_by_date',
|
||||
'mod_glossary_get_categories',
|
||||
'mod_glossary_get_entries_by_category',
|
||||
'mod_glossary_get_authors',
|
||||
'mod_glossary_get_entries_by_author',
|
||||
'mod_glossary_get_entries_by_author_id',
|
||||
'mod_glossary_get_entries_by_search',
|
||||
'mod_glossary_get_entries_by_term',
|
||||
'mod_glossary_get_entries_to_approve',
|
||||
'mod_glossary_get_entry_by_id',
|
||||
),
|
||||
'enabled' => 0,
|
||||
'restrictedusers' => 0,
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Entry query builder.
|
||||
*
|
||||
* @package mod_glossary
|
||||
* @copyright 2015 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Entry query builder class.
|
||||
*
|
||||
* The purpose of this class is to avoid duplicating SQL statements to fetch entries
|
||||
* which are very similar with each other. This builder is not meant to be smart, it
|
||||
* will not out rule any previously set condition, or join, etc...
|
||||
*
|
||||
* You should be using this builder just like you would be creating your SQL query. Only
|
||||
* some methods are shorthands to avoid logic duplication and common mistakes.
|
||||
*
|
||||
* @package mod_glossary
|
||||
* @copyright 2015 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
class mod_glossary_entry_query_builder {
|
||||
|
||||
/** Alias for table glossary_alias. */
|
||||
const ALIAS_ALIAS = 'ga';
|
||||
/** Alias for table glossary_categories. */
|
||||
const ALIAS_CATEGORIES = 'gc';
|
||||
/** Alias for table glossary_entries_categories. */
|
||||
const ALIAS_ENTRIES_CATEGORIES = 'gec';
|
||||
/** Alias for table glossary_entries. */
|
||||
const ALIAS_ENTRIES = 'ge';
|
||||
/** Alias for table user. */
|
||||
const ALIAS_USER = 'u';
|
||||
|
||||
/** Include none of the entries to approve. */
|
||||
const NON_APPROVED_NONE = 'na_none';
|
||||
/** Including all the entries. */
|
||||
const NON_APPROVED_ALL = 'na_all';
|
||||
/** Including only the entries to be approved. */
|
||||
const NON_APPROVED_ONLY = 'na_only';
|
||||
/** Including my entries to be approved. */
|
||||
const NON_APPROVED_SELF = 'na_self';
|
||||
|
||||
/** @var array Raw SQL statements representing the fields to select. */
|
||||
protected $fields = array();
|
||||
/** @var array Raw SQL statements representing the JOINs to make. */
|
||||
protected $joins = array();
|
||||
/** @var string Raw SQL statement representing the FROM clause. */
|
||||
protected $from;
|
||||
/** @var object The glossary we are fetching from. */
|
||||
protected $glossary;
|
||||
/** @var int The number of records to fetch from. */
|
||||
protected $limitfrom = 0;
|
||||
/** @var int The number of records to fetch. */
|
||||
protected $limitnum = 0;
|
||||
/** @var array List of SQL parameters. */
|
||||
protected $params = array();
|
||||
/** @var array Raw SQL statements representing the ORDER clause. */
|
||||
protected $order = array();
|
||||
/** @var array Raw SQL statements representing the WHERE clause. */
|
||||
protected $where = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
*/
|
||||
public function __construct($glossary = null) {
|
||||
$this->from = sprintf('FROM {glossary_entries} %s', self::ALIAS_ENTRIES);
|
||||
if (!empty($glossary)) {
|
||||
$this->glossary = $glossary;
|
||||
$this->where[] = sprintf('(%s.glossaryid = :gid OR %s.sourceglossaryid = :gid2)',
|
||||
self::ALIAS_ENTRIES, self::ALIAS_ENTRIES);
|
||||
$this->params['gid'] = $glossary->id;
|
||||
$this->params['gid2'] = $glossary->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to select.
|
||||
*
|
||||
* @param string $field The field, or *.
|
||||
* @param string $table The table name, without the prefix 'glossary_'.
|
||||
* @param string $alias An alias for the field.
|
||||
*/
|
||||
public function add_field($field, $table, $alias = null) {
|
||||
$field = self::resolve_field($field, $table);
|
||||
if (!empty($alias)) {
|
||||
$field .= ' AS ' . $alias;
|
||||
}
|
||||
$this->fields[] = $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the user fields.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_user_fields() {
|
||||
$this->fields[] = user_picture::fields('u', null, 'userdataid', 'userdata');
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to build the query.
|
||||
*
|
||||
* @param bool $count Query to count?
|
||||
* @return string The SQL statement.
|
||||
*/
|
||||
protected function build_query($count = false) {
|
||||
$sql = 'SELECT ';
|
||||
|
||||
if ($count) {
|
||||
$sql .= 'COUNT(\'x\') ';
|
||||
} else {
|
||||
$sql .= implode(', ', $this->fields) . ' ';
|
||||
}
|
||||
|
||||
$sql .= $this->from . ' ';
|
||||
$sql .= implode(' ', $this->joins) . ' ';
|
||||
|
||||
if (!empty($this->where)) {
|
||||
$sql .= 'WHERE (' . implode(') AND (', $this->where) . ') ';
|
||||
}
|
||||
|
||||
if (!$count && !empty($this->order)) {
|
||||
$sql .= 'ORDER BY ' . implode(', ', $this->order);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the records.
|
||||
*
|
||||
* @return int The number of records.
|
||||
*/
|
||||
public function count_records() {
|
||||
global $DB;
|
||||
return $DB->count_records_sql($this->build_query(true), $this->params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a field using a letter.
|
||||
*
|
||||
* @param string $letter The letter.
|
||||
* @param string $finalfield The SQL statement representing the field.
|
||||
*/
|
||||
protected function filter_by_letter($letter, $finalfield) {
|
||||
global $DB;
|
||||
|
||||
$letter = core_text::strtoupper($letter);
|
||||
$len = core_text::strlen($letter);
|
||||
$sql = $DB->sql_substr(sprintf('upper(%s)', $finalfield), 1, $len);
|
||||
|
||||
$this->where[] = "$sql = :letter";
|
||||
$this->params['letter'] = $letter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a field by special characters.
|
||||
*
|
||||
* @param string $finalfield The SQL statement representing the field.
|
||||
*/
|
||||
protected function filter_by_non_letter($finalfield) {
|
||||
global $DB;
|
||||
|
||||
$alphabet = explode(',', get_string('alphabet', 'langconfig'));
|
||||
list($nia, $aparams) = $DB->get_in_or_equal($alphabet, SQL_PARAMS_NAMED, 'nonletter', false);
|
||||
|
||||
$sql = $DB->sql_substr(sprintf('upper(%s)', $finalfield), 1, 1);
|
||||
|
||||
$this->where[] = "$sql $nia";
|
||||
$this->params = array_merge($this->params, $aparams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the author by letter.
|
||||
*
|
||||
* @param string $letter The letter.
|
||||
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
|
||||
*/
|
||||
public function filter_by_author_letter($letter, $firstnamefirst = false) {
|
||||
$field = self::get_fullname_field($firstnamefirst);
|
||||
$this->filter_by_letter($letter, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the author by special characters.
|
||||
*
|
||||
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
|
||||
*/
|
||||
public function filter_by_author_non_letter($firstnamefirst = false) {
|
||||
$field = self::get_fullname_field($firstnamefirst);
|
||||
$this->filter_by_non_letter($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the concept by letter.
|
||||
*
|
||||
* @param string $letter The letter.
|
||||
*/
|
||||
public function filter_by_concept_letter($letter) {
|
||||
$this->filter_by_letter($letter, self::resolve_field('concept', 'entries'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the concept by special characters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function filter_by_concept_non_letter() {
|
||||
$this->filter_by_non_letter(self::resolve_field('concept', 'entries'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter non approved entries.
|
||||
*
|
||||
* @param string $constant One of the NON_APPROVED_* constants.
|
||||
* @param int $userid The user ID when relevant, otherwise current user.
|
||||
*/
|
||||
public function filter_by_non_approved($constant, $userid = null) {
|
||||
global $USER;
|
||||
if (!$userid) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
|
||||
if ($constant === self::NON_APPROVED_ALL) {
|
||||
// Nothing to do.
|
||||
|
||||
} else if ($constant === self::NON_APPROVED_SELF) {
|
||||
$this->where[] = sprintf('%s != 0 OR %s = :toapproveuserid',
|
||||
self::resolve_field('approved', 'entries'), self::resolve_field('userid', 'entries'));
|
||||
$this->params['toapproveuserid'] = $USER->id;
|
||||
|
||||
} else if ($constant === self::NON_APPROVED_NONE) {
|
||||
$this->where[] = sprintf('%s != 0', self::resolve_field('approved', 'entries'));
|
||||
|
||||
} else if ($constant === self::NON_APPROVED_ONLY) {
|
||||
$this->where[] = sprintf('%s = 0', self::resolve_field('approved', 'entries'));
|
||||
|
||||
} else {
|
||||
throw new coding_exception('Invalid constant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by concept or alias.
|
||||
*
|
||||
* This requires the alias table to be joined in the query. See {@link self::join_alias()}.
|
||||
*
|
||||
* @param string $term What the concept or aliases should be.
|
||||
*/
|
||||
public function filter_by_term($term) {
|
||||
$this->where[] = sprintf("(%s = :filterterma OR %s = :filtertermb)",
|
||||
self::resolve_field('concept', 'entries'),
|
||||
self::resolve_field('alias', 'alias'));
|
||||
$this->params['filterterma'] = $term;
|
||||
$this->params['filtertermb'] = $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get get the SQL statement for the full name.
|
||||
*
|
||||
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
|
||||
* @return string The SQL statement.
|
||||
*/
|
||||
public static function get_fullname_field($firstnamefirst = false) {
|
||||
global $DB;
|
||||
if ($firstnamefirst) {
|
||||
return $DB->sql_fullname(self::resolve_field('firstname', 'user'), self::resolve_field('lastname', 'user'));
|
||||
}
|
||||
return $DB->sql_fullname(self::resolve_field('lastname', 'user'), self::resolve_field('firstname', 'user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the records.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_records() {
|
||||
global $DB;
|
||||
return $DB->get_records_sql($this->build_query(), $this->params, $this->limitfrom, $this->limitnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recordset.
|
||||
*
|
||||
* @return moodle_recordset
|
||||
*/
|
||||
public function get_recordset() {
|
||||
global $DB;
|
||||
return $DB->get_recordset_sql($this->build_query(), $this->params, $this->limitfrom, $this->limitnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a user object from a record.
|
||||
*
|
||||
* This comes handy when {@link self::add_user_fields} was used.
|
||||
*
|
||||
* @param stdClass $record The record.
|
||||
* @return stdClass A user object.
|
||||
*/
|
||||
public static function get_user_from_record($record) {
|
||||
return user_picture::unalias($record, null, 'userdataid', 'userdata');
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the alias table.
|
||||
*
|
||||
* Note that this may cause the same entry to be returned more than once. You might want
|
||||
* to add a distinct on the entry id.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function join_alias() {
|
||||
$this->joins[] = sprintf('LEFT JOIN {glossary_alias} %s ON %s = %s',
|
||||
self::ALIAS_ALIAS, self::resolve_field('id', 'entries'), self::resolve_field('entryid', 'alias'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Join on the category tables.
|
||||
*
|
||||
* Depending on the category passed the joins will be different. This is due to the display
|
||||
* logic that assumes that when displaying all categories the non categorised entries should
|
||||
* not be returned, etc...
|
||||
*
|
||||
* @param int $categoryid The category ID, or GLOSSARY_SHOW_* constant.
|
||||
*/
|
||||
public function join_category($categoryid) {
|
||||
|
||||
if ($categoryid === GLOSSARY_SHOW_ALL_CATEGORIES) {
|
||||
$this->joins[] = sprintf('JOIN {glossary_entries_categories} %s ON %s = %s',
|
||||
self::ALIAS_ENTRIES_CATEGORIES, self::resolve_field('id', 'entries'),
|
||||
self::resolve_field('entryid', 'entries_categories'));
|
||||
|
||||
$this->joins[] = sprintf('JOIN {glossary_categories} %s ON %s = %s',
|
||||
self::ALIAS_CATEGORIES, self::resolve_field('id', 'categories'),
|
||||
self::resolve_field('categoryid', 'entries_categories'));
|
||||
|
||||
} else if ($categoryid === GLOSSARY_SHOW_NOT_CATEGORISED) {
|
||||
$this->joins[] = sprintf('LEFT JOIN {glossary_entries_categories} %s ON %s = %s',
|
||||
self::ALIAS_ENTRIES_CATEGORIES, self::resolve_field('id', 'entries'),
|
||||
self::resolve_field('entryid', 'entries_categories'));
|
||||
|
||||
} else {
|
||||
$this->joins[] = sprintf('JOIN {glossary_entries_categories} %s ON %s = %s AND %s = :joincategoryid',
|
||||
self::ALIAS_ENTRIES_CATEGORIES, self::resolve_field('id', 'entries'),
|
||||
self::resolve_field('entryid', 'entries_categories'),
|
||||
self::resolve_field('categoryid', 'entries_categories'));
|
||||
$this->params['joincategoryid'] = $categoryid;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the user table.
|
||||
*
|
||||
* @param bool $strict When strict uses a JOIN rather than a LEFT JOIN.
|
||||
*/
|
||||
public function join_user($strict = false) {
|
||||
$join = $strict ? 'JOIN' : 'LEFT JOIN';
|
||||
$this->joins[] = sprintf("$join {user} %s ON %s = %s",
|
||||
self::ALIAS_USER, self::resolve_field('id', 'user'), self::resolve_field('userid', 'entries'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the number of records to fetch.
|
||||
* @param int $from Fetch from.
|
||||
* @param int $num Number to fetch.
|
||||
*/
|
||||
public function limit($from, $num) {
|
||||
$this->limitfrom = $from;
|
||||
$this->limitnum = $num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise a direction.
|
||||
*
|
||||
* This ensures that the value is either ASC or DESC.
|
||||
*
|
||||
* @param string $direction The desired direction.
|
||||
* @return string ASC or DESC.
|
||||
*/
|
||||
protected function normalize_direction($direction) {
|
||||
$direction = core_text::strtoupper($direction);
|
||||
if ($direction == 'DESC') {
|
||||
return 'DESC';
|
||||
}
|
||||
return 'ASC';
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by a field.
|
||||
*
|
||||
* @param string $field The field, or *.
|
||||
* @param string $table The table name, without the prefix 'glossary_'.
|
||||
* @param string $direction ASC, or DESC.
|
||||
*/
|
||||
public function order_by($field, $table, $direction = '') {
|
||||
$direction = self::normalize_direction($direction);
|
||||
$this->order[] = self::resolve_field($field, $table) . ' ' . $direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by author name.
|
||||
*
|
||||
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
|
||||
* @param string $direction ASC, or DESC.
|
||||
*/
|
||||
public function order_by_author($firstnamefirst = false, $direction = '') {
|
||||
$field = self::get_fullname_field($firstnamefirst);
|
||||
$direction = self::normalize_direction($direction);
|
||||
$this->order[] = $field . ' ' . $direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to transform a field into SQL statement.
|
||||
*
|
||||
* @param string $field The field, or *.
|
||||
* @param string $table The table name, without the prefix 'glossary_'.
|
||||
* @return string SQL statement.
|
||||
*/
|
||||
protected static function resolve_field($field, $table) {
|
||||
$prefix = constant(__CLASS__ . '::ALIAS_' . core_text::strtoupper($table));
|
||||
return sprintf('%s.%s', $prefix, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple where conditions.
|
||||
*
|
||||
* @param string $field The field, or *.
|
||||
* @param string $table The table name, without the prefix 'glossary_'.
|
||||
* @param mixed $value The value to be equal to.
|
||||
*/
|
||||
public function where($field, $table, $value) {
|
||||
static $i = 0;
|
||||
$sql = self::resolve_field($field, $table) . ' ';
|
||||
|
||||
if ($value === null) {
|
||||
$sql .= 'IS NULL';
|
||||
|
||||
} else {
|
||||
$param = 'where' . $i++;
|
||||
$sql .= " = :$param";
|
||||
$this->params[$param] = $value;
|
||||
}
|
||||
|
||||
$this->where[] = $sql;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,4 +35,108 @@ $functions = array(
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_view_glossary' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'view_glossary',
|
||||
'description' => 'Notify the glossary as being viewed.',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_view_entry' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'view_entry',
|
||||
'description' => 'Notify a glossary entry as being viewed.',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_letter' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_letter',
|
||||
'description' => 'Browse entries by letter.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_date' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_date',
|
||||
'description' => 'Browse entries by date.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_categories' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_categories',
|
||||
'description' => 'Get the categories.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_category' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_category',
|
||||
'description' => 'Browse entries by category.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_authors' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_authors',
|
||||
'description' => 'Get the authors.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_author' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_author',
|
||||
'description' => 'Browse entries by author.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_author_id' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_author_id',
|
||||
'description' => 'Browse entries by author ID.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_search' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_search',
|
||||
'description' => 'Browse entries by search query.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_by_term' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_by_term',
|
||||
'description' => 'Browse entries by term (concept or alias).',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entries_to_approve' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entries_to_approve',
|
||||
'description' => 'Browse entries to be approved.',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:approve'
|
||||
),
|
||||
|
||||
'mod_glossary_get_entry_by_id' => array(
|
||||
'classname' => 'mod_glossary_external',
|
||||
'methodname' => 'get_entry_by_id',
|
||||
'description' => 'Get an entry by ID',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'mod/glossary:view'
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
@@ -3295,3 +3295,597 @@ function glossary_get_visible_tabs($displayformat) {
|
||||
|
||||
return $showtabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that the glossary was viewed.
|
||||
*
|
||||
* This will trigger relevant events and activity completion.
|
||||
*
|
||||
* @param stdClass $glossary The glossary object.
|
||||
* @param stdClass $course The course object.
|
||||
* @param stdClass $cm The course module object.
|
||||
* @param stdClass $context The context object.
|
||||
* @param string $mode The mode in which the glossary was viewed.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_view($glossary, $course, $cm, $context, $mode) {
|
||||
|
||||
// Completion trigger.
|
||||
$completion = new completion_info($course);
|
||||
$completion->set_module_viewed($cm);
|
||||
|
||||
// Trigger the course module viewed event.
|
||||
$event = \mod_glossary\event\course_module_viewed::create(array(
|
||||
'objectid' => $glossary->id,
|
||||
'context' => $context,
|
||||
'other' => array('mode' => $mode)
|
||||
));
|
||||
$event->add_record_snapshot('course', $course);
|
||||
$event->add_record_snapshot('course_modules', $cm);
|
||||
$event->add_record_snapshot('glossary', $glossary);
|
||||
$event->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a glossary entry was viewed.
|
||||
*
|
||||
* This will trigger relevant events.
|
||||
*
|
||||
* @param stdClass $entry The entry object.
|
||||
* @param stdClass $context The context object.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_entry_view($entry, $context) {
|
||||
|
||||
// Trigger the entry viewed event.
|
||||
$event = \mod_glossary\event\entry_viewed::create(array(
|
||||
'objectid' => $entry->id,
|
||||
'context' => $context
|
||||
));
|
||||
$event->add_record_snapshot('glossary_entries', $entry);
|
||||
$event->trigger();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by letter.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param string $letter The letter, or ALL, or SPECIAL.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_letter($glossary, $context, $letter, $from, $limit, $options = array()) {
|
||||
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if ($letter != 'ALL' && $letter != 'SPECIAL' && core_text::strlen($letter)) {
|
||||
$qb->filter_by_concept_letter($letter);
|
||||
}
|
||||
if ($letter == 'SPECIAL') {
|
||||
$qb->filter_by_concept_non_letter();
|
||||
}
|
||||
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ALL);
|
||||
} else {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_SELF);
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_user();
|
||||
$qb->add_user_fields();
|
||||
$qb->order_by('concept', 'entries');
|
||||
$qb->order_by('id', 'entries', 'ASC'); // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by date.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param string $order The mode of ordering: CREATION or UPDATE.
|
||||
* @param string $sort The direction of the ordering: ASC or DESC.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_date($glossary, $context, $order, $sort, $from, $limit, $options = array()) {
|
||||
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ALL);
|
||||
} else {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_SELF);
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_user();
|
||||
$qb->add_user_fields();
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
if ($order == 'CREATION') {
|
||||
$qb->order_by('timecreated', 'entries', $sort);
|
||||
} else {
|
||||
$qb->order_by('timemodified', 'entries', $sort);
|
||||
}
|
||||
$qb->order_by('id', 'entries', $sort); // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by category.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param int $categoryid The category ID, or GLOSSARY_SHOW_* constant.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_category($glossary, $context, $categoryid, $from, $limit, $options = array()) {
|
||||
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ALL);
|
||||
} else {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_SELF);
|
||||
}
|
||||
|
||||
$qb->join_category($categoryid);
|
||||
$qb->join_user();
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->add_field('categoryid', 'entries_categories');
|
||||
$qb->add_user_fields();
|
||||
|
||||
if ($categoryid === GLOSSARY_SHOW_ALL_CATEGORIES) {
|
||||
$qb->add_field('name', 'categories', 'categoryname');
|
||||
$qb->order_by('name', 'categories');
|
||||
|
||||
} else if ($categoryid === GLOSSARY_SHOW_NOT_CATEGORISED) {
|
||||
$qb->where('categoryid', 'entries_categories', null);
|
||||
}
|
||||
|
||||
// Sort on additional fields to avoid random ordering when entries share an ordering value.
|
||||
$qb->order_by('concept', 'entries');
|
||||
$qb->order_by('id', 'entries', 'ASC');
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by author.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param string $letter The letter
|
||||
* @param string $field The field to search: FIRSTNAME or LASTNAME.
|
||||
* @param string $sort The sorting: ASC or DESC.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_author($glossary, $context, $letter, $field, $sort, $from, $limit, $options = array()) {
|
||||
|
||||
$firstnamefirst = $field === 'FIRSTNAME';
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if ($letter != 'ALL' && $letter != 'SPECIAL' && core_text::strlen($letter)) {
|
||||
$qb->filter_by_author_letter($letter, $firstnamefirst);
|
||||
}
|
||||
if ($letter == 'SPECIAL') {
|
||||
$qb->filter_by_author_non_letter($firstnamefirst);
|
||||
}
|
||||
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ALL);
|
||||
} else {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_SELF);
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_user(true);
|
||||
$qb->add_user_fields();
|
||||
$qb->order_by_author($firstnamefirst, $sort);
|
||||
$qb->order_by('concept', 'entries');
|
||||
$qb->order_by('id', 'entries', 'ASC'); // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by category.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param int $authorid The author ID.
|
||||
* @param string $order The mode of ordering: CONCEPT, CREATION or UPDATE.
|
||||
* @param string $sort The direction of the ordering: ASC or DESC.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_author_id($glossary, $context, $authorid, $order, $sort, $from, $limit, $options = array()) {
|
||||
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ALL);
|
||||
} else {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_SELF);
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_user(true);
|
||||
$qb->add_user_fields();
|
||||
$qb->where('id', 'user', $authorid);
|
||||
|
||||
if ($order == 'CREATION') {
|
||||
$qb->order_by('timecreated', 'entries', $sort);
|
||||
} else if ($order == 'UPDATE') {
|
||||
$qb->order_by('timemodified', 'entries', $sort);
|
||||
} else {
|
||||
$qb->order_by('concept', 'entries', $sort);
|
||||
}
|
||||
$qb->order_by('id', 'entries', $sort); // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authors in a glossary
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param int $from Fetch records from.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes self even if all of their entries require approval.
|
||||
* When true, also includes authors only having entries pending approval.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_authors($glossary, $context, $limit, $from, $options = array()) {
|
||||
global $DB, $USER;
|
||||
|
||||
$params = array();
|
||||
$userfields = user_picture::fields('u', null);
|
||||
|
||||
$approvedsql = '(ge.approved <> 0 OR ge.userid = :myid)';
|
||||
$params['myid'] = $USER->id;
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$approvedsql = '1 = 1';
|
||||
}
|
||||
|
||||
$sqlselectcount = "SELECT COUNT(DISTINCT(u.id))";
|
||||
$sqlselect = "SELECT DISTINCT(u.id) AS userId, $userfields";
|
||||
$sql = " FROM {user} u
|
||||
JOIN {glossary_entries} ge
|
||||
ON ge.userid = u.id
|
||||
AND (ge.glossaryid = :gid1 OR ge.sourceglossaryid = :gid2)
|
||||
AND $approvedsql";
|
||||
$ordersql = " ORDER BY u.lastname, u.firstname";
|
||||
|
||||
$params['gid1'] = $glossary->id;
|
||||
$params['gid2'] = $glossary->id;
|
||||
|
||||
$count = $DB->count_records_sql($sqlselectcount . $sql, $params);
|
||||
$users = $DB->get_recordset_sql($sqlselect . $sql . $ordersql, $params, $from, $limit);
|
||||
|
||||
return array($users, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the categories of a glossary.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_categories($glossary, $from, $limit) {
|
||||
global $DB;
|
||||
|
||||
$count = $DB->count_records('glossary_categories', array('glossaryid' => $glossary->id));
|
||||
$categories = $DB->get_recordset('glossary_categories', array('glossaryid' => $glossary->id), 'name ASC', '*', $from, $limit);
|
||||
|
||||
return array($categories, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL where clause for searching terms.
|
||||
*
|
||||
* Note that this does not handle invalid or too short terms.
|
||||
*
|
||||
* @param array $terms Array of terms.
|
||||
* @param bool $fullsearch Whether or not full search should be enabled.
|
||||
* @return array The first element being the where clause, the second array of parameters.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_search_terms_sql(array $terms, $fullsearch = true) {
|
||||
global $DB;
|
||||
static $i = 0;
|
||||
|
||||
if ($DB->sql_regex_supported()) {
|
||||
$regexp = $DB->sql_regex(true);
|
||||
$notregexp = $DB->sql_regex(false);
|
||||
}
|
||||
|
||||
$params = array();
|
||||
$conditions = array();
|
||||
|
||||
foreach ($terms as $searchterm) {
|
||||
$i++;
|
||||
|
||||
$not = false; // Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
|
||||
// will use it to simulate the "-" operator with LIKE clause.
|
||||
|
||||
if (empty($fullsearch)) {
|
||||
// With fullsearch disabled, look only within concepts and aliases.
|
||||
$concat = $DB->sql_concat('ge.concept', "' '", "COALESCE(al.alias, :emptychar{$i})");
|
||||
} else {
|
||||
// With fullsearch enabled, look also within definitions.
|
||||
$concat = $DB->sql_concat('ge.concept', "' '", 'ge.definition', "' '", "COALESCE(al.alias, :emptychar{$i})");
|
||||
}
|
||||
$params['emptychar' . $i] = '';
|
||||
|
||||
// Under Oracle and MSSQL, trim the + and - operators and perform simpler LIKE (or NOT LIKE) queries.
|
||||
if (!$DB->sql_regex_supported()) {
|
||||
if (substr($searchterm, 0, 1) === '-') {
|
||||
$not = true;
|
||||
}
|
||||
$searchterm = trim($searchterm, '+-');
|
||||
}
|
||||
|
||||
if (substr($searchterm, 0, 1) === '+') {
|
||||
$searchterm = trim($searchterm, '+-');
|
||||
$conditions[] = "$concat $regexp :searchterm{$i}";
|
||||
$params['searchterm' . $i] = '(^|[^a-zA-Z0-9])' . preg_quote($searchterm, '|') . '([^a-zA-Z0-9]|$)';
|
||||
|
||||
} else if (substr($searchterm, 0, 1) === "-") {
|
||||
$searchterm = trim($searchterm, '+-');
|
||||
$conditions[] = "$concat $notregexp :searchterm{$i}";
|
||||
$params['searchterm' . $i] = '(^|[^a-zA-Z0-9])' . preg_quote($searchterm, '|') . '([^a-zA-Z0-9]|$)';
|
||||
|
||||
} else {
|
||||
$conditions[] = $DB->sql_like($concat, ":searchterm{$i}", false, true, $not);
|
||||
$params['searchterm' . $i] = '%' . $DB->sql_like_escape($searchterm) . '%';
|
||||
}
|
||||
}
|
||||
|
||||
// When there are no conditions we add a negative one to ensure that we don't return anything.
|
||||
if (empty($conditions)) {
|
||||
$conditions[] = '1 = 2';
|
||||
}
|
||||
|
||||
$where = implode(' AND ', $conditions);
|
||||
return array($where, $params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by search.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param string $query The search query.
|
||||
* @param bool $fullsearch Whether or not full search is required.
|
||||
* @param string $order The mode of ordering: CONCEPT, CREATION or UPDATE.
|
||||
* @param string $sort The direction of the ordering: ASC or DESC.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_search($glossary, $context, $query, $fullsearch, $order, $sort, $from, $limit,
|
||||
$options = array()) {
|
||||
global $DB, $USER;
|
||||
|
||||
// Remove too little terms.
|
||||
$terms = explode(' ', $query);
|
||||
foreach ($terms as $key => $term) {
|
||||
if (strlen(trim($term, '+-')) < 2) {
|
||||
unset($terms[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
list($searchcond, $params) = glossary_get_search_terms_sql($terms, $fullsearch);
|
||||
|
||||
$userfields = user_picture::fields('u', null, 'userdataid', 'userdata');
|
||||
|
||||
// Need one inner view here to avoid distinct + text.
|
||||
$sqlwrapheader = 'SELECT ge.*, ge.concept AS glossarypivot, ' . $userfields . '
|
||||
FROM {glossary_entries} ge
|
||||
LEFT JOIN {user} u ON u.id = ge.userid
|
||||
JOIN ( ';
|
||||
$sqlwrapfooter = ' ) gei ON (ge.id = gei.id)';
|
||||
$sqlselect = "SELECT DISTINCT ge.id";
|
||||
$sqlfrom = "FROM {glossary_entries} ge
|
||||
LEFT JOIN {glossary_alias} al ON al.entryid = ge.id";
|
||||
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$approvedsql = '';
|
||||
} else {
|
||||
$approvedsql = 'AND (ge.approved <> 0 OR ge.userid = :myid)';
|
||||
$params['myid'] = $USER->id;
|
||||
}
|
||||
|
||||
if ($order == 'CREATION') {
|
||||
$sqlorderby = "ORDER BY ge.timecreated $sort";
|
||||
} else if ($order == 'UPDATE') {
|
||||
$sqlorderby = "ORDER BY ge.timemodified $sort";
|
||||
} else {
|
||||
$sqlorderby = "ORDER BY ge.concept $sort";
|
||||
}
|
||||
$sqlorderby .= " , ge.id ASC"; // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
|
||||
$sqlwhere = "WHERE ($searchcond) $approvedsql";
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $DB->count_records_sql("SELECT COUNT(DISTINCT(ge.id)) $sqlfrom $sqlwhere", $params);
|
||||
|
||||
$query = "$sqlwrapheader $sqlselect $sqlfrom $sqlwhere $sqlwrapfooter $sqlorderby";
|
||||
$entries = $DB->get_recordset_sql($query, $params, $from, $limit);
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries of a glossary by term.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param string $term The term we are searching for, a concept or alias.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @param array $options Accepts:
|
||||
* - (bool) includenotapproved. When false, includes the non-approved entries created by
|
||||
* the current user. When true, also includes the ones that the user has the permission to approve.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_term($glossary, $context, $term, $from, $limit, $options = array()) {
|
||||
|
||||
// Build the query.
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if (!empty($options['includenotapproved']) && has_capability('mod/glossary:approve', $context)) {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ALL);
|
||||
} else {
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_SELF);
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_alias();
|
||||
$qb->join_user();
|
||||
$qb->add_user_fields();
|
||||
$qb->filter_by_term($term);
|
||||
|
||||
$qb->order_by('concept', 'entries');
|
||||
$qb->order_by('id', 'entries'); // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries to be approved.
|
||||
*
|
||||
* @param object $glossary The glossary.
|
||||
* @param context $context The context of the glossary.
|
||||
* @param string $letter The letter, or ALL, or SPECIAL.
|
||||
* @param string $order The mode of ordering: CONCEPT, CREATION or UPDATE.
|
||||
* @param string $sort The direction of the ordering: ASC or DESC.
|
||||
* @param int $from Fetch records from.
|
||||
* @param int $limit Number of records to fetch.
|
||||
* @return array The first element being the recordset, the second the number of entries.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_to_approve($glossary, $context, $letter, $order, $sort, $from, $limit) {
|
||||
|
||||
$qb = new mod_glossary_entry_query_builder($glossary);
|
||||
if ($letter != 'ALL' && $letter != 'SPECIAL' && core_text::strlen($letter)) {
|
||||
$qb->filter_by_concept_letter($letter);
|
||||
}
|
||||
if ($letter == 'SPECIAL') {
|
||||
$qb->filter_by_concept_non_letter();
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_user();
|
||||
$qb->add_user_fields();
|
||||
$qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ONLY);
|
||||
if ($order == 'CREATION') {
|
||||
$qb->order_by('timecreated', 'entries', $sort);
|
||||
} else if ($order == 'UPDATE') {
|
||||
$qb->order_by('timemodified', 'entries', $sort);
|
||||
} else {
|
||||
$qb->order_by('concept', 'entries', $sort);
|
||||
}
|
||||
$qb->order_by('id', 'entries', $sort); // Sort on ID to avoid random ordering when entries share an ordering value.
|
||||
$qb->limit($from, $limit);
|
||||
|
||||
// Fetching the entries.
|
||||
$count = $qb->count_records();
|
||||
$entries = $qb->get_recordset();
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an entry.
|
||||
*
|
||||
* @param int $id The entry ID.
|
||||
* @return object|false The entry, or false when not found.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entry_by_id($id) {
|
||||
|
||||
// Build the query.
|
||||
$qb = new mod_glossary_entry_query_builder();
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->join_user();
|
||||
$qb->add_user_fields();
|
||||
$qb->where('id', 'entries', $id);
|
||||
|
||||
// Fetching the entries.
|
||||
$entries = $qb->get_records();
|
||||
if (empty($entries)) {
|
||||
return false;
|
||||
}
|
||||
return array_pop($entries);
|
||||
}
|
||||
|
||||
+20
-16
@@ -187,26 +187,30 @@ echo html_writer::tag('div', $modname, array('class' => 'modname'));
|
||||
if ( $allentries ) {
|
||||
foreach ($allentries as $entry) {
|
||||
|
||||
// Setting the pivot for the current entry
|
||||
$pivot = $entry->glossarypivot;
|
||||
$upperpivot = core_text::strtoupper($pivot);
|
||||
$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
|
||||
// Reduce pivot to 1cc if necessary
|
||||
if ( !$fullpivot ) {
|
||||
$upperpivot = core_text::substr($upperpivot, 0, 1);
|
||||
$pivottoshow = core_text::substr($pivottoshow, 0, 1);
|
||||
}
|
||||
// Setting the pivot for the current entry.
|
||||
if ($printpivot) {
|
||||
|
||||
// If there's group break
|
||||
if ( $currentpivot != $upperpivot ) {
|
||||
if ($userispivot) {
|
||||
$pivot = $entry->userid;
|
||||
} else {
|
||||
$pivot = $pivotfn($entry);
|
||||
}
|
||||
$upperpivot = core_text::strtoupper($pivot);
|
||||
$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
|
||||
|
||||
// print the group break if apply
|
||||
if ( $printpivot ) {
|
||||
// Reduce pivot to 1cc if necessary.
|
||||
if (!$fullpivot) {
|
||||
$upperpivot = core_text::substr($upperpivot, 0, 1);
|
||||
$pivottoshow = core_text::substr($pivottoshow, 0, 1);
|
||||
}
|
||||
|
||||
// If there's a group break.
|
||||
if ($currentpivot != $upperpivot) {
|
||||
$currentpivot = $upperpivot;
|
||||
|
||||
if ( isset($entry->userispivot) ) {
|
||||
// printing the user icon if defined (only when browsing authors)
|
||||
$user = $DB->get_record("user", array("id"=>$entry->userid));
|
||||
if ($userispivot) {
|
||||
// Printing the user icon if defined (only when browsing authors).
|
||||
$user = mod_glossary_entry_query_builder::get_user_from_record($entry);
|
||||
$pivottoshow = fullname($user);
|
||||
}
|
||||
echo html_writer::tag('div', clean_text($pivottoshow), array('class' => 'mdl-align strong'));
|
||||
|
||||
@@ -61,12 +61,7 @@ if ($entries) {
|
||||
}
|
||||
}
|
||||
$entries[$key]->footer = "<p style=\"text-align:right\">» <a href=\"$CFG->wwwroot/mod/glossary/view.php?g=$entry->glossaryid\">".format_string($entry->glossaryname,true)."</a></p>";
|
||||
$event = \mod_glossary\event\entry_viewed::create(array(
|
||||
'objectid' => $entry->id,
|
||||
'context' => $modinfo->cms[$entry->cmid]->context
|
||||
));
|
||||
$event->add_record_snapshot('glossary_entries', $entry);
|
||||
$event->trigger();
|
||||
glossary_entry_view($entry, $modinfo->cms[$entry->cmid]->context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,12 +80,7 @@ if ($entries) {
|
||||
}
|
||||
|
||||
$entries[$key]->footer = "<p style=\"text-align:right\">» <a href=\"$CFG->wwwroot/mod/glossary/view.php?g=$entry->glossaryid\">".format_string($entry->glossaryname,true)."</a></p>";
|
||||
$event = \mod_glossary\event\entry_viewed::create(array(
|
||||
'objectid' => $entry->id,
|
||||
'context' => $modinfo->cms[$entry->cmid]->context
|
||||
));
|
||||
$event->add_record_snapshot('glossary_entries', $entry);
|
||||
$event->trigger();
|
||||
glossary_entry_view($entry, $modinfo->cms[$entry->cmid]->context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+74
-251
@@ -6,281 +6,104 @@
|
||||
* @copyright 2003
|
||||
**/
|
||||
|
||||
/// Creating the SQL statements
|
||||
/**
|
||||
* This file defines, or redefines, the following variables:
|
||||
*
|
||||
* bool $userispivot Whether the user is the pivot.
|
||||
* bool $fullpivot Whether the pivot should be displayed in full.
|
||||
* bool $printpivot Whether the pivot should be displayed.
|
||||
* string $pivotkey The property of the record at which the pivot is.
|
||||
* int $count The number of records matching the request.
|
||||
* array $allentries The entries matching the request.
|
||||
* mixed $field Unset in this file.
|
||||
* mixed $entry Unset in this file.
|
||||
* mixed $canapprove Unset in this file.
|
||||
*
|
||||
* It relies on the following variables:
|
||||
*
|
||||
* object $glossary The glossary object.
|
||||
* context $context The glossary context.
|
||||
* mixed $hook The hook for the selected tab.
|
||||
* string $sortkey The key to sort the records.
|
||||
* string $sortorder The order of the sorting.
|
||||
* int $offset The number of records to skip.
|
||||
* int $entriesbypage The number of entries per page.
|
||||
* string $mode The mode of browsing.
|
||||
* string $tab The tab selected.
|
||||
*/
|
||||
|
||||
/// Initialise some variables
|
||||
$sqlorderby = '';
|
||||
$sqlsortkey = NULL;
|
||||
$userispivot = false;
|
||||
$fullpivot = true;
|
||||
$pivotkey = 'concept';
|
||||
|
||||
// For cases needing inner view
|
||||
$sqlwrapheader = '';
|
||||
$sqlwrapfooter = '';
|
||||
|
||||
/// Calculate the SQL sortkey to be used by the SQL statements later
|
||||
switch ( $sortkey ) {
|
||||
case "CREATION":
|
||||
$sqlsortkey = "timecreated";
|
||||
break;
|
||||
case "UPDATE":
|
||||
$sqlsortkey = "timemodified";
|
||||
break;
|
||||
case "FIRSTNAME":
|
||||
$sqlsortkey = "firstname";
|
||||
break;
|
||||
case "LASTNAME":
|
||||
$sqlsortkey = "lastname";
|
||||
break;
|
||||
}
|
||||
$sqlsortorder = $sortorder;
|
||||
|
||||
/// Pivot is the field that set the break by groups (category, initial, author name, etc)
|
||||
|
||||
/// fullpivot indicate if the whole pivot should be compared agasint the db or just the first letter
|
||||
/// printpivot indicate if the pivot should be printed or not
|
||||
|
||||
$fullpivot = 1;
|
||||
$params = array('gid1'=>$glossary->id, 'gid2'=>$glossary->id, 'myid'=>$USER->id, 'hook'=>$hook);
|
||||
|
||||
$userid = '';
|
||||
if ( isloggedin() ) {
|
||||
$userid = "OR ge.userid = :myid";
|
||||
}
|
||||
switch ($tab) {
|
||||
case GLOSSARY_CATEGORY_VIEW:
|
||||
if ($hook == GLOSSARY_SHOW_ALL_CATEGORIES ) {
|
||||
|
||||
$sqlselect = "SELECT gec.id AS cid, ge.*, gec.entryid, gc.name AS glossarypivot";
|
||||
$sqlfrom = "FROM {glossary_entries} ge,
|
||||
{glossary_entries_categories} gec,
|
||||
{glossary_categories} gc";
|
||||
$sqlwhere = "WHERE (ge.glossaryid = :gid1 OR ge.sourceglossaryid = :gid2) AND
|
||||
ge.id = gec.entryid AND gc.id = gec.categoryid AND
|
||||
(ge.approved <> 0 $userid)";
|
||||
|
||||
$sqlorderby = ' ORDER BY gc.name, ge.concept';
|
||||
|
||||
} elseif ($hook == GLOSSARY_SHOW_NOT_CATEGORISED ) {
|
||||
|
||||
$printpivot = 0;
|
||||
$sqlselect = "SELECT ge.*, concept AS glossarypivot";
|
||||
$sqlfrom = "FROM {glossary_entries} ge LEFT JOIN {glossary_entries_categories} gec
|
||||
ON ge.id = gec.entryid";
|
||||
$sqlwhere = "WHERE (glossaryid = :gid1 OR sourceglossaryid = :gid2) AND
|
||||
(ge.approved <> 0 $userid) AND gec.entryid IS NULL";
|
||||
|
||||
|
||||
$sqlorderby = ' ORDER BY concept';
|
||||
|
||||
} else {
|
||||
|
||||
$printpivot = 0;
|
||||
$sqlselect = "SELECT ge.*, ce.entryid, c.name AS glossarypivot";
|
||||
$sqlfrom = "FROM {glossary_entries} ge, {glossary_entries_categories} ce, {glossary_categories} c";
|
||||
$sqlwhere = "WHERE ge.id = ce.entryid AND ce.categoryid = :hook AND
|
||||
ce.categoryid = c.id AND ge.approved != 0 AND
|
||||
(ge.glossaryid = :gid1 OR ge.sourceglossaryid = :gid2) AND
|
||||
(ge.approved <> 0 $userid)";
|
||||
|
||||
$sqlorderby = ' ORDER BY c.name, ge.concept';
|
||||
|
||||
}
|
||||
break;
|
||||
case GLOSSARY_AUTHOR_VIEW:
|
||||
|
||||
$where = '';
|
||||
$params['hookup'] = core_text::strtoupper($hook);
|
||||
|
||||
if ( $sqlsortkey == 'firstname' ) {
|
||||
$usernamefield = $DB->sql_fullname('u.firstname' , 'u.lastname');
|
||||
} else {
|
||||
$usernamefield = $DB->sql_fullname('u.lastname' , 'u.firstname');
|
||||
}
|
||||
if ($hook != 'ALL' && ($hookstrlen = core_text::strlen($hook))) {
|
||||
$where = "AND " . $DB->sql_substr("upper($usernamefield)", 1, core_text::strlen($hook)) . " = :hookup";
|
||||
}
|
||||
|
||||
$sqlselect = "SELECT ge.*, $usernamefield AS glossarypivot, 1 AS userispivot ";
|
||||
$sqlfrom = "FROM {glossary_entries} ge, {user} u";
|
||||
$sqlwhere = "WHERE ge.userid = u.id AND
|
||||
(ge.approved <> 0 $userid)
|
||||
$where AND
|
||||
(ge.glossaryid = :gid1 OR ge.sourceglossaryid = :gid2)";
|
||||
$sqlorderby = "ORDER BY $usernamefield $sqlsortorder, ge.concept";
|
||||
$userispivot = true;
|
||||
$pivotkey = 'userid';
|
||||
$field = ($sortkey == 'LASTNAME' ? 'LASTNAME' : 'FIRSTNAME');
|
||||
list($allentries, $count) = glossary_get_entries_by_author($glossary, $context, $hook,
|
||||
$field, $sortorder, $offset, $entriesbypage);
|
||||
unset($field);
|
||||
break;
|
||||
case GLOSSARY_APPROVAL_VIEW:
|
||||
$fullpivot = 0;
|
||||
$printpivot = 0;
|
||||
|
||||
$where = '';
|
||||
$params['hookup'] = core_text::strtoupper($hook);
|
||||
|
||||
if ($hook != 'ALL' and $hook != 'SPECIAL' && ($hookstrlen = core_text::strlen($hook))) {
|
||||
$where = "AND " . $DB->sql_substr("upper(concept)", 1, $hookstrlen) . " = :hookup";
|
||||
}
|
||||
|
||||
$sqlselect = "SELECT ge.*, ge.concept AS glossarypivot";
|
||||
$sqlfrom = "FROM {glossary_entries} ge";
|
||||
$sqlwhere = "WHERE (ge.glossaryid = :gid1 OR ge.sourceglossaryid = :gid2) AND
|
||||
ge.approved = 0 $where";
|
||||
|
||||
if ( $sqlsortkey ) {
|
||||
$sqlorderby = "ORDER BY $sqlsortkey $sqlsortorder";
|
||||
} else {
|
||||
$sqlorderby = "ORDER BY ge.concept";
|
||||
case GLOSSARY_CATEGORY_VIEW:
|
||||
$hook = (int) $hook; // Make sure it's properly casted to int.
|
||||
list($allentries, $count) = glossary_get_entries_by_category($glossary, $context, $hook, $offset, $entriesbypage);
|
||||
$pivotkey = 'categoryname';
|
||||
if ($hook != GLOSSARY_SHOW_ALL_CATEGORIES) {
|
||||
$printpivot = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GLOSSARY_DATE_VIEW:
|
||||
$printpivot = 0;
|
||||
$printpivot = false;
|
||||
$field = ($sortkey == 'CREATION' ? 'CREATION' : 'UPDATE');
|
||||
list($allentries, $count) = glossary_get_entries_by_date($glossary, $context, $field, $sortorder,
|
||||
$offset, $entriesbypage);
|
||||
unset($field);
|
||||
break;
|
||||
|
||||
case GLOSSARY_APPROVAL_VIEW:
|
||||
$fullpivot = false;
|
||||
$printpivot = false;
|
||||
list($allentries, $count) = glossary_get_entries_to_approve($glossary, $context, $hook, $sortkey, $sortorder,
|
||||
$offset, $entriesbypage);
|
||||
break;
|
||||
|
||||
case GLOSSARY_STANDARD_VIEW:
|
||||
default:
|
||||
$sqlselect = "SELECT ge.*, ge.concept AS glossarypivot";
|
||||
$sqlfrom = "FROM {glossary_entries} ge";
|
||||
|
||||
$where = '';
|
||||
$fullpivot = 0;
|
||||
|
||||
switch ( $mode ) {
|
||||
$fullpivot = false;
|
||||
switch ($mode) {
|
||||
case 'search':
|
||||
|
||||
if ($DB->sql_regex_supported()) {
|
||||
$REGEXP = $DB->sql_regex(true);
|
||||
$NOTREGEXP = $DB->sql_regex(false);
|
||||
}
|
||||
|
||||
$searchcond = array();
|
||||
$alcond = array();
|
||||
//$params = array();
|
||||
$i = 0;
|
||||
|
||||
$searchterms = explode(" ",$hook);
|
||||
|
||||
foreach ($searchterms as $searchterm) {
|
||||
$i++;
|
||||
|
||||
$NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
|
||||
/// will use it to simulate the "-" operator with LIKE clause
|
||||
|
||||
if (empty($fullsearch)) {
|
||||
// With fullsearch disabled, look only within concepts and aliases.
|
||||
$concat = $DB->sql_concat('ge.concept', "' '", "COALESCE(al.alias, :emptychar".$i.")");
|
||||
} else {
|
||||
// With fullsearch enabled, look also within definitions.
|
||||
$concat = $DB->sql_concat('ge.concept', "' '", 'ge.definition', "' '", "COALESCE(al.alias, :emptychar".$i.")");
|
||||
}
|
||||
$params['emptychar'.$i] = '';
|
||||
|
||||
/// Under Oracle and MSSQL, trim the + and - operators and perform
|
||||
/// simpler LIKE (or NOT LIKE) queries
|
||||
if (!$DB->sql_regex_supported()) {
|
||||
if (substr($searchterm, 0, 1) == '-') {
|
||||
$NOT = true;
|
||||
}
|
||||
$searchterm = trim($searchterm, '+-');
|
||||
}
|
||||
|
||||
if (substr($searchterm,0,1) == '+') {
|
||||
$searchterm = trim($searchterm, '+-');
|
||||
if (core_text::strlen($searchterm) < 2) {
|
||||
continue;
|
||||
}
|
||||
$searchterm = preg_quote($searchterm, '|');
|
||||
$searchcond[] = "$concat $REGEXP :ss$i";
|
||||
$params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)";
|
||||
|
||||
} else if (substr($searchterm,0,1) == "-") {
|
||||
$searchterm = trim($searchterm, '+-');
|
||||
if (core_text::strlen($searchterm) < 2) {
|
||||
continue;
|
||||
}
|
||||
$searchterm = preg_quote($searchterm, '|');
|
||||
$searchcond[] = "$concat $NOTREGEXP :ss$i";
|
||||
$params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)";
|
||||
|
||||
} else {
|
||||
if (core_text::strlen($searchterm) < 2) {
|
||||
continue;
|
||||
}
|
||||
$searchcond[] = $DB->sql_like($concat, ":ss$i", false, true, $NOT);
|
||||
$params['ss'.$i] = "%$searchterm%";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($searchcond)) {
|
||||
$where = "AND 1=2 "; // no search result
|
||||
|
||||
} else {
|
||||
$searchcond = implode(" AND ", $searchcond);
|
||||
|
||||
// Need one inner view here to avoid distinct + text
|
||||
$sqlwrapheader = 'SELECT ge.*, ge.concept AS glossarypivot
|
||||
FROM {glossary_entries} ge
|
||||
JOIN ( ';
|
||||
$sqlwrapfooter = ' ) gei ON (ge.id = gei.id)';
|
||||
|
||||
$sqlselect = "SELECT DISTINCT ge.id";
|
||||
$sqlfrom = "FROM {glossary_entries} ge
|
||||
LEFT JOIN {glossary_alias} al ON al.entryid = ge.id";
|
||||
$where = "AND ($searchcond)";
|
||||
}
|
||||
|
||||
list($allentries, $count) = glossary_get_entries_by_search($glossary, $context, $hook, $fullsearch,
|
||||
$sortkey, $sortorder, $offset, $entriesbypage);
|
||||
break;
|
||||
|
||||
case 'term':
|
||||
$params['hook2'] = $hook;
|
||||
$printpivot = 0;
|
||||
$sqlfrom .= " LEFT JOIN {glossary_alias} ga on ge.id = ga.entryid";
|
||||
$where = "AND (ge.concept = :hook OR ga.alias = :hook2) ";
|
||||
$printpivot = false;
|
||||
list($allentries, $count) = glossary_get_entries_by_term($glossary, $context, $hook, $offset, $entriesbypage);
|
||||
break;
|
||||
|
||||
case 'entry':
|
||||
$printpivot = 0;
|
||||
$where = "AND ge.id = :hook";
|
||||
$printpivot = false;
|
||||
$entry = glossary_get_entry_by_id($hook);
|
||||
$canapprove = has_capability('mod/glossary:approve', $context);
|
||||
if ($entry && ($entry->glossaryid == $glossary->id || $entry->sourceglossaryid != $glossary->id)
|
||||
&& (!empty($entry->approved) || $entry->userid == $USER->id || $canapprove)) {
|
||||
$count = 1;
|
||||
$allentries = array($entry);
|
||||
} else {
|
||||
$count = 0;
|
||||
$allentries = array();
|
||||
}
|
||||
unset($entry, $canapprove);
|
||||
break;
|
||||
|
||||
case 'letter':
|
||||
if ($hook != 'ALL' and $hook != 'SPECIAL' and ($hookstrlen = core_text::strlen($hook))) {
|
||||
$params['hookup'] = core_text::strtoupper($hook);
|
||||
$where = "AND " . $DB->sql_substr("upper(concept)", 1, $hookstrlen) . " = :hookup";
|
||||
}
|
||||
if ($hook == 'SPECIAL') {
|
||||
//Create appropiate IN contents
|
||||
$alphabet = explode(",", get_string('alphabet', 'langconfig'));
|
||||
list($nia, $aparams) = $DB->get_in_or_equal($alphabet, SQL_PARAMS_NAMED, $start='a', false);
|
||||
$params = array_merge($params, $aparams);
|
||||
$where = "AND " . $DB->sql_substr("upper(concept)", 1, 1) . " $nia";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$sqlwhere = "WHERE (ge.glossaryid = :gid1 or ge.sourceglossaryid = :gid2) AND
|
||||
(ge.approved <> 0 $userid)
|
||||
$where";
|
||||
switch ( $tab ) {
|
||||
case GLOSSARY_DATE_VIEW:
|
||||
$sqlorderby = "ORDER BY $sqlsortkey $sqlsortorder";
|
||||
break;
|
||||
|
||||
case GLOSSARY_STANDARD_VIEW:
|
||||
$sqlorderby = "ORDER BY ge.concept";
|
||||
default:
|
||||
list($allentries, $count) = glossary_get_entries_by_letter($glossary, $context, $hook, $offset, $entriesbypage);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
if ($tab == GLOSSARY_CATEGORY_VIEW && $hook == GLOSSARY_SHOW_ALL_CATEGORIES) {
|
||||
$count = $DB->count_records_sql("SELECT COUNT(ge.id) $sqlfrom $sqlwhere", $params);
|
||||
} else {
|
||||
$count = $DB->count_records_sql("SELECT COUNT(DISTINCT(ge.id)) $sqlfrom $sqlwhere", $params);
|
||||
}
|
||||
|
||||
$limitfrom = $offset;
|
||||
$limitnum = 0;
|
||||
|
||||
if ( $offset >= 0 ) {
|
||||
$limitnum = $entriesbypage;
|
||||
}
|
||||
|
||||
$query = "$sqlwrapheader $sqlselect $sqlfrom $sqlwhere $sqlwrapfooter $sqlorderby";
|
||||
$allentries = $DB->get_records_sql($query, $params, $limitfrom, $limitnum);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Glossary lib tests.
|
||||
*
|
||||
* @package mod_glossary
|
||||
* @copyright 2015 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/glossary/lib.php');
|
||||
|
||||
/**
|
||||
* Glossary lib testcase.
|
||||
*
|
||||
* @package mod_glossary
|
||||
* @copyright 2015 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_glossary_lib_testcase extends advanced_testcase {
|
||||
|
||||
public function test_glossary_view() {
|
||||
global $CFG;
|
||||
$origcompletion = $CFG->enablecompletion;
|
||||
$CFG->enablecompletion = true;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Generate all the things.
|
||||
$c1 = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
|
||||
$g1 = $this->getDataGenerator()->create_module('glossary', array(
|
||||
'course' => $c1->id,
|
||||
'completion' => COMPLETION_TRACKING_AUTOMATIC,
|
||||
'completionview' => 1
|
||||
));
|
||||
$g2 = $this->getDataGenerator()->create_module('glossary', array(
|
||||
'course' => $c1->id,
|
||||
'completion' => COMPLETION_TRACKING_AUTOMATIC,
|
||||
'completionview' => 1
|
||||
));
|
||||
$u1 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($u1->id, $c1->id);
|
||||
$modinfo = course_modinfo::instance($c1->id);
|
||||
$cm1 = $modinfo->get_cm($g1->cmid);
|
||||
$cm2 = $modinfo->get_cm($g2->cmid);
|
||||
$ctx1 = $cm1->context;
|
||||
$completion = new completion_info($c1);
|
||||
|
||||
$this->setUser($u1);
|
||||
|
||||
// Confirm what we've set up.
|
||||
$this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm1, false, $u1->id)->viewed);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm1, false, $u1->id)->completionstate);
|
||||
$this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm2, false, $u1->id)->viewed);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm2, false, $u1->id)->completionstate);
|
||||
|
||||
// Simulate the view call.
|
||||
$sink = $this->redirectEvents();
|
||||
glossary_view($g1, $c1, $cm1, $ctx1, 'letter');
|
||||
$events = $sink->get_events();
|
||||
|
||||
// Assertions.
|
||||
$this->assertCount(3, $events);
|
||||
$this->assertEquals('\core\event\course_module_completion_updated', $events[0]->eventname);
|
||||
$this->assertEquals('\core\event\course_module_completion_updated', $events[1]->eventname);
|
||||
$this->assertEquals('\mod_glossary\event\course_module_viewed', $events[2]->eventname);
|
||||
$this->assertEquals($g1->id, $events[2]->objectid);
|
||||
$this->assertEquals('letter', $events[2]->other['mode']);
|
||||
$this->assertEquals(COMPLETION_VIEWED, $completion->get_data($cm1, false, $u1->id)->viewed);
|
||||
$this->assertEquals(COMPLETION_COMPLETE, $completion->get_data($cm1, false, $u1->id)->completionstate);
|
||||
$this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm2, false, $u1->id)->viewed);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm2, false, $u1->id)->completionstate);
|
||||
|
||||
// Tear down.
|
||||
$sink->close();
|
||||
$CFG->enablecompletion = $origcompletion;
|
||||
}
|
||||
|
||||
public function test_glossary_entry_view() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Generate all the things.
|
||||
$gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id));
|
||||
$e1 = $gg->create_content($g1);
|
||||
$u1 = $this->getDataGenerator()->create_user();
|
||||
$ctx = context_module::instance($g1->cmid);
|
||||
$this->getDataGenerator()->enrol_user($u1->id, $c1->id);
|
||||
|
||||
// Assertions.
|
||||
$sink = $this->redirectEvents();
|
||||
glossary_entry_view($e1, $ctx);
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$this->assertEquals('\mod_glossary\event\entry_viewed', $events[0]->eventname);
|
||||
$this->assertEquals($e1->id, $events[0]->objectid);
|
||||
$sink->close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111601; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2015111605; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version
|
||||
$plugin->component = 'mod_glossary'; // Full name of the plugin (used for diagnostics)
|
||||
$plugin->cron = 0;
|
||||
|
||||
+16
-29
@@ -255,19 +255,7 @@ break;
|
||||
}
|
||||
|
||||
// Trigger module viewed event.
|
||||
$event = \mod_glossary\event\course_module_viewed::create(array(
|
||||
'objectid' => $glossary->id,
|
||||
'context' => $context,
|
||||
'other' => array('mode' => $mode)
|
||||
));
|
||||
$event->add_record_snapshot('course', $course);
|
||||
$event->add_record_snapshot('course_modules', $cm);
|
||||
$event->add_record_snapshot('glossary', $glossary);
|
||||
$event->trigger();
|
||||
|
||||
// Mark as viewed
|
||||
$completion = new completion_info($course);
|
||||
$completion->set_module_viewed($cm);
|
||||
glossary_view($glossary, $course, $cm, $context, $mode);
|
||||
|
||||
/// Printing the heading
|
||||
$strglossaries = get_string("modulenameplural", "glossary");
|
||||
@@ -459,31 +447,31 @@ if ($allentries) {
|
||||
foreach ($allentries as $entry) {
|
||||
|
||||
// Setting the pivot for the current entry
|
||||
$pivot = $entry->glossarypivot;
|
||||
$upperpivot = core_text::strtoupper($pivot);
|
||||
$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
|
||||
// Reduce pivot to 1cc if necessary
|
||||
if ( !$fullpivot ) {
|
||||
$upperpivot = core_text::substr($upperpivot, 0, 1);
|
||||
$pivottoshow = core_text::substr($pivottoshow, 0, 1);
|
||||
}
|
||||
if ($printpivot) {
|
||||
$pivot = $entry->{$pivotkey};
|
||||
$upperpivot = core_text::strtoupper($pivot);
|
||||
$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
|
||||
|
||||
// if there's a group break
|
||||
if ( $currentpivot != $upperpivot ) {
|
||||
// Reduce pivot to 1cc if necessary.
|
||||
if (!$fullpivot) {
|
||||
$upperpivot = core_text::substr($upperpivot, 0, 1);
|
||||
$pivottoshow = core_text::substr($pivottoshow, 0, 1);
|
||||
}
|
||||
|
||||
// print the group break if apply
|
||||
if ( $printpivot ) {
|
||||
// If there's a group break.
|
||||
if ($currentpivot != $upperpivot) {
|
||||
$currentpivot = $upperpivot;
|
||||
|
||||
// print the group break if apply
|
||||
|
||||
echo '<div>';
|
||||
echo '<table cellspacing="0" class="glossarycategoryheader">';
|
||||
|
||||
echo '<tr>';
|
||||
if ( isset($entry->userispivot) ) {
|
||||
if ($userispivot) {
|
||||
// printing the user icon if defined (only when browsing authors)
|
||||
echo '<th align="left">';
|
||||
|
||||
$user = $DB->get_record("user", array("id"=>$entry->userid));
|
||||
$user = mod_glossary_entry_query_builder::get_user_from_record($entry);
|
||||
echo $OUTPUT->user_picture($user, array('courseid'=>$course->id));
|
||||
$pivottoshow = fullname($user, has_capability('moodle/site:viewfullnames', context_course::instance($course->id)));
|
||||
} else {
|
||||
@@ -492,7 +480,6 @@ if ($allentries) {
|
||||
|
||||
echo $OUTPUT->heading($pivottoshow, 3);
|
||||
echo "</th></tr></table></div>\n";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2015123100.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2015123100.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user