How to configure extbase to fetch inline / IRRE relations to tt_content? - typo3

I've built a extension where I can assign content elements (tt_content) inline (IRRE) to my entries in the TYPO3 Backend.
But I can't figure out how I can resolve the relations so that I can display the assigned content elements in the frontend.
I've created the extension with the 'Extension Builder' in TYPO3 9.5.5.
I created a Model Object 'Content' and selected 'Map to existing table' in the 'Domain object settings' and choosed 'tt_content'.
In my model 'ProductTab' I configured a 1:n relation of type 'Inline (IRRE)' with the name 'content' to my 'Content' model.
If I add content elements to my model entries in the Backend, it works like expected. The relational fields in the DB are mapped correctly. With the 'Extbase Variable Dump' I can see that all my relations are passed to the front end plugin, but my 'content' relation is an empty 'ObjectStorage'.
What am I missing so that the extbase persistence fetches my content relations?
ext_tables.sql excerpts
CREATE TABLE tx_myext_domain_model_producttab (
product int(11) unsigned DEFAULT '0' NOT NULL,
title varchar(255) DEFAULT '' NOT NULL,
content int(11) unsigned DEFAULT '0' NOT NULL,
);
CREATE TABLE tt_content (
producttab int(11) unsigned DEFAULT '0' NOT NULL,
);
TCA excerpts
'content' => [
'exclude' => false,
'label' => 'producttab.content',
'config' => [
'type' => 'inline',
'foreign_table' => 'tt_content',
'foreign_field' => 'producttab',
'maxitems' => 9999,
'appearance' => [
'collapseAll' => 0,
'levelLinksPosition' => 'top',
'showSynchronizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showAllLocalizationLink' => 1
],
],
],
Since I can add and edit the content elements in the Backend, I think the DB and TCA relation is fine.
But something is still missing, so that the relation is fetched and provided to the FE template so that I can display the assigned content elements with a ViewHelper.
ProductTab.php excerpts
class ProductTab extends \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject
{
protected $content = null;
protected function initStorageObjects()
{
$this->content = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
public function addContent(\MyExt\Domain\Model\Content $content)
{
$this->content->attach($content);
}
public function removeContent(\MyExt\Domain\Model\Content $contentToRemove)
{
$this->content->detach($contentToRemove);
}
public function getContent()
{
return $this->content;
}
public function setContent(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $content)
{
$this->content = $content;
}
}
Extbase Variable Dump
Screenshot of debug output
On the screenshot you can see the fetched products (one item in this case) and the producttabs (also 1 item). There is one content element assigned, but the property content of the ProductTab with uid=1 is empty.
Update
Since I'm still not able to solve this issue, I've created a minimalistic extension with the Extension Builder to demonstrate the issue: https://github.com/apiening/demo_irrecontent
The extension is the most simple one I could create with one model holding only one property and the relation to tt_content. It has a plugin list which also shows the debug output.
I've put some more details in the README.mdof the GitHub project.

Related

how to extend the metadata in TYPO3 10.4.13

I am trying to add a description field under the page properties/metadata which was still present in the TYPO3 8.7.32 version.
I have also already tried in the setup with the following code:
page.meta.description.field = description
#page.meta.description.ifEmpty =
currently it looks like this
and should look like this
If your goal is to add a SEO description field, this field is already available in the SEO tab.
Nevertheless, if you want to add a new field in metadata, you have to :
Add the new field in : your_ext/ext_tables.sql
CREATE TABLE pages (
new_field varchar(255) DEFAULT '' NOT NULL
);
Override the TCA : create or update the file your_ext/Configuration/TCA/Overrides/pages.php
<?php
defined('TYPO3_MODE') or die();
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
call_user_func(static function () {
// Define new TCA field
$additionalFields = [
'new_field' => [
'exclude' => false,
'l10n_mode' => 'prefixLangTitle',
'label' => 'LLL:EXT:your_ext/Resources/Private/Language/locallang_db.xlf:pages.your_ext',
'description' => 'LLL:EXT:your_ext/Resources/Private/Language/locallang_db.xlf:pages.your_ext.description',
'config' => [
'type' => 'input',
'size' => 60,
'max' => 255
]
]
];
// Add the new TCA columns
ExtensionManagementUtility::addTCAcolumns('pages', $additionalFields);
// Add the field to the palette
ExtensionManagementUtility::addFieldsToPalette('pages', 'metatags', 'new_field', 'after:keywords');
});
Then you have to update the DB with BE module Maintenance > Analyze Database Structure.
Flush all cache - because TCA are in cache.
And your new field will now be available.

get mergedProperties of sys_file_reference in tx_news

I am using TYPO3 9.5.26 with tx_news 8.5.2. I have extended sys_file_reference with my own field. I can access this fields value in my fluid templates like so:
{file.properties.tx_myext_frame}
This is tested and works fine. However in the news module this stays empty
{mediaElement.properties.tx_myext_frame}
How can I use the orginalFile properties in tx_news?
Thanks
Code I use to add the field:
typo3conf\ext\myext\ext_tables.sql
CREATE TABLE sys_file_reference (
tx_myext_frame tinyint(4) DEFAULT '0' NOT NULL,
);
typo3conf\ext\myext\Configuration\TCA\Overrides\sys_file_reference.php
// Add some fields to sys_file_reference table
$temporaryColumns = [
'tx_myext_frame' => [
'exclude' => 0,
'label' => 'LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:tx_myext_frame',
'config' => [
'type' => 'check',
'default' => '0',
]
],
];
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addFieldsToPalette(
'sys_file_reference',
'imageoverlayPalette',
'--linebreak--,tx_myext_invert,tx_myext_frame',
'after:description'
);
found the answer myself just now - so for anyone trying this use
{mediaElement.originalResource.properties.tx_myext_frame}

TYPO3 TCA make the 'default' value dynamic

The title is rather self explanatory, but what i would like to have is a dynamic default value.
The idea behind it is to get the biggest number from a column in the database and then add one to the result. This result should be saved as the default value.
Lets take for example this code:
$GLOBALS['TCA'][$modelName]['columns']['autojobnumber'] = array(
'exclude' => true,
'label' => 'LLL:EXT:path/To/The/LLL:tx_extension_domain_model_job_autojobnumber',
'config' => [
'type' => 'input',
'size' => 10,
'eval' => 'trim,int',
'readOnly' =>1,
'default' => $result,
]
);
The SQL looks like this:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_extension_domain_model_job');
$getBiggestNumber = $queryBuilder
->select('autojobnumber')
->from('tx_extension_domain_model_job')
->groupBy('autojobnumber')
->orderBy('autojobnumber', 'DESC')
->setMaxResults(1)
->execute()
->fetchColumn(0);
$result = $getBiggestNumber + 1;
So how can i do that "clean"?
I thought about processCmdmap_preProcess but i dont know how to pass the value to the coorisponding TCA field. Plus i do not get any results on my backend when i use the DebuggerUtility like i get them when i use processDatamap_afterAllOperations after saving the Object.
Can someone point me to the right direction?
I don't think it is supported to create a dynamic default value, see default property of input field.
What you can do however, is to create your own type (use this instead of type="input"). You can use the "user" type. (It might also be possible to create your own renderType for type="input", I never did this, but created custom renderTypes for type= "select").
You can look at the code of InputTextElement, extend that or create your own from scratch.
core code: InputTextElement
documentation for user type
more examples in FormEngine documentation
Example
(slightly modified, from documentation)
ext_localconf.php:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][<current timestamp>] = [
'nodeName' => 'customInputField',
'priority' => 40,
'class' => \T3docs\Examples\Form\Element\CustomInputElement::class,
];
CustomInputElement
<?php
declare(strict_types = 1);
namespace Myvendor\MyExtension\Backend\FormEngine\Element\CustomInputElement;
use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
// extend from AbstractFormElement
// alternatively, extend from existing Type and extend it.
class CustomInputElement extends AbstractFormElement
{
public function render():array
{
$resultArray = $this->initializeResultArray();
// add some HTML
$resultArray['html'] = 'something ...';
// ... see docs + core for more info what you can set here!
return $resultArray;
}
}

