PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/search/documents/resource_document.php

https://github.com/kpike/moodle
PHP | 363 lines | 213 code | 38 blank | 112 comment | 39 complexity | caf903324ff1fc8f5511e2f77f0d8fdc MD5 | raw file
  1. <?php
  2. /**
  3. * Global Search Engine for Moodle
  4. *
  5. * @package search
  6. * @category core
  7. * @subpackage document_wrappers
  8. * @author Michael Campanis (mchampan) [cynnical@gmail.com], Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
  9. * @contributor Tatsuva Shirai 20090530
  10. * @date 2008/03/31
  11. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  12. * @version Moodle 2.0
  13. *
  14. * document handling for all resources
  15. * This file contains the mapping between a resource and it's indexable counterpart,
  16. *
  17. * Functions for iterating and retrieving the necessary records are now also included
  18. * in this file, rather than mod/resource/lib.php
  19. */
  20. /**
  21. * requires and includes
  22. */
  23. require_once($CFG->dirroot.'/search/documents/document.php');
  24. require_once($CFG->dirroot.'/mod/resource/lib.php');
  25. /* *
  26. * a class for representing searchable information
  27. *
  28. */
  29. class ResourceSearchDocument extends SearchDocument {
  30. public function __construct(&$resource, $context_id) {
  31. // generic information; required
  32. $doc->docid = $resource['trueid'];
  33. $doc->documenttype = SEARCH_TYPE_RESOURCE;
  34. $doc->itemtype = $resource['type'];
  35. $doc->contextid = $context_id;
  36. $doc->title = strip_tags($resource['name']);
  37. $doc->date = $resource['timemodified'];
  38. $doc->author = '';
  39. $doc->contents = strip_tags($resource['summary']).' '.strip_tags($resource['alltext']);
  40. $doc->url = resource_make_link($resource['id']);
  41. // module specific information; optional
  42. $data = array();
  43. // construct the parent class
  44. parent::__construct($doc, $data, $resource['course'], 0, 0, 'mod/'.SEARCH_TYPE_RESOURCE);
  45. }
  46. }
  47. /**
  48. * constructs valid access links to information
  49. * @param resourceId the of the resource
  50. * @return a full featured link element as a string
  51. */
  52. function resource_make_link($resource_id) {
  53. global $CFG;
  54. return $CFG->wwwroot.'/mod/resource/view.php?id='.$resource_id;
  55. }
  56. /**
  57. * part of standard API
  58. *
  59. */
  60. function resource_iterator() {
  61. //trick to leave search indexer functionality intact, but allow
  62. //this document to only use the below function to return info
  63. //to be searched
  64. return array(true);
  65. }
  66. /**
  67. * part of standard API
  68. * this function does not need a content iterator, returns all the info
  69. * itself;
  70. * @param void $notneeded to comply API, remember to fake the iterator array though
  71. * @uses $CFG, $DB
  72. * @return an array of searchable documents
  73. */
  74. function resource_get_content_for_index(&$notneeded) {
  75. global $CFG, $DB;
  76. // starting with Moodle native resources
  77. $documents = array();
  78. $dbman = $DB->get_manager();
  79. if (!$dbman->table_exists('resource_old')) {
  80. return $documents;
  81. }
  82. // the resources have been moved into modules of their own. indexing need to be created for these.
  83. // for a temporary fix (until MDL-24856 is fixed) pointing this query to a table that is copy of the old resource table schema.
  84. $query = "
  85. SELECT
  86. id as trueid,
  87. r.*
  88. FROM
  89. {resource_old} as r
  90. WHERE
  91. alltext != '' AND
  92. alltext != ' ' AND
  93. alltext != '&nbsp;' AND
  94. type != 'file'
  95. ";
  96. if ($resources = $DB->get_records_sql($query)){
  97. foreach($resources as $aResource){
  98. $coursemodule = $DB->get_field('modules', 'id', array('name' => 'resource'));
  99. $cm = $DB->get_record('course_modules', array('course' => $aResource->course, 'module' => $coursemodule, 'instance' => $aResource->id));
  100. $context = get_context_instance(CONTEXT_MODULE, $cm->id);
  101. $aResource->id = $cm->id;
  102. $documents[] = new ResourceSearchDocument(get_object_vars($aResource), $context->id);
  103. mtrace("finished $aResource->name");
  104. }
  105. }
  106. // special physical files handling
  107. /**
  108. * this sequence searches for a compatible physical stream handler for getting a text
  109. * equivalence for the content.
  110. *
  111. */
  112. if (@$CFG->block_search_enable_file_indexing){
  113. $query = "
  114. SELECT
  115. r.id as trueid,
  116. cm.id as id,
  117. r.course as course,
  118. r.name as name,
  119. r.summary as summary,
  120. r.alltext as alltext,
  121. r.reference as reference,
  122. r.type as type,
  123. r.timemodified as timemodified
  124. FROM
  125. {resource_old} as r,
  126. {course_modules} as cm,
  127. {modules} as m
  128. WHERE
  129. r.type = 'file' AND
  130. cm.instance = r.id AND
  131. cm.course = r.course AND
  132. cm.module = m.id AND
  133. m.name = 'resource'
  134. ";
  135. if ($resources = $DB->get_records_sql($query)){
  136. // invokes external content extractor if exists.
  137. foreach($resources as $aResource){
  138. // fetches a physical indexable document and adds it to documents passed by ref
  139. $coursemodule = $DB->get_field('modules', 'id', array('name' => 'resource'));
  140. $cm = $DB->get_record('course_modules', array('id' => $aResource->id));
  141. $context = get_context_instance(CONTEXT_MODULE, $cm->id);
  142. resource_get_physical_file($aResource, $context->id, false, $documents);
  143. }
  144. }
  145. }
  146. return $documents;
  147. }
  148. /**
  149. * get text from a physical file
  150. * @uses $CFG
  151. * @param reference $resource a resource for which to fetch some representative text
  152. * @param int $context_id the context associated with the resource
  153. * @param bool $getsingle if true, returns a single search document, elsewhere return the array
  154. * given as documents increased by one
  155. * @param array $documents the array of documents, by ref, where to add the new document.
  156. * @return a search document when unique or false.
  157. */
  158. function resource_get_physical_file(&$resource, $context_id, $getsingle, &$documents = null){
  159. global $CFG;
  160. // cannot index empty references
  161. if (empty($resource->reference)){
  162. mtrace("Cannot index, empty reference.");
  163. return false;
  164. }
  165. // cannot index remote resources
  166. if (resource_is_url($resource->reference)){
  167. mtrace("Cannot index remote URLs.");
  168. return false;
  169. }
  170. $fileparts = pathinfo($resource->reference);
  171. // cannot index unknown or masked types
  172. if (empty($fileparts['extension'])) {
  173. mtrace("Cannot index without explicit extension.");
  174. return false;
  175. }
  176. // cannot index non existent file
  177. $file = "{$CFG->dataroot}/{$resource->course}/{$resource->reference}";
  178. if (!file_exists($file)){
  179. mtrace("Missing resource file $file : will not be indexed.");
  180. return false;
  181. }
  182. $ext = strtolower($fileparts['extension']);
  183. // cannot index unallowed or unhandled types
  184. if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) {
  185. mtrace($fileparts['extension'] . ' is not an allowed extension for indexing');
  186. return false;
  187. }
  188. if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){
  189. include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php');
  190. $function_name = 'get_text_for_indexing_'.$ext;
  191. $resource->alltext = $function_name($resource);
  192. if (!empty($resource->alltext)){
  193. if ($getsingle){
  194. $single = new ResourceSearchDocument(get_object_vars($resource), $context_id);
  195. mtrace("finished file $resource->name as {$resource->reference}");
  196. return $single;
  197. } else {
  198. $documents[] = new ResourceSearchDocument(get_object_vars($resource), $context_id);
  199. }
  200. mtrace("finished file $resource->name as {$resource->reference}");
  201. }
  202. } else {
  203. mtrace("fulltext handler not found for $ext type");
  204. }
  205. return false;
  206. }
  207. /**
  208. * part of standard API.
  209. * returns a single resource search document based on a resource_entry id
  210. * @uses $CFG, $DB
  211. * @param id the id of the accessible document
  212. * @return a searchable object or null if failure
  213. */
  214. function resource_single_document($id, $itemtype) {
  215. global $CFG, $DB;
  216. // rewriting with legacy moodle databse API
  217. $query = "
  218. SELECT
  219. r.id as trueid,
  220. cm.id as id,
  221. r.course as course,
  222. r.name as name,
  223. r.summary as summary,
  224. r.alltext as alltext,
  225. r.reference as reference,
  226. r.type as type,
  227. r.timemodified as timemodified
  228. FROM
  229. {resource} as r,
  230. {course_modules} as cm,
  231. {modules} as m
  232. WHERE
  233. cm.instance = r.id AND
  234. cm.course = r.course AND
  235. cm.module = m.id AND
  236. m.name = 'resource' AND
  237. ((r.type != 'file' AND
  238. r.alltext != '' AND
  239. r.alltext != ' ' AND
  240. r.alltext != '&nbsp;') OR
  241. r.type = 'file') AND
  242. r.id = '?'
  243. ";
  244. $resource = $DB->get_record_sql($query, array($id));
  245. if ($resource){
  246. $coursemodule = $DB->get_field('modules', 'id', array('name' => 'resource'));
  247. $cm = $DB->get_record('course_modules', array('id' => $resource->id));
  248. $context = get_context_instance(CONTEXT_MODULE, $cm->id);
  249. if ($resource->type == 'file' && @$CFG->block_search_enable_file_indexing){
  250. $document = resource_get_physical_file($resource, true, $context->id);
  251. if (!$document) mtrace("Warning : this document {$resource->name} will not be indexed");
  252. return $document;
  253. } else {
  254. return new ResourceSearchDocument(get_object_vars($resource), $context->id);
  255. }
  256. }
  257. mtrace('null resource');
  258. return null;
  259. }
  260. /**
  261. * dummy delete function that aggregates id with itemtype.
  262. * this was here for a reason, but I can't remember it at the moment.
  263. *
  264. */
  265. function resource_delete($info, $itemtype) {
  266. $object->id = $info;
  267. $object->itemtype = $itemtype;
  268. return $object;
  269. }
  270. /**
  271. * returns the var names needed to build a sql query for addition/deletions
  272. *
  273. */
  274. function resource_db_names() {
  275. //[primary id], [table name], [time created field name], [time modified field name], [additional where conditions for sql]
  276. return array(array('id', 'resource_old', 'timemodified', 'timemodified', 'any', " (alltext != '' AND alltext != ' ' AND alltext != '&nbsp;' AND TYPE != 'file') OR TYPE = 'file' "));
  277. }
  278. /**
  279. * this function handles the access policy to contents indexed as searchable documents. If this
  280. * function does not exist, the search engine assumes access is allowed.
  281. * @uses $CFG, $DB
  282. * @param path the access path to the module script code
  283. * @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
  284. * @param this_id the item id within the information class denoted by itemtype. In resources, this id
  285. * points to the resource record and not to the module that shows it.
  286. * @param user the user record denoting the user who searches
  287. * @param group_id the current group used by the user when searching
  288. * @return true if access is allowed, false elsewhere
  289. */
  290. function resource_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
  291. global $CFG, $DB;
  292. // include_once("{$CFG->dirroot}/{$path}/lib.php");
  293. $r = $DB->get_record('resource', array('id' => $this_id));
  294. $module_context = $DB->get_record('context', array('id' => $context_id));
  295. $cm = $DB->get_record('course_modules', array('id' => $module_context->instanceid));
  296. if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete
  297. $course = $DB->get_record('course', array('id' => $r->course));
  298. $course_context = get_context_instance(CONTEXT_COURSE, $r->course);
  299. $course = $DB->get_record('course', array('id' => $r->course));
  300. //check if course is visible
  301. if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $course_context)) {
  302. return false;
  303. }
  304. //check if user is registered in course or course is open to guests
  305. if (!is_enrolled($course_context) and !is_viewing($course_context)) { //TODO: guest course access is gone, this needs a different solution
  306. return false;
  307. }
  308. //check if found course module is visible
  309. if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $module_context)){
  310. return false;
  311. }
  312. return true;
  313. }
  314. /**
  315. * post processes the url for cleaner output.
  316. * @param string $title
  317. */
  318. function resource_link_post_processing($title){
  319. global $CFG;
  320. if ($CFG->block_search_utf8dir){
  321. return mb_convert_encoding($title, 'UTF-8', 'auto');
  322. }
  323. return mb_convert_encoding($title, 'auto', 'UTF-8');
  324. }
  325. ?>