Task #85216

EXT:form SaveToDatabase Finisher saves files as sys_file, not as sys_file_reference

Added by Lidia Demin about 1 year ago. Updated 12 months ago.

Status:
Closed
Priority:
Should have
Assignee:
-
Category:
Form Framework
Target version:
-
Start date:
2018-06-11
Due date:
% Done:

0%

TYPO3 Version:
8
PHP Version:
Tags:
Complexity:
Sprint Focus:
On Location Sprint

Description

Use case:
I have a model with file properies (logo) that can be filled by a form, but should also be editable via backend.

Form field configuration:

-
  identifier: logo
  type: ImageUpload
    saveToFileMount: '1:/user_upload/myfolder/'

Finisher configuration:

finishers:
  -
    identifier: SaveToDatabase
    options:
      table: 'tx_myext_domain_model_mymodel'
      mode:  'insert'
      elements:
        logo:
          mapOnDatabaseColumn: 'logo'

My model used to have a TCA configuration for FAL using \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig. But that doesn't work with the form, because the finisher only creates a sys_file entry, so sys_file_reference. Why?
My current solution was to adjust my TCA and templates. But it just doesn't seem right not being able to use the advantages of FAL. Or am I missing some configuration?


Related issues

Related to TYPO3 Core - Bug #85772: EXT:form SaveToDatabaseFinisher cannot handle multi value fields New 2018-08-07
Copied to TYPO3 Core - Feature #85378: EXT:form option for saving uploaded file as sys_file_reference New 2018-06-25

History

#1 Updated by Ralf Zimmermann about 1 year ago

  • Tracker changed from Bug to Task
  • Status changed from New to Needs Feedback
  • Assignee set to Lidia Demin

Uploads are sys_file entities because there are no relations to other records (sys_file_reference) at this point.
Your finisher configuration has the intention to establish such a relationship, so you have to do that.
You need a second insert statement which creates the relation between the "sys_file" record and the "tx_myext_domain_model_mymodel.logo" property.

finishers:
  -
    identifier: SaveToDatabase
    options:
      -
        table: 'tx_myext_domain_model_mymodel'
        mode:  'insert'
        elements:
          logo:
            mapOnDatabaseColumn: 'logo'
      -
        table: 'sys_file_reference'
        mode: insert
        elements:
          logo:
            mapOnDatabaseColumn: 'uid_local'
        databaseColumnMappings:
          table_local:
            value: 'sys_file'
          tablenames:
            value: 'tx_myext_domain_model_mymodel'
          fieldname:
            value: 'logo'
          tstamp:
            value: '{__currentTimestamp}'
          crdate:
            value: '{__currentTimestamp}'
          uid_foreign:
            value: '{SaveToDatabase.insertedUids.0}'

#2 Updated by Lidia Demin about 1 year ago

It works, thank you very much!

Can we add this to documentation? Even if I would guessed that the file reference has to be set manually, I wouldn't have figured out all of the settings.

#3 Updated by Riccardo De Contardi about 1 year ago

  • Sprint Focus set to On Location Sprint

#4 Updated by Presedo Roberto about 1 year ago

This configuration is ok as long as the upload field is filled, otherwise ,if the field is not required, a broken sys_file_reference record is added with a uid_local set to 0...
I know that this is not resolving this issue, but if this example goes in the documentation, I think we should warn the users of this scenario...

The only way to resolve this situation, is not to use the SaveToDatabase finisher and create a custom one, or overwrite it, which is probably easier

As discussed on Slack, https://typo3.slack.com/archives/C093RB4P9/p1529417777000792
"the easiest way would be to create a `BaseSetup.yaml` and overwrite `TYPO3.CMS.Form.prototypes.standard.finisherDefinition.SaveToDatabase.implementationClassName = 'Your own class'`
the `SaveToDatabase` finisher has the protected method `process` which seems to be exactly what you need. Wrap that in whatever condition you need and that should work"

#5 Updated by Lidia Demin about 1 year ago

Yes, I had also the issue with an exception for the sys_file_reference table if no file was submitted. I tried setting skipIfValueIsEmpty: true for the field in both tables without no luck. But imho it should work out of the box as well that the file field does not need to be mandatory. I'll open a feature request. Till then I agree, that this hint should go into documentation as well.

