File name is not valid file upload (FAL) - TYPO3 - typo3

I have a fluid form with one filed as file upload. The file upload field is optional. I'm using Helhum's fileupload property converter. But the problem is that when the file is null then an error occured. Model is
/**
* file
*
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $file = null;
/**
* Returns the file
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $file
*/
public function getFile()
{
return $this->file;
}
/**
* Sets the file
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $file
* #return void
*/
public function setFile($file = NULL)
{
$this->file = $file;
}
and my form is
<f:form.upload property="file" />

Related

Handle filesUpload in a single table Symfony

Thank you for your interest,
SHORT
I want to manage all my uploads (Image, PDF, Video etc...) in a single entity, so I use entity Inheritance to get various "types" and OneToOne relations to link parent entity with correct upload. I didn't found any bundle to do this and face problems:
Constraints use
Setting uploaded file and not upload entity
Get uploaded file and not upload entity (edition)
LONG
Instead of having 1 file management in each table (which is quiet verbose) I preferred to have only one table Uploads to handle every Uploads. Then I just have to do OneToOne relations to get my file, plus using inheritance I can apply various treatment depending on Image or PDF for example.
I have at least 4 entities that needs image, so I think that 1to1 relation is a good choice.
But I face problems doing things like this :
Constraints aren't taking into account
Edition of $file should set $file->file (it doesn't send the entity from Uploads/Image but the file to create this entity
The Uploaded file isn't loaded on entity edition and should be reuploaded each time I edit entity
Does anyone did this ? I can't find out how to achieve this correctly.
Looking at the assert problem I tried to:
Define asserts on Image (this doesn't work as expected as the form target the $file of WithImage)
Using annotation #Assert\Image()
Using loadValidatorMetadata
Using annotation #Assert\Callback()
Define assert on form field 'constraints' => array(new Assert\Image()), this works but need to be defined everywhere I use it...
Looking at the setter misused I found a workaround, but this is quiet ugly:
public function setFile($file = null)
{
if ($file instanceof \Symfony\Component\HttpFoundation\File\UploadedFile) {
$tmpfile = new Image();
$tmpfile->setFile($file);
$file = $tmpfile;
}
$this->file = $file;
return $this;
}
(PS: I read about traits to avoid copy/paste of code, I have checked the SonataMediaBundle but this doesn't seems to apply to my case)
CODE
So I designed my classes as follow:
Entity\Uploads.php To handle all the life of a file from upload to remove (and access, move, edit, possibly thumbnail etc ...)
<?php
namespace Acme\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Acme\CoreBundle\Utils\UUID;
/**
* Uploads
*
* #ORM\Table(name="uploads")
* #ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\UploadsRepository")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="class", type="string")
* #ORM\DiscriminatorMap({"image" = "Image"})
* #ORM\HasLifecycleCallbacks
*/
abstract class Uploads
{
protected $file;
private $tempFileName;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var string
*
* #ORM\Column(name="fileName", type="string", length=36, unique=true)
*/
private $fileName; // UUID
/**
* #var string
*
* #ORM\Column(name="extension", type="string", length=4)
*/
private $extension;
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set date.
*
* #param \DateTime $date
*
* #return uploads
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date.
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set fileName.
*
* #param string $fileName
*
* #return uploads
*/
public function setFileName($fileName)
{
$this->fileName = $fileName;
return $this;
}
/**
* Get fileName.
*
* #return string
*/
public function getFileName()
{
return $this->fileName;
}
/**
* Set extension
*
* #param string $extension
*
* #return string
*/
public function setExtension($extension)
{
$this->extension = $extension;
return $this;
}
/**
* Get extension
*
* #return string
*/
public function getExtension()
{
return $this->extension;
}
public function getFileNameExt()
{
return $this->getFileName().'.'.$this->getExtension();
}
public function setFile(UploadedFile $file)
{
$this->file = $file;
if (null !== $this->getId()) {
$this->tempFileName = $this->getFileNameExt();
$this->fileName = null;
$this->extension = null;
}
}
public function getFile()
{
return $this->file;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null === $this->file) {
return;
}
$this->extension = $this->file->guessExtension();
$this->fileName = UUID::v4();
$this->preUpdateFile();
}
protected function preUpdateFile(){} // To define if specific treatment
/**
* #ORM\PrePersist()
*/
public function prePersistDate()
{
$this->date = new \DateTime();
return $this;
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
if (null !== $this->tempFileName) {
$oldFile = $this->getUploadRootDir().$this->tempFileName;
if (file_exists($oldFile)) {
unlink($oldFile);
}
}
$this->file = $this->file->move(
$this->getUploadRootDir(),
$this->getFileNameExt()
);
$this->postUpdateFile();
}
protected function postUpdateFile(){} // To define if specific treatment
/**
* #ORM\PreRemove()
*/
public function preRemoveUpload()
{
// On sauvegarde temporairement le nom du fichier
$this->tempFileName = $this->getFileNameExt();
$this->preRemoveFile();
}
protected function preRemoveFile(){} // To define if specific treatment
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
$oldFile = $this->getUploadRootDir().$this->tempFileName;
if (file_exists($oldFile)) {
unlink($oldFile);
}
$this->postRemoveFile();
}
protected function postRemoveFile(){} // To define if specific treatment
public function getFileUri()
{
return $this->getUploadDir().$this->getFileNameExt();
}
public function getUploadDir()
{
return 'uploads/';
}
protected function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function __toString() {
return $this->getFileNameExt();
}
}
Entity\Image.php A specific type of upload with its own constraints and file management
<?php
namespace Acme\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Image
*
* #ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\ImageRepository")
*/
class Image extends Uploads
{
}
Entity\WithImage.php An entity which needs an Image
<?php
namespace Acme\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* WithImage
*
* #ORM\Table(name="with_image")
* #ORM\Entity(repositoryClass="Acme\CoreBundle\Repository\WithImageRepository")
*/
class WithImage
{
/**
* #ORM\OneToOne(targetEntity="Acme\CoreBundle\Entity\Image", cascade={"persist", "remove"})
*/
protected $file;
}
Some thoughts come to my mind to help you achieve what you want.
First, you have to upload the files in a form, and the constraints should be in a property in an entity (unless you want to have the pain of writing your constraints in every form, which is not very mantainable). So, for every entity that's going to have files, define a file property (not ORM anotated) and write your constraints there. Also add the respective getters and setters.
/**
* #var UploadedFile
* #Assert\NotBlank(groups={"New"})
* #Assert\File(mimeTypes={"text/html", "text/markdown", "text/plain"})
*/
private $file;
Second, you might ask ¿but how do I save them to a different Entity? This is when I would recommend you to use a Doctrine Event Subscriber. Basically, is a service that is defined with a doctrine.event_subscriber tag which class implements the Doctrine\Common\EventSubscriber Interface. You can subscribe to events like preUpdate, postLoad, and the interesting for you: prePersist.
My take on this would be that you subscribe to the prePersist event. The event will pass you the entity (with that file non-orm property we created, that has the UploadedFile instance holding your file info).
Then, using the info for that file, create a new Upload entity, pass all the info you want, and then set that in the real file orm mapped property that holds your file relationship with your desired entity. For this to work you will have to enable persist cascade if I recall correctly.
The benefits of this:
1. You can define your constraints in your Entities.
2. You can have the Uploads Entity you desire.
The only major problem is that you will have to do all the retrieval, storing and updating of the Uploads entity through a listener. But's the only thing I can think of to help you.

How to get translated FAL image in extbase (not in Fluid) in TYPO3?

I am trying to get translated FAL image in extbase but it gives me default language FAL image.
I am using TYPO3 7.6.16. Its a multi-language website.
I have created 2 website languages 1) English, 2) Spanish and the default one is Dutch.
Currently I am fetching data from repository and it gives me model with the same FAL image in both translated version and in original version of the record.
How Can I get translated FAL image using extbase (not in Fluid), because I want to return it to JSON response?
Here is the code:
Controller:
$posts = $this->postRepository->findByLanguage($langId);
foreach($posts as $post) {
$output[] = [
'uid' => $post->getUid(),
'title' => $post->getTitle(),
'image' => $post->getImage()->getOriginalResource()->getOriginalFile()->getPublicUrl()
];
}
header('Content-Type: application/json');
echo json_encode($output);
exit();
Here I am getting default language FAL image instead of localised on line $post->getImage()->getOriginalResource()->getOriginalFile()->getPublicUrl()
Repository:
/**
* #return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
*/
public function findByLanguage($langId, $postId = 0)
{
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(FALSE);
$query->getQuerySettings()->setRespectSysLanguage(TRUE);
$query->getQuerySettings()->setLanguageUid($langId);
if ($postId) {
$query->matching(
$query->equals('uid' , $postId)
);
return $query->execute()->getFirst();
}
return $query->execute();
}
Model:
/**
* title
*
* #var string
*/
protected $title;
/**
* image
*
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $image = null;
/**
* #return bool $title
*/
public function getTitle() {
return $this->title;
}
/**
* #param string $title
* #return void
*/
public function setTitle($title) {
$this->title = $title;
}
/**
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
*/
public function getImage() {
return $this->image;
}
/**
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image
* #return void
*/
public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) {
$this->image = $image;
}
There was a bug where the FAL records (sys_file_reference) of translated (copy translate) contents did not get the lanuguage id of the translation.
I made a bugfix for that: https://github.com/BenjaminBeck/bdm_bugfix_translatecopy - maybe thats your issue?

