TYPO3 Extbase extension: Backend FAL Upload fails - typo3

I have set up an extension with the current extension_builder in TYPO3 6.2.11.
FAL File upload in the backend is not working.
extension_builder says that file upload isn't implemented at all in extbase, but as far as I understood (cf https://github.com/helhum/upload_example), this is regarding FE upload. Correct?
I only need completely regular BE file upload - select via "Create new relation" or "Select & upload files".
The direct upload fails with "Upload failed! A file with "*" extension is expected!" (or whatever extensions I specify in TCA).
The reference creation works, but the reference is lost after saving.
This screenshot shows the two tries before saving.
And after saving, empty again:
How do I make this work? Do I have to add extra code to the repo for saving the relation? Or might there be a basic setting missing?
For tt_content, FAL relations and upload work fine.
And: As a workaround, is it possible to use a regular "Pibase" 'type' => 'group','internal_type' => 'file' field? But how would getters and setters in the model look then? Just like a regular string?
TCA:
'apprenticeship_document' => array(
'exclude' => 1,
'label' => 'LLL:EXT:stellen/Resources/Private/Language/locallang_db.xlf:tx_stellen_domain_model_institution.apprenticeship_document',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'apprenticeshipDocument',
array('maxitems' => 1),
'*'
),
),
Model as created by extension_builder:
/**
* apprenticeshipDocument
*
* #var \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
protected $apprenticeshipDocument = NULL;
/**
* Returns the apprenticeshipDocument
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $apprenticeshipDocument
*/
public function getApprenticeshipDocument() {
return $this->apprenticeshipDocument;
}
/**
* Sets the apprenticeshipDocument
*
* #param \TYPO3\CMS\Extbase\Domain\Model\FileReference $apprenticeshipDocument
* #return void
*/
public function setApprenticeshipDocument(\TYPO3\CMS\Extbase\Domain\Model\FileReference $apprenticeshipDocument) {
$this->apprenticeshipDocument = $apprenticeshipDocument;
}
I have also tried to use \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> instead of \TYPO3\CMS\Extbase\Domain\Model\FileReference $apprenticeshipDocument, but that doesn't make a difference either.

Your TCA definition has an error, the first argument of getFileFieldTCAConfig should be with lower underscore, not lowerCamelCase:
'apprenticeship_document' => array(
'exclude' => 1,
'label' => 'LLL:EXT:stellen/Resources/Private/Language/locallang_db.xlf:tx_stellen_domain_model_institution.apprenticeship_document',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'apprenticeship_document',
array('maxitems' => 1),
'pdf,doc,docx'
),
),
Apart from that, "*" is not a valid file extension. You need to define a comma-separated list of file extensions (e.g. 'doc,docx,pdf'). From reading the documentation, there is no wildcard for file extensions.
File upload in FE is not implemented in the Extension Builder, but perfectly possible with the solution provided by Helmut Hummel.

Related

After TYPO3 Update from 6.2 to 7.6 still errors in TCA?

I've made an update from TYPO3 CMS 6.2 to TYPO3 CMS 7.6.16. After a few problems with other extensions (tx_newsand third party ext.) and the changes in the TCA. Everything works fine after import live-dump ...
Upgrade wizard / Database compare
Update reference Index
Flush Cache and empty typo3temp
Deactivate and reactivate the Extensions with problems
Everything? Unfortunately, no. The extension doesn't work. I don't written the extension by myself. If I try to add a new data record in backend with this ext., I'll get this error:
An item in field form of table tx_blah_domain_model_job is not an array as expected
But the database comprare is finished. All tables are correct?!
Where's the problem? I know it's hard to analyze this without source code. There's a database field wrong, but why? It's the same database like before?
Where's the fault .. ext_tables.php or still sth. in TCA is wrong? I really need a tip .. its frustrating ..
EDIT: sys_log entry
Core: Exception handler (WEB): Uncaught TYPO3 Exception: #1439288036: An item in field form of table tx_blah_domain_model_job is not an array as expected | UnexpectedValueException thrown in file /typo3_src/typo3_src-7.6.16/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php in line 1264.
EDIT 2: I think, there must be sth. in typo3conf/ext/blah/Configuration/TCA/tx_blah_domain_model_job.php
see TCA source code
and that's in line 1264
/**
* Sanitize incoming item array
*
* Used by TcaSelectItems and TcaSelectTreeItems data providers
*
* #param mixed $itemArray
* #param string $tableName
* #param string $fieldName
* #throws \UnexpectedValueException
* #return array
*/
public function sanitizeItemArray($itemArray, $tableName, $fieldName)
{
if (!is_array($itemArray)) {
$itemArray = [];
}
foreach ($itemArray as $item) {
if (!is_array($item)) {
throw new \UnexpectedValueException(
'An item in field ' . $fieldName . ' of table ' . $tableName . ' is not an array as expected',
1439288036
);
}
}
return $itemArray;
}
aTry to use this in the TCA tx_imappointments_domain_model_job.php
'form' => array(
'exclude' => 1,
'label' => 'LLL:EXT:im_appointments/Resources/Private/Language/locallang_db.xlf:tx_imappointments_domain_model_job.form',
'config' => array(
'type' => 'select',
'renderType' => 'selectSingle',
'items' => array(array('', 0)),
'foreign_table' => 'pages',
'foreign_table_where' => ' AND pages.pid = 293',
'minitems' => 0,
'maxitems' => 1,
),
),
'items' in 'form' has to be a array how your error message said:
https://docs.typo3.org/typo3cms/TCAReference/ColumnsConfig/Type/Select.html#items

