Answers.Body: <p>I think you need to resave the element after using <code>setFieldValue</code>. Maybe try hooking into <code>EVENT_AFTER_SAVE</code> instead?</p>
  <pre class="lang-php prettyprint-override"><code>Event::on(
      Asset::class,
      Asset::EVENT_AFTER_SAVE,
      function (AssetEvent $event) {
          $asset = $event-&gt;asset;
          //Avoid endless loop if the asset already has duration set
          if ($asset-&gt;extension == 'mp3' &amp;&amp; !$asset-&gt;duration) {
              $mp3 = new Mp3($asset-&gt;path);
              $duration = $mp3-&gt;getDuration();
              $asset-&gt;setFieldValue('duration', $duration);
              Craft::$app-&gt;getElements()-&gt;saveElement($asset);
          }
          
      }
  );
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-01-25T20:52:43.790Z
Answers.Text: Unfortunately that doesn't work. The asset is in S3, so I don't want to download it again. It has to happen before uploading it to S3. I am also getting the following errors: `Argument #1 ($event) must be of type craft\events\AssetEvent, craft\events\ModelEvent given` and `Invalid field handle: duration` (the duration field does exist though!) I did workaround those errors, and can see the duration is in the dirty fields array and the saveElement function is being called, but it's just not being saved!
Answers.UserDisplayName: thomasjonas
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-03-27T20:50:18.163Z
Answers.Text: @thomasjonas - Looking at the [EVENT_AFTER_SAVE docs](https://docs.craftcms.com/api/v4/craft-base-element.html#event-after-save), it's returning a `ModelEvent` instead of an `AssetEvent`. 
  
  So changing...
  
  `function (AssetEvent $event) {` 
  
  ...to ... 
  
  `function (ModelEvent $event) {`
  
  ... should fix this error.
Answers.UserDisplayName: Dan Letsche
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-01-25T18:54:23.300Z
Answers.LastActivityDate: 2024-01-25T18:54:23.300Z
Answers.UserDisplayName: Dalton Rooney
Body: <p>I'm trying to set the value of a custom field for an asset while uploading the asset. But somehow the value is not being saved. I can see the data in the <code>EVENT_BEFORE_SAVE</code> and <code>EVENT_AFTER_SAVE</code> hook, it is also in the dirty fields array, but it's just not saved in the database. What am I doing wrong?</p>
  <pre><code>Event::on(
      Asset::class,
      Asset::EVENT_BEFORE_HANDLE_FILE,
      function (AssetEvent $event) {
          if (Craft::$app-&gt;getRequest()-&gt;getIsCpRequest()) {
              $asset = $event-&gt;asset;
              if ($asset-&gt;extension === 'mp3' &amp;&amp; $asset-&gt;tempFilePath) {
                  $mp3 = new Mp3($asset-&gt;tempFilePath);
                  $duration = $mp3-&gt;getDuration();
                  $asset-&gt;setFieldValue('duration', $duration);
              }
          }
      }
  );
  </code></pre>
  
Tags: <assets><hook>
Title: Saving metadata for asset when uploading file
ThreadText: # Saving metadata for asset when uploading file
  
  (Asked by: username_0 on 2024-01-25)
  
  I'm trying to set the value of a custom field for an asset while uploading the asset. But somehow the value is not being saved. I can see the data in the `EVENT_BEFORE_SAVE` and `EVENT_AFTER_SAVE` hook, it is also in the dirty fields array, but it's just not saved in the database. What am I doing wrong?
  
  ```
  Event::on(
      Asset::class,
      Asset::EVENT_BEFORE_HANDLE_FILE,
      function (AssetEvent $event) {
          if (Craft::$app->getRequest()->getIsCpRequest()) {
              $asset = $event->asset;
              if ($asset->extension === 'mp3' && $asset->tempFilePath) {
                  $mp3 = new Mp3($asset->tempFilePath);
                  $duration = $mp3->getDuration();
                  $asset->setFieldValue('duration', $duration);
              }
          }
      }
  );
  
  ```
  
  **Tags:** assets, hook
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2024-01-25. Score: 1
  
  I think you need to resave the element after using `setFieldValue`. Maybe try hooking into `EVENT_AFTER_SAVE` instead?
  
  ```php
  Event::on(
      Asset::class,
      Asset::EVENT_AFTER_SAVE,
      function (AssetEvent $event) {
          $asset = $event->asset;
          //Avoid endless loop if the asset already has duration set
          if ($asset->extension == 'mp3' && !$asset->duration) {
              $mp3 = new Mp3($asset->path);
              $duration = $mp3->getDuration();
              $asset->setFieldValue('duration', $duration);
              Craft::$app->getElements()->saveElement($asset);
          }
          
      }
  );
  
  ```
  
  > **Comments:**
  > **username_0**: Unfortunately that doesn't work. The asset is in S3, so I don't want to download it again. It has to happen before uploading it to S3. I am also getting the following errors: `Argument #1 ($event) must be of type craft\events\AssetEvent, craft\events\ModelEvent given` and `Invalid field handle: duration` (the duration field does exist though!) I did workaround those errors, and can see the duration is in the dirty fields array and the saveElement function is being called, but it's just not being saved!  
  > **username_2**: @username_0 - Looking at the [EVENT_AFTER_SAVE docs](https://docs.craftcms.com/api/v4/craft-base-element.html#event-after-save), it's returning a `ModelEvent` instead of an `AssetEvent`.   So changing...  `function (AssetEvent $event) {`   ...to ...   `function (ModelEvent $event) {`  ... should fix this error.  
  
  ---
  
  