TYPO3 href not working

I am quite new to TYPO3, I am inspecting a code for errors and I saw a non working href.
the inspection in the browser shows empty href :
<a class="download" target="_blank" title="Initiates file download" href=""> here..</a>
The code is :
<a class="download" target="_blank" title="Initiates file download" href="{location.pdf.originalResource.publicUrl}"><f:translate key="tx_locations_domain_model_location.here" />..</a>
I don't understand this location.pdf.originalResource.publicUrl !!
When I display {location} I get : Locations\Locations\Domain\Model\Location:102
I can't find such path in my folders !!
What am I missing !!
When I make
<f:debug>{location}</f:debug>
I see : pdf => NULL , how can I fix it, in my backend I select a PDF and saved. no error message
UPDATE:
My Pdf field is int(11) unsigned,
Here is my TCA (typo3conf/ext/locations/Configuration/TCA/Location.php)
$GLOBALS['TCA']['tx_locations_domain_model_location'] = array(
....
'columns' => array(
....
'pdf' => array(
'exclude' => 1,
'label' => 'LLL:EXT:locations/Resources/Private/Language/locallang_db.xlf:tx_locations_domain_model_location.pdf',
'config' => array (
'type' => 'group',
'internal_type' => 'file',
'allowed' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
'max_size' => $GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize'],
'uploadfolder' => 'uploads/pics',
'show_thumbs' => 1,
'size' => 1,
'minitems' => 0,
'maxitems' => 1
)
),
here is my Location class :
<?php
namespace Locations\Locations\Domain\Model;
/**
* Location
*/
class Location extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
/**
* title
*
* #var string
*/
protected $title = '';
/**
* fullTitle
*
* #var string
*/
protected $fullTitle = '';
/**
* description
*
* #var string
*/
protected $description = '';
/**
* image
*
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $image = NULL;
/**
* secondTitle
*
* #var string
*/
protected $secondTitle = '';
/**
* secondDescription
*
* #var string
*/
protected $secondDescription = '';
/**
* address
*
* #var string
*/
protected $address = '';
/**
* howToGetIt
*
* #var string
*/
protected $howToGetIt = '';
/**
* thirdTitle
*
* #var string
*/
protected $thirdTitle = '';
/**
* thirdDescription
*
* #var string
*/
protected $thirdDescription = '';
/**
* googleMap
*
* #var string
*/
protected $googleMap = '';
/**
* pdf
*
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $pdf = NULL;
/**
* pricingtpl
*
* #var int
*/
protected $pricingtpl;
/**
* category
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Locations\Locations\Domain\Model\Category>
*/
protected $category = NULL;
/**
* __construct
*/
public function __construct() {
//Do not remove the next line: It would break the functionality
$this->initStorageObjects();
}
/**
* Initializes all ObjectStorage properties
* Do not modify this method!
* It will be rewritten on each save in the extension builder
* You may modify the constructor of this class instead
*
* #return void
*/
protected function initStorageObjects() {
$this->category = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* Returns the title
*
* #return string $title
*/
public function getTitle() {
return $this->title;
}
/**
* 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;
}
/**
* Sets the pdf
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $pdf
* #return void
*/
public function setPdf(\TYPO3\CMS\Extbase\Domain\Model\FileReference $pdf) {
$this->pdf = $pdf;
}
/**
* Removes a Category
*
* #param \Locations\Locations\Domain\Model\Category $categoryToRemove The Category to be removed
* #return void
*/
public function removeCategory(\Locations\Locations\Domain\Model\Category $categoryToRemove) {
$this->category->detach($categoryToRemove);
}
/**
* Returns the category
*
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Locations\Locations\Domain\Model\Category> $category
*/
public function getCategory() {
return $this->category;
}
/**
* Sets the category
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Locations\Locations\Domain\Model\Category> $category
* #return void
*/
public function setCategory(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $category) {
$this->category = $category;
}
}
Your model Location.php file. You can't define getPdf() method only use set method. Please define first getPdf() method in your Location.php file.
Like this.
/**
* Returns the pdf
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $pdf
*/
public function getPdf() {
return $this->Pdf;
}
After you can debug your .html file like this <f:debug>{_all}</f:debug> and see the debug output.
You don't have to use in Fluid things like <a href=""/>, you can find the <f:link..>, <f:uri..>,etc, in fluid documentation for generating links.
But there for file downloading you have to use this viewhelper. You have to know only the uid of the file. In your case {location.pdf.uid} Be sure that you have indexed files before use it.
<v:resource.file additionalAttributes="{foo: 'bar'}" data="{foo: 'bar'}" identifier="[mixed]" categories="[mixed]" treatIdAsUid="1" treatIdAsReference="1" as="NULL">
<!-- tag content - may be ignored! -->
</v:resource.file>

How to implement multiple file upload in TYPO3 Front End Extension

My requirement is to implement a multiple fileupload field in TYPO3 Front-end Extension. Here is what I've used for a single file upload.
My Fields in Model
/**
* angebotuploaden
*
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $angebotuploaden = NULL;
/**
* Returns the angebotuploaden
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $angebotuploaden
*/
public function getAngebotuploaden() {
return $this->angebotuploaden;
}
/**
* Sets the angebotuploaden
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $angebotuploaden
* #return void
*/
public function setAngebotuploaden(\TYPO3\CMS\Extbase\Domain\Model\FileReference $angebotuploaden) {
$this->angebotuploaden = $angebotuploaden;
}
Now I face issues in implementing multiple file-uploads for this field. Please help me to sort it out.
Use ObjectStorage to get an 1:n-Relation to the FileReference model. In your model that could look like this:
/**
* uploadFiles
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
* #cascade remove
*/
protected $uploadFiles = NULL;
/**
* __construct
*/
public function __construct() {
//Do not remove the next line: It would break the functionality
$this->initStorageObjects();
}
/**
* Initializes all ObjectStorage properties
* Do not modify this method!
* It will be rewritten on each save in the extension builder
* You may modify the constructor of this class instead
*
* #return void
*/
protected function initStorageObjects() {
$this->uploadFiles = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* Adds a UploadFile
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $uploadFile
* #return void
*/
public function addUploadFile(\TYPO3\CMS\Extbase\Domain\Model\FileReference $uploadFile) {
$this->uploadFiles->attach($uploadFile);
}
/**
* Removes a UploadFile
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $uploadFileToRemove The UploadFile to be removed
* #return void
*/
public function removeUploadFile(\TYPO3\CMS\Extbase\Domain\Model\FileReference $uploadFileToRemove) {
$this->uploadFiles->detach($uploadFileToRemove);
}
/**
* Returns the uploadFiles
*
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $uploadFiles
*/
public function getUploadFiles() {
return $this->uploadFiles;
}
/**
* Sets the uploadFiles
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $uploadFiles
* #return void
*/
public function setUploadFiles(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $uploadFiles) {
$this->uploadFiles = $uploadFiles;
}
There're still more things to do, especially in TCA, but I don't know them in detail because I didn't use that yet. See Hemult Hummels Upload Example an this question for more detailed information.

Create and save a value object in CommandController

im trying to create and save a value object in my ImportCommandController.php, but only the entity will be saved.
Let me show some code:
// Create Entity "Fewo"
$fewo = new Fewo();
$fewo->setTitle('MyFewo');
...
// Create Value Object "Period"
$period = new Period();
$period->setTitle('MyTestTitle');
...
$fewo->addPeriod($period);
$this->fewoRepository->add($fewo);
$this->persistenceManager->persistAll();
Now the Fewo is in the database, but the period-table is still empty. I can't find my mistake...
UPDATE:
This is the Period Model:
<?php
namespace TYPO3\Fewo\Domain\Model;
class Period extends \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject {
/**
* Name der Saison
*
* #var \string
*/
protected $name;
/**
* Von
*
* #var \DateTime
*/
protected $begin;
/**
* Bis
*
* #var \DateTime
*/
protected $end;
/**
* rentalcharges
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\Fewo\Domain\Model\Rentalcharge>
*/
protected $rentalcharges;
/**
* __construct
*
* #return Period
*/
public function __construct() {
//Do not remove the next line: It would break the functionality
$this->initStorageObjects();
}
/**
* Initializes all ObjectStorage properties.
*
* #return void
*/
protected function initStorageObjects() {
/**
* Do not modify this method!
* It will be rewritten on each save in the extension builder
* You may modify the constructor of this class instead
*/
$this->rentalcharges = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* Returns the name
*
* #return \string $name
*/
public function getName() {
return $this->name;
}
/**
* Sets the name
*
* #param \string $name
* #return void
*/
public function setName($name) {
$this->name = $name;
}
/**
* Returns the begin
*
* #return \DateTime $begin
*/
public function getBegin() {
return $this->begin;
}
/**
* Sets the begin
*
* #param \DateTime $begin
* #return void
*/
public function setBegin($begin) {
$this->begin = $begin;
}
/**
* Returns the end
*
* #return \DateTime $end
*/
public function getEnd() {
return $this->end;
}
/**
* Sets the end
*
* #param \DateTime $end
* #return void
*/
public function setEnd($end) {
$this->end = $end;
}
/**
* Adds a Rentalcharge
*
* #param \TYPO3\Fewo\Domain\Model\Rentalcharge $rentalcharge
* #return void
*/
public function addRentalcharge(\TYPO3\Fewo\Domain\Model\Rentalcharge $rentalcharge) {
$this->rentalcharges->attach($rentalcharge);
}
/**
* Removes a Rentalcharge
*
* #param \TYPO3\Fewo\Domain\Model\Rentalcharge $rentalchargeToRemove The Rentalcharge to be removed
* #return void
*/
public function removeRentalcharge(\TYPO3\Fewo\Domain\Model\Rentalcharge $rentalchargeToRemove) {
$this->rentalcharges->detach($rentalchargeToRemove);
}
/**
* Returns the rentalcharges
*
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\Fewo\Domain\Model\Rentalcharge> $rentalcharges
*/
public function getRentalcharges() {
return $this->rentalcharges;
}
/**
* Sets the rentalcharges
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\Fewo\Domain\Model\Rentalcharge> $rentalcharges
* #return void
*/
public function setRentalcharges(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $rentalcharges) {
$this->rentalcharges = $rentalcharges;
}
}
UPDATE2:
Tried:
class Period extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {...}
and:
$period = $this->objectManager->get('TYPO3\Fewo\Domain\Model\Period');
with no effect :(
Is Period in FeWo of the right type?
It have to be something like this:
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\Fewo\Domain\Model\Fewo>