mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 13:38:32 +01:00
MDL-51119 glossary: Allow multilang concepts.
This commit is contained in:
parent
ab5692acdf
commit
9e791db25a
@ -81,75 +81,92 @@ class block_glossary_random extends block_base {
|
||||
|
||||
$glossaryctx = context_module::instance($cm->id);
|
||||
|
||||
$limitfrom = 0;
|
||||
$limitnum = 1;
|
||||
$entries = $DB->get_records_sql('SELECT id, concept, definition, definitionformat, definitiontrust
|
||||
FROM {glossary_entries}
|
||||
WHERE glossaryid = ? AND approved = 1
|
||||
ORDER BY timemodified ASC', [$this->config->glossary]);
|
||||
|
||||
$orderby = 'timemodified ASC';
|
||||
if (empty($entries)) {
|
||||
$text = get_string('noentriesyet', 'block_glossary_random');
|
||||
} else {
|
||||
// Now picking out the correct entry from the array.
|
||||
switch ($this->config->type) {
|
||||
case BGR_RANDOMLY:
|
||||
$i = ($numberofentries > 1) ? rand(1, $numberofentries) : 1;
|
||||
if (count($entries) == 1) {
|
||||
$entry = reset($entries);
|
||||
} else {
|
||||
$entry = $entries[$i - 1];
|
||||
}
|
||||
break;
|
||||
|
||||
switch ($this->config->type) {
|
||||
case BGR_NEXTONE:
|
||||
// The array is already sorted by last modified.
|
||||
if (isset($this->config->previous)) {
|
||||
$i = $this->config->previous + 1;
|
||||
} else {
|
||||
$i = 1;
|
||||
}
|
||||
if ($i > $numberofentries) { // Loop back to beginning.
|
||||
$i = 1;
|
||||
}
|
||||
if (count($entries) == 1) {
|
||||
$entry = reset($entries);
|
||||
} else {
|
||||
$entry = $entries[$i - 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case BGR_RANDOMLY:
|
||||
$i = ($numberofentries > 1) ? rand(1, $numberofentries) : 1;
|
||||
$limitfrom = $i-1;
|
||||
break;
|
||||
case BGR_NEXTALPHA:
|
||||
// Now sort the array in regard to the current language.
|
||||
usort($entries, function($a, $b) {
|
||||
return format_string($a->concept) <=> format_string($b->concept);
|
||||
});
|
||||
if (isset($this->config->previous)) {
|
||||
$i = $this->config->previous + 1;
|
||||
} else {
|
||||
$i = 1;
|
||||
}
|
||||
if ($i > $numberofentries) { // Loop back to beginning.
|
||||
$i = 1;
|
||||
}
|
||||
if (count($entries) == 1) {
|
||||
$entry = $entries;
|
||||
} else {
|
||||
$entry = $entries[$i - 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case BGR_NEXTONE:
|
||||
if (isset($this->config->previous)) {
|
||||
$i = $this->config->previous + 1;
|
||||
} else {
|
||||
$i = 1;
|
||||
}
|
||||
if ($i > $numberofentries) { // Loop back to beginning
|
||||
$i = 1;
|
||||
}
|
||||
$limitfrom = $i-1;
|
||||
break;
|
||||
|
||||
case BGR_NEXTALPHA:
|
||||
$orderby = 'concept ASC';
|
||||
if (isset($this->config->previous)) {
|
||||
$i = $this->config->previous + 1;
|
||||
} else {
|
||||
$i = 1;
|
||||
}
|
||||
if ($i > $numberofentries) { // Loop back to beginning
|
||||
$i = 1;
|
||||
}
|
||||
$limitfrom = $i-1;
|
||||
break;
|
||||
|
||||
default: // BGR_LASTMODIFIED
|
||||
$i = $numberofentries;
|
||||
$limitfrom = 0;
|
||||
$orderby = 'timemodified DESC, id DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($entry = $DB->get_records_sql("SELECT id, concept, definition, definitionformat, definitiontrust
|
||||
FROM {glossary_entries}
|
||||
WHERE glossaryid = ? AND approved = 1
|
||||
ORDER BY $orderby", array($this->config->glossary), $limitfrom, $limitnum)) {
|
||||
|
||||
$entry = reset($entry);
|
||||
|
||||
if (empty($this->config->showconcept)) {
|
||||
default: // BGR_LASTMODIFIED
|
||||
// The array is already sorted by last modified.
|
||||
$i = $numberofentries;
|
||||
if (count($entries) == 1) {
|
||||
$entry = reset($entries);
|
||||
} else {
|
||||
$entry = array_pop($entries);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (empty($this->config->showconcept) || (!isset($entry->concept))) {
|
||||
$text = '';
|
||||
} else {
|
||||
$text = "<h3>".format_string($entry->concept,true)."</h3>";
|
||||
$text = "<h3>" . format_string($entry->concept, true, ["context" => $glossaryctx]) . "</h3>";
|
||||
}
|
||||
|
||||
$options = new stdClass();
|
||||
$options->trusted = $entry->definitiontrust;
|
||||
if (isset($entry->definitiontrust)) {
|
||||
$options->trusted = $entry->definitiontrust;
|
||||
}
|
||||
$options->overflowdiv = true;
|
||||
$entry->definition = file_rewrite_pluginfile_urls($entry->definition, 'pluginfile.php', $glossaryctx->id, 'mod_glossary', 'entry', $entry->id);
|
||||
$text .= format_text($entry->definition, $entry->definitionformat, $options);
|
||||
|
||||
if (isset($entry->definitiontrust) && isset($entry->id) && isset($entry->definition)) {
|
||||
$entry->definition = file_rewrite_pluginfile_urls($entry->definition, 'pluginfile.php', $glossaryctx->id,
|
||||
'mod_glossary', 'entry', $entry->id);
|
||||
$text .= format_text($entry->definition, $entry->definitionformat, $options);
|
||||
}
|
||||
$this->config->nexttime = usergetmidnight(time()) + DAYSECS * $this->config->refresh;
|
||||
$this->config->previous = $i;
|
||||
|
||||
} else {
|
||||
$text = get_string('noentriesyet','block_glossary_random');
|
||||
}
|
||||
|
||||
// store the text
|
||||
$this->config->cache = $text;
|
||||
$this->instance_config_commit();
|
||||
|
@ -8,6 +8,14 @@ Feature: Add the glossary random block when main feature is enabled
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I am on the "C1" "course" page logged in as "admin"
|
||||
|
||||
Scenario: The glossary random block can be added when glossary module is enabled
|
||||
@ -21,3 +29,32 @@ Feature: Add the glossary random block when main feature is enabled
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I click on "Add a block" "link"
|
||||
Then I should not see "Random glossary entry"
|
||||
|
||||
Scenario: View alphabetical order multilang entries in the glossary block
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | defaultapproval |
|
||||
| glossary | Animals | An animal glossary | C1 | glossary3 | 1 |
|
||||
And the following "mod_glossary > entries" exist:
|
||||
| glossary | user | concept | definition |
|
||||
| Animals | student1 | Aardvark | <span lang="en" class="multilang">Aardvark</span><span lang="de" class="multilang">Erdferkel</span> |
|
||||
| Animals | student1 | Kangaroo | <span lang="en" class="multilang">Kangaroo</span><span lang="de" class="multilang">Känguru</span> |
|
||||
| Animals | student1 | Zebra | <span lang="en" class="multilang">Zebra</span><span lang="de" class="multilang">Zebra</span> |
|
||||
And the "multilang" filter is "on"
|
||||
And the "multilang" filter applies to "content and headings"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "C1" course homepage with editing mode on
|
||||
And I add the "Random glossary entry..." block
|
||||
And I set the following fields to these values:
|
||||
| Title | ManualGlossaryblock |
|
||||
| Take entries from this glossary | Animals |
|
||||
| Days before a new entry is chosen | 0 |
|
||||
| How a new entry is chosen | Alphabetical order |
|
||||
And I press "Save changes"
|
||||
And I should see "Aardvark" in the "ManualGlossaryblock" "block"
|
||||
And I should not see "AardvarkErdferkel" in the "ManualGlossaryblock" "block"
|
||||
And I reload the page
|
||||
And I should see "Kangaroo" in the "ManualGlossaryblock" "block"
|
||||
And I reload the page
|
||||
Then I should see "Zebra" in the "ManualGlossaryblock" "block"
|
||||
And I log out
|
||||
|
@ -29,8 +29,6 @@ use stdClass;
|
||||
/**
|
||||
* This filter provides automatic linking to glossary entries, aliases and categories when found inside every Moodle text.
|
||||
*
|
||||
* NOTE: multilang glossary entries are not compatible with this filter.
|
||||
*
|
||||
* @package filter_glossary
|
||||
* @copyright 2004 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@ -92,7 +90,7 @@ class text_filter extends \core_filters\text_filter {
|
||||
foreach ($allconcepts as $concepts) {
|
||||
foreach ($concepts as $concept) {
|
||||
$conceptlist[] = new filter_object(
|
||||
$concept->concept,
|
||||
format_string($concept->concept, true, ['context' => $this->context]),
|
||||
null,
|
||||
null,
|
||||
$concept->casesensitive,
|
||||
@ -148,7 +146,9 @@ class text_filter extends \core_filters\text_filter {
|
||||
$title = get_string(
|
||||
'glossaryconcept',
|
||||
'filter_glossary',
|
||||
['glossary' => $glossaries[$concept->glossaryid], 'concept' => $concept->concept]
|
||||
['glossary' => replace_ampersands_not_followed_by_entity(strip_tags(format_string($glossaries[$concept->glossaryid],
|
||||
true, ['context' => $this->context]))),
|
||||
'concept' => format_string($concept->concept, true, ['context' => $this->context])]
|
||||
);
|
||||
// Hardcoding dictionary format in the URL rather than defaulting
|
||||
// to the current glossary format which may not work in a popup.
|
||||
|
@ -216,24 +216,6 @@ class mod_glossary_entry_query_builder {
|
||||
$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.
|
||||
*
|
||||
@ -273,11 +255,11 @@ class mod_glossary_entry_query_builder {
|
||||
* @param string $term What the concept or aliases should be.
|
||||
*/
|
||||
public function filter_by_term($term) {
|
||||
$this->where[] = sprintf("(%s = :filterterma OR %s = :filtertermb)",
|
||||
$this->where[] = sprintf("(%s LIKE :filterterma OR %s LIKE :filtertermb)",
|
||||
self::resolve_field('concept', 'entries'),
|
||||
self::resolve_field('alias', 'alias'));
|
||||
$this->params['filterterma'] = $term;
|
||||
$this->params['filtertermb'] = $term;
|
||||
$this->params['filterterma'] = "%" . $term . "%";
|
||||
$this->params['filtertermb'] = "%" . $term . "%";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,7 +148,8 @@ class mod_glossary_external extends external_api {
|
||||
$context,
|
||||
'mod_glossary',
|
||||
'entry',
|
||||
$entry->id
|
||||
$entry->id,
|
||||
['trusted' => true],
|
||||
);
|
||||
|
||||
// Author details.
|
||||
|
@ -122,9 +122,9 @@ class concept_cache {
|
||||
$concepts = array();
|
||||
$rs = $DB->get_recordset_sql($sql);
|
||||
foreach ($rs as $concept) {
|
||||
$currentconcept = trim(strip_tags($concept->concept));
|
||||
$currentconcept = trim($concept->concept);
|
||||
|
||||
// Concept must be HTML-escaped, so do the same as format_string to turn ampersands into &.
|
||||
// Turn ampersands into & but keep HTML format for filters.
|
||||
$currentconcept = replace_ampersands_not_followed_by_entity($currentconcept);
|
||||
|
||||
if (empty($currentconcept)) {
|
||||
@ -188,7 +188,7 @@ class concept_cache {
|
||||
}
|
||||
foreach ($glossaries as $id => $name) {
|
||||
$name = str_replace(':', '-', $name);
|
||||
$glossaries[$id] = replace_ampersands_not_followed_by_entity(strip_tags($name));
|
||||
$glossaries[$id] = $name;
|
||||
}
|
||||
|
||||
$allconcepts = self::fetch_concepts(array_keys($glossaries));
|
||||
@ -254,7 +254,7 @@ class concept_cache {
|
||||
}
|
||||
foreach ($glossaries as $id => $name) {
|
||||
$name = str_replace(':', '-', $name);
|
||||
$glossaries[$id] = replace_ampersands_not_followed_by_entity(strip_tags($name));
|
||||
$glossaries[$id] = replace_ampersands_not_followed_by_entity($name);
|
||||
}
|
||||
$allconcepts = self::fetch_concepts(array_keys($glossaries));
|
||||
foreach ($glossaries as $gid => $unused) {
|
||||
|
@ -120,7 +120,7 @@ if ( $hook >0 ) {
|
||||
echo $OUTPUT->heading(format_string($glossary->name), 2);
|
||||
echo $OUTPUT->heading(format_string(get_string("editcategory", "glossary")), 3);
|
||||
|
||||
$name = $category->name;
|
||||
$name = format_string($category->name, true, ['context' => $context]);
|
||||
$usedynalink = $category->usedynalink;
|
||||
require "editcategories.html";
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -3452,18 +3452,13 @@ function glossary_entry_view($entry, $context) {
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @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);
|
||||
@ -3476,12 +3471,59 @@ function glossary_get_entries_by_letter($glossary, $context, $letter, $from, $li
|
||||
$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();
|
||||
// Fetching the entries. Those are all entries.
|
||||
$entries = $qb->get_records();
|
||||
|
||||
// Now sorting out the array.
|
||||
$filteredentries = [];
|
||||
|
||||
if ($letter != 'ALL' && $letter != 'SPECIAL' && core_text::strlen($letter)) {
|
||||
// Build a new array with the filtered entries.
|
||||
foreach ($entries as $key => $entry) {
|
||||
if (strtoupper(substr(format_string($entry->concept), 0, 1)) === strtoupper($letter)) {
|
||||
// Add it when starting with the correct letter.
|
||||
$filteredentries[$key] = $entry;
|
||||
}
|
||||
}
|
||||
$entries = $filteredentries;
|
||||
}
|
||||
|
||||
if ($letter == 'SPECIAL') {
|
||||
// Build a new array with the filtered entries.
|
||||
foreach ($entries as $key => $entry) {
|
||||
if (!ctype_alpha(substr(format_string($entry->concept), 0, 1))) {
|
||||
// Add it when starting with a non-letter character.
|
||||
$filteredentries[$key] = $entry;
|
||||
}
|
||||
}
|
||||
$entries = $filteredentries;
|
||||
}
|
||||
|
||||
if ($letter == 'ALL') {
|
||||
// No filtering needed.
|
||||
$filteredentries = $entries;
|
||||
}
|
||||
|
||||
// Now sort the array in regard to the current language.
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return format_string($a->concept) <=> format_string($b->concept);
|
||||
});
|
||||
|
||||
// Size of the overall array.
|
||||
$count = count($entries);
|
||||
|
||||
// Now applying limit.
|
||||
if (isset($limit)) {
|
||||
if (isset($from)) {
|
||||
$entries = array_slice($filteredentries, $from, $limit);
|
||||
} else {
|
||||
$entries = array_slice($filteredentries);
|
||||
}
|
||||
} else {
|
||||
$entries = $filteredentries;
|
||||
}
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
@ -3497,7 +3539,8 @@ function glossary_get_entries_by_letter($glossary, $context, $letter, $from, $li
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_date($glossary, $context, $order, $sort, $from, $limit, $options = array()) {
|
||||
@ -3539,7 +3582,8 @@ function glossary_get_entries_by_date($glossary, $context, $order, $sort, $from,
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_category($glossary, $context, $categoryid, $from, $limit, $options = array()) {
|
||||
@ -3596,7 +3640,8 @@ function glossary_get_entries_by_category($glossary, $context, $categoryid, $fro
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_author($glossary, $context, $letter, $field, $sort, $from, $limit, $options = array()) {
|
||||
@ -3644,7 +3689,8 @@ function glossary_get_entries_by_author($glossary, $context, $letter, $field, $s
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_author_id($glossary, $context, $authorid, $order, $sort, $from, $limit, $options = array()) {
|
||||
@ -3689,7 +3735,8 @@ function glossary_get_entries_by_author_id($glossary, $context, $authorid, $orde
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_authors($glossary, $context, $limit, $from, $options = array()) {
|
||||
@ -3729,7 +3776,8 @@ function glossary_get_authors($glossary, $context, $limit, $from, $options = arr
|
||||
* @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.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_categories($glossary, $from, $limit) {
|
||||
@ -3833,7 +3881,8 @@ function glossary_get_search_terms_sql(array $terms, $fullsearch = true, $glossa
|
||||
* @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 array of results, the second the number of entries.
|
||||
* @return array The first element being the recordset (taking into account the limit), the second the number of entries the overall
|
||||
* array has.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
function glossary_get_entries_by_search($glossary, $context, $query, $fullsearch, $order, $sort, $from, $limit,
|
||||
@ -3915,6 +3964,7 @@ function glossary_get_entries_by_term($glossary, $context, $term, $from, $limit,
|
||||
}
|
||||
|
||||
$qb->add_field('*', 'entries');
|
||||
$qb->add_field('alias', 'alias');
|
||||
$qb->join_alias();
|
||||
$qb->join_user();
|
||||
$qb->add_user_fields();
|
||||
@ -3922,12 +3972,46 @@ function glossary_get_entries_by_term($glossary, $context, $term, $from, $limit,
|
||||
|
||||
$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();
|
||||
// Fetching the entries. Those are all entries.
|
||||
$entries = $qb->get_records();
|
||||
|
||||
// Now sorting out the array.
|
||||
$filteredentries = [];
|
||||
|
||||
// Now sorting out the array.
|
||||
foreach ($entries as $key => $entry) {
|
||||
if (strtoupper(format_string($entry->concept)) === strtoupper($term)) {
|
||||
// Add it when matching concept or alias.
|
||||
$filteredentries[$key] = $entry;
|
||||
}
|
||||
if ((isset($entry->alias)) && (strtoupper(format_string($entry->alias)) === strtoupper($term))) {
|
||||
// Add it when matching concept or alias.
|
||||
$filteredentries[$key] = $entry;
|
||||
}
|
||||
}
|
||||
$entries = $filteredentries;
|
||||
// Check whether concept or alias match the term.
|
||||
|
||||
// Now sort the array in regard to the current language.
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return format_string($a->concept) <=> format_string($b->concept);
|
||||
});
|
||||
|
||||
// Size of the overall array.
|
||||
$count = count($entries);
|
||||
|
||||
// Now applying limit.
|
||||
if (isset($limit)) {
|
||||
if (isset($from)) {
|
||||
$entries = array_slice($filteredentries, $from, $limit);
|
||||
} else {
|
||||
$entries = array_slice($filteredentries);
|
||||
}
|
||||
} else {
|
||||
$entries = $filteredentries;
|
||||
}
|
||||
|
||||
return array($entries, $count);
|
||||
}
|
||||
|
||||
@ -3947,32 +4031,87 @@ function glossary_get_entries_by_term($glossary, $context, $term, $from, $limit,
|
||||
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();
|
||||
// Fetching the entries. Those are all non approved entries.
|
||||
$entries = $qb->get_records();
|
||||
|
||||
return array($entries, $count);
|
||||
// Size of the overall array.
|
||||
$count = count($entries);
|
||||
|
||||
// If a some filter is set, restrict by that filter.
|
||||
$filteredentries = [];
|
||||
|
||||
if ($letter != 'ALL' && $letter != 'SPECIAL' && core_text::strlen($letter)) {
|
||||
// Build a new array with the filtered entries.
|
||||
foreach ($entries as $key => $entry) {
|
||||
if (strtoupper(substr(format_string($entry->concept), 0, 1)) === strtoupper($letter)) {
|
||||
// Add it when starting with the correct letter.
|
||||
$filteredentries[$key] = $entry;
|
||||
}
|
||||
}
|
||||
} else if ($letter == 'SPECIAL') {
|
||||
// Build a new array with the filtered entries.
|
||||
foreach ($entries as $key => $entry) {
|
||||
if (!ctype_alpha(substr(format_string($entry->concept), 0, 1))) {
|
||||
// Add it when starting with a non-letter character.
|
||||
$filteredentries[$key] = $entry;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No filtering needed (This means CONCEPT).
|
||||
$filteredentries = $entries;
|
||||
}
|
||||
|
||||
// Now sort the array in regard to the current language.
|
||||
if ($order == 'CREATION') {
|
||||
if ($sort == "DESC") {
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return $b->timecreated <=> $a->timecreated;
|
||||
});
|
||||
} else {
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return $a->timecreated <=> $b->timecreated;
|
||||
});
|
||||
}
|
||||
} else if ($order == 'UPDATE') {
|
||||
if ($sort == "DESC") {
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return $b->timemodified <=> $a->timemodified;
|
||||
});
|
||||
} else {
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return $a->timemodified <=> $b->timemodified;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// This means CONCEPT.
|
||||
if ($sort == "DESC") {
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return format_string($b->concept) <=> format_string($a->concept);
|
||||
});
|
||||
} else {
|
||||
usort($filteredentries, function($a, $b) {
|
||||
return format_string($a->concept) <=> format_string($b->concept);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Now applying limit.
|
||||
if (isset($limit)) {
|
||||
$count = count($filteredentries);
|
||||
if (isset($from)) {
|
||||
$filteredentries = array_slice($filteredentries, $from, $limit);
|
||||
} else {
|
||||
$filteredentries = array_slice($filteredentries, 0, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
return [$filteredentries, $count];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,7 @@ if ($eid) {
|
||||
$entry->glossaryname = $glossary->name;
|
||||
$entry->cmid = $cm->id;
|
||||
$entry->courseid = $cm->course;
|
||||
$entry->concept = format_string($entry->concept, true, ["escape" => false]);
|
||||
$entries = array($entry);
|
||||
|
||||
} else if ($concept) {
|
||||
|
@ -69,7 +69,7 @@ class behat_mod_glossary extends behat_base {
|
||||
|
||||
$this->execute("behat_forms::press_button", get_string('addcategory', 'glossary'));
|
||||
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('name', $this->escape($categoryname)));
|
||||
$this->execute('behat_forms::i_set_the_field_to', ['name', $categoryname]);
|
||||
|
||||
$this->execute("behat_forms::press_button", get_string('savechanges'));
|
||||
$this->execute("behat_forms::press_button", get_string('back', 'mod_glossary'));
|
||||
|
53
mod/glossary/tests/behat/glossary_autolink.feature
Normal file
53
mod/glossary/tests/behat/glossary_autolink.feature
Normal file
@ -0,0 +1,53 @@
|
||||
@mod @mod_glossary
|
||||
Feature: Glossary can set autolinked entries in text and media areas
|
||||
In order to display the glossary entries for concepts in texts
|
||||
As a teacher
|
||||
I can set the glossary activity to autolink the entries
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | displayformat | course | idnumber |
|
||||
| glossary | Test <span class="multilang" lang="en">glossary</span><span class="multilang" lang="fr">glossaire</span><span class="multilang" lang="es">glossario</span> | Test glossary description | encyclopedia | C1 | glossary1 |
|
||||
And the following "mod_glossary > entries" exist:
|
||||
| glossary | concept | definition | usedynalink |
|
||||
| glossary1 | <span class="multilang" lang="en">English</span><span class="multilang" lang="fr">Anglais</span><span class="multilang" lang="es">inglés</span> | <span class="multilang" lang="en">Relating to England, its people, or the language spoken there.</span><span class="multilang" lang="fr">Relatif à l'Angleterre, à son peuple ou à la langue parlée là-bas.</span><span class="multilang" lang="es">Relacionado con Inglaterra, su gente o el idioma hablado allí.</span> | 1 |
|
||||
| glossary1 | <span class="multilang" lang="en">Spanish</span><span class="multilang" lang="fr">Espagnol</span><span class="multilang" lang="es">Castellano</span> | <span class="multilang" lang="en">Relating to Spain, its people, or the language spoken there.</span><span class="multilang" lang="fr">Relatif à l'Espagne, à son peuple ou à la langue parlée là-bas.</span><span class="multilang" lang="es">Relacionado con España, su gente o el idioma hablado allí.</span> | 1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| label | Text and media area | <p>This is a text with the multilang syntax on the <span class="multilang" lang="en">English</span><span class="multilang" lang="fr">Anglais</span><span class="multilang" lang="es">Inglés</span> word that should be auto-linked.</p><p>This are plain text words that should also be auto-linked: English, Anglais, Inglés.</p> | C1 | label1 |
|
||||
And the "glossary" filter is "on"
|
||||
And the following "language pack" exists:
|
||||
| language | fr | es |
|
||||
And the "multilang" filter is "on"
|
||||
And the "multilang" filter applies to "content and headings"
|
||||
|
||||
@javascript
|
||||
Scenario: Glossary entries show up in text and media areas in the correct user interface/language combination
|
||||
When I am on the "Course 1" course page logged in as teacher1
|
||||
Then "English" "link" should exist in the ".modtype_label" "css_element"
|
||||
And "Anglais" "link" should not exist in the ".modtype_label" "css_element"
|
||||
And "Inglés" "link" should not exist in the ".modtype_label" "css_element"
|
||||
And the "title" attribute of ".glossary.autolink" "css_element" should contain "Test glossary: English"
|
||||
And I follow "Language" in the user menu
|
||||
And I click on "//a[contains(@href, 'lang=es')]" "xpath"
|
||||
Then "English" "link" should not exist in the ".modtype_label" "css_element"
|
||||
And "Anglais" "link" should not exist in the ".modtype_label" "css_element"
|
||||
And "Inglés" "link" should exist in the ".modtype_label" "css_element"
|
||||
And the "title" attribute of ".glossary.autolink" "css_element" should contain "Test glossario: inglés"
|
||||
And I follow "Idioma" in the user menu
|
||||
And I click on "//a[contains(@href, 'lang=fr')]" "xpath"
|
||||
Then "English" "link" should not exist in the ".modtype_label" "css_element"
|
||||
And "Anglais" "link" should exist in the ".modtype_label" "css_element"
|
||||
And "Inglés" "link" should not exist in the ".modtype_label" "css_element"
|
||||
And the "title" attribute of ".glossary.autolink" "css_element" should contain "Test glossaire : Anglais"
|
@ -20,13 +20,18 @@ Feature: Glossary entries can be searched or browsed by alphabet, category, date
|
||||
| activity | name | intro | displayformat | course | idnumber |
|
||||
| glossary | Test glossary name | Test glossary description | fullwithauthor | C1 | g1 |
|
||||
And the following "mod_glossary > categories" exist:
|
||||
| glossary | name |
|
||||
| g1 | The ones I like |
|
||||
| g1 | All for you |
|
||||
| glossary | name |
|
||||
| g1 | <span lang=\"en\" class=\"multilang\">The ones I like</span><span lang=\"fr\" class=\"multilang\">Ceux qui me plaisent</span> |
|
||||
| g1 | <span lang=\"en\" class=\"multilang\">All for you</span><span lang=\"fr\" class=\"multilang\">Tout pour toi</span> |
|
||||
|
||||
And the following "mod_glossary > entries" exist:
|
||||
| glossary | concept | definition | user | categories |
|
||||
| g1 | Eggplant | Sour eggplants | teacher1 | All for you |
|
||||
| g1 | Cucumber | Sweet cucumber | student1 | The ones I like |
|
||||
| glossary | concept | definition | user | categories |
|
||||
| g1 | <span lang="en" class="multilang">Eggplant</span><span lang="fr" class="multilang">Aubergine</span> | <span lang="en" class="multilang">Sour eggplants</span><span lang="fr" class="multilang">Aubergines aigres</span> | teacher1 | <span lang=\"en\" class=\"multilang\">All for you</span><span lang=\"fr\" class=\"multilang\">Tout pour toi</span> |
|
||||
| g1 | 7up | <span lang="en" class="multilang">7up is a softdrink</span><span lang="fr" class="multilang">7up est une boisson</span> | teacher1 | <span lang=\"en\" class=\"multilang\">The ones I like</span><span lang=\"fr\" class=\"multilang\">Ceux qui me plaisent</span> |
|
||||
| g1 | <span lang="en" class="multilang">Cucumber</span><span lang="fr" class="multilang">Concombre</span> | <span lang="en" class="multilang">Sweet cucumber</span><span lang="fr" class="multilang">Doux concombre</span> | student1 | <span lang=\"en\" class=\"multilang\">The ones I like</span><span lang=\"fr\" class=\"multilang\">Ceux qui me plaisent</span> |
|
||||
And the "multilang" filter is "on"
|
||||
And the "multilang" filter applies to "content and headings"
|
||||
And I log out
|
||||
And I am on the "Test glossary name" "glossary activity" page logged in as teacher1
|
||||
|
||||
@javascript
|
||||
@ -35,13 +40,35 @@ Feature: Glossary entries can be searched or browsed by alphabet, category, date
|
||||
And I press "Search"
|
||||
Then I should see "Sweet cucumber"
|
||||
And I should see "Search: cucumber"
|
||||
And I set the field "hook" to "aubergine"
|
||||
And I press "Search"
|
||||
And I should see "Sour eggplants"
|
||||
And I should see "Search: aubergine"
|
||||
And I should see "E" in the ".glossarycategoryheader" "css_element"
|
||||
And I click on "E" "link" in the ".entrybox" "css_element"
|
||||
And I should see "Sour eggplants"
|
||||
And I should not see "Sweet cucumber"
|
||||
And I should not see "No entries found in this section"
|
||||
And I click on "Special" "link" in the ".entrybox" "css_element"
|
||||
And I should see "7up"
|
||||
And I should not see "Sweet cucumber"
|
||||
And I should not see "Sour eggplants"
|
||||
And I should not see "No entries found in this section"
|
||||
And I click on "X" "link" in the ".entrybox" "css_element"
|
||||
And I should not see "Sweet cucumber"
|
||||
And I should see "No entries found in this section"
|
||||
|
||||
@javascript
|
||||
Scenario: Search by keyword and browse by alphabet when several multilang entries can be found
|
||||
When I add a glossary entry with the following data:
|
||||
| Concept | <span lang="de" class="multilang">Concombre</span><span lang="en" class="multilang">Cucumber</span> |
|
||||
| Definition | <span lang="fr" class="multilang">Doux concombre</span><span lang="en" class="multilang">Sweet cucumber alternate entry</span> |
|
||||
And I set the field "hook" to "cucumber"
|
||||
And I press "Search"
|
||||
Then I should see "Sweet cucumber"
|
||||
And I should see "Sweet cucumber alternate entry"
|
||||
And I should see "Search: cucumber"
|
||||
|
||||
@javascript
|
||||
Scenario: Browse by category
|
||||
When I select "Browse by category" from the "Browse the glossary using this index" singleselect
|
||||
|
129
mod/glossary/tests/external/external_test.php
vendored
129
mod/glossary/tests/external/external_test.php
vendored
@ -367,7 +367,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Ordering including to approve.
|
||||
$return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 0, 20,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
|
||||
$this->assertCount(4, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
@ -378,14 +378,14 @@ final class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Ordering including to approve and pagination.
|
||||
$return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 0, 2,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
$this->assertEquals($e1a->id, $return['entries'][0]['id']);
|
||||
$this->assertEquals($e1c->id, $return['entries'][1]['id']);
|
||||
$return = mod_glossary_external::get_entries_by_date($g1->id, 'CREATION', 'ASC', 2, 2,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_date_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
@ -480,7 +480,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Including to approve.
|
||||
$return = mod_glossary_external::get_entries_by_category($g1->id, $cat1b->id, 0, 20,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(2, $return['count']);
|
||||
@ -489,7 +489,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Using limit.
|
||||
$return = mod_glossary_external::get_entries_by_category($g1->id, GLOSSARY_SHOW_ALL_CATEGORIES, 0, 3,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
|
||||
$this->assertCount(3, $return['entries']);
|
||||
$this->assertEquals(6, $return['count']);
|
||||
@ -497,7 +497,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$this->assertEquals($e1b2->id, $return['entries'][1]['id']);
|
||||
$this->assertEquals($e1a1->id, $return['entries'][2]['id']);
|
||||
$return = mod_glossary_external::get_entries_by_category($g1->id, GLOSSARY_SHOW_ALL_CATEGORIES, 3, 2,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_category_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(6, $return['count']);
|
||||
@ -536,7 +536,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$this->assertEquals($u1->id, $return['authors'][1]['id']);
|
||||
|
||||
// Include users with entries pending approval.
|
||||
$return = mod_glossary_external::get_authors($g1->id, 0, 20, array('includenotapproved' => true));
|
||||
$return = mod_glossary_external::get_authors($g1->id, 0, 20, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_authors_returns(), $return);
|
||||
$this->assertCount(3, $return['authors']);
|
||||
$this->assertEquals(3, $return['count']);
|
||||
@ -545,7 +545,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$this->assertEquals($u1->id, $return['authors'][2]['id']);
|
||||
|
||||
// Pagination.
|
||||
$return = mod_glossary_external::get_authors($g1->id, 1, 1, array('includenotapproved' => true));
|
||||
$return = mod_glossary_external::get_authors($g1->id, 1, 1, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_authors_returns(), $return);
|
||||
$this->assertCount(1, $return['authors']);
|
||||
$this->assertEquals(3, $return['count']);
|
||||
@ -613,7 +613,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
// Including non-approved.
|
||||
$this->setAdminUser();
|
||||
$return = mod_glossary_external::get_entries_by_author($g1->id, 'ALL', 'LASTNAME', 'ASC', 0, 20,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_returns(), $return);
|
||||
$this->assertCount(7, $return['entries']);
|
||||
$this->assertEquals(7, $return['count']);
|
||||
@ -750,7 +750,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Including non approved.
|
||||
$return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 0, 20,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
|
||||
$this->assertCount(4, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
@ -761,14 +761,14 @@ final class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Pagination.
|
||||
$return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 0, 2,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
$this->assertEquals($e1a2->id, $return['entries'][0]['id']);
|
||||
$this->assertEquals($e1a4->id, $return['entries'][1]['id']);
|
||||
$return = mod_glossary_external::get_entries_by_author_id($g1->id, $u1->id, 'CONCEPT', 'ASC', 1, 2,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_author_id_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
@ -872,7 +872,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
// Including not approved.
|
||||
$query = 'ou';
|
||||
$return = mod_glossary_external::get_entries_by_search($g1->id, $query, false, 'CONCEPT', 'ASC', 0, 20,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
|
||||
$this->assertCount(4, $return['entries']);
|
||||
$this->assertEquals(4, $return['count']);
|
||||
@ -884,7 +884,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
// Advanced query string.
|
||||
$query = '+Heroes -Abcd';
|
||||
$return = mod_glossary_external::get_entries_by_search($g1->id, $query, true, 'CONCEPT', 'ASC', 0, 20,
|
||||
array('includenotapproved' => true));
|
||||
['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_search_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(2, $return['count']);
|
||||
@ -914,7 +914,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$e5 = $gg->create_content($g2, array('userid' => $u1->id, 'approved' => 1, 'concept' => 'dog'), array('cat'));
|
||||
|
||||
// Search concept + alias.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'cat', 0, 20, array('includenotapproved' => false));
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'cat', 0, 20, ['includenotapproved' => false]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(2, $return['count']);
|
||||
@ -933,7 +933,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
|
||||
// Search alias.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, array('includenotapproved' => false));
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, ['includenotapproved' => false]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
|
||||
$this->assertCount(2, $return['entries']);
|
||||
@ -944,7 +944,7 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
|
||||
// Search including not approved.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, array('includenotapproved' => true));
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(3, $return['entries']);
|
||||
$this->assertEquals(3, $return['count']);
|
||||
@ -954,13 +954,104 @@ final class external_test extends externallib_advanced_testcase {
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
|
||||
// Pagination.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 1, array('includenotapproved' => true));
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 1, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(1, $return['entries']);
|
||||
// We don't compare the returned entry id because it may be different depending on the DBMS,
|
||||
// for example, Postgres does a random sorting in this case.
|
||||
$this->assertEquals(3, $return['count']);
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 1, 1, array('includenotapproved' => true));
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 1, 1, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(1, $return['entries']);
|
||||
$this->assertEquals(3, $return['count']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_entries_by_multilingual_term.
|
||||
*
|
||||
* @covers \mod_glossary_external::get_entries_by_term
|
||||
* @return void
|
||||
* @throws \coding_exception
|
||||
* @throws \invalid_response_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function test_get_entries_by_multilingual_term(): void {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Enable multilang filter to on content and heading.
|
||||
filter_set_global_state('multilang', TEXTFILTER_ON);
|
||||
filter_set_applies_to_strings('multilang', 1);
|
||||
|
||||
// Generate all the things.
|
||||
$gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$g1 = $this->getDataGenerator()->create_module('glossary', ['course' => $c1->id]);
|
||||
$g2 = $this->getDataGenerator()->create_module('glossary', ['course' => $c1->id]);
|
||||
$u1 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($u1->id, $c1->id);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$e1 = $gg->create_content($g1, ['userid' => $u1->id, 'approved' => 1, 'concept' => '<span lang="en" ' .
|
||||
'class="multilang">cat</span><span lang="fr" class="multilang">chat</span>', 'tags' => ['Cats', 'Dogs']]);
|
||||
$e2 = $gg->create_content($g1, ['userid' => $u1->id, 'approved' => 1], ['<span lang="en" class="' .
|
||||
'multilang">cat</span><span lang="fr" class="multilang">chat</span>', '<span lang="en" class="multilang">' .
|
||||
'dog</span><span lang="fr" class="multilang">chien</span>']);
|
||||
$e3 = $gg->create_content($g1, ['userid' => $u1->id, 'approved' => 1], ['<span lang="en" class="' .
|
||||
'multilang">dog</span><span lang="fr" class="multilang">chien</span>']);
|
||||
$e4 = $gg->create_content($g1, ['userid' => $u1->id, 'approved' => 0, 'concept' => '<span lang="en" class="' .
|
||||
'multilang">dog</span><span lang="fr" class="multilang">chien</span>']);
|
||||
$e5 = $gg->create_content($g2, ['userid' => $u1->id, 'approved' => 1, 'concept' => '<span lang="en" class="' .
|
||||
'multilang">cog</span><span lang="fr" class="multilang">chien</span>'], ['cat']);
|
||||
|
||||
// Search concept + alias.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'cat', 0, 20, ['includenotapproved' => false]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(2, $return['count']);
|
||||
// Compare ids, ignore ordering of array, using canonicalize parameter of assertEquals.
|
||||
$expected = [$e1->id, $e2->id];
|
||||
$actual = [$return['entries'][0]['id'], $return['entries'][1]['id']];
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
// Compare rawnames of all expected tags, ignore ordering of array, using canonicalize parameter of assertEquals.
|
||||
$expected = ['Cats', 'Dogs']; // Only $e1 has 2 tags.
|
||||
$actual = []; // Accumulate all tags returned.
|
||||
foreach ($return['entries'] as $entry) {
|
||||
foreach ($entry['tags'] as $tag) {
|
||||
$actual[] = $tag['rawname'];
|
||||
}
|
||||
}
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
|
||||
// Search alias.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, ['includenotapproved' => false]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
|
||||
$this->assertCount(2, $return['entries']);
|
||||
$this->assertEquals(2, $return['count']);
|
||||
// Compare ids, ignore ordering of array, using canonicalize parameter of assertEquals.
|
||||
$expected = [$e2->id, $e3->id];
|
||||
$actual = [$return['entries'][0]['id'], $return['entries'][1]['id']];
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
|
||||
// Search including not approved.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(3, $return['entries']);
|
||||
$this->assertEquals(3, $return['count']);
|
||||
// Compare ids, ignore ordering of array, using canonicalize parameter of assertEquals.
|
||||
$expected = [$e4->id, $e2->id, $e3->id];
|
||||
$actual = [$return['entries'][0]['id'], $return['entries'][1]['id'], $return['entries'][2]['id']];
|
||||
$this->assertEqualsCanonicalizing($expected, $actual);
|
||||
|
||||
// Pagination.
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 1, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(1, $return['entries']);
|
||||
// We don't compare the returned entry id because it may be different depending on the DBMS,
|
||||
// for example, Postgres does a random sorting in this case.
|
||||
$this->assertEquals(3, $return['count']);
|
||||
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 1, 1, ['includenotapproved' => true]);
|
||||
$return = external_api::clean_returnvalue(mod_glossary_external::get_entries_by_term_returns(), $return);
|
||||
$this->assertCount(1, $return['entries']);
|
||||
$this->assertEquals(3, $return['count']);
|
||||
|
@ -418,7 +418,7 @@ if ($allentries) {
|
||||
|
||||
// Setting the pivot for the current entry
|
||||
if ($printpivot) {
|
||||
$pivot = $entry->{$pivotkey};
|
||||
$pivot = format_string($entry->{$pivotkey}, false, ["context" => $context]);
|
||||
$upperpivot = core_text::strtoupper($pivot);
|
||||
$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user