How to use DataProcessors with TYPO3 plugins - typo3

The way to add a DataProcessor to a PAGE or a FLUIDTEMPLATE is often shown. How can it be assigned to a TYPO3 plugin?
For a PAGE you can do it like this:
page {
10 {
dataProcessing {
1558428437 = BK2K\BootstrapPackage\DataProcessing\ConstantsProcessor
1558428437 {
as = myconstants
key = settings.constants
}
}
}
}
But can you do something like this:
config.tx_extbase {
dataProcessing {
1558428437 = BK2K\BootstrapPackage\DataProcessing\ConstantsProcessor
1558428437 {
as = myconstants
key = settings.constants
}
}
Many thanks!

No, this is not possible since data processors is a feature of the FLUIDTEMPLATE content object alone.
In this case you can invoke the ConstantsProcessor manually in your controller action. You can get the current ContentObjectRenderer via $this->configurationManager->getContentObject(). The $processorConfiguration is the same as in TypoScript but as array:
$constantsProcessor = GeneralUtility::makeInstance(ConstantsProcessor::class);
$data = $constantsProcessor->process(
$this->configurationManager->getContentObject(),
[],
[
'key' => 'settings.constants',
'as' => 'myconstants',
],
[]
);
// Use $data['myconstants']

That's currently not possible.
This would definitely be a feature that would make live of Integrators much easier.

Related

why Typo3 website v10 show empty sitemap xml in frontend

I'm using a Typo3 website version 10 and the sitemap is not working properly,
i can see the configuration in the typoscript object browser but in the front-end www.mydomain.ch/?type=1533906435 the xml file is blanc.
Frontend screenshot:
Typoscript object browser screenshot:
seo extension is installed.
the website is multilangage.
what can be missing so that i see the sitemap ?
If this is all you have, then you are missing some key configuration. You need to specify what should be shown. So, on your TypoScript, based on the documentation, you should define what pages/extension etc must be shown. For example:
plugin.tx_seo {
config {
xmlSitemap {
sitemaps {
pages {
config {
excludedDoktypes = 137, 138
additionalWhere = AND (no_index = 0 OR no_follow = 0)
#rootPage = <optionally specify a different root page. (default: rootPageId from site configuration)>
}
}
}
}
}
}
Here is an example for the extension news as well, in case you are using it.
plugin.tx_seo.config {
xmlSitemap {
sitemaps {
news {
provider = TYPO3\CMS\Seo\XmlSitemap\RecordsXmlSitemapDataProvider
config {
table = tx_news_domain_model_news
additionalWhere =
sortField = sorting
lastModifiedField = tstamp
changeFreqField = sitemap_changefreq
priorityField = sitemap_priority
pid = 26
recursive = 2
url {
pageId = 25
fieldToParameterMap {
uid = tx_news_pi1[news]
}
additionalGetParameters {
tx_news_pi1.controller = News
tx_news_pi1.action = detail
}
}
}
}
}
}
}
Here the documentation as well: Documentation
i have solved the problem, i think it was the sourceopt extension installed have a bug, i have update it to the latest version, now i can see the xml sitemap working fine, thanks!

TYPO3: Render a plugin via Typoscript or ViewHelper and change settings

I would like to load a plugin dynamically according to some data. First I tried to do it with Typoscript, but after some research I figured out, that it is not possible to change the settings of the plugin (see old forum entry).
I need to change settings.simplepoll.uid according to the passed data:
This is the Typoscript I tried:
lib.loadSimplepoll = USER
lib.loadSimplepoll {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = Simplepoll
pluginName = Polllisting
vendorName = Pixelink
switchableControllerActions {
SimplePoll {
1 = list
}
}
settings < plugin.tx_simplepoll.settings
settings {
simplepoll {
uid.current = 1
}
}
}
The call in the template looks like that:
<f:cObject typoscriptObjectPath="lib.loadSimplepoll">{newsItem.simplepoll}</f:cObject>
After figuring out, that changing the settings is not possible, I tried a viewhelper:
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class LoadSimplepollViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
* #param int $uid Uid of poll
* #return string
*/
public function render($uid) {
$cObj = GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$configurationManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManager');
$simplepollTs = $configurationManager->getConfiguration(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'simplepoll',
'Polllisting'
);
$ttContentConfig = array(
'tables' => 'tt_content',
'source' => 1030,
'dontCheckPid' => 1
);
// returning this works perfectly!
// but I need to change the "settings.simplepoll.uid"
$data = $cObj->RECORDS($ttContentConfig);
$cObj->start($data, 'tx_simplepoll_domain_model_simplepoll');
$renderObjName = '<tt_content.list.20.simplepoll_polllisting';
$renderObjConf = $GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']['simplepoll_polllisting.'];
$renderObjConf['persistence']['storagePid'] = 394; // This does not work!
$renderObjConf['settings'] = $simplepollTs;
$renderObjConf['settings']['simplepoll']['uid'] = $uid;
return $cObj->cObjGetSingle($renderObjName, $renderObjConf);
}
}
The viehelper is called like this:
{vh:LoadSimplepoll(uid: '{newsItem.simplepoll}')}
Now I am able to change the uid of the poll with this line:
$renderObjConf['settings']['simplepoll']['uid'] = $uid;
My problem is now, that it loads the poll, but not the answers. I tracked this down to the fact, that the plugin somehow does not know the Record Storage Page anymore. The line $renderObjConf['persistence']['storagePid'] = 394; does not help.
How can I tell the plugin the Storage Pid?
Or is there another/better way to load a plugin with changing data?
Why shouldn't it be possible to modify settings.simplepoll.uid in typoscript?
because the extension simplepoll does not handle any stdWrap functionality to its typoscript settings.
Have a look into the code:
this special setting is used here:
$simplePoll = $this->simplePollRepository->findByUid($this->settings['simplepoll']['uid']);
no stdWrap, just plain usage.
compare it to ext:news:
before any settings is used it is processed. A dedicated join of typoscript settings with the settings in the plugin. And if necessary there is a stdWrap possible: here
$this->originalSettings = $originalSettings;
// 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 . '.']
);
}
}
}
As you can see:
extbase does not support you with typoscript stdWrap functionality.
You (and every extension author) need to do it by hand. But that was so even before extbase.
In this way: as you can not configure your value you only can trick TYPO3 (and the plugin):
if you have a small number of uids you can have one variant for each uid
lib.loadSimplepoll123 < lib.loadSimplepoll
lib.loadSimplepoll123.settings.simplepoll.uid = 123
lib.loadSimplepoll234 < lib.loadSimplepoll
lib.loadSimplepoll234.settings.simplepoll.uid = 234
lib.loadSimplepoll345 < lib.loadSimplepoll
lib.loadSimplepoll345.settings.simplepoll.uid = 345
lib.loadSimplepoll456 < lib.loadSimplepoll
lib.loadSimplepoll456.settings.simplepoll.uid = 456
and call it like
<f:cObject typoscriptObjectPath="lib.loadSimplepoll{newsItem.simplepoll}" />
or you build a pull request implementing the stdWrap functionality and send it to the extension author.
Why shouldn't it be possible to modify settings.simplepoll.uid in typoscript?
you just need the correct construction to modify it.
For a single value you can use current, but use it properly. It is a stdWrap function which needs to be evaluated.
If there is no stdWrap evaluation by default it might work with a cObject of type TEXT
settings.simplepoll.uid.cObject = TEXT
settings.simplepoll.uid.cObject.current = 1
or to indicate a stdWrap you need to use stdWrap literally:
settings.simplepoll.uid.stdWrap.current = 1
another variant of data transfer are named parameters. Just build an associative array as data parameter and access the values individual:
fluid:
<f:cObject typoscriptObjectPath="lib.arraytest" data="{a:'abc',b:'xyz'}" >
inside text
</f:cObject>
and the typoscript:
lib.arraytest = COA
lib.arraytest {
10 = TEXT
10.field = a
10.wrap = /|/
20 = TEXT
20.field = b
20.wrap = \|\
}
which results in an output of /abc/\xyz\. Be aware: the inner text of the f:cobject tag will be lost as the data parameter has priority about inner children.
In the meantime I got the Viewhelpter to work:
Viewhelper:
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class LoadSimplepollViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
* #return void
*/
public function initializeArguments()
{
parent::initializeArguments();
$this->registerArgument('simplepollUid', 'int', 'Uid of simplepoll', false);
}
/**
* #return string
*/
public function render()
{
$configurationManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManager');
$simplepollTs = $configurationManager->getConfiguration(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'simplepoll',
'Polllisting');
$cObj = GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$renderObjName = '<tt_content.list.20.simplepoll_polllisting';
$renderObjConf = $GLOBALS['TSFE']->tmpl->setup['tt_content.']['list.']['20.']['simplepoll_polllisting.'];
$renderObjConf['settings'] = $simplepollTs;
$renderObjConf['settings']['simplepoll']['uid'] = (int)$this->arguments['simplepollUid'];
return $cObj->cObjGetSingle($renderObjName, $renderObjConf);
}
}
Call the viewhelper in the template (don't forget to register the namespace):
{vh:LoadSimplepoll(simplepollUid: '{newsItem.ipgSimplepoll}')}
That's it.

How to choose the template dynamically with fluidpages

I was using fluidpages for template building, and would like to choose the template dynamically based on a field in the fe_users table. For example, most people will see the EXT:default template by default, while some will see EXT:advanced template instead, as they are marked as special.
I tried
plugin.tx_template {
view {
templateRootPaths {
0 = EXT:default/Resources/Private/Templates/
10 {
data = TSFE:fe_user|user|template
wrap = EXT: | /Resources/Private/Templates/
}
}
}
}
But it seems the TS is not parsed and is used directly by fluid, therefore failed.
Any idea or hint is appreciated!
Actually this may be possible. But i can't see an obvious way on how to override the chosen template in the page properties.
To my knowledge, you are required to select a template in the page record.
If you find a possibility to override that one, you could use a TS Setup like this:
EXT:template_package/Configuration/TypoScript/constants.txt:
plugin.tx_templatepackage {
view {
templateRootPaths.default = EXT:template_package/Resources/Private/Templates/
partialRootPaths.default = EXT:template_package/Resources/Private/Partials/
layoutRootPaths.default = EXT:template_package/Resources/Private/Layouts/
}
}
EXT:template_package/Configuration/TypoScript/setup.txt:
plugin.tx_templatepackage {
view {
templateRootPaths.default = {$plugin.tx_templatepackage.view.templateRootPaths.default}
partialRootPaths.default = {$plugin.tx_templatepackage.view.partialRootPaths.default}
layoutRootPaths.default = {$plugin.tx_templatepackage.view.layoutRootPaths.default}
}
}
Above part will setup your global paths.
After that, you'll define your sub packages for templates.
EXT:template_package/Configuration/TypoScript/Basic/setup.txt
plugin.tx_templatepackage {
view {
templateRootPaths.10 = {$plugin.tx_templatepackage.view.templateRootPaths.0}Basic/
partialRootPaths.10 = {$plugin.tx_templatepackage.view.partialRootPaths.0}Basic/
layoutRootPaths.10 = {$plugin.tx_templatepackage.view.layoutRootPaths.0}Basic/
}
}
And
EXT:template_package/Configuration/TypoScript/Advanced/setup.txt
plugin.tx_templatepackage {
view {
templateRootPaths.20 = {$plugin.tx_templatepackage.view.templateRootPaths.0}Advanced/
partialRootPaths.20 = {$plugin.tx_templatepackage.view.partialRootPaths.0}Advanced/
layoutRootPaths.20 = {$plugin.tx_templatepackage.view.layoutRootPaths.0}Advanced/
}
}
Of course you should make them available within TYPO3:
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript', 'Template Package: Base');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript/Basic', 'Template Package: Basic');
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript/Advanced', 'Template Package: Advanced');
After all of that, you could override a value — IDK which one — via:
[usergroup = group1-uid]
// override option, which defines the default template
[usergroup = group2-uid]
// override option, which defines the default template
Sorry I can't help you out any further. I tried to dig deeper into EXT:flux and EXT:fluidpages. But i can't see that option.

