Answers.Body: <p>Just as a little example how to store files in a custom field</p>
  
  <pre class="lang-PHP prettyprint-override"><code>/**
   * @inheritdoc
   */
  public function normalizeValue($value, ElementInterface $element = null)
  {
  
      $namespace = $element? $element-&gt;getFieldParamNamespace() . '.' : '';
      $file = UploadedFile::getInstanceByName($namespace . $this-&gt;handle);
      if($file !== null){
          // replace this
          $somePath = __DIR__ . DIRECTORY_SEPARATOR . $file-&gt;name;
          $file-&gt;saveAs($somePath);
      }
      return $file;
  }
  
  /**
   * @inheritdoc
   */
  public function getInputHtml($value, ElementInterface $element = null): string
  {
      Craft::$app-&gt;getView()-&gt;registerJs('Craft.cp.$primaryForm.attr(\'enctype\', \'multipart/form-data\');');
      return '&lt;input type="file" name="' . $this-&gt;handle . '"&gt;';
  }
  </code></pre>
  
  <h3>Edit:</h3>
  
  <p>If you want to store the file path in your Database you would check if <code>$value</code> is an instance of <code>File</code> and if so return the path. Otherwise just declare your field has <code>contentColumn = false</code></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-10-31T01:28:33.103Z
Answers.Text: Robin - thank you so very much!  This works a treat.  I had thought to use `serializeValue` to save the file when the field value is being saved to the DB - this feels the more logical spot (still!)  But this definitely works & is very much appreciated.
Answers.UserDisplayName: Jeremy Daalder
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-10-30T09:54:43.723Z
Answers.LastActivityDate: 2018-10-30T10:27:59.377Z
Answers.LastEditDate: 2018-10-30T10:27:59.377Z
Answers.UserDisplayName: Robin Schambach
Body: <p>I have a custom field type I am porting from Craft 2 to Craft 3.</p>
  
  <p>This field type used <code>prepValueFromPost</code> to grab a reference to a just uploaded file and then saves said file to an appropriate place for temporary storage (the file is sent on to a ticketing system which keeps its own copy so really it's only needed here for a few seconds).  The actual field value is jsut set to the full file path/name as a record.</p>
  
  <p>I'm really struggling to port this across to Craft 3 as this area has seemingly been re-factored a lot...</p>
  
  <p>I think I need to use <code>serializeValue</code> in place of <code>prepValueFromPost</code>, but I can't grab the actual filename from input in there and the value received is null (I <em>expected</em> it to be the filename..but it's not).  I used to use <code>getContentPostLocation();</code> for this.</p>
  
  <p>My specific questions are - is serializeValue() the right place to do this?  I want it to occur, once (per field - this is in a matrix), when the element (a Commerce Order) is saved.</p>
  
  <p>And - how do I get the name of the uploaded file (i.e. what has replaced <code>getContentPostLocation</code>).</p>
  
  <p>Here is the code that worked in Craft 2.</p>
  
  <pre><code>    public function prepValueFromPost($value, $element)
  {
  
      $finalFilePath = null;
  
      //Weird function that works out the dynamic name of this field
      $filename = $this-&gt;getContentPostLocation();
      $file = UploadedFile::getInstanceByName($filename);
  
      //Save the file where we want it, delete the temporary file
      $outputDir = craft()-&gt;path-&gt;getTempPath() . "BusinessLogicPlugin_upload_" . time();
      IOHelper::ensureFolderExists($outputDir);
      //Was needed on dev, can't really hurt...leave it here.
      chmod($outputDir, 0775);
  
      $finalFilePath = $outputDir ."/" . $file-&gt;name;
  
      if(!($file-&gt;saveAs($finalFilePath, false))){
          BusinessLogicPlugin::log("Unable to save actual file [$finalFilePath], file will not be attached");
          $finalFilePath = "";
      }
  
      //Save the pathname of the file, if we were able to save it, otherwise empty string.
      return $finalFilePath;
  }
  </code></pre>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-10-30T09:06:25.350Z
