mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 16:04:10 +01:00
Compare commits
71 Commits
1.2.1
...
support/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62510e2b04 | ||
|
|
f33c821306 | ||
|
|
11d0e9f52b | ||
|
|
3330fd79d0 | ||
|
|
02e0a61dcf | ||
|
|
2bb8028d4d | ||
|
|
891b22909a | ||
|
|
463748b6da | ||
|
|
fc2878b6d1 | ||
|
|
17919f5389 | ||
|
|
e54b1d2ff4 | ||
|
|
523fb8bd25 | ||
|
|
fad77fb9fa | ||
|
|
8da92c9251 | ||
|
|
977d616ef2 | ||
|
|
29faa739c1 | ||
|
|
b986f63a67 | ||
|
|
8fa3a6d47d | ||
|
|
0e6876b068 | ||
|
|
8d962f4bdb | ||
|
|
3b8f945c44 | ||
|
|
9600c89a1f | ||
|
|
d01202ba33 | ||
|
|
1bc1a0a1b2 | ||
|
|
37ea4cb5e3 | ||
|
|
c4a003f620 | ||
|
|
7a8ee0353a | ||
|
|
6b526ba455 | ||
|
|
9d9b923b7e | ||
|
|
fcaad0cd07 | ||
|
|
da875dd945 | ||
|
|
2a71bf5008 | ||
|
|
9b36ebc106 | ||
|
|
1a507b7aa4 | ||
|
|
178ee28596 | ||
|
|
e44a5d2980 | ||
|
|
828c02db0b | ||
|
|
d1e4e2109f | ||
|
|
b7a9b340b8 | ||
|
|
3731cf6dc1 | ||
|
|
0e7fc5e5c4 | ||
|
|
bc62c06894 | ||
|
|
4ed85c23de | ||
|
|
b6c1347f27 | ||
|
|
237eefcbc6 | ||
|
|
5ee3c69898 | ||
|
|
53b3ae8016 | ||
|
|
26b6bfaf7f | ||
|
|
1a659cc4d0 | ||
|
|
b000900d6c | ||
|
|
f68ec1cef1 | ||
|
|
3fb867d393 | ||
|
|
fe559eb492 | ||
|
|
0041afd6d0 | ||
|
|
dc1b5b0d4c | ||
|
|
10a930b7b2 | ||
|
|
72b6089db8 | ||
|
|
0cfb1c3a83 | ||
|
|
36a73535a5 | ||
|
|
9382b89277 | ||
|
|
6d14da15cf | ||
|
|
3113205f88 | ||
|
|
09bd8052d7 | ||
|
|
85f0b79203 | ||
|
|
81145d7b1c | ||
|
|
7e6d1c2ce4 | ||
|
|
364259daa5 | ||
|
|
7b270294f6 | ||
|
|
c7aa00e81a | ||
|
|
f9e7446e7b | ||
|
|
493ab80965 |
@@ -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;
|
||||
|
||||
@@ -597,12 +597,12 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
}
|
||||
|
||||
|
||||
protected $m_aAdmins; // id of users being linked to the well-known admin profile
|
||||
protected $m_aPortalUsers; // id of users being linked to the well-known admin profile
|
||||
protected $m_aAdmins = array(); // id -> bool, true if the user has the well-known admin profile
|
||||
protected $m_aPortalUsers = array(); // id -> bool, true if the user has the well-known portal user profile
|
||||
|
||||
protected $m_aProfiles; // id -> object
|
||||
protected $m_aUserProfiles; // userid,profileid -> object
|
||||
protected $m_aUserOrgs; // userid -> orgid
|
||||
protected $m_aUserProfiles = array(); // userid,profileid -> object
|
||||
protected $m_aUserOrgs = array(); // userid -> array of orgid
|
||||
|
||||
// Those arrays could be completed on demand (inheriting parent permissions)
|
||||
protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
|
||||
@@ -611,20 +611,80 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||
protected $m_aObjectActionGrants = array();
|
||||
|
||||
/**
|
||||
* Read and cache organizations allowed to the given user
|
||||
*
|
||||
* @param oUser
|
||||
* @param sClass -not used here but can be used in overloads
|
||||
*/
|
||||
protected function GetUserOrgs($oUser, $sClass)
|
||||
{
|
||||
return @$this->m_aUserOrgs[$oUser->GetKey()];
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aUserOrgs))
|
||||
{
|
||||
$this->m_aUserOrgs[$iUser] = array();
|
||||
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$sUserOrgQuery = 'SELECT UserOrg, Org FROM Organization AS Org JOIN Organization AS Root ON Org.'.$sHierarchicalKeyCode.' BELOW Root.id JOIN URP_UserOrg AS UserOrg ON UserOrg.allowed_org_id = Root.id WHERE UserOrg.userid = :userid';
|
||||
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sUserOrgQuery), array(), array('userid' => $iUser));
|
||||
while ($aRow = $oUserOrgSet->FetchAssoc())
|
||||
{
|
||||
$oUserOrg = $aRow['UserOrg'];
|
||||
$oOrg = $aRow['Org'];
|
||||
$this->m_aUserOrgs[$iUser][] = $oOrg->GetKey();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSearch = new DBObjectSearch('URP_UserOrg');
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
$this->m_aUserOrgs[$iUser][] = $oUserOrg->Get('allowed_org_id');
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->m_aUserOrgs[$iUser];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and cache profiles of the given user
|
||||
*/
|
||||
protected function GetUserProfiles($iUser)
|
||||
{
|
||||
if (!array_key_exists($iUser, $this->m_aUserProfiles))
|
||||
{
|
||||
$oSearch = new DBObjectSearch('URP_UserProfile');
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
$this->m_aUserProfiles[$iUser] = array();
|
||||
$oUserProfileSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserProfile = $oUserProfileSet->Fetch())
|
||||
{
|
||||
$this->m_aUserProfiles[$iUser][$oUserProfile->Get('profileid')] = $oUserProfile;
|
||||
}
|
||||
}
|
||||
return $this->m_aUserProfiles[$iUser];
|
||||
|
||||
}
|
||||
|
||||
public function ResetCache()
|
||||
{
|
||||
// Loaded by Load cache
|
||||
$this->m_aProfiles = null;
|
||||
$this->m_aUserProfiles = null;
|
||||
$this->m_aUserOrgs = null;
|
||||
$this->m_aUserProfiles = array();
|
||||
$this->m_aUserOrgs = array();
|
||||
|
||||
$this->m_aAdmins = null;
|
||||
$this->m_aPortalUsers = null;
|
||||
$this->m_aAdmins = array();
|
||||
$this->m_aPortalUsers = array();
|
||||
|
||||
// Loaded on demand (time consuming as compared to the others)
|
||||
$this->m_aClassActionGrants = null;
|
||||
@@ -659,6 +719,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())
|
||||
@@ -666,30 +731,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
|
||||
}
|
||||
|
||||
$oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserProfile"));
|
||||
$this->m_aUserProfiles = array();
|
||||
$this->m_aAdmins = array();
|
||||
$this->m_aPortalUsers = array();
|
||||
while ($oUserProfile = $oUserProfileSet->Fetch())
|
||||
{
|
||||
$this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile;
|
||||
if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aAdmins[] = $oUserProfile->Get('userid');
|
||||
}
|
||||
elseif ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aPortalUsers[] = $oUserProfile->Get('userid');
|
||||
}
|
||||
}
|
||||
|
||||
$oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
|
||||
$this->m_aUserOrgs = array();
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
$this->m_aUserOrgs[$oUserOrg->Get('userid')][] = $oUserOrg->Get('allowed_org_id');
|
||||
}
|
||||
|
||||
$this->m_aClassStimulusGrants = array();
|
||||
$oStimGrantSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant"));
|
||||
$this->m_aStimGrants = array();
|
||||
@@ -716,33 +757,45 @@ exit;
|
||||
|
||||
public function IsAdministrator($oUser)
|
||||
{
|
||||
$this->LoadCache();
|
||||
|
||||
if (in_array($oUser->GetKey(), $this->m_aAdmins))
|
||||
//$this->LoadCache();
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aAdmins))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
$bIsAdmin = false;
|
||||
foreach($this->GetUserProfiles($iUser) as $oUserProfile)
|
||||
{
|
||||
return false;
|
||||
if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
|
||||
{
|
||||
$bIsAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->m_aAdmins[$iUser] = $bIsAdmin;
|
||||
}
|
||||
return $this->m_aAdmins[$iUser];
|
||||
}
|
||||
|
||||
public function IsPortalUser($oUser)
|
||||
{
|
||||
$this->LoadCache();
|
||||
|
||||
if (in_array($oUser->GetKey(), $this->m_aPortalUsers))
|
||||
//$this->LoadCache();
|
||||
$iUser = $oUser->GetKey();
|
||||
if (!array_key_exists($iUser, $this->m_aPortalUsers))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
$bIsPortalUser = false;
|
||||
foreach($this->GetUserProfiles($iUser) as $oUserProfile)
|
||||
{
|
||||
return false;
|
||||
if ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
|
||||
{
|
||||
$bIsPortalUser = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->m_aPortalUsers[$iUser] = $bIsPortalUser;
|
||||
}
|
||||
return $this->m_aPortalUsers[$iUser];
|
||||
}
|
||||
|
||||
public function GetSelectFilter($oUser, $sClass)
|
||||
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
|
||||
{
|
||||
$this->LoadCache();
|
||||
|
||||
@@ -754,41 +807,18 @@ 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
|
||||
//
|
||||
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
|
||||
if (is_null($aUserOrgs) || count($aUserOrgs) == 0)
|
||||
if (count($aUserOrgs) == 0)
|
||||
{
|
||||
// No position means 'Everywhere'
|
||||
// No org means 'any org'
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -796,48 +826,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;
|
||||
}
|
||||
|
||||
@@ -883,10 +930,8 @@ exit;
|
||||
|
||||
$iPermission = UR_ALLOWED_NO;
|
||||
$aAttributes = array();
|
||||
if (isset($this->m_aUserProfiles[$iUser]))
|
||||
foreach($this->GetUserProfiles($iUser) as $iProfile => $oProfile)
|
||||
{
|
||||
foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
|
||||
{
|
||||
$iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (is_null($iGrant) || !$iGrant)
|
||||
{
|
||||
@@ -895,7 +940,7 @@ exit;
|
||||
else
|
||||
{
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
|
||||
|
||||
// update the list of attributes with those allowed for this profile
|
||||
//
|
||||
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
|
||||
@@ -912,7 +957,6 @@ exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aRes = array(
|
||||
'permission' => $iPermission,
|
||||
@@ -926,10 +970,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)
|
||||
@@ -974,10 +1084,8 @@ exit;
|
||||
// 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
|
||||
$iPermission = UR_ALLOWED_NO;
|
||||
if (isset($this->m_aUserProfiles[$iUser]))
|
||||
foreach($this->GetUserProfiles($iUser) as $iProfile => $oProfile)
|
||||
{
|
||||
foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
|
||||
{
|
||||
$oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($oGrantRecord))
|
||||
{
|
||||
@@ -985,7 +1093,6 @@ exit;
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $iPermission;
|
||||
}
|
||||
|
||||
@@ -993,6 +1100,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)
|
||||
@@ -303,5 +304,58 @@ class ApplicationContext
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
protected static $m_aPluginProperties = null;
|
||||
|
||||
/**
|
||||
* Load plugin properties for the current session
|
||||
* @return void
|
||||
*/
|
||||
protected static function LoadPluginProperties()
|
||||
{
|
||||
if (isset($_SESSION['PluginProperties']))
|
||||
{
|
||||
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aPluginProperties = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set plugin properties
|
||||
* @param sPluginClass string Class implementing any plugin interface
|
||||
* @param sProperty string Name of the property
|
||||
* @param value scalar Value (numeric or string)
|
||||
* @return void
|
||||
*/
|
||||
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
|
||||
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin properties
|
||||
* @param sPluginClass string Class implementing any plugin interface
|
||||
* @return array of sProperty=>value pairs
|
||||
*/
|
||||
public static function GetPluginProperties($sPluginClass)
|
||||
{
|
||||
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
|
||||
|
||||
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
|
||||
{
|
||||
return self::$m_aPluginProperties[$sPluginClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -252,16 +252,17 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sCount = " ($iCount)";
|
||||
}
|
||||
$oPage->SetCurrentTab($oAttDef->GetLabel().$sCount);
|
||||
if ($bEditMode)
|
||||
if ($this->IsNew())
|
||||
{
|
||||
$iFlags = $this->GetInitialStateAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
$bReadOnly = ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE));
|
||||
if ($bEditMode && (!$bReadOnly))
|
||||
{
|
||||
if ($this->IsNew())
|
||||
{
|
||||
$iFlags = $this->GetInitialStateAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
$sInputId = $this->m_iFormId.'_'.$sAttCode;
|
||||
if (get_class($oAttDef) == 'AttributeLinkedSet')
|
||||
{
|
||||
@@ -1365,7 +1366,7 @@ EOF
|
||||
{
|
||||
$iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($sAttCode));
|
||||
$aRow[] = '<td>'.date('Y-m-d', $iDate).'</td>';
|
||||
$aRow[] = '<td>'.date('h:i:s', $iDate).'</td>';
|
||||
$aRow[] = '<td>'.date('H:i:s', $iDate).'</td>';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1548,7 +1549,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();
|
||||
@@ -1692,7 +1695,7 @@ EOF
|
||||
$aEventsList[] ='validate';
|
||||
$aEventsList[] ='keyup';
|
||||
$aEventsList[] ='change';
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" class=\"date-pick\" type=\"text\" size=\"20\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"20\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
break;
|
||||
|
||||
case 'Duration':
|
||||
@@ -2378,7 +2381,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];
|
||||
@@ -2663,7 +2666,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);
|
||||
}
|
||||
|
||||
@@ -348,7 +348,11 @@ class DisplayBlock
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
$iTotalCount = $this->m_oSet->Count();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
$oTmpSet = clone $this->m_oSet;
|
||||
// Speed up the load, load only the needed field to group on
|
||||
$sAlias = $oTmpSet->GetFilter()->GetClassAlias();
|
||||
$oTmpSet->OptimizeColumnLoad(array($sAlias => array($sGroupByField)));
|
||||
while($oObj = $oTmpSet->Fetch())
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
@@ -746,7 +750,7 @@ EOF
|
||||
$sHtml .= "<div id=\"my_chart_{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
|
||||
$oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }");
|
||||
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
|
||||
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle&id=$sId&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
$iChartCounter++;
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
@@ -1081,12 +1085,12 @@ class MenuBlock extends DisplayBlock
|
||||
$sDefault.= "&default[$sKey]=$sValue";
|
||||
}
|
||||
}
|
||||
$bIsCreationAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
|
||||
switch($oSet->Count())
|
||||
{
|
||||
case 0:
|
||||
// No object in the set, the only possible action is "new"
|
||||
$bIsModifyAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@@ -1100,7 +1104,7 @@ class MenuBlock extends DisplayBlock
|
||||
if (!isset($aExtraParams['link_attr']))
|
||||
{
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify&class=$sClass&id=$id{$sContext}#"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=delete&class=$sClass&id=$id{$sContext}"); }
|
||||
// Transitions / Stimuli
|
||||
$aTransitions = $oObj->EnumTransitions();
|
||||
@@ -1169,13 +1173,16 @@ class MenuBlock extends DisplayBlock
|
||||
else
|
||||
{
|
||||
// many objects in the set, possible actions are: new / modify all / delete all
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=$sFilter{$sContext}"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=$sFilter{$sContext}"); }
|
||||
|
||||
// Stimuli
|
||||
$aStates = MetaModel::EnumStates($sClass);
|
||||
if (count($aStates) > 0)
|
||||
// Do not perform time consuming computations if there are too may objects in the list
|
||||
$iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
|
||||
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count() < $iLimit)))
|
||||
{
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
$oSet->Rewind();
|
||||
|
||||
@@ -32,13 +32,13 @@ require_once(APPROOT."/application/user.preferences.class.inc.php");
|
||||
class iTopWebPage extends NiceWebPage
|
||||
{
|
||||
private $m_sMenu;
|
||||
// private $m_currentOrganization;
|
||||
// private $m_currentOrganization;
|
||||
private $m_aTabs;
|
||||
private $m_sCurrentTabContainer;
|
||||
private $m_sCurrentTab;
|
||||
private $m_sMessage;
|
||||
private $m_sInitScript;
|
||||
|
||||
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
@@ -159,7 +159,7 @@ class iTopWebPage extends NiceWebPage
|
||||
alert(err);
|
||||
}
|
||||
EOF
|
||||
;
|
||||
;
|
||||
$this->add_ready_script(
|
||||
<<< EOF
|
||||
//add new widget called TruncatedList to properly display truncated lists when they are sorted
|
||||
@@ -317,6 +317,15 @@ EOF
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
$(".datetime-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
buttonImageOnly: true,
|
||||
dateFormat: 'yy-mm-dd 00:00:00',
|
||||
constrainInput: false,
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
// Restore the persisted sortable order, for all sortable lists... if any
|
||||
$('.sortable').each(function()
|
||||
{
|
||||
@@ -354,7 +363,7 @@ EOF
|
||||
|
||||
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry').toggle(); });
|
||||
EOF
|
||||
);
|
||||
);
|
||||
$sUserPrefs = appUserPreferences::GetAsJSON();
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
@@ -443,10 +452,10 @@ EOF
|
||||
});
|
||||
|
||||
EOF
|
||||
);
|
||||
|
||||
// Build menus from module handlers
|
||||
//
|
||||
);
|
||||
|
||||
// Build menus from module handlers
|
||||
//
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
|
||||
@@ -456,7 +465,7 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
@@ -472,11 +481,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');
|
||||
@@ -486,76 +497,76 @@ EOF
|
||||
switch($iCount)
|
||||
{
|
||||
case 0:
|
||||
// No such dimension/silo => nothing to select
|
||||
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
|
||||
break;
|
||||
|
||||
// No such dimension/silo => nothing to select
|
||||
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Only one possible choice... no selection, but display the value
|
||||
$oOrg = $oSet->Fetch();
|
||||
$sHtml = '<div id="SiloSelection">'.$oOrg->GetName().'</div>';
|
||||
$sHtml .= '';
|
||||
break;
|
||||
|
||||
// Only one possible choice... no selection, but display the value
|
||||
$oOrg = $oSet->Fetch();
|
||||
$sHtml = '<div id="SiloSelection">'.$oOrg->GetName().'</div>';
|
||||
$sHtml .= '';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
|
||||
$sHtml = '<div id="SiloSelection">';
|
||||
$sHtml .= '<form style="display:inline" action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">'; //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
/*
|
||||
$sSelected = ($iCurrentOrganization == '') ? ' selected' : '';
|
||||
$sHtml .= '<option value=""'.$sSelected.'>'.Dict::S('UI:AllOrganizations').'</option>';
|
||||
while($oOrg = $oSet->Fetch())
|
||||
{
|
||||
if ($iCurrentOrganization == $oOrg->GetKey())
|
||||
{
|
||||
// $oCurrentOrganization = $oOrg;
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
|
||||
$sHtml = '<div id="SiloSelection">';
|
||||
$sHtml .= '<form style="display:inline" action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">'; //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
/*
|
||||
$sSelected = ($iCurrentOrganization == '') ? ' selected' : '';
|
||||
$sHtml .= '<option value=""'.$sSelected.'>'.Dict::S('UI:AllOrganizations').'</option>';
|
||||
while($oOrg = $oSet->Fetch())
|
||||
{
|
||||
if ($iCurrentOrganization == $oOrg->GetKey())
|
||||
{
|
||||
// $oCurrentOrganization = $oOrg;
|
||||
$sSelected = " selected";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = "";
|
||||
}
|
||||
$sHtml .= '<option title="'.$oOrg->GetName().'" value="'.$oOrg->GetKey().'"'.$sSelected.'>'.$oOrg->GetName().'</option>';
|
||||
}
|
||||
$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);
|
||||
$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
|
||||
$oAppContext->Reset('org_id'); // org_id is handled above and we want to be able to change it here !
|
||||
$oAppContext->Reset('menu'); // don't pass the menu, since a menu may expect more parameters
|
||||
$sHtml .= $oAppContext->GetForForm(); // Pass what remains, if anything...
|
||||
$sHtml .= '</form>';
|
||||
$sHtml .= '</div>';
|
||||
}
|
||||
$sHtml .= '<option title="'.$oOrg->GetName().'" value="'.$oOrg->GetKey().'"'.$sSelected.'>'.$oOrg->GetName().'</option>';
|
||||
}
|
||||
$sHtml .= '</select>';
|
||||
*/
|
||||
$sFavoriteOrgs = '';
|
||||
$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
|
||||
$oAppContext->Reset('org_id'); // org_id is handled above and we want to be able to change it here !
|
||||
$oAppContext->Reset('menu'); // don't pass the menu, since a menu may expect more parameters
|
||||
$sHtml .= $oAppContext->GetForForm(); // Pass what remains, if anything...
|
||||
$sHtml .= '</form>';
|
||||
$sHtml .= '</div>';
|
||||
}
|
||||
return $sHtml;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function DisplayMenu()
|
||||
{
|
||||
|
||||
public function DisplayMenu()
|
||||
{
|
||||
// Display the menu
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iAccordionIndex = 0;
|
||||
|
||||
ApplicationMenu::DisplayMenu($this, $oAppContext->GetAsHash());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs (via some echo) the complete HTML page by assembling all its elements
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
public function output()
|
||||
{
|
||||
$sForm = $this->GetSiloSelectionForm();
|
||||
$this->DisplayMenu(); // Compute the menu
|
||||
|
||||
// Put here the 'ready scripts' that must be executed after all others
|
||||
$this->add_ready_script(
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
@@ -565,78 +576,87 @@ EOF
|
||||
$('table.listResults').each( function() { FixTableSorter($(this)); } );
|
||||
|
||||
EOF
|
||||
);
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
$s_captured_output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
||||
echo "<html>\n";
|
||||
echo "<head>\n";
|
||||
// Make sure that Internet Explorer renders the page using its latest/highest/greatest standards !
|
||||
echo "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
echo $this->get_base_tag();
|
||||
// Stylesheets MUST be loaded before any scripts otherwise
|
||||
// jQuery scripts may face some spurious problems (like failing on a 'reload')
|
||||
foreach($this->a_linked_stylesheets as $a_stylesheet)
|
||||
{
|
||||
if ($a_stylesheet['condition'] != "")
|
||||
);
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
echo "<!--[if {$a_stylesheet['condition']}]>\n";
|
||||
header($s_header);
|
||||
}
|
||||
echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$a_stylesheet['link']}\" />\n";
|
||||
if ($a_stylesheet['condition'] != "")
|
||||
{
|
||||
echo "<![endif]-->\n";
|
||||
}
|
||||
}
|
||||
foreach($this->a_linked_scripts as $s_script)
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
$this->add_script("\$(document).ready(function() {\n{$this->m_sInitScript};\nwindow.setTimeout('onDelayedReady()',10)\n});");
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
{
|
||||
$this->add_script("\nonDelayedReady = function() {\n".implode("\n", $this->m_aReadyScripts)."\n}\n");
|
||||
}
|
||||
if (count($this->a_scripts)>0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
foreach($this->a_scripts as $s_script)
|
||||
{
|
||||
echo "$s_script\n";
|
||||
}
|
||||
echo "</script>\n";
|
||||
}
|
||||
|
||||
if (count($this->a_styles)>0)
|
||||
{
|
||||
echo "<style>\n";
|
||||
foreach($this->a_styles as $s_style)
|
||||
{
|
||||
echo "$s_style\n";
|
||||
}
|
||||
echo "</style>\n";
|
||||
}
|
||||
echo "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/opensearch.xml.php\" />\n";
|
||||
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
$s_captured_output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$sHtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
||||
$sHtml .= "<html>\n";
|
||||
$sHtml .= "<head>\n";
|
||||
// Make sure that Internet Explorer renders the page using its latest/highest/greatest standards !
|
||||
$sHtml .= "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n";
|
||||
$sHtml .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
$sHtml .= "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
$sHtml .= $this->get_base_tag();
|
||||
// Stylesheets MUST be loaded before any scripts otherwise
|
||||
// jQuery scripts may face some spurious problems (like failing on a 'reload')
|
||||
foreach($this->a_linked_stylesheets as $a_stylesheet)
|
||||
{
|
||||
if ($a_stylesheet['condition'] != "")
|
||||
{
|
||||
$sHtml .= "<!--[if {$a_stylesheet['condition']}]>\n";
|
||||
}
|
||||
$sHtml .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$a_stylesheet['link']}\" />\n";
|
||||
if ($a_stylesheet['condition'] != "")
|
||||
{
|
||||
$sHtml .= "<![endif]-->\n";
|
||||
}
|
||||
}
|
||||
// special stylesheet for printing, hides the navigation gadgets
|
||||
$sHtml .= "<link rel=\"stylesheet\" media=\"print\" type=\"text/css\" href=\"../css/print.css\" />\n";
|
||||
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
foreach($this->a_linked_scripts as $s_script)
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
$sHtml .= "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
$this->add_script("\$(document).ready(function() {\n{$this->m_sInitScript};\nwindow.setTimeout('onDelayedReady()',10)\n});");
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
{
|
||||
$this->add_script("\nonDelayedReady = function() {\n".implode("\n", $this->m_aReadyScripts)."\n}\n");
|
||||
}
|
||||
if (count($this->a_scripts)>0)
|
||||
{
|
||||
$sHtml .= "<script type=\"text/javascript\">\n";
|
||||
foreach($this->a_scripts as $s_script)
|
||||
{
|
||||
$sHtml .= "$s_script\n";
|
||||
}
|
||||
$sHtml .= "</script>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($this->a_styles)>0)
|
||||
{
|
||||
$sHtml .= "<style>\n";
|
||||
foreach($this->a_styles as $s_style)
|
||||
{
|
||||
$sHtml .= "$s_style\n";
|
||||
}
|
||||
$sHtml .= "</style>\n";
|
||||
}
|
||||
$sHtml .= "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/opensearch.xml.php\" />\n";
|
||||
$sHtml .= "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
|
||||
$sHtml .= "</head>\n";
|
||||
$sHtml .= "<body>\n";
|
||||
|
||||
|
||||
|
||||
@@ -666,7 +686,7 @@ EOF
|
||||
// 2) clicking on it will erase it
|
||||
$sText = Dict::S("UI:YourSearch");
|
||||
$sOnClick = " onclick=\"this.value='';this.onclick=null;\"";
|
||||
}
|
||||
}
|
||||
// Render the tabs in the page (if any)
|
||||
foreach($this->m_aTabs as $sTabContainerName => $m_aTabs)
|
||||
{
|
||||
@@ -674,149 +694,185 @@ EOF
|
||||
$container_index = 0;
|
||||
if (count($m_aTabs) > 0)
|
||||
{
|
||||
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$container_index}\" class=\"light\">\n";
|
||||
$sTabs .= "<ul>\n";
|
||||
// Display the unordered list that will be rendered as the tabs
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<li><a href=\"#tab_$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</ul>\n";
|
||||
// Now add the content of the tabs themselves
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<div id=\"tab_$i\">".$sTabContent."</div>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</div>\n<!-- end of tabs-->\n";
|
||||
}
|
||||
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$container_index}\" class=\"light\">\n";
|
||||
$sTabs .= "<ul>\n";
|
||||
// Display the unordered list that will be rendered as the tabs
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<li><a href=\"#tab_$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</ul>\n";
|
||||
// Now add the content of the tabs themselves
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<div id=\"tab_$i\">".$sTabContent."</div>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</div>\n<!-- end of tabs-->\n";
|
||||
}
|
||||
$this->s_content = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $this->s_content);
|
||||
$container_index++;
|
||||
}
|
||||
$sUserName = UserRights::GetUser();
|
||||
$sIsAdmin = UserRights::IsAdministrator() ? '(Administrator)' : '';
|
||||
if (UserRights::IsAdministrator())
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage+Admin', $sUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
|
||||
}
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>";
|
||||
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/preferences.php\">".Dict::S('UI:Preferences')."</a></li>\n";
|
||||
|
||||
if (utils::CanLogOff())
|
||||
{
|
||||
//$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
}
|
||||
if (UserRights::CanChangePassword())
|
||||
{
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
}
|
||||
$sLogOffMenu .= "</ul>\n</li>\n</ul></span>\n";
|
||||
|
||||
$sRestrictions = '';
|
||||
if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
$sUserName = UserRights::GetUser();
|
||||
$sIsAdmin = UserRights::IsAdministrator() ? '(Administrator)' : '';
|
||||
if (UserRights::IsAdministrator())
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage+Admin', $sUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
|
||||
}
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>";
|
||||
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/preferences.php\">".Dict::S('UI:Preferences')."</a></li>\n";
|
||||
|
||||
if (utils::CanLogOff())
|
||||
{
|
||||
//$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
}
|
||||
if (UserRights::CanChangePassword())
|
||||
{
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
}
|
||||
$sLogOffMenu .= "</ul>\n</li>\n</ul></span>\n";
|
||||
|
||||
$sRestrictions = '';
|
||||
if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
|
||||
{
|
||||
$sRestrictions = Dict::S('UI:AccessRO-All');
|
||||
if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
|
||||
{
|
||||
$sRestrictions = Dict::S('UI:AccessRO-All');
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (!MetaModel::DBHasAccess(ACCESS_USER_WRITE))
|
||||
{
|
||||
$sRestrictions = Dict::S('UI:AccessRO-Users');
|
||||
}
|
||||
|
||||
if (strlen($sRestrictions) > 0)
|
||||
{
|
||||
$sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message'));
|
||||
$sApplicationBanner = '<div id="admin-banner">';
|
||||
$sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">';
|
||||
$sApplicationBanner .= ' <b>'.$sRestrictions.'</b>';
|
||||
if (strlen($sAdminMessage) > 0)
|
||||
elseif (!MetaModel::DBHasAccess(ACCESS_USER_WRITE))
|
||||
{
|
||||
$sApplicationBanner .= ' <b>'.$sAdminMessage.'</b>';
|
||||
$sRestrictions = Dict::S('UI:AccessRO-Users');
|
||||
}
|
||||
$sApplicationBanner .= '</div>';
|
||||
}
|
||||
else if(strlen($this->m_sMessage))
|
||||
{
|
||||
$sApplicationBanner = '<div id="admin-banner"><span style="padding:5px;">'.$this->m_sMessage.'<span></div>';
|
||||
|
||||
if (strlen($sRestrictions) > 0)
|
||||
{
|
||||
$sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message'));
|
||||
$sApplicationBanner = '<div id="admin-banner">';
|
||||
$sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">';
|
||||
$sApplicationBanner .= ' <b>'.$sRestrictions.'</b>';
|
||||
if (strlen($sAdminMessage) > 0)
|
||||
{
|
||||
$sApplicationBanner .= ' <b>'.$sAdminMessage.'</b>';
|
||||
}
|
||||
$sApplicationBanner .= '</div>';
|
||||
}
|
||||
else if(strlen($this->m_sMessage))
|
||||
{
|
||||
$sApplicationBanner = '<div id="admin-banner"><span style="padding:5px;">'.$this->m_sMessage.'<span></div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sApplicationBanner = '';
|
||||
}
|
||||
|
||||
$sOnlineHelpUrl = MetaModel::GetConfig()->Get('online_help');
|
||||
//$sLogOffMenu = "<span id=\"logOffBtn\" style=\"height:55px;padding:0;margin:0;\"><img src=\"../images/onOffBtn.png\"></span>";
|
||||
|
||||
$sHtml .= '<div id="left-pane" class="ui-layout-west">';
|
||||
$sHtml .= '<!-- Beginning of the left pane -->';
|
||||
$sHtml .= ' <div id="header-logo">';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="header-menu">';
|
||||
$sHtml .= ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>';
|
||||
$sHtml .= ' <div style="text-align:center;">'.self::FilterXSS($sForm).'</div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div id="menu" class="ui-layout-content">';
|
||||
$sHtml .= ' <div id="inner_menu">';
|
||||
$sHtml .= ' <div id="accordion">';
|
||||
$sHtml .= self::FilterXSS($this->m_sMenu);
|
||||
$sHtml .= ' <!-- Beginning of the accordion menu -->';
|
||||
$sHtml .= ' <!-- End of the accordion menu-->';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' </div> <!-- /inner menu -->';
|
||||
$sHtml .= ' </div> <!-- /menu -->';
|
||||
$sHtml .= ' <div class="footer"><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logo-combodo.png"/></a></div>';
|
||||
$sHtml .= '<!-- End of the left pane -->';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$sHtml .= '<div class="ui-layout-center">';
|
||||
$sHtml .= ' <div id="top-bar" style="width:100%">';
|
||||
$sHtml .= self::FilterXSS($sApplicationBanner);
|
||||
$sHtml .= ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
$sHtml .= '<td><input type="image" src="../images/searchBtn.png"/></a></td>';
|
||||
$sHtml .= '<td><a style="background:transparent;" href="'.$sOnlineHelpUrl.'" target="_blank"><img style="border:0;padding-left:20px;padding-right:10px;" title="'.Dict::S('UI:Help').'" src="../images/help.png"/></td>';
|
||||
$sHtml .= '<td style="padding-right:20px;padding-left:10px;">'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="ui-layout-content">';
|
||||
$sHtml .= ' <!-- Beginning of page content -->';
|
||||
$sHtml .= self::FilterXSS($this->s_content);
|
||||
$sHtml .= ' <!-- End of page content -->';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
// Add the captured output
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
$sHtml .= "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".self::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
}
|
||||
$sHtml .= "<div id=\"at_the_end\">".self::FilterXSS($this->s_deferred_content)."</div>";
|
||||
// echo $this->s_deferred_content;
|
||||
$sHtml .= "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window
|
||||
$sHtml .= "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>";
|
||||
$sHtml .= "<div style=\"display:none\" id=\"ajax_content\"></div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sApplicationBanner = '';
|
||||
$sHtml .= self::FilterXSS($this->s_content);
|
||||
}
|
||||
|
||||
$sOnlineHelpUrl = MetaModel::GetConfig()->Get('online_help');
|
||||
//$sLogOffMenu = "<span id=\"logOffBtn\" style=\"height:55px;padding:0;margin:0;\"><img src=\"../images/onOffBtn.png\"></span>";
|
||||
$sHtml .= "</body>\n";
|
||||
$sHtml .= "</html>\n";
|
||||
|
||||
echo '<div id="left-pane" class="ui-layout-west">';
|
||||
echo '<!-- Beginning of the left pane -->';
|
||||
echo ' <div id="header-logo">';
|
||||
echo ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="header-menu">';
|
||||
echo ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>';
|
||||
echo ' <div style="text-align:center;">'.self::FilterXSS($sForm).'</div>';
|
||||
echo ' </div>';
|
||||
echo ' <div id="menu" class="ui-layout-content">';
|
||||
echo ' <div id="inner_menu">';
|
||||
echo ' <div id="accordion">';
|
||||
echo self::FilterXSS($this->m_sMenu);
|
||||
echo ' <!-- Beginning of the accordion menu -->';
|
||||
echo ' <!-- End of the accordion menu-->';
|
||||
echo ' </div>';
|
||||
echo ' </div> <!-- /inner menu -->';
|
||||
echo ' </div> <!-- /menu -->';
|
||||
echo ' <div class="footer"><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logo-combodo.png"/></a></div>';
|
||||
echo '<!-- End of the left pane -->';
|
||||
echo '</div>';
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
echo $sHtml;
|
||||
}
|
||||
else if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf') )
|
||||
{
|
||||
require_once(APPROOT.'lib/MPDF/mpdf.php');
|
||||
$oMPDF = new mPDF('c');
|
||||
$oMPDF->mirroMargins = false;
|
||||
if ($this->a_base['href'] != '')
|
||||
{
|
||||
$oMPDF->setBasePath($this->a_base['href']); // Seems that the <BASE> tag is not recognized by mPDF...
|
||||
}
|
||||
$oMPDF->showWatermarkText = true;
|
||||
if ($this->GetOutputOption('pdf', 'template_path'))
|
||||
{
|
||||
$oMPDF->setImportUse(); // Allow templates
|
||||
$oMPDF->SetDocTemplate ($this->GetOutputOption('pdf', 'template_path'), 1);
|
||||
}
|
||||
$oMPDF->WriteHTML($sHtml);
|
||||
$sOutputName = $this->s_title.'.pdf';
|
||||
if ($this->GetOutputOption('pdf', 'output_name'))
|
||||
{
|
||||
$sOutputName = $this->GetOutputOption('pdf', 'output_name');
|
||||
}
|
||||
$oMPDF->Output($sOutputName, 'I');
|
||||
}
|
||||
}
|
||||
|
||||
echo '<div class="ui-layout-center">';
|
||||
echo ' <div id="top-bar" style="width:100%">';
|
||||
echo self::FilterXSS($sApplicationBanner);
|
||||
echo ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
echo '<td><input type="image" src="../images/searchBtn.png"/></a></td>';
|
||||
echo '<td><a style="background:transparent;" href="'.$sOnlineHelpUrl.'" target="_blank"><img style="border:0;padding-left:20px;padding-right:10px;" title="'.Dict::S('UI:Help').'" src="../images/help.png"/></td>';
|
||||
echo '<td style="padding-right:20px;padding-left:10px;">'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="ui-layout-content">';
|
||||
echo ' <!-- Beginning of page content -->';
|
||||
echo self::FilterXSS($this->s_content);
|
||||
echo ' <!-- End of page content -->';
|
||||
echo ' </div>';
|
||||
echo '</div>';
|
||||
|
||||
// Add the captured output
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".self::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
}
|
||||
echo "<div id=\"at_the_end\">".self::FilterXSS($this->s_deferred_content)."</div>";
|
||||
// echo $this->s_deferred_content;
|
||||
echo "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window
|
||||
echo "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>";
|
||||
echo "<div style=\"display:none\" id=\"ajax_content\"></div>";
|
||||
|
||||
echo "</body>\n";
|
||||
echo "</html>\n";
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer)
|
||||
{
|
||||
$this->m_aTabs[$sTabContainer] = array();
|
||||
$this->add("\$Tabs:$sTabContainer\$");
|
||||
}
|
||||
|
||||
|
||||
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
|
||||
{
|
||||
if (!isset($this->m_aTabs[$sTabContainer][$sTabLabel]))
|
||||
@@ -844,12 +900,53 @@ EOF
|
||||
$this->m_sCurrentTab = $sTabLabel;
|
||||
return $sPreviousTab;
|
||||
}
|
||||
|
||||
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_sCurrentTab;
|
||||
}
|
||||
|
||||
|
||||
public function RemoveTab($sTabLabel, $sTabContainer = null)
|
||||
{
|
||||
if ($sTabContainer == null)
|
||||
{
|
||||
$sTabContainer = $this->m_sCurrentTabContainer;
|
||||
}
|
||||
if (isset($this->m_aTabs[$sTabContainer][$sTabLabel]))
|
||||
{
|
||||
// Delete the content of the tab
|
||||
unset($this->m_aTabs[$sTabContainer][$sTabLabel]);
|
||||
|
||||
// If we just removed the active tab, let's reset the active tab
|
||||
if (($this->m_sCurrentTabContainer == $sTabContainer) && ($this->m_sCurrentTab == $sTabLabel))
|
||||
{
|
||||
$this->m_sCurrentTab = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the tab whose title matches a given pattern
|
||||
* @return mixed The name of the tab as a string or false if not found
|
||||
*/
|
||||
public function FindTab($sPattern, $sTabContainer = null)
|
||||
{
|
||||
$return = false;
|
||||
if ($sTabContainer == null)
|
||||
{
|
||||
$sTabContainer = $this->m_sCurrentTabContainer;
|
||||
}
|
||||
foreach($this->m_aTabs[$sTabContainer] as $sTabLabel => $void)
|
||||
{
|
||||
if (preg_match($sPattern, $sTabLabel))
|
||||
{
|
||||
$result = $sTabLabel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the given tab the active one, as if it were clicked
|
||||
* DOES NOT WORK: apparently in the *old* version of jquery
|
||||
@@ -871,7 +968,7 @@ EOF
|
||||
break;
|
||||
}
|
||||
$tab_index++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
$container_index++;
|
||||
@@ -879,7 +976,7 @@ EOF
|
||||
$sSelector = '#tabbedContent_'.$container_index.' > ul';
|
||||
$this->add_ready_script("$('$sSelector').tabs('select', $tab_index);");
|
||||
}
|
||||
|
||||
|
||||
public function StartCollapsibleSection($sSectionLabel, $bOpen = false)
|
||||
{
|
||||
$this->add($this->GetStartCollapsibleSection($sSectionLabel, $bOpen));
|
||||
@@ -909,91 +1006,69 @@ EOF
|
||||
return "</div>";
|
||||
}
|
||||
|
||||
public function add($sHtml)
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::add($sHtml);
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sHtml)
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::add($sHtml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]): 0;
|
||||
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_sCurrentTab, 'offset' => $iOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::start_capture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
if (is_array($offset))
|
||||
{
|
||||
if (isset($this->m_aTabs[$offset['tc']][$offset['tab']]))
|
||||
{
|
||||
$sCaptured = substr($this->m_aTabs[$offset['tc']][$offset['tab']], $offset['offset']);
|
||||
$this->m_aTabs[$offset['tc']][$offset['tab']] = substr($this->m_aTabs[$offset['tc']][$offset['tab']], 0, $offset['offset']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = parent::end_capture($offset);
|
||||
}
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message to be displayed in the 'admin-banner' section at the top of the page
|
||||
*/
|
||||
public function SetMessage($sMessage)
|
||||
{
|
||||
$this->m_sMessage = $sMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
public function AddSearchForm($sClassName, $bOpen = false)
|
||||
{
|
||||
$iSearchSectionId = 0;
|
||||
|
||||
$sStyle = $bOpen ? 'SearchDrawer' : 'SearchDrawer DrawerClosed';
|
||||
$this->add("<div id=\"Search_$iSearchSectionId\" class=\"$sStyle\">\n");
|
||||
$this->add("<h1>Search form for ".Metamodel::GetName($sClassName)."</h1>\n");
|
||||
$this->add_ready_script("\$(\"#LnkSearch_$iSearchSectionId\").click(function() {\$(\"#Search_$iSearchSectionId\").slideToggle('normal'); $(\"#LnkSearch_$iSearchSectionId\").toggleClass('open');});");
|
||||
$oFilter = new DBObjectSearch($sClassName);
|
||||
$sFilter = $oFilter->serialize();
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
cmdbAbstractObject::DisplaySearchForm($this, $oSet, array('operation' => 'search', 'filter' => $sFilter, 'search_form' => true));
|
||||
$this->add("</div>\n");
|
||||
$this->add("<div class=\"HRDrawer\"/></div>\n");
|
||||
$this->add("<div id=\"LnkSearch_$iSearchSectionId\" class=\"DrawerHandle\">Search</div>\n");
|
||||
|
||||
|
||||
$iSearchSectionId++;
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]): 0;
|
||||
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_sCurrentTab, 'offset' => $iOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::start_capture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
if (is_array($offset))
|
||||
{
|
||||
if (isset($this->m_aTabs[$offset['tc']][$offset['tab']]))
|
||||
{
|
||||
$sCaptured = substr($this->m_aTabs[$offset['tc']][$offset['tab']], $offset['offset']);
|
||||
$this->m_aTabs[$offset['tc']][$offset['tab']] = substr($this->m_aTabs[$offset['tc']][$offset['tab']], 0, $offset['offset']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = parent::end_capture($offset);
|
||||
}
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message to be displayed in the 'admin-banner' section at the top of the page
|
||||
*/
|
||||
public function SetMessage($sMessage)
|
||||
{
|
||||
$this->m_sMessage = $sMessage;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -34,7 +34,7 @@ class LoginWebPage extends NiceWebPage
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct("iTop Login");
|
||||
parent::__construct(Dict::S("UI:iTopLogin"));
|
||||
$this->add_style(<<<EOF
|
||||
body {
|
||||
background: #eee;
|
||||
|
||||
@@ -87,22 +87,31 @@ class ApplicationMenu
|
||||
* Main function to add a menu entry into the application, can be called during the definition
|
||||
* of the data model objects
|
||||
*/
|
||||
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex = -1, $fRank)
|
||||
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
|
||||
{
|
||||
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
|
||||
if ($index == -1)
|
||||
{
|
||||
// The menu does not already exist, insert it
|
||||
$index = count(self::$aMenusIndex);
|
||||
self::$aMenusIndex[$index] = array( 'node' => $oMenuNode, 'children' => array());
|
||||
|
||||
if ($iParentIndex == -1)
|
||||
{
|
||||
$sParentId = '';
|
||||
self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sParentId = self::$aMenusIndex[$iParentIndex]['node']->GetMenuId();
|
||||
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
|
||||
}
|
||||
|
||||
// Note: At the time when 'parent', 'rank' and 'source_file' have been added for the reflection API,
|
||||
// they were not used to display the menus (redundant or unused)
|
||||
//
|
||||
$aBacktrace = debug_backtrace();
|
||||
$sFile = $aBacktrace[2]["file"];
|
||||
self::$aMenusIndex[$index] = array('node' => $oMenuNode, 'children' => array(), 'parent' => $sParentId, 'rank' => $fRank, 'source_file' => $sFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,6 +120,14 @@ class ApplicationMenu
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflection API - Get menu entries
|
||||
*/
|
||||
static public function ReflectionMenuNodes()
|
||||
{
|
||||
return self::$aMenusIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point to display the whole menu into the web page, used by iTopWebPage
|
||||
@@ -289,6 +306,11 @@ abstract class MenuNode
|
||||
protected $sMenuId;
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* Properties reflecting how the node has been declared
|
||||
*/
|
||||
protected $aReflectionProperties;
|
||||
|
||||
/**
|
||||
* Class of objects to check if the menu is enabled, null if none
|
||||
*/
|
||||
@@ -323,12 +345,25 @@ abstract class MenuNode
|
||||
public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
{
|
||||
$this->sMenuId = $sMenuId;
|
||||
$this->aReflectionProperties = array();
|
||||
if (strlen($sEnableClass) > 0)
|
||||
{
|
||||
$this->aReflectionProperties['enable_class'] = $sEnableClass;
|
||||
$this->aReflectionProperties['enable_action'] = $iActionCode;
|
||||
$this->aReflectionProperties['enable_permission'] = $iAllowedResults;
|
||||
$this->aReflectionProperties['enable_stimulus'] = $sEnableStimulus;
|
||||
}
|
||||
$this->m_aEnableClasses = array($sEnableClass);
|
||||
$this->m_aEnableActions = array($iActionCode);
|
||||
$this->m_aEnableActionResults = array($iAllowedResults);
|
||||
$this->m_aEnableStimuli = array($sEnableStimulus);
|
||||
$this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank);
|
||||
}
|
||||
|
||||
public function ReflectionProperties()
|
||||
{
|
||||
return $this->aReflectionProperties;
|
||||
}
|
||||
|
||||
public function GetMenuId()
|
||||
{
|
||||
@@ -479,6 +514,7 @@ class TemplateMenuNode extends MenuNode
|
||||
{
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
$this->sTemplateFile = $sTemplateFile;
|
||||
$this->aReflectionProperties['template_file'] = $sTemplateFile;
|
||||
}
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
@@ -537,6 +573,8 @@ class OQLMenuNode extends MenuNode
|
||||
$this->sOQL = $sOQL;
|
||||
$this->bSearch = $bSearch;
|
||||
$this->m_aParams = array();
|
||||
$this->aReflectionProperties['oql'] = $sOQL;
|
||||
$this->aReflectionProperties['do_search'] = $bSearch;
|
||||
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
|
||||
// of the class specified by the OQL...
|
||||
}
|
||||
@@ -548,6 +586,10 @@ class OQLMenuNode extends MenuNode
|
||||
public function SetParameters($aParams)
|
||||
{
|
||||
$this->m_aParams = $aParams;
|
||||
foreach($aParams as $sKey => $value)
|
||||
{
|
||||
$this->aReflectionProperties[$sKey] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
@@ -614,6 +656,7 @@ class SearchMenuNode extends MenuNode
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
$this->sPageTitle = "Menu:$sMenuId+";
|
||||
$this->sClass = $sClass;
|
||||
$this->aReflectionProperties['class'] = $sClass;
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
@@ -653,6 +696,7 @@ class WebPageMenuNode extends MenuNode
|
||||
{
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
$this->sHyperlink = $sHyperlink;
|
||||
$this->aReflectionProperties['url'] = $sHyperlink;
|
||||
}
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
@@ -690,6 +734,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
{
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank);
|
||||
$this->sClass = $sClass;
|
||||
$this->aReflectionProperties['class'] = $sClass;
|
||||
}
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
|
||||
@@ -212,8 +212,10 @@ EOF
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// For Wizard helper to process the ajax replies
|
||||
$this->add('<div id="ajax_content"></div>');
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
@@ -273,13 +275,9 @@ EOF
|
||||
{
|
||||
// Home-made and very limited display of an object set
|
||||
|
||||
//
|
||||
//$oSet->Seek(0);// juste pour que le warning soit moins crado
|
||||
//$oSet->Fetch();// juste pour que le warning soit moins crado
|
||||
//
|
||||
|
||||
$this->add("<div id=\"listOf$sClass\">\n");
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => "listOf$sClass", 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$sUniqueId = $sClass.$this->GetUniqueId();
|
||||
$this->add("<div id=\"$sUniqueId\">\n"); // The id here MUST be the same as currentId, otherwise the pagination will be broken
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $sUniqueId, 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$this->add("</div>\n");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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,41 @@ 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()';
|
||||
if (isset($aArgs['wizHelper']))
|
||||
{
|
||||
$sWizHelper = $aArgs['wizHelper'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
}
|
||||
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
|
||||
$sJSSearchMode = 'false';
|
||||
}
|
||||
if (is_null($oAllowedValues))
|
||||
{
|
||||
@@ -155,7 +170,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 +199,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 +230,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 +293,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";
|
||||
@@ -307,7 +323,7 @@ EOF
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of sTargetClass
|
||||
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
|
||||
*/
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
|
||||
@@ -318,7 +334,23 @@ EOF
|
||||
}
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
if ($sRemoteClass != $this->sTargetClass)
|
||||
{
|
||||
//$oBaseClassFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
//$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
//$oFilter->AddConditionExpression($oBaseClassFilter->GetCriteria());
|
||||
//$oFilter->TransferConditionExpression($oBaseClassFilter, array());
|
||||
//$oFilter->TransferConditionExpression($oBaseClassFilter, array($this->sTargetClass => array('*' => $sRemoteClass.'_'.strtolower($this->sTargetClass))));
|
||||
$sFilter = str_replace(" $this->sTargetClass ", " $sRemoteClass ", $sFilter);
|
||||
$sFilter = str_replace("`$this->sTargetClass`", "`$sRemoteClass`", $sFilter);
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
}
|
||||
//$oP->p($oFilter->ToOQL());
|
||||
$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 +360,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 +380,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 +393,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 +465,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 +474,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
|
||||
@@ -103,45 +104,94 @@ class UILinksWidget
|
||||
{
|
||||
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
if(is_object($linkObjOrId))
|
||||
{
|
||||
$key = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$sPrefix .= "[$key][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$key}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"$key\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
|
||||
$sSafeId = str_replace(array('[',']','-'), '_', $sFieldId);
|
||||
$sSafeId = self::MakeID($sFieldId);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $linkObjOrId->Get($sFieldCode), '' /* DisplayValue */, $sSafeId, $sNameSuffix, 0, $aArgs);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
$sState = $linkObjOrId->GetState();
|
||||
}
|
||||
else
|
||||
{
|
||||
// form for creating a new record
|
||||
$sPrefix .= "[$linkObjOrId][";
|
||||
$iRemoteObjKey = -$linkObjOrId;
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, -$linkObjOrId);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".(-$linkObjOrId);
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$linkObjOrId\">";
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId.']';
|
||||
$sSafeId = str_replace(array('[',']','-'), '_', $sFieldId);
|
||||
$sSafeId = self::MakeID($sFieldId);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
$sState = '';
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
$(".date-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
buttonImageOnly: true,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
constrainInput: false,
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
$(".datetime-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
buttonImageOnly: true,
|
||||
dateFormat: 'yy-mm-dd 00:00:00',
|
||||
constrainInput: false,
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
$sExtKeyToMeId = self::MakeID($sPrefix.$this->m_sExtKeyToMe);
|
||||
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
|
||||
$sExtKeyToRemoteId = self::MakeID($sPrefix.$this->m_sExtKeyToRemote);
|
||||
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
|
||||
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
|
||||
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
|
||||
EOF
|
||||
);
|
||||
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
|
||||
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
@@ -149,6 +199,11 @@ class UILinksWidget
|
||||
}
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
protected function MakeID($sName)
|
||||
{
|
||||
return str_replace(array('[', ']'), '_', $sName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display one row of the whole form
|
||||
|
||||
@@ -50,6 +50,8 @@ class WebPage
|
||||
protected $sContentType;
|
||||
protected $sContentDisposition;
|
||||
protected $sContentFileName;
|
||||
protected $s_sOutputFormat;
|
||||
protected $a_OutputOptions;
|
||||
|
||||
public function __construct($s_title)
|
||||
{
|
||||
@@ -67,6 +69,8 @@ class WebPage
|
||||
$this->sContentType = '';
|
||||
$this->sContentDisposition = '';
|
||||
$this->sContentFileName = '';
|
||||
$this->s_OutputFormat = utils::ReadParam('output_format', 'html');
|
||||
$this->a_OutputOptions = array();
|
||||
ob_start(); // Start capturing the output
|
||||
}
|
||||
|
||||
@@ -515,5 +519,67 @@ class WebPage
|
||||
{
|
||||
return str_ireplace('<script', '<script', $sHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the currently selected output format
|
||||
* @return string The selected output format: html, pdf...
|
||||
*/
|
||||
public function GetOutputFormat()
|
||||
{
|
||||
return $this->s_OutputFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the desired output format is possible or not
|
||||
* @param string $sOutputFormat The desired output format: html, pdf...
|
||||
* @return bool True if the format is Ok, false otherwise
|
||||
*/
|
||||
function IsOutputFormatAvailable($sOutputFormat)
|
||||
{
|
||||
$bResult = false;
|
||||
switch($sOutputFormat)
|
||||
{
|
||||
case 'html':
|
||||
$bResult = true; // Always supported
|
||||
break;
|
||||
|
||||
case 'pdf':
|
||||
$bResult = @is_readable(APPROOT.'lib/MPDF/mpdf.php');
|
||||
break;
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a named output option for the given format
|
||||
* @param string $sFormat The format: html or pdf
|
||||
* @param string $sOptionName The name of the option
|
||||
* @return mixed false if the option was never set or the options's value
|
||||
*/
|
||||
public function GetOutputOption($sFormat, $sOptionName)
|
||||
{
|
||||
if (isset($this->a_OutputOptions[$sFormat][$sOptionName]))
|
||||
{
|
||||
return $this->a_OutputOptions[$sFormat][$sOptionName];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Sets a named output option for the given format
|
||||
* @param string $sFormat The format for which to set the option: html or pdf
|
||||
* @param string $sOptionName the name of the option
|
||||
* @param mixed $sValue The value of the option
|
||||
*/
|
||||
public function SetOutputOption($sFormat, $sOptionName, $sValue)
|
||||
{
|
||||
if (!isset($this->a_OutputOptions[$sFormat]))
|
||||
{
|
||||
$this->a_OutputOptions[$sFormat] = array($sOptionName => $sValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->a_OutputOptions[$sFormat][$sOptionName] = $sValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -305,7 +305,8 @@ class ActionEmail extends ActionNotification
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
|
||||
if (!is_null($oLog))
|
||||
{
|
||||
// Note: we have to secure this because those values are calculated
|
||||
|
||||
@@ -140,7 +140,7 @@ class AsyncSendEmail extends AsyncTask
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("header", array("allowed_values"=>null, "sql"=>"header", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
|
||||
@@ -116,6 +116,8 @@ abstract class AttributeDefinition
|
||||
$this->m_aParams = $aParams;
|
||||
$this->ConsistencyCheck();
|
||||
}
|
||||
|
||||
// Left here for backward compatibility, deprecated in 2.0
|
||||
public function OverloadParams($aParams)
|
||||
{
|
||||
foreach ($aParams as $sParam => $value)
|
||||
@@ -130,6 +132,12 @@ abstract class AttributeDefinition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetParams()
|
||||
{
|
||||
return $this->m_aParams;
|
||||
}
|
||||
|
||||
public function SetHostClass($sHostClass)
|
||||
{
|
||||
$this->m_sHostClass = $sHostClass;
|
||||
@@ -141,7 +149,7 @@ abstract class AttributeDefinition
|
||||
|
||||
// Note: I could factorize this code with the parameter management made for the AttributeDef class
|
||||
// to be overloaded
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
@@ -444,7 +452,7 @@ abstract class AttributeDefinition
|
||||
*/
|
||||
class AttributeLinkedSet extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("allowed_values", "depends_on", "linked_class", "ext_key_to_me", "count_min", "count_max"));
|
||||
}
|
||||
@@ -754,7 +762,7 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
*/
|
||||
class AttributeLinkedSetIndirect extends AttributeLinkedSet
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("ext_key_to_remote"));
|
||||
}
|
||||
@@ -771,7 +779,7 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet
|
||||
*/
|
||||
class AttributeDBFieldVoid extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("allowed_values", "depends_on", "sql"));
|
||||
}
|
||||
@@ -857,7 +865,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
|
||||
*/
|
||||
class AttributeDBField extends AttributeDBFieldVoid
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("default_value", "is_null_allowed"));
|
||||
}
|
||||
@@ -872,7 +880,7 @@ class AttributeDBField extends AttributeDBFieldVoid
|
||||
*/
|
||||
class AttributeInteger extends AttributeDBField
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -968,7 +976,7 @@ class AttributeInteger extends AttributeDBField
|
||||
*/
|
||||
class AttributeDecimal extends AttributeDBField
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('digits', 'decimals' /* including precision */));
|
||||
}
|
||||
@@ -1063,7 +1071,7 @@ class AttributeDecimal extends AttributeDBField
|
||||
*/
|
||||
class AttributeBoolean extends AttributeInteger
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -1094,7 +1102,7 @@ class AttributeBoolean extends AttributeInteger
|
||||
*/
|
||||
class AttributeString extends AttributeDBField
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -1220,7 +1228,7 @@ class AttributeString extends AttributeDBField
|
||||
*/
|
||||
class AttributeClass extends AttributeString
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("class_category", "more_values"));
|
||||
}
|
||||
@@ -1272,7 +1280,7 @@ class AttributeClass extends AttributeString
|
||||
*/
|
||||
class AttributeApplicationLanguage extends AttributeString
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
}
|
||||
@@ -1362,7 +1370,7 @@ class AttributeFinalClass extends AttributeString
|
||||
*/
|
||||
class AttributePassword extends AttributeString
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -1829,7 +1837,7 @@ class AttributeCaseLog extends AttributeLongText
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class AttributeHTML extends AttributeText
|
||||
class AttributeHTML extends AttributeLongText
|
||||
{
|
||||
public function GetEditClass() {return "HTML";}
|
||||
|
||||
@@ -1924,7 +1932,7 @@ class AttributeTemplateHTML extends AttributeText
|
||||
*/
|
||||
class AttributeEnum extends AttributeString
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -2094,7 +2102,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
return "Y-m-d H:i:s";
|
||||
}
|
||||
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -2308,6 +2316,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
|
||||
default:
|
||||
$oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, $aParams);
|
||||
|
||||
}
|
||||
|
||||
return $oNewCondition;
|
||||
@@ -2405,7 +2414,7 @@ class AttributeDate extends AttributeDateTime
|
||||
return "Y-m-d";
|
||||
}
|
||||
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
//return array_merge(parent::ListExpectedParams(), array());
|
||||
@@ -2491,7 +2500,7 @@ class AttributeDeadline extends AttributeDateTime
|
||||
*/
|
||||
class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("targetclass", "is_null_allowed", "on_target_delete"));
|
||||
}
|
||||
@@ -2608,7 +2617,7 @@ class AttributeHierarchicalKey extends AttributeExternalKey
|
||||
{
|
||||
protected $m_sTargetClass;
|
||||
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
$aParams = parent::ListExpectedParams();
|
||||
$idx = array_search('targetclass', $aParams);
|
||||
@@ -2732,7 +2741,7 @@ class AttributeHierarchicalKey extends AttributeExternalKey
|
||||
*/
|
||||
class AttributeExternalField extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("extkey_attcode", "target_attcode"));
|
||||
}
|
||||
@@ -2959,7 +2968,7 @@ class AttributeExternalField extends AttributeDefinition
|
||||
*/
|
||||
class AttributeURL extends AttributeString
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
//return parent::ListExpectedParams();
|
||||
return array_merge(parent::ListExpectedParams(), array("target"));
|
||||
@@ -2993,7 +3002,7 @@ class AttributeURL extends AttributeString
|
||||
*/
|
||||
class AttributeBlob extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("depends_on"));
|
||||
}
|
||||
@@ -3140,7 +3149,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
*/
|
||||
class AttributeOneWayPassword extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array("depends_on"));
|
||||
}
|
||||
@@ -3290,16 +3299,26 @@ class AttributeOneWayPassword extends AttributeDefinition
|
||||
}
|
||||
|
||||
// Indexed array having two dimensions
|
||||
class AttributeTable extends AttributeText
|
||||
class AttributeTable extends AttributeDBField
|
||||
{
|
||||
public function GetEditClass() {return "Text";}
|
||||
protected function GetSQLCol() {return "TEXT";}
|
||||
public function GetEditClass() {return "Table";}
|
||||
protected function GetSQLCol() {return "LONGTEXT";}
|
||||
|
||||
public function GetMaxSize()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function GetNullValue()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function IsNull($proposedValue)
|
||||
{
|
||||
return (count($proposedValue) == 0);
|
||||
}
|
||||
|
||||
// Facilitate things: allow the user to Set the value from a string
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
@@ -3362,13 +3381,39 @@ class AttributeTable extends AttributeText
|
||||
$sRes .= "</TABLE>";
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
|
||||
{
|
||||
// Not implemented
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null)
|
||||
{
|
||||
if (count($value) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$sRes = "";
|
||||
foreach($value as $iRow => $aRawData)
|
||||
{
|
||||
$sRes .= "<row>";
|
||||
foreach ($aRawData as $iCol => $cell)
|
||||
{
|
||||
$sCell = Str::pure2xml((string)$cell);
|
||||
$sRes .= "<cell icol=\"$iCol\">$sCell</cell>";
|
||||
}
|
||||
$sRes .= "</row>";
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
|
||||
// The PHP value is a hash array, it is stored as a TEXT column
|
||||
class AttributePropertySet extends AttributeTable
|
||||
{
|
||||
public function GetEditClass() {return "Text";}
|
||||
protected function GetSQLCol() {return "TEXT";}
|
||||
public function GetEditClass() {return "PropertySet";}
|
||||
|
||||
// Facilitate things: allow the user to Set the value from a string
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
@@ -3395,6 +3440,10 @@ class AttributePropertySet extends AttributeTable
|
||||
$sRes .= "<TBODY>";
|
||||
foreach($value as $sProperty => $sValue)
|
||||
{
|
||||
if ($sProperty == 'auth_pwd')
|
||||
{
|
||||
$sValue = '*****';
|
||||
}
|
||||
$sRes .= "<TR>";
|
||||
$sCell = str_replace("\n", "<br>\n", Str::pure2html((string)$sValue));
|
||||
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
|
||||
@@ -3404,6 +3453,53 @@ class AttributePropertySet extends AttributeTable
|
||||
$sRes .= "</TABLE>";
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
|
||||
{
|
||||
if (count($value) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$aRes = array();
|
||||
foreach($value as $sProperty => $sValue)
|
||||
{
|
||||
if ($sProperty == 'auth_pwd')
|
||||
{
|
||||
$sValue = '*****';
|
||||
}
|
||||
$sFrom = array(',', '=');
|
||||
$sTo = array('\,', '\=');
|
||||
$aRes[] = $sProperty.'='.str_replace($sFrom, $sTo, (string)$sValue);
|
||||
}
|
||||
$sRaw = implode(',', $aRes);
|
||||
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, $sRaw);
|
||||
return $sTextQualifier.$sEscaped.$sTextQualifier;
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null)
|
||||
{
|
||||
if (count($value) == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$sRes = "";
|
||||
foreach($value as $sProperty => $sValue)
|
||||
{
|
||||
if ($sProperty == 'auth_pwd')
|
||||
{
|
||||
$sValue = '*****';
|
||||
}
|
||||
$sRes .= "<property id=\"$sProperty\">";
|
||||
$sRes .= Str::pure2xml((string)$sValue);
|
||||
$sRes .= "</property>";
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3413,7 +3509,7 @@ class AttributePropertySet extends AttributeTable
|
||||
*/
|
||||
class AttributeComputedFieldVoid extends AttributeDefinition
|
||||
{
|
||||
static protected function ListExpectedParams()
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array());
|
||||
}
|
||||
|
||||
@@ -401,7 +401,13 @@ class BulkChange
|
||||
if ($sAttCode == 'id') continue;
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
|
||||
$aReasons = array();
|
||||
$iFlags = $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
|
||||
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) )
|
||||
{
|
||||
$aErrors[$sAttCode] = "the attribute '$sAttCode' is read-only and cannot be modified (current value: ".$oTargetObj->Get($sAttCode).", proposed value: {$aRowData[$iCol]}).";
|
||||
}
|
||||
else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -93,6 +93,23 @@ abstract class CMDBObject extends DBObject
|
||||
protected static $m_oCurrChange = null;
|
||||
|
||||
|
||||
public static function SetCurrentChange(CMDBChange $oChange)
|
||||
{
|
||||
self::$m_oCurrChange = $oChange;
|
||||
}
|
||||
|
||||
//
|
||||
// Todo: simplify the APIs and do not pass the current change as an argument anymore
|
||||
// SetCurrentChange to be invoked in very few cases (UI.php, CSV import, Data synchro)
|
||||
// GetCurrentChange to be called ONCE (!) by CMDBChangeOp::OnInsert ($this->Set('change', ..GetCurrentChange())
|
||||
// GetCurrentChange to create a default change if not already done in the current context
|
||||
//
|
||||
public static function GetCurrentChange()
|
||||
{
|
||||
return self::$m_oCurrChange;
|
||||
}
|
||||
|
||||
|
||||
private function RecordObjCreation(CMDBChange $oChange)
|
||||
{
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate");
|
||||
|
||||
@@ -197,6 +197,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'csv_import_history_display' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Display the history tab in the import wizard',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'access_mode' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Combination of flags (ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE, or ACCESS_FULL)',
|
||||
@@ -400,6 +408,15 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_update_profiles' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Whether or not to update the profiles of an existing user from the CAS information',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_profile_pattern' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A regular expression pattern to extract the name of the iTop profile from the name of an LDAP/CAS group',
|
||||
@@ -409,6 +426,15 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_default_profiles' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A semi-colon separated list of iTop Profiles to use when creating a new user if no profile is retrieved from CAS',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 'Portal user',
|
||||
'value' => 'Portal user',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_debug' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Activate the CAS debug',
|
||||
@@ -445,6 +471,15 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'complex_actions_limit' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Display the "actions" menu items that require long computation only if the list of objects is contains less objects than this number (0 means no limit)',
|
||||
// examples... not used
|
||||
'default' => 50,
|
||||
'value' => 50,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
|
||||
@@ -302,30 +302,53 @@ abstract class DBObject
|
||||
$this->Reload();
|
||||
}
|
||||
|
||||
if ($oAttDef->IsExternalKey() && is_object($value))
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// Setting an external key with a whole object (instead of just an ID)
|
||||
// let's initialize also the external fields that depend on it
|
||||
// (useful when building objects in memory and not from a query)
|
||||
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass())))
|
||||
if (is_object($value))
|
||||
{
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
// Setting an external key with a whole object (instead of just an ID)
|
||||
// let's initialize also the external fields that depend on it
|
||||
// (useful when building objects in memory and not from a query)
|
||||
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass())))
|
||||
{
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aCurrValues[$sAttCode] = $value->GetKey();
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
}
|
||||
$this->m_aCurrValues[$sAttCode.'_friendlyname'] = $value->GetName();
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ($this->m_aCurrValues[$sAttCode] != $value)
|
||||
{
|
||||
// The object has changed, reset caches
|
||||
$this->m_bCheckStatus = null;
|
||||
$this->m_aAsArgs = null;
|
||||
|
||||
$this->m_aCurrValues[$sAttCode] = $value->GetKey();
|
||||
// If the external key changed, invalidate all the external fields (and friendly name) related to this external key
|
||||
$this->m_aCurrValues[$sAttCode] = $value;
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
unset($this->m_aLoadedAtt[$sCode]);
|
||||
$this->m_aCurrValues[$sCode] = null;
|
||||
}
|
||||
}
|
||||
$this->m_aCurrValues[$sAttCode.'_friendlyname'] = null;
|
||||
unset($this->m_aLoadedAtt[$sAttCode.'_friendlyname']);
|
||||
}
|
||||
|
||||
// The object has changed, reset caches
|
||||
$this->m_bCheckStatus = null;
|
||||
$this->m_aAsArgs = null;
|
||||
|
||||
// Make sure we do not reload it anymore... before saving it
|
||||
$this->RegisterAsDirty();
|
||||
|
||||
return;
|
||||
}
|
||||
if(!$oAttDef->IsScalar() && !is_object($value))
|
||||
@@ -400,10 +423,60 @@ abstract class DBObject
|
||||
{
|
||||
throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
|
||||
}
|
||||
if ($this->m_bIsInDB && !isset($this->m_aLoadedAtt[$sAttCode]) && !$this->m_bDirty)
|
||||
if ($this->m_bIsInDB && !isset($this->m_aLoadedAtt[$sAttCode]))
|
||||
{
|
||||
// #@# non-scalar attributes.... handle that differently
|
||||
$this->Reload();
|
||||
if (!$this->m_bDirty)
|
||||
{
|
||||
$this->Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the missing attribute is an external fields (or a friendlyname), try to selectively reload it
|
||||
// from the value of its external key... and reload the related external fields & friendlyname as well
|
||||
$sTargetClass = '';
|
||||
$iCurrKey = 0;
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$iCurrKey = $this->m_aCurrValues[$oAttDef->GetKeyAttCode()];
|
||||
$sTargetClass= $oAttDef->GetTargetClass();
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sKeyAttCode);
|
||||
$iCurrKey = $this->m_aCurrValues[$oAttDef->GetKeyAttCode()];
|
||||
$sTargetClass = $oKeyAttDef->GetTargetClass();
|
||||
}
|
||||
|
||||
if (($sTargetClass != '') && ($iCurrKey != 0))
|
||||
{
|
||||
$oTargetObj = MetaModel::GetObject($sTargetClass, $iCurrKey, false);
|
||||
if (is_object($oTargetObj))
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sKeyAttCode))
|
||||
{
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
$this->m_aCurrValues[$sCode] = $oTargetObj->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
}
|
||||
if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$this->m_aLoadedAtt[$sAttCode] = true;
|
||||
$this->m_aCurrValues[$sAttCode] = $oTargetObj->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aLoadedAtt[$sKeyAttCode.'_friendlyname'] = true;
|
||||
$this->m_aCurrValues[$sKeyAttCode.'_friendlyname'] = $oTargetObj->GetName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
if ($value instanceof DBObjectSet)
|
||||
@@ -981,30 +1054,35 @@ abstract class DBObject
|
||||
$aDelta = array();
|
||||
foreach ($aProposal as $sAtt => $proposedValue)
|
||||
{
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// Ignore external fields and friendly names that change only as a consequence of modifying another field
|
||||
if ((!$oAttDef->IsExternalField() && !($oAttDef instanceof AttributeFriendlyName)))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// The value is an object, the comparison is not strict
|
||||
if (!$oLinkAttDef->Equals($proposedValue, $this->m_aOrigValues[$sAtt]))
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// The value is an object, the comparison is not strict
|
||||
if (!$oLinkAttDef->Equals($proposedValue, $this->m_aOrigValues[$sAtt]))
|
||||
{
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1303,6 +1381,11 @@ abstract class DBObject
|
||||
return $this->DBInsert();
|
||||
}
|
||||
|
||||
public function DBInsertTrackedNoReload(CMDBChange $oVoid)
|
||||
{
|
||||
return $this->DBInsertNoReload();
|
||||
}
|
||||
|
||||
// Creates a copy of the current object into the database
|
||||
// Returns the id of the newly created object
|
||||
public function DBClone($iNewKey = null)
|
||||
@@ -1656,7 +1739,7 @@ abstract class DBObject
|
||||
// #@# Note: This has been proven to be quite slow, this can slow down bulk load
|
||||
$sAsHtml = $this->GetAsHtml($sAttCode);
|
||||
$aScalarArgs[$sArgName.'->html('.$sAttCode.')'] = $sAsHtml;
|
||||
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = strip_tags($sAsHtml);
|
||||
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = $this->GetEditValue($sAttCode); // "Nice" display value, but without HTML tags and entities
|
||||
}
|
||||
// Do something for case logs... quick N' dirty...
|
||||
if ($aScalarArgs[$sArgName.'->'.$sAttCode] instanceof ormCaseLog)
|
||||
|
||||
@@ -66,6 +66,8 @@ class DBObjectSearch
|
||||
$this->m_aRelatedTo = array();
|
||||
$this->m_bDataFiltered = false;
|
||||
$this->m_aParentConditions = array();
|
||||
|
||||
$this->m_aModifierProperties = array();
|
||||
}
|
||||
|
||||
public function AllowAllData() {$this->m_bAllowAllData = true;}
|
||||
@@ -126,6 +128,23 @@ class DBObjectSearch
|
||||
}
|
||||
|
||||
|
||||
public function SetModifierProperty($sPluginClass, $sProperty, $value)
|
||||
{
|
||||
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
|
||||
}
|
||||
|
||||
public function GetModifierProperties($sPluginClass)
|
||||
{
|
||||
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
|
||||
{
|
||||
return $this->m_aModifierProperties[$sPluginClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
public function IsAny()
|
||||
{
|
||||
// #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false;
|
||||
@@ -788,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)
|
||||
@@ -799,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
|
||||
|
||||
@@ -137,7 +137,7 @@ class EMail
|
||||
}
|
||||
}
|
||||
|
||||
protected function AddToHeader($sKey, $sValue)
|
||||
public function AddToHeader($sKey, $sValue)
|
||||
{
|
||||
if (strlen($sValue) > 0)
|
||||
{
|
||||
|
||||
@@ -174,7 +174,7 @@ class EventNotificationEmail extends EventNotification
|
||||
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body')); // Attributes to be displayed for the complete details
|
||||
@@ -340,14 +340,22 @@ class EventLoginUsage extends Event
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
$aZList = array('date', 'user_id');
|
||||
if (MetaModel::IsValidAttCode('Contact', 'name'))
|
||||
{
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
$aZList[] = 'contact_name';
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Contact', 'email'))
|
||||
{
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
$aZList[] = 'contact_email';
|
||||
}
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'user_id', 'contact_name', 'contact_email', 'userinfo', 'message')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'user_id', 'contact_name', 'contact_email', 'userinfo')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('date', 'user_id', 'contact_name', 'contact_email')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
@@ -953,10 +953,10 @@ class QueryBuilderExpressions
|
||||
protected $m_aSelectExpr;
|
||||
protected $m_aJoinFields;
|
||||
|
||||
public function __construct($aSelect, $oCondition)
|
||||
public function __construct($oCondition)
|
||||
{
|
||||
$this->m_oConditionExpr = $oCondition;
|
||||
$this->m_aSelectExpr = $aSelect;
|
||||
$this->m_aSelectExpr = array();
|
||||
$this->m_aJoinFields = array();
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ abstract class FilterDefinition
|
||||
$this->ConsistencyCheck();
|
||||
}
|
||||
|
||||
// Left here for backward compatibility, deprecated in 2.0
|
||||
public function OverloadParams($aParams)
|
||||
{
|
||||
foreach ($aParams as $sParam => $value)
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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
|
||||
@@ -25,8 +28,6 @@ require_once(APPROOT.'core/modulehandler.class.inc.php');
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// #@# todo: change into class const (see Doctrine)
|
||||
// Doctrine example
|
||||
// class toto
|
||||
@@ -1172,6 +1173,33 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
|
||||
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 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
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 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
// Build the list of available extensions
|
||||
//
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension');
|
||||
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)
|
||||
@@ -1542,6 +1549,8 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
self::$m_aChildClasses[$sAncestorClass][] = $sTargetClass;
|
||||
}
|
||||
}
|
||||
|
||||
// Left here for backward compatibility, deprecated in 2.0
|
||||
public static function Init_OverloadAttributeParams($sAttCode, $aParams)
|
||||
{
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
@@ -1562,9 +1571,12 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
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')
|
||||
@@ -1625,11 +1637,14 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
// 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)
|
||||
@@ -1916,7 +1931,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
//
|
||||
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
|
||||
@@ -1934,12 +1949,26 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
}
|
||||
}
|
||||
|
||||
// Compute query modifiers properties (can be set in the search itself, by the context, etc.)
|
||||
//
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
|
||||
if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries)
|
||||
{
|
||||
// Need to identify the query
|
||||
$sOqlQuery = $oFilter->ToOql();
|
||||
|
||||
$sRawId = $sOqlQuery;
|
||||
if (count($aModifierProperties))
|
||||
{
|
||||
array_multisort($aModifierProperties);
|
||||
$sModifierProperties = json_encode($aModifierProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sModifierProperties = '';
|
||||
}
|
||||
|
||||
$sRawId = $sOqlQuery.$sModifierProperties;
|
||||
if (!is_null($aAttToLoad))
|
||||
{
|
||||
foreach($aAttToLoad as $sAlias => $aAttributes)
|
||||
@@ -2035,12 +2064,10 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
|
||||
if (!isset($oSelect))
|
||||
{
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $aAttToLoad, array(), true /* main query */);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, $aAttToLoad, array(), true /* main query */);
|
||||
$oSelect->SetSourceOQL($sOqlQuery);
|
||||
$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
|
||||
|
||||
@@ -2149,12 +2176,33 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
}
|
||||
}
|
||||
|
||||
protected static function MakeModifierProperties($oFilter)
|
||||
{
|
||||
// Compute query modifiers properties (can be set in the search itself, by the context, etc.)
|
||||
//
|
||||
$aModifierProperties = array();
|
||||
foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier)
|
||||
{
|
||||
// Lowest precedence: the application context
|
||||
$aPluginProps = ApplicationContext::GetPluginProperties($sPluginClass);
|
||||
// Highest precedence: programmatically specified (or OQL)
|
||||
foreach($oFilter->GetModifierProperties($sPluginClass) as $sProp => $value)
|
||||
{
|
||||
$aPluginProps[$sProp] = $value;
|
||||
}
|
||||
if (count($aPluginProps) > 0)
|
||||
{
|
||||
$aModifierProperties[$sPluginClass] = $aPluginProps;
|
||||
}
|
||||
}
|
||||
return $aModifierProperties;
|
||||
}
|
||||
|
||||
public static function MakeDeleteQuery(DBObjectSearch $oFilter, $aArgs = array())
|
||||
{
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, null, array(), true /* main query */);
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, null, array(), true /* main query */);
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderDelete($aScalarArgs);
|
||||
}
|
||||
@@ -2162,26 +2210,21 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
public static function MakeUpdateQuery(DBObjectSearch $oFilter, $aValues, $aArgs = array())
|
||||
{
|
||||
// $aValues is an array of $sAttCode => $value
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, null, $aValues, true /* main query */);
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, null, $aValues, true /* main query */);
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderUpdate($aScalarArgs);
|
||||
}
|
||||
|
||||
private static function MakeQuery($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false)
|
||||
private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false)
|
||||
{
|
||||
// Note: query class might be different than the class of the filter
|
||||
// -> this occurs when we are linking our class to an external class (referenced by, or pointing to)
|
||||
$sClass = $oFilter->GetFirstJoinedClass();
|
||||
$sClassAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
|
||||
$bIsOnQueriedClass = array_key_exists($sClassAlias, $aSelectedClasses);
|
||||
if ($bIsOnQueriedClass)
|
||||
{
|
||||
$aClassAliases = array_merge($aClassAliases, $oFilter->GetJoinedClasses());
|
||||
}
|
||||
$bIsOnQueriedClass = array_key_exists($sClassAlias, $oBuild->GetRootFilter()->GetSelectedClasses());
|
||||
|
||||
self::DbgTrace("Entering: ".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
|
||||
|
||||
@@ -2191,7 +2234,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
if ($bIsOnQueriedClass)
|
||||
{
|
||||
// default to the whole list of attributes + the very std id/finalclass
|
||||
$oQBExpr->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias));
|
||||
$oBuild->m_oQBExpressions->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias));
|
||||
|
||||
if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad))
|
||||
{
|
||||
@@ -2207,7 +2250,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
{
|
||||
$oQBExpr->AddSelect($sClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias));
|
||||
$oBuild->m_oQBExpressions->AddSelect($sClassAlias.$sAttCode.$sColId, new FieldExpression($sAttCode.$sColId, $sClassAlias));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2227,14 +2270,14 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
foreach($aFullText as $sFTNeedle)
|
||||
{
|
||||
$oNewCond = new BinaryExpression($oTextFields, 'LIKE', new ScalarExpression("%$sFTNeedle%"));
|
||||
$oQBExpr->AddCondition($oNewCond);
|
||||
$oBuild->m_oQBExpressions->AddCondition($oNewCond);
|
||||
}
|
||||
}
|
||||
}
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
$aExpectedAtts = array(); // array of (attcode => fieldexpression)
|
||||
//echo "<p>".__LINE__.": GetUnresolvedFields($sClassAlias, ...)</p>\n";
|
||||
$oQBExpr->GetUnresolvedFields($sClassAlias, $aExpectedAtts);
|
||||
$oBuild->m_oQBExpressions->GetUnresolvedFields($sClassAlias, $aExpectedAtts);
|
||||
|
||||
// Compute a clear view of required joins (from the current class)
|
||||
// Build the list of external keys:
|
||||
@@ -2271,9 +2314,9 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
$aTranslateNow = array();
|
||||
$aTranslateNow[$sClassAlias]['friendlyname'] = self::GetNameExpression($sClass, $sClassAlias);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
$oBuild->m_oQBExpressions->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
foreach($aNameSpec[1] as $i => $sAttCode)
|
||||
@@ -2315,7 +2358,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
self::DbgTrace("Main (=leaf) class, call MakeQuerySingleTable()");
|
||||
if (self::HasTable($sClass))
|
||||
{
|
||||
$oSelectBase = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sClass, $aExtKeys, $aValues);
|
||||
$oSelectBase = self::MakeQuerySingleTable($oBuild, $oFilter, $sClass, $aExtKeys, $aValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2324,7 +2367,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
// As the join will not filter on the expected classes, we have to specify it explicitely
|
||||
$sExpectedClasses = implode("', '", self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
|
||||
$oQBExpr->AddCondition($oFinalClassRestriction);
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
|
||||
// Then we join the queries of the eventual parent classes (compound model)
|
||||
@@ -2333,7 +2376,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
if (!self::HasTable($sParentClass)) continue;
|
||||
//echo "<p>Parent class: $sParentClass... let's call MakeQuerySingleTable()</p>";
|
||||
self::DbgTrace("Parent class: $sParentClass... let's call MakeQuerySingleTable()");
|
||||
$oSelectParentTable = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sParentClass, $aExtKeys, $aValues);
|
||||
$oSelectParentTable = self::MakeQuerySingleTable($oBuild, $oFilter, $sParentClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
@@ -2358,11 +2401,11 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
//self::DbgTrace($oSelectForeign->RenderSelect(array()));
|
||||
|
||||
$sForeignClassAlias = $oForeignFilter->GetFirstJoinedClassAlias();
|
||||
$oQBExpr->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias));
|
||||
$oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias));
|
||||
|
||||
$oSelectForeign = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oForeignFilter, $aAttToLoad);
|
||||
$oSelectForeign = self::MakeQuery($oBuild, $oForeignFilter, $aAttToLoad);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField();
|
||||
$sForeignKeyTable = $oJoinExpr->GetParent();
|
||||
$sForeignKeyColumn = $oJoinExpr->GetName();
|
||||
$oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyColumn, $sForeignKeyTable);
|
||||
@@ -2401,8 +2444,8 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
//
|
||||
if ($bIsMainQuery)
|
||||
{
|
||||
$oSelectBase->SetCondition($oQBExpr->GetCondition());
|
||||
$oSelectBase->SetSelect($oQBExpr->GetSelect());
|
||||
$oSelectBase->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelectBase->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
}
|
||||
|
||||
// That's all... cross fingers and we'll get some working query
|
||||
@@ -2413,7 +2456,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
return $oSelectBase;
|
||||
}
|
||||
|
||||
protected static function MakeQuerySingleTable($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, $oFilter, $sTableClass, $aExtKeys, $aValues)
|
||||
protected static function MakeQuerySingleTable(&$oBuild, $oFilter, $sTableClass, $aExtKeys, $aValues)
|
||||
{
|
||||
// $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields))
|
||||
//echo "MAKEQUERY($sTableClass)-liste des clefs externes($sTableClass): <pre>".print_r($aExtKeys, true)."</pre><br/>\n";
|
||||
@@ -2427,13 +2470,13 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
$sTargetClass = $oFilter->GetFirstJoinedClass();
|
||||
$sTargetAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
$sTable = self::DBGetTable($sTableClass);
|
||||
$sTableAlias = self::GenerateUniqueAlias($aTableAliases, $sTargetAlias.'_'.$sTable, $sTable);
|
||||
$sTableAlias = $oBuild->GenerateTableAlias($sTargetAlias.'_'.$sTable, $sTable);
|
||||
|
||||
$aTranslation = array();
|
||||
$aExpectedAtts = array();
|
||||
$oQBExpr->GetUnresolvedFields($sTargetAlias, $aExpectedAtts);
|
||||
$oBuild->m_oQBExpressions->GetUnresolvedFields($sTargetAlias, $aExpectedAtts);
|
||||
|
||||
$bIsOnQueriedClass = array_key_exists($sTargetAlias, $aSelectedClasses);
|
||||
$bIsOnQueriedClass = array_key_exists($sTargetAlias, $oBuild->GetRootFilter()->GetSelectedClasses());
|
||||
|
||||
self::DbgTrace("Entering: tableclass=$sTableClass, filter=".$oFilter->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
|
||||
|
||||
@@ -2482,6 +2525,18 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
$aUpdateValues[$sColumn] = $sValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - The SQL query, for this table only
|
||||
//
|
||||
$oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField);
|
||||
|
||||
// 3 - Resolve expected expressions (translation table: alias.attcode => table.column)
|
||||
//
|
||||
foreach(self::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
if (self::$m_aAttribOrigins[$sTargetClass][$sAttCode] != $sTableClass) continue;
|
||||
|
||||
// Select...
|
||||
//
|
||||
@@ -2498,16 +2553,17 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
if (array_key_exists($sAttCode, $aExpectedAtts))
|
||||
{
|
||||
$aTranslation[$sTargetAlias][$sAttCode.$sColId] = new FieldExpressionResolved($sSQLExpr, $sTableAlias);
|
||||
$oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sTableAlias);
|
||||
foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier)
|
||||
{
|
||||
$oFieldSQLExp = $oQueryModifier->GetFieldExpression($oBuild, $sTargetClass, $sAttCode, $sColId, $oFieldSQLExp, $oSelectBase);
|
||||
}
|
||||
$aTranslation[$sTargetAlias][$sAttCode.$sColId] = $oFieldSQLExp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3 - The whole stuff, for this table only
|
||||
//
|
||||
$oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField);
|
||||
|
||||
//echo "MAKEQUERY- Classe $sTableClass<br/>\n";
|
||||
// 4 - The external keys -> joins...
|
||||
//
|
||||
@@ -2527,7 +2583,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
// The join was not explicitely defined in the filter,
|
||||
// we need to do it now
|
||||
$sKeyClass = $oKeyAttDef->GetTargetClass();
|
||||
$sKeyClassAlias = self::GenerateUniqueAlias($aClassAliases, $sKeyClass.'_'.$sKeyAttCode, $sKeyClass);
|
||||
$sKeyClassAlias = $oBuild->GenerateClassAlias($sKeyClass.'_'.$sKeyAttCode, $sKeyClass);
|
||||
$oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias);
|
||||
|
||||
$aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter;
|
||||
@@ -2584,18 +2640,18 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
}
|
||||
// Translate prior to recursing
|
||||
//
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n";
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n";
|
||||
$oBuild->m_oQBExpressions->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
|
||||
//echo "<p>External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()/p>\n";
|
||||
self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()");
|
||||
$oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
|
||||
$oBuild->m_oQBExpressions->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
|
||||
|
||||
//echo "<p>Recursive MakeQuery ".__LINE__.": <pre>\n".print_r($aSelectedClasses, true)."</pre></p>\n";
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
|
||||
//echo "<p>Recursive MakeQuery ".__LINE__.": <pre>\n".print_r($oBuild->GetRootFilter()->GetSelectedClasses(), true)."</pre></p>\n";
|
||||
$oSelectExtKey = self::MakeQuery($oBuild, $oExtFilter);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField();
|
||||
$sExternalKeyTable = $oJoinExpr->GetParent();
|
||||
$sExternalKeyField = $oJoinExpr->GetName();
|
||||
|
||||
@@ -2615,9 +2671,9 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
}
|
||||
elseif(self::$m_aAttribOrigins[$sKeyClass][$sKeyAttCode] == $sTableClass)
|
||||
{
|
||||
$oQBExpr->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias));
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$oBuild->m_oQBExpressions->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias));
|
||||
$oSelectExtKey = self::MakeQuery($oBuild, $oExtFilter);
|
||||
$oJoinExpr = $oBuild->m_oQBExpressions->PopJoinField();
|
||||
//echo "MAKEQUERY-PopJoinField pour $sKeyAttCode, $sKeyClassAlias: <pre>".print_r($oJoinExpr, true)."</pre><br/>\n";
|
||||
$sExternalKeyTable = $oJoinExpr->GetParent();
|
||||
$sExternalKeyField = $oJoinExpr->GetName();
|
||||
@@ -2636,9 +2692,9 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
|
||||
// Translate the selected columns
|
||||
//
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
$oQBExpr->Translate($aTranslation, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
$oBuild->m_oQBExpressions->Translate($aTranslation, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
|
||||
//MyHelpers::var_dump_html($oSelectBase->RenderSelect());
|
||||
return $oSelectBase;
|
||||
@@ -4145,17 +4201,15 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
// Note: load the dictionary as soon as possible, because it might be
|
||||
// needed when some error occur
|
||||
$sAppIdentity = self::GetConfig()->Get('session_name');
|
||||
$bDictInitializedFromData = false;
|
||||
if (!self::$m_bUseAPCCache || !Dict::InCache($sAppIdentity))
|
||||
{
|
||||
$bDictInitializedFromData = true;
|
||||
foreach (self::$m_oConfig->GetDictionaries() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule($sConfigFile, 'dictionaries', $sToInclude);
|
||||
}
|
||||
if (self::$m_bUseAPCCache)
|
||||
{
|
||||
Dict::InitCache($sAppIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the language... after the dictionaries have been loaded!
|
||||
Dict::SetDefaultLanguage(self::$m_oConfig->GetDefaultLanguage());
|
||||
|
||||
@@ -4259,6 +4313,11 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$m_bUseAPCCache && $bDictInitializedFromData)
|
||||
{
|
||||
Dict::InitCache($sAppIdentity);
|
||||
}
|
||||
|
||||
self::$m_sDBName = $sSource;
|
||||
self::$m_sTablePrefix = $sTablePrefix;
|
||||
|
||||
@@ -4318,17 +4377,31 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
$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
|
||||
@@ -4337,20 +4410,30 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
// 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);
|
||||
@@ -4396,10 +4479,10 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
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;
|
||||
@@ -4646,7 +4729,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of classes implementing the given interface
|
||||
* Returns an array of classes=>instance implementing the given interface
|
||||
*/
|
||||
public static function EnumPlugins($sInterface)
|
||||
{
|
||||
@@ -4731,5 +4814,4 @@ MetaModel::RegisterZList("preview", array("description"=>"All attributes visible
|
||||
MetaModel::RegisterZList("standard_search", array("description"=>"List of criteria for the standard search", "type"=>"filters"));
|
||||
MetaModel::RegisterZList("advanced_search", array("description"=>"List of criteria for the advanced search", "type"=>"filters"));
|
||||
|
||||
|
||||
?>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -168,7 +168,7 @@ class OQLLexerRaw
|
||||
'/\GABOVE STRICT/ ',
|
||||
'/\GNOT ABOVE/ ',
|
||||
'/\GNOT ABOVE STRICT/ ',
|
||||
'/\G[0-9]+|0x[0-9a-fA-F]+/ ',
|
||||
'/\G(0x[0-9a-fA-F]+|[0-9]+)/ ',
|
||||
'/\G\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/ ',
|
||||
'/\G([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ ',
|
||||
'/\G:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ ',
|
||||
|
||||
@@ -140,7 +140,23 @@ above = "ABOVE"
|
||||
above_strict = "ABOVE STRICT"
|
||||
not_above = "NOT ABOVE"
|
||||
not_above_strict = "NOT ABOVE STRICT"
|
||||
numval = /[0-9]+|0x[0-9a-fA-F]+/
|
||||
//
|
||||
// WARNING: there seems to be a bug in the Lexer about matching the longest pattern
|
||||
// when there are alternates in the regexp.
|
||||
//
|
||||
// For instance:
|
||||
// numval = /[0-9]+|0x[0-9a-fA-F]+/
|
||||
// Does not work: SELECT Toto WHERE name = 'Text0xCTest' => Fails because 0xC is recongnized as a numval (inside the string) instead of a strval !!
|
||||
//
|
||||
// Inserting a ^ after the alternate (see comment at the top of this file) does not work either
|
||||
// numval = /[0-9]+|'.chr(94).'0x[0-9a-fA-F]+/
|
||||
// SELECT Toto WHERE name = 'Text0xCTest' => works but
|
||||
// SELECT Toto WHERE id = 0xC => does not work, 'xC' is found as a name (apparently 0 is recognized as a numval and the remaining is a name !)
|
||||
//
|
||||
// numval = /([0-9]+|0x[0-9a-fA-F]+)/
|
||||
// Does not work either, the hexadecimal numbers are not matched properly
|
||||
// The following seems to work...
|
||||
numval = /(0x[0-9a-fA-F]+|[0-9]+)/
|
||||
strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/
|
||||
name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/
|
||||
varname = /:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/
|
||||
|
||||
74
core/querybuildercontext.class.inc.php
Normal file
74
core/querybuildercontext.class.inc.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?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
|
||||
|
||||
/**
|
||||
* Associated with the metamodel -> MakeQuery/MakeQuerySingleTable
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
class QueryBuilderContext
|
||||
{
|
||||
protected $m_oRootFilter;
|
||||
protected $m_aClassAliases;
|
||||
protected $m_aTableAliases;
|
||||
protected $m_aModifierProperties;
|
||||
|
||||
public $m_oQBExpressions;
|
||||
|
||||
public function __construct($oFilter, $aModifierProperties)
|
||||
{
|
||||
$this->m_oRootFilter = $oFilter;
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria());
|
||||
|
||||
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
|
||||
$this->m_aTableAliases = array();
|
||||
|
||||
$this->m_aModifierProperties = $aModifierProperties;
|
||||
}
|
||||
|
||||
public function GetRootFilter()
|
||||
{
|
||||
return $this->m_oRootFilter;
|
||||
}
|
||||
|
||||
public function GenerateTableAlias($sNewName, $sRealName)
|
||||
{
|
||||
return MetaModel::GenerateUniqueAlias($this->m_aTableAliases, $sNewName, $sRealName);
|
||||
}
|
||||
|
||||
public function GenerateClassAlias($sNewName, $sRealName)
|
||||
{
|
||||
return MetaModel::GenerateUniqueAlias($this->m_aClassAliases, $sNewName, $sRealName);
|
||||
}
|
||||
|
||||
public function GetModifierProperties($sPluginClass)
|
||||
{
|
||||
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
|
||||
{
|
||||
return $this->m_aModifierProperties[$sPluginClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
33
core/querymodifier.class.inc.php
Normal file
33
core/querymodifier.class.inc.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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
|
||||
|
||||
/**
|
||||
* Interface iQueryModifier
|
||||
* Defines the API to tweak queries (e.g. translate data on the fly)
|
||||
*
|
||||
* @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 iQueryModifier
|
||||
{
|
||||
public function __construct();
|
||||
|
||||
public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect);
|
||||
}
|
||||
?>
|
||||
@@ -68,6 +68,11 @@ class SQLQuery
|
||||
$this->m_oSelectedIdField = $oSelectedIdField;
|
||||
}
|
||||
|
||||
public function GetTableAlias()
|
||||
{
|
||||
return $this->m_sTableAlias;
|
||||
}
|
||||
|
||||
public function SetSourceOQL($sOQL)
|
||||
{
|
||||
$this->m_SourceOQL = $sOQL;
|
||||
@@ -101,11 +106,20 @@ class SQLQuery
|
||||
{
|
||||
$sJoinType = $aJoinInfo["jointype"];
|
||||
$oSQLQuery = $aJoinInfo["select"];
|
||||
$sLeftField = $aJoinInfo["leftfield"];
|
||||
$sRightField = $aJoinInfo["rightfield"];
|
||||
$sRightTableAlias = $aJoinInfo["righttablealias"];
|
||||
if (isset($aJoinInfo["on_expression"]))
|
||||
{
|
||||
$sOnCondition = $aJoinInfo["on_expression"]->Render();
|
||||
|
||||
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
|
||||
echo "<li>Join '$sJoinType', ON ($sOnCondition)".$oSQLQuery->DisplayHtml()."</li>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLeftField = $aJoinInfo["leftfield"];
|
||||
$sRightField = $aJoinInfo["rightfield"];
|
||||
$sRightTableAlias = $aJoinInfo["righttablealias"];
|
||||
|
||||
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
|
||||
}
|
||||
}
|
||||
echo "</ul>";
|
||||
}
|
||||
@@ -196,6 +210,24 @@ class SQLQuery
|
||||
{
|
||||
return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField);
|
||||
}
|
||||
|
||||
public function AddInnerJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
|
||||
{
|
||||
$this->m_aJoinSelects[] = array(
|
||||
"jointype" => 'inner',
|
||||
"select" => $oSQLQuery,
|
||||
"on_expression" => $oOnExpression
|
||||
);
|
||||
}
|
||||
|
||||
public function AddLeftJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
|
||||
{
|
||||
$this->m_aJoinSelects[] = array(
|
||||
"jointype" => 'left',
|
||||
"select" => $oSQLQuery,
|
||||
"on_expression" => $oOnExpression
|
||||
);
|
||||
}
|
||||
|
||||
// Interface, build the SQL query
|
||||
public function RenderDelete($aArgs = array())
|
||||
@@ -412,8 +444,14 @@ class SQLQuery
|
||||
break;
|
||||
case "inner":
|
||||
case "left":
|
||||
// table or tablealias ???
|
||||
$sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
|
||||
if (isset($aJoinData["on_expression"]))
|
||||
{
|
||||
$sJoinCond = $aJoinData["on_expression"]->Render();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
break;
|
||||
case "inner_tree":
|
||||
@@ -488,10 +526,6 @@ class SQLQuery
|
||||
foreach ($this->m_aJoinSelects as $aJoinData)
|
||||
{
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
// $sJoinType = $aJoinData["jointype"];
|
||||
// $sLeftField = $aJoinData["leftfield"];
|
||||
// $sRightField = $aJoinData["rightfield"];
|
||||
// $sRightTableAlias = $aJoinData["righttablealias"];
|
||||
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"category" => "core/cmdb,bizmodel",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -1041,6 +1041,7 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
*/
|
||||
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
$bOk = true;
|
||||
if ($sLoginMode != 'cas') return false; // Must be authenticated via CAS
|
||||
|
||||
$sCASMemberships = MetaModel::GetConfig()->Get('cas_memberof');
|
||||
@@ -1066,24 +1067,49 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
phpCAS::log("Info: user if a member of the group: ".$sGroupName);
|
||||
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
|
||||
$aFilteredGroupNames[] = $sGroupName;
|
||||
if (in_array($sGroupName, $aCASMemberships))
|
||||
$bIsMember = false;
|
||||
foreach($aCASMemberships as $sCASPattern)
|
||||
{
|
||||
if (self::IsPattern($sCASPattern))
|
||||
{
|
||||
if (preg_match($sCASPattern, $sGroupName))
|
||||
{
|
||||
$bIsMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ($sPattern == $sGroupName)
|
||||
{
|
||||
$bIsMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bIsMember)
|
||||
{
|
||||
$bCASUserSynchro = MetaModel::GetConfig()->Get('cas_user_synchro');
|
||||
if ($bCASUserSynchro)
|
||||
{
|
||||
// If needed create a new user for this email/profile
|
||||
phpCAS::log('Info: cas_user_synchro is ON');
|
||||
$bFound = self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
|
||||
$bOk = self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
|
||||
if($bOk)
|
||||
{
|
||||
$bFound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("User ".phpCAS::getUser()." cannot be created in iTop. Logging off...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log('Info: cas_user_synchro is OFF');
|
||||
$bFound = true;
|
||||
}
|
||||
$bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!$bFound)
|
||||
if($bOk && !$bFound)
|
||||
{
|
||||
phpCAS::log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
|
||||
}
|
||||
@@ -1125,7 +1151,8 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
*/
|
||||
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication)
|
||||
{
|
||||
if (($sLoginMode == 'cas') && (phpCAS::hasAttribute('memberOf')))
|
||||
$bCASUpdateProfiles = MetaModel::GetConfig()->Get('cas_update_profiles');
|
||||
if (($sLoginMode == 'cas') && $bCASUpdateProfiles && (phpCAS::hasAttribute('memberOf')))
|
||||
{
|
||||
$aMemberOf = phpCAS::getAttribute('memberOf');
|
||||
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
|
||||
@@ -1163,7 +1190,7 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
{
|
||||
case 0:
|
||||
phpCAS::log("Error: found no contact with the email: '$sEmail'. Cannot create the user in iTop.");
|
||||
return;
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
$oContact = $oSet->Fetch();
|
||||
@@ -1173,7 +1200,7 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
|
||||
default:
|
||||
phpCAS::log("Error: ".$oSet->Count()." contacts have the same email: '$sEmail'. Cannot create a user for this email.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$oUser = new UserExternal();
|
||||
@@ -1240,17 +1267,43 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
if (array_key_exists(strtolower($aMatches[1]), $aAllProfiles))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[strtolower($aMatches[1])];
|
||||
phpCAS::log("Info: Adding the profile '{$aMatches[1]}' from CAS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Warning: {$aMatches[1]} is not a valid iTop profile (extracted from group name: '$sGroupName'). Ignored.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Info: The CAS group '$sGroupName' does not seem to match an iTop pattern. Ignored.");
|
||||
}
|
||||
}
|
||||
if (count($aProfiles) == 0)
|
||||
{
|
||||
phpCAS::log("Error: no group name matches the pattern: '$sPattern'. The user '$sEmail' has no profiles in iTop, and therefore cannot be created.");
|
||||
return false;
|
||||
phpCAS::log("Info: The user '".$oUser->GetName()."' has no profiles retrieved from CAS. Default profile(s) will be used.");
|
||||
|
||||
// Second attempt: check if there is/are valid default profile(s)
|
||||
$sCASDefaultProfiles = MetaModel::GetConfig()->Get('cas_default_profiles');
|
||||
$aCASDefaultProfiles = explode(';', $sCASDefaultProfiles);
|
||||
foreach($aCASDefaultProfiles as $sDefaultProfileName)
|
||||
{
|
||||
if (array_key_exists(strtolower($sDefaultProfileName), $aAllProfiles))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[strtolower($sDefaultProfileName)];
|
||||
phpCAS::log("Info: Adding the default profile '".$aAllProfiles[strtolower($sDefaultProfileName)]."' from CAS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Warning: the default profile {$sDefaultProfileName} is not a valid iTop profile. Ignored.");
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aProfiles) == 0)
|
||||
{
|
||||
phpCAS::log("Error: The user '".$oUser->GetName()."' has no profiles in iTop, and therefore cannot be created.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
@@ -1263,7 +1316,23 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
$oProfilesSet->AddObject($oLink);
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
phpCAS::log("Info: the user $sEmail (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
|
||||
phpCAS::log("Info: the user '".$oUser->GetName()."' (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
|
||||
if ($oUser->IsModified())
|
||||
{
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
|
||||
$oMyChange->DBInsert();
|
||||
if ($oUser->IsNew())
|
||||
{
|
||||
$oUser->DBInsertTracked($oMyChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
@@ -187,6 +208,11 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
return 'Filter: '.$this->m_sFilterExpr;
|
||||
}
|
||||
|
||||
public function GetFilterExpression()
|
||||
{
|
||||
return $this->m_sFilterExpr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -278,6 +304,13 @@ class ValueSetEnum extends ValueSetDefinition
|
||||
$this->m_values = $Values;
|
||||
}
|
||||
|
||||
// Helper to export the datat model
|
||||
public function GetValueList()
|
||||
{
|
||||
$this->LoadValues($aArgs = array());
|
||||
return $this->m_aValues;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
if (is_array($this->m_values))
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
body {
|
||||
font-family: Tahoma, Verdana, Arial, Helvetica;
|
||||
font-size: 10pt;
|
||||
background-color: #fff;
|
||||
color:#000000;
|
||||
margin: 0; /* Remove body margin/padding */
|
||||
padding: 0;
|
||||
@@ -60,6 +59,7 @@ table.listContainer {
|
||||
padding: 0;
|
||||
margin:0;
|
||||
width: 97%;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
tr.containerHeader, tr.containerHeader td {
|
||||
|
||||
15
css/print.css
Normal file
15
css/print.css
Normal file
@@ -0,0 +1,15 @@
|
||||
@CHARSET "UTF-8";
|
||||
#left-pane { display: none; }
|
||||
span.ui-layout-resizer { display: none; }
|
||||
#header-logo { display: none; }
|
||||
#logo { display: none; }
|
||||
div.header-menu { display:none; }
|
||||
div.footer { display:none; }
|
||||
#top-bar { display: none; }
|
||||
#menu { display: none; }
|
||||
div.actions_button { display:none; }
|
||||
div.itop_popup { display:none; }
|
||||
div.HRDrawer { display:none; }
|
||||
div.DrawerHandle { display:none; }
|
||||
a.tab { display:none; }
|
||||
div.itop-tab { border: #ccc 1px solid; margin-top: 1em; padding-bottom:1em; }
|
||||
@@ -284,6 +284,9 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:SynchroReplica/Attribute:status_last_warning' => 'Letzte Warnung',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Erzeugungs-Datum',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Datum der letzten Modifikation',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name' => 'Datenbanktabelle',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name+' => 'Name der Tabelle, die Speicherung der Daten aus dieser Datenquelle. Ein Default-Name wird automatisch berechnet, wenn dieses Feld leer gelassen wird.',
|
||||
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'Tabelle %1$s existiert bereits in der Datenbank. Bitte benutzen Sie einen anderen Namen für die Datenbanktabelle aus dieser Datenquelle.',
|
||||
'Class:appUserPreferences' => 'Benutzer-Voreinstellungen',
|
||||
'Class:appUserPreferences/Attribute:userid' => 'Benutzer',
|
||||
'Class:appUserPreferences/Attribute:preferences' => 'Voreinstellungen',
|
||||
|
||||
@@ -788,5 +788,6 @@ Wenn Aktionen mit Trigger verknüpft sind, bekommt jede Aktion eine Auftragsnumm
|
||||
'UI:FavoriteOrganizations+' => '',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Alle Änderungen werden verworfen.',
|
||||
'UI:Create_Class_InState' => 'Lege %1$s an in Status: ',
|
||||
'UI:Button:Refresh' => 'Neu laden',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -144,7 +144,7 @@ Operators:<br/>
|
||||
'Core:AttributeFriendlyName' => 'Friendly name',
|
||||
'Core:AttributeFriendlyName+' => 'Attribute created automatically ; the friendly name is computed after several attributes',
|
||||
|
||||
'Core:FriendlyName-Label' => 'Name',
|
||||
'Core:FriendlyName-Label' => 'Friendly name',
|
||||
'Core:FriendlyName-Description' => 'Friendly name',
|
||||
));
|
||||
|
||||
@@ -570,6 +570,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update+' => 'Syntax: field_name:value; ...',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Retention Duration',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => 'How much time an obsolete object is kept before being deleted',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name' => 'Data table',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name+' => 'Name of the table to store the synchronization data. If left empty, a default name will be computed.',
|
||||
'SynchroDataSource:Description' => 'Description',
|
||||
'SynchroDataSource:Reconciliation' => 'Search & reconciliation',
|
||||
'SynchroDataSource:Deletion' => 'Deletion rules',
|
||||
@@ -618,6 +620,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'At Least one reconciliation key must be specified, or the reconciliation policy must be to use the primary key.',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'A delete retention period must be specified, since objects are to be deleted after being marked as obsolete',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Obsolete objects are to be updated, but no update is specified.',
|
||||
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'The table %1$s already exists in the database. Please use another name for the synchro data table.',
|
||||
'Core:SynchroReplica:PublicData' => 'Public Data',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Private Details',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Go Back to the Synchro Data Source: %1$s',
|
||||
|
||||
@@ -963,5 +963,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'Note that this is not a security setting, objects from any organization are still visible and can be accessed by selecting "All Organizations" in the drop-down list.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Any modification will be discarded.',
|
||||
'UI:Create_Class_InState' => 'Create the %1$s in state: ',
|
||||
'UI:Button:Refresh' => 'Refresh',
|
||||
'UI:iTopLogin' => 'iTop Login',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -280,6 +280,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:SynchroDataSource/Attribute:url_icon+' => 'Hyperlien vers une icône représentant l\'application source des données',
|
||||
'Class:SynchroDataSource/Attribute:url_application' => 'Application (hyperlien)',
|
||||
'Class:SynchroDataSource/Attribute:url_application+' => 'Un hyperlien vers l\'application source des données. Paramètres possibles: $this->nom_de_champ$ et $replica->primary_key$',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name' => 'Table de données',
|
||||
'Class:SynchroDataSource/Attribute:database_table_name+' => 'Nom de la table stockant les données de cette source. Un nom par défaut est calculé automatiquement si ce champ est laissé vide.',
|
||||
'Class:SynchroAttribute' => 'Champs de synchronisation',
|
||||
'Class:SynchroAttribute+' => '',
|
||||
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Source de données',
|
||||
@@ -587,6 +589,7 @@ Opérateurs :<br/>
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Si la politique de réconciliation n\'est pas la clé primaire, au moins une clé de recherche doit être spécifiée',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Pour que les objets soient effacés après avoir été obsoletés, il faut spécifier une durée de rétention',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Les objets obsolètes doivent être mis à jour, mais aucune information de mise à jour n\'est spécifiée',
|
||||
'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'La table %1$s existe déjà dans la base de données. Veuillez utiliser un autre nom pour la table des données de cette source.',
|
||||
'Core:SynchroReplica:PublicData' => 'Données synchronisées',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Informations internes',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Retourner aux détails de la source de données: %1$s',
|
||||
@@ -602,7 +605,7 @@ Opérateurs :<br/>
|
||||
'Core:SynchroAtt:update_policy+' => '',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Clé de recherche',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => '',
|
||||
'Core:SyncDataExchangeComment' => '(Synhcronisation)',
|
||||
'Core:SyncDataExchangeComment' => '(Synchronisation)',
|
||||
'Core:Synchro:ListOfDataSources' => 'Sources de données:',
|
||||
'Core:Synchro:LastSynchro' => 'Dernière synchronisation:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'Cet objet est synchronisé avec une source de données',
|
||||
|
||||
@@ -503,7 +503,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Schema:LifeCycleAttributeMustPrompt' => 'L\'utilisateur se verra proposer de changer la valeur',
|
||||
'UI:Schema:LifeCycleEmptyList' => 'liste vide',
|
||||
'UI:LinksWidget:Autocomplete+' => 'Tapez les 3 premiers caractères...',
|
||||
'UI:Edit:TestQuery' => 'Tester le requête',
|
||||
'UI:Edit:TestQuery' => 'Tester la requête',
|
||||
'UI:Combo:SelectValue' => '--- choisissez une valeur ---',
|
||||
'UI:Label:SelectedObjects' => 'Objets sélectionnés: ',
|
||||
'UI:Label:AvailableObjects' => 'Objets disponibles: ',
|
||||
@@ -806,5 +806,6 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'Ceci n\'est pas un réglage de sécurité. Les objets de toutes les organisations sont toujours visibles en choisissant "Toutes les Organisations" dans le menu.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Toute modification sera perdue.',
|
||||
'UI:Create_Class_InState' => 'Créer l\'objet %1$s dans l\'état: ',
|
||||
'UI:Button:Refresh' => 'Rafraîchir',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -772,5 +772,6 @@ Akció kiváltó okhoz rendelésekor kap egy sorszámot , amely meghatározza az
|
||||
'UI:ActionNotAllowed' => 'Ennek a műveletnek a végrehajtása nem engedélyezett ezen az objektumon.',
|
||||
'UI:BulkAction:NoObjectSelected' => 'Válasszon ki legalább egy objketumot a művelet végrehajtásához',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => '%1$s mező nem írható, mert a szinkronizációnál használt kulcs. Érték változatlan maradt.',
|
||||
'UI:Button:Refresh' => 'Frissítés',
|
||||
));
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,76 +15,265 @@
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
* Localized data
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'gui'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'application'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: AuditCategory
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:AuditCategory' => 'Categoria di Audit',
|
||||
'Class:AuditCategory+' => 'Una sezione all\'interno del controllo globale',
|
||||
'Class:AuditCategory/Attribute:name' => 'Nome della categoria',
|
||||
'Class:AuditCategory/Attribute:name+' => 'Abbreviazione per questa categoria',
|
||||
'Class:AuditCategory/Attribute:description' => 'Descrizione della categoria di Audit',
|
||||
'Class:AuditCategory/Attribute:description+' => 'Descrizione dettagliata della categoria di audit',
|
||||
'Class:AuditCategory/Attribute:definition_set' => 'Insieme di definizione',
|
||||
'Class:AuditCategory/Attribute:definition_set+' => 'Espressione OQLche definisce l\'insieme di oggetti da controllare',
|
||||
'Class:AuditCategory/Attribute:rules_list' => 'Regole di Audit',
|
||||
'Class:AuditCategory/Attribute:rules_list+' => 'Regolele di audit per queste categorie',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: AuditRule
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:AuditRule' => 'Regola di Audit',
|
||||
'Class:AuditRule+' => '',
|
||||
'Class:AuditRule/Attribute:name' => 'Nome della regola',
|
||||
'Class:AuditRule/Attribute:name+' => '',
|
||||
'Class:AuditRule/Attribute:description' => 'Descrizione della regola di Audit',
|
||||
'Class:AuditRule/Attribute:description+' => '',
|
||||
'Class:AuditRule/Attribute:description+' => 'Descrizione dettagliata per questa regola di audit ',
|
||||
'Class:AuditRule/Attribute:query' => 'Query da eseguire',
|
||||
'Class:AuditRule/Attribute:query+' => '',
|
||||
'Class:AuditRule/Attribute:query+' => 'Espressio OQL da eseguire',
|
||||
'Class:AuditRule/Attribute:valid_flag' => 'Oggetti validi?',
|
||||
'Class:AuditRule/Attribute:valid_flag+' => '',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false' => 'falso',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false+' => '',
|
||||
'Class:AuditRule/Attribute:valid_flag+' => 'Vero se la regola ritorna oggetti validi, falso altrimenti ',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true' => 'vero',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true+' => '',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true+' => 'vero',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false' => 'falso',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false+' => 'falso',
|
||||
'Class:AuditRule/Attribute:category_id' => 'Categoria',
|
||||
'Class:AuditRule/Attribute:category_id+' => '',
|
||||
'Class:AuditCategory' => 'Categoria di Audit',
|
||||
'Class:AuditCategory+' => '',
|
||||
'Class:AuditCategory/Attribute:name' => 'Nome della Categoria',
|
||||
'Class:AuditCategory/Attribute:name+' => '',
|
||||
'Class:AuditCategory/Attribute:description' => 'Descrizione della Categoria di Audit',
|
||||
'Class:AuditCategory/Attribute:description+' => '',
|
||||
'Class:AuditCategory/Attribute:definition_set' => 'Insieme di definizione',
|
||||
'Class:AuditCategory/Attribute:definition_set+' => '',
|
||||
'Class:AuditCategory/Attribute:rules_list' => 'Regole di Audit',
|
||||
'Class:AuditCategory/Attribute:rules_list+' => '',
|
||||
'Class:AuditRule/Attribute:category_id+' => 'Categoria per questa regola',
|
||||
'Class:AuditRule/Attribute:category_name' => 'Categoria',
|
||||
'Class:AuditRule/Attribute:category_name+' => 'Nome della categoria per questa regola',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: QueryOQL
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:Query' => 'Query',
|
||||
'Class:Query+' => 'Una query è un insieme di dati definito in modo dinamico',
|
||||
'Class:Query/Attribute:name' => 'Nome',
|
||||
'Class:Query/Attribute:name+' => 'Identificativi della query',
|
||||
'Class:Query/Attribute:description' => 'Descrizione',
|
||||
'Class:Query/Attribute:description+' => 'Descrizione dettagliata della query(scopo, usagoetc.)',
|
||||
'Class:Query/Attribute:fields' => 'Campi',
|
||||
'Class:Query/Attribute:fields+' => 'Lista di attributi separati da virgola (o alias.attributo) per l\'esportazione',
|
||||
|
||||
'Class:QueryOQL' => 'OQL Query',
|
||||
'Class:QueryOQL+' => 'Una query basata su Object Query Language',
|
||||
'Class:QueryOQL/Attribute:oql' => 'Espressione',
|
||||
'Class:QueryOQL/Attribute:oql+' => 'Espressione OQL',
|
||||
));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'addon/userrights'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: User
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:User' => 'Utente',
|
||||
'Class:User+' => 'Login Utente',
|
||||
'Class:User/Attribute:finalclass' => 'Tipo di account',
|
||||
'Class:User/Attribute:finalclass+' => '',
|
||||
'Class:User/Attribute:contactid' => 'Contatto (persona)',
|
||||
'Class:User/Attribute:contactid+' => 'Dettagli personali per dati aziendali',
|
||||
'Class:User/Attribute:last_name' => 'Cognome',
|
||||
'Class:User/Attribute:last_name+' => 'Cognome del contatto corrispondente',
|
||||
'Class:User/Attribute:first_name' => 'Nome',
|
||||
'Class:User/Attribute:first_name+' => 'Nome del contatto corrispondente',
|
||||
'Class:User/Attribute:email' => 'Email',
|
||||
'Class:User/Attribute:email+' => 'Email del contatto corrispondente',
|
||||
'Class:User/Attribute:login' => 'Login',
|
||||
'Class:User/Attribute:login+' => 'Stringa di identificazione dell\'utente',
|
||||
'Class:User/Attribute:language' => 'Lingua',
|
||||
'Class:User/Attribute:language+' => 'Lingua utente',
|
||||
'Class:User/Attribute:language/Value:EN US' => 'English',
|
||||
'Class:User/Attribute:language/Value:EN US+' => 'English (U.S.)',
|
||||
'Class:User/Attribute:language/Value:IT IT' => 'Italiano',
|
||||
'Class:User/Attribute:language/Value:IT IT+' => 'Italiano (IT)',
|
||||
'Class:User/Attribute:language/Value:FR FR' => 'French',
|
||||
'Class:User/Attribute:language/Value:FR FR+' => 'French (France)',
|
||||
'Class:User/Attribute:profile_list' => 'Profili',
|
||||
'Class:User/Attribute:profile_list+' => 'Regole per la concessione dei diritti per quella persona',
|
||||
'Class:User/Attribute:allowed_org_list' => 'Organizzazione Consentite',
|
||||
'Class:User/Attribute:allowed_org_list+' => 'L\'utente finale è autorizzato a vedere i dati appartenenti alle seguenti organizzazioni. Se non è specificato organizzazione, vi è alcuna restrizione.',
|
||||
|
||||
'Class:User/Error:LoginMustBeUnique' => 'Il Login deve essere unico - "%1s" già usato',
|
||||
'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Almeno un profilo deve essere assegnato all\'utente.',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_Profiles
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_Profiles' => 'Profilo',
|
||||
'Class:URP_Profiles+' => '',
|
||||
'Class:URP_Profiles/Attribute:name' => 'Nome',
|
||||
'Class:URP_Profiles/Attribute:name+' => '',
|
||||
'Class:URP_Profiles/Attribute:description' => 'Descrizione',
|
||||
'Class:URP_Profiles/Attribute:description+' => '',
|
||||
'Class:URP_Profiles/Attribute:description+' => 'una linea di descrizione',
|
||||
'Class:URP_Profiles/Attribute:user_list' => 'Utenti',
|
||||
'Class:URP_Profiles/Attribute:user_list+' => '',
|
||||
'Class:URP_Profiles/Attribute:user_list+' => 'Persone che hanno questo ruuolo',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_Dimensions
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_Dimensions' => 'dimensione',
|
||||
'Class:URP_Dimensions+' => 'dimensione dell\'applicazione (definizione di silos))',
|
||||
'Class:URP_Dimensions/Attribute:name' => 'Nome',
|
||||
'Class:URP_Dimensions/Attribute:name+' => 'etichetta',
|
||||
'Class:URP_Dimensions/Attribute:description' => 'Descrizione',
|
||||
'Class:URP_Dimensions/Attribute:description+' => 'una linea di descrizione',
|
||||
'Class:URP_Dimensions/Attribute:type' => 'Tipo',
|
||||
'Class:URP_Dimensions/Attribute:type+' => 'nome della classe o tipo di dato (proiezione dell\'unità)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_UserProfile
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_UserProfile' => 'Utente da Profilare',
|
||||
'Class:URP_UserProfile+' => '',
|
||||
'Class:URP_UserProfile/Attribute:userid' => 'Utente',
|
||||
'Class:URP_UserProfile/Attribute:userid+' => '',
|
||||
'Class:URP_UserProfile/Attribute:userlogin' => 'Login',
|
||||
'Class:URP_UserProfile/Attribute:userlogin+' => 'User\'s login',
|
||||
'Class:URP_UserProfile/Attribute:profileid' => 'Profilo',
|
||||
'Class:URP_UserProfile/Attribute:profileid+' => '',
|
||||
'Class:URP_UserProfile/Attribute:profileid+' => 'utilizzo del profilo',
|
||||
'Class:URP_UserProfile/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_UserProfile/Attribute:profile+' => 'Nome del profilo',
|
||||
'Class:URP_UserProfile/Attribute:reason' => 'Motivo',
|
||||
'Class:URP_UserProfile/Attribute:reason+' => '',
|
||||
'Class:URP_UserProfile/Attribute:reason+' => 'spiega perchè questo utente dovrebbe avere questo ruolo',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_UserOrg
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_UserOrg' => 'Organizzazione dell\'utente',
|
||||
'Class:URP_UserOrg+' => '',
|
||||
'Class:URP_UserOrg/Attribute:userid' => 'Utente',
|
||||
'Class:URP_UserOrg/Attribute:userid+' => '',
|
||||
'Class:URP_UserOrg/Attribute:userid+' => 'Account Utente',
|
||||
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
|
||||
'Class:URP_UserOrg/Attribute:userlogin+' => 'Login Utente',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id' => 'Organizazione',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id+' => '',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id+' => 'Organizzazione permesse',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name' => 'Organizzazione',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name+' => 'Organizzazione permesse',
|
||||
'Class:URP_UserOrg/Attribute:reason' => 'Motivo',
|
||||
'Class:URP_UserOrg/Attribute:reason+' => '',
|
||||
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ProfileProjection
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_ProfileProjection' => 'profile_projection',
|
||||
'Class:URP_ProfileProjection+' => 'proiezioni di profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid' => 'Dimensione',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid+' => 'dimensione applicazione',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension' => 'Dimensione',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension+' => 'dimensione applicazione',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid' => 'Profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid+' => 'utilizzo di profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:profile+' => 'Nome del profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:value' => 'Valore dell\'espressione',
|
||||
'Class:URP_ProfileProjection/Attribute:value+' => 'Espressione OQL (uso $user) | constante| | +codice attributo',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute' => 'Attributo',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute+' => 'Codice attributo bersaglio (opzionale)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ClassProjection
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_ClassProjection' => 'class_projection',
|
||||
'Class:URP_ClassProjection+' => 'proiezioni di classe',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid' => 'Dimensione',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid+' => 'dimensione dell\'applicazione',
|
||||
'Class:URP_ClassProjection/Attribute:dimension' => 'Dimensione',
|
||||
'Class:URP_ClassProjection/Attribute:dimension+' => 'dimensione applicazione',
|
||||
'Class:URP_ClassProjection/Attribute:class' => 'Classe',
|
||||
'Class:URP_ClassProjection/Attribute:class+' => 'Classe bersaglio',
|
||||
'Class:URP_ClassProjection/Attribute:value' => 'Valore dell\'espressione',
|
||||
'Class:URP_ClassProjection/Attribute:value+' => 'Espressione OQL (uso $this) | constante| | +codice attributo',
|
||||
'Class:URP_ClassProjection/Attribute:attribute' => 'Attributo',
|
||||
'Class:URP_ClassProjection/Attribute:attribute+' => 'Codice attributo bersaglio (opzionale)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ActionGrant
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_ActionGrant' => 'azione_autorizzazione',
|
||||
'Class:URP_ActionGrant+' => '',
|
||||
'Class:URP_ActionGrant+' => 'permesso su classi',
|
||||
'Class:URP_ActionGrant/Attribute:profileid' => 'Profilo',
|
||||
'Class:URP_ActionGrant/Attribute:profileid+' => '',
|
||||
'Class:URP_ActionGrant/Attribute:profileid+' => 'Utilizzo del profilo',
|
||||
'Class:URP_ActionGrant/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_ActionGrant/Attribute:profile+' => 'Utilizzo del profilo',
|
||||
'Class:URP_ActionGrant/Attribute:class' => 'Classe',
|
||||
'Class:URP_ActionGrant/Attribute:class+' => '',
|
||||
'Class:URP_ActionGrant/Attribute:class+' => 'Classe bersaglio',
|
||||
'Class:URP_ActionGrant/Attribute:permission' => 'Autorizzazione',
|
||||
'Class:URP_ActionGrant/Attribute:permission+' => '',
|
||||
'Class:URP_ActionGrant/Attribute:permission+' => 'permesso non permesso',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'si',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => 'si',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'no',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => '',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'yes',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => '',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => 'no',
|
||||
'Class:URP_ActionGrant/Attribute:action' => 'Azione',
|
||||
'Class:URP_ActionGrant/Attribute:action+' => 'operazioni da effettuare sulla data classe',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_StimulusGrant
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_ActionGrant/Attribute:action' => 'Azione',
|
||||
'Class:URP_ActionGrant/Attribute:action+' => '',
|
||||
'Class:URP_StimulusGrant' => 'stimulus_autorizzazione',
|
||||
@@ -95,92 +284,32 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_StimulusGrant/Attribute:class+' => '',
|
||||
'Class:URP_StimulusGrant/Attribute:permission' => 'Autorizzazione',
|
||||
'Class:URP_StimulusGrant/Attribute:permission+' => '',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'si',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => 'si',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'no',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => '',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'yes',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => '',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => 'no',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus' => 'Stimulus',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus+' => '',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus+' => 'Codice per lo Stimolus',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_AttributeGrant
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:URP_AttributeGrant' => 'attributo_autorizzazione',
|
||||
'Class:URP_AttributeGrant+' => '',
|
||||
'Class:URP_AttributeGrant+' => 'autorizzazioni a livello di attributi',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid' => 'Azione di sovvenzione',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => '',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => 'azione di sovvenzione',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode' => 'Attributo',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode+' => '',
|
||||
'Class:AuditRule/Attribute:category_name' => 'Categoria',
|
||||
'Class:AuditRule/Attribute:category_name+' => '',
|
||||
'Class:User' => 'User~~',
|
||||
'Class:User+' => '',
|
||||
'Class:User/Attribute:finalclass' => 'Tipo di account',
|
||||
'Class:User/Attribute:finalclass+' => '',
|
||||
'Class:User/Attribute:contactid' => 'Contatto (persona)',
|
||||
'Class:User/Attribute:contactid+' => '',
|
||||
'Class:User/Attribute:last_name' => 'Cognome',
|
||||
'Class:User/Attribute:last_name+' => '',
|
||||
'Class:User/Attribute:first_name' => 'Nome',
|
||||
'Class:User/Attribute:first_name+' => '',
|
||||
'Class:User/Attribute:email' => 'Email',
|
||||
'Class:User/Attribute:email+' => '',
|
||||
'Class:User/Attribute:login' => 'Login',
|
||||
'Class:User/Attribute:login+' => '',
|
||||
'Class:User/Attribute:language' => 'Lingua',
|
||||
'Class:User/Attribute:language+' => '',
|
||||
'Class:User/Attribute:language/Value:EN US' => 'Inglese',
|
||||
'Class:User/Attribute:language/Value:EN US+' => '',
|
||||
'Class:User/Attribute:language/Value:FR FR' => 'Francese',
|
||||
'Class:User/Attribute:language/Value:FR FR+' => '',
|
||||
'Class:User/Attribute:profile_list' => 'Profili',
|
||||
'Class:User/Attribute:profile_list+' => '',
|
||||
'Class:User/Attribute:allowed_org_list' => 'Organizzazioni autorizzate',
|
||||
'Class:User/Attribute:allowed_org_list+' => '',
|
||||
'Class:User/Error:LoginMustBeUnique' => 'Login deve essere unico - "%1s" è già utilizzato.~~',
|
||||
'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Almeno un profilo deve essere assegnato a questo utente',
|
||||
'Class:URP_Dimensions' => 'dimensione',
|
||||
'Class:URP_Dimensions+' => '',
|
||||
'Class:URP_Dimensions/Attribute:name' => 'Nome',
|
||||
'Class:URP_Dimensions/Attribute:name+' => '',
|
||||
'Class:URP_Dimensions/Attribute:description' => 'Descrizione',
|
||||
'Class:URP_Dimensions/Attribute:description+' => '',
|
||||
'Class:URP_Dimensions/Attribute:type' => 'Tipo',
|
||||
'Class:URP_Dimensions/Attribute:type+' => '',
|
||||
'Class:URP_UserProfile/Attribute:userlogin' => 'Login',
|
||||
'Class:URP_UserProfile/Attribute:userlogin+' => '',
|
||||
'Class:URP_UserProfile/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_UserProfile/Attribute:profile+' => '',
|
||||
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
|
||||
'Class:URP_UserOrg/Attribute:userlogin+' => '',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name' => 'Organizazione',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name+' => '',
|
||||
'Class:URP_ProfileProjection' => 'profilo_proiezione',
|
||||
'Class:URP_ProfileProjection+' => '',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid' => 'Dimensione',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid+' => '',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension' => 'Dimensione',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension+' => '',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid' => 'Profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid+' => '',
|
||||
'Class:URP_ProfileProjection/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_ProfileProjection/Attribute:profile+' => '',
|
||||
'Class:URP_ProfileProjection/Attribute:value' => 'Valore dell\'espressione',
|
||||
'Class:URP_ProfileProjection/Attribute:value+' => '',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute' => 'Attributo',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute+' => '',
|
||||
'Class:URP_ClassProjection' => 'classe_proiezione',
|
||||
'Class:URP_ClassProjection+' => '',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid' => 'Dimensione',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid+' => '',
|
||||
'Class:URP_ClassProjection/Attribute:dimension' => 'Dimensione',
|
||||
'Class:URP_ClassProjection/Attribute:dimension+' => '',
|
||||
'Class:URP_ClassProjection/Attribute:class' => 'Classe',
|
||||
'Class:URP_ClassProjection/Attribute:class+' => '',
|
||||
'Class:URP_ClassProjection/Attribute:value' => 'Valore dell\'espressione',
|
||||
'Class:URP_ClassProjection/Attribute:value+' => '',
|
||||
'Class:URP_ClassProjection/Attribute:attribute' => 'Attributo',
|
||||
'Class:URP_ClassProjection/Attribute:attribute+' => '',
|
||||
'Class:URP_ActionGrant/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_ActionGrant/Attribute:profile+' => '',
|
||||
'Class:URP_StimulusGrant/Attribute:profile' => 'Profilo',
|
||||
'Class:URP_StimulusGrant/Attribute:profile+' => '',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode+' => 'codice attributo',
|
||||
));
|
||||
|
||||
//
|
||||
// String from the User Interface: menu, messages, buttons, etc...
|
||||
//
|
||||
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Menu:WelcomeMenu' => 'Benveuto',
|
||||
'Menu:WelcomeMenu+' => '',
|
||||
'Menu:WelcomeMenuPage' => 'Benvenuto',
|
||||
@@ -280,6 +409,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'UI:Error:ObjectAlreadyCreated' => 'Errore: l\'oggetto è già stato creato!',
|
||||
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'Errore: stimolo non valido "%1$s" su un oggetto %2$s nello stato "%3$s".',
|
||||
|
||||
|
||||
'UI:GroupBy:Count' => 'Conteggio',
|
||||
'UI:GroupBy:Count+' => '',
|
||||
'UI:CountOfObjects' => '%1$d oggetti corrispondenti ai criteri.',
|
||||
@@ -313,6 +443,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'UI:Menu:CSVExport' => 'CSV Export',
|
||||
'UI:Menu:Modify' => 'Modifica...',
|
||||
'UI:Menu:Delete' => 'Cancella...',
|
||||
'UI:Menu:Manage' => 'Gestisci...',
|
||||
'UI:Menu:BulkDelete' => 'Cancella...',
|
||||
'UI:UndefinedObject' => 'non definito',
|
||||
'UI:Document:OpenInNewWindow:Download' => 'Apri in una nuova finestra: %1$s, Scarica: %2$s',
|
||||
@@ -777,5 +908,6 @@ Quando è associata a un trigger, ad ogni azione è assegnato un numero "ordine"
|
||||
'UI:ActionNotAllowed' => 'Non hai i permessi per eseguire questa azione su questi oggetti.',
|
||||
'UI:BulkAction:NoObjectSelected' => 'Si prega di selezionare almeno un oggetto per eseguire questa operazione',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => 'Il campo %1$s on è scrivibile, perché è comandato dalla sincronizzazione dei dati. Valore rimane invariato.',
|
||||
'UI:Button:Refresh' => 'Ricarica',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -907,6 +907,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Portal:RemoveAttachment' => ' 添付を除去する ', // ' Remove Attachment ',
|
||||
'Portal:Attachment_No_To_Ticket_Name' => '#%1$d を$2$s ($3$s)に添付する', // 'Attachment #%1$d to %2$s (%3$s)',
|
||||
'Enum:Undefined' => '定義されていません', // 'Undefined',
|
||||
'UI:Button:Refresh' => '更新', // 'Refresh',
|
||||
));
|
||||
|
||||
|
||||
|
||||
@@ -960,5 +960,6 @@ Quando associada a um gatilho, cada ação é dada um número "ordem", especific
|
||||
'Note-se que esta não é uma configuração de segurança, objetos de qualquer organização ainda são visíveis e podem ser acessadas selecionando a opção "Todas as Organizações" na lista drop-down.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Qualquer modificação será descartada.',
|
||||
'UI:Create_Class_InState' => 'Criar o %1$s em estado: ',
|
||||
'UI:Button:Refresh' => 'Atualizar',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -872,6 +872,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Portal:ErrorNoContactForThisUser' => 'Ошибка: текющий пользователь не ассоциирован с Контактом/Человеком. Пожалуйста свяжитесь с вашим администратором.',
|
||||
|
||||
'Enum:Undefined' => 'Неопределён',
|
||||
'UI:Button:Refresh' => 'Обновить',
|
||||
));
|
||||
|
||||
|
||||
|
||||
@@ -871,8 +871,6 @@ Tetikleme gerçekleştiriğinde işlemler tanımlanan sıra numarası ile gerçe
|
||||
'Portal:ErrorNoContactForThisUser' => 'Hata: mevcut kullanıcının irtibat bilgisi yok. Sistem yöneticisi ile irtibata geçiniz.',
|
||||
|
||||
'Enum:Undefined' => 'Tanımsız',
|
||||
'UI:Button:Refresh' => 'Yenile',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -869,6 +869,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Portal:ErrorNoContactForThisUser' => '错误: 当前用户没有和一个联系人或人员关联. 请联系您的系统管理员.',
|
||||
|
||||
'Enum:Undefined' => '未定义',
|
||||
'UI:Button:Refresh' => '刷新',
|
||||
));
|
||||
|
||||
|
||||
|
||||
BIN
images/favicon.ico
Executable file
BIN
images/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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'
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,12 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
}
|
||||
}
|
||||
|
||||
this.UpdateWizardToJSON = function ()
|
||||
{
|
||||
this.UpdateWizard();
|
||||
return this.ToJSON()
|
||||
}
|
||||
|
||||
this.AjaxQueryServer = function ()
|
||||
{
|
||||
//console.log('data sent:', this.ToJSON());
|
||||
|
||||
@@ -120,7 +120,7 @@ class UserLDAP extends UserInternal
|
||||
$aEntry = ldap_get_entries($hDS, $hSearchResult);
|
||||
$sUserDN = $aEntry[0]['dn'];
|
||||
$bUserBind = @ldap_bind($hDS, $sUserDN, $sPassword);
|
||||
if ($bUserBind !== false)
|
||||
if (($bUserBind !== false) && !empty($sPassword))
|
||||
{
|
||||
ldap_unbind($hDS);
|
||||
return true; // Password Ok
|
||||
|
||||
@@ -468,7 +468,7 @@ EOF
|
||||
$oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading"> <img src="../images/indicator.gif"></span> '.$sMaxUpload);
|
||||
//$oPage->p('<input type="button" onClick="ajaxFileUpload();" value=" Upload !">');
|
||||
$oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>');
|
||||
$oPage->p('<input type="hidden" id="attachment_plugin"/>');
|
||||
$oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
|
||||
$oPage->add('</fieldset>');
|
||||
if ($this->m_bDeleteEnabled)
|
||||
{
|
||||
@@ -499,6 +499,12 @@ EOF
|
||||
|
||||
protected static function UpdateAttachments($oObject, $oChange = null)
|
||||
{
|
||||
if (utils::ReadParam('attachment_plugin', 'not-in-form') == 'not-in-form')
|
||||
{
|
||||
// Workaround to an issue in iTop < 2.0
|
||||
// Leave silently if there is no trace of the attachment form
|
||||
return;
|
||||
}
|
||||
$iTransactionId = utils::ReadParam('transaction_id', null);
|
||||
if (!is_null($iTransactionId))
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
m_aNodes = new Array();
|
||||
m_sExclude = '';
|
||||
m_fZoom = 1;
|
||||
m_oLoader = null;
|
||||
initParameters();
|
||||
var success = true;
|
||||
if (ExternalInterface.available)
|
||||
@@ -168,6 +169,10 @@
|
||||
var myString:String = m_sDataUrl+sSeparator+'relation='+m_sRelation+'&class='+m_sObjClass+'&id='+m_sObjId+'&exclude='+m_sExclude;
|
||||
trace("Requesting:"+myString);
|
||||
var myXMLURL:URLRequest = new URLRequest(myString);
|
||||
if (m_oLoader != null)
|
||||
{
|
||||
m_oLoader.close();
|
||||
}
|
||||
m_oLoader = new URLLoader();
|
||||
m_oLoader.addEventListener(Event.COMPLETE, onXMLLoadComplete);
|
||||
m_oLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onXMLLoadError);
|
||||
|
||||
Binary file not shown.
25
pages/UI.php
25
pages/UI.php
@@ -674,7 +674,7 @@ try
|
||||
else
|
||||
{
|
||||
$oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
|
||||
$oP->p("<h1>".Dict::Format('UI:FullTextSearchTitle_Text', $sFullText)."</h1>");
|
||||
$oP->p("<h1>".Dict::Format('UI:FullTextSearchTitle_Text', htmlentities($sFullText, ENT_QUOTES, 'UTF-8'))."</h1>");
|
||||
$iCount = 0;
|
||||
$iBlock = 0;
|
||||
// Search in full text mode in all the classes
|
||||
@@ -1737,13 +1737,13 @@ EOF
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aErrors[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel());
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj->Set($sAttCode, $paramValue);
|
||||
unset($aExpectedAttributes[$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $sTargetState);
|
||||
|
||||
if (count($aErrors) == 0)
|
||||
{
|
||||
if ($oObj->ApplyStimulus($sStimulus))
|
||||
@@ -1980,13 +1980,13 @@ EOF
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aErrors[] = Dict::Format('UI:AttemptingToChangeASlaveAttribute_Name', $oAttDef->GetLabel());
|
||||
unset($aExpectedAttributes[$sAttCode]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj->Set($sAttCode, $paramValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $sTargetState);
|
||||
|
||||
if (count($aErrors) == 0)
|
||||
{
|
||||
if ($oObj->ApplyStimulus($sStimulus))
|
||||
@@ -2056,10 +2056,11 @@ EOF
|
||||
$idx = 0;
|
||||
foreach($aSortedElements as $sSubClass => $sClassName)
|
||||
{
|
||||
$oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"DoReload()\"><label for=\"exclude_$idx\"> ".MetaModel::GetClassIcon($sSubClass)." $sClassName</label></span> ");
|
||||
$oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\"> ".MetaModel::GetClassIcon($sSubClass)." $sClassName</label></span> ");
|
||||
$idx++;
|
||||
}
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"DoReload()\">".Dict::S('UI:Button:Refresh')."</button></p>");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<div class=\"HRDrawer\"></div>\n");
|
||||
$oP->add("<div id=\"dh_flash\" class=\"DrawerHandle\">".Dict::S('UI:ElementsDisplayed')."</div>\n");
|
||||
|
||||
@@ -2123,6 +2124,8 @@ EOF
|
||||
<<<EOF
|
||||
var ajax_request = null;
|
||||
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
|
||||
function UpdateImpactedObjects(sClass, iId, sRelation)
|
||||
{
|
||||
var class_name = sClass; //$('select[name=class_name]').val();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -519,7 +527,7 @@ try
|
||||
$oPage->add_header("Pragma: public");
|
||||
|
||||
$oPage->SetContentType('application/json');
|
||||
$aParams = utils::ReadParam('params', array());
|
||||
$aParams = utils::ReadParam('params', array(), false, 'raw_data');
|
||||
if ($sFilter != '')
|
||||
{
|
||||
$oFilter = CMDBSearchFilter::unserialize($sFilter);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -304,6 +304,9 @@ try
|
||||
$sUserString .= ' (CSV)';
|
||||
$oMyChange->Set("userinfo", $sUserString);
|
||||
$iChangeId = $oMyChange->DBInsert();
|
||||
|
||||
// Todo - simplify that when reworking the change tracking
|
||||
CMDBObject::SetCurrentChange($oMyChange);
|
||||
}
|
||||
|
||||
$oBulk = new BulkChange(
|
||||
@@ -1402,14 +1405,18 @@ $('#select_template_class').change( function() {
|
||||
EOF
|
||||
);
|
||||
|
||||
if (MetaModel::GetConfig()->Get('csv_import_history_display'))
|
||||
{
|
||||
$oPage->SetCurrentTabContainer('tabs1');
|
||||
$oPage->SetCurrentTab(Dict::S('UI:History:BulkImports'));
|
||||
BulkChange::DisplayImportHistory($oPage);
|
||||
}
|
||||
}
|
||||
|
||||
switch($iStep)
|
||||
{
|
||||
case 10:
|
||||
// Case generated by BulkChange::DisplayImportHistory
|
||||
$iChange = (int)utils::ReadParam('changeid', 0);
|
||||
BulkChange::DisplayImportHistoryDetails($oPage, $iChange);
|
||||
break;
|
||||
|
||||
@@ -160,7 +160,7 @@ try
|
||||
|
||||
$oP->add("<form method=\"get\">\n");
|
||||
$oP->add(Dict::S('UI:RunQuery:ExpressionToEvaluate')."<br/>\n");
|
||||
$oP->add("<textarea cols=\"120\" rows=\"8\" name=\"expression\">$sExpression</textarea>\n");
|
||||
$oP->add("<textarea cols=\"120\" rows=\"8\" name=\"expression\">".htmlentities($sExpression, ENT_QUOTES, 'UTF-8')."</textarea>\n");
|
||||
|
||||
if (count($aArgs) > 0)
|
||||
{
|
||||
@@ -186,7 +186,7 @@ try
|
||||
|
||||
$oP->p('');
|
||||
$oP->StartCollapsibleSection(Dict::S('UI:RunQuery:MoreInfo'), false);
|
||||
$oP->p(Dict::S('UI:RunQuery:DevelopedQuery').$oFilter->ToOQL());
|
||||
$oP->p(Dict::S('UI:RunQuery:DevelopedQuery').htmlentities($oFilter->ToOQL(), ENT_QUOTES, 'UTF-8'));
|
||||
$oP->p(Dict::S('UI:RunQuery:SerializedFilter').$oFilter->serialize());
|
||||
$oP->EndCollapsibleSection();
|
||||
}
|
||||
|
||||
@@ -385,6 +385,10 @@ function DisplayClassDetails($oPage, $sClass, $sContext)
|
||||
{
|
||||
$sValue = Dict::Format('UI:Schema:ExternalKey_To',MakeClassHLink($oAttDef->GetTargetClass(), $sContext));
|
||||
}
|
||||
elseif ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sValue = MakeClassHLink($oAttDef->GetLinkedClass(), $sContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oAttDef->GetDescription();
|
||||
|
||||
@@ -245,8 +245,9 @@ function RequestCreationForm($oP, $oUserOrg)
|
||||
}
|
||||
$aArgs = array('this' => $oRequest);
|
||||
|
||||
$aFieldsMap[$sAttCode] = 'attr_'.$sAttCode;
|
||||
$sValue = $oRequest->GetFormElementForField($oP, get_class($oRequest), $sAttCode, $oAttDef, $value, '', 'attr_'.$sAttCode, '', $iFlags, $aArgs);
|
||||
$sInputId = 'attr_'.$sAttCode;
|
||||
$aFieldsMap[$sAttCode] = $sInputId;
|
||||
$sValue = "<span id=\"field_{$sInputId}\">".$oRequest->GetFormElementForField($oP, get_class($oRequest), $sAttCode, $oAttDef, $value, '', 'attr_'.$sAttCode, '', $iFlags, $aArgs).'</span>';
|
||||
$aDetails[] = array('label' => '<span>'.$oAttDef->GetLabel().'</span>', 'value' => $sValue);
|
||||
}
|
||||
if (!class_exists('AttachmentPlugIn'))
|
||||
@@ -289,7 +290,7 @@ function RequestCreationForm($oP, $oUserOrg)
|
||||
$oP->add("</div>\n");
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
$oP->add_ready_script(
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
// Create the object once at the beginning of the page... no state specified => new
|
||||
var oWizardHelper = new WizardHelper('UserRequest', '');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
// Copyright (C) 2012 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
|
||||
@@ -54,7 +54,8 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=>null, "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("notify_contact_id", array("targetclass"=>"Contact", "jointype"=>null, "allowed_values"=>null, "sql"=>"notify_contact_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("scope_class", array("class_category"=>"bizmodel,addon/authentication", "more_values"=>"", "sql"=>"scope_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("database_table_name", array("allowed_values"=>null, "sql"=>"database_table_name", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array(), "validation_pattern" => "^[A-Za-z0-9_]*$")));
|
||||
|
||||
// Declared here for a future usage, but ignored so far
|
||||
MetaModel::Init_AddAttribute(new AttributeString("scope_restriction", array("allowed_values"=>null, "sql"=>"scope_restriction", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
@@ -86,7 +87,7 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array(
|
||||
'col:0'=> array(
|
||||
'fieldset:SynchroDataSource:Description' => array('name','description','status','scope_class','user_id','notify_contact_id','url_icon','url_application')),
|
||||
'fieldset:SynchroDataSource:Description' => array('name','description','status','scope_class','user_id','notify_contact_id','url_icon','url_application', 'database_table_name')),
|
||||
'col:1'=> array(
|
||||
'fieldset:SynchroDataSource:Reconciliation' => array('reconciliation_policy','action_on_zero','action_on_one','action_on_multiple'),
|
||||
'fieldset:SynchroDataSource:Deletion' => array('user_delete_policy','full_load_periodicity','delete_policy','delete_policy_update','delete_policy_retention'))
|
||||
@@ -98,6 +99,15 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
public function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
{
|
||||
if (!$this->IsNew())
|
||||
{
|
||||
$this->Set('database_table_name', $this->GetDataTable());
|
||||
}
|
||||
parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
|
||||
}
|
||||
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
if (!$this->IsNew())
|
||||
@@ -476,7 +486,7 @@ EOF
|
||||
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
if (($sAttCode == 'scope_class') && (!$this->IsNew()))
|
||||
if ( (($sAttCode == 'scope_class') || ($sAttCode == 'database_table_name')) && (!$this->IsNew()))
|
||||
{
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
@@ -574,6 +584,13 @@ EOF
|
||||
|
||||
if ($this->IsNew())
|
||||
{
|
||||
// Compute the database_table_name
|
||||
$sDataTable = $this->Get('database_table_name');
|
||||
if (!empty($sDataTable))
|
||||
{
|
||||
$this->Set('database_table_name', $this->ComputeDataTableName());
|
||||
}
|
||||
|
||||
// When inserting a new datasource object, also create the SynchroAttribute objects
|
||||
// for each field of the target class
|
||||
// Create all the SynchroAttribute records
|
||||
@@ -659,6 +676,17 @@ EOF
|
||||
{
|
||||
$this->m_aCheckIssues[] = Dict::Format('Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified');
|
||||
}
|
||||
|
||||
// When creating the data source with a specified database_table_name, this table must NOT exist
|
||||
if ($this->IsNew())
|
||||
{
|
||||
$sDataTable = $this->GetDataTable();
|
||||
if (!empty($sDataTable) && CMDBSource::IsTable($this->GetDataTable()))
|
||||
{
|
||||
// Hmm, the synchro_data_xxx table already exists !!
|
||||
$this->m_aCheckIssues[] = Dict::Format('Class:SynchroDataSource/Error:DataTableAlreadyExists', $this->GetDataTable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetTargetClass()
|
||||
@@ -668,12 +696,34 @@ EOF
|
||||
|
||||
public function GetDataTable()
|
||||
{
|
||||
$sName = strtolower($this->GetTargetClass());
|
||||
$sName = str_replace('\'"&@|\\/ ', '_', $sName); // Remove forbidden characters from the table name
|
||||
$sName .= '_'.$this->GetKey(); // Add a suffix for unicity
|
||||
$sTable = MetaModel::GetConfig()->GetDBSubName()."synchro_data_$sName"; // Add the prefix if any
|
||||
$sTable = $this->Get('database_table_name');
|
||||
if (empty($sTable))
|
||||
{
|
||||
$sTable = $this->ComputeDataTableName();
|
||||
}
|
||||
return $sTable;
|
||||
}
|
||||
|
||||
protected function ComputeDataTableName()
|
||||
{
|
||||
$sDBTableName = $this->Get('database_table_name');
|
||||
if (empty($sDBTableName))
|
||||
{
|
||||
$sDBTableName = strtolower($this->GetTargetClass());
|
||||
$sDBTableName = preg_replace('/[^A-za-z0-9_]/', '_', $sDBTableName); // Remove forbidden characters from the table name
|
||||
$sDBTableName .= '_'.$this->GetKey(); // Add a suffix for unicity
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDBTableName = preg_replace('/[^A-za-z0-9_]/', '_', $sDBTableName); // Remove forbidden characters from the table name
|
||||
}
|
||||
$sPrefix = MetaModel::GetConfig()->GetDBSubName()."synchro_data_";
|
||||
if (strpos($sDBTableName, $sPrefix) !== 0)
|
||||
{
|
||||
$sDBTableName = $sPrefix.$sDBTableName;
|
||||
}
|
||||
return $sDBTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the new datasource has been created, let's create the synchro_data table
|
||||
@@ -819,6 +869,7 @@ EOF
|
||||
|
||||
}
|
||||
|
||||
$sTable = $this->GetDataTable();
|
||||
foreach($this->ListTargetAttributes() as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (!isset($aAttributes[$sAttCode]))
|
||||
@@ -845,8 +896,48 @@ EOF
|
||||
$oAttribute->DBInsertTracked($oChange);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aColumns = $this->GetSQLColumns(array($sAttCode));
|
||||
foreach($aColumns as $sColName => $sColumnDef)
|
||||
{
|
||||
$bOneColIsMissing = false;
|
||||
if (!CMDBSource::IsField($sTable, $sColName))
|
||||
{
|
||||
$bFixNeeded = true;
|
||||
$bOneColIsMissing = true;
|
||||
if ($bVerbose)
|
||||
{
|
||||
if (count($aColumns) > 1)
|
||||
{
|
||||
echo "Missing column '$sColName', in the table '$sTable' for the data synchro task ".$this->GetName()." (".$this->GetKey()."). The columns '".implode("', '", $aColumns )." will be re-created.'.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Missing column '$sColName', in the table '$sTable' for the data synchro task ".$this->GetName()." (".$this->GetKey()."). The column '$sColName' will be added.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(CMDBSource::GetFieldType($sTable, $sColName), $sColumnDef) != 0)
|
||||
{
|
||||
$bFixNeeded = true;
|
||||
$bOneColIsMissing = true;
|
||||
if (count($aColumns) > 1)
|
||||
{
|
||||
echo "Incorrect column '$sColName' (".CMDBSource::GetFieldType($sTable, $sColName)." instead of ".$sColumnDef."), in the table '$sTable' for the data synchro task ".$this->GetName()." (".$this->GetKey()."). The columns '".implode("', '", $aColumns )." will be re-created.'.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Incorrect column '$sColName' (".CMDBSource::GetFieldType($sTable, $sColName)." instead of ".$sColumnDef."), in the table '$sTable' for the data synchro task ".$this->GetName()." (".$this->GetKey()."). The column '$sColName' will be added.\n";
|
||||
}
|
||||
}
|
||||
if ($bOneColIsMissing)
|
||||
{
|
||||
$aMissingFields[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$sTable = $this->GetDataTable();
|
||||
if ($bFixNeeded && (count($aMissingFields) > 0))
|
||||
{
|
||||
$aRepairQueries = array();
|
||||
@@ -858,13 +949,18 @@ EOF
|
||||
{
|
||||
if (CMDBSource::IsField($sTable, $sAttCode))
|
||||
{
|
||||
$aRepairQueries[] = "ALTER TABLE `$sTable` DROP COLUMN `$sAttCode`;";
|
||||
$aRepairQueries[] = "ALTER TABLE `$sTable` CHANGE `$sAttCode` `$sAttCode` $sColumnDef";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aFieldDefs[] = "`$sAttCode` $sColumnDef";
|
||||
}
|
||||
|
||||
$aFieldDefs[] = "`$sAttCode` $sColumnDef";
|
||||
}
|
||||
|
||||
$aRepairQueries[] = "ALTER TABLE `$sTable` ADD (".implode(',', $aFieldDefs).");";
|
||||
if (count($aFieldDefs) > 0)
|
||||
{
|
||||
$aRepairQueries[] = "ALTER TABLE `$sTable` ADD (".implode(',', $aFieldDefs).");";
|
||||
}
|
||||
|
||||
// The triggers as well must be adjusted
|
||||
$aTriggersDefs = $this->GetTriggersDefinition();
|
||||
@@ -880,7 +976,7 @@ EOF
|
||||
if ($bVerbose)
|
||||
{
|
||||
// Report the issue
|
||||
echo "The structure of the table $sTable for the data synchro task ".$this->GetName()." (".$this->GetKey().") must be altered (missing fields: ".implode(',', $aMissingFields).").\n";
|
||||
echo "The structure of the table $sTable for the data synchro task ".$this->GetName()." (".$this->GetKey().") must be altered (missing or incorrect fields: ".implode(',', $aMissingFields).").\n";
|
||||
echo "The trigger {$sTable}_bi, {$sTable}_bu, {$sTable}_ad for the data synchro task ".$this->GetName()." (".$this->GetKey().") must be re-created.\n";
|
||||
echo implode("\n", $aRepairQueries)."\n";
|
||||
}
|
||||
@@ -989,7 +1085,7 @@ EOF
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// The pkey might be used as well as any other key column
|
||||
$aColumns[$sAttCode] = 'VARCHAR (255)';
|
||||
$aColumns[$sAttCode] = 'VARCHAR(255)';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1460,11 +1556,15 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
$oDataSource = MetaModel::GetObject('SynchroDataSource', $this->Get('sync_source_id'));
|
||||
$sTable = $oDataSource->GetDataTable();
|
||||
$oDataSource = MetaModel::GetObject('SynchroDataSource', $this->Get('sync_source_id'), false);
|
||||
if ($oDataSource)
|
||||
{
|
||||
$sTable = $oDataSource->GetDataTable();
|
||||
|
||||
$sSQL = "DELETE FROM `$sTable` WHERE id = '{$this->GetKey()}'";
|
||||
CMDBSource::Query($sSQL);
|
||||
$sSQL = "DELETE FROM `$sTable` WHERE id = '{$this->GetKey()}'";
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
// else the whole datasource has probably been already deleted
|
||||
}
|
||||
|
||||
$this->AfterDelete();
|
||||
@@ -1686,8 +1786,21 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$value = $this->GetValueFromExtData($sAttCode, $oSyncAtt, $oStatLog);
|
||||
if (!is_null($value))
|
||||
{
|
||||
$oDestObj->Set($sAttCode, $value);
|
||||
$aValueTrace[] = "$sAttCode: $value";
|
||||
if ($oSyncAtt->Get('update_policy') == 'write_if_empty')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oDestObj), $sAttCode);
|
||||
if ($oAttDef->IsNull($oDestObj->Get($sAttCode)))
|
||||
{
|
||||
// The value is still "empty" in the target object, we are allowed to write the new value
|
||||
$oDestObj->Set($sAttCode, $value);
|
||||
$aValueTrace[] = "$sAttCode: $value";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDestObj->Set($sAttCode, $value);
|
||||
$aValueTrace[] = "$sAttCode: $value";
|
||||
}
|
||||
}
|
||||
}
|
||||
// Really modified ?
|
||||
|
||||
@@ -283,12 +283,26 @@ abstract class WebServicesBase
|
||||
$oLog->Set('userinfo', UserRights::GetUser());
|
||||
$oLog->Set('verb', $sVerb);
|
||||
$oLog->Set('result', $oRes->IsOk());
|
||||
$oLog->Set('log_info', $oRes->GetInfoAsText());
|
||||
$oLog->Set('log_warning', $oRes->GetWarningsAsText());
|
||||
$oLog->Set('log_error', $oRes->GetErrorsAsText());
|
||||
$oLog->Set('data', $oRes->GetReturnedDataAsText());
|
||||
$this->TrimAndSetValue($oLog, 'log_info', $oRes->GetInfoAsText());
|
||||
$this->TrimAndSetValue($oLog, 'log_warning', $oRes->GetWarningsAsText());
|
||||
$this->TrimAndSetValue($oLog, 'log_error', $oRes->GetErrorsAsText());
|
||||
$this->TrimAndSetValue($oLog, 'data', $oRes->GetReturnedDataAsText());
|
||||
$oLog->DBInsertNoReload();
|
||||
}
|
||||
|
||||
protected function TrimAndSetValue($oLog, $sAttCode, $sValue)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oLog), $sAttCode);
|
||||
if (is_object($oAttDef))
|
||||
{
|
||||
$iMaxSize = $oAttDef->GetMaxSize();
|
||||
if ($iMaxSize)
|
||||
{
|
||||
$sValue = substr($sValue, 0, $iMaxSize);
|
||||
}
|
||||
$oLog->Set($sAttCode, $sValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set a scalar attribute
|
||||
|
||||
Reference in New Issue
Block a user