Can someone help with File API please?

Can someone help with File API please?

by Pete Smith -
Number of replies: 12

I'm doing a small hack to the certificates module so that users can upload their own image files for background, watermarks etc. I've got that bit working OK, but now I want to use the file API to retrieve the stored file when the pdf document is created. I'm very new to Moodle and I can't quite see the correct way to call up the image - and even if it works in this context, how will I get it to work in the context for the person whose certificate it is?

 

Any insights would be appreciated. Thanks.

Average of ratings: -
In reply to Pete Smith

Re: Can someone help with File API please?

by Pete Smith -

Right. The form element 'filemanager' just stores the file in the database as 991861473 which is its itemid. Clearly it has some way of picking this file back out by using a combination of itemid and context. I want to bypass the context part and pull the file simply by using the itemid from the mdl_certificate table.

I'm trying (as an experiment - hardcoded):

  $fs = get_file_storage();
  $fileid = 991861473;
  $file = $fs->get_file_by_id($fileid);
 
  $pathname = "$CFG->dirroot/mod/certificate/pix/borders/temp";
  $tempfile = $file->copy_content_to($pathname);

But clearly, get_file_by_id() is the wrong function as it uses id, not itemid.

In reply to Pete Smith

Re: Can someone help with File API please?

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Take a look here at how to set up a filemanager element then store the files back into a location of your choice once the form has been submitted:

http://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filemanager

Once you have saved the files from the filemanager into your desired location, you can then access them via:

$context = context_module::instance($cmid);
$component = 'mod_certificate';
$filearea = 'whatever you called the filearea when you saved the filemanager files';
$itemid = 'whatever itemid you used when saving the files'; // Note this is not the 'draftfileid' that was used temporarilly whilst showing the filemanager on the form, but the itemid you used when saving the form data
$filepath = '/'; // Unless the file was stored in a subdirectory
$filename = 'name of the file.ext'; // The name of the file you are trying to retrieve

$file = $fs->get_file($context->id, $component, $filearea, $itemid, $filepath, $filename);

OR (if you don't know the exact name of the file uploaded by the user)

$files = $fs->get_area_files($contextid, $component, $filearea, $itemid);
foreach ($files as $file) {
...

Average of ratings: Useful (1)
In reply to Davo Smith

Re: Can someone help with File API please?

by Pete Smith -

Thanks Davo. I'll go and try that and report back.

In reply to Pete Smith

Re: Can someone help with File API please?

by Pete Smith -

Well wadda ya know! I cloned the latest certificate module from github and all the required functionality seems to have been added. That's a bit of a timesaver.

Thanks for looking anyway.

Pete

In reply to Davo Smith

Re: Can someone help with File API please?

by Pete Smith -

Isn't it a bit odd that the unique item ID AND the filename are needed to access the file?

It seems crazy to 'guess' the filename when I already know an ID for it.

I'd be grateful if someone can explain how I can serve a file after I've saved it. Let's say I've put it into $CFG->dataroot.'/mod/pete/test/' and it's called pic.jpg

This is a separate (but similar) issue fom my original PDF problem.

In reply to Pete Smith

Re: Can someone help with File API please?

by Pete Smith -

I can't seem to find anything in the docs that shows me how to handle files. There's stuff about capturing them from forms, but the 'filemanager' only writes an itemid to the database and this is insufficient information for file retrieval. Strangely, the filemanager can use this single id to get the file details - as we see if the form is reloaded; but there's no legitimate way that I can access a file solely from its itemid.

I can save a file directly (as per the certificates plug-in) but I can only access it from the server - I can't make a serveable file from it unless I know the itemid and the filename.

Am I missing the point totally?

In reply to Pete Smith

Re: Can someone help with File API please?

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

You are missing the point so far.

The item id does not refer to the specific file. It is part of what you need to specify a file area.


A file area is a place files can be stored that belong to a particular thing. To specify a file you need 4 bits of information:

  • component
  • contextid
  • file area name
  • itemid

So, an example would be

('mod_forum', context_module::instance(55), 'forum_post', 929564)

That context id is the context id of this forum, and that item id is the id of your post.

Within that area, there may be any number of files (if you had added serveral images to your forum post).

In your code, if you want to get at a particular file, you need to use the file_storage class, which can return instances of the stored_file class from a given file area.

In reply to Tim Hunt

Re: Can someone help with File API please?

by Pete Smith -

Sorry Tim - I was getting frustrated when I wrote the previous two posts. I can now see that the certificates module saves the file "outside" the Moodle File API when it uses the method save_file($CFG->dataroot . $mypath)

So if I want to do things right (and I do), then I'll use the filemanager. Why does the filemanager return an itemid to the database? Clearly, an itemid is not sufficient?

Example: I have a text input and I replace it with a filemanager of the same name. It stores the file but the "text" value written to the database is just the itemid.

In reply to Pete Smith

Re: Can someone help with File API please?

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

The Filemanager doesn't store the itemid in the database - it returns it, so you can identify the draft files area it was using and copy the files out of it.

You may want to have a read through this discusison: http://moodle.org/mod/forum/discuss.php?d=212377 to see if it clarifies things a bit.

In reply to Davo Smith

Re: Can someone help with File API please?

by Pete Smith -

Thanks. I'll try to take it step-by-step.

I might be starting to understand this a little bit!

In reply to Pete Smith

Re: Can someone help with File API please?

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

The thing about when a user is interacting with a form is: the user may upload a lot of files into the file manager, and perhaps delete some other files, and then they may click Cancel. At that point, all the previous file manipulation they did is irrelevant.

To make this work, what happens is that when we show the form, all the files are copied into a temporary file area. If they save the form, we use those files to replace the existing files. If they Cancel the form, we just throw that file area away and forget about it.#

That temporary file-area is indentified as

('user', context_user::instance($USER->id), 'draft', {some item id})

The {some item id} is the item id that gets passed around in relation to forms.

In reply to Tim Hunt

Re: Can someone help with File API please?

by Pete Smith -

...when we show the form, all the files are copied into a temporary file area...

That's the part that I only realised yesterday. Thanks for your time and patience.

Pete