In diesem Beispiel wird eine neue FAL FileReference im Controller erzeugt und diese anschließend einem Extbase Model Person zugewiesen. Die Erzeugung von FAL FileReferences im Controller wird bislang von Extbase leider noch nicht nativ unterstützt, so dass manuelle Maßnahmen erforderlich sind. Eine Möglichkeit, welche in diesem Beispiel verwendet wird, ist die Erweiterung der Klasse FileReference (Danke an Helmut Hummel).

Zu beachten und Grund für so manche Verwirrung ist, dass TYPO3 zwei unterschiedliche FileReference-Klassen liefert: Das Extbase Model \TYPO3\CMS\Extbase\Domain\Model\FileReference sowie das Core Model \TYPO3\CMS\Core\Resource\FileReference. Ebenso ist darauf zu achten, dass die TCA Konfiguration vollständig ist und der Methode getFileFieldTCAConfig die erforderlichen Parameter (foreign_match_fields) übergeben werden.

Update: Ein aktualisiertes Beispiel findet sich hier ;)

Extbase Model (FileReference)

<?php

namespace Vendor\Ext\Domain\Model;

/***************************************************************
 *  Copyright notice
 *
 *  (c) 2014 Helmut Hummel
 *
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
 *
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/

/**
 * Class FileReference
 */
class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {

    /**
     * uid of a sys_file
     *
     * @var integer
     */
    protected $originalFileIdentifier;

    /**
     * setOriginalResource
     *
     * @param \TYPO3\CMS\Core\Resource\FileReference $originalResource
     * @return void
     */
    public function setOriginalResource(\TYPO3\CMS\Core\Resource\FileReference $originalResource) {
        $this->originalResource = $originalResource;
        $this->originalFileIdentifier = (int)$originalResource->getOriginalFile()->getUid();
    }

    /**
     * setFile
     *
     * @param \TYPO3\CMS\Core\Resource\File $falFile
     * @return void
     */
    public function setFile(\TYPO3\CMS\Core\Resource\File $falFile) {
        $this->originalFileIdentifier = (int)$falFile->getUid();
    }

}

Extbase Model (Person)

<?php

namespace Vendor\Ext\Domain\Model;

/**
 * Class Person
 */
class Person extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {

    /**
     * title
     *
     * @var string
     */
    protected $title = '';

    /**
     * image
     *
     * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference
     */
    protected $image = NULL;

    /**
     * Returns the title
     *
     * @return string $title
     */
    public function getTitle() {
        return $this->title;
    }

    /**
     * Sets the title
     *
     * @param string $title
     * @return void
     */
    public function setTitle($title) {
        $this->title = $title;
    }

    /**
     * Returns the image
     *
     * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
     */
    public function getImage() {
        return $this->image;
    }

    /**
     * Sets the image
     *
     * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
     * @return void
     */
    public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) {
        $this->image = $image;
    }

}

Extbase Controller (Person)

<?php

namespace Vendor\Ext\Domain\Model;

/**
 * Class PersonController
 */
class PersonController  extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {

   /**
    * personRepository
    *
    * @var \Vendor\Ext\Domain\Repository\PersonRepository
    * @inject
    */
    protected $personRepository;

   /**
    * pesistenceManager - not neccessary since 6.2
    *
    * @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
    * @inject
    */
    protected $persistenceManager;

    /**
     * Action addImage
     *
     * @param \Vendor\Ext\Domain\Model\Person $person
     * @return void
     */
    public function AddImageAction(\Vendor\Ext\Domain\Model\Person $person) {

        $storageRepository = $this->objectManager->get('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
        $storage = $storageRepository->findByUid('1');
        $targetFolder = $storage->createFolder('path/to/target_folder');
        $originalFilePath = '/tmp/tempfile.png';
        $newFileName = 'myfile123.png';

        if (file_exists($originalFilePath)) {
            $movedNewFile = $storage->addFile($originalFilePath, $targetFolder, $newFileName);
            $newFileReference = $this->objectManager->get('Vendor\\Ext\\Domain\\Model\\FileReference');
            $newFileReference->setFile($movedNewFile);
            $person->setImage($newFileReference);
        }

        $this->personRepository->update($person);
        // Not neccessary since 6.2
        $this->persistenceManager->persistAll();

    }

}

TCA Konfiguration (Person)

'image' => array(
	'exclude' => 1,
	'label' => 'LLL:EXT:ext/Resources/Private/Language/locallang_db.xlf:tx_ext_domain_model_person.image',
	'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
		'image',
		array(
			'maxitems' => 6,
			'foreign_match_fields' => array(
				'fieldname' => 'image',
				'tablenames' => 'tx_ext_domain_model_person',
				'table_local' => 'sys_file',
			),
		),
		$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
	),
),

