Error accessing SocialEngine Groups
David CoxUsers have recently reported receiving error messages when accessing Groups on a website built on the SocialEngine platform. The site was recently upgraded to SocialEngine 4.1.7 from 4.1.3
The Error
The error messages the users received weren’t very detailed (as usual). This is the relevant message found in the log file:
2011-09-16T03:15:03+00:00 ERR (3): [4096] Object of class Zend_View_Helper_Translate could not be converted to string (/socialengine-root/application/libraries/Engine/View/Helper/HtmlLink.php) [51]
Error Code: a0dceb
Stack trace:
#0 (unknown file)(0): Engine_View_Helper_HtmlLink->htmlLink(Array, Zend_View_Helper_Translate)
#1 /socialengine-root/application/libraries/Zend/View/Abstract.php(342): call_user_func_array(Array, Array)
#2 (unknown file)(0): Zend_View_Abstract->__call('htmlLink', Array)
#3 /socialengine-root/application/modules/Group/widgets/profile-info/index.tpl(22): Zend_View->htmlLink(Array, Zend_View_Helper_Translate)
#4 /socialengine-root/application/libraries/Zend/View.php(108): include('/socialengine-root/applicatio...')
#5 /socialengine-root/application/libraries/Zend/View/Abstract.php(835): Zend_View->_run('/socialengine-root/applicatio...')
#6 /socialengine-root/application/libraries/Engine/Content/Widget/Abstract.php(292): Zend_View_Abstract->render('application/modules/Group/widget...')
#7 /socialengine-root/application/libraries/Engine/Content/Widget/Abstract.php(258): Engine_Content_Widget_Abstract->renderScript()
#8 /socialengine-root/application/libraries/Engine/Content/Element/Widget.php(66): Engine_Content_Widget_Abstract->render()
#9 /socialengine-root/application/libraries/Engine/Content/Element/Abstract.php(583): Engine_Content_Element_Widget->_render()
#10 /socialengine-root/application/libraries/Engine/Content/Decorator/Children.php(31): Engine_Content_Element_Abstract->render()
#11 /socialengine-root/application/libraries/Engine/Content/Element/Abstract.php(594): Engine_Content_Decorator_Children->render('')
#12 /socialengine-root/application/libraries/Engine/Content/Decorator/Children.php(31): Engine_Content_Element_Abstract->render()
#13 /socialengine-root/application/libraries/Engine/Content/Element/Abstract.php(594): Engine_Content_Decorator_Children->render('')
#14 /socialengine-root/application/libraries/Engine/Content/Decorator/Children.php(31): Engine_Content_Element_Abstract->render()
#15 /socialengine-root/application/libraries/Engine/Content/Element/Abstract.php(594): Engine_Content_Decorator_Children->render('')
#16 /socialengine-root/application/libraries/Engine/Content.php(207): Engine_Content_Element_Abstract->render()
#17 /socialengine-root/application/libraries/Engine/Content/Controller/Action/Helper/Content.php(136): Engine_Content->render('group_profile_index')
#18 /socialengine-root/application/libraries/Engine/Content/Controller/Action/Helper/Content.php(38): Engine_Content_Controller_Action_Helper_Content->render()
#19 /socialengine-root/application/libraries/Zend/Controller/Action/HelperBroker.php(277): Engine_Content_Controller_Action_Helper_Content->postDispatch()
#20 /socialengine-root/application/libraries/Zend/Controller/Action.php(523): Zend_Controller_Action_HelperBroker->notifyPostDispatch()
#21 /socialengine-root/application/libraries/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('indexAction')
#22 /socialengine-root/application/libraries/Zend/Controller/Front.php(946): Zend_Controller_Dispatcher_Standard->dispatch(Zend_Controller_Request_Http, Zend_Controller_Response_Http)
#23 /socialengine-root/application/modules/Core/Bootstrap.php(75): Zend_Controller_Front->dispatch()
#24 /socialengine-root/application/libraries/Engine/Application.php(99): Core_Bootstrap->run()
#25 /socialengine-root/application/index.php(177): Engine_Application->run()
#26 /socialengine-root/index.php(24): include('/socialengine-root/applicatio...')
#27 {main}
It’s the #3 line of the stack trace that most closely relates to groups, so that’s probably a good place to start. Because it’s Zend_View_Helper_Translate that’s have the issue, and because Zend_View_Helper_Translate is the second parameter passed to the Zend_View->htmlLink() method, let’s see where Zend_View_Helper_Translate comes from?
Here’s line 22 of the specified file:
<?php echo $this->htmlLink(array('route' => 'group_general', 'action' => 'browse', 'category_id' => $this->group->category_id), $this->translate($this->group->getCategory()->title)) ?>
The entire line is the htmlLink() method (because $this is an extension of Zend_View somehow). Most of that stuff is the first parameter. The translate() method at the end must be what results in Zend_View_Helper_Translate.
So, translate() is messing up, huh? It looks like a simple function that takes the title of the category the group belongs to, and translates it in case our users are viewing the site in another language (we don’t have any other languages set up, but it’s a common feature of these out-of-the-box site platforms). I wonder what the title of the category is?
Because the frontend of the site isn’t working, I did some digging in the database. Here’s what I found:
This group’s id: 147
This groups’s category id: 1
Category 1′s title: Problem. There is no category 1.
The only possible category id’s on this site are 18, 19, and 20. Looking at all the groups in the database shows that most of them are 18, 19, or 20 (or 0, which is okay too). The most recent groups and a few of the old ones are 1. How did that happen?
The Fix (but not completely)
I did a manual query on the database to change every group with a category of 1 (which is an invalid category id for my system) to a category of 0 (meaning no category, which is valid for all systems). After making that change I was able to view the group page again.
Here’s the format of the query I ran. Your query will be unique to your system:
UPDATE `engine4_group_groups` SET `category_id`=0 WHERE `category_id`=X; // where X is the invalid category id (in my case: 1, 2, or 3)
Don’t stop here though. There’s more.
Discovering the Real Problem
After I was able to view the group pages again, I went to the group edit page. SocialEngine was giving me the right options for categories, but if I tried to save the group with a category the group started throwing error messages again (which I undid by resetting the group category in the database again).
Looking at the source code of the group edit page, I found that SocialEngine was using the numbers 1, 2, and 3 to represent my group categories instead of 18, 19, and 20. That didn’t seem right, but it could be okay as long as SocialEngine is translating them back into 18, 19, and 20.
I checked.
When you save information from the group edit page, the data eventually winds up in the editAction() method of the Group_GroupController class, found here:
/socialengine-root/application/modules/Group/controllers/IndexController.php
About 44 lines into the editAction() method there is a check to see if and data has been posted. Everything after that is done to prep and save your data. Sure enough, there is no prep work done to convert 1, 2, or 3 into actual group category ids (in my case, 18, 19, or 20).
So why is SocialEngine converting my category ids to 1, 2, and 3?
The group category options are prepared in this same method (the editAction() method of the Group_GroupController class), just closer to the beginning. On about the 10th line, SocialEngine retrieves category names from the database. I dug a little deeper and found that when the categories are retrieved from the database, they are arranged in an array with their ids as keys. It would seem like SocialEngine intends for categories to be accessed by their ids.
After the categories are retrieved from the database, they are sorted in alphabetical order. The sorting method that is used is one that keeps the existing keys in tact (just reorders them). Remember, those keys are the category ids. So again, it seems like SocialEngine wants to continue to refer to these categories by their ids.
After the categories are sorted, they’re combined with a blank entry. That blank entry is what provides the option for a group to belong to no category. The interesting thing here is that the function used to add the blank entry rewrites the keys of the categories to start at 1! Why would SocialEngine make specific efforts to preserve the category ids as keys only to rewrite them right at the end. That seems like an oversight to me.
Thanks to the magic of version control, I compared the current file to the one used before the upgrade. The old file didn’t rewrite the keys. It preserved them all the way to the end. That settles it. These category keys aren’t supposed to be rewritten. It was a sloppy update on the part of SocialEngine.
Why would SocialEngine make a sloppy modification like this? Programmers are human and humans make mistakes. If my category ids were 1, 2, and 3 (which they would be if someone hadn’t created and deleted 17 other categories in the past) this change wouldn’t have hurt me. I’m guessing the system the programmers used for their testing had group categories starting at 1 and so they never noticed the problem.
The Final Fix
While I really hate changing the files provided from the original distributor, I decided to change the editAction() method.
Here’s the code as it was before my update:
// ...
// Populate with categories
$categories = Engine_Api::_()->getDbtable('categories', 'group')->getCategoriesAssoc();
asort($categories, SORT_LOCALE_STRING);
$categories = array_merge(array('0' => ''), $categories);
$form->category_id->setMultiOptions($categories);
// ...
Here’s the code after the update:
// ...
// Populate with categories
$categories = Engine_Api::_()->getDbtable('categories', 'group')->getCategoriesAssoc();
$categories[0] = ''; // added to accomplish what the removed line was doing.
asort($categories, SORT_LOCALE_STRING);
//$categories = array_merge(array('0' => ''), $categories); // removed b/c it was renumbering category ids
$form->category_id->setMultiOptions($categories);
// ...
The first line retrieves the categories from the database. The second line adds a blank category (without affecting the original ones). The third line sorts them. The last line sets them as options.
This fixes the problem when editing existing categories, but the problem still exists when creating new groups. Make this same fix to the createAction() method of the Group_IndexController class, found here:
/socialengine-root/application/modules/Group/controllers/IndexController.php
The end.
Resolution Summary
This problem occurs when these conditions are met:
- The site is running SocialEngine 4.1.7 (perhaps earlier versions as well, but we skipped over those)
- Group categories have ids that start at something other than 1 OR are non-sequential (i.e. 1, 2, and 5)
- People create new groups or edit existing group details and have a category selected
To fix this problem:
- Update the
editAction()method of theGroup_GroupControllerclass - Update the
createAction()method of theGroup_IndexControllerclass - Reset the category ids of existing groups to valid category ids.
I hope this helps.