TYPO3 set template view for controller action - typo3

I want to use the view template of the list action for my listByYear action. I tried setTemplatePathAndFilename without success. It still cannot find the template.
Sorry, the requested view was not found.
The technical reason is: No template was found. View could not be
resolved for action "listByYear" in class
"XXX\YYY\Controller\EventController".
/**
* action listByYear
* #param \XXX\YYY\Domain\Model\Event $event
*
* #return void
*/
public function listByYearAction(\XXX\YYY\Domain\Model\Event $event)
{
$date = $event->getStart();
$events = $this->eventRepository->findByYear($date->format('Y'));
$this->view->setTemplatePathAndFilename(
'typo3conf/ext/' .
$this->request->getControllerExtensionKey() .
'/Resources/Private/Templates/Event/List.html'
);
debug('typo3conf/ext/' .
$this->request->getControllerExtensionKey() .
'/Resources/Private/Templates/Event/List.html');
$this->view->assign('events', $events);
}
How do I make it use the template for the list?

The very short answer is, you can't. The view will already have been initialised and asked to resolve a template well before your action fires, indeed well before any point where you can affect the template filename that it would look for.
The template file that by convention would be resolved must always exist. This is what allows your controller action to render. You can then, but I would not recommend that you do, override the template file by setting the template name (the action).
Overall recommendation: use the default template naming logic. If you need to re-use templates, consider refactoring the template parts you need to reuse, placing them in partial templates.

// Do not forget the use in the header ...,
// or write fully qualified class path..
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
// then add something like this in your action before the assign...
// or maybe create a Standalone view: search the web for "Extbase Standaloneview"
// have a look at: /typo3/sysext/about/Classes/Controller/AboutController.php
$this->view = GeneralUtility::makeInstance(StandaloneView::class);
$this->view->setTemplate('ActionName');
$this->view->setTemplateRootPaths(['EXT:your_ext/Resources/Private/Templates']);
$this->view->setPartialRootPaths(['EXT:your_ext/Resources/Private/Partials']);
$this->view->setLayoutRootPaths(['EXT:your_ext/Resources/Private/Layouts']);
$this->view->assignMultiple([
'whatever' => $whatever,
'youLike' => $youLike,
]);

Related

Extbase view variable not getting