Typoscript Konfiguration

config.tx_extbase {
	persistence {
		classes {
			Vendor\Ext\Domain\Model\FileReference {
				mapping {
					tableName = sys_file_reference
					columns {
						uid_local.mapOnProperty = originalFileIdentifier
					}
				}
			}
		}
		objects {
			TYPO3\CMS\Extbase\Domain\Model\FileReference.className = Vendor\Ext\Domain\Model\FileReference
		}
		updateReferenceIndex = 1
	}
}




Kommentare

Rolf schrieb am 15.07.2015:
Hallo,
ich habe das für meine Extension so gemacht - mit dem Unterschied, das ich nur eine einzelne Datei meinem Objekt zuordne mit setImage() statt addImage().
Das funktioniert soweit ganz prima mit einem Problem:
im Backend werden bei diesen Objekten dann immer 2 Dateien zugeordnet - eine davon mit einer Warning (dreieckiges Warnschild). Woran kann das liegen?

Rolf schrieb am 15.07.2015:
Nachtrag,

in der Tabelle zu meiner Extension steht dann die (2.) UID aus sys_file_reference (ich hätte eher eine 1 erwartet - wie bei per Backend zugeordneten Dateien)

TYPO3 Tiger schrieb am 15.07.2015:
Hallo Rolf, bei meinem Beispiel war ein Fehler im Controller, es sollte natürlich heißen $person->setImage() anstelle $person->addImage(). Zu deinem Problem: Wenn die TCA Konfiguration korrekt ist, sollte alles funktionieren. Ggf. zur Sicherheit mal die vorher erzeugten FileReferences löschen und den Reference-Index updaten?

Simon schrieb am 15.07.2015:
Hi,
danke für den guten Beitrag.
Hast Du eine Ahnung wie ich dem neu erzeugten FAL-Objekt noch seine Metadaten (title, description) mitgebe?

Mark schrieb am 03.08.2015:
Hallo,

