Reintegrated from branch 1.2: capability to develop a module to share objects between organizations (beta)

SVN:trunk[1859]
This commit is contained in:
Romain Quetiez
2012-02-17 15:11:00 +00:00
parent 92c1a4af63
commit b3dadcba77
17 changed files with 433 additions and 160 deletions

View File

@@ -274,7 +274,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
return true;
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;

View File

@@ -47,7 +47,7 @@ class UserRightsNull extends UserRightsAddOnAPI
return true;
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;

View File

@@ -659,6 +659,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oKPI = new ExecutionKPI();
if (self::HasSharing())
{
SharedObject::InitSharedClassProperties();
}
$oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Profiles"));
$this->m_aProfiles = array();
while ($oProfile = $oProfileSet->Fetch())
@@ -683,11 +688,27 @@ class UserRightsProfile extends UserRightsAddOnAPI
}
}
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
$this->m_aUserOrgs = array();
while ($oUserOrg = $oUserOrgSet->Fetch())
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
if ($sHierarchicalKeyCode !== false)
{
$this->m_aUserOrgs[$oUserOrg->Get('userid')][] = $oUserOrg->Get('allowed_org_id');
$sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.parent_id BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id';
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery));
while ($aRow = $oUserOrgSet->FetchAssoc())
{
$oUserOrg = $aRow['UserOrg'];
$oOrg = $aRow['Org'];
$this->m_aUserOrgs[$oUserOrg->Get('userid')][] = $oOrg->GetKey();
}
}
else
{
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
while ($oUserOrg = $oUserOrgSet->Fetch())
{
$this->m_aUserOrgs[$oUserOrg->Get('userid')][] = $oUserOrg->Get('allowed_org_id');
}
}
$this->m_aClassStimulusGrants = array();
@@ -742,7 +763,7 @@ exit;
}
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$this->LoadCache();
@@ -754,33 +775,10 @@ exit;
// Determine how to position the objects of this class
//
$aCallSpec = array($sClass, 'MapContextParam');
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization'))
$sAttCode = self::GetOwnerOrganizationAttCode($sClass);
if (is_null($sAttCode))
{
$sAttCode = 'id';
}
elseif (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
if ($sAttCode == null)
{
return true;
}
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
{
// Skip silently. The data model checker will tell you something about this...
return true;
}
}
elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
{
$sAttCode = 'org_id';
}
else
{
// The objects of this class are not positioned in this dimension
// All of them are visible
// No filtering for this object
return true;
}
// Position the user
@@ -796,48 +794,65 @@ exit;
$oFilter = new DBObjectSearch($sClass);
$oListExpr = ListExpression::FromScalars($aUserOrgs);
// Check if the condition points to a hierarchical key
$bConditionAdded = false;
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
$oFilter->AddConditionExpression($oCondition);
if ($sAttCode == 'id')
if (self::HasSharing())
{
// Filtering on the objects themselves
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sClass);
if ($sHierarchicalKeyCode !== false)
if (($sAttCode == 'id') && isset($aSettings['bSearchMode']) && $aSettings['bSearchMode'])
{
$oRootFilter = new DBObjectSearch($sClass);
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
$oRootFilter->AddConditionExpression($oCondition);
$oFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
$bConditionAdded = true;
}
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsExternalKey())
{
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
if ($sHierarchicalKeyCode !== false)
// Querying organizations (or derived)
// and the expected list of organizations will be used as a search criteria
// Therefore the query can also return organization having objects shared with the allowed organizations
//
// 1) build the list of organizations sharing something with the allowed organizations
// Organization <== sharing_org_id == SharedObject having org_id IN {user orgs}
$oShareSearch = new DBObjectSearch('SharedObject');
$oOrgField = new FieldExpression('org_id', 'SharedObject');
$oShareSearch->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
$oSearchSharers = new DBObjectSearch('Organization');
$oSearchSharers->AllowAllData();
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
$aSharers = array();
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
{
$oRootFilter = new DBObjectSearch($oAttDef->GetTargetClass());
$oExpression = new FieldExpression('id', $oAttDef->GetTargetClass());
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
$oRootFilter->AddConditionExpression($oCondition);
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
$oHKFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
$oFilter->AddCondition_PointingTo($oHKFilter, $sAttCode);
$bConditionAdded = true;
$aSharers[] = $aRow['id'];
}
// 2) Enlarge the overall results: ... OR id IN(id1, id2, id3)
if (count($aSharers) > 0)
{
$oSharersList = ListExpression::FromScalars($aSharers);
$oFilter->MergeConditionExpression(new BinaryExpression($oExpression, 'IN', $oSharersList));
}
}
}
if (!$bConditionAdded)
{
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
$oFilter->AddConditionExpression($oCondition);
}
$aShareProperties = SharedObject::GetSharedClassProperties($sClass);
if ($aShareProperties)
{
$sShareClass = $aShareProperties['share_class'];
$sShareAttCode = $aShareProperties['attcode'];
$oSearchShares = new DBObjectSearch($sShareClass);
$oSearchShares->AllowAllData();
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
$oOrgField = new FieldExpression('org_id', $sShareClass);
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
$aShared = array();
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
{
$aShared[] = $aRow[$sShareAttCode];
}
if (count($aShared) > 0)
{
$oObjId = new FieldExpression('id', $sClass);
$oSharedIdList = ListExpression::FromScalars($aShared);
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList));
}
}
} // if HasSharing
return $oFilter;
}
@@ -926,10 +941,76 @@ exit;
{
$this->LoadCache();
// Note: The object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
return $aObjectPermissions['permission'];
$iPermission = $aObjectPermissions['permission'];
// Note: In most cases the object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set
if ($iPermission != UR_ALLOWED_YES)
{
// It is already NO for everyone... that's the final word!
}
elseif ($iActionCode == UR_ACTION_READ)
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
}
elseif ($iActionCode == UR_ACTION_BULK_READ)
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
}
elseif ($oInstanceSet)
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
// We have to answer NO for objects shared for reading purposes
if (self::HasSharing())
{
$aClassProps = SharedObject::GetSharedClassProperties($sClass);
if ($aClassProps)
{
// This class is shared, GetSelectFilter may allow some objects for read only
// But currently we are checking wether the objects might be written...
// Let's exclude the objects based on the relevant criteria
$sOrgAttCode = self::GetOwnerOrganizationAttCode($sClass);
if (!is_null($sOrgAttCode))
{
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
if (!is_null($aUserOrgs) && count($aUserOrgs) > 0)
{
$iCountNO = 0;
$iCountYES = 0;
$oInstanceSet->Rewind();
while($oObject = $oInstanceSet->Fetch())
{
$iOrg = $oObject->Get($sOrgAttCode);
if (in_array($iOrg, $aUserOrgs))
{
$iCountYES++;
}
else
{
$iCountNO++;
}
}
if ($iCountNO == 0)
{
$iPermission = UR_ALLOWED_YES;
}
elseif ($iCountYES == 0)
{
$iPermission = UR_ALLOWED_NO;
}
else
{
$iPermission = UR_ALLOWED_DEPENDS;
}
}
}
}
}
}
return $iPermission;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
@@ -993,6 +1074,49 @@ exit;
{
$this->ResetCache();
}
/**
* Find out which attribute is corresponding the the dimension 'owner org'
* returns null if no such attribute has been found (no filtering should occur)
*/
public static function GetOwnerOrganizationAttCode($sClass)
{
$sAttCode = null;
$aCallSpec = array($sClass, 'MapContextParam');
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization'))
{
$sAttCode = 'id';
}
elseif (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
{
// Skip silently. The data model checker will tell you something about this...
$sAttCode = null;
}
}
elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
{
$sAttCode = 'org_id';
}
return $sAttCode;
}
/**
* Determine wether the objects can be shared by the mean of a class SharedObject
**/
protected static function HasSharing()
{
static $bHasSharing;
if (!isset($bHasSharing))
{
$bHasSharing = class_exists('SharedObject');
}
return $bHasSharing;
}
}

