TYPO3 TCA select, NULL value in items array - typo3

I have made an extension in Typo3 4.5 with extbase and fluid. Now to insert some data i use the backend module 'list' that makes some forms with the TCA of the tables.
To make a select box optional, I insert an item before the foreign table like this:
'feuser' => array(
'exclude' => 0,
'label' => 'LLL:EXT:yes/Resources/Private/Language/locallang_db.xml:tx_yes_domain_model_schools.feuser',
'config' => array(
'type' => 'select',
'items' => array(
array('', NULL),
),
'foreign_table' => 'fe_users',
'maxitems' => 1,
),
),
Now, since i have a relation (with NULL alowed) in my DB, i have to insert a NULL value. But like this it doesn't work. I have also tried '', "" and 0. But those don't work either.
I would appreciate any help.

Try this:
'items' => array(
array('', -1))
The second parameter in the array is not the value for the db!

Related

Typo3 select filled with childs category from sys_category

I'm writing a TCA to define a form, and I need to fill the select with the childs categories from sys_category table.
'category' => [
'label' => 'LLL:EXT:hebo_ideas/Resources/Private/Language/locallang_db.xlf:hk_ideas_idea.category',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'foreign_table' => 'sys_category',
'foreign_table_where' => ' AND sys_category.sys_language_uid IN (-1, 0) ORDER BY sys_category.sorting ASC',
'MM' => 'sys_category_record_mm',
'size' => 10
],
],
I understand that I have to use foreign_table_where but I don't know what parameter from TYPO3 core database should I use to filter this categories by parent. Or may be my approach is wrong?
If you want to add categories to your table, you should use \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable(). Thats the easiest way. Please have a look at the documentation for details.

Extension, get value of TCA select

I created a new extension with the extension_builder and added a select-field:
'selectlist' => array(
'exclude' => 1,
'label' => 'LLL:EXT:my_test/Resources/Private/Language/locallang_db.xlf:tx_mytest_domain_model_test.selectlist',
'config' => array(
'type' => 'select',
'renderType' => 'selectSingle',
'items' => array(
array('LLL:EXT:my_test/Resources/Private/Language/locallang.xlf:tx_mytest_domain_model_test.selectlist.item1', 0),
array('LLL:EXT:my_test/Resources/Private/Language/locallang.xlf:tx_mytest_domain_model_test.selectlist.item2', 1),
),
'size' => 1,
'maxitems' => 1,
'eval' => ''
),
),
In the template I access this field with:
<td><f:link.action action="show" arguments="{test : test}"> {test.selectlist}</f:link.action></td>
The problem is that test.selectlist is only the key of the select-item. But what I need is the value (in my case the translated value from locallang.xlf).
I have not found any documentation about how to access the value in the template.
Is it possible? How can I do it?
In my case I can use a work around.
array('LLL:EXT:my_test/Resources/Private/Language/locallang.xlf:tx_mytest_domain_model_test.selectlist.item1', 1),
array('LLL:EXT:my_test/Resources/Private/Language/locallang.xlf:tx_mytest_domain_model_test.selectlist.item2', 2),
and
<f:translate key="tx_joyatest_domain_model_test.selectlist.item{test.selectlist}" />
this works, cause the translation key can be identified by the select-item-key.
Try biesior's answer for "TYPO3 TCA type select in FLUID?". That technique may be helpful to you, or give you an idea.

Backend TCA: possible to make a field nullable?

