Answers.Body: <p>Craft's developer support helped me out with this.</p>
  <p>The key was to use <code>Asset::EVENT_AFTER_SAVE</code> and the Craft asset service's <a href="https://docs.craftcms.com/api/v4/craft-services-assets.html#public-methods" rel="nofollow noreferrer">moveAsset</a> function.</p>
  <pre class="lang-php prettyprint-override"><code>use yii\base\Event;
  use craft\elements\Asset;
  use craft\events\ModelEvent
  
  class SiteModule extends \yii\base\Module
  {
  
      public function init()
      {
          // ...
  
          $this-&gt;registerAssetEvents();
      }
  
      private function registerAssetEvents()
      {
          // Automatically assign asset volumes on upload, based on file kind.
          Event::on(
              Asset::class,
              Asset::EVENT_AFTER_SAVE,
              function (ModelEvent $event) {
                  $asset = $event-&gt;sender;
  
                  // mp4s which are not being put into the videos volume (id 2)
                  // will be moved to the videos volume
                  // NB this requires a GeneralConfig::$extraFileKinds definition for mp4s.
                  if ($asset-&gt;kind == 'mp4' &amp;&amp; $asset-&gt;getVolumeId() !== 2) {
                      $targetFolder = Craft::$app-&gt;assets-&gt;getRootFolderByVolumeId(2);
                      Craft::$app-&gt;assets-&gt;moveAsset($asset, $targetFolder);
                  }
              }
          );
      }
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-12-13T13:19:05.197Z
Answers.LastActivityDate: 2022-12-13T13:19:05.197Z
Answers.UserDisplayName: Josh Harrison
Body: <p>I'm trying to set the asset volume dynamically for new assets, using a module. I would like the volume to be based on the asset's file kind – in my case, automatically putting MP4s into a 'Videos' asset volume.</p>
  <p>I would like this to work when the asset is uploaded via an assets field, or directly via the Assets CP screen.</p>
  <p>The Craft docs for this stuff are a bit of a mystery to me as they lack examples and explanations... here's what I've tried so far in my site module. It works when uploading assets on the Assets CP screen, but it does nothing when uploading via an Assets field on an entry:</p>
  <pre class="lang-php prettyprint-override"><code>use yii\base\Event;
  use craft\elements\Asset;
  use craft\events\ModelEvent;
  
  // Automatically put MP4 uploads into the 'Videos' asset volume (volume ID 2, folder ID 2).
  // This function is called in the module's constructor.
  private function registerDynamicAssetVolumeSettings()
  {
      Event::on(
          Asset::class,
          Asset::EVENT_BEFORE_SAVE,
          function (ModelEvent $event) {
  
              // only act on new assets matching my `mp4` custom file kind
              if ($event-&gt;isNew &amp;&amp; $event-&gt;sender-&gt;kind == 'mp4') {
  
                  // only act on mp4s which are not already being put into the mp4 volume
                  if ($event-&gt;sender-&gt;getVolumeId() !== 2) {
                      $event-&gt;sender-&gt;setVolumeId(2);
                      $event-&gt;sender-&gt;newLocation = '{folder:2}' . $event-&gt;sender-&gt;getFilename();
                  }
              }
          }
      );
  }
  </code></pre>
  <p>Thanks in advance for any thoughts </p>
  
Tags: <assets><php><modules><craft4><volumes>
Title: Set asset volume dynamically via module depending on uploaded file kind
ThreadText: # Set asset volume dynamically via module depending on uploaded file kind
  
  (Asked by: username_0 on 2022-11-17)
  
  I'm trying to set the asset volume dynamically for new assets, using a module. I would like the volume to be based on the asset's file kind – in my case, automatically putting MP4s into a 'Videos' asset volume.
  
  I would like this to work when the asset is uploaded via an assets field, or directly via the Assets CP screen.
  
  The Craft docs for this stuff are a bit of a mystery to me as they lack examples and explanations... here's what I've tried so far in my site module. It works when uploading assets on the Assets CP screen, but it does nothing when uploading via an Assets field on an entry:
  
  ```php
  use yii\base\Event;
  use craft\elements\Asset;
  use craft\events\ModelEvent;
  
  // Automatically put MP4 uploads into the 'Videos' asset volume (volume ID 2, folder ID 2).
  // This function is called in the module's constructor.
  private function registerDynamicAssetVolumeSettings()
  {
      Event::on(
          Asset::class,
          Asset::EVENT_BEFORE_SAVE,
          function (ModelEvent $event) {
  
              // only act on new assets matching my `mp4` custom file kind
              if ($event->isNew && $event->sender->kind == 'mp4') {
  
                  // only act on mp4s which are not already being put into the mp4 volume
                  if ($event->sender->getVolumeId() !== 2) {
                      $event->sender->setVolumeId(2);
                      $event->sender->newLocation = '{folder:2}' . $event->sender->getFilename();
                  }
              }
          }
      );
  }
  
  ```
  
  Thanks in advance for any thoughts
  
  **Tags:** assets, php, modules, craft4, volumes
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2022-12-13. Score: 1 | Accepted answer
  
  Craft's developer support helped me out with this.
  
  The key was to use `Asset::EVENT_AFTER_SAVE` and the Craft asset service's [moveAsset](https://docs.craftcms.com/api/v4/craft-services-assets.html#public-methods) function.
  
  ```php
  use yii\base\Event;
  use craft\elements\Asset;
  use craft\events\ModelEvent
  
  class SiteModule extends \yii\base\Module
  {
  
      public function init()
      {
          // ...
  
          $this->registerAssetEvents();
      }
  
      private function registerAssetEvents()
      {
          // Automatically assign asset volumes on upload, based on file kind.
          Event::on(
              Asset::class,
              Asset::EVENT_AFTER_SAVE,
              function (ModelEvent $event) {
                  $asset = $event->sender;
  
                  // mp4s which are not being put into the videos volume (id 2)
                  // will be moved to the videos volume
                  // NB this requires a GeneralConfig::$extraFileKinds definition for mp4s.
                  if ($asset->kind == 'mp4' && $asset->getVolumeId() !== 2) {
                      $targetFolder = Craft::$app->assets->getRootFolderByVolumeId(2);
                      Craft::$app->assets->moveAsset($asset, $targetFolder);
                  }
              }
          );
      }
  }
  
  ```
  
  
  ---
  
  