File API + Custom course format: Sorry, the requested file could not be found

File API + Custom course format: Sorry, the requested file could not be found

by Rogier Wijnands -
Number of replies: 0
I've made a custom course format where I'm adding some extra settings. One of these settings is a new image upload that I will be using as a header image. In my custom format lib.php I use the following to set the upload field and save the data.

/**
* Definitions of the additional options that this course format uses for course
*
* Topics format uses the following options:
* - coursedisplay
* - hiddensections
*
* @param bool $foreditform
* @return array of options
*/
public function course_format_options($foreditform = false) {
static $courseformatoptions = false;
if ($courseformatoptions === false) {
$courseconfig = get_config('moodlecourse');
$courseformatoptions = array(
'hiddensections' => array(
'default' => $courseconfig->hiddensections,
'type' => PARAM_INT,
),
'coursedisplay' => array(
'default' => $courseconfig->coursedisplay,
'type' => PARAM_INT,
),
'coursetheme' => array(
'default' => $courseconfig->coursetheme,
'type' => PARAM_TEXT,
),
'headingimage' => array(
'default' => $courseconfig->headingimage,
'type' => PARAM_CLEANFILE,
),
);
}
if ($foreditform && !isset($courseformatoptions['coursedisplay']['label'])) {
$courseformatoptionsedit = array(
'hiddensections' => array(
'label' => new lang_string('hiddensections'),
'help' => 'hiddensections',
'help_component' => 'moodle',
'element_type' => 'select',
'element_attributes' => array(
array(
0 => new lang_string('hiddensectionscollapsed'),
1 => new lang_string('hiddensectionsinvisible')
)
),
),
'coursedisplay' => array(
'label' => new lang_string('coursedisplay'),
'element_type' => 'select',
'element_attributes' => array(
array(
COURSE_DISPLAY_SINGLEPAGE => new lang_string('coursedisplay_single'),
COURSE_DISPLAY_MULTIPAGE => new lang_string('coursedisplay_multi')
)
),
'help' => 'coursedisplay',
'help_component' => 'moodle',
),
'coursetheme' => array(
'label' => new lang_string('coursetheme', 'format_custom'),
'element_type' => 'select',
'element_attributes' => array(
array(
'red' => new lang_string('coursethemered', 'format_custom'),
'blue' => new lang_string('coursethemeblue','format_custom')
)
),
),
'headingimage' => array(
'label' => new lang_string('headingimage', 'format_custom'),
'element_type' => 'filemanager',
'element_attributes' => array(null,
array(
'subdirs' => 0,
'maxfiles' => 1,
'accepted_types' => array('.jpg', '.gif', '.png')
))
),
);
$courseformatoptions = array_merge_recursive($courseformatoptions, $courseformatoptionsedit);
}
return $courseformatoptions;
}

/**
* Adds format options elements to the course/section edit form.
*
* This function is called from {@link course_edit_form::definition_after_data()}.
*
* @param MoodleQuickForm $mform form the elements are added to.
* @param bool $forsection 'true' if this is a section edit form, 'false' if this is course edit form.
* @return array array of references to the added form elements.
*/
public function create_edit_form_elements(&$mform, $forsection = false) {
global $COURSE;
$elements = parent::create_edit_form_elements($mform, $forsection);

if (!$forsection && (empty($COURSE->id) || $COURSE->id == SITEID)) {
// Add "numsections" element to the create course form - it will force new course to be prepopulated
// with empty sections.
// The "Number of sections" option is no longer available when editing course, instead teachers should
// delete and add sections when needed.
$courseconfig = get_config('moodlecourse');
$max = (int)$courseconfig->maxsections;
$element = $mform->addElement('select', 'numsections', get_string('numberweeks'), range(0, $max ?: 52));
$mform->setType('numsections', PARAM_INT);
if (is_null($mform->getElementValue('numsections'))) {
$mform->setDefault('numsections', $courseconfig->numsections);
}
array_unshift($elements, $element);
}

return $elements;
}

/**
* Updates format options for a course
*
* In case if course format was changed to 'topics', we try to copy options
* 'coursedisplay' and 'hiddensections' from the previous format.
*
* @param stdClass|array $data return value from {@link moodleform::get_data()} or array with data
* @param stdClass $oldcourse if this function is called from {@link update_course()}
* this object contains information about the course before update
* @return bool whether there were any changes to the options values
*/
public function update_course_format_options($data, $oldcourse = null) {
global $COURSE;

$data = (array)$data;
$context = context_course::instance($COURSE->id);

// Save settings
if ($oldcourse !== null) {
$oldcourse = (array)$oldcourse;
$options = $this->course_format_options();
foreach ($options as $key => $unused) {
if (!array_key_exists($key, $data)) {
if (array_key_exists($key, $oldcourse)) {
$data[$key] = $oldcourse[$key];
}
}
}
}

// Save header image
$saveHeadingImage = file_save_draft_area_files($data['headingimage'], $context->id, 'format_custom',
'headingimage', 0, array('subdirs' => 0, 'maxfiles' => 1));

return $this->update_format_options($data);
}

Everything seems to work fine. I can even find the image and set the url as follows:

$context = context_course::instance($COURSE->id);
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'format_custom', 'headingimage', 0);
foreach($files as $file){
if ($file->is_valid_image())
{
$url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename(), false);
break;
}
}
echo html_writer::empty_tag('img', array(
'src' => $url
)
);

The URL returns successfully (in this case http://localhost/Moodle/moodle/pluginfile.php/35/format_custom/headingimage/0/01-airastana-b767300er-Wikipedia.jpg). The problem is that Moodle now says this file does not exist. I get the following error:

Stack trace:

  • line 482 of \lib\setuplib.php: moodle_exception thrown
  • line 1913 of \lib\filelib.php: call to print_error()
  • line 4834 of \lib\filelib.php: call to send_file_not_found()
  • line 40 of \pluginfile.php: call to file_pluginfile()


And from the debug I get:

Notice: Undefined property: stdClass::$headingimage in C:\Users\Rogier\Documents\Development\Moodle\moodle\course\format\custom\lib.php on line 244


The above error refers to the following line:

'default' => $courseconfig->headingimage,


I can not seem to find why my file is not available, even though the upload works and I can even get the image successfully with the above code. It just does not seem to exist. Any ideas? Thanks in advance!

Moodle version: 3.5.1+ (Build: 20180810)
Theme: Custom child theme based on Cognitio

Attachment 2019-02-01_1357.png
Average of ratings: -