mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 15:34:12 +01:00
Reintegrated from branch 1.2: capability to develop a module to share objects between organizations (beta)
SVN:trunk[1859]
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
31
core/metamodelmodifier.inc.php
Normal file
31
core/metamodelmodifier.inc.php
Normal 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);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user