7

I have the hypothetical Zoo extension in which I've Animal model with photo field and FrontEnd (FE) plugin with typical CRUD actions. photo field is typical FAL's FileReference and it works perfectly in backend (BE) with common TCA IRRE config.

I'm able to successful upload the file to the storage, it's visible in the Filelist module, and I can use it in BE during my Animal editing, anyway I can't create FileReference within my FE plugin.

My current approach looks like this:

/**
 * @param \Zoo\Zoo\Domain\Model\Animal $animal
 */
public function updateAction(\Zoo\Zoo\Domain\Model\Animal $animal) {

    // It reads proper uploaded `photo` from form's $_FILES
    $file = $this->getFromFILES('tx_zoo_animal', 'photo');

    if ($file && is_array($file) && $file['error'] == 0) {

        /** @type  $storageRepository \TYPO3\CMS\Core\Resource\StorageRepository */
        $storageRepository = GeneralUtility::makeInstance('\TYPO3\CMS\Core\Resource\StorageRepository');
        $storage = $storageRepository->findByUid(5); // TODO: make target storage configurable

        // This adds uploaded file to the storage perfectly
        $fileObject = $storage->addFile($file['tmp_name'], $storage->getRootLevelFolder(), $file['name']);

        // Here I stuck... below line doesn't work (throws Exception no. 1 :/)
        // It's 'cause $fileObject is type of FileInterface and FileReference is required
        $animal->addPhoto($fileObject);

    }

    $this->animalRepository->update($animal);
    $this->redirect('list');
}

anyway attempt to create reference by this line throws exception:

$animal->addPhoto($fileObject);

How can I resolve this?

Checked: DataHandler approach (link) won't work also, as it's unavailable for FE users.

TL;DR

How to add FileReference to Animal model from existing (just created) FAL record?

Community
  • 1
  • 1
biesior
  • 55,576
  • 10
  • 125
  • 182
  • 1
    Did you check http://insight.helhum.io/post/85015526410/file-upload-using-extbase-and-fal-in-typo3-6-2 - it is a different approach than your code in `uploadAction` as it uses a generic typeconverter to convert your uploaded file (or files) to an object which is directly used when creating your `Animal` model. Works perfectly both in FE and BE. – derhansen Feb 25 '15 at 07:25
  • @derhansen thx, that's first thing you see when googling, TBH, I was hope there's simpler solution for such a ... basic thing, anyway as I can see I need to dig deeper into Helmut's poc. – biesior Feb 25 '15 at 10:31

3 Answers3

13

You need to do several things. This issue on forge is where I got the info, and some stuff is taken out of Helmut Hummels frontend upload example (and the accompanying blogpost) which @derhansen already commented.

I'm not entirely sure if this is everything you need, so feel free to add things. This does not use a TypeConverter, which you should probably do. That would open further possibilities, for example it would be easily possible to implement deletion and replacement of file references.

You need to:

  • Create a FAL file reference object from the File object. This can be done using FALs resource factory.
  • Wrap it in a \TYPO3\CMS\Extbase\Domain\Model\FileReference (method ->setOriginalResource)
  • EDIT: This step is unnecessary as of TYPO3 6.2.11 and 7.2, you can directly use the class \TYPO3\CMS\Extbase\Domain\Model\FileReference.

    But, because the extbase model misses a field ($uidLocal) in 6.2.10rc1, that won't work. You need to inherit from the extbase model, add that field, and fill it. Don't forget to add a mapping in TypoScript to map your own model to sys_file_reference.

    config.tx_extbase.persistence.classes.Zoo\Zoo\Domain\Model\FileReference.mapping.tableName = sys_file_reference
    

    The class would look like this (taken from the forge issue):

     class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {
    
         /**
          * We need this property so that the Extbase persistence can properly persist the object
          *
          * @var integer
          */
          protected $uidLocal;
    
          /**
           * @param \TYPO3\CMS\Core\Resource\ResourceInterface $originalResource
           */
          public function setOriginalResource(\TYPO3\CMS\Core\Resource\ResourceInterface $originalResource) {
              $this->originalResource = $originalResource;
              $this->uidLocal = (int)$originalResource->getUid();
          }
      }
    
  • Add this to the TCA of the image field, in the config-section (adapt to your table and field names of course):

    'foreign_match_fields' => array(
        'fieldname' => 'photo',
        'tablenames' => 'tx_zoo_domain_model_animal',
        'table_local' => 'sys_file',
    ),
    
  • EDIT: Use \TYPO3\CMS\Extbase\Domain\Model\FileReference in this step if on TYPO3 6.2.11 or 7.2 or above.

    So at the end add the created $fileRef instead of $fileObject

    $fileRef = GeneralUtility::makeInstance('\Zoo\Zoo\Domain\Model\FileReference');
    $fileRef->setOriginalResource($fileObject);
    
    $animal->addPhoto($fileRef);
    
  • Don't tell anyone what you have done.