/**
* New post form
* #param \Vendor\My\Domain\Model\Post|null $newPost New post
* #return void
* #dontvalidate $newPost
*/
public function newAction(\Vendor\My\Domain\Model\Post $newPost = NULL) {
$this->view->assign('test', 'hello');
$this->view->assign('categoryList', $this->categoryRepository->findAllByBlog(0));
$this->view->assign('postObject', $newPost);
}
public function editAction() {
$this->view->assign('categoryList', $this->categoryRepository->findAllByBlog(0));
$postObject = $this->postRepository->findOneByUid($this->request->getArgument('id'));
$this->view->assign('postObject', $postObject);
}
this is my script and my problem is that I have a categoryList array, its is only getting in edit view. I want to use that category list on newaction. When I tried to foreach that array in new action view file it is getting empty. and i can get it after saving the postObject. Any idea about this particular problem? and variable test from newaction also not visible in the newAction Template file.
Am using Typo3 7.6.11
Declare arguments you want to receive, as arguments for your controller action. Reference this argument name correctly in Fluid templates when you build links to your controller action. Do not access arguments from the Request directly. Add correct PDPdoc comments for it, too.
Basically: do the correct thing with your arguments instead of bypassing the framework. This advise applies to anything you do in Extbase.
NB: New and Edit actions should never, ever share the same template (this further indicates you bypass the framework's expected behavior). Create and New, yes. But not New and Edit. If necessary, put the form fields in a partial and the form itself in separate templates so you can control the action building and object/object-name setup correctly.
If a $this->***Repository method returns NULL, it may be that the repository had no StoragePid defined.
Make sure both newAction and editAction have the same storagePid defined in TypoScript or your Backend Plugin Settings (Flexform).
The TypoScript for this would look something like this:
plugin.tx_extension.persistence.storagePid = 100

Typo3 Extension PHP View

Using the infos in this link:
https://docs.typo3.org/typo3cms/ExtbaseFluidBook/8-Fluid/9-using-php-based-views.html
I try to create an action to output a JSON.
I have a normal controller with the list action:
public function listAction()
{
$storelocators = $this->storelocatorRepository->findAll();
$this->view->assign('storelocators', $storelocators);
}
And in ext/my_storelocator/Classes/View/Storelocator I have a class List.php:
<?
class Tx_MyStorelocator_View_Storelocator_List extends Tx_Extbase_MVC_View_AbstractView {
public function render() {
return 'Hello World';
}
}
All I get is:
Sorry, the requested view was not found.
The technical reason is: No template was found. View could not be resolved for action "list" in class "My\MyStorelocator\Controller\StorelocatorController".
So I guess there is something wrong with the paths. Or where is the Problem?
Edit: Extensioninfos
Vendor: My
key: my_storelocator
controller: NOT SURE (I created it with the extension_builder so I guess my controllers name is Storelocator)
action: list
From my understanding a classname like Tx_MyStorelocator_View_Storelocator_List should be correct. But its not working
You will need to create an empty file for the HTML view for your controller, e.g. Resources/Private/Template/Storelocator/List.html, even if you do not plan to use the HTML view or if you just return the content yourself (which is perfectly fine).
The reason for this is simply technical limitation.
First of all, TYPO3 now has a built-in JSON view, described thoroughly here: https://usetypo3.com/json-view.html. It lets you easily define which properties you'd like to render.
The error message means that your Controller is still pointing to the TemplateView - because thats the error the TemplateView throws if it can't find the defined template file.
You can specify which view to use to render within your controller. You can either set a default view via the $defaultViewObjectName property, like so:
/**
* #var string
*/
protected $defaultViewObjectName = '\TYPO3\CMS\Fluid\View\TemplateView';
You can also set it from within the Controller inside initialization actions like so:
public function initializeExportPDFAction(){
$this->defaultViewObjectName = 'Vendor\Extension\View\FileTransferView';
}
(I have, however, not yet found a way to define the template from within actions, any tips in the comments would be appreciated)
Your path syntax is probably out of date. Instead of writing a render() function in Classes/View/Storelocator/List.php, try writing a listAction() function in a Classes/Controller/StorelocatorController.php file. Extension Builder should have created this file for you, if you made an aggregate model with the usual "list, create, edit ..." and such actions.
Review A journey through the Blog Example and the following chapter, Creating a first extension, for tips.
Keep in mind that there is a mismatch between the documentation and the Extension Builder generated PHP code files. Developing TYPO3 Extensions with Extbase and Fluid has some parts up to date, and other parts still using old syntax.

Automatically clear captured placeholder view-helper content after it is displayed

Generating a mail message in a partial, I use the placeholder view-helper as follows:
<?php $this->placeholder('mykey')->startCapture() ?>
Some content here that is actually more complicated than just text.
Trust me that, in this case the, using the placeholder for capturing
is desirable.
<?php
$this->placeholder('mykey')->endCapture();
echo $this->placeholder('mykey');
?>
The problem is that if I use the same key in a different partial for a different mail message within the same request, then this captured content is still stored in the container for that key. In principle, I'd like the partials to be free to use whatever placeholder keys they want without having to sweat what other partials are using.
I know I can use different keys in different partials. Alternatively, I can manually clear the content after use/display with something like:
$this->placeholder('mykey')->set('');
But I'd hate to put the burden of all that on the view script that uses the placeholder.
I suspect what I want to do is create my own custom placeholder view-helper that auto-clears his captured content after it has been output.
I've tried creating a custom placeholder container (extends the Standalone container, overriding the toString() method), creating a custom view-helper (extends the the standard Placeholder view-helper), and telling the view-helper to use the custom container class.
But I keep bumping into some error associated to a missing view object. Clearly, I'm missing something about the how the view object, the container, and the registry all interact - and probably even something how the plugin system loads them all.
Any advice and general explanation greatly appreciated.
You need to set this container in the Placeholder view helper because otherwise the Zend_View_Helper_Placeholder_Registry loads automatically the Zend_View_Helper_Placeholder_Container. So, first you need to set your custom container manually. In a view script:
$this->getHelper('placeholder')
->getRegistry()
->setContainerClass('My_View_Helper_Placeholder_Container');
Or for exameple in a _initCustomContainer() in your Bootstrap.php:
$view = $this->bootstrap('view')->getResource('view');
$view->getHelper('placeholder')
->getRegistry()
->setContainerClass('My_View_Helper_Placeholder_Container');
Then, you need to create this class based on the Zend_View_Helper_Placeholder_Container (and not the Zend_View_Helper_Placeholder_Container_Standalone. I'd suggest you keep the option open to reset the content or not, you do that with a setter:
class My_View_Helper_Placeholder_Container
extends Zend_View_Helper_Placeholder_Container
{
protected $_resetCapture = true; // defaults true for new behaviour
public function setResetCapture($flag)
{
$this->_resetCapture = (bool) $flag;
return $this;
}
public function toString($indent = null)
{
$return = parent::toString($indent);
if ($this->_resetCapture) {
$this->exchangeArray(array());
}
return $return;
}
}
By default, the reset capture is already on, but to switch it off and start capturing:
$this->placeholder('my_key')->setResetCapture(false)->startCapture();
And to switch it on again:
$this->placeholder('my_key')->setResetCapture(true);
In a view script, use:
$this->placeholder('mykey')->captureStart('SET');
or using the class constant:
$this->placeholder('mykey')->captureStart(Zend_View_Helper_Placeholder_Container_Abstract::SET);

Zend framework rendering custom place holders in layout

I have some custom place holders in layout file, like [Region_Contents]
now I want to replace these placeholders with my custom html as layout is rendered
like instead of displaying [Region_Contents] it may show Hello this is test block
is there any way to do this?
You can use view filters for this. First we have to implement the Zend_Filter_Interface like so:
class My_View_Filter_PlaceholderReplacer implements Zend_Filter_Interface
{
public function filter($value)
{
return str_replace('[Region_Contents]', 'Hello this is test block', $value);
}
}
In the code above, $value contains the string representation of the view just before it is displayed. Whatever is returned by the function above will be used by ZF when rendering the view. Note that we're using str_replace over preg_replace for performance reasons.
Next, we need to tell ZF to use the filter we just made. You can do this in the bootstrap.
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initViewSettings()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$view->addFilterPath('My/View/Filter', 'My_View_Filter');
$view->setFilter('PlaceholderReplacer');
...
}
...
}
For more info, please refer to the following links:
Zend Manual
Zend Framework and Translation
If it's not necessary to keep the same syntax you describe above, you might just use the standard Zend_View placeholder view helpers: http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.placeholder
Hope that helps,

