Protect \iApplicationUIExtension::EnumAllowedActions uses (#214)

Some impl just return null while we expect to have an array... This is causing PHP notices in lots of iTop instances with modules implementing this method incorrectly !

This modification get rid of the notice and : 
* add a log (warning level) indicating the impl classes
* if dev env, then throw an exception after browsing all impl (so you get a complete invalid impl list)

Note : since iTop 2.7.0 you should use \AbstractApplicationUIExtension instead of implementing the whole interface !
This commit is contained in:
Pierre Goiffon
2021-05-19 14:58:55 +02:00
committed by Eric
parent 8b591a5c0a
commit 1fbb94e265

View File

@@ -1992,13 +1992,9 @@ class MenuBlock extends DisplayBlock
$this->AddMenuSeparator($aRegularActions);
/** @var \iApplicationUIExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
$oSet->Rewind();
foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) {
$aRegularActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl) + $aActionParams;
}
}
$this->GetEnumAllowedActions($oSet, function ($sLabel, $data) use (&$aRegularActions, $aActionParams) {
$aRegularActions[$sLabel] = array('label' => $sLabel, 'url' => $data) + $aActionParams;
});
}
break;
@@ -2100,24 +2096,20 @@ class MenuBlock extends DisplayBlock
$this->AddMenuSeparator($aRegularActions);
/** @var \iApplicationUIExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
$oSet->Rewind();
foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) {
if (is_array($data)) {
// New plugins can provide javascript handlers via the 'onclick' property
//TODO: enable extension of different menus by checking the 'target' property ??
$aRegularActions[$sLabel] = [
'label' => $sLabel,
'url' => isset($data['url']) ? $data['url'] : '#',
'onclick' => isset($data['onclick']) ? $data['onclick'] : '',
];
} else {
// Backward compatibility with old plugins
$aRegularActions[$sLabel] = ['label' => $sLabel, 'url' => $data] + $aActionParams;
}
$this->GetEnumAllowedActions($oSet, function ($sLabel, $data) use (&$aRegularActions, $aActionParams) {
if (is_array($data)) {
// New plugins can provide javascript handlers via the 'onclick' property
//TODO: enable extension of different menus by checking the 'target' property ??
$aRegularActions[$sLabel] = [
'label' => $sLabel,
'url' => isset($data['url']) ? $data['url'] : '#',
'onclick' => isset($data['onclick']) ? $data['onclick'] : '',
];
} else {
// Backward compatibility with old plugins
$aRegularActions[$sLabel] = ['label' => $sLabel, 'url' => $data] + $aActionParams;
}
}
});
if (empty($sRefreshAction) && $this->m_sStyle == 'list') {
//for the detail page this var is defined way beyond this line
@@ -2317,10 +2309,61 @@ class MenuBlock extends DisplayBlock
return $oRenderBlock;
}
/**
* If an extension doesn't return an array as expected :
* - calls IssueLog:Warning
*
* @param \DBObjectSet $oSet
* @param callable $callback EnumAllowedActions returns an array, we will call this anonymous function on each of its value
* with two parameters : label (array index), data (array value)
*
* @throws \Exception
*
* @uses \MetaModel::EnumPlugins()
* @uses \iApplicationUIExtension::EnumAllowedActions()
*
* @since 3.0.0
*/
private function GetEnumAllowedActions(DBObjectSet $oSet, callable $callback)
{
$aInvalidExtensions = [];
/** @var \iApplicationUIExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
$oSet->Rewind();
$aExtEnumAllowedActions = $oExtensionInstance->EnumAllowedActions($oSet);
if (!is_array($aExtEnumAllowedActions)) {
$aInvalidExtensions[] = get_class($oExtensionInstance);
continue;
}
foreach ($aExtEnumAllowedActions as $sLabel => $data) {
$callback($sLabel, $data);
}
}
if (!empty($aInvalidExtensions)) {
$sMessage = 'Some extensions returned non array value for EnumAllowedActions() method impl';
IssueLog::Warning(
$sMessage,
null,
['extensions' => $aInvalidExtensions]
);
if (utils::IsDevelopmentEnvironment()) {
throw new CoreUnexpectedValue($sMessage, $aInvalidExtensions);
}
}
}
/**
* Appends a menu separator to the current list of actions
*
* @param array $aActions The current actions list
*
* @return void
*/
protected function AddMenuSeparator(&$aActions)