#6 Updated by Lidia Demin about 1 year ago

  • Copied to Feature #85378: EXT:form option for saving uploaded file as sys_file_reference added

#7 Updated by Vasyl Mosiychuk about 1 year ago

  • Related to Bug #85772: EXT:form SaveToDatabaseFinisher cannot handle multi value fields added

#8 Updated by Vasyl Mosiychuk about 1 year ago

Ralf Zimmermann wrote:

Uploads are sys_file entities because there are no relations to other records (sys_file_reference) at this point.
Your finisher configuration has the intention to establish such a relationship, so you have to do that.
You need a second insert statement which creates the relation between the "sys_file" record and the "tx_myext_domain_model_mymodel.logo" property.

[...]

My finisher is correct and working it at the moment

 -
    options:
      -
        table: tx_foo_domain_model_foo
        mode: insert
        databaseColumnMappings:
          pid:
            value: '0'
          datetime:
            value: '{__currentTimestamp}'
          tstamp:
            value: '{__currentTimestamp}'
          crdate:
            value: '{__currentTimestamp}'
        elements:
          categories:
            mapOnDatabaseColumn: categories
          title:
            mapOnDatabaseColumn: title
          bodytext:
            mapOnDatabaseColumn: bodytext
          attachment:
            mapOnDatabaseColumn: fal_media
      -
        table: sys_category_record_mm
        mode: insert
        elements:
          categories:
            mapOnDatabaseColumn: uid_local
        databaseColumnMappings:
          tablenames:
            value: tx_foo_domain_model_foo
          fieldname:
            value: categories
          uid_foreign:
            value: '{SaveToDatabase.insertedUids.0}'
      -
        table: sys_file_reference
        mode: insert
        elements:
          attachment:
            mapOnDatabaseColumn: uid_local
        databaseColumnMappings:
          table_local:
            value: sys_file
          tablenames:
            value: tx_foo_domain_model_foo
          fieldname:
            value: fal_media
          tstamp:
            value: '{__currentTimestamp}'
          crdate:
            value: '{__currentTimestamp}'
          uid_foreign:
            value: '{SaveToDatabase.insertedUids.0}'
    identifier: SaveToDatabase

I described it here #85378

#9 Updated by alejandro antolinez about 1 year ago

I have a solution for all case.
You insert sys_file_reference whit skipIfValueIsEmpty: true

And after you update sys_file_reference whit your pid and your uid_foreign and uid_local=0 (if the case if you skipIfValueIsEmpty)
You set your pid and your uid_foreign to 0 and you dont have a broken sys_file_reference record

Example

identifier: SaveToDatabase
      options:
        1:
          table: 'tx_news_domain_model_news'
          mode: insert
          databaseColumnMappings:
            pid:
              value: 41
            datetime:
              value: '{__currentTimestamp}'
            tstamp:
              value: '{__currentTimestamp}'
            crdate:
              value: '{__currentTimestamp}'  
          elements:
            text-1:
              mapOnDatabaseColumn: 'title'
            textarea-1:
              mapOnDatabaseColumn: 'bodytext'      

        2:
          table: 'sys_file_reference'
          mode: insert
          databaseColumnMappings:
            pid:
              value: 41
            tstamp:
              value: '{__currentTimestamp}'
            crdate:
              value: '{__currentTimestamp}'  
            tablenames:
              value: 'tx_news_domain_model_news'
            table_local:
              value: 'sys_file'  
            fieldname:
              value: 'fal_media'
            uid_foreign:
              value: '{SaveToDatabase.insertedUids.1}'
          elements:
            imageupload-1:
              mapOnDatabaseColumn: 'uid_local'
              skipIfValueIsEmpty: true       
        3:
          table: 'sys_file_reference'
          mode: update
          whereClause:
            pid: 41
            uid_foreign: '{SaveToDatabase.insertedUids.1}' 
            uid_local: 0
          databaseColumnMappings:
            pid:
              value: 0
            uid_foreign:
              value: 0

But for me we need a skipActionIfValueIsEmpty to skip all the action and not just the elements.

#10 Updated by Vasyl Mosiychuk about 1 year ago

alejandro antolinez wrote:

I have a solution for all case.
You insert sys_file_reference whit skipIfValueIsEmpty: true

And after you update sys_file_reference whit your pid and your uid_foreign and uid_local=0 (if the case if you skipIfValueIsEmpty)
You set your pid and your uid_foreign to 0 and you dont have a broken sys_file_reference record

