TYPO3 11 call stdWrap from Extbase - typo3

How do you call the ContentObjectRenderer method stdWrap from Extbase?
The setup from a pi_base plugin is:
plugin.tx_myextension {
standard = TEXT
standard.value = Sorry, no data could be fetched!
}
In TYPO3 extensions without Extbase you have the $conf array with the keys
'standard' =>
'TEXT' (string)
and the key
'standard.' =>
'value' (array) =>
'Sorry, no data could be fetched!'.
Then you call the method by:
$out =
$cObj->stdWrap(
$conf['standard'],
$conf['standard.']
);
This will render the desired text 'Sorry, no data could be fetched!' into $out.
But in Extbase you do not have the $conf array in this way. Exbase delivers the $this->settings to store the settings part of the setup.
plugin.tx_myextension {
settings {
standard = TEXT
standard.value = Sorry, no data could be fetched!
}
}
The standard setup is internally stored by Extbase as a 2-dimensional array with this data:
'standard'
=> 'value' (Array)
=> 'Sorry, no data could be fetched!'
and
'standard'
=> '_typoScriptNodeValue' (Array)
=> 'TEXT'
I have tried it this way ($conf = $this->settings):
$out =
$cObj->stdWrap(
'',
$conf['standard']
);
And I have tried this:
$out =
$cObj->stdWrap(
$conf['standard']['_typoScriptNodeValue'],
$conf['standard']
);
But the result is an empty string only.
What is the recommended way to accomplish the stdWrap rendering with Extbase?

Basically $cObj->stdWrap only supports stdWrap instructions - however, you were using a cObject instruction (with TEXT).
Let's assume your settings look like this in TypoScript:
plugin.tx_myextension {
settings {
standard {
# cObject is a stdWrap function
# (that was the missing piece)
cObject = TEXT
cObject.value = Sorry, no data could be fetched!
}
}
}
Inside an Extbase controller $this->settings holds all data of the TypoScript path plugin.tx_myextension.settings as shown in the example before - and, the structure has been converted to be a "plain array".
Thus, inside a controller action things would look like this:
public function myAction()
{
// consider using dependency-injection instead
$typoScriptService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\TypoScript\TypoScriptService::class);
// converting "plain array" back to TypoScript array
$typoScriptArray = $typoScriptService->convertPlainArrayToTypoScriptArray($this->settings['standard']);
// invoking stdWrap instruction
$cObj = $this->configurationManager->getContentObject();
$out = $cObj->stdWrap('', $typoScriptArray);
// ...
}
Additional considerations:
in Extbase, plugin settings from TypoScript and potential FlexForm settings for a specific plugin are merged
→ make sure, to keep scopes separated before "executing" it as instruction
→ otherwise editors might be able to trigger stdWrap functions via FlexForm
→ that would be an "injection" and a security vulnerability
e.g. use plugin.tx_myextension.instructions dedicated to be used in e.g. stdWrap, instead of putting everything to plugin.tx_myextension.settings
in general consider moving view-related aspects to a corresponding view or Fluid template, e.g using f:cObject view helper there

Maybe a look into the News extension can help. IMO it's a proper, flexible way without much overhead.
// Use stdWrap for given defined settings
if (isset($originalSettings['useStdWrap']) && !empty($originalSettings['useStdWrap'])) {
$typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
$typoScriptArray = $typoScriptService->convertPlainArrayToTypoScriptArray($originalSettings);
$stdWrapProperties = GeneralUtility::trimExplode(',', $originalSettings['useStdWrap'], true);
foreach ($stdWrapProperties as $key) {
if (is_array($typoScriptArray[$key . '.'])) {
$originalSettings[$key] = $this->configurationManager->getContentObject()->stdWrap(
$typoScriptArray[$key],
$typoScriptArray[$key . '.']
);
}
}
}
// start override
if (isset($tsSettings['settings']['overrideFlexformSettingsIfEmpty'])) {
$typoScriptUtility = GeneralUtility::makeInstance(TypoScript::class);
$originalSettings = $typoScriptUtility->override($originalSettings, $tsSettings);
}
// ...
$this->settings = $originalSettings;
snippet taken from https://github.com/georgringer/news/blob/main/Classes/Controller/NewsController.php#L658-L688

Related

Typo3 Typoscript additionalHeaders header location using variable

