mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 14:03:52 +01:00
MDL-78879 reportbuilder: allow for negation of category filter.
Add "Equal to" and "Not equal to" operators to the filter class. AMOS BEGIN CPY [subcats,qtype_randomsamatch],[includesubcategories,moodle] AMOS END
This commit is contained in:
parent
a1d5d1b2f7
commit
501a170cb6
@ -22,6 +22,7 @@ use context_course;
|
||||
use core_reportbuilder_testcase;
|
||||
use core_reportbuilder_generator;
|
||||
use core_reportbuilder\local\filters\boolean_select;
|
||||
use core_reportbuilder\local\filters\category;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\filters\select;
|
||||
use core_reportbuilder\local\filters\tags;
|
||||
@ -219,6 +220,11 @@ class courses_test extends core_reportbuilder_testcase {
|
||||
return [
|
||||
// Category.
|
||||
'Filter category' => ['course_category:name', [
|
||||
'course_category:name_operator' => category::NOT_EQUAL_TO,
|
||||
'course_category:name_value' => -1,
|
||||
], true],
|
||||
'Filter category (no match)' => ['course_category:name', [
|
||||
'course_category:name_operator' => category::EQUAL_TO,
|
||||
'course_category:name_value' => -1,
|
||||
], false],
|
||||
'Filter category name' => ['course_category:text', [
|
||||
|
@ -1118,6 +1118,7 @@ $string['includeneededusers'] = 'Include needed users';
|
||||
$string['includenoneusers'] = 'Include no users';
|
||||
$string['includeroleassignments'] = 'Include role assignments';
|
||||
$string['includesitefiles'] = 'Include site files used in this course';
|
||||
$string['includesubcategories'] = 'Include subcategories';
|
||||
$string['includeuserfiles'] = 'Include user files';
|
||||
$string['increasesections'] = 'Increase the number of sections';
|
||||
$string['indicator:accessesafterend'] = 'Course accessed after end date';
|
||||
|
@ -19,6 +19,7 @@ declare(strict_types=1);
|
||||
namespace core_reportbuilder\local\filters;
|
||||
|
||||
use core_course_category;
|
||||
use lang_string;
|
||||
use MoodleQuickForm;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
|
||||
@ -36,20 +37,43 @@ use core_reportbuilder\local\helpers\database;
|
||||
*/
|
||||
class category extends base {
|
||||
|
||||
/** @var int Category is equal to */
|
||||
public const EQUAL_TO = 0;
|
||||
|
||||
/** @var int Category is not equal to */
|
||||
public const NOT_EQUAL_TO = 1;
|
||||
|
||||
/**
|
||||
* Returns an array of comparison operators
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_operators(): array {
|
||||
$operators = [
|
||||
self::EQUAL_TO => new lang_string('filterisequalto', 'core_reportbuilder'),
|
||||
self::NOT_EQUAL_TO => new lang_string('filterisnotequalto', 'core_reportbuilder'),
|
||||
];
|
||||
|
||||
return $this->filter->restrict_limited_operators($operators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup form
|
||||
*
|
||||
* @param MoodleQuickForm $mform
|
||||
*/
|
||||
public function setup_form(MoodleQuickForm $mform): void {
|
||||
$label = get_string('filterfieldvalue', 'core_reportbuilder', $this->get_header());
|
||||
$operatorlabel = get_string('filterfieldoperator', 'core_reportbuilder', $this->get_header());
|
||||
$mform->addElement('select', "{$this->name}_operator", $operatorlabel, $this->get_operators())
|
||||
->setHiddenLabel(true);
|
||||
|
||||
// See MDL-74627: in order to set the default value to "No selection" we need to prepend an empty value.
|
||||
$requiredcapabilities = $this->filter->get_options()['requiredcapabilities'] ?? '';
|
||||
$categories = [0 => ''] + core_course_category::make_categories_list($requiredcapabilities);
|
||||
|
||||
$mform->addElement('autocomplete', "{$this->name}_value", $label, $categories)->setHiddenLabel(true);
|
||||
$mform->addElement('advcheckbox', "{$this->name}_subcategories", get_string('viewallsubcategories'));
|
||||
$valuelabel = get_string('filterfieldvalue', 'core_reportbuilder', $this->get_header());
|
||||
$mform->addElement('autocomplete', "{$this->name}_value", $valuelabel, $categories)->setHiddenLabel(true);
|
||||
$mform->addElement('advcheckbox', "{$this->name}_subcategories", get_string('includesubcategories'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,6 +87,7 @@ class category extends base {
|
||||
|
||||
[$fieldsql, $params] = $this->filter->get_field_sql_and_params();
|
||||
|
||||
$operator = (int) ($values["{$this->name}_operator"] ?? self::EQUAL_TO);
|
||||
$category = (int) ($values["{$this->name}_value"] ?? 0);
|
||||
$subcategories = !empty($values["{$this->name}_subcategories"]);
|
||||
|
||||
@ -92,6 +117,11 @@ class category extends base {
|
||||
)";
|
||||
}
|
||||
|
||||
// If specified "Not equal to", then negate the entire clause.
|
||||
if ($operator === self::NOT_EQUAL_TO) {
|
||||
$sql = "NOT ({$sql})";
|
||||
}
|
||||
|
||||
return [$sql, $params];
|
||||
}
|
||||
|
||||
|
@ -40,11 +40,20 @@ class category_test extends advanced_testcase {
|
||||
*/
|
||||
public function get_sql_filter_provider(): array {
|
||||
return [
|
||||
['One', false, ['One']],
|
||||
['One', true, ['One', 'Two', 'Three']],
|
||||
['Two', true, ['Two', 'Three']],
|
||||
['Three', true, ['Three']],
|
||||
[null, false, ['Category 1', 'One', 'Two', 'Three']],
|
||||
// Equal to.
|
||||
['One', category::EQUAL_TO, false, ['One']],
|
||||
['One', category::EQUAL_TO, true, ['One', 'Two', 'Three']],
|
||||
['Two', category::EQUAL_TO, true, ['Two', 'Three']],
|
||||
['Three', category::EQUAL_TO, true, ['Three']],
|
||||
|
||||
// Not equal to.
|
||||
['One', category::NOT_EQUAL_TO, false, ['Category 1', 'Two', 'Three', 'Four', 'Five', 'Six']],
|
||||
['One', category::NOT_EQUAL_TO, true, ['Category 1', 'Four', 'Five', 'Six']],
|
||||
['Two', category::NOT_EQUAL_TO, true, ['Category 1', 'One', 'Four', 'Five', 'Six']],
|
||||
['Three', category::NOT_EQUAL_TO, true, ['Category 1', 'One', 'Two', 'Four', 'Five', 'Six']],
|
||||
|
||||
// Default/empty state.
|
||||
[null, category::EQUAL_TO, false, ['Category 1', 'One', 'Two', 'Three', 'Four', 'Five', 'Six']],
|
||||
];
|
||||
}
|
||||
|
||||
@ -52,20 +61,33 @@ class category_test extends advanced_testcase {
|
||||
* Test getting filter SQL
|
||||
*
|
||||
* @param string|null $categoryname
|
||||
* @param int $operator
|
||||
* @param bool $subcategories
|
||||
* @param string[] $expectedcategories
|
||||
*
|
||||
* @dataProvider get_sql_filter_provider
|
||||
*/
|
||||
public function test_get_sql_filter(?string $categoryname, bool $subcategories, array $expectedcategories): void {
|
||||
public function test_get_sql_filter(
|
||||
?string $categoryname,
|
||||
int $operator,
|
||||
bool $subcategories,
|
||||
array $expectedcategories,
|
||||
): void {
|
||||
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create category tree "One -> Two -> Three".
|
||||
$category1 = $this->getDataGenerator()->create_category(['name' => 'One']);
|
||||
$category2 = $this->getDataGenerator()->create_category(['name' => 'Two', 'parent' => $category1->id]);
|
||||
$category3 = $this->getDataGenerator()->create_category(['name' => 'Three', 'parent' => $category2->id]);
|
||||
|
||||
// Second category tree "Four -> Five -> Six".
|
||||
$category4 = $this->getDataGenerator()->create_category(['name' => 'Four']);
|
||||
$category5 = $this->getDataGenerator()->create_category(['name' => 'Five', 'parent' => $category4->id]);
|
||||
$category6 = $this->getDataGenerator()->create_category(['name' => 'Six', 'parent' => $category5->id]);
|
||||
|
||||
if ($categoryname !== null) {
|
||||
$categoryid = $DB->get_field('course_categories', 'id', ['name' => $categoryname], MUST_EXIST);
|
||||
} else {
|
||||
@ -82,6 +104,7 @@ class category_test extends advanced_testcase {
|
||||
|
||||
// Create instance of our filter, passing given operator.
|
||||
[$select, $params] = category::create($filter)->get_sql_filter([
|
||||
$filter->get_unique_identifier() . '_operator' => $operator,
|
||||
$filter->get_unique_identifier() . '_value' => $categoryid,
|
||||
$filter->get_unique_identifier() . '_subcategories' => $subcategories,
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user