diff --git a/mod/data/classes/search/entry.php b/mod/data/classes/search/entry.php new file mode 100644 index 00000000000..0a2e8ceb641 --- /dev/null +++ b/mod/data/classes/search/entry.php @@ -0,0 +1,330 @@ +. + +/** + * Search area for mod_data activity entries. + * + * @package mod_data + * @copyright 2016 Devang Gaur + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_data\search; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/mod/data/lib.php'); +require_once($CFG->dirroot . '/lib/grouplib.php'); + +/** + * Search area for mod_data activity entries. + * + * @package mod_data + * @copyright 2016 Devang Gaur + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class entry extends \core_search\base_mod { + + /** + * @var array Internal quick static cache. + */ + protected $entriesdata = array(); + + /** + * Returns recordset containing required data for indexing database entries. + * + * @param int $modifiedfrom timestamp + * @return moodle_recordset + */ + public function get_recordset_by_timestamp($modifiedfrom = 0) { + global $DB; + + $sql = "SELECT dr.*, d.course + FROM {data_records} dr + JOIN {data} d ON d.id = dr.dataid + WHERE dr.timemodified >= :timemodified"; + return $DB->get_recordset_sql($sql, array('timemodified' => $modifiedfrom)); + } + + /** + * Returns the documents associated with this glossary entry id. + * + * @param stdClass $entry glossary entry. + * @param array $options + * @return \core_search\document + */ + public function get_document($entry, $options = array()) { + global $DB; + + try { + $cm = $this->get_cm('data', $entry->dataid, $entry->course); + $context = \context_module::instance($cm->id); + } catch (\dml_missing_record_exception $ex) { + // Notify it as we run here as admin, we should see everything. + debugging('Error retrieving mod_data ' . $entry->id . ' document, not all required data is available: ' . + $ex->getMessage(), DEBUG_DEVELOPER); + return false; + } catch (\dml_exception $ex) { + // Notify it as we run here as admin, we should see everything. + debugging('Error retrieving mod_data' . $entry->id . ' document: ' . $ex->getMessage(), DEBUG_DEVELOPER); + return false; + } + + // Prepare associative array with data from DB. + $doc = \core_search\document_factory::instance($entry->id, $this->componentname, $this->areaname); + $doc->set('contextid', $context->id); + $doc->set('courseid', $entry->course); + $doc->set('userid', $entry->userid); + $doc->set('owneruserid', \core_search\manager::NO_OWNER_ID); + $doc->set('modified', $entry->timemodified); + + $indexfields = $this->get_fields_for_entries($entry); + + if (count($indexfields) < 2) { + return false; + } + + $doc->set('title', $indexfields[0]); + $doc->set('content', $indexfields[1]); + + if (isset($indexfields[2])) { + $doc->set('description1', $indexfields[2]); + } + + if (isset($indexfields[3])) { + $doc->set('description2', $indexfields[3]); + } + + return $doc; + } + + /** + * Whether the user can access the document or not. + * + * @throws \dml_missing_record_exception + * @throws \dml_exception + * @param int $id Glossary entry id + * @return bool + */ + public function check_access($id) { + global $DB, $USER; + + if (isguestuser()) { + return \core_search\manager::ACCESS_DENIED; + } + + $now = time(); + + $sql = "SELECT dr.*, d.* + FROM {data_records} dr + JOIN {data} d ON d.id = dr.dataid + WHERE dr.id = ?"; + + $entry = $DB->get_record_sql($sql, array( $id ), IGNORE_MISSING); + + if (!$entry) { + return \core_search\manager::ACCESS_DELETED; + } + + if (($entry->timeviewfrom && $now < $entry->timeviewfrom) || ($entry->timeviewto && $now > $entry->timeviewto)) { + return \core_search\manager::ACCESS_DENIED; + } + + $cm = $this->get_cm('data', $entry->dataid, $entry->course); + $context = \context_module::instance($cm->id); + + $canmanageentries = has_capability('mod/data:manageentries', $context); + + if (!has_capability('mod/data:viewentry', $context)) { + return \core_search\manager::ACCESS_DENIED; + } + + $numberofentriesindb = $DB->count_records('data_records', array('dataid' => $entry->dataid)); + $requiredentriestoview = $entry->requiredentriestoview; + + if ($requiredentriestoview && ($requiredentriestoview > $numberofentriesindb) && + ($USER->id != $entry->userid) && !$canmanageentries) { + return \core_search\manager::ACCESS_DENIED; + } + + if ($entry->approval && !$entry->approved && ($entry->userid != $USER->id) && !$canmanageentries) { + return \core_search\manager::ACCESS_DENIED; + } + + $currentgroup = groups_get_activity_group($cm, true); + $groupmode = groups_get_activity_groupmode($cm); + + if (($groupmode == 1) && ($entry->groupid != $currentgroup) && !$canmanageentries) { + return \core_search\manager::ACCESS_DENIED; + } + + return \core_search\manager::ACCESS_GRANTED; + } + + /** + * Link to database entry. + * + * @param \core_search\document $doc + * @return \moodle_url + */ + public function get_doc_url(\core_search\document $doc) { + $entry = $this->get_entry($doc->get('itemid')); + return new \moodle_url('/mod/data/view.php', array( 'd' => $entry->dataid, 'rid' => $entry->id )); + } + + /** + * Link to the database activity. + * + * @param \core_search\document $doc + * @return \moodle_url + */ + public function get_context_url(\core_search\document $doc) { + $entry = $this->get_entry($doc->get('itemid')); + return new \moodle_url('/mod/data/view.php', array('d' => $entry->dataid)); + } + + /** + * Returns true if this area uses file indexing. + * + * @return bool + */ + public function uses_file_indexing() { + return true; + } + + /** + * Add the database entries attachments. + * + * @param \core_search\document $doc + * @return void + */ + public function attach_files($doc) { + global $DB; + + $entryid = $doc->get('itemid'); + + try { + $entry = $this->get_entry($entryid); + } catch (\dml_missing_record_exception $e) { + debugging('Could not get record to attach files to '.$doc->get('id'), DEBUG_DEVELOPER); + return; + } + + $cm = $this->get_cm('data', $entry->dataid, $doc->get('courseid')); + $context = \context_module::instance($cm->id); + + // Get the files and attach them. + $fs = get_file_storage(); + $files = $fs->get_area_files($context->id, 'mod_data', 'content', $entryid, 'filename', false); + foreach ($files as $file) { + $doc->add_stored_file($file); + } + } + + /** + * Get database entry data + * + * @throws \dml_exception + * @param int $entryid + * @return stdClass + */ + protected function get_entry($entryid) { + global $DB; + + if (empty($this->entriesdata[$entryid])) { + $this->entriesdata[$entryid] = $DB->get_record('data_records', array( 'id' => $entryid ), '*', MUST_EXIST); + } + + return $this->entriesdata[$entryid]; + } + + /** + * get_fields_for_entries + * + * @param StdClass $entry + * @return array + */ + protected function get_fields_for_entries($entry) { + global $DB; + + $indexfields = array(); + $validfieldtypes = array('text', 'textarea', 'menu', 'radiobutton', 'checkbox', 'multimenu', 'url'); + + $sql = "SELECT dc.id, dc.content, df.name AS fldname, + df.type AS fieldtype, df.required + FROM {data_content} dc, {data_fields} df + WHERE dc.fieldid = df.id + AND dc.recordid = :recordid"; + + $contents = $DB->get_records_sql($sql, array('recordid' => $entry->id)); + $filteredcontents = array(); + + $template = $DB->get_record_sql('SELECT addtemplate FROM {data} WHERE id = ?', array($entry->dataid)); + $template = $template->addtemplate; + + // Filtering out the data_content records having invalid fieldtypes. + foreach ($contents as $content) { + if (in_array($content->fieldtype, $validfieldtypes)) { + $filteredcontents[] = $content; + } + } + + foreach ($filteredcontents as $content) { + $classname = 'data_field_' . trim($content->fieldtype); + $content->priority = $classname::get_priority(); + $content->addtemplateposition = strpos($template, '[['.$content->fldname.']]'); + } + + $orderqueue = new \SPLPriorityQueue(); + + // Filtering out contents which belong to fields that aren't present in the addtemplate of the database activity instance. + foreach ($filteredcontents as $content) { + + if ($content->addtemplateposition >= 0) { + $orderqueue->insert($content, $content->addtemplateposition); + } + } + + $filteredcontents = array(); + + while ($orderqueue->valid()) { + $filteredcontents[] = $orderqueue->extract(); + } + + // SPLPriorityQueue sorts according to descending order of the priority (here, addtemplateposition). + $filteredcontents = array_reverse($filteredcontents); + + // Using a CUSTOM SPLPriorityQueure instance to sort out the filtered contents according to these rules : + // 1. Priorities in $fieldtypepriorities + // 2. Compulsory fieldtypes are to be given the top priority. + $contentqueue = new sortedcontentqueue($filteredcontents); + + foreach ($filteredcontents as $key => $content) { + $contentqueue->insert($content, $key); + } + + while ($contentqueue->valid()) { + + $content = $contentqueue->extract(); + $classname = 'data_field_' . trim($content->fieldtype); + + $indexfields[] = $classname::get_content_value($content->content); + } + + return $indexfields; + } + +} \ No newline at end of file diff --git a/mod/data/classes/search/sortedcontentqueue.php b/mod/data/classes/search/sortedcontentqueue.php new file mode 100644 index 00000000000..12a555b47c5 --- /dev/null +++ b/mod/data/classes/search/sortedcontentqueue.php @@ -0,0 +1,80 @@ +. + +/** + * Priority Queue class to sort out db entry contents. + * + * @package mod_data + * @copyright 2016 Devang Gaur + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_data\search; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Priority Queue class to sort out db entry contents. + * + * @package mod_data + * @copyright 2016 Devang Gaur + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class sortedcontentqueue extends \SPLPriorityQueue { + + /** + * @var array All contents that will be sorted. + */ + private $contents; + + /** + * contructor + * + * @param array $contents + * @return void + */ + public function __construct($contents) { + $this->contents = $contents; + } + + /** + * comparator function overriden for sorting the records + * ...as per 'required' and 'priotirity' field values + * + * @param int $key1 + * @param int $key2 + * @return bool + */ + public function compare($key1 , $key2) { + $record1 = $this->contents[$key1]; + $record2 = $this->contents[$key2]; + + // If a content's fieldtype is compulsory in the database than it would have priority than any other noncompulsory content. + if ( ($record1->required && $record2->required) || (!$record1->required && !$record2->required)) { + if ($record1->priority === $record2->priority) { + return $key1 < $key2 ? 1 : -1; + } + + return $record1->priority < $record2->priority ? -1 : 1; + + } else if ($record1->required && !$record2->required) { + return 1; + } else { + return -1; + } + + } +} \ No newline at end of file diff --git a/mod/data/field/checkbox/field.class.php b/mod/data/field/checkbox/field.class.php index c1b60a836f5..c8675d98c35 100644 --- a/mod/data/field/checkbox/field.class.php +++ b/mod/data/field/checkbox/field.class.php @@ -25,6 +25,12 @@ class data_field_checkbox extends data_field_base { var $type = 'checkbox'; + /** + * priority for globalsearch indexing + * + * @var int + */ + protected static $priority = self::LOW_PRIORITY; function display_add_field($recordid = 0, $formdata = null) { global $CFG, $DB, $OUTPUT; @@ -242,4 +248,19 @@ class data_field_checkbox extends data_field_base { return $found; } + /** + * Returns the presentable string value for a field content. + * @param string $value + * @return string + */ + public static function get_content_value($value) { + $arr = explode('##', $value); + + $content = ''; + foreach ($arr as $a) { + $content .= $a.' '; + } + + return trim($content); + } } diff --git a/mod/data/field/menu/field.class.php b/mod/data/field/menu/field.class.php index 53e2d4f0410..1b62356e460 100644 --- a/mod/data/field/menu/field.class.php +++ b/mod/data/field/menu/field.class.php @@ -25,6 +25,12 @@ class data_field_menu extends data_field_base { var $type = 'menu'; + /** + * priority for globalsearch indexing + * + * @var int + */ + protected static $priority = self::HIGH_PRIORITY; function display_add_field($recordid = 0, $formdata = null) { global $DB, $OUTPUT; diff --git a/mod/data/field/multimenu/field.class.php b/mod/data/field/multimenu/field.class.php index 34beb47d41b..fb7e290b6c2 100644 --- a/mod/data/field/multimenu/field.class.php +++ b/mod/data/field/multimenu/field.class.php @@ -25,6 +25,12 @@ class data_field_multimenu extends data_field_base { var $type = 'multimenu'; + /** + * priority for globalsearch indexing + * + * @var int + * */ + protected static $priority = self::LOW_PRIORITY; function display_add_field($recordid = 0, $formdata = null) { global $DB, $OUTPUT; @@ -267,4 +273,21 @@ class data_field_multimenu extends data_field_base { unset($value['xxx']); return !empty($value); } + + /** + * Returns the presentable string value for a field content. + * @param string $value + * @return string + */ + public static function get_content_value($value) { + $arr = explode('##', $value); + + $content = ''; + foreach ($arr as $a) { + $content .= $a.' '; + } + + return trim($content); + } + } diff --git a/mod/data/field/radiobutton/field.class.php b/mod/data/field/radiobutton/field.class.php index 6dd1d3ecee3..dbc5c1e29ed 100644 --- a/mod/data/field/radiobutton/field.class.php +++ b/mod/data/field/radiobutton/field.class.php @@ -25,6 +25,12 @@ class data_field_radiobutton extends data_field_base { var $type = 'radiobutton'; + /** + * priority for globalsearch indexing + * + * @var int + */ + protected static $priority = self::HIGH_PRIORITY; function display_add_field($recordid = 0, $formdata = null) { global $CFG, $DB, $OUTPUT; diff --git a/mod/data/field/text/field.class.php b/mod/data/field/text/field.class.php index 9489db71f3b..dd72649249e 100644 --- a/mod/data/field/text/field.class.php +++ b/mod/data/field/text/field.class.php @@ -25,6 +25,12 @@ class data_field_text extends data_field_base { var $type = 'text'; + /** + * priority for globalsearch indexing + * + * @var int + */ + protected static $priority = self::MAX_PRIORITY; function display_search_field($value = '') { return '' . ''; diff --git a/mod/data/field/textarea/field.class.php b/mod/data/field/textarea/field.class.php index 659fed60b2d..a6d6248c1d2 100644 --- a/mod/data/field/textarea/field.class.php +++ b/mod/data/field/textarea/field.class.php @@ -27,6 +27,12 @@ require_once($CFG->dirroot.'/repository/lib.php'); class data_field_textarea extends data_field_base { var $type = 'textarea'; + /** + * priority for globalsearch indexing + * + * @var int + */ + protected static $priority = self::LOW_PRIORITY; /** * Returns options for embedded files @@ -275,4 +281,14 @@ class data_field_textarea extends data_field_base { } return false; } + + /** + * Returns the presentable string value for a field content. + * @param string $value + * @return string + */ + public static function get_content_value($value) { + return clean_param($value, PARAM_NOTAGS); + } + } diff --git a/mod/data/field/url/field.class.php b/mod/data/field/url/field.class.php index 521891146b3..6769c81a764 100644 --- a/mod/data/field/url/field.class.php +++ b/mod/data/field/url/field.class.php @@ -24,6 +24,12 @@ class data_field_url extends data_field_base { var $type = 'url'; + /** + * priority for globalsearch indexing + * + * @var int + */ + protected static $priority = self::MIN_PRIORITY; function display_add_field($recordid = 0, $formdata = null) { global $CFG, $DB, $OUTPUT, $PAGE; diff --git a/mod/data/lang/en/data.php b/mod/data/lang/en/data.php index a8127e0dfa1..4b0e332b58b 100644 --- a/mod/data/lang/en/data.php +++ b/mod/data/lang/en/data.php @@ -324,6 +324,7 @@ $string['savesuccess'] = 'Saved successfully. Your preset will now be available $string['savetemplate'] = 'Save template'; $string['search'] = 'Search'; $string['search:activity'] = 'Database - activity information'; +$string['search:entry'] = 'Database - entries'; $string['selectedrequired'] = 'All selected required'; $string['showall'] = 'Show all entries'; $string['single'] = 'View single'; diff --git a/mod/data/lib.php b/mod/data/lib.php index 6c03edf4921..5accbeb46ab 100644 --- a/mod/data/lib.php +++ b/mod/data/lib.php @@ -64,6 +64,18 @@ class data_field_base { // Base class for Database Field Types (see field/*/ var $cm; /** @var object activity context */ var $context; + /** @var priority for globalsearch indexing */ + protected static $priority = self::NO_PRIORITY; + /** priority value for invalid fields regarding indexing */ + const NO_PRIORITY = 0; + /** priority value for minimum priority */ + const MIN_PRIORITY = 1; + /** priority value for low priority */ + const LOW_PRIORITY = 2; + /** priority value for high priority */ + const HIGH_PRIORITY = 3; + /** priority value for maximum priority */ + const MAX_PRIORITY = 4; /** * Constructor function @@ -527,6 +539,24 @@ class data_field_base { // Base class for Database Field Types (see field/*/ function file_ok($relativepath) { return false; } + + /** + * Returns the priority for being indexed by globalsearch + * + * @return int + */ + public static function get_priority() { + return static::$priority; + } + + /** + * Returns the presentable string value for a field content. + * @param string $value + * @return string + */ + public static function get_content_value($value) { + return trim($value); + } } diff --git a/mod/data/tests/generator/lib.php b/mod/data/tests/generator/lib.php index 86480c91e21..e511bbb8788 100644 --- a/mod/data/tests/generator/lib.php +++ b/mod/data/tests/generator/lib.php @@ -133,8 +133,10 @@ class mod_data_generator extends testing_module_generator { } if (!isset($record['param1'])) { - if (in_array($record['type'], array('checkbox', 'menu', 'multimenu', 'radiobutton'))) { - $record['param1'] = implode("\n", array('one', 'two', 'three', 'four')); + if (in_array($record['type'], array('checkbox', 'radiobutton'))) { + $record['param1'] = implode("\n", array('opt1', 'opt2', 'opt3', 'opt4')); + } else if (in_array($record['type'], array('multimenu', 'menu'))) { + $record['param1'] = implode("\n", array('menu1', 'menu2', 'menu3', 'menu4')); } else if (($record['type'] === 'text') || ($record['type'] === 'url')) { $record['param1'] = 1; } else { @@ -185,6 +187,8 @@ class mod_data_generator extends testing_module_generator { /** * Creates a field for a mod_data instance. + * Keep in mind the default data field params created in create_field() function! + * ...if you haven't provided your own custom data field parameters there. * Currently, the field types in the ignoredfieldtypes array aren't supported. * The developers using the generator must adhere to the following format : * @@ -203,12 +207,12 @@ class mod_data_generator extends testing_module_generator { * @param array $contents * @return data_field_{type} */ - public function create_entry($data, array $contents) { + public function create_entry($data, array $contents, $groupid = 0) { global $DB; $this->databaserecordcount++; - $recordid = data_add_record($data); + $recordid = data_add_record($data, $groupid); $fields = $DB->get_records('data_fields', array('dataid' => $data->id)); @@ -254,11 +258,11 @@ class mod_data_generator extends testing_module_generator { $contents[$fieldid] = $values; - foreach ($values as $fieldname => $value) { - if (!$field->notemptyfield($value, $fieldname)) { - $fieldhascontent = false; - } + $fieldname = 'field_' . $fieldid; + if (!$field->notemptyfield($values[$fieldname], $fieldname)) { + $fieldhascontent = false; } + } else if ($field->type === 'url') { $values = array(); @@ -271,12 +275,11 @@ class mod_data_generator extends testing_module_generator { } $contents[$fieldid] = $values; - - foreach ($values as $fieldname => $value) { - if (!$field->notemptyfield($value, $fieldname)) { - $fieldhascontent = false; - } + $fieldname = 'field_' . $fieldid . '_0'; + if (!$field->notemptyfield($values[$fieldname], $fieldname)) { + $fieldhascontent = false; } + } else { if ($field->notemptyfield($contents[$fieldid], 'field_' . $fieldid . '_0')) { continue; @@ -291,7 +294,7 @@ class mod_data_generator extends testing_module_generator { foreach ($contents as $fieldid => $content) { $field = data_get_field_from_id($fieldid, $data); - if (is_array($content)) { + if (is_array($content) and in_array($field->type, array('date', 'textarea', 'url'))) { foreach ($content as $fieldname => $value) { $field->update_content($recordid, $value, $fieldname); diff --git a/mod/data/tests/generator_test.php b/mod/data/tests/generator_test.php index c554423f66f..ebcfa335dec 100644 --- a/mod/data/tests/generator_test.php +++ b/mod/data/tests/generator_test.php @@ -136,7 +136,12 @@ class mod_data_generator_testcase extends advanced_testcase { $this->setAdminUser(); $this->assertEquals(0, $DB->count_records('data')); + $user1 = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + + $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupA')); + $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $groupa->id)); /** @var mod_data_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('mod_data'); @@ -166,6 +171,7 @@ class mod_data_generator_testcase extends advanced_testcase { $record = new StdClass(); $record->name = $fieldname; $record->type = $fieldtype; + $record->required = 1; ${$fieldname} = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field($record, $data); $this->assertInstanceOf('data_field_' . $fieldtype, ${$fieldname}); @@ -177,12 +183,12 @@ class mod_data_generator_testcase extends advanced_testcase { $fields = $DB->get_records('data_fields', array('dataid' => $data->id), 'id'); $contents = array(); - $contents[] = array('one', 'two', 'three', 'four'); + $contents[] = array('opt1', 'opt2', 'opt3', 'opt4'); $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows. - $contents[] = 'one'; - $contents[] = array('one', 'two', 'three', 'four'); + $contents[] = 'menu1'; + $contents[] = array('menu1', 'menu2', 'menu3', 'menu4'); $contents[] = '12345'; - $contents[] = 'one'; + $contents[] = 'opt1'; $contents[] = 'text for testing'; $contents[] = '

text area testing

'; $contents[] = array('example.url', 'sampleurl'); @@ -192,9 +198,36 @@ class mod_data_generator_testcase extends advanced_testcase { $fieldcontents[$fieldrecord->id] = $contents[$count++]; } - $datarecordid = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data, $fieldcontents); + $datarecordid = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data, $fieldcontents, + $groupa->id); $this->assertEquals(1, $DB->count_records('data_records', array('dataid' => $data->id))); $this->assertEquals(count($contents), $DB->count_records('data_content', array('recordid' => $datarecordid))); + + $entry = $DB->get_record('data_records', array('id' => $datarecordid)); + $this->assertEquals($entry->groupid, $groupa->id); + + $contents = $DB->get_records('data_content', array('recordid' => $datarecordid)); + + $contentstartid = 0; + $flag = 0; + foreach ($contents as $key => $content) { + if (!$flag++) { + $contentstartid = $key; + } + $this->assertFalse($content->content == null); + } + + $this->assertEquals($contents[$contentstartid]->content, 'opt1##opt2##opt3##opt4'); + $this->assertEquals($contents[++$contentstartid]->content, '2114380800'); + $this->assertEquals($contents[++$contentstartid]->content, 'menu1'); + $this->assertEquals($contents[++$contentstartid]->content, 'menu1##menu2##menu3##menu4'); + $this->assertEquals($contents[++$contentstartid]->content, '12345'); + $this->assertEquals($contents[++$contentstartid]->content, 'opt1'); + $this->assertEquals($contents[++$contentstartid]->content, 'text for testing'); + $this->assertEquals($contents[++$contentstartid]->content, '

text area testing

'); + $this->assertEquals($contents[$contentstartid]->content1, '1'); + $this->assertEquals($contents[++$contentstartid]->content, 'http://example.url'); + $this->assertEquals($contents[$contentstartid]->content1, 'sampleurl'); } -} +} \ No newline at end of file diff --git a/mod/data/tests/search_test.php b/mod/data/tests/search_test.php index 1e54d95e9d2..ee6b073ddae 100644 --- a/mod/data/tests/search_test.php +++ b/mod/data/tests/search_test.php @@ -28,8 +28,10 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/data/lib.php'); +require_once($CFG->dirroot . '/lib/datalib.php'); require_once($CFG->dirroot . '/lib/csvlib.class.php'); - +require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php'); +require_once($CFG->dirroot . '/mod/data/tests/generator/lib.php'); /** * Unit tests for {@see data_get_all_recordids()}. @@ -41,7 +43,7 @@ require_once($CFG->dirroot . '/lib/csvlib.class.php'); * @copyright 2012 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class data_advanced_search_sql_test extends advanced_testcase { +class mod_data_search_test extends advanced_testcase { /** * @var stdObject $recorddata An object that holds information from the table data. */ @@ -90,6 +92,11 @@ class data_advanced_search_sql_test extends advanced_testcase { */ public $approvedatarecordcount = 89; + /** + * @var string Area id + */ + protected $databaseentryareaid = null; + /** * Set up function. In this instance we are setting up database * records to be used in the unit tests. @@ -100,6 +107,43 @@ class data_advanced_search_sql_test extends advanced_testcase { $this->resetAfterTest(true); + set_config('enableglobalsearch', true); + + $this->databaseentryareaid = \core_search\manager::generate_areaid('mod_data', 'entry'); + + // Set \core_search::instance to the mock_search_engine as we don't require the search engine to be working to test this. + $search = testable_core_search::instance(); + + } + + /** + * Test 1: The function data_get_all_recordids. + * + * Test 2: This tests the data_get_advance_search_ids() function. The function takes a set + * of all the record IDs in the database and then with the search details ($this->recordsearcharray) + * returns a comma seperated string of record IDs that match the search criteria. + * + * Test 3: This function tests data_get_recordids(). This is the function that is nested in the last + * function (see data_get_advance_search_ids). This function takes a couple of + * extra parameters. $alias is the field alias used in the sql query and $commaid + * is a comma seperated string of record IDs. + * + * Test 3.1: This tests that if no recordids are provided (In a situation where a search is done on an empty database) + * That an empty array is returned. + * + * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records + * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test + * takes that information and does a search on the database, returning a record. + * + * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to + * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed + * from the total so we should only have 75 records total. + * + * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to + * display the records that have been approved. In this record set we have 89 approved records. + */ + public function test_advanced_search_sql_section() { + global $DB; // we already have 2 users, we need 98 more - let's ignore the fact that guest can not post anywhere // We reset the user sequence here to ensure we get the expected numbers. @@ -116,9 +160,9 @@ class data_advanced_search_sql_test extends advanced_testcase { // Set up data for the test database. $files = array( - 'data_fields' => __DIR__.'/fixtures/test_data_fields.csv', - 'data_records' => __DIR__.'/fixtures/test_data_records.csv', - 'data_content' => __DIR__.'/fixtures/test_data_content.csv', + 'data_fields' => __DIR__.'/fixtures/test_data_fields.csv', + 'data_records' => __DIR__.'/fixtures/test_data_records.csv', + 'data_content' => __DIR__.'/fixtures/test_data_content.csv', ); $this->loadDataSet($this->createCsvDataSet($files)); // Set dataid to the correct value now the data has been inserted by csv file. @@ -127,10 +171,10 @@ class data_advanced_search_sql_test extends advanced_testcase { // Create the search array which contains our advanced search criteria. $fieldinfo = array('0' => new stdClass(), - '1' => new stdClass(), - '2' => new stdClass(), - '3' => new stdClass(), - '4' => new stdClass()); + '1' => new stdClass(), + '2' => new stdClass(), + '3' => new stdClass(), + '4' => new stdClass()); $fieldinfo['0']->id = 1; $fieldinfo['0']->data = '3.721,46.6126'; $fieldinfo['1']->id = 2; @@ -175,36 +219,6 @@ class data_advanced_search_sql_test extends advanced_testcase { $this->finalrecord[6]->picture = $user->picture; $this->finalrecord[6]->imagealt = $user->imagealt; $this->finalrecord[6]->email = $user->email; - } - - /** - * Test 1: The function data_get_all_recordids. - * - * Test 2: This tests the data_get_advance_search_ids() function. The function takes a set - * of all the record IDs in the database and then with the search details ($this->recordsearcharray) - * returns a comma seperated string of record IDs that match the search criteria. - * - * Test 3: This function tests data_get_recordids(). This is the function that is nested in the last - * function (@see data_get_advance_search_ids). This function takes a couple of - * extra parameters. $alias is the field alias used in the sql query and $commaid - * is a comma seperated string of record IDs. - * - * Test 3.1: This tests that if no recordids are provided (In a situation where a search is done on an empty database) - * That an empty array is returned. - * - * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records - * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test - * takes that information and does a search on the database, returning a record. - * - * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to - * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed - * from the total so we should only have 75 records total. - * - * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to - * display the records that have been approved. In this record set we have 89 approved records. - */ - function test_advanced_search_sql_section() { - global $DB; // Test 1 $recordids = data_get_all_recordids($this->recorddata->id); @@ -242,4 +256,744 @@ class data_advanced_search_sql_test extends advanced_testcase { $recordids = data_get_all_recordids($this->recorddata->id, $approvesql, $params); $this->assertEquals($this->approvedatarecordcount, count($recordids)); } -} + + /** + * Indexing database entries contents. + * + * @return void + */ + public function test_data_entries_indexing() { + global $DB; + + // Returns the instance as long as the area is supported. + $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid); + $this->assertInstanceOf('\mod_data\search\entry', $searcharea); + + $user1 = self::getDataGenerator()->create_user(); + + $course1 = self::getDataGenerator()->create_course(); + + $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student'); + + $record = new stdClass(); + $record->course = $course1->id; + + $this->setUser($user1); + + // Available for both student and teacher. + $data1 = $this->getDataGenerator()->create_module('data', $record); + + // Excluding LatLong and Picture as we aren't indexing LatLong and Picture fields any way + // ...and they're complex and not of any use to consider for this test. + // Excluding File as we are indexing files seperately and its complex to implement. + $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' ); + + $this->create_default_data_fields($fieldtypes, $data1); + + $data1record1id = $this->create_default_data_record($data1); + // All records. + $recordset = $searcharea->get_recordset_by_timestamp(0); + + $this->assertTrue($recordset->valid()); + + $nrecords = 0; + foreach ($recordset as $record) { + $this->assertInstanceOf('stdClass', $record); + $doc = $searcharea->get_document($record); + $this->assertInstanceOf('\core_search\document', $doc); + $nrecords++; + } + + // If there would be an error/failure in the foreach above the recordset would be closed on shutdown. + $recordset->close(); + $this->assertEquals(1, $nrecords); + + // The +2 is to prevent race conditions. + $recordset = $searcharea->get_recordset_by_timestamp(time() + 2); + + // No new records. + $this->assertFalse($recordset->valid()); + $recordset->close(); + } + + /** + * Document contents. + * + * @return void + */ + public function test_data_entries_document() { + global $DB; + + // Returns the instance as long as the area is supported. + $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid); + $this->assertInstanceOf('\mod_data\search\entry', $searcharea); + + $user1 = self::getDataGenerator()->create_user(); + + $course = self::getDataGenerator()->create_course(); + + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + + $record = new stdClass(); + $record->course = $course->id; + + $this->setAdminUser(); + + // First Case. + $data1 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' ); + + $this->create_default_data_fields($fieldtypes, $data1); + + $data1record1id = $this->create_default_data_record($data1); + + $data1entry1 = $this->get_entry_for_id($data1record1id); + + $data1doc = $searcharea->get_document($data1entry1); + + $this->assertEquals($data1doc->get('courseid'), $course->id); + $this->assertEquals($data1doc->get('title'), 'text for testing'); + $this->assertEquals($data1doc->get('content'), 'menu1'); + $this->assertEquals($data1doc->get('description1'), 'opt1'); + $this->assertEquals($data1doc->get('description2'), 'opt1 opt2 opt3 opt4'); + + // Second Case. + $data2 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( + array('checkbox', 1), + array('textarea', 0), + array('menu', 0), + array('number', 1), + array('url', 0), + array('text', 0) + ); + + $this->create_default_data_fields($fieldtypes, $data2); + + $data2record1id = $this->create_default_data_record($data2); + + $data2entry1 = $this->get_entry_for_id($data2record1id); + + $data2doc = $searcharea->get_document($data2entry1); + + $this->assertEquals($data2doc->get('courseid'), $course->id); + $this->assertEquals($data2doc->get('title'), 'opt1 opt2 opt3 opt4'); + $this->assertEquals($data2doc->get('content'), 'text for testing'); + $this->assertEquals($data2doc->get('description1'), 'menu1'); + $this->assertEquals($data2doc->get('description2'), 'text area testing'); + + // Third Case. + $data3 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( 'url' ); + + $this->create_default_data_fields($fieldtypes, $data3); + + $data3record1id = $this->create_default_data_record($data3); + + $data3entry1 = $this->get_entry_for_id($data3record1id); + + $this->assertFalse($searcharea->get_document($data3entry1)); + + // Fourth Case. + $data4 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( array('date', 1), array('text', 1)); + + $this->create_default_data_fields($fieldtypes, $data4); + + $data4record1id = $this->create_default_data_record($data4); + + $data4entry1 = $this->get_entry_for_id($data4record1id); + + $this->assertFalse($searcharea->get_document($data4entry1)); + + // Fifth Case. + $data5 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( + array('checkbox', 0), + array('number', 1), + array('text', 0), + array('date', 1), + array('textarea', 0), + array('url', 1)); + + $this->create_default_data_fields($fieldtypes, $data5); + + $data5record1id = $this->create_default_data_record($data5); + + $data5entry1 = $this->get_entry_for_id($data5record1id); + + $data5doc = $searcharea->get_document($data5entry1); + + $this->assertEquals($data5doc->get('courseid'), $course->id); + $this->assertEquals($data5doc->get('title'), 'http://example.url'); + $this->assertEquals($data5doc->get('content'), 'text for testing'); + $this->assertEquals($data5doc->get('description1'), 'opt1 opt2 opt3 opt4'); + $this->assertEquals($data5doc->get('description2'), 'text area testing'); + + // Sixth Case. + $data6 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( array('date', 1), array('number', 1)); + + $this->create_default_data_fields($fieldtypes, $data6); + + $data6record1id = $this->create_default_data_record($data6); + + $data6entry1 = $this->get_entry_for_id($data6record1id); + + $data6doc = $searcharea->get_document($data6entry1); + + $this->assertFalse($data6doc); + + // Seventh Case. + $data7 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( array('date', 1), array('number', 1), + array('text', 0), array('textarea', 0)); + + $this->create_default_data_fields($fieldtypes, $data7); + + $data7record1id = $this->create_default_data_record($data7); + + $data7entry1 = $this->get_entry_for_id($data7record1id); + + $data7doc = $searcharea->get_document($data7entry1); + + $this->assertEquals($data7doc->get('courseid'), $course->id); + $this->assertEquals($data7doc->get('title'), 'text for testing'); + $this->assertEquals($data7doc->get('content'), 'text area testing'); + + // Eight Case. + $data8 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array('url', 'url', 'url', 'text'); + + $this->create_default_data_fields($fieldtypes, $data8); + + $data8record1id = $this->create_default_data_record($data8); + + $data8entry1 = $this->get_entry_for_id($data8record1id); + + $data8doc = $searcharea->get_document($data8entry1); + + $this->assertEquals($data8doc->get('courseid'), $course->id); + $this->assertEquals($data8doc->get('title'), 'text for testing'); + $this->assertEquals($data8doc->get('content'), 'http://example.url'); + $this->assertEquals($data8doc->get('description1'), 'http://example.url'); + $this->assertEquals($data8doc->get('description2'), 'http://example.url'); + + // Ninth Case. + $data9 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array('radiobutton', 'menu', 'multimenu'); + + $this->create_default_data_fields($fieldtypes, $data9); + + $data9record1id = $this->create_default_data_record($data9); + + $data9entry1 = $this->get_entry_for_id($data9record1id); + + $data9doc = $searcharea->get_document($data9entry1); + + $this->assertEquals($data9doc->get('courseid'), $course->id); + $this->assertEquals($data9doc->get('title'), 'opt1'); + $this->assertEquals($data9doc->get('content'), 'menu1'); + $this->assertEquals($data9doc->get('description1'), 'menu1 menu2 menu3 menu4'); + + // Tenth Case. + $data10 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array('checkbox', 'textarea', 'multimenu'); + + $this->create_default_data_fields($fieldtypes, $data10); + + $data10record1id = $this->create_default_data_record($data10); + + $data10entry1 = $this->get_entry_for_id($data10record1id); + + $data10doc = $searcharea->get_document($data10entry1); + + $this->assertEquals($data10doc->get('courseid'), $course->id); + $this->assertEquals($data10doc->get('title'), 'opt1 opt2 opt3 opt4'); + $this->assertEquals($data10doc->get('content'), 'text area testing'); + $this->assertEquals($data10doc->get('description1'), 'menu1 menu2 menu3 menu4'); + + } + + /** + * Document accesses. + * + * @return void + */ + public function test_data_entries_access() { + global $DB; + + // Returns the instance as long as the area is supported. + $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid); + $this->assertInstanceOf('\mod_data\search\entry', $searcharea); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $userteacher1 = self::getDataGenerator()->create_user(); + + $course1 = self::getDataGenerator()->create_course(); + $course2 = self::getDataGenerator()->create_course(); + + $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student'); + $this->getDataGenerator()->enrol_user($user2->id, $course1->id, 'student'); + $this->getDataGenerator()->enrol_user($userteacher1->id, $course1->id, 'teacher'); + + $this->getDataGenerator()->enrol_user($user3->id, $course2->id, 'student'); + + $record = new stdClass(); + $record->course = $course1->id; + + $this->setUser($userteacher1); + + $data1 = $this->getDataGenerator()->create_module('data', $record); + + $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' ); + + $this->create_default_data_fields($fieldtypes, $data1); + + $this->setUser($user1); + $data1record1id = $this->create_default_data_record($data1); + + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id)); + $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1)); + + $this->setUser($user2); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id)); + + $this->setUser($user3); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data1record1id)); + + $this->setUser($userteacher1); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id)); + + $this->setAdminUser(); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id)); + + $this->setGuestUser(); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data1record1id)); + + // Case with groups. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $userteacher1 = self::getDataGenerator()->create_user(); + + $course = self::getDataGenerator()->create_course(array('groupmode' => 1, 'groupmodeforce' => 1)); + + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($userteacher1->id, $course->id, 'teacher'); + $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student'); + + $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupA')); + $groupb = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupB')); + + $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $groupa->id)); + $this->getDataGenerator()->create_group_member(array('userid' => $user2->id, 'groupid' => $groupa->id)); + $this->getDataGenerator()->create_group_member(array('userid' => $userteacher1->id, 'groupid' => $groupa->id)); + + $this->getDataGenerator()->create_group_member(array('userid' => $user3->id, 'groupid' => $groupb->id)); + + $record = new stdClass(); + $record->course = $course->id; + + $this->setUser($userteacher1); + + $data2 = $this->getDataGenerator()->create_module('data', $record); + + $cm = get_coursemodule_from_instance('data', $data2->id, $course->id); + $cm->groupmode = '1'; + $cm->effectivegroupmode = '1'; + + $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' ); + + $this->create_default_data_fields($fieldtypes, $data2); + + $this->setUser($user1); + + $data2record1id = $this->create_default_data_record($data2, $groupa->id); + + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id)); + $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1)); + + $this->setUser($user2); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id)); + + $this->setUser($user3); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data2record1id)); + + $this->setUser($userteacher1); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id)); + + $this->setAdminUser(); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id)); + + $this->setGuestUser(); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data2record1id)); + + // Case with approval. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $userteacher1 = self::getDataGenerator()->create_user(); + + $course = self::getDataGenerator()->create_course(); + + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($userteacher1->id, $course->id, 'teacher'); + + $record = new stdClass(); + $record->course = $course->id; + + $this->setUser($userteacher1); + + $data3 = $this->getDataGenerator()->create_module('data', $record); + + $DB->update_record('data', array('id' => $data3->id, 'approval' => 1)); + + $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' ); + + $this->create_default_data_fields($fieldtypes, $data3); + + $this->setUser($user1); + + $data3record1id = $this->create_default_data_record($data3); + + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1)); + + $this->setUser($user2); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id)); + + $this->setUser($userteacher1); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + + $this->setAdminUser(); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + + $this->setGuestUser(); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id)); + + $DB->update_record('data_records', array('id' => $data3record1id, 'approved' => 1)); + + $this->setUser($user1); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1)); + + $this->setUser($user2); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + + $this->setUser($userteacher1); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + + $this->setAdminUser(); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id)); + + $this->setGuestUser(); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id)); + + // Case with requiredentriestoview. + $this->setAdminUser(); + + $record->requiredentriestoview = 2; + + $data4 = $this->getDataGenerator()->create_module('data', $record); + $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' ); + + $this->create_default_data_fields($fieldtypes, $data4); + + $data4record1id = $this->create_default_data_record($data4); + + $this->setUser($user1); + $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data4record1id)); + + $data4record2id = $this->create_default_data_record($data4); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data4record1id)); + $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data4record2id)); + } + + /** + * Test for file contents. + * + * @return void + */ + public function test_attach_files() { + global $DB, $USER; + + $fs = get_file_storage(); + + // Returns the instance as long as the area is supported. + $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid); + $this->assertInstanceOf('\mod_data\search\entry', $searcharea); + + $user1 = self::getDataGenerator()->create_user(); + + $course = self::getDataGenerator()->create_course(); + + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + + $record = new stdClass(); + $record->course = $course->id; + + $this->setAdminUser(); + + // Creating database activity instance. + $data1 = $this->getDataGenerator()->create_module('data', $record); + + // Creating file field. + $record = new stdClass; + $record->type = 'file'; + $record->dataid = $data1->id; + $record->required = 0; + $record->name = 'FileFld'; + $record->description = 'Just another file field'; + $record->param3 = 0; + $record->param1 = ''; + $record->param2 = ''; + + $data1filefieldid = $DB->insert_record('data_fields', $record); + + // Creating text field. + $record = new stdClass; + $record->type = 'text'; + $record->dataid = $data1->id; + $record->required = 0; + $record->name = 'TextFld'; + $record->description = 'Just another text field'; + $record->param3 = 0; + $record->param1 = ''; + $record->param2 = ''; + + $data1textfieldid = $DB->insert_record('data_fields', $record); + + // Creating textarea field. + $record = new stdClass; + $record->type = 'textarea'; + $record->dataid = $data1->id; + $record->required = 0; + $record->name = 'TextAreaFld'; + $record->description = 'Just another textarea field'; + $record->param1 = ''; + $record->param2 = 60; + $record->param3 = 35; + $record->param3 = 1; + $record->param3 = 0; + + $data1textareafieldid = $DB->insert_record('data_fields', $record); + + // Creating 1st entry. + $record = new stdClass; + $record->userid = $USER->id; + $record->dataid = $data1->id; + $record->groupid = 0; + + $data1record1id = $DB->insert_record('data_records', $record); + + $filerecord = array( + 'contextid' => context_module::instance($data1->cmid)->id, + 'component' => 'mod_data', + 'filearea' => 'content', + 'itemid' => $data1record1id, + 'filepath' => '/', + 'filename' => 'myfile1.txt' + ); + + $data1record1file = $fs->create_file_from_string($filerecord, 'Some contents 1'); + + $record = new stdClass; + $record->fieldid = $data1filefieldid; + $record->recordid = $data1record1id; + $record->content = 'myfile1.txt'; + $DB->insert_record('data_content', $record); + + $record = new stdClass; + $record->fieldid = $data1textfieldid; + $record->recordid = $data1record1id; + $record->content = 'sample text'; + $DB->insert_record('data_content', $record); + + $record = new stdClass; + $record->fieldid = $data1textareafieldid; + $record->recordid = $data1record1id; + $record->content = '
sample text


'; + $record->content1 = 1; + $DB->insert_record('data_content', $record); + + // Creating 2nd entry. + $record = new stdClass; + $record->userid = $USER->id; + $record->dataid = $data1->id; + $record->groupid = 0; + $data1record2id = $DB->insert_record('data_records', $record); + + $filerecord['itemid'] = $data1record2id; + $filerecord['filename'] = 'myfile2.txt'; + $data1record2file = $fs->create_file_from_string($filerecord, 'Some contents 2'); + + $record = new stdClass; + $record->fieldid = $data1filefieldid; + $record->recordid = $data1record2id; + $record->content = 'myfile2.txt'; + $DB->insert_record('data_content', $record); + + $record = new stdClass; + $record->fieldid = $data1textfieldid; + $record->recordid = $data1record2id; + $record->content = 'sample text'; + $DB->insert_record('data_content', $record); + + $record = new stdClass; + $record->fieldid = $data1textareafieldid; + $record->recordid = $data1record2id; + $record->content = '
sample text


'; + $record->content1 = 1; + $DB->insert_record('data_content', $record); + + // Now get all the posts and see if they have the right files attached. + $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid); + $recordset = $searcharea->get_recordset_by_timestamp(0); + $nrecords = 0; + foreach ($recordset as $record) { + $doc = $searcharea->get_document($record); + $searcharea->attach_files($doc); + $files = $doc->get_files(); + // Now check that each doc has the right files on it. + switch ($doc->get('itemid')) { + case ($data1record1id): + $this->assertCount(1, $files); + $this->assertEquals($data1record1file->get_id(), $files[$data1record1file->get_id()]->get_id()); + break; + case ($data1record2id): + $this->assertCount(1, $files); + $this->assertEquals($data1record2file->get_id(), $files[$data1record2file->get_id()]->get_id()); + break; + default: + $this->fail('Unexpected entry returned'); + break; + } + $nrecords++; + } + $recordset->close(); + $this->assertEquals(2, $nrecords); + } + + /** + * Creates default fields for a database instance + * + * @param array $fieldtypes + * @param mod_data $data + * @return void + */ + protected function create_default_data_fields($fieldtypes = array(), $data) { + $count = 1; + + // Creating test Fields with default parameter values. + foreach ($fieldtypes as $fieldtype) { + + // Creating variables dynamically. + $fieldname = 'field-'.$count; + $record = new stdClass(); + $record->name = $fieldname; + + if (is_array($fieldtype)) { + $record->type = $fieldtype[0]; + $record->required = $fieldtype[1]; + } else { + $record->type = $fieldtype; + $record->required = 0; + } + + ${$fieldname} = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field($record, $data); + $count++; + } + } + + /** + * Creates default database entry content values for default field param values + * + * @param mod_data $data + * @param int $groupid + * @return int + */ + protected function create_default_data_record($data, $groupid = 0) { + global $DB; + + $fields = $DB->get_records('data_fields', array('dataid' => $data->id)); + + $fieldcontents = array(); + foreach ($fields as $fieldrecord) { + switch ($fieldrecord->type) { + case 'checkbox': + $fieldcontents[$fieldrecord->id] = array('opt1', 'opt2', 'opt3', 'opt4'); + break; + + case 'multimenu': + $fieldcontents[$fieldrecord->id] = array('menu1', 'menu2', 'menu3', 'menu4'); + break; + + case 'date': + $fieldcontents[$fieldrecord->id] = '27-07-2016'; + break; + + case 'menu': + $fieldcontents[$fieldrecord->id] = 'menu1'; + break; + + case 'radiobutton': + $fieldcontents[$fieldrecord->id] = 'opt1'; + break; + + case 'number': + $fieldcontents[$fieldrecord->id] = '12345'; + break; + + case 'text': + $fieldcontents[$fieldrecord->id] = 'text for testing'; + break; + + case 'textarea': + $fieldcontents[$fieldrecord->id] = '

text area testing

'; + break; + + case 'url': + $fieldcontents[$fieldrecord->id] = array('example.url', 'sampleurl'); + break; + + default: + $this->fail('Unexpected field type'); + break; + } + + } + + return $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data, $fieldcontents, $groupid); + } + + /** + * Creates default database entry content values for default field param values + * + * @param int $recordid + * @return stdClass + */ + protected function get_entry_for_id($recordid ) { + global $DB; + + $sql = "SELECT dr.*, d.course + FROM {data_records} dr + JOIN {data} d ON d.id = dr.dataid + WHERE dr.id = :drid"; + return $DB->get_record_sql($sql, array('drid' => $recordid)); + } + +} \ No newline at end of file