Zend Form Element with Javascript - Decorator, View Helper or View Script?

I want to add some javacsript to a Zend_Form_Element_Text .
At first I thought a decorator would be the best way to do it, but since it is just a script (the markup doesn't change) then maybe a view helper is better? or a view script?
It seems like they are all for the same purpose (regarding a form element).
The javascript I want to add is not an event (e.g. change, click, etc.). I can add it easily with headScript() but I want to make it re-usable , that's why I thought about a decorator/view helper. I'm just not clear about the difference between them.
What is the best practice in this case? advantages?
UPDATE: Seems like the best practice is to use view helpers from view scripts , so decorators would be a better fit?
Thanks.
You could create your own decorator by extending Zend_From_Decorator_Abstract and generate your snippet in it's render() method :
class My_Decorator_FieldInitializer extends Zend_Form_Decorator_Abstract {
public function render($content){
$separator = $this->getSeparator();
$element = $this->getElement();
$output = '<script>'.
//you write your js snippet here, using
//the data you have in $element if you need
.'</script>';
return $content . $separator . $output;
}
}
If you need more details, ask for it in a comment, i'll edit this answer. And I didn't test this code.
Use setAttrib function.
eg:-
$element = new Zend_Form_Element_Text('test');
$element->setAttrib('onclick', 'alert("Test")');
I'm not actually seeing where this needs to be a decorator or a view-helper or a view-script.
If I wanted to attach some client-side behavior to a form element, I'd probably set an attribute with $elt->setAttrib('class', 'someClass') or $elt->setAttrib('id', 'someId'), some hook onto which my script can attach. Then I'd add listeners/handlers to those targeted elements.
For example, for a click handler using jQuery , it would be something like:
(function($){
$(document).ready(function(){
$('.someClass').click(function(e){
// handle the event here
});
});
})(jQuery);
The benefit is that it is unobtrusive, so the markup remains clean. Hopefully, the javascript is an enhancement- not a critical part of the functionality - so it degrades gracefully.
Perhaps you mean that this javascript segment itself needs to be reusable across different element identifiers - someClass, in this example. In this case, you could simply write a view-helper that accepts the CSS class name as the parameter.
"the markup doesn't change", Yap,
but I like to add some javascript function throw ZendForm Element:
$text_f = new Zend_Form_Element_Text("text_id");
$text_f->setAttrib('OnChange', 'someFunction($(this));');
The best way is if you are working with a team, where all of you should use same code standard. For me and my team this is the code above.