to modify my breadcrumbs on certain pages, I added a plugin which is supposed to add something to my breadcrumb values. But I need a certain get variable value and it just doesn't work:
lib.tippBreadcrumbs = USER_INT
lib.tippBreadcrumbs{
vendorName = Package
userFunc = tx_extbase_core_bootstrap->run
extensionName = SomethingArticles
pluginName = ArticleBreadcrumbs
controller = Article
action = articleBreadcrumbs
settings.articleCategory = TEXT
settings.articleCategory.data = gp:tx_somethingarticles_categorydetail|articleCategory
}
In my Article controller in my articleBreadcrumbs action, my settings array looks like this:
Array
(
[articleCategory] => Array
(
[data] =>
[_typoScriptNodeValue] => gp:tx_somethingarticles_categorydetail|articleCategory
)
)
How can I make this work?
I did not know the answer, but another smart person did:
http://lists.typo3.org/pipermail/typo3-project-typo3v4mvc/2011-October/010591.html
learned something myself
Related
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
I want to realize an image slide, that show the last 3 news from the news extension on it.
So - I'm obvioulsy new to TYPO3 - I somehow need to fetch the data from the news extension.
I would prefer doing it inside the new extension, so I guess - from what I know so far - it should look somehow like this
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$orderRepository = $objectManager->get('Tx_News_Extension_Path_To_Articles'); // don't know path
$articles = $orderRepository->find(3, BY-DATE, DESC); // don't know the command
$this->view->assign('articles', $articles);
I head of another way by doing it through TypoScript. Maybe I could use this:
lib.news_list < lib.news
lib.news_list {
action = list
switchableControllerActions.News.1 = list
}
Would be glad to get some advise.
Chris
One option is to add a function like this to your repository:
public function findLastByDate($amount){
$query = $this->createQuery();
$query->setLimit($amount);
$query->setOrderings(array(
'date' => \TYPO3\CMS\Extbase\Persistence\Generic\QueryInterface::ORDER_DESCENDING
));
return $query->execute();
}
And call it in your controller:
$articles = $this->orderRepository->findLastByDate(3);
We have developed a typo3 plug in that searches for trucks. For SEO reasons, we are trying to use the realURL plug in to make the URLs friendlier to use.
On the front page we have several call to actions that link to the search page with certain search parameters. An example is bellow:
/search-results/?tx_fds_searchresults[type_name]=Trailer
This link works as expected. On the results page is a link to the listings page with more details. An example is bellow:
/listing/?tx_fds_listing[id]=119870
This link is not working. tx_fds_listing[id] is not being populated in the arguments passed to the plug in controller.
At first we thought it might be a config issue but again, it isn't present on other pages.
The ID is not a database object and may be a text string instead.
Edit:
I should add that it works fine with RealURL turned off.
We get the id as $id = $this->request->getArgument('id');
Edit 2:
Here is the error message from the logs.
[ALERT] request="28233e225150a" component="TYPO3.CMS.Frontend.ContentObject.Exception.ProductionExceptionHandler": Oops, an error occurred! Code: 201512141630381db91bba - {"exception":"exception 'TYPO3\\CMS\\Extbase\\Mvc\\Exception\\NoSuchArgumentException' with message 'An argument \"id\" does not exist for this request.'
I also tried renaming the variable to name, but that didn't work either.
I have a solution that solves the root cause of the problem, if not the specific issue.
So I had to add additional mapping to the realurl_conf.php file. For example to get the listing id:
$config['domain.com']['postVarSets'][3]['stock'] = array(array('GETvar' => 'tx_fds_listing[id]'));
This makes the effective URL:
/listing/stock/119870
This was the intended usage for the plugin, so this is a good result. I also added configuration for ajax and pdfs. This required modification to the typoscript that was not obvious.
PDF TS:
pdf = PAGE
pdf {
typeNum = 300
10 = USER_INT
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
#vendorName = TYPO3
extensionName = Fds
pluginName = Listing
#controller = FDS
controller = Tx_Fds_Controller_FDSController
#action = listingPdf
switchableControllerActions.FDS.1 = listingPdf
}
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type:application/pdf
xhtml_cleaning = 0
admPanel = 0
}
}
PDF RealURL Config:
$config['domain.com']['postVarSets'][3]['pdf'] = array('type' => 'single', 'keyValues' => array ('type' => 300));
PDF effective URL:
/listing/pdf/stock/119870
I have a nearly unconfigured flexform (only set the Switchable Controller Action to "list") which I wanted to configure via TypoScript, e.g. as such:
plugin.tx_news {
settings {
pluginType = news-list
limit = 999
orderBy = datetime
orderDirection = desc
startingpoint = {$pidNewsStorage}
detailPid = {$pidNewsDetail}
archiveRestriction = active
categories = 24
categoryConjunction = and
}
}
The TS is included in the page's setup, and the properties show up correctly in the TSOB.
Strangely, not all settings will work (the custom setting pluginType for use in fluid works, while detailPid doesn't). By "work", I mean override the empty settings in the flexform.
Some default settings I have set on the root page DO apply.
Where could I look?
You can also add here the fields which you want to override from typoscript
plugin.tx_news.settings.overrideFlexformSettingsIfEmpty = cropMaxCharacters,dateField,timeRestriction,orderBy,orderDirection,backPid,listPid,startingpoint,recursive,list.paginate.itemsPerPage,list.paginate.templatePath,templateLayout
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.