I need a backend field where users can enter a time (ie "23:13:46", hours, minutes, seconds). But it should also be possible to not enter a time at all (which should of course be different from 00:00:00). Is it possible to make a field nullable?
What I have so far is this:
$GLOBALS['TCA']['tx_something_domain_model_delivery'] = array(
'columns' => array(
'deadline' => array(
'exclude' => 1,
'label' => 'Deadline',
'config' => array(
'dbType' => 'time',
'type' => 'input',
),
),
...
),
);
But if I enter nothing in the Deadline field, it stores "00:00:00" to the database. The database looks like this:
CREATE TABLE IF NOT EXISTS `tx_something_domain_model_delivery` (
`uid` int(11) NOT NULL,
`pid` int(11) NOT NULL DEFAULT '0',
`deadline` time DEFAULT NULL,
...
);
so deadline is nullable, but I don't know how to achieve this.
BTW: I'm a newbie at typo3, so if you think the way I create the field is retarded or there is a much better way, I'd be thankful for any suggestions.
First: You are creating the field exactly in the intended way :-)
Second: You need to use the eval property in the configuration of the field. Add the setting null to it. Your config should then look like this:
$GLOBALS['TCA']['tx_something_domain_model_delivery'] = array(
'columns' => array(
'deadline' => array(
'exclude' => 1,
'label' => 'Deadline',
'config' => array(
'dbType' => 'time',
'type' => 'input',
'eval' => 'null',
),
),
...
),
);
There are more settings for the eval setting that might be of interest to you.

TYPO3 extbase & IRRE: add existing records with 'foreign_selector'