I try to redirect a link which is coming, but before part of the link should be replaced.
tmp.getSlug = TEXT
tmp.getSlug.data = getIndpEnv : TYPO3_REQUEST_URL
tmp.getSlug.replacement {
10 {
search = myLinkPart
replace = myNewLinkPart
}
}
config.additionalHeaders.10 {
header = Location: {tmp.getSlug}
}
So from: www.myUrl.de/test/myLinkPart/test2/
To: www.myUrl.de/test/myNewLinkPart/test2/
It must be inside Typoscript because of other conditions.
Does anybody has an idea?
you are mixing different objects in a non functional way.
First you define tmp.getSlug as a typoscript object. Then you try to use it as a data variable.
Additional everything beyond tmp. is not available at rendering time. (it just is available when the typoscript is scanned.)
If you want to use the evaluation of tmp.getSlug you need to assign it to a permanent object and then store it in a register so you can access it afterwards.
Additional you need a flexible object to compose the Location header, which by default just contains a string.
Either a text object where you can use data (which must be evaluated and stored in a register before) or a COA to compose the static and the dynamic string.
This might be a solution:
tmp.getSlug = TEXT
tmp.getSlug.data = getIndpEnv : TYPO3_REQUEST_URL
tmp.getSlug.replacement {
10 {
search = myLinkPart
replace = myNewLinkPart
}
}
config.additionalHeaders.10 {
header.cObject = COA
header.cObject {
10 = TEXT
10.value = Location:
20 < tmp.getSlug
}
}

TYPO3: Special tt_contenttype. Modify content before output

Can I create a "special" type of tt_content, so text is beeing processed in some custom ways before outputtet?
In my case I would like to add ###MY_MARKER### somewhere in header and/or bodytext and have it replaced by the right words for the given page.
eg:
When visiting this page: mypage.com/?marker=test
Header in tt_content: "Welcome to ###MY_MARKER##, enjoy
Output in browser: "Welcome to TEST, enjoy"
I CAN do it by making a custom plugin. Question is more if I can reuse normal tt_contant for the same purpose
Yes, you can easily extend the tt_content by adding your own TCA configuration to the typo3conf/extTables.php file:
t3lib_div::loadTCA('tt_content');
$TCA['tt_content']['columns']['CType']['config']['items']['user_my_type'] = array(
0 => 'My custom content',
1 => 'user_my_type',
2 => 'i/tt_content.gif',
);
$TCA['tt_content']['ctrl']['typeicon_classes']['user_my_type'] = 'mimetypes-x-content-text';
$TCA['tt_content']['ctrl']['typeicons']['user_my_type'] = 'tt_content.gif';
/* In the following either copy, insert and modify configuration from some other
content elemenet (you can find it in the ADMIN TOOLS -> Configuration - $TCA)... */
$TCA['tt_content']['types']['user_my_type']['showitem'] = '';
/* ...or assign it some other configuration so that it's exactly the same
as some other content type and stays the same after some update of TYPO3: */
$TCA['tt_content']['types']['user_my_type']['showitem'] = $TCA['tt_content']['types']['text']['showitem'];
After that, just set in your Typoscript template how the element is supposed to be rendered:
tt_content.user_my_type = COA
tt_content.user_my_type {
10 = TEMPLATE
10 {
template = TEXT
template.field = header
marks {
MY_MARKER = TEXT
MY_MARKER.value = TEST
}
}
20 = TEMPLATE
20 {
template = TEXT
template {
field = bodytext
required = 1
parseFunc = < lib.parseFunc_RTE
}
marks < tt_content.user_my_type.10.marks
}
}
NOTES
The Typoscript rendering is just a simplified example. You might want to add other standard configuration like in other elements, e.g. the one that adds edit icons for frontend display.
The marker in my example can be populated by the value of a GET paramater in the URL as you wanted but this would have nasty security implications. You would certainly need very good validation of that input.

Generating random string by TypoScript

Is it possible to auto generate a mixed string of digits and letters by TypoScript, e.g. 12A54 or something similar?
I'd prefer a userFunc to a php include script. For example, you can pass parameters to a user function.
Typoscript:
includeLibs.generateInvoiceNo= fileadmin/scripts/generateInvoiceNo.php
temp.invoiceNo = USER
temp.invoiceNo {
userFunc =user_generateInvoiceNo->main
}
PHP:
fileadmin/scripts/generateInvoiceNo.php
<?
class user_generateInvoiceNo {
var $cObj;// The backReference to the mother cObj object set at call time
/**
* Call it from a USER cObject with 'userFunc = user_generateInvoiceNo->main'
*/
function main($content,$conf){
$length = 6;
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$number=substr(str_shuffle($chars),0,$length);
return $number;
}
}
?>
Credits:
This php script
TYPO3 Wizard on userFunc
As already mentioned, there is no such functionality in Typoscript and so the preferred method is to use some simle PHP function as suggested in other answers.
However, there is a cheat and that would be to use MySQL. Mind you, that it's a solution only if you absolutely cannot (for a reason that I really cannot think of) write a piece of custom PHP. Take it rather as an academic answer than a practical one.
temp.random = CONTENT
temp.random {
table = tt_content
select {
pidInList = 1
recursive = 99
max = 1
selectFields = SUBSTRING(MD5(RAND()) FROM 1 FOR 6) AS random_string
}
renderObj = TEXT
renderObj {
field = random_string
case = upper
}
}
NOTES:
pidInList must point to an existing page.
The MySQL command is really just an example as the string would never contain letters G-Z. I'm sure it's possible to come up with a better string generated by MySQL.
Patching TYPO3 sources for such easy tasks is wrong idea. After the next source upgrade you'll lose your changes.
Instead it's better to include an easy PHP script where you can render what you need check TSREF