TYPO3 Extbase FAL - How to update file metadata (sys_file) from frontend controller

I have a frontend extensions where logged in users shall add/edit sys_file records.
I try to update the file metadata like this (simplified):
$uid = (int)$this->request->getArgument('file');
$resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
$file = $resourceFactory->getFileObject($uid);
$file->updateProperties(array(
'title' => $this->request->getArgument('title'),
'keywords' => $this->request->getArgument('keywords'),
'description' => $this->request->getArgument('description'),
'copyright' => $this->request->getArgument('copyright'),
'modification_date' => time()
));
$this->fileRepository->update($file);
$this->addFlashMessage(LocalizationUtility::translate('messages.success.file'));
$this->persistenceManager->persistAll();
persistenceManager and fileRepository are injected via:
/**
* fileRepository
*
* #var \TYPO3\CMS\Core\Resource\FileRepository
* #inject
*/
protected $fileRepository = NULL;
/**
* #var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
* #inject
*/
protected $persistenceManager;
and generally I get no error, the flash message displays, the fluid form even shows the new data inside the form, but it is actually not saved.
Any way to debug/solve this? It seems the $fileRepository doesn't actually perform the "update" statement, is there some kind of permission check that I need to circumvent in the frontend?
Kind of an old thread but there is a solution wich works in 7.6 and 8.x, as the Repository in 7.6 uses the $GLOBAL['TYPO3_DB'] and in 8.x it's already migrated to Doctrine, so there is no need to rewrite your code.
Maybe it saves someone some time.
Use the TYPO3\CMS\Core\Resource\Index\MetaDataRepository repository and just load it via objectManager.
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
$metadata = $objectManager->get('TYPO3\CMS\Core\Resource\Index\MetaDataRepository');
then you can populate the metadata like this
$metadata->update($fileUid, $metadataInput);
The update method requires two params, the file uid and an array with db field names and values
As far as I know you have to update them by yourself with an update query:
$GLOBALS['TYPO3_DB']->->exec_UPDATEquery('sys_file_metadata', 'file = ' . $fileUid, array('modification_date' => time()));

TYPO3 Extbase: InversedBy 1:1 Relation

Is it possible to inverse a 1:1 Relation without adding a second field into DB in Extbase?
Example:
The extension has Contact-Persons which can have an fe_user.
The Contact-Person-Domain-Model is the owning site of the relation.
Now you can use $contactPerson->getFrontendUser();
Is there any way to add an inversed property to FrontendUser without adding it to the DB?
So you can use $frontendUser->getContactPerson(),
or even more important: $frontendUserRepository->findByContactPerson();
I tried adding the property to the FrontendUser-Model:
/**
* FrontendUser
*/
class FrontendUser extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
{
/**
* #var \Vendor\ExtKey\Domain\Model\ContactPerson
*/
protected $contactPerson = null;
}
And overriding the fe_users TCA:
$GLOBALS['TCA']['fe_users']['columns']['contact_person'] = array(
'exclude' => 1,
'label' => 'LLL:EXT:ExtKey/Resources/Private/Language/locallang_db.xlf:tx_ExtKey_domain_model_contactperson',
'config' => array(
'type' => 'inline',
'foreign_table' => 'tx_ExtKey_domain_model_contactperson',
'foreign_field' => 'frontend_user',
'minitems' => 0,
'maxitems' => 1,
),
);
But when I call:
/**
* The repository for Customers
*/
class FrontendUserRepository extends \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository
{
/**
* #param \Vendor\ExtKey\Domain\Model\ContactPerson $contactPerson
* #param boolean $ignoreEnableFields
* #param boolean $respectStoragePage
* #return object
*/
public function findByContactPerson(ContactPerson $contactPerson, $ignoreEnableFields = false, $respectStoragePage = true){
$query = $this->createQuery();
$query->getQuerySettings()
->setIgnoreEnableFields($ignoreEnableFields)
->setRespectStoragePage($respectStoragePage);
$query->matching($query->equals('contactPerson', $contactPerson));
return $query->execute()->getFirst();
}
}
It creates following SQL-Error:
Unknown column 'fe_users.contact_person' in 'where clause'
Computed bidirectional 1:1 relations are not supported in TYPO3, only m:n relations support that with an extra definition in TCA - which also requires an additional field on the opposite site of the relation.
Concerning you scenario, you have to create the additional property and database field in an extended FrontendUser domain model on your own.
There is a possibility like described here: http://www.oliver-weiss.com/blog/einzelansicht/article/relationen-in-typo3-teil-1-11-relation/News/detail/ . Additionally, instead of having an "inline" relation on both sides, this also works if only one side is "inline" and the other side is "select". But the single (inverted) "inline" relation needs to have "foreign_field" defined. Following this, the "foreign" uid is only stored on one side of the relation.