I "kickstarted" an extension with the extbase extension builder that contains some 1:1 and 1:n relations. It automatically set the field types to 'inline' and displayed a nice IRRE UI in the backend.
But by default, there is no way to select an existing record, just create new ones.
I found various explanations on how to achieve this with 'foreign_selector', but all of them very sketchy. The feature itself should be working, see https://forge.typo3.org/issues/43239
Can someone walk me through this or point to a working example in the TER? I could create a step-by-step tutorial from the example, once I get it to work.
PS The field's TCA config as generated by extension_builder:
'myfield' => array(
'exclude' => 1,
'label' => 'LLL:EXT:myextension/Resources/Private/Language/locallang_db.xlf:tx_myextension_domain_model_myitem.myfield',
'config' => array(
'type' => 'inline',
'foreign_table' => 'tx_myextension_domain_model_myfield',
'foreign_field' => 'myitem',
'maxitems' => 9999,
'appearance' => array(
'collapseAll' => 0,
'levelLinksPosition' => 'top',
'showSynchronizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showAllLocalizationLink' => 1
),
),
),
The main problem is that IRRE relations of type 1:n work like this: A child record holds the uid of its parent. So your table tx_myext_domain_model_city holds the UID of your (imaginary) tx_myext_domain_model_address.
Therefore with the default configuration you will not be able to select a city multiple times as it can only have exactly one parent.
So you will need to use a relation table for this field. This table needs to contain a uid field for both the address (uid_address) and the city (uid_city):
CREATE TABLE tx_irreforeignselectordemo_address_city_mm (
uid int(11) NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL,
uid_address int(11) unsigned DEFAULT '0' NOT NULL,
uid_city int(11) unsigned DEFAULT '0' NOT NULL,
sorting int(11) unsigned DEFAULT '0' NOT NULL,
PRIMARY KEY (uid),
KEY parent (pid)
);
And it needs to have a TCA configuration for these fields (while the table itself can be hidden):
return array(
'ctrl' => array(
'title' => 'Relation table',
'hideTable' => TRUE,
'sortby' => 'sorting',
),
'columns' => array(
'uid_address' => Array(
'label' => 'Address',
'config' => Array(
'type' => 'select',
'foreign_table' => 'tx_irreforeignselectordemo_domain_model_address',
'size' => 1,
'minitems' => 0,
'maxitems' => 1,
),
),
'uid_city' => Array(
'label' => 'City',
'config' => Array(
'type' => 'select',
'foreign_table' => 'tx_irreforeignselectordemo_domain_model_city',
'foreign_table_where' => ' AND sys_language_uid IN (0,-1)',
'size' => 1,
'minitems' => 0,
'maxitems' => 1,
),
),
),
'types' => array(
'0' => array('showitem' => 'uid_address,uid_city')
),
'palettes' => array()
);
You can then configure the TCA of your address to make it an IRRE field:
'type' => 'inline',
'foreign_table' => 'tx_yourext_address_city_mm',
'foreign_field' => 'uid_address',
'foreign_label' => 'uid_city',
'foreign_selector' => 'uid_city',
'foreign_unique' => 'uid_city',
'foreign_sortby' => 'sorting',
Note that foreign_unique tells TYPO3 that a city can only selected once.
And you need to define the relation from the other side (from your city TCA):
'addresses' => array(
'exclude' => 1,
'label' => 'Addresses',
'config' => array(
'type' => 'inline',
'foreign_table' => 'tx_irreforeignselectordemo_address_city_mm',
'foreign_field' => 'uid_city',
'foreign_label' => 'uid_address',
),
),
Once your configuration is complete, you will be able to use this in the Backend.
Since this is a non-standard MM relation, Extbase will not be able to deal with it by default. But we can compare this to the sys_file_reference table that was introduced in TYPO3 6. So we build an Extbase model for the CityRelation with the properties "address" and "city" and map this model to our mm table:
config.tx_extbase.persistence.classes {
Visol\Irreforeignselectordemo\Domain\Model\CityRelation {
mapping {
tableName = tx_irreforeignselectordemo_address_city_mm
columns {
uid_address.mapOnProperty = address
uid_city.mapOnProperty = city
}
}
}
}
Now in our address model, we define the city (or cities - of you allow more than one choice) as ObjectStorage of type CityRelation:
/**
* Cities
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Visol\Irreforeignselectordemo\Domain\Model\CityRelation>
*/
protected $cities = NULL;
We now have a property "cities" that contains the references to all selected cities. You can iterate through them and use them:
<f:for each="{address.cities}" as="cityRelation">
<li>{cityRelation.city.name}</li>
</f:for>
Since I couldn't find an all-in-one demo for this and was interested in the topic, I created a demo extension that does what I just described - based on the Core and two extensions that deal with the topic: https://github.com/lorenzulrich/irreforeignselectordemo
The solution is an m:n approach anyway (because 1:n wouldn't work for the reasons stated above) so I decided to use "cities" instead of "city". While this might not make sense for selecting a city (as suggested by your post), it might make sense for other opportunities. Feel free to replace "cities" by "city" and set maxItems in the inline configuration to one - then you have kind of an 1:n.

Why doesn't eval null not work in the TCA

I have a field defined as such:
max_items int(11) NULL
If you leave this field empty in the backend I want it to store NULL.
For this I use this configuration in the TCA, which doesn't work:
'max_items' => array(
'exclude' => 0,
'label' => '...',
'config' => array(
'type' => 'input',
'eval' => 'null',
),
),
Edit:
Instead of storing the expected value NULL, it stores 0.
I tried max_items int(11) DEFAULT NULL, but that didn't work aswell.
Edit2:
Thanks freshp!
I ended up writing my own eval function:
<?php
class tx_myextension_evalfunc {
function evaluateFieldValue($sValue, $aIsIn, &$bSet)
{
return ($sValue === '') ? null : $sValue;
}
}
?>
Using this configuration:
'max_items' => array(
'exclude' => 0,
'label' => '...',
'config' => array(
'type' => 'input',
'eval' => 'tx_myextension_evalfunc',
),
),
There was a bug in older TYPO3 versions:
The current implementation in the TYPO3 backend does not allow to store NULL values, only empty strings or zero as number are allowed.
This bug is fixed in TYPO3 6.0 and higher. In the TCA config there is a new eval option "null":
'config' = array(
'type' => 'input',
'eval' => 'null',
...
);
If this option is enabled, there is a checkbox at the right side of the input. If it's deactivated, the NULL value is saved to the database, if it is activated, an integer value can be entered.
If you want to have the checkbox per default deactivated to store Null as default, add 'default' => null to it:
'config' = array(
'type' => 'input',
'eval' => 'null',
'default' => null,
);
Tested in TYPO3 8 LTS. Then it looks like this:
Original answer:
There are two interesting links for you:
the core-bug for your question - http://forge.typo3.org/issues/41773
one way to fix it with a own eval-function - http://www.blogix.net/2008/05/10/eigene-eval-funktion-in-typo3-tca/