ZF2: How to pass a variable from the method attached to MvcEvent::EVENT_FINISH to the layout attached in MvcEvent::EVENT_RENDER? - zend-framework2

I am trying to understand Zend Framework 2 (ZF2). Few days ago I bought the book "Learn ZF2: Learning By Example" by Slavey Karadzhov. Now I am reading it and trying to get some examples working.
I am stuck in page 60. The example shown in the book works well, but the modification I just made does not work... Why? How to fix it?
To get into the same code/situation you would have to:
git clone https://github.com/slaff/learnzf2 .
composer.phar self-update
composer.phar install
git stash
git checkout 'ch-view'
After that You will have the same setup as I do.
Now I have changed the file /module/Debug/view/debug/layout/sidebar.phtml from this:
<h1>Top Line</h1>
<?= $this->content ?>
<h1>Bottom Line</h1>
to this (just added one line at the end):
<h1>Top Line</h1>
<?= $this->content ?>
<h1>Bottom Line</h1>
<p>MVC duration: <?= $this->mvcDuration ?></p>
I would like $this->mvcDuration to be the value of $duration from /module/Debug/Module.php file getMvcDuration method.
I changed the content of method getMvcDuration from this:
public function getMvcDuration(MvcEvent $event)
{
// Here we get the service manager
$serviceManager = $event->getApplication()->getServiceManager();
// Get the already created instance of our timer service
$timer = $serviceManager->get('timer');
$duration = $timer->stop('mvc-execution');
// and finally print the duration
error_log("MVC Duration:".$duration." seconds");
}
to this (added two lines at the end of the method):
public function getMvcDuration(MvcEvent $event)
{
// Here we get the service manager
$serviceManager = $event->getApplication()->getServiceManager();
// Get the already created instance of our timer service
$timer = $serviceManager->get('timer');
$duration = $timer->stop('mvc-execution');
// and finally print the duration
error_log("MVC Duration:".$duration." seconds");
$viewModel = $event->getViewModel();
$viewModel->setVariable('mvcDuration', $duration);
}
However, this kind of change does not work and the value of $duration is not passed to the layout. The question is WHY? How can I pass $duration to $this->mvcDuration of the layout?
p.s. The code downloaded from official github repo (https://github.com/slaff/learnzf2) is acting quite strange... Changing project files (e.g.: /module/Debug/view/debug/layout/sidebar.phtml) does not change the output. If You have the same situation while trying to help me with this case then I would suggest you to modify files in /vendor/learnzf2 directory instead of files in /module directory. I know that modifying code in vendor directory is not good thing to do, but let this post (my question) be about the one problem only.

Good book. Your basic problem is that you are Trying to update a variable into the view in a method that is triggered after the view has already been sent. You probably can't do this, unless you redefine which event triggers it, but that would defeat the intended purpose of timing the whole mvc duration.
All that said, you shouldn't be injecting variables into the view model from module.php. It's very hard to test that. This is what view helpers are good for.

Related

TYPO3 - Retrieved TypoScript in itemsProcFunc are incomplete

I have following problem:
We are overriding the tt_content TCA with a custom column which has an itemsProcFunc in it's config. In the function we try to retrieve the TypoScript-Settings, so we can display the items dynamically. The problem is: In the function we don't receive all the TypoScript-Settings, which are included but only some.
'itemsProcFunc' => 'Vendor\Ext\Backend\Hooks\TcaHook->addFields',
class TcaHook
{
public function addFields($config){
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
$configurationManager = $objectManager->get('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
$setup = $configurationManager->getConfiguration(
\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT
);
}
$setup is now incomplete and doesn't contain the full TypoScript, for example some of the static-included TypoScript is missing.
Used TYPO3 7 LTS (7.6.18), PHP 7.0.* in composer-mode.
Does anybody know where the problem is? Is there some alternative?
You maybe misunderstood the purpose of TypoScipt. It is a way of configuration for the Frontend. The Hook you mentioned is used in the TCA, whích is a Backend part of TYPO3. TypoScript usually isn't used for backend related stuff at all, because it is bound to a specific page template record. Instead in the backend, there is the TSConfig, that can be bound to a page, but also can be added globally. Another thing you are doing wrong is the use of the ObjectManager and the ConfigurationManager, which are classes of extbase, which isn't initialized in the backend. I would recommend to not use extbase in TCA, because the TCA is cached and loaded for every page request. Instead use TSConfig or give your configuration settings directly to the TCA. Do not initialize extbase and do not use extbase classes in these hooks.
Depending on what you want to configure via TypoScript, you may want to do something like this:
'config' => [
'type' => 'select',
'renderType' => 'singleSelect',
'items' => [
['EXT:my_ext/Resources/Private/Language/locallang_db.xlf:myfield.I.0', '']
],
'itemsProcFunc' => \VENDOR\MyExt\UserFunctions\FormEngine\TypeSelectProcFunc::class . '->fillSelect',
'customSetting' => 'somesetting'
]
and then access it in your class:
class TypeSelectProcFunc{
public function fillSelect(&$params){
if( $params['customSetting'] === 'somesetting' ){
$params['items'][] = ['New item',1];
}
}
}
I had a similar problem (also with itemsProcFunc and retrieving TypoScript). In my case, the current page ID of the selected backend page was not known to the ConfigurationManager. Because of this it used the page id of the root page (e.g. 1) and some TypoScript templates were not loaded.
However, before we look at the solution, Euli made some good points in his answer:
Do not use extbase configuration manager in TCA functions
Use TSconfig instead of TypoScript for backend configuration
You may like to ask another question what you are trying to do specifically and why you need TypoScript in BE context.
For completeness sake, I tested this workaround, but I wouldn't recommend it because of the mentioned reasons and because I am not sure if this is best practice. (I only used it because I was patching an extension which was already using TypoScript in the TCA and I wanted to find out why it wasn't working. I will probably rework this part entirely.)
I am posting this in the hope that it may be helpful for similar problems.
public function populateItemsProcFunc(array &$config): array
{
// workaround to set current page id for BackendConfigurationManager
$_GET['id'] = $this->getPageId((int)($config['flexParentDatabaseRow']['pid'] ?? 0));
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$configurationManager = $objectManager->get(BackendConfigurationManager::class);
$setting = $configurationManager->getTypoScriptSetup();
$templates = $setting['plugin.']['tx_rssdisplay.']['settings.']['templates.'] ?? [];
// ... some code removed
}
protected function getPageId(int $pid): int
{
if ($pid > 0) {
return $pid;
}
$row = BackendUtility::getRecord('tt_content', abs($pid), 'uid,pid');
return $row['pid'];
}
The function getPageId() was derived from ext:news which also uses this in an itemsProcFunc but it then retrieves configuration from TSconfig. You may want to also look at that for an example: ext:news GeorgRinger\News\Hooks\ItemsProcFunc::user_templateLayout
If you look at the code in the TYPO3 core, it will try to get the current page id from
(int)GeneralUtility::_GP('id');
https://github.com/TYPO3/TYPO3.CMS/blob/90fa470e37d013769648a17a266eb3072dea4f56/typo3/sysext/extbase/Classes/Configuration/BackendConfigurationManager.php#L132
This will usually be set, but in an itemsProcFunc it may not (which was the case for me in TYPO3 10.4.14).

Lua: addEventListner cannot be nil:nil stack traceback

ok, I've been starring at this error message for better part of a day now.
I'm trying to make a simple eventlistner to run when someone touches a button. The problem is that hower ever I decided to name it it says it's nil and cannot be used.
I'm working on a scene with the name "scene", self.view named "sceneGroup". The rectangle I try to add a listner to is called "mMnew" and is in the group called "mMnewU".
I've tried to change the name between all of those. At first I hade problem with adding the eventlistener but solved it, problem was not the same sulution worked for the listners name.
Listner:
function scene.mMnewUeser:touch(event)
if(event.phase == "begun")then
local test1 = display.newRect(100,150,40,40)
test1:setFillColor(0,1,0)
print("Touch found")
end
end
Added listner:
scene:addEventListener("touch", scene.mMnewUeser)
I'm still pretty green with this language and used to code in JavaC, php, html, sql and AS3.0. Sorry for my rockie problems!
UPDATE:
After adding a few simple checkpoints check in the code, it would seam that it refuses to run the function scene:create(event) my scene does hwoerver get created by local composer = require("composer")
local scene = composer.newScene()
This
function scene.mMnewUeser:touch(event)
is not the correct syntax. You probably meant to have:
function scene:mMnewUeser(event)
which means you're adding new method with a name mMnewUeser to scene object. Then you can just use it as touch listener the way you did in the last line of code. See an explanation of the difference between . and : here.

Why data is not send by form submitting (zf2 forms + filters)?

I have problem:
When I fill in form and pressing add button page is reloaded, but no data is added to the database.
Code of NewsController, add action is below:
public function addAction() {
$form = new AddNewsForm();
$form->get('submit')->setValue('Add1');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
var_dump($form->isValid());
if ($form->isValid()) {
echo "form is valid";
$objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$blogpost = new NewsItem();
$blogpost->exchangeArray($form->getData());
$blogpost->setCreated(time());
$blogpost->setUserId(0);
$objectManager->persist($blogpost);
$objectManager->flush();
// Redirect to list of blogposts
return $this->redirect()->toRoute('news');
}
}
return array('form' => $form);
}
Class AddNewsForm is included as use \News\Form\AddNewsForm as AddNewsForm; above.
I tried to debug my code and realized, that $form->isValid() return false all time. I tried to fill in all fields of form — it says that form is not valid. If not all fields are filled in it false too.
The problem is with validation, I think, so I will add here how I assing filter to the form. This is how I assing filter to my form:
$this->setInputFilter(new AddNewsInputFilter());
Class AddNewsInputFilter is included by this:
use \News\Form\AddNewsInputFilter as AddNewsInputFilter;
I don't think it is good to paste there ~100 lines of code, so I will just give a link to files in my github repo (full code of controllers/files available here):
AddNewsForm.php — file, where I create the form
AddNewsInputFilter.php — file, where I set fil
NewsController.php — file, controller, where I call created form
Repository link — root dir of my module
So the problem is that $form->isValid(); doesn't show is form valid or not properly and I don't know why. Note, that request is getting properly and first condition is passed (but second is not passed). It is the problem, thats why I am writing here.
How I can solve it?
Thanks is advance!
try var_dump($form->getMessages()) and var_dump($form->getInputFilter()->getMessages()) in controller(after calling $form->isValid()) or in view . see what error you getting and on witch element ?
NOTICE : getMessages() will be empty if $form->isValid() has not been called yet,
UPDATE : do this in controller :
var_dump($form->isValid());
var_dump($form->getMessages())
var_dump($form->getInputFilter()->getMessages())

Zend Framework 2 Get controller name from layout

I have the follow routes to different controllers and actions, that all shows the same layout and different views, example:
http://<my domain>/controllername1/action1
http://<my domain>/controllername1/
http://<my domain>/controllername2/action1
http://<my domain>/controllername3/action1
How can I get the controller name that loads the Layout in the Layout code?, something that returns: "controllername1", "controllername2" or "controllername3"
The goal is to identify in which section I'm of my site and make some customization in layout.
I checked similar replies but are for old versions of Zend Framework.
Clarification:
The idea is to get the controller name from the Layout code, not pass it from the controller code. Maybe isn't possible? Other answers are for older versions of ZendFramework (beta versions), and maybe is a more straightforward way now.
Edited: more information
I can set in my Module.php file the follow code on onBootstrap($e):
public function onBootstrap($e)
{
// (...) Other code
$application = $e->getParam('application');
$viewModel = $application->getMvcEvent()->getViewModel();
// Parsing URI to get controller name
$viewModel->controllerName = trim($_SERVER['REQUEST_URI'],'/');
if (substr_count($viewModel->controllerName, '/')) {
$viewModel->controllerName = substr($viewModel->controllerName, 0, strpos($viewModel->controllerName, '/'));
}
}
And then from the Layout code use it as follow:
echo $this->layout()->controllerName;
The first problem is that the follow piece of code should be replaced with something (more "beautiful") using ZF2 functions to get Controller name:
(...)
// Parsing URI to get controller name
$viewModel->controllerName = trim($_SERVER['REQUEST_URI'],'/');
if (substr_count($viewModel->controllerName, '/')) {
$viewModel->controllerName = substr($viewModel->controllerName, 0, strpos($viewModel->controllerName, '/'));
}
I want to avoid inject the Controller name from all controllers/actions: that is solved by using Module.php, but maybe is a more direct way.
Thanks!
You're looking for this link: How to get the controller name, action name in Zend Framework 2
$this->getEvent()->getRouteMatch()->getParam('action', 'index');
$this->getEvent()->getRouteMatch()->getParam('controller', 'index');
Otherwise you have the same question (and answer(s)) here : ZF2 - Get controller name into layout/views
MvcEvent – get NAMESPACE / Module Name from Layout
http://samsonasik.wordpress.com/2012/07/27/zend-framework-2-mvcevent-layout-view-get-namespace/
I didn't test but it seems correct : http://pastebin.com/HXbVRwTi
I know that this is an old question but there is a simple answer that should be noted here:
$this->getHelperPluginManager()->getServiceLocator()->get('Application')->getMvcEvent()->getRouteMatch()->getParam('action')
this will return any route param, 'action' in this case.
This code can be used in view or in layout.

magento display request url

i wanted to display the module,controller,method being called
i thought that the cms module found in the
app\code\core\Mage\cms\
calls the IndexController.php and uses the IndexAction method .since it is the default page url.
but when I tried to echo out something inside the IndexAction method .nothing comes out. I even tried to call it manually and it still redirects to the home page.
localhost/magento/index.php/cms/index/index/
am i doing it right?
how can i display the request url being called in magento?
I was looking for this also, here's how to do it:
echo Mage::helper('core/url')->getCurrentUrl();
Hi you could try to output the following
<?php
echo Mage::app()->getRequest()->getModuleName();
echo Mage::app()->getRequest()->getControllerName();
echo Mage::app()->getRequest()->getActionName();
?>
Not tested but maybe you can do something like this
<?php
echo Mage::app()->getRequest()->getRequestUri();
?>
Hope this helps
greetings
I needed the URL segments, so I used this:
function getUrlSegment($i) {
$_baseUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
$_currentUrl = Mage::helper('core/url')->getCurrentUrl();
$_path = str_replace($_baseUrl, '', $_currentUrl);
$_segments = explode('/', rtrim($_path, '/'));
return $_segments[$i];
}
// Would get 'store' if URL: http://example.com/store/product/123
$root = getUrlSegment(1);
You might be getting 'headers already sent' warnings in your log files using an echo in the controller. Instead of using echo use Mage::log, e.g.
Mage::log('My request url is: '.$requestUrl);
The log line should appear in the /var/logs/system.log file.
The route cms/index/index is only ever used for the home page. Other standard pages like "no-route" and "enable-cookies" are optionally handled by specific actions on the IndexController. The remaining pages are handled by Mage_Cms_PageController::viewAction() instead. Try the path cms/page/view/id/customer-service to see. The parameter is id and so the next term customer-service is the page identifier which you set in the admin as "URL Key".

Resources