First, when you attach event listeners using craft.on
, the naming convention for the event name is assets.beforeSaveEntry
, not assets.onBeforeSaveEntry
(i.e., skip the on
part). Both names appear to work, but the former is the one used in the docs and I'd recommend using that.
Second, the reason why your upload "gets stuck" is your call to craft()->assets->storeFile
inside the event listener. Basically, that call results in a loop, because craft->assets->storeFile()
will fire another beforeSaveAsset
event – making your script execute continually before timing out.
As for actually changing the filename on upload; unfortunately, if there's a reliable way to change the asset filename before the asset is saved, I haven't been able to find it.
However, if you can work with the assets.saveAsset
event (which is fired after the asset is uploaded and saved on the server), I found a way:
First, set up an event listener for assets.saveAsset
. Inside the event listener, you need to check the $event
object's isNewAsset
property; making sure the filename is only changed the first time the asset is saved and preventing the loop mentioned above.
Concerning the actual filename, there's a couple of issues to consider. For one, the filename needs to be unique (to that particular folder, as least). If you attempt to store an asset with an existing filename, Craft will use the original filename for your upload (I'd expect Craft to either ask if you wanted to replace the existing file, or suffix the filename with a number, but that doesn't appear to be the case). Secondly, the filename needs to include the file's extension (i.e. jpg
or pdf
). And finally; because this code runs after the asset has been saved and the file is already stored on the server, it isn't enough to set the filename attribute to the AssetFileModel object (i.e. $asset
), you'll also need to rename the actual file.
Keeping these issues in mind, here's a working example:
craft()->on('assets.saveAsset', function (Event $event) {
if ($event->params['isNewAsset']) {
$asset = $event->params['asset'];
// Set the filename to a variable, appending the file extension
$filename = 'filename-'.md5(time()).'.'.$asset->getExtension();
// Rename the file on the server
craft()->assets->renameFile($asset, $filename);
// Set filename attribute and re-save asset
$asset->setAttribute('filename', $filename);
craft()->assets->storeFile($asset);
}
});
Note that in the above example, I'm hashing the current timestamp and adding it to the filename as an easy fix to ensure that it's unique. I don't know how you want your filenames to look or if duplicate filenames would even be an issue in your case, but you could of course implement a solution that tests for duplicate filenames and/or generates unique filenames in a different manner.
To be honest, although the above should work I do feel this solution is a bit convoluted and I wouldn't be surprised if there's a better way – if there is, hopefully you'll have another answer.