Skip to content

Commit

Permalink
MDL-51888 mod_resource: cache file details for performance
Browse files Browse the repository at this point in the history
If file details (size, type, date) are configured to be displayed we cache them
in course cache raw and build the display string in user language/timezone when
displaying. Also changed behat test not to fail in 2016
  • Loading branch information
marinaglancy authored and andrewnicols committed Nov 2, 2015
1 parent 821ab27 commit 9dfe870
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 41 deletions.
4 changes: 2 additions & 2 deletions mod/resource/lang/en/resource.php
Expand Up @@ -63,7 +63,7 @@
$string['legacyfiles'] = 'Migration of old course file';
$string['legacyfilesactive'] = 'Active';
$string['legacyfilesdone'] = 'Finished';
$string['modifieddate'] = 'Modified on {$a}';
$string['modifieddate'] = 'Modified {$a}';
$string['modulename'] = 'File';
$string['modulename_help'] = 'The file module enables a teacher to provide a file as a course resource. Where possible, the file will be displayed within the course interface; otherwise students will be prompted to download it. The file may include supporting files, for example an HTML page may have embedded images or Flash objects.
Expand Down Expand Up @@ -115,4 +115,4 @@
If there are multiple files in this resource, the start file type is displayed.
If the file type is not known to the system, it will not display.';
$string['uploadeddate'] = 'Uploaded on {$a}';
$string['uploadeddate'] = 'Uploaded {$a}';
12 changes: 10 additions & 2 deletions mod/resource/lib.php
Expand Up @@ -237,8 +237,16 @@ function resource_get_coursemodule_info($coursemodule) {

}

// If any optional extra details are turned on, store in custom data
$info->customdata = $resource->displayoptions;
// If any optional extra details are turned on, store in custom data,
// add some file details as well to be used later by resource_get_optional_details() without retriving.
// Do not store filedetails if this is a reference - they will still need to be retrieved every time.
if (($filedetails = resource_get_file_details($resource, $coursemodule)) && empty($filedetails['isref'])) {
$displayoptions = @unserialize($resource->displayoptions);
$displayoptions['filedetails'] = $filedetails;
$info->customdata = serialize($displayoptions);
} else {
$info->customdata = $resource->displayoptions;
}

return $info;
}
Expand Down
121 changes: 86 additions & 35 deletions mod/resource/locallib.php
Expand Up @@ -270,13 +270,75 @@ function resource_print_heading($resource, $cm, $course, $notused = false) {
echo $OUTPUT->heading(format_string($resource->name), 2);
}


/**
* Gets details of the file to cache in course cache to be displayed using {@link resource_get_optional_details()}
*
* @param object $resource Resource table row (only property 'displayoptions' is used here)
* @param object $cm Course-module table row
* @return string Size and type or empty string if show options are not enabled
*/
function resource_get_file_details($resource, $cm) {
$options = empty($resource->displayoptions) ? array() : @unserialize($resource->displayoptions);
$filedetails = array();
if (!empty($options['showsize']) || !empty($options['showtype']) || !empty($options['showdate'])) {
$context = context_module::instance($cm->id);
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', 0, 'sortorder DESC, id ASC', false);
// For a typical file resource, the sortorder is 1 for the main file
// and 0 for all other files. This sort approach is used just in case
// there are situations where the file has a different sort order.
$mainfile = $files ? reset($files) : null;
if (!empty($options['showsize'])) {
$filedetails['size'] = 0;
foreach ($files as $file) {
// This will also synchronize the file size for external files if needed.
$filedetails['size'] += $file->get_filesize();
if ($file->get_repository_id()) {
// If file is a reference the 'size' attribute can not be cached.
$filedetails['isref'] = true;
}
}
}
if (!empty($options['showtype'])) {
if ($mainfile) {
$filedetails['type'] = get_mimetype_description($mainfile);
// Only show type if it is not unknown.
if ($filedetails['type'] === get_mimetype_description('document/unknown')) {
$filedetails['type'] = '';
}
} else {
$filedetails['type'] = '';
}
}
if (!empty($options['showdate'])) {
if ($mainfile) {
// Modified date may be up to several minutes later than uploaded date just because
// teacher did not submit the form promptly. Give teacher up to 5 minutes to do it.
if ($mainfile->get_timemodified() > $mainfile->get_timecreated() + 5 * MINSECS) {
$filedetails['modifieddate'] = $mainfile->get_timemodified();
} else {
$filedetails['uploadeddate'] = $mainfile->get_timecreated();
}
if ($mainfile->get_repository_id()) {
// If main file is a reference the 'date' attribute can not be cached.
$filedetails['isref'] = true;
}
} else {
$filedetails['uploadeddate'] = '';
}
}
}
return $filedetails;
}

