========================== Media Upload for TYPO3 CMS ========================== This extension for `TYPO3 CMS`_ provides a Fluid widget for (mass) uploading media on the Frontend using HTML5 techniques. Once selected by the User, the Media will be directly uploaded to a temporary space within ``typo3temp``. After the form is posted, uploaded File can be retrieved by an ``UploadService``. If the form has a "show" step before the final submission, the uploaded images can be displayed by another widget. The file upload is handled by Fine Uploader which is a Javascript plugin aiming to bring a user-friendly file-uploading experience over the web. The plugin relies on HTML5 technology which enables Drag & Drop from the Desktop. File transfer is achieved by Ajax if supported. If not, a fall back method with classical file upload is used by posting the file. (Though, the legacy approach still need to be tested more thoroughly). .. _Fine Uploader: http://fineuploader.com/ .. _TYPO3 CMS: http://typo3.org/ .. image:: https://raw.github.com/fabarea/media_upload/master/Documentation/Upload-01.png After a file has been uploaded, the user can validate and possibly remove it from the list. .. image:: https://raw.github.com/fabarea/media_upload/master/Documentation/Upload-02.png Installation ============ The installation is completed in two steps. Install the extension as normal in the Extension Manager. Then, load the JavaScript / CSS for the pages that will contain the upload widget. The extension assumes jQuery to be loaded:: # CSS EXT:media_upload/Resources/Public/Build/media_upload.min.css # JavaScript EXT:media_upload/Resources/Public/Build/media_upload.min.js Upload Widget ============= You can make use of a Media Upload widget. Syntax is as follows:: # Minimum syntax {namespace mu=Fab\MediaUpload\ViewHelpers} # With some more attributes... We assume we have a property "images" in our model # and this value could be something different like "documents" or whatever. # Required attributes: # -------------------- # # - storage # Default values: # --------------- # # The Storage identifier to get some automatic settings, such as allowedExtensions, default NULL. # storage = 1 # # Allowed extension to be uploaded. Override the allowed extension list from the storage. default NULL. # allowedExtensions = "jpg, png" # # Maximum size allowed by the plugin, default 0. # maximumSize = # # The unit used for computing the maximumSize, default Mo. # sizeUnit = Mo # # Maximum items to be uploaded, default 10. # maximumItems = 10 # # The property to be used for retrieving the uploaded images, default NULL. # property = foo To see the uploaded images in a second step:: # The property to be used for retrieving the uploaded images, default NULL. # property = foo Upload Service ============== Once files have been uploaded on the Frontend and are placed in a temporary directory, we have to to retrieve them and store them into their final location. This code can be used in your controller:: /** * @var \Fab\MediaUpload\Service\UploadFileService * @inject */ protected $uploadFileService; /** * @return void */ public function createAction() { /** @var array $uploadedFiles */ $uploadedFiles = $this->uploadFileService->getUploadedFiles() # A property name is needed in case specified in the Fluid Widget # $uploadedFiles = $this->uploadFileService->getUploadedFiles('images') # Process uploaded files and move them into a Resource Storage (FAL) foreach($uploadedFiles as $uploadedFile) { /** @var \Fab\MediaUpload\UploadedFile $uploadedFile */ $uploadedFile->getTemporaryFileNameAndPath(); $storage = ResourceFactory::getInstance()->getStorageObject(1); /** @var File $file */ $file = $storage->addFile( $uploadedFile->getTemporaryFileNameAndPath(), $storage->getRootLevelFolder(), $uploadedFile->getFileName(), 'changeName' ); # Note: Use method `addUploadedFile` instead of `addFile` if file is uploaded # via a regular "input" control instead of the upload widget (fine uploader plugin) # $file = $storage->addUploadedFile() $fileReference = $this->objectManager->get(\YourVendor\YourExtensionKey\Domain\Model\FileReference::class); $fileReference->setFile($file); $yourDomainObject->addImages($fileReference); } ... } File Configuration in FAL ========================= How to configure a field / property of type file? SQL --- :: CREATE TABLE tx_domain_model_foo ( images varchar(255) DEFAULT '' NOT NULL, ); TCA --- :: $TCA['tx_domain_model_foo'] = array( 'images' => array( 'label' => 'Images', 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( 'images', array( 'appearance' => array( 'createNewRelationLinkTitle' => 'LLL:EXT:cms/locallang_ttc.xlf:images.addFileReference' ), 'minitems' => 0, 'maxitems' => 1, ), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] ), ), ); Model ----- Your domain model, should then contain the method ``addImages`` for the purpose of ``$yourDomainObject->addImages($fileReference);``. See code above in the Upload Service. :: /** * Images * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> */ protected $images; public function addImages(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) { $this->images->attach($image); } File Reference Model -------------------- We must extend the FileReference for the purpose of ``$fileReference->setFile($file);```. See code above in the Upload Service. :: namespace YourVendor\YourExtensionKey\Domain\Model; class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference { /** * @params \TYPO3\CMS\Core\Resource\File $file */ public function setFile(\TYPO3\CMS\Core\Resource\File $file) { $this->originalFileIdentifier = (int)$file->getUid(); } } TypoScript ---------- Finally we must configure the persistence layer of Extbase. :: config.tx_extbase { persistence { # Enable this if you need the reference index to be updated updateReferenceIndex = 1 classes { YourVendor\YourExtensionKey\Domain\Model\FileReference { mapping { tableName = sys_file_reference columns { uid_local.mapOnProperty = originalFileIdentifier } } } } } objects { TYPO3\CMS\Extbase\Domain\Model\FileReference.className = YourVendor\YourExtensionKey\Domain\Model\FileReference } } Security ======== By default Media Upload require a Frontend User to be authenticated. This can be adjusted according to your needs by selecting only allowed Frontend User Group. This behaviour can be configured by TypoScript. :: plugin.tx_mediaupload { settings { # "*", means every authenticated User can upload. (default) # "1,2", means every User belonging of Frontend Groups 1 and 2 are allowed. # no value, everybody can upload. No authentication is required. Caution!! allowedFrontendGroups = * } } Scheduler tasks =============== The temporary files contained within ``typo3temp`` can be flushed from time to time. It could be files are left aside if the user has not finalized the upload. The Command can be used via a scheduler task with a low redundancy, once per week as instance:: # List all temporary files ./typo3/cli_dispatch.phpsh extbase temporaryFile:list # Remove them. ./typo3/cli_dispatch.phpsh extbase temporaryFile:flush Building assets in development ============================== The extension provides JS / CSS bundles which included all the necessary code. If you need to make a new build for those JS / CSS files, consider that `Bower`_ and `Grunt`_ must be installed on your system as prerequisite. Install the required Web Components:: cd typo3conf/ext/media_upload # This will populate the directory Resources/Public/WebComponents. bower install # Install the necessary NodeJS package. npm install Then you must build Fine Uploader from the source:: cd Resources/Private/BowerComponents/fine-uploader # Install the necessary NodeJS package inside "fine-uploader". npm install # Do the packaging works. It will create a "_dist" directory containing the build. grunt package Finally, you can run the Grunt of the extension to generate a build:: cd typo3conf/ext/media_upload grunt build While developing, you can use the ``watch`` which will generate the build as you edit files:: grunt watch .. _Bower: http://bower.io/ .. _Grunt: http://gruntjs.com/