How to realize inheritance in Typo3 6.2 Extension?

My goal is being able to:
Create Expertise Entries in the backend (already accomplished)
Create SubExpertise Entries in the backend
(same props as Expertise but
they belong to one or many Expertise)
Create AdditionalInfoTitles Entries in the backend
(they can belong to one or many Expertise OR SubExpertise)
I want to be able to choose Objects from all Expertise AND SubExpertise when creating a new entry
Right now I can only choose between all Expertise-Entries:
That's why I thought about inheritance since then SubExpertise would be of the same type as Expertise and therefore automatically displayed in the Expertise list in a AdditionalInfoTitles entry. But that's just my theory and I'm kinda stuck in reality with typo3 TCA and other knowledge that I'm lacking...
In my extension builder I made following (don't mind the subExpertises property)
Then I added expertise to the Overrides folder, because I'm trying to extend it with subexpertise:
<?php
if (!defined('TYPO3_MODE')) {
die ('Access denied.');
}
$temporaryColumns = array (
'expertise' => array(
'exclude' => 1,
'label' => 'LLL:EXT:appoints/Resources/Private/Language/locallang_db.xlf:tx_appoints_domain_model_subexpertise.expertise',
'config' => array(
'type' => 'select',
'foreign_table' => 'tx_appoints_domain_model_subexpertise',
'MM' => 'tx_appoints_subexpertise_expertise_mm',
'size' => 10,
'autoSizeMax' => 30,
'maxitems' => 9999,
'multiple' => 0,
'wizards' => array(
'_PADDING' => 1,
'_VERTICAL' => 1,
'edit' => array(
'module' => array(
'name' => 'wizard_edit',
),
'type' => 'popup',
'title' => 'Edit',
'icon' => 'edit2.gif',
'popup_onlyOpenIfSelected' => 1,
'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1',
),
'add' => Array(
'module' => array(
'name' => 'wizard_add',
),
'type' => 'script',
'title' => 'Create new',
'icon' => 'add.gif',
'params' => array(
'table' => 'tx_appoints_domain_model_expertise',
'pid' => '###CURRENT_PID###',
'setValue' => 'prepend'
),
),
),
),
),
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
'tx_appoints_domain_model_expertise',
$temporaryColumns
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'tx_appoints_domain_model_expertise',
'expertise'
);
But I don't think I'm going into the right direction with this -
Because I think this way I'm not gonna be able to add a SubExpertise in the backend separately from an Expertise - I already have the same problem with my Objects that extend fe_user because when creating them I usually have to go through a new User and then set the extension type - but this way I don't have separate listings of the different entities that extend fe_user.
I would get rid of the separation between Expertise and SubExpertise for the most part. According to your description a SubExpertise cannot have another SubExpertise as its parent, so you can adapt the select field that it only lists Expertises which have an empty parent field.
By removing the difference the problem of selecting (Sub)Expertise's in AdditionalInfoTitles is removed; it's just one and the same type of objects.
If you need to differentiate in the presentation in the BE forms there are plenty of options to adjust the labels of the listed items, use a function of your own to build the list or even a custom form element.
In Extbase you can simply write a few functions in your repository to fetch Expertise's, SubExpertise's or both.
If the entity SubExpertise does not have a meaning in your domain model, Jigal's answer is perfect for your scenario. If it does have a meaning, you can achieve that using single table inheritance in Extbase.
class Expertise extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
// all common properties
}
class SubExpertise extends Expertise
{
/**
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\[YourVendorName]\Appoints\Domain\Model\Expertise>
*/
protected $expertises;
public function __construct()
{
$this->expertises = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
public function getExpertises() {}
public function setExpertises($expertises) {}
}
Via TypoScript then you have to define mapping rules, since both Expertise and SubExpertise would be stored in the same table tx_appoints_domain_model_subexpertise.
You'll find more details on single table inheritance in the Extbase book.

Cakephp automatically filled form select for two word named belongTo model

What is right naming or what am I missing to get automagic run for two word named Model. Actual model belong to the two words named model.
Exact example:
Tour belongs to Accommodation type.
in database there is table tours and table accommodation_types
foreign key from tours is tours.accommodation_type_id
Snapshots of code below.
ToursController.php
public function add() {
//...
$accommodation_types = $this->Tour->AccommodationType->find('list');
//...
$this->set(compact('accommodation_types', ...));
}
Tour.php
//...
public $belongsTo = array(
//...
'AccommodationType' => array(
'className' => 'AccommodationType',
'foreignKey' => 'accommodation_type_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
//...
);
Tours/add.ctp (inside a form)
echo $this->Form->input('accommodation_type_id', array('label' => 'Accommodation type'));
As per convention the view vars names should be camelBacked. So rename the view var from $accommodation_types to $accommodationTypes. If you don't follow convention you have to explicitly specify the options var to use like this:
echo $this->Form->input('accommodation_type_id', array('options' => $accommodation_types, 'label' => 'Accommodation type'));