/**
* Gets optional details for a resource, depending on resource settings.
*
* Result may include the file size and type if those settings are chosen,
* or blank if none.
*
* @param object $resource Resource table row
* @param object $resource Resource table row (only property 'displayoptions' is used here)
* @param object $cm Course-module table row
* @return string Size and type or empty string if show options are not enabled
*/
Expand All @@ -285,50 +347,39 @@ function resource_get_optional_details($resource, $cm) {

$details = '';

$options = empty($resource->displayoptions) ? array() : unserialize($resource->displayoptions);
$options = empty($resource->displayoptions) ? array() : @unserialize($resource->displayoptions);
if (!empty($options['showsize']) || !empty($options['showtype']) || !empty($options['showdate'])) {
$context = context_module::instance($cm->id);
if (!array_key_exists('filedetails', $options)) {
$filedetails = resource_get_file_details($resource, $cm);
} else {
$filedetails = $options['filedetails'];
}
$size = '';
$type = '';
$date = '';
$langstring = '';
$infodisplayed = 0;
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', 0, 'sortorder DESC, id ASC', false);
if (!empty($options['showsize']) && count($files)) {
$sizebytes = 0;
foreach ($files as $file) {
// this will also synchronize the file size for external files if needed
$sizebytes += $file->get_filesize();
if (!empty($options['showsize'])) {
if (!empty($filedetails['size'])) {
$size = display_size($filedetails['size']);
$langstring .= 'size';
$infodisplayed += 1;
}
if ($sizebytes) {
$size = display_size($sizebytes);
}
$langstring .= 'size';
$infodisplayed += 1;
}
if (!empty($options['showtype']) && count($files)) {
// For a typical file resource, the sortorder is 1 for the main file
// and 0 for all other files. This sort approach is used just in case
// there are situations where the file has a different sort order
$mainfile = reset($files);
$type = get_mimetype_description($mainfile);
// Only show type if it is not unknown
if ($type === get_mimetype_description('document/unknown')) {
$type = '';
if (!empty($options['showtype'])) {
if (!empty($filedetails['type'])) {
$type = $filedetails['type'];
$langstring .= 'type';
$infodisplayed += 1;
}
$langstring .= 'type';
$infodisplayed += 1;
}
if (!empty($options['showdate'])) {
$mainfile = reset($files);
$uploaddate = $mainfile->get_timecreated();
$modifieddate = $mainfile->get_timemodified();

if ($modifieddate > $uploaddate) {
$date = get_string('modifieddate', 'mod_resource', userdate($modifieddate));
} else {
$date = get_string('uploadeddate', 'mod_resource', userdate($uploaddate));
if (!empty($options['showdate']) && (!empty($filedetails['modifieddate']) || !empty($filedetails['uploadeddate']))) {
if (!empty($filedetails['modifieddate'])) {
$date = get_string('modifieddate', 'mod_resource', userdate($filedetails['modifieddate'],
get_string('strftimedatetimeshort', 'langconfig')));
} else if (!empty($filedetails['uploadeddate'])) {
$date = get_string('uploadeddate', 'mod_resource', userdate($filedetails['uploadeddate'],
get_string('strftimedatetimeshort', 'langconfig')));
}
$langstring .= 'date';
$infodisplayed += 1;
Expand Down
4 changes: 2 additions & 2 deletions mod/resource/tests/behat/display_resource.feature
Expand Up @@ -48,11 +48,11 @@ Feature: Teacher can specify different display options for the resource
And I press "Save and display"
Then I <seesize> see "6 bytes" in the ".resourcedetails" "css_element"
And I <seetype> see "Text file" in the ".resourcedetails" "css_element"
And I <seedate> see "2015" in the ".resourcedetails" "css_element"
And I <seedate> see "Uploaded" in the ".resourcedetails" "css_element"
And I follow "Course 1"
And I <seesize> see "6 bytes" in the ".activity.resource .resourcelinkdetails" "css_element"
And I <seetype> see "Text file" in the ".activity.resource .resourcelinkdetails" "css_element"
And I <seedate> see "2015" in the ".activity.resource .resourcelinkdetails" "css_element"
And I <seedate> see "Uploaded" in the ".activity.resource .resourcelinkdetails" "css_element"
And I log out

Examples:
Expand Down

0 comments on commit 9dfe870

Please sign in to comment.