1

I'm trying to rename files uploaded by users on the frontend. Changing the title is working, but I can't rename the file.

Would appreciate some help!

Event::on(
  Asset::class,Asset::EVENT_BEFORE_HANDLE_FILE,function (AssetEvent $event) {
    if (Craft::$app->request->isSiteRequest) {
      $asset = $event->asset;
      $now = new DateTime();
      $timestamp = $now->getTimestamp();
  $newAssetTitle = Craft::$app->getRequest()->getBodyParam('imageTitle');
  $newAssetFilename = StringHelper::toKebabCase($newAssetTitle) . '-' . $timestamp . '.' . $asset->getExtension();

  $asset->title = $newAssetTitle; // this works
  $asset->filename = $newAssetFilename; // this doesn't work
}

} );

supazu
  • 576
  • 4
  • 12

3 Answers3

2

I just found a very nice solution for changing the filename usind the Assets::EVENT_SET_FILENAME event:

Event::on(Assets::class, Assets::EVENT_SET_FILENAME, function (SetAssetFilenameEvent $event) {
    $event->filename = YourHelper::sanitizeFilename($event->originalFilename);
});

where YourHelper::sanitizeFilename(...) is a placeholder function for your own modifier.

And since I assume that the reason people looking for this issue are sometimes dealing with special characters like e.g. german Umlaute, here is another learning:

  • MacOS sometimes seems to use a so called "Trema" character to map Umlaute into filenames instead of using UTF-8 Umlaute.
  • The "Trema" character is a horizontal colon placed above the previous character.
  • In order to correctly convert those Umlaute into ASCII, it's easy to replace the "Trema" character with an "e" to achieve the same result as converting a real UTF-8 Umlaut into its 2 character equivalent.

$filename = str_replace(['Ä', 'Ö', 'Ü', 'ä', 'ö', 'ü', 'ß', '̈'], ['AE', 'OE', 'UE', 'ae', 'oe', 'ue', 'ss', 'e'], $filename);

Please note: the "Trema" character is the last one in the search array, which is optically placed above the first quotation mark, so it looks like a broken quotation mark or a dirty screen :-)

Matthias Redl-Mann
  • 1,921
  • 11
  • 21
1

If you're using Craft 4.0.0 or later, you should be able to use $asset->setFilename($newAssetFilename) (docs).

Martin Spain
  • 1,519
  • 7
  • 9
  • Thanks for the reply. Unfortunately, that doesn't seem to do it... – supazu Jan 12 '23 at 10:56
  • Hmm, that's strange. There's a few issues on SE which suggest using moveAsset to achieve this, which might be worth a try. Something like: Craft::$app->assets->moveAsset($asset, $asset->getFolder(), $newAssetFilename); The docs for moveAsset do suggest it's intended for renaming. – Martin Spain Jan 12 '23 at 12:26
  • I did try that actually, but get Asset is missing its folder ID. I assume that's because it's on EVENT_BEFORE_HANDLE_FILE. I got it working with EVENT_AFTER_SAVE but then renaming the title broke. – supazu Jan 12 '23 at 12:32
1

Got it working with this:

Event::on(Asset::class,Element::EVENT_AFTER_SAVE,
  static function (ModelEvent $event) {
    if (Craft::$app->request->isSiteRequest) {
      $asset = $event->sender;
      $folderId = $asset->getFolder();
      $now = new DateTime();
      $timestamp = $now->getTimestamp();
      $newAssetTitle = Craft::$app->getRequest()->getBodyParam('imageTitle');
      $asset->title = $newAssetTitle;
      $newAssetFilename = StringHelper::toKebabCase($asset->title) . '-' . $timestamp . '.' . $asset->getExtension();
      if (!empty($asset)) {
        Craft::$app->assets->moveAsset($asset, $folderId, $newAssetFilename);
      }
    }
  }
);
supazu
  • 576
  • 4
  • 12