<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>

CC BY-SA 4.0
2018-10-31T01:28:33.103Z
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.
Jeremy Daalder
CC BY-SA 4.0
2018-10-30T09:54:43.723Z
2018-10-30T10:27:59.377Z
2018-10-30T10:27:59.377Z
Robin Schambach
<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>

CC BY-SA 4.0
2018-10-30T09:06:25.350Z
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
Robin Schambach
CC BY-SA 4.0
2018-10-30T09:09:36.637Z
Yep already doing that, thanks via some js in the field template. But need to work out the rest still!
Jeremy Daalder
<plugin-development><craft3><modules>
Craft 3 Custom Field Type with a File Uploader
# 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
/**
 * @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 '';
}

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**: 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.  

---