View File

@@ -734,7 +734,7 @@ exit;
return true;
}
public function GetSelectFilter($oUser, $sClass)
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$aConditions = array();
foreach ($this->m_aDimensions as $iDimension => $oDimension)

View File

@@ -115,6 +115,7 @@ class ApplicationContext
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->Count();
if ($iCount == 1)

View File

@@ -1548,7 +1548,9 @@ EOF
if ($oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass));
$oSearch = new DBObjectSearch($sTargetClass);
$oSearch->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oAllowedValues = new DBObjectSet($oSearch);
$iFieldSize = $oAttDef->GetMaxSize();
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
@@ -2382,7 +2384,7 @@ EOF
$current = HILIGHT_CLASS_NONE; // Not hilighted by default
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
{
$new = $oExtensionInstance->GetHilightClass($this);
@$current = self::$m_highlightComparison[$current][$new];
@@ -2667,7 +2669,7 @@ EOF
$this->UpdateObjectFromArray($aFinalValues);
// Invoke extensions after the update of the object from the form
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
{
$oExtensionInstance->OnFormSubmit($this, $sFormPrefix);
}

View File

@@ -462,11 +462,13 @@ EOF
// Display the list of *favorite* organizations... but keeping in mind what is the real number of organizations
$aFavoriteOrgs = appUserPreferences::GetPref('favorite_orgs', null);
$oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->Count(); // total number of existing Orgs
// Now get the list of Orgs to be displayed in the menu
$oSearchFilter = DBObjectSearch::FromOQL(ApplicationMenu::GetFavoriteSiloQuery());
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
if (!empty($aFavoriteOrgs))
{
$oSearchFilter->AddCondition('id', $aFavoriteOrgs, 'IN');
@@ -513,8 +515,8 @@ EOF
$sHtml .= '</select>';
*/
$sFavoriteOrgs = '';
$oWidget = new UIExtKeyWidget('Organization', 'org_id');
$sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'iMinChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'sDefaultValue' => Dict::S('UI:AllOrganizations')), $bSearchMode = true);
$oWidget = new UIExtKeyWidget('Organization', 'org_id', '', true /* search mode */);
$sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'iMinChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'sDefaultValue' => Dict::S('UI:AllOrganizations')));
$this->add_ready_script('$("#org_id").bind("extkeychange", function() { $("#SiloSelection form").submit(); } )');
$this->add_ready_script("$('#label_org_id').click( function() { $(this).val(''); $('#org_id').val(''); return true; } );\n");
// Add other dimensions/context information to this form

View File

@@ -66,6 +66,7 @@ class UIExtKeyWidget
protected $iId;
protected $sTargetClass;
protected $sAttCode;
protected $bSearchMode;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
@@ -82,15 +83,16 @@ class UIExtKeyWidget
{
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list
}
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode);
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, $bSearchMode, $sDisplayStyle);
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
}
public function __construct($sTargetClass, $iInputId, $sAttCode = '')
public function __construct($sTargetClass, $iInputId, $sAttCode = '', $bSearchMode = false)
{
$this->sTargetClass = $sTargetClass;
$this->iId = $iInputId;
$this->sAttCode = $sAttCode;
$this->bSearchMode = $bSearchMode;
}
/**
@@ -99,28 +101,34 @@ class UIExtKeyWidget
* @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = false, $sDisplayStyle = 'select')
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select')
{
if (!is_null($bSearchMode))
{
$this->bSearchMode = $bSearchMode;
}
$sTitle = addslashes($sTitle);
$oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bCreate = (!$this->bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true;
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($bSearchMode) ? '' : 'attr_';
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($bSearchMode)
if($this->bSearchMode)
{
$sWizHelper = 'null';
$sWizHelperJSON = "''";
$sJSSearchMode = 'true';
}
else
{
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$sWizHelperJSON = $sWizHelper.'.ToJSON()';
$sJSSearchMode = 'false';
}
if (is_null($oAllowedValues))
{
@@ -155,7 +163,7 @@ class UIExtKeyWidget
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
if ($bSearchMode)
if ($this->bSearchMode)
{
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
@@ -184,7 +192,7 @@ class UIExtKeyWidget
$sHTMLValue .= "</select>\n";
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}');
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
@@ -215,13 +223,14 @@ EOF
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}');
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter', json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
@@ -277,10 +286,10 @@ EOF
}
else
{
$aParam = array();
$aParams = array();
$oFilter = new DBObjectSearch($this->sTargetClass);
$oSet = new CMDBObjectSet($oFilter);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $this->iId));
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
@@ -319,6 +328,7 @@ EOF
try
{
$oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
}
@@ -328,6 +338,7 @@ EOF
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$sRemoteClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
//$oBlock = new DisplayBlock($oFilter, 'list', false);
//$oBlock->Display($oP, $this->iId.'_results', array('cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
}
@@ -347,6 +358,7 @@ EOF
throw new Exception('Implementation: null value for allowed values definition');
}
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
foreach($aValues as $sKey => $sFriendlyName)
{
@@ -359,8 +371,18 @@ EOF
*/
public function GetObjectName($iObjId)
{
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId);
return $oObj->GetName();
$aModifierProps = array();
$aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode;
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps);
if ($oObj)
{
return $oObj->GetName();
}
else
{
return '';
}
}
/**
@@ -421,6 +443,7 @@ EOF
try
{
$oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
}
catch(MissingQueryArgument $e)
@@ -429,6 +452,7 @@ EOF
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$this->m_sTargetClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter);
}

View File

@@ -62,8 +62,9 @@ class UILinksWidget
$this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach(MetaModel::ListAttributeDefs($this->m_sLinkedClass) as $sAttCode=>$oAttDef)
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
if ($sStateAttCode == $sAttCode)
{
// State attribute is always hidden from the UI

View File

@@ -807,7 +807,7 @@ class DBObjectSearch
public function serialize($bDevelopParams = false, $aContextParams = null)
{
$sOql = $this->ToOql($bDevelopParams, $aContextParams);
return base64_encode(serialize(array($sOql, $this->m_aParams)));
return base64_encode(serialize(array($sOql, $this->m_aParams, $this->m_aModifierProperties)));
}
static public function unserialize($sValue)
@@ -818,7 +818,9 @@ class DBObjectSearch
// We've tried to use gzcompress/gzuncompress, but for some specific queries
// it was not working at all (See Trac #193)
// gzuncompress was issuing a warning "data error" and the return object was null
return self::FromOQL($sOql, $aParams);
$oRetFilter = self::FromOQL($sOql, $aParams);
$oRetFilter->m_aModifierProperties = $aData[2];
return $oRetFilter;
}
// SImple BUt Structured Query Languag - SubuSQL

View File

@@ -220,6 +220,20 @@ class Dict
}
}
/**
* Clone a string in every language (if it exists in that language)
*/
public static function CloneString($sSourceCode, $sDestCode)
{
foreach(self::$m_aLanguages as $sLanguageCode => $foo)
{
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]))
{
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
}
}
}
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{
$aMissing = array(); // Strings missing for the target language

View File

@@ -17,6 +17,7 @@
require_once(APPROOT.'core/modulehandler.class.inc.php');
require_once(APPROOT.'core/querybuildercontext.class.inc.php');
require_once(APPROOT.'core/querymodifier.class.inc.php');
require_once(APPROOT.'core/metamodelmodifier.inc.php');
/**
* Metamodel
@@ -1172,6 +1173,33 @@ abstract class MetaModel
self::$m_sTablePrefix = $sTablePrefix;
// Build the list of available extensions
//
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization');
foreach($aInterfaces as $sInterface)
{
self::$m_aExtensionClasses[$sInterface] = array();
}
foreach(get_declared_classes() as $sPHPClass)
{
$oRefClass = new ReflectionClass($sPHPClass);
$oExtensionInstance = null;
foreach($aInterfaces as $sInterface)
{
if ($oRefClass->implementsInterface($sInterface))
{
if (is_null($oExtensionInstance))
{
$oExtensionInstance = new $sPHPClass;
}
self::$m_aExtensionClasses[$sInterface][$sPHPClass] = $oExtensionInstance;
}
}
}
// Initialize the classes (declared attributes, etc.)
//
foreach(get_declared_classes() as $sPHPClass) {
if (is_subclass_of($sPHPClass, 'DBObject'))
{
@@ -1184,6 +1212,10 @@ abstract class MetaModel
if (method_exists($sPHPClass, 'Init'))
{
call_user_func(array($sPHPClass, 'Init'));
foreach (MetaModel::EnumPlugins('iOnClassInitialization') as $sPluginClass => $oClassInit)
{
$oClassInit->OnAfterClassInitialization($sPHPClass);
}
}
}
}
@@ -1401,31 +1433,6 @@ abstract class MetaModel
// }
//}
}
// Build the list of available extensions
//
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier');
foreach($aInterfaces as $sInterface)
{
self::$m_aExtensionClasses[$sInterface] = array();
}
foreach(get_declared_classes() as $sPHPClass)
{
$oRefClass = new ReflectionClass($sPHPClass);
$oExtensionInstance = null;
foreach($aInterfaces as $sInterface)
{
if ($oRefClass->implementsInterface($sInterface))
{
if (is_null($oExtensionInstance))
{
$oExtensionInstance = new $sPHPClass;
}
self::$m_aExtensionClasses[$sInterface][$sPHPClass] = $oExtensionInstance;
}
}
}
}
// To be overriden, must be called for any object class (optimization)
@@ -1552,9 +1559,12 @@ abstract class MetaModel
return true;
}
public static function Init_AddAttribute(AttributeDefinition $oAtt)
public static function Init_AddAttribute(AttributeDefinition $oAtt, $sTargetClass = null)
{
$sTargetClass = self::GetCallersPHPClass("Init");
if (!$sTargetClass)
{
$sTargetClass = self::GetCallersPHPClass("Init");
}
$sAttCode = $oAtt->GetCode();
if ($sAttCode == 'finalclass')
@@ -1615,11 +1625,14 @@ abstract class MetaModel
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
}
public static function Init_SetZListItems($sListCode, $aItems)
public static function Init_SetZListItems($sListCode, $aItems, $sTargetClass = null)
{
MyHelpers::CheckKeyInArray('list code', $sListCode, self::$m_aListInfos);
$sTargetClass = self::GetCallersPHPClass("Init");
if (!$sTargetClass)
{
$sTargetClass = self::GetCallersPHPClass("Init");
}
// Discard attributes that do not make sense
// (missing classes in the current module combination, resulting in irrelevant ext key or link set)
@@ -1906,7 +1919,7 @@ abstract class MetaModel
//
if (!$oFilter->IsAllDataAllowed() && !$oFilter->IsDataFiltered())
{
$oVisibleObjects = UserRights::GetSelectFilter($oFilter->GetClass());
$oVisibleObjects = UserRights::GetSelectFilter($oFilter->GetClass(), $oFilter->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
// Make sure this is a valid search object, saying NO for all
@@ -4375,17 +4388,31 @@ abstract class MetaModel
{
$aRes = array();
$iTotalHits = 0;
foreach(self::$aQueryCacheGetObjectHits as $sClass => $iHits)
foreach(self::$aQueryCacheGetObjectHits as $sClassSign => $iHits)
{
$aRes[] = "$sClass: $iHits";
$aRes[] = "$sClassSign: $iHits";
$iTotalHits += $iHits;
}
return $iTotalHits.' ('.implode(', ', $aRes).')';
}
public static function MakeSingleRow($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false)
public static function MakeSingleRow($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
{
if (!array_key_exists($sClass, self::$aQueryCacheGetObject))
// Build the query cache signature
//
$sQuerySign = $sClass;
if($bAllowAllData)
{
$sQuerySign .= '_all_';
}
if (count($aModifierProperties))
{
array_multisort($aModifierProperties);
$sModifierProperties = json_encode($aModifierProperties);
$sQuerySign .= '_all_'.md5($sModifierProperties);
}
if (!array_key_exists($sQuerySign, self::$aQueryCacheGetObject))
{
// NOTE: Quick and VERY dirty caching mechanism which relies on
// the fact that the string '987654321' will never appear in the
@@ -4394,20 +4421,30 @@ abstract class MetaModel
// but this would slow down -by how much time?- the application
$oFilter = new DBObjectSearch($sClass);
$oFilter->AddCondition('id', 987654321, '=');
if ($aModifierProperties)
{
foreach ($aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
}
if ($bAllowAllData)
{
$oFilter->AllowAllData();
}
$sSQL = self::MakeSelectQuery($oFilter);
self::$aQueryCacheGetObject[$sClass] = $sSQL;
self::$aQueryCacheGetObjectHits[$sClass] = 0;
self::$aQueryCacheGetObject[$sQuerySign] = $sSQL;
self::$aQueryCacheGetObjectHits[$sQuerySign] = 0;
}
else
{
$sSQL = self::$aQueryCacheGetObject[$sClass];
self::$aQueryCacheGetObjectHits[$sClass] += 1;
// echo " -load $sClass/$iKey- ".self::$aQueryCacheGetObjectHits[$sClass]."<br/>\n";
$sSQL = self::$aQueryCacheGetObject[$sQuerySign];
self::$aQueryCacheGetObjectHits[$sQuerySign] += 1;
// echo " -load $sClass/$iKey- ".self::$aQueryCacheGetObjectHits[$sQuerySign]."<br/>\n";
}
$sSQL = str_replace(CMDBSource::Quote(987654321), CMDBSource::Quote($iKey), $sSQL);
$res = CMDBSource::Query($sSQL);
@@ -4453,10 +4490,10 @@ abstract class MetaModel
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
}
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false)
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
{
self::_check_subclass($sClass);
$aRow = self::MakeSingleRow($sClass, $iKey, $bMustBeFound, $bAllowAllData);
$aRow = self::MakeSingleRow($sClass, $iKey, $bMustBeFound, $bAllowAllData, $aModifierProperties);
if (empty($aRow))
{
return null;

View File

@@ -0,0 +1,31 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Any extension to hook the initialization of the metamodel
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
interface iOnClassInitialization
{
public function OnAfterClassInitialization($sClass);
}
?>

View File

@@ -55,7 +55,7 @@ abstract class UserRightsAddOnAPI
abstract public function Init(); // loads data (possible optimizations)
// Used to build select queries showing only objects visible for the given user
abstract public function GetSelectFilter($sLogin, $sClass); // returns a filter object
abstract public function GetSelectFilter($sLogin, $sClass, $aSettings = array()); // returns a filter object
abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null);
@@ -647,7 +647,7 @@ class UserRights
return true;
}
public static function GetSelectFilter($sClass)
public static function GetSelectFilter($sClass, $aSettings = array())
{
// When initializing, we need to let everything pass trough
if (!self::CheckLogin()) return true;
@@ -656,7 +656,7 @@ class UserRights
if (MetaModel::HasCategory($sClass, 'bizmodel'))
{
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass);
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass, $aSettings);
}
else
{

View File

@@ -97,17 +97,24 @@ class ValueSetObjects extends ValueSetDefinition
protected $m_aOrderBy;
protected $m_aExtraConditions;
private $m_bAllowAllData;
private $m_aModifierProperties;
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false)
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
{
$this->m_sContains = '';
$this->m_sFilterExpr = $sFilterExp;
$this->m_sValueAttCode = $sValueAttCode;
$this->m_aOrderBy = $aOrderBy;
$this->m_bAllowAllData = $bAllowAllData;
$this->m_aModifierProperties = $aModifierProperties;
$this->m_aExtraConditions = array();
}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
public function AddCondition(DBObjectSearch $oFilter)
{
$this->m_aExtraConditions[] = $oFilter;
@@ -127,6 +134,13 @@ class ValueSetObjects extends ValueSetDefinition
{
$oFilter->MergeWith($oExtraFilter);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
}
@@ -162,6 +176,13 @@ class ValueSetObjects extends ValueSetDefinition
{
$oFilter->MergeWith($oExtraFilter);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());

View File

@@ -13,7 +13,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper, sAttCode)
function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper, sAttCode, bSearchMode)
{
this.id = id;
this.sTargetClass = sTargetClass;
@@ -25,6 +25,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
this.oWizardHelper = oWizHelper;
this.ajax_request = null;
this.bSelectMode = bSelectMode; // true if the edited field is a SELECT, false if it's an autocomplete
this.bSearchMode = bSearchMode; // true if selecting a value in the context of a search form
this.v_html = '';
var me = this;
@@ -64,6 +65,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
sTitle: me.sTitle,
sAttCode: me.sAttCode,
sTargetClass: me.sTargetClass,
bSearchMode: me.bSearchMode,
operation: 'objectSearchForm'
}
@@ -138,7 +140,8 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
{
var theMap = { sTargetClass: me.sTargetClass,
iInputId: me.id,
sFilter: me.sFilter
sFilter: me.sFilter,
bSearchMode: me.bSearchMode
}
// Gather the parameters from the search form
@@ -215,6 +218,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
iInputId: me.id,
iObjectId: iObjectId,
sAttCode: me.sAttCode,
bSearchMode: me.bSearchMode,
operation: 'getObjectName'
}
@@ -420,6 +424,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
var theMap = { sTargetClass: me.sTargetClass,
sInputId: me.id,
sFilter: me.sFilter,
bSearchMode: me.bSearchMode,
sAttCode: me.sAttCode,
value: $('#'+me.id).val()
};
@@ -503,6 +508,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
iInputId: me.id,
iObjectId: iObjectId,
sAttCode: me.sAttCode,
bSearchMode: me.bSearchMode,
operation: 'getObjectName'
}

View File

@@ -214,6 +214,7 @@ try
$sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
$sJson = utils::ReadParam('json', '', false, 'raw_data');
$sAttCode = utils::ReadParam('sAttCode', '');
$bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
if (!empty($sJson))
{
$oWizardHelper = WizardHelper::FromJSON($sJson);
@@ -224,7 +225,7 @@ try
// Search form: no current object
$oObj = null;
}
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode);
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
$oWidget->SearchObjectsToSelect($oPage, $sFilter, $sRemoteClass, $oObj);
break;
@@ -235,18 +236,22 @@ try
$sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
$sJson = utils::ReadParam('json', '', false, 'raw_data');
$sContains = utils::ReadParam('q', '', false, 'raw_data');
if (!empty($sJson))
$bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
if ($sContains !='')
{
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
if (!empty($sJson))
{
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
}
else
{
// Search form: no current object
$oObj = null;
}
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, '', $bSearchMode);
$oWidget->AutoComplete($oPage, $sFilter, $oObj, $sContains);
}
else
{
// Search form: no current object
$oObj = null;
}
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId);
$oWidget->AutoComplete($oPage, $sFilter, $oObj, $sContains);
break;
// ui.extkeywidget
@@ -256,7 +261,8 @@ try
$iInputId = utils::ReadParam('iInputId', '');
$sTitle = utils::ReadParam('sTitle', '', false, 'raw_data');
$sAttCode = utils::ReadParam('sAttCode', '');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode);
$bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode);
$sJson = utils::ReadParam('json', '', false, 'raw_data');
if (!empty($sJson))
{
@@ -276,7 +282,7 @@ try
$sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
$iInputId = utils::ReadParam('iInputId', '');
$sAttCode = utils::ReadParam('sAttCode', '');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode);
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
$sJson = utils::ReadParam('json', '', false, 'raw_data');
if (!empty($sJson))
{
@@ -297,7 +303,7 @@ try
$iInputId = utils::ReadParam('iInputId', '');
$sFormPrefix = utils::ReadParam('sFormPrefix', '');
$sAttCode = utils::ReadParam('sAttCode', '');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode);
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, false);
$aResult = $oWidget->DoCreateObject($oPage);
echo json_encode($aResult);
break;
@@ -307,7 +313,8 @@ try
$sTargetClass = utils::ReadParam('sTargetClass', '', false, 'class');
$iInputId = utils::ReadParam('iInputId', '');
$iObjectId = utils::ReadParam('iObjectId', '');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId);
$bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, '', $bSearchMode);
$sName = $oWidget->GetObjectName($iObjectId);
echo json_encode(array('name' => $sName));
break;
@@ -320,6 +327,7 @@ try
$sFilter = utils::ReadParam('sFilter', '', false, 'raw_data');
$sJson = utils::ReadParam('json', '', false, 'raw_data');
$currValue = utils::ReadParam('value', '');
$bSearchMode = (utils::ReadParam('bSearchMode', 'false') == 'true');
if (!empty($sJson))
{
$oWizardHelper = WizardHelper::FromJSON($sJson);
@@ -330,7 +338,7 @@ try
// Search form: no current object
$oObj = null;
}
$oWidget = new UIExtKeyWidget($sTargetClass, $sInputId);
$oWidget = new UIExtKeyWidget($sTargetClass, $sInputId, '', $bSearchMode);
$oWidget->DisplayHierarchy($oPage, $sFilter, $currValue, $oObj);
break;
@@ -619,7 +627,7 @@ try
// Let's take this opportunity to inform the plug-ins so that they can perform some cleanup
$iTransactionId = utils::ReadParam('transaction_id', 0);
$sTempId = session_id().'_'.$iTransactionId;
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
{
$oExtensionInstance->OnFormCancel($sTempId);
}