TYPO3: Parse current url into variable

i know how i get the current URL with typoscript, but i dont know how i can parse this url into a variable so i can use and work with it.
temp.getUrl = TEXT
temp.getUrl.typolink {
parameter.data=TSFE:id
returnLast=url
}
This example returns me an url segment like 'This/is/just/a/test.html', so long – perfect!
Now i try to save this url into an Variable like
temp.getUrl = TEXT
temp.getUrl.typolink {
parameter.data=TSFE:id
returnLast=url
}
wiredMindsCompleteUrl < temp.getUrl
This results everytime just with 'TEXT' :( i kinda depressed.
Please help :)
The question is, where do you want to use it.
If you want to use it in different places in TypoScript you can f.e. render it into stdWrap.append / stdWrap.prepend of your links.
myMenu = HMENU
myMenu ...
myMenu.stdWrap.append < temp.getUrl
You could just put it into an Register:
page.1.LOAD_REGISTER
page.1.getUrl < temp.getUrl
and f.e. use your register in the tilte-Tag of an image:
lib.MyImage = IMAGE
lib.MyImage.file = ...
lib.MyImage.titleText.data = REGISTER:getUrl
lib.MyImage.tilteText.noTrimWrap = | makes no sense (IMHO:) ||
If you need it in your extension, just use it with cObjGetSingle.
plugin.tx_yourextension_pi1.getUrl < temp.getUrl
Inside your extension use it via
function main($content, $conf) {
$this->conf = $conf;
return $this->cObj->cObjGetSingle($this->conf['getUrl'], $this->conf['getUrl.'], 'getUrl');
}
Side note: use lib.getUrl instead of temp.getUrl, otherwise you can get in trouble with non-cached TypoScript parts.

Call TYPO3 plugin from other plugin's body

I need to call typo3 plugin from other plugin's body and pass its result to template. This is pseudo-code that describes what I want to achieve doing this:
$data['###SOME_VARIABLE###'] = $someOtherPlugin->main();
$this->cObj->substituteMarkerArray($someTemplate, $data);
Is it possible?
Thanks!
It doenst work if you use the whole pi construct, e.g. for links, marker function etc, and the TSFE Data can be corrupted.
Dmitry said:
http://lists.typo3.org/pipermail/typo3-english/2008-August/052259.html
$cObjType = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_rgsmoothgallery_pi1'];
$conf = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_rgsmoothgallery_pi1.'];
$cObj = t3lib_div::makeInstance('tslib_cObj');
$cObj->start(array(), '_NO_TABLE');
$conf['val'] = 1;
$content = $cObj->cObjGetSingle($cObjType, $conf); //calling the main method
You should use t3lib_div:makeInstance method.
There is a working example from TYPO3's "powermail" extension.
function getGeo() {
// use geo ip if loaded
if (t3lib_extMgm::isLoaded('geoip')) {
require_once( t3lib_extMgm::extPath('geoip').'/pi1/class.tx_geoip_pi1.php');
$this->media = t3lib_div::makeInstance('tx_geoip_pi1');
if ($this->conf['geoip.']['file']) { // only if file for geoip is set
$this->media->init($this->conf['geoip.']['file']); // Initialize the geoip Ext
$this->GEOinfos = $this->media->getGeoIP($this->ipOverride ? $this->ipOverride : t3lib_div::getIndpEnv('REMOTE_ADDR')); // get all the infos of current user ip
}
}
}
The answer of #mitchiru is nice and basically correct.
If you have created your outer extension with Kickstarter and you are using pi_base then there is already an instance of tslib_cObj and the whole construct becomes simpler:
// get type of inner extension, eg. USER or USER_INT
$cObjType = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_innerextension_pi1'];
// get configuration array of inner extension
$cObjConf = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_innerextension_pi1.'];
// add own parameters to configuration array if needed - otherwise skip this line
$cObjConf['myparam'] = 'myvalue';
// call main method of inner extension, using cObj of outer extension
$content = $this->cObj->cObjGetSingle($cObjType, $cObjConf);
Firstly, you have to include your plugin class, before using, or outside your class:
include_once(t3lib_extMgm::extPath('myext').'pi1/class.tx_myext_pi1.php');
Secondly in your code (in the main as example)
$res = tx_myext_pi1::myMethod();
This will work for sure (I've checked this): http://lists.typo3.org/pipermail/typo3-english/2008-August/052259.html.
Probably Fedir's answer is correct too but I didn't have a chance to try it.
Cheers!