Access page properties within fluid_styled_content element

I'm trying to extend the fluid_styled_content element "Menu". Within my partial (e.g. typo3conf/ext/my_theme/Resources/Private/Templates/Content/Partials/Menu/Type-1.html I need to access the page properties of the page where the menu CE resides. How can I archive this? {data} contains only the data of the content element.
In {data.pid} you have the uid of the page.
You can use a viewhelper to get the complete pages record (in ext:vhs there is a viewhelper to get any kind of records).
or you can use <f:cObject> and some typoscript to access single values.
Use \TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor.
I cannot check the code right now but you could take this as a starting point:
tt_content.menu.dataProcessing {
30 = \TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
30 {
table = pages
where.dataWrap = uid = {TSFE:id}
as = page
}
}
Afterwards you can access the current page‘s properties via {page.0.property}.
There‘s just one query for each menu content object with this approach while most view helper solutions tend to increase the number of database queries issued.
#undko: The DatabaseQueryProcessor was the perfect hint. But your snippet had two problems I had to fix:
- the TypoScript code needs pidInList to work
- in the Fluid Template there was data missing: pageproperties.0.data.myproperty
Here is my final code that works fine for me:
tt_content.menu.dataProcessing {
30 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
30 {
table = pages
where.dataWrap = uid = {TSFE:id}
pidInList = 1
as = pageproperties
}
}
In the Fluid template I use {pageproperties.0.data.tx_mytheme_fieldname}.
I don't know why exactly but I can't access page properties with the proposed solution. I'm using Typo3 10.4.9.
I found an alternative solution :
tt_content.menu dataProcessing {
30 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
30 {
table = pages
pidInList = 0
recursive = 99
uidInList = this
as = pageproperties
}
}
Maybe this will help someone else.
More brutal approach; to access the page properties everywhere, for example in a custom content element. Create in the sitepackage Classes/ViewHelper/GetPagePropertiesViewHelper.php :
<?php namespace Xxx\Sitepackage\ViewHelpers;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class GetPagePropertiesViewHelper extends \TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper
{
public function initializeArguments()
{
$this->registerArgument('pid', 'int', 'The page uid to get the pageproperties from', true, 1);
$this->registerArgument('property', 'string', 'A specific page property to be returned', false, null);
}
public function render()
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connectionPool->getQueryBuilderForTable('pages');
$pageProperties = [];
$statement = $queryBuilder
->select('*')
->from('pages')
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($this->arguments['pid'], \PDO::PARAM_INT))
)
->execute();
while ($row = $statement->fetch()) {
$pageProperties[] = $row;
}
if ($property) {
return $pageProperties[0][$property];
}
return $pageProperties[0];
}
}
Usage in a template or partial:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:c="http://typo3.org/ns/Xxx/Sitepackage/ViewHelpers"
data-namespace-typo3-fluid="true">
<c:getPageProperties pid="{data.pid}" property="description"/>
<f:debug><c:getPageProperties pid="{data.pid}"/></f:debug>

typoscript variable in plugin settings?

I am using a custom plugin and I need to add the page title as one of the plugin's settings variables:
plugin.tx_fsearch {
settings {
resultsPath = search-results/brand/{field:title}/make/{field:title}
resultsPath.insertData = 1
}
}
However this is outputting the word 'Array' instead of the path I need.
Does anyone know how I might be able to make this work?
There is no stdWrap available for settings in extbase extensions, no matter if using TEXT cObj or insertData!
As a workaround, you can fix that yourself by doing something like EXT:news does here https://github.com/georgringer/news/blob/master/Classes/Controller/NewsController.php#L495
public function injectConfigurationManager(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
) {
$this->configurationManager = $configurationManager;
$typoScriptService = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Service\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(
$originalSettings[$key],
$typoScriptArray[$key . '.']
);
}
}
}
$this->settings = $originalSettings;
}
Or you skip the TS part and call the stdWrap directly in your controller.
Try TEXT object
plugin.tx_fsearch {
settings {
resultsPath = TEXT
resultsPath.value = search-results/brand/{field.title}/make/{field.title}
}
}