Repository/controller: How can I force TYPO3 to load the field "sorting"?

In a controller/template I'd like to have access to the field sorting of an entity.
I've tried to access it like:
$category->getSorting();
But it fails, as the method does not exist. When I dump the entity, all those meta fields, like hidden, starttime etc. aren't listed at all.
How can I tell TYPO3 to load those fields along with the other fields of the entitiy?
Since you are in Extbase context, you have to add the property to your model or (if you use the model of another extension) extend it and add the property. In both cases a getter and a setter method is needed if you want to access and edit the properties value:
/**
* #var integer
*/
protected $sorting;
public function setSorting($sorting) {
$this->sorting = $sorting;
}
public function getSorting() {
return $this->sorting;
}
Make sure you have that field configured in the TCA as well:
...
'columns' => array(
'sorting' => array(
'label' => 'sorting',
'config' => array(
'type' => 'passthrough'
)
),
...
After this you should be able to access the sorting property.

Extbase ObjectStorage returns a hashcode. But why?

I was just extending an existing Typo3 4.7 Extension with two own Model classes.
It runs quite well, Backendforms look like expected BUT when I try to access some SubObjects of my Model Classes in the templates via Object Accessor {class.subclass.attribute} I am not able to access the attribute. The problem that showed me, is that the Object for the Attribute "mainColor" for example in the Object Storage is a HashCode, which contains the Actual Object I want to access ( the object following the hashcode is the correct related object from the database ).
Does anyone of you have an Idea where the problem might be ?
If any more Code Snippets are needed, I will deliver them. But since I really don't know where the problem comes from, I prefer to not deliver a wall of Code.
Domain/Model/Cluster.php
/**
* Main Color of Cluster
* #var Tx_Extbase_Persistence_ObjectStorage<Tx_Alp_Domain_Model_ColorCombination> $mainColor
*/
protected $mainColor;
/**
* Subcolors of Cluster
* #var Tx_Extbase_Persistence_ObjectStorage<Tx_Alp_Domain_Model_ColorCombination> $subColors
*/
protected $subColors;
/**
* Constructor
* #return void
*/
public function __construct() {
$this->initStorageObjects();
}
/**
* Initializes all Tx_Extbase_Persistence_ObjectStorage properties.
* #return void
*/
protected function initStorageObjects() {
$this->subColors = new Tx_Extbase_Persistence_ObjectStorage();
$this->mainColor = new Tx_Extbase_Persistence_ObjectStorage();
}
TCA/Cluster.php
'sub_colors' => array(
'exclude' => 1,
'label' => 'Sub-Colors',
'config' => array(
// edited
'type' => 'inline',
'internal_type' => 'db',
'allowed' => 'tx_alp_domain_model_colorcombination',
'foreign_table' => 'tx_alp_domain_model_colorcombination',
'MM' => 'tx_alp_cluster_subcolorcombination_mm',
'MM_opposite_field' => 'parent_cluster',
'size' => 6,
'autoSizeMax' => 30,
'maxitems' => 9999,
'multiple' => 0,
'selectedListStyle' => 'width:250px;',
'wizards' => array(
'_PADDING' => 5,
'_VERTICAL' => 1,
'suggest' => array(
'type' => 'suggest',
),
),
),
),
Fluid Debug Output can be found here:
http://i60.tinypic.com/28kluub.jpg
Thanks for any help :(
And sorry for my bad English and this is my first question here, hope I did it right ;)
Unless you have a 1:1 relation from a model to a sub model, you cannot access the sub model because the sub model is an ObjectStorage.
Example:
Domain/Model/Cluster.php
/**
* Main Color of Cluster
* #var Tx_Alp_Domain_Model_ColorCombination $mainColor
*/
protected $mainColor;
This means that the Cluster model has exacly one main color (mind the annotation), this is a 1:1 relation.
Therefore using {cluster.mainColor.property} will work.
What you are doing is:
Domain/Model/Cluster.php
/**
* Main Color of Cluster
* #var Tx_Extbase_Persistence_ObjectStorage<Tx_Alp_Domain_Model_ColorCombination> $mainColor
*/
protected $mainColor;
This means that every Cluster can have multiple main colors, this is a 1:n relation. Therefore you must iterate through the mainColors (and call the property $mainColors):
<f:for each="{cluster.mainColors}" as="mainColor">
{mainColor.property}
</f:for>