bei mir wird die uid_local in der sys_file_reference nicht gesetzt (0). Finde den Fehler einfach nicht :(
Eine Idee vielleicht?
Gruß
Mark

micha schrieb am 19.08.2015:
Hallo, tolle Anleitung! Da man hierzu sehr viele falsche Sachen im Netz findet, eventuell noch einen Hinweis, damit es korrekt funktioniert.

Im TypoScript Setup des Moduls sollte das Mapping noch eingerichtet werden:

config.tx_extbase {
persistence {
classes {
Vendor\Ext\Domain\Model\FileReference {
mapping {
tableName = sys_file_reference
columns {
uid_local.mapOnProperty = originalFileIdentifier
}
}
}
}
}
objects {
TYPO3\CMS\Extbase\Domain\Model\FileReference.className = Vendor\Ext\Domain\Model\FileReference
}
}

VG Micha

Jens schrieb am 23.09.2015:
Hallo,

folgende Zeilen musste ich im TypoScript hinzufügen, damit die Lösung in meinem Backend-Modul funktioniert (TYPO3 6.2.9):
config.tx_extbase {
persistence {
classes {
Vendor\Ext\Domain\Model\FileReference {
mapping {
tableName = sys_file_reference
columns {
uid_local.mapOnProperty = originalFileIdentifier
}
}
}
}
# make sure ref_index is updated
updateReferenceIndex = 1
}
}

Grüße & vielen Dank für die Lösung

TYPO3 Tiger schrieb am 08.10.2015:
Hi Micha & Jens,

danke für eure Hinweise. Das TypoScript ist natürlich erforderlich damit das Ganze funktioniert. Irgendwie ist mir das untergegangen... Das Beispiel ist nun ergänzt.

MichaF schrieb am 14.11.2015:
Hallo,

ich habe mit Freude deinen Post gefunden, leider habe ich ein Problem, wo ich nix mit anfangen kann, vielleicht hast du einen Ansatz für mich.

Und zwar erhalte ich folgende Meldung:
Exception while property mapping at property path "image":Property "name" was not found in target object of type "TYPO3\CMS\Extbase\Domain\Model\FileReference"

leider habe ich keinen schimmer wie er an das Property name kommt das er es anmeckert.

Ich hoffe du hast einen tipp.

Gruß MichaF

fullstack schrieb am 23.05.2016:
Hallo MichaF,

steht vor dem selben issue. Konntest Du das Problem mittlerweile Lösen?

Patrick schrieb am 10.07.2017:
Hallo, vielen Dank für diese tolle Erklärung!

Ich stehe nun vor dem Problem, dass ich anstelle eines FileObjects / FileReferenceoBjects NULL erhalte.

In der Datenbank wird alles ordentlich persistiert.
Es handelt sich, entgegen deinem / eurem Tutorial um keine reine image-file.

Ich habe genau gleich gemacht wie ihr.
Genutzt wird Typo3 6.2 LTS.

Andreas Krüger schrieb am 31.01.2018:
Hallo,

wenn ich die File nun update schreibt er auch in die Database eine neue reference Nummer aber im frontend wird die alte genutzt?!?

Jens schrieb am 06.02.2018:
Danke erst einmal für den Beitrag. Der hilft mir schon ein ganzes Stück weiter.

Hat das jemand schon einmal mit mehreren Files zum Laufen gekriegt? Zwar werden alle ausgewählten Inhalte korrekt hochgeladen, aber verknüpft ist immer nur ein File im Datensatz...

Patrik schrieb am 02.08.2018:
Hallo,

ich habe auch versucht Dateireferenzen über einen Import (Planer Task) zu erstellen. Im Grunde klappt das Ganze auch, aber es gibt noch ein Problem, was meiner Meinung nach aber im Core zu liegen scheint.

Wenn ich den Import fahre, dann werden mir die Einträge in der sys_file_reference erstellt. Stoße ich den Import erneut an, werden die Einträge erneut erstellt, da hier der Primärschlüssel alleine auf dem Feld uid liegt. Es müsste aber (wie bei einer Zwischentabelle in TYPO3 üblich) auch uid_local und uid_foreign und in diesem Fall auch noch tablenames + fieldname berücksichtigt werden.

Das Resultat ist hier übrigens auch, dass das Model an das die Datei angehängt wird diese Datei im Backend dann doppelt/dreifach/mehrfach verknüpft hat.

Sehe ich das richtig oder habe ich evtl. einen Fehler?

Zudem denke ich, dass das Beispiel eigentlich nicht ganz richtig ist.

Eine Beziehung zu einer Datei über die Zwischentabelle sys_file_reference ist doch eine m:n Beziehung.

Daher müsste das Attribut "image" im Model eigentlich nicht als einzelnes FileReference Model, sondern als ObjectStorage<FileReference> definiert werden.

Dann gäbe es entsprechend die Methoden addImage und removeImage die intern wiederum $this->image->attach() und $this->image->detach() aufrufen.

Ansonsten ist die hier angegebene Einstellung maxItems = 6 sinnlos. Aber auch ich habe maxItems = 1 eingetragen und das wird im Programmiercode natürlich ignoriert. Ist ja nur fürs Backend.

Klappt das denn zuverlässig bei Jemandem auch wenn der Code mehrmals/regelmäßig ausgeführt wird?

Ich würde mich über einen Hinweis freuen, der hilft. Ich persönlich bin kurz davor den ganzen Müll rauszuschmeißen und über $GLOBALS['TYPO3_DB']->exec_SELECT und exec_INSERT bzw. exec_UPDATE zu arbeiten. Das ist auf jeden Fall zuverlässiger als der TYPO3 Core.

Gruß
Patrik