Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

   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   * Unit tests for data_get_all_recordsids(), data_get_advance_search_ids(), data_get_record_ids(),
  19   * and data_get_advanced_search_sql()
  20   *
  21   * @package    mod_data
  22   * @category   phpunit
  23   * @copyright  2012 Adrian Greeve
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->dirroot . '/mod/data/lib.php');
  31  require_once($CFG->dirroot . '/lib/datalib.php');
  32  require_once($CFG->dirroot . '/lib/csvlib.class.php');
  33  require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
  34  require_once($CFG->dirroot . '/mod/data/tests/generator/lib.php');
  35  
  36  /**
  37   * Unit tests for {@see data_get_all_recordids()}.
  38   *                {@see data_get_advanced_search_ids()}
  39   *                {@see data_get_record_ids()}
  40   *                {@see data_get_advanced_search_sql()}
  41   *
  42   * @package    mod_data
  43   * @copyright  2012 Adrian Greeve
  44   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  45   */
  46  class mod_data_search_test extends advanced_testcase {
  47      /**
  48       * @var stdObject $recorddata An object that holds information from the table data.
  49       */
  50      public $recorddata = null;
  51      /**
  52       * @var int $recordcontentid The content ID.
  53       */
  54      public $recordcontentid = null;
  55      /**
  56       * @var int $recordrecordid The record ID.
  57       */
  58      public $recordrecordid = null;
  59      /**
  60       * @var int $recordfieldid The field ID.
  61       */
  62      public $recordfieldid = null;
  63      /**
  64       * @var array $recordsearcharray An array of stdClass which contains search criteria.
  65       */
  66      public $recordsearcharray = null;
  67  
  68      // CONSTANTS
  69  
  70      /**
  71       * @var int $datarecordcount   The number of records in the database.
  72       */
  73      public $datarecordcount = 100;
  74  
  75      /**
  76       * @var int $groupdatarecordcount  The number of records in the database in groups 0 and 1.
  77       */
  78      public $groupdatarecordcount = 75;
  79  
  80      /**
  81       * @var array $datarecordset   Expected record IDs.
  82       */
  83      public $datarecordset = array('0' => '6');
  84  
  85      /**
  86       * @var array $finalrecord   Final record for comparison with test four.
  87       */
  88      public $finalrecord = array();
  89  
  90      /**
  91       * @var int $approvedatarecordcount  The number of approved records in the database.
  92       */
  93      public $approvedatarecordcount = 89;
  94  
  95      /**
  96       * @var string Area id
  97       */
  98      protected $databaseentryareaid = null;
  99  
 100      /**
 101       * Set up function. In this instance we are setting up database
 102       * records to be used in the unit tests.
 103       */
 104      protected function setUp() {
 105          global $DB, $CFG;
 106          parent::setUp();
 107  
 108          $this->resetAfterTest(true);
 109  
 110          set_config('enableglobalsearch', true);
 111  
 112          $this->databaseentryareaid = \core_search\manager::generate_areaid('mod_data', 'entry');
 113  
 114          // Set \core_search::instance to the mock_search_engine as we don't require the search engine to be working to test this.
 115          $search = testable_core_search::instance();
 116  
 117      }
 118  
 119      /**
 120       * Test 1: The function data_get_all_recordids.
 121       *
 122       * Test 2: This tests the data_get_advance_search_ids() function. The function takes a set
 123       * of all the record IDs in the database and then with the search details ($this->recordsearcharray)
 124       * returns a comma seperated string of record IDs that match the search criteria.
 125       *
 126       * Test 3: This function tests data_get_recordids(). This is the function that is nested in the last
 127       * function (see data_get_advance_search_ids). This function takes a couple of
 128       * extra parameters. $alias is the field alias used in the sql query and $commaid
 129       * is a comma seperated string of record IDs.
 130       *
 131       * Test 3.1: This tests that if no recordids are provided (In a situation where a search is done on an empty database)
 132       * That an empty array is returned.
 133       *
 134       * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records
 135       * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test
 136       * takes that information and does a search on the database, returning a record.
 137       *
 138       * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to
 139       * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed
 140       * from the total so we should only have 75 records total.
 141       *
 142       * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to
 143       * display the records that have been approved. In this record set we have 89 approved records.
 144       */
 145      public function test_advanced_search_sql_section() {
 146          global $DB;
 147  
 148          // we already have 2 users, we need 98 more - let's ignore the fact that guest can not post anywhere
 149          // We reset the user sequence here to ensure we get the expected numbers.
 150          // TODO: Invent a better way for managing data file input against database sequence id's.
 151          $DB->get_manager()->reset_sequence('user');
 152          for($i=3;$i<=100;$i++) {
 153              $this->getDataGenerator()->create_user();
 154          }
 155  
 156          // create database module - there should be more of these I guess
 157          $course = $this->getDataGenerator()->create_course();
 158          $data = $this->getDataGenerator()->create_module('data', array('course'=>$course->id));
 159          $this->recorddata = $data;
 160  
 161          // Set up data for the test database.
 162          $files = array(
 163                  'data_fields'  => __DIR__.'/fixtures/test_data_fields.csv',
 164                  'data_records' => __DIR__.'/fixtures/test_data_records.csv',
 165                  'data_content' => __DIR__.'/fixtures/test_data_content.csv',
 166          );
 167          $this->loadDataSet($this->createCsvDataSet($files));
 168          // Set dataid to the correct value now the data has been inserted by csv file.
 169          $DB->execute('UPDATE {data_fields} SET dataid = ?', array($data->id));
 170          $DB->execute('UPDATE {data_records} SET dataid = ?', array($data->id));
 171  
 172          // Create the search array which contains our advanced search criteria.
 173          $fieldinfo = array('0' => new stdClass(),
 174                  '1' => new stdClass(),
 175                  '2' => new stdClass(),
 176                  '3' => new stdClass(),
 177                  '4' => new stdClass());
 178          $fieldinfo['0']->id = 1;
 179          $fieldinfo['0']->data = '3.721,46.6126';
 180          $fieldinfo['1']->id = 2;
 181          $fieldinfo['1']->data = 'Hahn Premium';
 182          $fieldinfo['2']->id = 5;
 183          $fieldinfo['2']->data = 'Female';
 184          $fieldinfo['3']->id = 7;
 185          $fieldinfo['3']->data = 'kel';
 186          $fieldinfo['4']->id = 9;
 187          $fieldinfo['4']->data = 'VIC';
 188  
 189          foreach($fieldinfo as $field) {
 190              $searchfield = data_get_field_from_id($field->id, $data);
 191              if ($field->id == 2) {
 192                  $searchfield->field->param1 = 'Hahn Premium';
 193                  $val = array();
 194                  $val['selected'] = array('0' => 'Hahn Premium');
 195                  $val['allrequired'] = 0;
 196              } else {
 197                  $val = $field->data;
 198              }
 199              $search_array[$field->id] = new stdClass();
 200              list($search_array[$field->id]->sql, $search_array[$field->id]->params) = $searchfield->generate_sql('c' . $field->id, $val);
 201          }
 202  
 203          $this->recordsearcharray = $search_array;
 204  
 205          // Setting up the comparison stdClass for the last test.
 206          $user = $DB->get_record('user', array('id'=>6));
 207          $this->finalrecord[6] = new stdClass();
 208          $this->finalrecord[6]->id = 6;
 209          $this->finalrecord[6]->approved = 1;
 210          $this->finalrecord[6]->timecreated = 1234567891;
 211          $this->finalrecord[6]->timemodified = 1234567892;
 212          $this->finalrecord[6]->userid = 6;
 213          $this->finalrecord[6]->firstname = $user->firstname;
 214          $this->finalrecord[6]->lastname = $user->lastname;
 215          $this->finalrecord[6]->firstnamephonetic = $user->firstnamephonetic;
 216          $this->finalrecord[6]->lastnamephonetic = $user->lastnamephonetic;
 217          $this->finalrecord[6]->middlename = $user->middlename;
 218          $this->finalrecord[6]->alternatename = $user->alternatename;
 219          $this->finalrecord[6]->picture = $user->picture;
 220          $this->finalrecord[6]->imagealt = $user->imagealt;
 221          $this->finalrecord[6]->email = $user->email;
 222  
 223          // Test 1
 224          $recordids = data_get_all_recordids($this->recorddata->id);
 225          $this->assertEquals(count($recordids), $this->datarecordcount);
 226  
 227          // Test 2
 228          $key = array_keys($this->recordsearcharray);
 229          $alias = $key[0];
 230          $newrecordids = data_get_recordids($alias, $this->recordsearcharray, $this->recorddata->id, $recordids);
 231          $this->assertEquals($this->datarecordset, $newrecordids);
 232  
 233          // Test 3
 234          $newrecordids = data_get_advance_search_ids($recordids, $this->recordsearcharray, $this->recorddata->id);
 235          $this->assertEquals($this->datarecordset, $newrecordids);
 236  
 237          // Test 3.1
 238          $resultrecordids = data_get_advance_search_ids(array(), $this->recordsearcharray, $this->recorddata->id);
 239          $this->assertEmpty($resultrecordids);
 240  
 241          // Test 4
 242          $sortorder = 'ORDER BY r.timecreated ASC , r.id ASC';
 243          $html = data_get_advanced_search_sql('0', $this->recorddata, $newrecordids, '', $sortorder);
 244          $allparams = array_merge($html['params'], array('dataid' => $this->recorddata->id));
 245          $records = $DB->get_records_sql($html['sql'], $allparams);
 246          $this->assertEquals($records, $this->finalrecord);
 247  
 248          // Test 5
 249          $groupsql = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
 250          $params = array('currentgroup' => 1);
 251          $recordids = data_get_all_recordids($this->recorddata->id, $groupsql, $params);
 252          $this->assertEquals($this->groupdatarecordcount, count($recordids));
 253  
 254          // Test 6
 255          $approvesql = ' AND r.approved=1 ';
 256          $recordids = data_get_all_recordids($this->recorddata->id, $approvesql, $params);
 257          $this->assertEquals($this->approvedatarecordcount, count($recordids));
 258      }
 259  
 260      public function test_advanced_search_tags() {
 261          $this->resetAfterTest();
 262          $this->setAdminUser();
 263  
 264          // Setup test data.
 265          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 266          $course1 = $this->getDataGenerator()->create_course();
 267  
 268          $fieldrecord = new StdClass();
 269          $fieldrecord->name = 'field-1';
 270          $fieldrecord->type = 'text';
 271          $fieldrecord->titlefield = true;
 272  
 273          $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
 274          $field1 = $datagenerator->create_field($fieldrecord, $data1);
 275  
 276          $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
 277          $record12 = $datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']);
 278          $record13 = $datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Bats']);
 279  
 280          $searcharray = [];
 281          $searcharray[DATA_TAGS] = new stdClass();
 282          $searcharray[DATA_TAGS]->params = [];
 283          $searcharray[DATA_TAGS]->rawtagnames = ['Cats'];
 284          $searcharray[DATA_TAGS]->sql = '';
 285  
 286          $recordids = data_get_all_recordids($data1->id);
 287          $newrecordids = data_get_advance_search_ids($recordids, $searcharray, $data1->id);
 288  
 289          $this->assertContains($record11, $newrecordids);
 290          $this->assertContains($record12, $newrecordids);
 291          $this->assertNotContains($record13, $newrecordids);
 292      }
 293  
 294      /**
 295       * Indexing database entries contents.
 296       *
 297       * @return void
 298       */
 299      public function test_data_entries_indexing() {
 300          global $DB;
 301  
 302          // Returns the instance as long as the area is supported.
 303          $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
 304          $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
 305  
 306          $user1 = self::getDataGenerator()->create_user();
 307  
 308          $course1 = self::getDataGenerator()->create_course();
 309  
 310          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
 311  
 312          $record = new stdClass();
 313          $record->course = $course1->id;
 314  
 315          $this->setUser($user1);
 316  
 317          // Available for both student and teacher.
 318          $data1 = $this->getDataGenerator()->create_module('data', $record);
 319  
 320          // Excluding LatLong and Picture as we aren't indexing LatLong and Picture fields any way
 321          // ...and they're complex and not of any use to consider for this test.
 322          // Excluding File as we are indexing files seperately and its complex to implement.
 323          $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
 324  
 325          $this->create_default_data_fields($fieldtypes, $data1);
 326  
 327          $data1record1id = $this->create_default_data_record($data1);
 328          // All records.
 329          $recordset = $searcharea->get_recordset_by_timestamp(0);
 330  
 331          $this->assertTrue($recordset->valid());
 332  
 333          $nrecords = 0;
 334          foreach ($recordset as $record) {
 335              $this->assertInstanceOf('stdClass', $record);
 336              $doc = $searcharea->get_document($record);
 337              $this->assertInstanceOf('\core_search\document', $doc);
 338              $nrecords++;
 339          }
 340  
 341          // If there would be an error/failure in the foreach above the recordset would be closed on shutdown.
 342          $recordset->close();
 343          $this->assertEquals(1, $nrecords);
 344  
 345          // The +2 is to prevent race conditions.
 346          $recordset = $searcharea->get_recordset_by_timestamp(time() + 2);
 347  
 348          // No new records.
 349          $this->assertFalse($recordset->valid());
 350          $recordset->close();
 351  
 352          // Create a second database, also with one record.
 353          $data2 = $this->getDataGenerator()->create_module('data', ['course' => $course1->id]);
 354          $this->create_default_data_fields($fieldtypes, $data2);
 355          $this->create_default_data_record($data2);
 356  
 357          // Test indexing with contexts.
 358          $rs = $searcharea->get_document_recordset(0, context_module::instance($data1->cmid));
 359          $this->assertEquals(1, iterator_count($rs));
 360          $rs->close();
 361          $rs = $searcharea->get_document_recordset(0, context_module::instance($data2->cmid));
 362          $this->assertEquals(1, iterator_count($rs));
 363          $rs->close();
 364          $rs = $searcharea->get_document_recordset(0, context_course::instance($course1->id));
 365          $this->assertEquals(2, iterator_count($rs));
 366          $rs->close();
 367      }
 368  
 369      /**
 370       * Document contents.
 371       *
 372       * @return void
 373       */
 374      public function test_data_entries_document() {
 375          global $DB;
 376  
 377          // Returns the instance as long as the area is supported.
 378          $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
 379          $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
 380  
 381          $user1 = self::getDataGenerator()->create_user();
 382  
 383          $course = self::getDataGenerator()->create_course();
 384  
 385          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
 386  
 387          $record = new stdClass();
 388          $record->course = $course->id;
 389  
 390          $this->setAdminUser();
 391  
 392          // First Case.
 393          $data1 = $this->getDataGenerator()->create_module('data', $record);
 394  
 395          $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
 396  
 397          $this->create_default_data_fields($fieldtypes, $data1);
 398  
 399          $data1record1id = $this->create_default_data_record($data1);
 400  
 401          $data1entry1 = $this->get_entry_for_id($data1record1id);
 402  
 403          $data1doc = $searcharea->get_document($data1entry1);
 404  
 405          $this->assertEquals($data1doc->get('courseid'), $course->id);
 406          $this->assertEquals($data1doc->get('title'), 'text for testing');
 407          $this->assertEquals($data1doc->get('content'), 'menu1');
 408          $this->assertEquals($data1doc->get('description1'), 'radioopt1');
 409          $this->assertEquals($data1doc->get('description2'), 'opt1 opt2 opt3 opt4 multimenu1 multimenu2 multimenu3 multimenu4 text area testing http://example.url');
 410  
 411          // Second Case.
 412          $data2 = $this->getDataGenerator()->create_module('data', $record);
 413  
 414          $fieldtypes = array(
 415                  array('checkbox', 1),
 416                  array('textarea', 0),
 417                  array('menu', 0),
 418                  array('number', 1),
 419                  array('url', 0),
 420                  array('text', 0)
 421          );
 422  
 423          $this->create_default_data_fields($fieldtypes, $data2);
 424  
 425          $data2record1id = $this->create_default_data_record($data2);
 426  
 427          $data2entry1 = $this->get_entry_for_id($data2record1id);
 428  
 429          $data2doc = $searcharea->get_document($data2entry1);
 430  
 431          $this->assertEquals($data2doc->get('courseid'), $course->id);
 432          $this->assertEquals($data2doc->get('title'), 'opt1 opt2 opt3 opt4');
 433          $this->assertEquals($data2doc->get('content'), 'text for testing');
 434          $this->assertEquals($data2doc->get('description1'), 'menu1');
 435          $this->assertEquals($data2doc->get('description2'), 'text area testing http://example.url');
 436  
 437          // Third Case.
 438          $data3 = $this->getDataGenerator()->create_module('data', $record);
 439  
 440          $fieldtypes = array( 'url' );
 441  
 442          $this->create_default_data_fields($fieldtypes, $data3);
 443  
 444          $data3record1id = $this->create_default_data_record($data3);
 445  
 446          $data3entry1 = $this->get_entry_for_id($data3record1id);
 447  
 448          $this->assertFalse($searcharea->get_document($data3entry1));
 449  
 450          // Fourth Case.
 451          $data4 = $this->getDataGenerator()->create_module('data', $record);
 452  
 453          $fieldtypes = array( array('date', 1), array('text', 1));
 454  
 455          $this->create_default_data_fields($fieldtypes, $data4);
 456  
 457          $data4record1id = $this->create_default_data_record($data4);
 458  
 459          $data4entry1 = $this->get_entry_for_id($data4record1id);
 460  
 461          $this->assertFalse($searcharea->get_document($data4entry1));
 462  
 463          // Fifth Case.
 464          $data5 = $this->getDataGenerator()->create_module('data', $record);
 465  
 466          $fieldtypes = array(
 467                  array('checkbox', 0),
 468                  array('number', 1),
 469                  array('text', 0),
 470                  array('date', 1),
 471                  array('textarea', 0),
 472                  array('url', 1));
 473  
 474          $this->create_default_data_fields($fieldtypes, $data5);
 475  
 476          $data5record1id = $this->create_default_data_record($data5);
 477  
 478          $data5entry1 = $this->get_entry_for_id($data5record1id);
 479  
 480          $data5doc = $searcharea->get_document($data5entry1);
 481  
 482          $this->assertEquals($data5doc->get('courseid'), $course->id);
 483          $this->assertEquals($data5doc->get('title'), 'http://example.url');
 484          $this->assertEquals($data5doc->get('content'), 'text for testing');
 485          $this->assertEquals($data5doc->get('description1'), 'opt1 opt2 opt3 opt4');
 486          $this->assertEquals($data5doc->get('description2'), 'text area testing');
 487  
 488          // Sixth Case.
 489          $data6 = $this->getDataGenerator()->create_module('data', $record);
 490  
 491          $fieldtypes = array( array('date', 1), array('number', 1));
 492  
 493          $this->create_default_data_fields($fieldtypes, $data6);
 494  
 495          $data6record1id = $this->create_default_data_record($data6);
 496  
 497          $data6entry1 = $this->get_entry_for_id($data6record1id);
 498  
 499          $data6doc = $searcharea->get_document($data6entry1);
 500  
 501          $this->assertFalse($data6doc);
 502  
 503          // Seventh Case.
 504          $data7 = $this->getDataGenerator()->create_module('data', $record);
 505  
 506          $fieldtypes = array( array('date', 1), array('number', 1),
 507                  array('text', 0), array('textarea', 0));
 508  
 509          $this->create_default_data_fields($fieldtypes, $data7);
 510  
 511          $data7record1id = $this->create_default_data_record($data7);
 512  
 513          $data7entry1 = $this->get_entry_for_id($data7record1id);
 514  
 515          $data7doc = $searcharea->get_document($data7entry1);
 516  
 517          $this->assertEquals($data7doc->get('courseid'), $course->id);
 518          $this->assertEquals($data7doc->get('title'), 'text for testing');
 519          $this->assertEquals($data7doc->get('content'), 'text area testing');
 520  
 521          // Eight Case.
 522          $data8 = $this->getDataGenerator()->create_module('data', $record);
 523  
 524          $fieldtypes = array('url', 'url', 'url', 'text');
 525  
 526          $this->create_default_data_fields($fieldtypes, $data8);
 527  
 528          $data8record1id = $this->create_default_data_record($data8);
 529  
 530          $data8entry1 = $this->get_entry_for_id($data8record1id);
 531  
 532          $data8doc = $searcharea->get_document($data8entry1);
 533  
 534          $this->assertEquals($data8doc->get('courseid'), $course->id);
 535          $this->assertEquals($data8doc->get('title'), 'text for testing');
 536          $this->assertEquals($data8doc->get('content'), 'http://example.url');
 537          $this->assertEquals($data8doc->get('description1'), 'http://example.url');
 538          $this->assertEquals($data8doc->get('description2'), 'http://example.url');
 539  
 540          // Ninth Case.
 541          $data9 = $this->getDataGenerator()->create_module('data', $record);
 542  
 543          $fieldtypes = array('radiobutton', 'menu', 'multimenu');
 544  
 545          $this->create_default_data_fields($fieldtypes, $data9);
 546  
 547          $data9record1id = $this->create_default_data_record($data9);
 548  
 549          $data9entry1 = $this->get_entry_for_id($data9record1id);
 550  
 551          $data9doc = $searcharea->get_document($data9entry1);
 552  
 553          $this->assertEquals($data9doc->get('courseid'), $course->id);
 554          $this->assertEquals($data9doc->get('title'), 'radioopt1');
 555          $this->assertEquals($data9doc->get('content'), 'menu1');
 556          $this->assertEquals($data9doc->get('description1'), 'multimenu1 multimenu2 multimenu3 multimenu4');
 557  
 558          // Tenth Case.
 559          $data10 = $this->getDataGenerator()->create_module('data', $record);
 560  
 561          $fieldtypes = array('checkbox', 'textarea', 'multimenu');
 562  
 563          $this->create_default_data_fields($fieldtypes, $data10);
 564  
 565          $data10record1id = $this->create_default_data_record($data10);
 566  
 567          $data10entry1 = $this->get_entry_for_id($data10record1id);
 568  
 569          $data10doc = $searcharea->get_document($data10entry1);
 570  
 571          $this->assertEquals($data10doc->get('courseid'), $course->id);
 572          $this->assertEquals($data10doc->get('title'), 'opt1 opt2 opt3 opt4');
 573          $this->assertEquals($data10doc->get('content'), 'text area testing');
 574          $this->assertEquals($data10doc->get('description1'), 'multimenu1 multimenu2 multimenu3 multimenu4');
 575  
 576      }
 577  
 578      /**
 579       * Group support for data entries.
 580       */
 581      public function test_data_entries_group_support() {
 582          global $DB;
 583  
 584          // Get the search area and test generators.
 585          $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
 586          $generator = $this->getDataGenerator();
 587          $datagenerator = $generator->get_plugin_generator('mod_data');
 588  
 589          // Create a course, a user, and two groups.
 590          $course = $generator->create_course();
 591          $user = $generator->create_user();
 592          $generator->enrol_user($user->id, $course->id, 'teacher');
 593          $group1 = $generator->create_group(['courseid' => $course->id]);
 594          $group2 = $generator->create_group(['courseid' => $course->id]);
 595  
 596          // Separate groups database.
 597          $data = self::getDataGenerator()->create_module('data', ['course' => $course->id,
 598                  'groupmode' => SEPARATEGROUPS]);
 599          $fieldtypes = ['text', 'textarea'];
 600          $this->create_default_data_fields($fieldtypes, $data);
 601          $fields = $DB->get_records('data_fields', array('dataid' => $data->id));
 602          foreach ($fields as $field) {
 603              switch ($field->type) {
 604                  case 'text' :
 605                      $textid = $field->id;
 606                      break;
 607                  case 'textarea' :
 608                      $textareaid = $field->id;
 609                      break;
 610              }
 611          }
 612  
 613          // As admin, create entries with each group and all groups.
 614          $this->setAdminUser();
 615          $fieldvalues = [$textid => 'Title', $textareaid => 'Content'];
 616          $e1 = $datagenerator->create_entry($data, $fieldvalues, $group1->id);
 617          $e2 = $datagenerator->create_entry($data, $fieldvalues, $group2->id);
 618          $e3 = $datagenerator->create_entry($data, $fieldvalues);
 619  
 620          // Do the indexing of all 3 entries.
 621          $rs = $searcharea->get_recordset_by_timestamp(0);
 622          $results = [];
 623          foreach ($rs as $rec) {
 624              $results[$rec->id] = $rec;
 625          }
 626          $rs->close();
 627          $this->assertCount(3, $results);
 628  
 629          // Check each has the correct groupid.
 630          $doc = $searcharea->get_document($results[$e1]);
 631          $this->assertTrue($doc->is_set('groupid'));
 632          $this->assertEquals($group1->id, $doc->get('groupid'));
 633          $doc = $searcharea->get_document($results[$e2]);
 634          $this->assertTrue($doc->is_set('groupid'));
 635          $this->assertEquals($group2->id, $doc->get('groupid'));
 636          $doc = $searcharea->get_document($results[$e3]);
 637          $this->assertFalse($doc->is_set('groupid'));
 638  
 639          // While we're here, also test that the search area requests restriction by group.
 640          $modinfo = get_fast_modinfo($course);
 641          $this->assertTrue($searcharea->restrict_cm_access_by_group($modinfo->get_cm($data->cmid)));
 642  
 643          // In visible groups mode, it won't request restriction by group.
 644          set_coursemodule_groupmode($data->cmid, VISIBLEGROUPS);
 645          $modinfo = get_fast_modinfo($course);
 646          $this->assertFalse($searcharea->restrict_cm_access_by_group($modinfo->get_cm($data->cmid)));
 647      }
 648  
 649      /**
 650       * Document accesses.
 651       *
 652       * @return void
 653       */
 654      public function test_data_entries_access() {
 655          global $DB;
 656  
 657          // Returns the instance as long as the area is supported.
 658          $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
 659          $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
 660  
 661          $user1 = self::getDataGenerator()->create_user();
 662          $user2 = self::getDataGenerator()->create_user();
 663          $user3 = self::getDataGenerator()->create_user();
 664          $userteacher1 = self::getDataGenerator()->create_user();
 665  
 666          $course1 = self::getDataGenerator()->create_course();
 667          $course2 = self::getDataGenerator()->create_course();
 668  
 669          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
 670          $this->getDataGenerator()->enrol_user($user2->id, $course1->id, 'student');
 671          $this->getDataGenerator()->enrol_user($userteacher1->id, $course1->id, 'teacher');
 672  
 673          $this->getDataGenerator()->enrol_user($user3->id, $course2->id, 'student');
 674  
 675          $record = new stdClass();
 676          $record->course = $course1->id;
 677  
 678          $this->setUser($userteacher1);
 679  
 680          $data1 = $this->getDataGenerator()->create_module('data', $record);
 681  
 682          $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
 683  
 684          $this->create_default_data_fields($fieldtypes, $data1);
 685  
 686          $this->setUser($user1);
 687          $data1record1id = $this->create_default_data_record($data1);
 688  
 689          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
 690          $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
 691  
 692          $this->setUser($user2);
 693          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
 694  
 695          $this->setUser($user3);
 696          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data1record1id));
 697  
 698          $this->setUser($userteacher1);
 699          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
 700  
 701          $this->setAdminUser();
 702          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
 703  
 704          $this->setGuestUser();
 705          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data1record1id));
 706  
 707          // Case with groups.
 708          $user1 = self::getDataGenerator()->create_user();
 709          $user2 = self::getDataGenerator()->create_user();
 710          $user3 = self::getDataGenerator()->create_user();
 711          $userteacher1 = self::getDataGenerator()->create_user();
 712  
 713          $course = self::getDataGenerator()->create_course(array('groupmode' => 1, 'groupmodeforce' => 1));
 714  
 715          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
 716          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
 717          $this->getDataGenerator()->enrol_user($userteacher1->id, $course->id, 'teacher');
 718          $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student');
 719  
 720          $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupA'));
 721          $groupb = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupB'));
 722  
 723          $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $groupa->id));
 724          $this->getDataGenerator()->create_group_member(array('userid' => $user2->id, 'groupid' => $groupa->id));
 725          $this->getDataGenerator()->create_group_member(array('userid' => $userteacher1->id, 'groupid' => $groupa->id));
 726  
 727          $this->getDataGenerator()->create_group_member(array('userid' => $user3->id, 'groupid' => $groupb->id));
 728  
 729          $record = new stdClass();
 730          $record->course = $course->id;
 731  
 732          $this->setUser($userteacher1);
 733  
 734          $data2 = $this->getDataGenerator()->create_module('data', $record);
 735  
 736          $cm = get_coursemodule_from_instance('data', $data2->id, $course->id);
 737          $cm->groupmode = '1';
 738          $cm->effectivegroupmode = '1';
 739  
 740          $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
 741  
 742          $this->create_default_data_fields($fieldtypes, $data2);
 743  
 744          $this->setUser($user1);
 745  
 746          $data2record1id = $this->create_default_data_record($data2, $groupa->id);
 747  
 748          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
 749          $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
 750  
 751          $this->setUser($user2);
 752          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
 753  
 754          $this->setUser($user3);
 755          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data2record1id));
 756  
 757          $this->setUser($userteacher1);
 758          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
 759  
 760          $this->setAdminUser();
 761          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
 762  
 763          $this->setGuestUser();
 764          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data2record1id));
 765  
 766          // Case with approval.
 767          $user1 = self::getDataGenerator()->create_user();
 768          $user2 = self::getDataGenerator()->create_user();
 769          $userteacher1 = self::getDataGenerator()->create_user();
 770  
 771          $course = self::getDataGenerator()->create_course();
 772  
 773          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
 774          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
 775          $this->getDataGenerator()->enrol_user($userteacher1->id, $course->id, 'teacher');
 776  
 777          $record = new stdClass();
 778          $record->course = $course->id;
 779  
 780          $this->setUser($userteacher1);
 781  
 782          $data3 = $this->getDataGenerator()->create_module('data', $record);
 783  
 784          $DB->update_record('data', array('id' => $data3->id, 'approval' => 1));
 785  
 786          $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
 787  
 788          $this->create_default_data_fields($fieldtypes, $data3);
 789  
 790          $this->setUser($user1);
 791  
 792          $data3record1id = $this->create_default_data_record($data3);
 793  
 794          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 795          $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
 796  
 797          $this->setUser($user2);
 798          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id));
 799  
 800          $this->setUser($userteacher1);
 801          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 802  
 803          $this->setAdminUser();
 804          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 805  
 806          $this->setGuestUser();
 807          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id));
 808  
 809          $DB->update_record('data_records', array('id' => $data3record1id, 'approved' => 1));
 810  
 811          $this->setUser($user1);
 812          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 813          $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
 814  
 815          $this->setUser($user2);
 816          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 817  
 818          $this->setUser($userteacher1);
 819          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 820  
 821          $this->setAdminUser();
 822          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
 823  
 824          $this->setGuestUser();
 825          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id));
 826  
 827          // Case with requiredentriestoview.
 828          $this->setAdminUser();
 829  
 830          $record->requiredentriestoview = 2;
 831  
 832          $data4 = $this->getDataGenerator()->create_module('data', $record);
 833          $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
 834  
 835          $this->create_default_data_fields($fieldtypes, $data4);
 836  
 837          $data4record1id = $this->create_default_data_record($data4);
 838  
 839          $this->setUser($user1);
 840          $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data4record1id));
 841  
 842          $data4record2id = $this->create_default_data_record($data4);
 843          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data4record1id));
 844          $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data4record2id));
 845      }
 846  
 847      /**
 848       * Test for file contents.
 849       *
 850       * @return void
 851       */
 852      public function test_attach_files() {
 853          global $DB, $USER;
 854  
 855          $fs = get_file_storage();
 856  
 857          // Returns the instance as long as the area is supported.
 858          $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
 859          $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
 860  
 861          $user1 = self::getDataGenerator()->create_user();
 862  
 863          $course = self::getDataGenerator()->create_course();
 864  
 865          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
 866  
 867          $record = new stdClass();
 868          $record->course = $course->id;
 869  
 870          $this->setAdminUser();
 871  
 872          // Creating database activity instance.
 873          $data1 = $this->getDataGenerator()->create_module('data', $record);
 874  
 875          // Creating file field.
 876          $record = new stdClass;
 877          $record->type = 'file';
 878          $record->dataid = $data1->id;
 879          $record->required = 0;
 880          $record->name = 'FileFld';
 881          $record->description = 'Just another file field';
 882          $record->param3 = 0;
 883          $record->param1 = '';
 884          $record->param2 = '';
 885  
 886          $data1filefieldid = $DB->insert_record('data_fields', $record);
 887  
 888          // Creating text field.
 889          $record = new stdClass;
 890          $record->type = 'text';
 891          $record->dataid = $data1->id;
 892          $record->required = 0;
 893          $record->name = 'TextFld';
 894          $record->description = 'Just another text field';
 895          $record->param3 = 0;
 896          $record->param1 = '';
 897          $record->param2 = '';
 898  
 899          $data1textfieldid = $DB->insert_record('data_fields', $record);
 900  
 901          // Creating textarea field.
 902          $record = new stdClass;
 903          $record->type = 'textarea';
 904          $record->dataid = $data1->id;
 905          $record->required = 0;
 906          $record->name = 'TextAreaFld';
 907          $record->description = 'Just another textarea field';
 908          $record->param1 = '';
 909          $record->param2 = 60;
 910          $record->param3 = 35;
 911          $record->param3 = 1;
 912          $record->param3 = 0;
 913  
 914          $data1textareafieldid = $DB->insert_record('data_fields', $record);
 915  
 916          // Creating 1st entry.
 917          $record = new stdClass;
 918          $record->userid = $USER->id;
 919          $record->dataid = $data1->id;
 920          $record->groupid = 0;
 921  
 922          $data1record1id = $DB->insert_record('data_records', $record);
 923  
 924          $filerecord = array(
 925                  'contextid' => context_module::instance($data1->cmid)->id,
 926                  'component' => 'mod_data',
 927                  'filearea'  => 'content',
 928                  'itemid'    => $data1record1id,
 929                  'filepath'  => '/',
 930                  'filename'  => 'myfile1.txt'
 931          );
 932  
 933          $data1record1file = $fs->create_file_from_string($filerecord, 'Some contents 1');
 934  
 935          $record = new stdClass;
 936          $record->fieldid = $data1filefieldid;
 937          $record->recordid = $data1record1id;
 938          $record->content = 'myfile1.txt';
 939          $DB->insert_record('data_content', $record);
 940  
 941          $record = new stdClass;
 942          $record->fieldid = $data1textfieldid;
 943          $record->recordid = $data1record1id;
 944          $record->content = 'sample text';
 945          $DB->insert_record('data_content', $record);
 946  
 947          $record = new stdClass;
 948          $record->fieldid = $data1textareafieldid;
 949          $record->recordid = $data1record1id;
 950          $record->content = '<br>sample text<p /><br/>';
 951          $record->content1 = 1;
 952          $DB->insert_record('data_content', $record);
 953  
 954          // Creating 2nd entry.
 955          $record = new stdClass;
 956          $record->userid = $USER->id;
 957          $record->dataid = $data1->id;
 958          $record->groupid = 0;
 959          $data1record2id = $DB->insert_record('data_records', $record);
 960  
 961          $filerecord['itemid'] = $data1record2id;
 962          $filerecord['filename'] = 'myfile2.txt';
 963          $data1record2file = $fs->create_file_from_string($filerecord, 'Some contents 2');
 964  
 965          $record = new stdClass;
 966          $record->fieldid = $data1filefieldid;
 967          $record->recordid = $data1record2id;
 968          $record->content = 'myfile2.txt';
 969          $DB->insert_record('data_content', $record);
 970  
 971          $record = new stdClass;
 972          $record->fieldid = $data1textfieldid;
 973          $record->recordid = $data1record2id;
 974          $record->content = 'sample text';
 975          $DB->insert_record('data_content', $record);
 976  
 977          $record = new stdClass;
 978          $record->fieldid = $data1textareafieldid;
 979          $record->recordid = $data1record2id;
 980          $record->content = '<br>sample text<p /><br/>';
 981          $record->content1 = 1;
 982          $DB->insert_record('data_content', $record);
 983  
 984          // Now get all the posts and see if they have the right files attached.
 985          $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
 986          $recordset = $searcharea->get_recordset_by_timestamp(0);
 987          $nrecords = 0;
 988          foreach ($recordset as $record) {
 989              $doc = $searcharea->get_document($record);
 990              $searcharea->attach_files($doc);
 991              $files = $doc->get_files();
 992              // Now check that each doc has the right files on it.
 993              switch ($doc->get('itemid')) {
 994                  case ($data1record1id):
 995                      $this->assertCount(1, $files);
 996                      $this->assertEquals($data1record1file->get_id(), $files[$data1record1file->get_id()]->get_id());
 997                      break;
 998                  case ($data1record2id):
 999                      $this->assertCount(1, $files);
1000                      $this->assertEquals($data1record2file->get_id(), $files[$data1record2file->get_id()]->get_id());
1001                      break;
1002                  default:
1003                      $this->fail('Unexpected entry returned');
1004                      break;
1005              }
1006              $nrecords++;
1007          }
1008          $recordset->close();
1009          $this->assertEquals(2, $nrecords);
1010      }
1011  
1012      /**
1013       * Creates default fields for a database instance
1014       *
1015       * @param array $fieldtypes
1016       * @param mod_data $data
1017       * @return void
1018       */
1019      protected function create_default_data_fields($fieldtypes = array(), $data) {
1020          $count = 1;
1021  
1022          // Creating test Fields with default parameter values.
1023          foreach ($fieldtypes as $fieldtype) {
1024  
1025              // Creating variables dynamically.
1026              $fieldname = 'field-'.$count;
1027              $record = new stdClass();
1028              $record->name = $fieldname;
1029  
1030              if (is_array($fieldtype)) {
1031                  $record->type = $fieldtype[0];
1032                  $record->required = $fieldtype[1];
1033              } else {
1034                  $record->type = $fieldtype;
1035                  $record->required = 0;
1036              }
1037  
1038              ${$fieldname} = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field($record, $data);
1039              $count++;
1040          }
1041      }
1042  
1043      /**
1044       * Creates default database entry content values for default field param values
1045       *
1046       * @param mod_data $data
1047       * @param int $groupid
1048       * @return int
1049       */
1050      protected function create_default_data_record($data, $groupid = 0) {
1051          global $DB;
1052  
1053          $fields = $DB->get_records('data_fields', array('dataid' => $data->id));
1054  
1055          $fieldcontents = array();
1056          foreach ($fields as $fieldrecord) {
1057              switch ($fieldrecord->type) {
1058                  case 'checkbox':
1059                      $fieldcontents[$fieldrecord->id] = array('opt1', 'opt2', 'opt3', 'opt4');
1060                      break;
1061  
1062                  case 'multimenu':
1063                      $fieldcontents[$fieldrecord->id] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4');
1064                      break;
1065  
1066                  case 'date':
1067                      $fieldcontents[$fieldrecord->id] = '27-07-2016';
1068                      break;
1069  
1070                  case 'menu':
1071                      $fieldcontents[$fieldrecord->id] = 'menu1';
1072                      break;
1073  
1074                  case 'radiobutton':
1075                      $fieldcontents[$fieldrecord->id] = 'radioopt1';
1076                      break;
1077  
1078                  case 'number':
1079                      $fieldcontents[$fieldrecord->id] = '12345';
1080                      break;
1081  
1082                  case 'text':
1083                      $fieldcontents[$fieldrecord->id] = 'text for testing';
1084                      break;
1085  
1086                  case 'textarea':
1087                      $fieldcontents[$fieldrecord->id] = '<p>text area testing<br /></p>';
1088                      break;
1089  
1090                  case 'url':
1091                      $fieldcontents[$fieldrecord->id] = array('example.url', 'sampleurl');
1092                      break;
1093  
1094                  default:
1095                      $this->fail('Unexpected field type');
1096                      break;
1097              }
1098  
1099          }
1100  
1101          return $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data, $fieldcontents, $groupid);
1102      }
1103  
1104      /**
1105       * Creates default database entry content values for default field param values
1106       *
1107       * @param int $recordid
1108       * @return stdClass
1109       */
1110      protected function get_entry_for_id($recordid ) {
1111          global $DB;
1112  
1113          $sql = "SELECT dr.*, d.course
1114                    FROM {data_records} dr
1115                    JOIN {data} d ON d.id = dr.dataid
1116                   WHERE dr.id = :drid";
1117          return $DB->get_record_sql($sql, array('drid' => $recordid));
1118      }
1119  
1120  }