diff --git a/course/classes/search/mycourse.php b/course/classes/search/mycourse.php index 9c3378c5e2ce1..9cbdc58e67967 100644 --- a/course/classes/search/mycourse.php +++ b/course/classes/search/mycourse.php @@ -174,4 +174,14 @@ public function get_search_fileareas() { public function get_component_name() { return 'course'; } + + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * @return \core_search\document_icon + */ + public function get_doc_icon(\core_search\document $doc) : \core_search\document_icon { + return new \core_search\document_icon('i/course'); + } } diff --git a/course/classes/search/section.php b/course/classes/search/section.php index ce286648a3d31..42badb486a994 100644 --- a/course/classes/search/section.php +++ b/course/classes/search/section.php @@ -195,4 +195,14 @@ public function get_search_fileareas() { public function get_component_name() { return 'course'; } + + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * @return \core_search\document_icon + */ + public function get_doc_icon(\core_search\document $doc) : \core_search\document_icon { + return new \core_search\document_icon('i/section'); + } } diff --git a/course/tests/search_test.php b/course/tests/search_test.php index 9751f1adf241d..ac9d44d7a7f13 100644 --- a/course/tests/search_test.php +++ b/course/tests/search_test.php @@ -446,4 +446,36 @@ public function test_section_access() { $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access($documents[1]->get('itemid'))); } + + /** + * Test document icon for mycourse area. + */ + public function test_get_doc_icon_for_mycourse_area() { + $searcharea = \core_search\manager::get_search_area($this->mycoursesareaid); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $searcharea->get_doc_icon($document); + + $this->assertEquals('i/course', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } + + /** + * Test document icon for section area. + */ + public function test_get_doc_icon_for_section_area() { + $searcharea = \core_search\manager::get_search_area($this->sectionareaid); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $searcharea->get_doc_icon($document); + + $this->assertEquals('i/section', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } } diff --git a/message/classes/search/base_message.php b/message/classes/search/base_message.php index 58479f2542318..5a3912f0be629 100644 --- a/message/classes/search/base_message.php +++ b/message/classes/search/base_message.php @@ -196,4 +196,15 @@ protected function get_document_recordset_helper($modifiedfrom, \context $contex ORDER BY m.timecreated ASC"; return $DB->get_recordset_sql($sql, $params); } + + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * + * @return \core_search\document_icon + */ + public function get_doc_icon(\core_search\document $doc) : \core_search\document_icon { + return new \core_search\document_icon('t/message'); + } } diff --git a/message/tests/search_received_test.php b/message/tests/search_received_test.php index fcc29215a9d7c..79b7137ae3804 100644 --- a/message/tests/search_received_test.php +++ b/message/tests/search_received_test.php @@ -336,4 +336,20 @@ public function test_message_received_deleted_user() { $this->assertFalse($doc); } + + /** + * Test document icon. + */ + public function test_get_doc_icon() { + $searcharea = \core_search\manager::get_search_area($this->messagereceivedareaid); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $searcharea->get_doc_icon($document); + + $this->assertEquals('t/message', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } } diff --git a/message/tests/search_sent_test.php b/message/tests/search_sent_test.php index 69338d1f9d912..7edee7d6d8a58 100644 --- a/message/tests/search_sent_test.php +++ b/message/tests/search_sent_test.php @@ -351,4 +351,20 @@ public function test_message_sent_deleted_user() { $this->assertFalse($doc); } + + /** + * Test document icon. + */ + public function test_get_doc_icon() { + $searcharea = \core_search\manager::get_search_area($this->messagesentareaid); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $searcharea->get_doc_icon($document); + + $this->assertEquals('t/message', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } } diff --git a/search/classes/base.php b/search/classes/base.php index 97fb8ab8e12c3..d8c948b73ca18 100644 --- a/search/classes/base.php +++ b/search/classes/base.php @@ -509,4 +509,14 @@ protected function get_course_level_context_restriction_sql(\context $context = public function get_contexts_to_reindex() { return new \ArrayIterator([\context_system::instance()]); } + + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * @return \core_search\document_icon + */ + public function get_doc_icon(document $doc) : document_icon { + return new document_icon('i/empty'); + } } diff --git a/search/classes/base_block.php b/search/classes/base_block.php index 42f63d4bb8b8e..6f4bdc8a2eac6 100644 --- a/search/classes/base_block.php +++ b/search/classes/base_block.php @@ -398,4 +398,14 @@ public function get_contexts_to_reindex() { return \context::instance_by_id($id); }); } + + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * @return \core_search\document_icon + */ + public function get_doc_icon(document $doc) : document_icon { + return new document_icon('e/anchor'); + } } diff --git a/search/classes/base_mod.php b/search/classes/base_mod.php index b45ae69bd7fec..fcf5af636a131 100644 --- a/search/classes/base_mod.php +++ b/search/classes/base_mod.php @@ -286,4 +286,14 @@ public function supports_group_restriction() { public function restrict_cm_access_by_group(\cm_info $cm) { return $cm->effectivegroupmode == SEPARATEGROUPS; } + + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * @return \core_search\document_icon + */ + public function get_doc_icon(document $doc) : document_icon { + return new document_icon('icon', $this->get_module_name()); + } } diff --git a/search/classes/document.php b/search/classes/document.php index 080806635eb84..cdde9cecfb106 100644 --- a/search/classes/document.php +++ b/search/classes/document.php @@ -58,6 +58,11 @@ class document implements \renderable, \templatable { */ protected $contexturl = null; + /** + * @var \core_search\document_icon Document icon instance. + */ + protected $docicon = null; + /** * @var int|null The content field filearea. */ @@ -496,6 +501,24 @@ public function get_doc_url() { return $this->docurl; } + /** + * Sets document icon instance. + * + * @param \core_search\document_icon $docicon + */ + public function set_doc_icon(document_icon $docicon) { + $this->docicon = $docicon; + } + + /** + * Gets document icon instance. + * + * @return \core_search\document_icon + */ + public function get_doc_icon() { + return $this->docicon; + } + public function set_context_url(\moodle_url $url) { $this->contexturl = $url; } @@ -628,6 +651,10 @@ public function export_for_template(\renderer_base $output) { $data['userfullname'] = format_string($this->get('userfullname'), true, array('context' => $this->get('contextid'))); } + if ($docicon = $this->get_doc_icon()) { + $data['icon'] = $output->image_url($docicon->get_name(), $docicon->get_component()); + } + return $data; } diff --git a/search/classes/document_icon.php b/search/classes/document_icon.php new file mode 100644 index 0000000000000..151f61f06c764 --- /dev/null +++ b/search/classes/document_icon.php @@ -0,0 +1,77 @@ +. + +/** + * Document icon class. + * + * @package core_search + * @copyright 2018 Dmitrii Metelkin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_search; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Represents a document icon. + * + * @package core_search + * @copyright 2018 Dmitrii Metelkin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class document_icon { + /** + * Icon file name. + * @var string + */ + protected $name; + + /** Icon file component. + * @var string + */ + protected $component; + + /** + * Constructor. + * + * @param string $name Icon name. + * @param string $component Icon component. + */ + public function __construct($name, $component = 'moodle') { + $this->name = $name; + $this->component = $component; + } + + /** + * Returns name of the icon file. + * + * @return string + */ + public function get_name() { + return $this->name; + } + + /** + * Returns the component of the icon file. + * + * @return string + */ + public function get_component() { + return $this->component; + } + +} diff --git a/search/classes/engine.php b/search/classes/engine.php index fe7450d44584e..a6b22fc736b9d 100644 --- a/search/classes/engine.php +++ b/search/classes/engine.php @@ -199,6 +199,7 @@ protected function to_document(\core_search\base $searcharea, $docdata) { $doc->set_data_from_engine($docdata); $doc->set_doc_url($searcharea->get_doc_url($doc)); $doc->set_context_url($searcharea->get_context_url($doc)); + $doc->set_doc_icon($searcharea->get_doc_icon($doc)); // Uses the internal caches to get required data needed to render the document later. $course = $this->get_course($doc->get('courseid')); diff --git a/search/templates/result.mustache b/search/templates/result.mustache index 331c7a340a853..2cb71983b745e 100644 --- a/search/templates/result.mustache +++ b/search/templates/result.mustache @@ -62,7 +62,7 @@ }}

- {{{title}}} + {{#icon}}{{/icon}}{{{title}}}

{{#content}}
{{{content}}}
diff --git a/search/tests/base_activity_test.php b/search/tests/base_activity_test.php index 6c61544321269..8f99a292d281a 100644 --- a/search/tests/base_activity_test.php +++ b/search/tests/base_activity_test.php @@ -373,4 +373,25 @@ public function test_get_contexts_to_reindex() { $contexts = iterator_to_array($glossaryarea->get_contexts_to_reindex(), false); $this->assertEquals([], $contexts); } + + /** + * Test document icon. + */ + public function test_get_doc_icon() { + $baseactivity = $this->getMockBuilder('\core_search\base_activity') + ->disableOriginalConstructor() + ->setMethods(array('get_module_name')) + ->getMockForAbstractClass(); + + $baseactivity->method('get_module_name')->willReturn('test_activity'); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $baseactivity->get_doc_icon($document); + + $this->assertEquals('icon', $result->get_name()); + $this->assertEquals('test_activity', $result->get_component()); + } } diff --git a/search/tests/base_block_test.php b/search/tests/base_block_test.php index 5a6d5c164a01b..e6f345870c1c3 100644 --- a/search/tests/base_block_test.php +++ b/search/tests/base_block_test.php @@ -444,4 +444,22 @@ protected function get_doc($courseid, $blockinstanceid) { 'areaid' => $area->get_area_id(), 'itemid' => 0]; return $engine->to_document($area, $docdata); } + + /** + * Test document icon. + */ + public function test_get_doc_icon() { + $baseblock = $this->getMockBuilder('\core_search\base_block') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $baseblock->get_doc_icon($document); + + $this->assertEquals('e/anchor', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } } diff --git a/search/tests/base_test.php b/search/tests/base_test.php index 08f3442664053..0d7cb18c1b5cb 100644 --- a/search/tests/base_test.php +++ b/search/tests/base_test.php @@ -139,4 +139,22 @@ public function test_get_contexts_to_reindex() { $this->assertEquals([\context_system::instance()], iterator_to_array($area->get_contexts_to_reindex(), false)); } + + /** + * Test default document icon. + */ + public function test_get_default_doc_icon() { + $basearea = $this->getMockBuilder('\core_search\base') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMock(); + + $result = $basearea->get_doc_icon($document); + + $this->assertEquals('i/empty', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } } diff --git a/search/tests/document_icon_test.php b/search/tests/document_icon_test.php new file mode 100644 index 0000000000000..917a2394267ad --- /dev/null +++ b/search/tests/document_icon_test.php @@ -0,0 +1,53 @@ +. + +/** + * Document icon unit tests. + * + * @package core_search + * @copyright 2018 Dmitrii Metelkin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Document icon unit tests. + * + * @package core_search + * @copyright 2018 Dmitrii Metelkin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class search_document_icon_testcase extends advanced_testcase { + /** + * Test that default component gets returned correctly. + */ + public function test_default_component() { + $docicon = new \core_search\document_icon('test_name'); + $this->assertEquals('test_name', $docicon->get_name()); + $this->assertEquals('moodle', $docicon->get_component()); + } + + /** + * Test that name and component get returned correctly. + */ + public function test_can_get_name_and_component() { + $docicon = new \core_search\document_icon('test_name', 'test_component'); + $this->assertEquals('test_name', $docicon->get_name()); + $this->assertEquals('test_component', $docicon->get_component()); + } + +} diff --git a/search/tests/document_test.php b/search/tests/document_test.php index d7196f3fbf858..d74a2aab592ad 100644 --- a/search/tests/document_test.php +++ b/search/tests/document_test.php @@ -103,6 +103,22 @@ public function test_search_user_accesses() { $this->assertEquals('Course & Title', $export['coursefullname']); } + /** + * Test we can set and get document icon. + */ + public function test_get_and_set_doc_icon() { + $document = $this->getMockBuilder('\core_search\document') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->assertNull($document->get_doc_icon()); + + $docicon = new \core_search\document_icon('test_name', 'test_component'); + $document->set_doc_icon($docicon); + + $this->assertEquals($docicon, $document->get_doc_icon()); + } + public function tearDown() { // For unit tests before PHP 7, teardown is called even on skip. So only do our teardown if we did setup. if ($this->generator) { diff --git a/search/tests/engine_test.php b/search/tests/engine_test.php index cfe8667e1361a..4fdba57f5a5a6 100644 --- a/search/tests/engine_test.php +++ b/search/tests/engine_test.php @@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/testable_core_search.php'); +require_once(__DIR__ . '/fixtures/mock_search_area.php'); /** * Search engine base unit tests. @@ -129,4 +130,24 @@ public function test_get_supported_orders() { $this->assertCount(1, $orders); $this->assertArrayHasKey('relevance', $orders); } + + /** + * Test that search engine sets an icon before render a document. + */ + public function test_engine_sets_doc_icon() { + $generator = self::getDataGenerator()->get_plugin_generator('core_search'); + $generator->setup(); + + $area = new core_mocksearch\search\mock_search_area(); + $engine = new \mock_search\engine(); + + $record = $generator->create_record(); + $docdata = $area->get_document($record)->export_for_engine(); + + $doc = $engine->to_document($area, $docdata); + + $this->assertNotNull($doc->get_doc_icon()); + + $generator->teardown(); + } } diff --git a/user/classes/search/user.php b/user/classes/search/user.php index 5724b69532f32..b0f4525928588 100644 --- a/user/classes/search/user.php +++ b/user/classes/search/user.php @@ -187,4 +187,15 @@ public function get_component_name() { return 'user'; } + /** + * Returns an icon instance for the document. + * + * @param \core_search\document $doc + * + * @return \core_search\document_icon + */ + public function get_doc_icon(\core_search\document $doc) : \core_search\document_icon { + return new \core_search\document_icon('i/user'); + } + } diff --git a/user/tests/search_test.php b/user/tests/search_test.php index 589665a44f763..3afa287803346 100644 --- a/user/tests/search_test.php +++ b/user/tests/search_test.php @@ -215,4 +215,18 @@ public function test_users_access() { $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($user2->id)); $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($user3->id)); } + + /** + * Test document icon. + */ + public function test_get_doc_icon() { + $searcharea = \core_search\manager::get_search_area($this->userareaid); + $user = self::getDataGenerator()->create_user(); + $doc = $searcharea->get_document($user); + + $result = $searcharea->get_doc_icon($doc); + + $this->assertEquals('i/user', $result->get_name()); + $this->assertEquals('moodle', $result->get_component()); + } }