craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.28k stars 635 forks source link

Uploads automatically saved as asset. #7591

Closed rauwebieten closed 3 years ago

rauwebieten commented 3 years ago

Description

I have a upload form on my frontend website, handled by a custom controller action (custom module). In this controller action a save a new Entry of a specific section. This section has a asset field defined.

It seems the uploaded file is automatically saved as an asset, and linked to the created entry. (However I coded nothing in my controller yet to handle the upload).

How is this achieved?

I cannot find anything in the docs. I can image this can lead to unexcpected situations.

Additional info

brandonkelly commented 3 years ago

It’s documented here: https://craftcms.com/docs/3.x/assets-fields.html#creating-new-assets

We are planning on adding field-level permissions (#947) in Craft 4, which you’ll be able to use to choose which user groups are allowed to view/edit each fields’ content.

brandonkelly commented 3 years ago

If you want to prevent this from happening, check your controller action and make sure you avoid calling setFieldValuesFromRequest() and setFieldParamNamespace() on the element before saving it. Those methods are what give Assets fields the green light to pull in uploaded files. You can call setFieldValues() instead, to set field values.

natebeaty commented 2 years ago

I am experiencing this and was equally baffled as the OP, though I kind of want the behavior, it's still confusing that it was working at all. I was trying to write my own handler for the file upload (which is hard to find info on fwiw), and even though my UploadedFile handling attempt was throwing an error, the asset was successfully uploading & associating with the entry, much to my confusion.

I'm updating several different entry types from a single form in the request, so I'm using setFieldValues() ... an abbreviated example of part of my form + controller method:

<form accept-charset="UTF-8" enctype="multipart/form-data">
  {{ csrfInput() }}
  {{ actionInput('clixel/onboarding/save-form') }}
  {{ hiddenInput('organizationId', organization.id) }}
  {{ input('text', 'organizationName', organization.title ?? '') }}
  {{ input('text', 'organizationUrl', organization.organizationUrl  ?? '') }}
  {{ input('file', 'organizationImage', null, {
    accept: 'image/png,image/jpeg',
  }) }}
</form>
public function actionSaveForm()
{
    $this->requirePostRequest();
    $this->requireSiteRequest();
    $request = Craft::$app->getRequest();

    $organization = Entry::find()->section('organizations')->id($request->getBodyParam('organizationId'))->one();
    $organization->title = $request->getBodyParam('organizationName');
    $organization->setFieldValues([
        'organizationUrl' => $request->getBodyParam('organizationUrl')
    ]);
    $savedOk = Craft::$app->getElements()->saveElement($organization);
}

... and organizationImage uploads are getting handled magically, adding a new asset and associating it. Any hints as to how that's happening? I'd like to have more control over error handling, so more understanding of what's going on would be ideal.

If I strip it all the way down to just the organizationImage file input, pulling $organization and then running Craft::$app->getElements()->saveElement($organization); it has the same behavior of handling the file upload.

brandonkelly commented 2 years ago

@natebeaty Hard to know for sure without having a full picture of what else is happening in the request.

Try putting an Xdebug breakpoint at the beginning of yii\web\UploadedFile::loadFiles() (vendor/yiisoft/yii2/web/UploadedFile.php), and see what (if anything) is triggering it before your own upload handling code.