Symfony cmf v1.1 upgrade - symfony-cmf

I am trying to upgrade the symfony cmf bundles from v1.0 to v1.1 in our project.
composer.json before upgrade:
"doctrine/phpcr-odm": "1.1.0-RC1 as 1.0",
"doctrine/phpcr-bundle": "1.1.0-beta1 as 1.0",
"phpcr/phpcr-utils": "1.1.0 as 1.0",
"symfony-cmf/routing-auto-bundle": "1.0.*#alpha",
"symfony-cmf/menu-bundle": "1.0.*",
"symfony-cmf/block-bundle": "1.0.*",
"symfony-cmf/routing-bundle": "1.1.*",
"jackalope/jackalope-jackrabbit": "1.1.*",
"sonata-project/doctrine-phpcr-admin-bundle": "1.0.*",
composer.json after upgrade:
"doctrine/phpcr-bundle": "1.1.*",
"doctrine/phpcr-odm": "1.1.*",
"symfony-cmf/routing-auto-bundle": "1.0.*#alpha",
"symfony-cmf/routing-bundle": "1.2.0 as 1.1.0",
"symfony-cmf/core-bundle": "1.1.0 as 1.0.0",
"symfony-cmf/menu-bundle": "1.1.*",
"symfony-cmf/block-bundle": "1.1.*",
"jackalope/jackalope-jackrabbit": "1.1.*",
"sonata-project/doctrine-phpcr-admin-bundle": "1.1.*",
As you can see I am using composer aliasing in both places in order to be able to use symfony-cmf/routing-auto-bundle. This aliasing method is the only way I was able to use the symfony-cmf/routing-auto-bundle.
So after doing composer update with above changes I have some failing tests in the sonata admin area of the project.
By doing some debugging I saw the below changes.
screenshot before
screenshot after
Below is how I load the Page fixtures.
<?php // load Page fixtures
protected function create($dm, $class, $parent_path, $data_file)
{
$parent = $dm->find(null, $parent_path);
$data = $this->getData($data_file);
foreach ($data as $item)
{
$doc = new $class();
$doc->setParent($parent);
if (is_array($item['title'])) {
foreach ($item['title'] as $locale => $title) {
$doc = $this->createDoc($doc, $title, $item['body'][$locale], $locale);
$dm->persist($doc);
$dm->bindTranslation($doc, $locale);
}
} else {
$doc = $this->createDoc($doc, $item['title'], $item['body']);
$dm->persist($doc);
}
}
$dm->flush();
}
protected function createDoc($doc, $title, $body, $locale = 'en')
{
$doc->setTitle($title);
$doc->setContent($body);
$doc->setlocale($locale);
return $doc;
}
My questions are:
I have used bindTranslation() method in my fixtures. Has that method changed in
cmf v1.1? Is that why I can't see the fields in the admin interface? (I am not using simple-cms-bundle or content-bundle.)
This is un-related to above. Should I continue to use
RoutingAutoBundle? (Because I don't see many questions about it on SO.
So I think perhaps people are not using it much)
I appreciate any sort of advice you can give me about using cmf bundles in our project.
BTW: I've also read the github issue update to 1.1.0-RC1 by #lsmith77 so please don't point me to that ;)
Please help! I'm here if you need further details.
Thank you.

bindTranslation was not supposed to change, so if that would be the problem, it would be a regression. You can investigate whether its a problem with the fixtures or later by looking at the output of app/console doctrine:phpcr:node:dump --props /parent/path. Is the list empty regardless of the language you request it?
Did you configure multilang on both cmf_core and doctrine_phpcr?
You could further investigate by loading a document in a controller or command and checking what the content document contains in that case.
For the discussion of routing auto bundle, best come to the mailinglist http://groups.google.com/group/symfony-cmf-devs . It should still happen but it seems we miss somebody to finalize it.

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).

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

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.

How to view db queries generated by TableGateway in Zend Framework 2

I am brand new to ZF2 and am trying to use a tableGateway to manage and update entries in a database. I am able to select and update items without a problem, but when inserting I get an error. Since the tableGateway class creates the query on the fly, how can I see the query itself?
$this->tableGateway->insert($data);
An error occurred during execution; please try again later.
Additional information:
Zend\Db\Adapter\Exception\InvalidQueryException
File:
/[redacted]/vendor/zendframework/zendframework/library/Zend/Db/Adapter/Driver/Pdo/Statement.php:220
Message:
Statement could not be executed
Just some notices to #zdenek-machek answer:
1) To profile database queries, BjyProfiler module should be installed too.
2) (skip if you use PDO) When I used BjyProfiler last time, there was an issue with mysqli connection (buffer_results option was not passed to ProfilingStatement class). Maybe it is fixed now, or I set it up in the wrong way, but my patch is to manually pass this parameter in BjyProfiler/src/BjyProfiler/Db/Adapter/ProfilingAdapter.php:
case 'Zend\Db\Adapter\Driver\Mysqli\Mysqli':
$statementPrototype = new Driver\Mysqli\ProfilingStatement($this->options['buffer_results']);
break;
3) ZendDeveloperTools displays count of queries, but doesn't list them. To list in the bottom of the page, I have modified view/zend-developer-tools/toolbar/toolbar.phtml in the following way:
<!-- END Zend Developer Toolbar -->
<?php
$queryProfiles = $this->getHelperPluginManager()->getServiceLocator()
->get('Zend\Db\Adapter\Adapter')->getProfiler()->getQueryProfiles();
echo '<ol>';
foreach($queryProfiles as $queryObj)
{
$query = $queryObj->toArray();
echo '<li>';
echo '<b>' . ($query['elapsed']*1000) . '</b> ms<br/>';
echo $query['sql'];
if(count($query['parameters']))
{
echo '<br/><i>Parameters:</i> ';
$list = array();
foreach($query['parameters'] as $key => $value)
$list[] = '?'. $this->escapeHtml($key)
."='". $this->escapeHtml($value) ."'";
echo implode(', ', $list);
}
echo '</li>';
}
echo '</ol>';
In my case I just covered this in one in try catch: $e->__toString() was the key
try {
this->tableGateway->insert($data);
} catch (\Exception $e) {
\Zend\Debug\Debug::dump($e->__toString()); exit;
}
Very elegant way how to see db queries is to use zend-developer-tools.
Easiest way how to use it is to install module by adding it to composer.json file
.....
"repositories": [
{
"type": "composer",
"url": "http://packages.zendframework.com/"
}
],
"require": {
"php": ">=5.3.3",
"zendframework/zend-developer-tools": "dev-master"
}
see documentation
For what I wanted to do, in Dev, which was to know exactly which queries were run associated to every step in the flow of my processes, this is what I did (using PDO with MySQL / MariaDB):
I went to the Statement class (vendor/zendframework/zendframework/library/Zend/Db/Adapter/Driver/Pdo/Statement.php)
I went to the execute method and just before it is executed I put:
...
error_log("DebugQ: ".print_r($this->getSql(),1).", ".print_r($this->getParameterContainer()->getNamedArray(),1));
try {
$this->resource->execute();
}
...
I wanted a quick and disposable solution to have the queries logged in the error logs. I was able to have all the queries and their conditions.