Comments.Text: Keep in mind Craft 3 default form does not have `enctype="multipart/form-data"` so you won't be able to upload files with this form. You can include custom JavaScript to add this tag to the `Craft.cp.$primaryForm` otherwise it's not possible to include an upload like that
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-10-30T09:09:36.637Z
Comments.Text: Yep already doing that, thanks via some js in the field template. But need to work out the rest still!
Comments.UserDisplayName: Jeremy Daalder
Tags: <plugin-development><craft3><modules>
Title: Craft 3 Custom Field Type with a File Uploader
ThreadText: # Craft 3 Custom Field Type with a File Uploader
  
  (Asked by: username_0 on 2018-10-30)
  
  I have a custom field type I am porting from Craft 2 to Craft 3.
  
  This field type used `prepValueFromPost` to grab a reference to a just uploaded file and then saves said file to an appropriate place for temporary storage (the file is sent on to a ticketing system which keeps its own copy so really it's only needed here for a few seconds). The actual field value is jsut set to the full file path/name as a record.
  
  I'm really struggling to port this across to Craft 3 as this area has seemingly been re-factored a lot...
  
  I think I need to use `serializeValue` in place of `prepValueFromPost`, but I can't grab the actual filename from input in there and the value received is null (I *expected* it to be the filename..but it's not). I used to use `getContentPostLocation();` for this.
  
  My specific questions are - is serializeValue() the right place to do this? I want it to occur, once (per field - this is in a matrix), when the element (a Commerce Order) is saved.
  
  And - how do I get the name of the uploaded file (i.e. what has replaced `getContentPostLocation`).
  
  Here is the code that worked in Craft 2.
  
  ```
      public function prepValueFromPost($value, $element)
  {
  
      $finalFilePath = null;
  
      //Weird function that works out the dynamic name of this field
      $filename = $this->getContentPostLocation();
      $file = UploadedFile::getInstanceByName($filename);
  
      //Save the file where we want it, delete the temporary file
      $outputDir = craft()->path->getTempPath() . "BusinessLogicPlugin_upload_" . time();
      IOHelper::ensureFolderExists($outputDir);
      //Was needed on dev, can't really hurt...leave it here.
      chmod($outputDir, 0775);
  
      $finalFilePath = $outputDir ."/" . $file->name;
  
      if(!($file->saveAs($finalFilePath, false))){
          BusinessLogicPlugin::log("Unable to save actual file [$finalFilePath], file will not be attached");
          $finalFilePath = "";
      }
  
      //Save the pathname of the file, if we were able to save it, otherwise empty string.
      return $finalFilePath;
  }
  
  ```
  
  **Tags:** plugin-development, craft3, modules
  
  > **Comments:**
  > **username_1**: Keep in mind Craft 3 default form does not have `enctype="multipart/form-data"` so you won't be able to upload files with this form. You can include custom JavaScript to add this tag to the `Craft.cp.$primaryForm` otherwise it's not possible to include an upload like that  
  > **username_0**: Yep already doing that, thanks via some js in the field template. But need to work out the rest still!  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2018-10-30. Score: 4 | Accepted answer
  
  Just as a little example how to store files in a custom field
  
  ```PHP
  /**
   * @inheritdoc
   */
  public function normalizeValue($value, ElementInterface $element = null)
  {
  
      $namespace = $element? $element->getFieldParamNamespace() . '.' : '';
      $file = UploadedFile::getInstanceByName($namespace . $this->handle);
      if($file !== null){
          // replace this
          $somePath = __DIR__ . DIRECTORY_SEPARATOR . $file->name;
          $file->saveAs($somePath);
      }
      return $file;
  }
  
  /**
   * @inheritdoc
   */
  public function getInputHtml($value, ElementInterface $element = null): string
  {
      Craft::$app->getView()->registerJs('Craft.cp.$primaryForm.attr(\'enctype\', \'multipart/form-data\');');
      return '<input type="file" name="' . $this->handle . '">';
  }
  
  ```
  
  ### Edit:
  
  If you want to store the file path in your Database you would check if `$value` is an instance of `File` and if so return the path. Otherwise just declare your field has `contentColumn = false`
  
  > **Comments:**
  > **username_0**: username_1 - thank you so very much!  This works a treat.  I had thought to use `serializeValue` to save the file when the field value is being saved to the DB - this feels the more logical spot (still!)  But this definitely works & is very much appreciated.  
  
  ---
  
  