Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Class provider_test
  19   *
  20   * @package     core_customfield
  21   * @copyright   2019 Marina Glancy
  22   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  namespace core_customfield\privacy;
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  use core_privacy\tests\provider_testcase;
  29  use core_privacy\local\request\approved_contextlist;
  30  use core_privacy\local\request\writer;
  31  use core_customfield\privacy\provider;
  32  
  33  /**
  34   * Class provider_test
  35   *
  36   * @package     core_customfield
  37   * @copyright   2019 Marina Glancy
  38   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class provider_test extends provider_testcase {
  41  
  42      /**
  43       * Generate data.
  44       *
  45       * @return array
  46       */
  47      protected function generate_test_data(): array {
  48          $this->resetAfterTest();
  49  
  50          $generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
  51          $cfcats[1] = $generator->create_category();
  52          $cfcats[2] = $generator->create_category();
  53          $cffields[11] = $generator->create_field(
  54              ['categoryid' => $cfcats[1]->get('id'), 'type' => 'checkbox']);
  55          $cffields[12] = $generator->create_field(
  56              ['categoryid' => $cfcats[1]->get('id'), 'type' => 'date']);
  57          $cffields[13] = $generator->create_field(
  58              ['categoryid' => $cfcats[1]->get('id'),
  59              'type' => 'select', 'configdata' => ['options' => "a\nb\nc"]]);
  60          $cffields[14] = $generator->create_field(
  61              ['categoryid' => $cfcats[1]->get('id'), 'type' => 'text']);
  62          $cffields[15] = $generator->create_field(
  63              ['categoryid' => $cfcats[1]->get('id'), 'type' => 'textarea']);
  64          $cffields[21] = $generator->create_field(
  65              ['categoryid' => $cfcats[2]->get('id')]);
  66          $cffields[22] = $generator->create_field(
  67              ['categoryid' => $cfcats[2]->get('id')]);
  68  
  69          $courses[1] = $this->getDataGenerator()->create_course();
  70          $courses[2] = $this->getDataGenerator()->create_course();
  71          $courses[3] = $this->getDataGenerator()->create_course();
  72  
  73          $generator->add_instance_data($cffields[11], $courses[1]->id, 1);
  74          $generator->add_instance_data($cffields[12], $courses[1]->id, 1546300800);
  75          $generator->add_instance_data($cffields[13], $courses[1]->id, 2);
  76          $generator->add_instance_data($cffields[14], $courses[1]->id, 'Hello1');
  77          $generator->add_instance_data($cffields[15], $courses[1]->id,
  78              ['text' => '<p>Hi there</p>', 'format' => FORMAT_HTML]);
  79  
  80          $generator->add_instance_data($cffields[21], $courses[1]->id, 'hihi1');
  81  
  82          $generator->add_instance_data($cffields[14], $courses[2]->id, 'Hello2');
  83  
  84          $generator->add_instance_data($cffields[21], $courses[2]->id, 'hihi2');
  85  
  86          $user = $this->getDataGenerator()->create_user();
  87          $this->setUser($user);
  88  
  89          return [
  90              'user' => $user,
  91              'cfcats' => $cfcats,
  92              'cffields' => $cffields,
  93              'courses' => $courses,
  94          ];
  95      }
  96  
  97      /**
  98       * Test for provider::get_metadata()
  99       */
 100      public function test_get_metadata() {
 101          $collection = new \core_privacy\local\metadata\collection('core_customfield');
 102          $collection = provider::get_metadata($collection);
 103          $this->assertNotEmpty($collection);
 104      }
 105  
 106      /**
 107       * Test for provider::get_customfields_data_contexts
 108       */
 109      public function test_get_customfields_data_contexts() {
 110          global $DB;
 111          [
 112              'cffields' => $cffields,
 113              'cfcats' => $cfcats,
 114              'courses' => $courses,
 115          ] = $this->generate_test_data();
 116  
 117          list($sql, $params) = $DB->get_in_or_equal([$courses[1]->id, $courses[2]->id], SQL_PARAMS_NAMED);
 118          $r = provider::get_customfields_data_contexts('core_course', 'course', '=0',
 119              $sql, $params);
 120          $this->assertEqualsCanonicalizing([\context_course::instance($courses[1]->id)->id,
 121              \context_course::instance($courses[2]->id)->id],
 122              $r->get_contextids());
 123      }
 124  
 125      /**
 126       * Test for provider::get_customfields_configuration_contexts()
 127       */
 128      public function test_get_customfields_configuration_contexts() {
 129          $this->generate_test_data();
 130  
 131          $r = provider::get_customfields_configuration_contexts('core_course', 'course');
 132          $this->assertEquals([\context_system::instance()->id], $r->get_contextids());
 133      }
 134  
 135      /**
 136       * Test for provider::export_customfields_data()
 137       */
 138      public function test_export_customfields_data() {
 139          global $USER, $DB;
 140          $this->resetAfterTest();
 141          [
 142              'cffields' => $cffields,
 143              'cfcats' => $cfcats,
 144              'courses' => $courses,
 145          ] = $this->generate_test_data();
 146  
 147          // Hack one of the fields so it has an invalid field type.
 148          $invalidfieldid = $cffields[21]->get('id');
 149          $DB->update_record('customfield_field', ['id' => $invalidfieldid, 'type' => 'invalid']);
 150  
 151          $context = \context_course::instance($courses[1]->id);
 152          $contextlist = new approved_contextlist($USER, 'core_customfield', [$context->id]);
 153          provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $courses[1]->id]);
 154          /** @var core_privacy\tests\request\content_writer $writer */
 155          $writer = writer::with_context($context);
 156  
 157          // Make sure that all and only data for the course1 was exported.
 158          // There is no way to fetch all data from writer as array so we need to fetch one-by-one for each data id.
 159          $invaldfieldischecked = false;
 160          foreach ($DB->get_records('customfield_data', []) as $dbrecord) {
 161              $data = $writer->get_data(['Custom fields data', $dbrecord->id]);
 162              if ($dbrecord->instanceid == $courses[1]->id) {
 163                  $this->assertEquals($dbrecord->fieldid, $data->fieldid);
 164                  $this->assertNotEmpty($data->fieldtype);
 165                  $this->assertNotEmpty($data->fieldshortname);
 166                  $this->assertNotEmpty($data->fieldname);
 167                  $invaldfieldischecked = $invaldfieldischecked ?: ($data->fieldid == $invalidfieldid);
 168              } else {
 169                  $this->assertEmpty($data);
 170              }
 171          }
 172  
 173          // Make sure field with was checked in this test.
 174          $this->assertTrue($invaldfieldischecked);
 175      }
 176  
 177      /**
 178       * Test for provider::delete_customfields_data()
 179       */
 180      public function test_delete_customfields_data() {
 181          global $USER, $DB;
 182          $this->resetAfterTest();
 183          [
 184              'cffields' => $cffields,
 185              'cfcats' => $cfcats,
 186              'courses' => $courses,
 187          ] = $this->generate_test_data();
 188  
 189          $approvedcontexts = new approved_contextlist($USER, 'core_course', [\context_course::instance($courses[1]->id)->id]);
 190          provider::delete_customfields_data($approvedcontexts, 'core_course', 'course');
 191          $this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[1]->id]));
 192          $this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[2]->id]));
 193      }
 194  
 195      /**
 196       * Test for provider::delete_customfields_configuration()
 197       */
 198      public function test_delete_customfields_configuration() {
 199          global $USER, $DB;
 200          $this->resetAfterTest();
 201          [
 202              'cffields' => $cffields,
 203              'cfcats' => $cfcats,
 204              'courses' => $courses,
 205          ] = $this->generate_test_data();
 206  
 207          // Remember the list of fields in the category 2 before we delete it.
 208          $catid1 = $cfcats[1]->get('id');
 209          $catid2 = $cfcats[2]->get('id');
 210          $fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
 211          $this->assertNotEmpty($fids2);
 212          list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
 213          $this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
 214  
 215          // A little hack here, modify customfields configuration so they have different itemids.
 216          $DB->update_record('customfield_category', ['id' => $catid2, 'itemid' => 1]);
 217          $contextlist = new approved_contextlist($USER, 'core_course', [\context_system::instance()->id]);
 218          provider::delete_customfields_configuration($contextlist, 'core_course', 'course', '=:i', ['i' => 1]);
 219  
 220          // Make sure everything for category $catid2 is gone but present for $catid1.
 221          $this->assertEmpty($DB->get_records('customfield_category', ['id' => $catid2]));
 222          $this->assertEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql, $fparams));
 223          $this->assertEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
 224  
 225          $this->assertNotEmpty($DB->get_records('customfield_category', ['id' => $catid1]));
 226          $fids1 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid1]);
 227          list($fsql1, $fparams1) = $DB->get_in_or_equal($fids1, SQL_PARAMS_NAMED);
 228          $this->assertNotEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql1, $fparams1));
 229          $this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql1, $fparams1));
 230      }
 231  
 232      /**
 233       * Test for provider::delete_customfields_configuration_for_context()
 234       */
 235      public function test_delete_customfields_configuration_for_context() {
 236          global $USER, $DB;
 237          $this->resetAfterTest();
 238          [
 239              'cffields' => $cffields,
 240              'cfcats' => $cfcats,
 241              'courses' => $courses,
 242          ] = $this->generate_test_data();
 243  
 244          // Remember the list of fields in the category 2 before we delete it.
 245          $catid1 = $cfcats[1]->get('id');
 246          $catid2 = $cfcats[2]->get('id');
 247          $fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
 248          $this->assertNotEmpty($fids2);
 249          list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
 250          $this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
 251  
 252          // A little hack here, modify customfields configuration so they have different contexts.
 253          $context = \context_user::instance($USER->id);
 254          $DB->update_record('customfield_category', ['id' => $catid2, 'contextid' => $context->id]);
 255          provider::delete_customfields_configuration_for_context('core_course', 'course', $context);
 256  
 257          // Make sure everything for category $catid2 is gone but present for $catid1.
 258          $this->assertEmpty($DB->get_records('customfield_category', ['id' => $catid2]));
 259          $this->assertEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql, $fparams));
 260          $this->assertEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
 261  
 262          $this->assertNotEmpty($DB->get_records('customfield_category', ['id' => $catid1]));
 263          $fids1 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid1]);
 264          list($fsql1, $fparams1) = $DB->get_in_or_equal($fids1, SQL_PARAMS_NAMED);
 265          $this->assertNotEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql1, $fparams1));
 266          $this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql1, $fparams1));
 267      }
 268  
 269      /**
 270       * Test for provider::delete_customfields_data_for_context()
 271       */
 272      public function test_delete_customfields_data_for_context() {
 273          global $DB;
 274          $this->resetAfterTest();
 275          [
 276              'cffields' => $cffields,
 277              'cfcats' => $cfcats,
 278              'courses' => $courses,
 279          ] = $this->generate_test_data();
 280  
 281          provider::delete_customfields_data_for_context('core_course', 'course',
 282              \context_course::instance($courses[1]->id));
 283          $fids2 = $DB->get_fieldset_select('customfield_field', 'id', '1=1', []);
 284          list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
 285          $fparams['course1'] = $courses[1]->id;
 286          $fparams['course2'] = $courses[2]->id;
 287          $this->assertEmpty($DB->get_records_select('customfield_data', 'instanceid = :course1 AND fieldid ' . $fsql, $fparams));
 288          $this->assertNotEmpty($DB->get_records_select('customfield_data', 'instanceid = :course2 AND fieldid ' . $fsql, $fparams));
 289      }
 290  }