3

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;
}
  • 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 Oct 30 '18 at 9:06
  • Yep already doing that, thanks via some js in the field template. But need to work out the rest still! – Jeremy Daalder Oct 30 '18 at 9:09
4

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

  • 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 Oct 31 '18 at 1:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.