Jost
  • 5,948
  • 8
  • 42
  • 72
  • Jost, ok, I won't tell anybody ;) Finally I realized that I totally missed TypeConverters in the past. – biesior Feb 25 '15 at 10:28
  • #biesior your question and #Jost your answer save my day. I have followed all steps, create new file FileRefence.php under my model. Everything is working after remove typo3temp ;) also I have to change my set method in model. Thank you both of you Gentleman :) – Ghanshyam Gohel Nov 21 '15 at 20:36
  • Actually it saved my day again yesterday ;) – biesior Nov 22 '15 at 01:15
0

Here is the complete function to upload file in TYPO3 using FAL and create filereference

/**
 * Function to upload file and create file reference
 *
 * @var array $fileData
 * @var mixed $obj foreing model object
 *
 * @return void
 */
private function uploadAndCreateFileReference($fileData, $obj) {
    $storageUid = 2;
    $resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();

    //Adding file to storage
    $storage = $resourceFactory->getStorageObject($storageUid);
    if (!is_object($storage)) {
        $storage = $resourceFactory->getDefaultStorage();
    }

    $file = $storage->addFile(
          $fileData['tmp_name'],
          $storage->getRootLevelFolder(),
          $fileData['name']
    );


    //Creating file reference
    $newId = uniqid('NEW_');
    $data = [];
    $data['sys_file_reference'][$newId] = [
        'table_local' => 'sys_file',
        'uid_local' => $file->getUid(),
        'tablenames' => 'tx_imageupload_domain_model_upload', //foreign table name
        'uid_foreign' => $obj->getUid(),
        'fieldname' => 'image', //field name of foreign table
        'pid' => $obj->getPid(),
    ];
    $data['tx_imageupload_domain_model_upload'][$obj->getUid()] = [
        'image' => $newId,
    ];

    $dataHandler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
        'TYPO3\CMS\Core\DataHandling\DataHandler'
    );
    $dataHandler->start($data, []);
}   

where $filedata = $this->request->getArgument('file_input_field_name');

And

$obj = //Object of your model for which you are creating file reference

Mihir Bhatt
  • 3,019
  • 2
  • 37
  • 41
  • Thanks for sharing! I get the error `Fatal error: Call to a member function writelog() on null in /var/www/typo3_src-7.6.15/typo3/sysext/core/Classes/DataHandling/DataHandler.php on line 8138` and found following issue on TYPO3 forge: https://forge.typo3.org/issues/75805. Am I doing something wrong, or why is this working for you and not for me? :-) – chris Jan 29 '17 at 16:46
0

This example does not deserve a beauty prize but it might help you. It works in 7.6.x

private function uploadLogo(){

   $file['name']    = $_FILES['logo']['name'];
   $file['type']    = $_FILES['logo']['type'];
   $file['tmp_name']  = $_FILES['logo']['tmp_name'];
   $file['size']    = $_FILES['logo']['size'];

   // Store the image
   $resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
   $storage = $resourceFactory->getDefaultStorage();

   $saveFolder = $storage->getFolder('logo-companies/');
   $newFile = $storage->addFile(
     $file['tmp_name'],
     $saveFolder,
     $file['name']
   );

   // remove earlier refereces
   $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_file_reference', 'uid_foreign = '. $this->getCurrentUserCompanyID());

   $addressRecord = $this->getUserCompanyAddressRecord();

   // Create new reference
   $data = array(
     'table_local' => 'sys_file',
     'uid_local' => $newFile->getUid(),
     'tablenames' => 'tt_address',
     'uid_foreign' => $addressRecord['uid'],
     'fieldname' => 'image',
     'pid' => $addressRecord['pid']
   );

   $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_file_reference', $data);
   $newId = $GLOBALS['TYPO3_DB']->sql_insert_id();

   $where = "tt_address.uid = ".$addressRecord['uid'];
   $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tt_address', $where, array('image' => $newId ));
}
mipmip
  • 1,072
  • 1
  • 10
  • 24