How to get the comments of a JIRA issue in a custom release note template

We upgraded our jira to version 5.0.5 today, before we were running version 4.2.4. In that version we had made a custom release notes template that would also show all comments made on an issue. To do that we had to be able to get a CommentManager object. We did this like this:
#foreach ($issue in $issueType.issues)
#if($issueType.issues.size() > 0)
#set ($comments = $action.ComponentManager.CommentManager.getComments($issue))
#if ($comments)
#foreach ($comment in $comments)
...
That worked fine in JIRA 4.2.4 however it isn't working anymore in jira 5.0.5, does anyone know how i can get a CommentManager object again when creating a custom release notes template in JIRA 5.0.5 or how to get a CommentManager object some other way, without using $action for example?
In your vm template, write this:
#set ($componentAccessorClass = $constantsManager.getClass().getClassLoader().findClass('com.atlassian.jira.component.ComponentAccessor'))
#set ($componentAccessorConstructor = $componentAccessorClass.getConstructor())
#set ($componentAccessor = $componentAccessorConstructor.newInstance())
Now you have access to the Component Accessor which can get you pretty much anything you want, including the Comment Manager.
Now, all you have to do is call getCommentManager() on your Component Accessor variable.
#set($commentManager = $componentAccessor.getCommentManager() )
Hope that helps ! :)
JiraWebActionSupport has the following deprecated method that provided the component manager object.
#Deprecated
public ComponentManager getComponentManager()
{
return ComponentManager.getInstance();
}
and https://developer.atlassian.com/display/JIRADEV/Creating+a+Custom+Release+Notes+Template+Containing+Release+Comments
has some Velocity code but looking at the 5.0.1 source it looks like Velocity is no longer being used?
I would file an Improvement at https://jira.atlassian.com/browse/JRA to add a getCommentManager method to JiraWebActionSupport.java
this is the way i used in jira to get a componentmanager object, once you have the componentmanager object it's rather easy to do the rest:
#set ($componentManagerClass = $constantsManager.getClass().getClassLoader().findClass('com.atlassian.jira.ComponentManager'))
#set ($method = $componentManagerClass.getDeclaredMethod('getInstance', null))
#set ($componentManager = $method.invoke(null, null))
i'm using this solution now, and it can be rather helpfull to others to almost get any kind of class using the constantsmanager.

Symfony: issue with switching context

I am using Symfony 1.2 and I have some issues switching context.
This code was working fine:
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('account', 'prod', false);
$context = sfContext::createInstance($configuration, 'account-prod');
$userToLogin = PcUserPeer::retrieveByEmailAddress("myemail#example.com");
Auth::login($context->getUser(), $userToLogin, false, false);
echo "all done.";
At some point requirements changed and I needed to use the 'public' application before the 'account' one.
Then I changed to:
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
// {{{ new code:
$configuration = ProjectConfiguration::getApplicationConfiguration('public', 'prod', false);
sfContext::createInstance($configuration);
// some code using the public app...
// }}}
$configuration = ProjectConfiguration::getApplicationConfiguration('account', 'prod', false);
$context = sfContext::createInstance($configuration, 'account-prod');
// {{{ new code:
sfContext::switchTo('account-prod');
// }}}
$userToLogin = PcUserPeer::retrieveByEmailAddress("myemail#example.com");
CustomAuth::login($context->getUser(), $userToLogin, false, false);
echo "all done.";
Basically I added a switchTo call.
After the change, the code got broken and the error message is this:
PHP Fatal error: Call to a member function prepare() on a non-object in /var/www/html/myproj/symfony/storage/sfPDOSessionStorage.class.php on line 109
Thanks for your help,
Dan
Symfony is trying to load the session storage object. I suppose there is a problem with your new environment's configuration.
Check
/apps/public/config/factories.yml
Look for "storage" and try to find out how is it different from the other app's configuration.
Hard to know without a backtrace/more info what is triggering the error. It looks like you are using sessions stored in a database, and that a query related to that is failing.
Try setting the third argument to getApplicationConfiguration to true (which will turn debug on) and see if you get more output.
At a guess, it looks like the account app is using PDO session storage, and is failing to connect to the database or something?

Resources