From e64e008aade651b7513fcf325e5539e588e23343 Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Wed, 30 May 2012 14:21:10 +0000 Subject: [PATCH] Protect dashboard/dashlets against exceptions, with a graceful degradation for non-existing classes SVN:trunk[2072] --- application/dashboardlayout.class.inc.php | 2 +- application/dashlet.class.inc.php | 228 +++++++++++++++------- 2 files changed, 157 insertions(+), 73 deletions(-) diff --git a/application/dashboardlayout.class.inc.php b/application/dashboardlayout.class.inc.php index 41509813e..271fb9b14 100644 --- a/application/dashboardlayout.class.inc.php +++ b/application/dashboardlayout.class.inc.php @@ -99,7 +99,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout { if ($oDashlet->IsVisible()) { - $oDashlet->DoRender($oPage, $bEditMode, $aExtraParams); + $oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams); } } } diff --git a/application/dashlet.class.inc.php b/application/dashlet.class.inc.php index fbb038641..e3e60cba1 100644 --- a/application/dashlet.class.inc.php +++ b/application/dashlet.class.inc.php @@ -109,20 +109,47 @@ abstract class Dashlet } } - public function DoRender($oPage, $bEditMode = false, $aExtraParams = array()) + public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array()) { $sCSSClasses = implode(' ', $this->aCSSClasses); - if ($bEditMode) + $sId = $this->GetID(); + if ($bEnclosingDiv) { - $sId = $this->GetID(); - $oPage->add('
'); + if ($bEditMode) + { + $oPage->add('
'); + } + else + { + $oPage->add('
'); + } } - else + + try { - $oPage->add('
'); + $this->Render($oPage, $bEditMode, $aExtraParams); } - $this->Render($oPage, $bEditMode, $aExtraParams); - $oPage->add('
'); + catch(UnknownClassOqlException $e) + { + // Maybe the class is part of a non-installed module, fail silently + // Except in Edit mode + if ($bEditMode) + { + $oPage->add('
'); + $oPage->add('

Unknown Class: '.$e->GetWrongWord().', did you mean '.OqlException::FindClosestString($e->GetWrongWord(), $e->GetSuggestions()).'?

'); //TODO localize and + $oPage->add('
'); + } + } + catch(Exception $e) + { + $oPage->p($e->getMessage()); + } + + if ($bEnclosingDiv) + { + $oPage->add('
'); + } + if ($bEditMode) { $sClass = get_class($this); @@ -478,33 +505,40 @@ abstract class DashletGroupBy extends Dashlet $oField = new DesignerLongTextField('query', 'Query', $this->aProperties['query']); $oForm->AddField($oField); - // Group by field: build the list of possible values (attribute codes + ...) - $oSearch = DBObjectSearch::FromOQL($this->aProperties['query']); - $sClass = $oSearch->GetClass(); - $aGroupBy = array(); - foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) + try { - if (!$oAttDef->IsScalar()) continue; // skip link sets - - $sLabel = $oAttDef->GetLabel(); - if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) + // Group by field: build the list of possible values (attribute codes + ...) + $oSearch = DBObjectSearch::FromOQL($this->aProperties['query']); + $sClass = $oSearch->GetClass(); + $aGroupBy = array(); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { - $sLabel = $oAttDef->GetLabel().' (strict)'; - } - - $aGroupBy[$sAttCode] = $sLabel; - - if ($oAttDef instanceof AttributeDateTime) - { - $aGroupBy[$sAttCode.':hour'] = $oAttDef->GetLabel().' (hour)'; - $aGroupBy[$sAttCode.':month'] = $oAttDef->GetLabel().' (month)'; - $aGroupBy[$sAttCode.':day_of_week'] = $oAttDef->GetLabel().' (day of week)'; - $aGroupBy[$sAttCode.':day_of_month'] = $oAttDef->GetLabel().' (day of month)'; + if (!$oAttDef->IsScalar()) continue; // skip link sets + + $sLabel = $oAttDef->GetLabel(); + if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) + { + $sLabel = $oAttDef->GetLabel().' (strict)'; + } + + $aGroupBy[$sAttCode] = $sLabel; + + if ($oAttDef instanceof AttributeDateTime) + { + $aGroupBy[$sAttCode.':hour'] = $oAttDef->GetLabel().' (hour)'; + $aGroupBy[$sAttCode.':month'] = $oAttDef->GetLabel().' (month)'; + $aGroupBy[$sAttCode.':day_of_week'] = $oAttDef->GetLabel().' (day of week)'; + $aGroupBy[$sAttCode.':day_of_month'] = $oAttDef->GetLabel().' (day of month)'; + } } + + $oField = new DesignerComboField('group_by', 'Group by', $this->aProperties['group_by']); + $oField->SetAllowedValues($aGroupBy); + } + catch(Exception $e) + { + $oField = new DesignerTextField('group_by', 'Group by', $this->aProperties['group_by']); } - - $oField = new DesignerComboField('group_by', 'Group by', $this->aProperties['group_by']); - $oField->SetAllowedValues($aGroupBy); $oForm->AddField($oField); $aStyles = array( @@ -522,19 +556,26 @@ abstract class DashletGroupBy extends Dashlet { if (in_array('query', $aUpdatedFields)) { - $sCurrQuery = $aValues['query']; - $oCurrSearch = DBObjectSearch::FromOQL($sCurrQuery); - $sCurrClass = $oCurrSearch->GetClass(); - - $sPrevQuery = $this->aProperties['query']; - $oPrevSearch = DBObjectSearch::FromOQL($sPrevQuery); - $sPrevClass = $oPrevSearch->GetClass(); - - if ($sCurrClass != $sPrevClass) + try + { + $sCurrQuery = $aValues['query']; + $oCurrSearch = DBObjectSearch::FromOQL($sCurrQuery); + $sCurrClass = $oCurrSearch->GetClass(); + + $sPrevQuery = $this->aProperties['query']; + $oPrevSearch = DBObjectSearch::FromOQL($sPrevQuery); + $sPrevClass = $oPrevSearch->GetClass(); + + if ($sCurrClass != $sPrevClass) + { + $this->bFormRedrawNeeded = true; + // wrong but not necessary - unset($aUpdatedFields['group_by']); + $this->aProperties['group_by'] = ''; + } + } + catch(Exception $e) { $this->bFormRedrawNeeded = true; - // wrong but not necessary - unset($aUpdatedFields['group_by']); - $this->aProperties['group_by'] = ''; } } $oDashlet = parent::Update($aValues, $aUpdatedFields); @@ -584,27 +625,34 @@ abstract class DashletGroupBy extends Dashlet $oField = new DesignerHiddenField('query', 'Query', $sOQL); $oForm->AddField($oField); - - // Group by field: build the list of possible values (attribute codes + ...) - $oSearch = DBObjectSearch::FromOQL($this->aProperties['query']); - $sClass = $oSearch->GetClass(); - $aGroupBy = array(); - foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) + + try { - if (!$oAttDef->IsScalar()) continue; // skip link sets - if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) continue; // skip external keys - $aGroupBy[$sAttCode] = $oAttDef->GetLabel(); - - if ($oAttDef instanceof AttributeDateTime) + // Group by field: build the list of possible values (attribute codes + ...) + $oSearch = DBObjectSearch::FromOQL($this->aProperties['query']); + $sClass = $oSearch->GetClass(); + $aGroupBy = array(); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { - //date_format(start_date, '%d') - $aGroupBy['date_of_'.$sAttCode] = 'Day of '.$oAttDef->GetLabel(); + if (!$oAttDef->IsScalar()) continue; // skip link sets + if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) continue; // skip external keys + $aGroupBy[$sAttCode] = $oAttDef->GetLabel(); + + if ($oAttDef instanceof AttributeDateTime) + { + //date_format(start_date, '%d') + $aGroupBy['date_of_'.$sAttCode] = 'Day of '.$oAttDef->GetLabel(); + } + } - + $oField = new DesignerComboField('group_by', 'Group by', $this->aProperties['group_by']); + $oField->SetAllowedValues($aGroupBy); + } + catch(Exception $e) + { + $oField = new DesignerTextField('group_by', 'Group by', $this->aProperties['group_by']); } - $oField = new DesignerComboField('group_by', 'Group by', $this->aProperties['group_by']); - $oField->SetAllowedValues($aGroupBy); $oForm->AddField($oField); $oField = new DesignerHiddenField('style', '', $this->aProperties['style']); @@ -906,30 +954,66 @@ class DashletHeaderDynamic extends Dashlet $oField = new DesignerTextField('query', 'Query', $this->aProperties['query']); $oForm->AddField($oField); - // Group by field: build the list of possible values (attribute codes + ...) - $oSearch = DBObjectSearch::FromOQL($this->aProperties['query']); - $sClass = $oSearch->GetClass(); - $aGroupBy = array(); - foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) + try { - if (!$oAttDef->IsScalar()) continue; // skip link sets - - $sLabel = $oAttDef->GetLabel(); - if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) + // Group by field: build the list of possible values (attribute codes + ...) + $oSearch = DBObjectSearch::FromOQL($this->aProperties['query']); + $sClass = $oSearch->GetClass(); + $aGroupBy = array(); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { - $sLabel = $oAttDef->GetLabel().' (strict)'; + if (!$oAttDef->IsScalar()) continue; // skip link sets + + $sLabel = $oAttDef->GetLabel(); + if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) + { + $sLabel = $oAttDef->GetLabel().' (strict)'; + } + + $aGroupBy[$sAttCode] = $sLabel; } - - $aGroupBy[$sAttCode] = $sLabel; + $oField = new DesignerComboField('group_by', 'Group by', $this->aProperties['group_by']); + $oField->SetAllowedValues($aGroupBy); + } + catch(Exception $e) + { + $oField = new DesignerTextField('group_by', 'Group by', $this->aProperties['group_by']); } - $oField = new DesignerComboField('group_by', 'Group by', $this->aProperties['group_by']); - $oField->SetAllowedValues($aGroupBy); $oForm->AddField($oField); $oField = new DesignerTextField('values', 'Values (CSV list)', $this->aProperties['values']); $oForm->AddField($oField); } + public function Update($aValues, $aUpdatedFields) + { + if (in_array('query', $aUpdatedFields)) + { + try + { + $sCurrQuery = $aValues['query']; + $oCurrSearch = DBObjectSearch::FromOQL($sCurrQuery); + $sCurrClass = $oCurrSearch->GetClass(); + + $sPrevQuery = $this->aProperties['query']; + $oPrevSearch = DBObjectSearch::FromOQL($sPrevQuery); + $sPrevClass = $oPrevSearch->GetClass(); + + if ($sCurrClass != $sPrevClass) + { + $this->bFormRedrawNeeded = true; + // wrong but not necessary - unset($aUpdatedFields['group_by']); + $this->aProperties['group_by'] = ''; + } + } + catch(Exception $e) + { + $this->bFormRedrawNeeded = true; + } + } + return parent::Update($aValues, $aUpdatedFields); + } + static public function GetInfo() { return array(