Example

[...]

But for me we need a skipActionIfValueIsEmpty to skip all the action and not just the elements.

Hello, Alejandro!

Thank you for reply.

but I have question, why so...

uid_foreign:
   value: '{SaveToDatabase.insertedUids.1}'

and not so...

uid_foreign:
   value: '{SaveToDatabase.insertedUids.0}'

I insert 'key: 0' - record = 0... and not 'key: 1' - record = 1 ...???

And I do not understand about it... skipActionIfValueIsEmpty - what is that?

I still get error when value: '{SaveToDatabase.insertedUids.0}' - empty. I don't know how it is solve.

#11 Updated by alejandro antolinez 12 months ago

You can write options as an array to perform multiple database operations.
In my case 1 is

1:
          table: 'tx_news_domain_model_news'
          mode: insert
          databaseColumnMappings:
            pid:
              value: 41
            datetime:
              value: '{__currentTimestamp}'
            tstamp:
              value: '{__currentTimestamp}'
            crdate:
              value: '{__currentTimestamp}'  
          elements:
            text-1:
              mapOnDatabaseColumn: 'title'
            textarea-1:
              mapOnDatabaseColumn: 'bodytext' 
{SaveToDatabase.insertedUids.1}
give me the uid of my first insert.

it's the code in the documentation for multiple database operations
[[https://docs.typo3.org/typo3cms/extensions/form/ApiReference/Index.html?highlight=inserteduids#savetodatabase-finisher]]

skipActionIfValueIsEmpty not exist but in the same way of skipIfValueIsEmpty skip the value from the submitted form element with the identifier <formElementIdentifier> is empty.

We need a skipActionIfValueIsEmpty (or other name) with argument a formElementIdentifier to skip all the insert

exemple:

2:
          table: 'sys_file_reference'
          mode: insert
          skipActionIfValueIsEmpty : imageupload-1
          databaseColumnMappings:
            pid:
              value: 41
            tstamp:
              value: '{__currentTimestamp}'
            crdate:
              value: '{__currentTimestamp}'  
            tablenames:
              value: 'tx_news_domain_model_news'
            table_local:
              value: 'sys_file'  
            fieldname:
              value: 'fal_media'
            uid_foreign:
              value: '{SaveToDatabase.insertedUids.1}'
          elements:
            imageupload-1:
              mapOnDatabaseColumn: 'uid_local'

if imageupload-1 it's empty whe skip all the insert in sys_file_reference

#12 Updated by alejandro antolinez 12 months ago

Try this whit your code

finishers:
  -
    identifier: SaveToDatabase
    options:
      -
        table: 'tx_myext_domain_model_mymodel'
        mode:  insert
        elements:
          logo:
            mapOnDatabaseColumn: 'logo'
      -
        table: 'sys_file_reference'
        mode: insert
        elements:
          logo:
            mapOnDatabaseColumn: 'uid_local'
            skipIfValueIsEmpty: true
        databaseColumnMappings:
          table_local:
            value: 'sys_file'
          tablenames:
            value: 'tx_myext_domain_model_mymodel'
          fieldname:
            value: 'logo'
          tstamp:
            value: '{__currentTimestamp}'
          crdate:
            value: '{__currentTimestamp}'
          uid_foreign:
            value: '{SaveToDatabase.insertedUids.0}'
      -
        table: 'sys_file_reference'
        mode: update
        whereClause:
          uid_foreign: '{SaveToDatabase.insertedUids.0}' 
          uid_local: 0
          databaseColumnMappings:
            pid:
              value: 0
            uid_foreign:
              value: 0

#13 Updated by Vasyl Mosiychuk 12 months ago

alejandro antolinez wrote:

Try this whit your code
[...]

Yes, I tried it and it is working. Now I do not get error and in the database does not created a broken records... is pretty cool...

#14 Updated by Bjoern Jacob 12 months ago

  • Status changed from Needs Feedback to Closed
  • Assignee deleted (Lidia Demin)

Since everyone is happy, I am closing this issue. Hope this is fine with everyone.

#15 Updated by Vasyl Mosiychuk 12 months ago

Bjoern Jacob wrote:

Since everyone is happy, I am closing this issue. Hope this is fine with everyone.

...will be good if this is add to the documentation.

Also available in: Atom PDF