fetchAllByKey($fetchTableProcesInitListSql, 'ID')); } public static function getProcesInitMapTreeOnlyIds($ids) { $mapTree = array(); $map = self::getProcesInitMapOnlyIds($ids); foreach ($map as $row) { if ('PROCES_INIT' == $row['TYPE']) { $mapTree[ $row['ID_PROCES'] ] = array(); } } foreach ($map as $row) { if ('GOTO_AND_RETURN' == $row['TYPE']) { $mapTree[ $row['idx_MAIN_PROCES_INIT_ID'] ][ $row['ID_PROCES'] ] = array(); } } foreach ($map as $row) { if ('GOTO_AND_RETURN_LVL2' == $row['TYPE']) { $mapTree[ $row['idx_MAIN_PROCES_INIT_ID'] ][ $row['idx_GOTO_LVL2_INIT_ID'] ][ $row['ID_PROCES'] ] = true; } } return $mapTree; } public static function getProcesInitMapOnlyIds($ids) { $map = array(); $sqlIds = V::filter($ids, array('V', 'filterPositiveInteger')); $sqlIds = implode(',', $sqlIds); if (empty($sqlIds)) return $map; $sql = " select i.`ID_PROCES` , i.`PARENT_ID` , i.`TYPE` , i.`idx_PROCES_INIT_ID` , i.`idx_MAIN_PROCES_INIT_ID` , i.`idx_PROCES_WITH_GROUPS_ID` , IF(i.`TYPE`='GOTO_AND_RETURN_LVL2' , (select ig.`idx_PROCES_INIT_ID` from `CRM_PROCES_idx` ig where ig.`ID_PROCES`=i.`PARENT_ID` limit 1) , 0 ) as idx_GOTO_LVL2_INIT_ID from `CRM_PROCES_idx` i where i.`ID_PROCES` in({$sqlIds}) and i.`idx_MAIN_PROCES_INIT_ID` in({$sqlIds}) "; return DB::getPDO()->fetchAll($sql); } public static function canGroupViewProces($idGroup, $idProcesInit) { $isAllowed = false; $idProcesInit = (int)$idProcesInit; if (!$idProcesInit) return false; $checkProcesAccessSql = " select count(*) as cnt from `CRM_PROCES_idx_GROUP_to_INIT_VIEW` giv where giv.`ID_GROUP` = '{$idGroup}' and giv.`ID_PROCES_INIT` = '{$idProcesInit}' "; return ( DB::getPDO()->fetchValue($checkProcesAccessSql) > 0 ); } public static function getStorageByNamespace($namespace, $forceTblAclInit = false) { Lib::loadClass('Core_AclHelper'); Lib::loadClass('SchemaFactory'); $ns = Core_AclHelper::parseNamespaceUrl($namespace); DBG::log($ns, 'array', "parseNamespaceUrl({$namespace})"); if ('default_db' == $ns['prefix']) { $acl = User::getAcl()->getObjectAcl($ns['prefix'], $ns['name']); } else if ('objects' == $ns['prefix']) { $acl = SchemaFactory::loadDefaultObject($ns['name']); } else if ('default_objects' == $ns['prefix']) { $acl = SchemaFactory::loadDefaultObject($ns['name']); } else if ('default_db__x3A__' == substr($ns['prefix'], 0, 17)) { $rootTableName = strtolower(substr($ns['prefix'], 17)); $acl = SchemaFactory::loadTableObject($rootTableName, $ns['name']); } else { throw new HttpException("Not Implemented", 501); } $acl->init($forceTblAclInit); return $acl; } public static function getBaseNamespace($namespace) { // map SystemObjects__x3A__{parent}/{name} to default_objects/{name} if ('SystemObjects/' === substr($namespace, 0, strlen('SystemObjects/'))) { $exNs = explode('/', $namespace); if (3 === count($exNs)) { return "default_objects/{$exNs[2]}"; } } return $namespace; } public static function getAclByNamespace($namespace, $forceTblAclInit = false) { $namespace = ACL::getBaseNamespace($namespace); return Core_AclHelper::getAclByNamespace($namespace, $forceTblAclInit); } public static function getAclByTypeName($typeName, $forceTblAclInit = false) { return Core_AclHelper::getAclByNamespace(str_replace(':', '/', $typeName), $forceTblAclInit); } public static function getNamespaceFromId($idZasob) { $sqlIdZasob = DB::getPDO()->quote($idZasob, PDO::PARAM_INT); $zasob = DB::getPDO()->fetchFirst(" select z.ID, z.DESC, z.PARENT_ID from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdZasob} and z.`TYPE` = 'TABELA' and z.A_STATUS != 'DELETED' "); if (!$zasob) throw new Exception("Object not exists '{$idZasob}'"); if ($zasob['PARENT_ID'] != DB::getPDO()->getZasobId()) { throw new Exception("TODO: getNamespaceFromId for remote database"); } return ('default_db/' === substr($zasob['DESC'], 0, strlen('default_db/'))) ? $zasob['DESC'] : "default_db/{$zasob['DESC']}" ; } public static function parseNamespaceUrl($namespace) {// returns assoc array: [ 'name', 'url', 'prefix', 'sourceName' ] return Core_AclHelper::parseNamespaceUrl($namespace); } static function getRefConfig($rootObjectNamespace, $childName) { // @return Type_RefConfig or throws Exception return RefConfig::getRefConfig($rootObjectNamespace, $childName); } public static function getRefTable($rootObjectNamespace, $childName) { // TODO: RMME - use getRefConfig static $cacheRefTables = array(); DBG::log("DBG get ref table ({$rootObjectNamespace}, {$childName}) ..."); $rootObjectNamespace = ACL::getBaseNamespace($rootObjectNamespace); $cacheKey = "{$rootObjectNamespace}/{$childName}"; if (array_key_exists($cacheKey, $cacheRefTables)) return $cacheRefTables[$cacheKey]; $rootAcl = self::getAclByNamespace($rootObjectNamespace); // $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($rootObjectNamespace, [ 'propertyName' => '*,field' ]); if (!($rootAcl instanceof AntAclBase)) throw new Exception("Ref allowed only for AntAcl objects"); $refConfig = RefConfig::getRefConfig($rootObjectNamespace, $childName); $cacheRefTables[$cacheKey] = $refConfig->tableName; return $cacheRefTables[$cacheKey]; } public static function getRefSource($rootObjectNamespace, $childName) { // CRM_REF_CONFIG $rootObjectNamespace = ACL::getBaseNamespace($rootObjectNamespace); $refConfig = RefConfig::fetch($rootObjectNamespace, $childName); return $refConfig->source; } public static function addRef($ns, $typeName, $pk, $remotePk) { $refTable = ACL::getRefTable($ns, $typeName); // TODO: RefConfig::fetch($ns, $typeName); DB::getPDO()->insert($refTable, [ 'PRIMARY_KEY' => $pk, 'REMOTE_PRIMARY_KEY' => $remotePk ]); } public static function addListRef($ns, $typeName, $pk, $listRemotePk) { $refTable = ACL::getRefTable($ns, $typeName); // TODO: RefConfig::fetch($ns, $typeName); foreach ($listRemotePk as $remotePk) { DB::getPDO()->insert($refTable, [ 'PRIMARY_KEY' => $pk, 'REMOTE_PRIMARY_KEY' => $remotePk ]); } } public static function removeRef($ns, $typeName, $pk, $remotePk) { $refTable = ACL::getRefTable($ns, $typeName); // TODO: RefConfig::fetch($ns, $typeName); DB::getPDO()->execSql(" delete from `{$refTable}` where PRIMARY_KEY = :pk and REMOTE_PRIMARY_KEY = :remote_pk ", [ ':pk' => $pk, ':remote_pk' => $remotePk ]); } public static function removeListRef($ns, $typeName, $pk, $listRemotePk) { $refTable = ACL::getRefTable($ns, $typeName); // TODO: RefConfig::fetch($ns, $typeName); foreach ($listRemotePk as $remotePk) { DB::getPDO()->execSql(" delete from `{$refTable}` where PRIMARY_KEY = :pk and REMOTE_PRIMARY_KEY = :remote_pk ", [ ':pk' => $pk, ':remote_pk' => $remotePk ]); } } public static function decodeAppInfoJson($appInfoJsonString) { $appInfo = @json_decode($appInfoJsonString, $assoc = true); if (null == $appInfo && 0 !== json_last_error()) throw new Exception("Parsing Json failed: " . json_last_error()); return $appInfo; } public static function generateRefSelectSqlByFlatRelationCache($rootObjectNamespace, $childName) { // CRM_REF_CONFIG $appInfo = DB::getPDO()->fetchValue(" select f.appInfo from `CRM_#CACHE_ACL_OBJECT_FIELD` f where f.objectNamespace = :objectNamespace and f.fieldNamespace = :fieldNamespace ", [ ':objectNamespace' => $rootObjectNamespace, ':fieldNamespace' => $childName, ]); if (!$appInfo) throw new Exception("Missing app:info for field '{$rootObjectNamespace}/{$childName}'"); $appInfo = ACL::decodeAppInfoJson($appInfo); if (empty($appInfo)) throw new Exception("Empty app:info for field '{$rootObjectNamespace}/{$childName}'"); DBG::log(['$appInfo'=>$appInfo, '$rootObjectNamespace'=>$rootObjectNamespace, '$childName'=>$childName], 'array', "\$appInfo"); $rootAcl = self::getAclByNamespace($rootObjectNamespace); $childXsdType = $rootAcl->getXsdFieldType($childName); list($typePrefix, $childNamespace) = explode(':', $childXsdType, 2); switch ($typePrefix) { case 'ref_uri': $childAcl = self::getAclByNamespace($childNamespace); break; case 'ref': $childAcl = self::getAclByTypeName($childNamespace); break; default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'"); } $lastActionDateField = "NULL"; // , IF(l.A_RECORD_UPDATE_DATE > r.A_RECORD_UPDATE_DATE, l.A_RECORD_UPDATE_DATE, r.A_RECORD_UPDATE_DATE) as A_LAST_ACTION_DATE $rootPrimaryKeyField = $rootAcl->getPrimaryKeyField(); $childPrimaryKeyField = $childAcl->getPrimaryKeyField(); $rootTableName = $rootAcl->getRootTableName(); $childTableName = $childAcl->getRootTableName(); // '$appInfo' => [ // 'flat_relation_cache' => [ // 'source' => [ // '@name' => 'ID', // '@xpath' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK/ID_PROCES', // ), // ), // ), // '$rootObjectNamespace' => 'default_db/CRM_PROCES/PROCES', // '$childName' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK', // '$appInfo' => [ // 'flat_relation_cache' => [ // 'source' => [ // '@name' => 'ID', // '@xpath' => 'default_db__x3A__CRM_PROCES:PROCES/PARENT_ID', // ), // ), // ), // '$rootObjectNamespace' => 'default_db/CRM_PROCES/PROCES', // '$childName' => 'default_db__x3A__CRM_PROCES:PROCES', $appInfoRootFieldName = null; $appInfoChildFieldName = null; { if (empty($appInfo['flat_relation_cache']['source']['@name'])) throw new Exception("Missing flat_relation_cache/source/@name"); if (empty($appInfo['flat_relation_cache']['source']['@xpath'])) throw new Exception("Missing flat_relation_cache/source/@xpath"); $appInfoName = $appInfo['flat_relation_cache']['source']['@name']; $appInfoXpath = $appInfo['flat_relation_cache']['source']['@xpath']; // $rootNs = $rootAcl->getNamespace() if ("{$childName}/" === substr($appInfoXpath, 0, strlen("{$childName}/"))) { $appInfoRootFieldName = substr($appInfoXpath, strlen("{$childName}/")); $appInfoChildFieldName = $appInfoName; } else { throw new Exception("TODO parse flat_relation_cache"); } } if (!$appInfoRootFieldName || !$appInfoChildFieldName) throw new Exception("Error Processing flat_relation_cache"); $sqlWhereFromRestrictions = []; DBG::log(['root'=>$rootAcl->getFields(), 'child'=>$childAcl->getFields()], 'array', "rootAcl and childAcl fields - xsdRestrictions"); if ($rootAcl instanceof AntAclBase && $childAcl instanceof AntAclBase) { $rootLocalFieldsWithRestrictions = array_filter($rootAcl->getFields(), function ($field) { if (!$field['isLocal']) return false; if (empty($field['xsdRestrictions'])) return false; if ('[]' == $field['xsdRestrictions']) return false; return true; }); $childLocalFieldsWithRestrictions = array_filter($childAcl->getFields(), function ($field) { if (!$field['isLocal']) return false; if (empty($field['xsdRestrictions'])) return false; if ('[]' == $field['xsdRestrictions']) return false; return true; }); DBG::log(['root'=>$rootLocalFieldsWithRestrictions, 'child'=>$childLocalFieldsWithRestrictions], 'array', "root and child fields with xsdRestrictions"); if (!empty($rootLocalFieldsWithRestrictions)) { $sqlTablePrefix = 'root'; $sqlWhereFromRestrictions = array_reduce( array_map(function ($field) use ($sqlTablePrefix) { $sqlRestrictions = []; // 'xsdRestrictions' => '{"enumeration":{"PROCES":"PROCES"}}', $restrictions = @json_decode($field['xsdRestrictions'], $assoc = true); if (!empty($restrictions)) { if (!empty($restrictions['enumeration'])) { $sqlRestrictions[] = "{$sqlTablePrefix}.`{$field['fieldNamespace']}` in (" . implode(",", array_map([DB::getPDO(), 'quote'], array_keys($restrictions['enumeration']))) . ")"; } } return $sqlRestrictions; }, $rootLocalFieldsWithRestrictions), function ($ret, $cur) { return array_merge($ret, array_filter($cur, ['V', 'filterNotEmpty'])); }, $sqlWhereFromRestrictions ); } if (!empty($childLocalFieldsWithRestrictions)) { $sqlTablePrefix = 'child'; $sqlWhereFromRestrictions = array_reduce( array_map(function ($field) use ($sqlTablePrefix) { $sqlRestrictions = []; // 'xsdRestrictions' => '{"enumeration":{"PROCES":"PROCES"}}', $restrictions = @json_decode($field['xsdRestrictions'], $assoc = true); if (!empty($restrictions)) { if (!empty($restrictions['enumeration'])) { $sqlRestrictions[] = "{$sqlTablePrefix}.`{$field['fieldNamespace']}` in (" . implode(",", array_map([DB::getPDO(), 'quote'], array_keys($restrictions['enumeration']))) . ")"; } } return $sqlRestrictions; }, $childLocalFieldsWithRestrictions), function ($ret, $cur) { return array_merge($ret, array_filter($cur, ['V', 'filterNotEmpty'])); }, $sqlWhereFromRestrictions ); } } $sqlWhereFromRestrictions = (!empty($sqlWhereFromRestrictions)) ? implode(" and ", $sqlWhereFromRestrictions) : "1=1"; $sqlChildFieldName = $childAcl->getSqlFieldName($appInfoRootFieldName); $sql = " select root.{$rootPrimaryKeyField} as PRIMARY_KEY , child.{$childPrimaryKeyField} as REMOTE_PRIMARY_KEY , '' as REMOTE_TYPENAME , 'WAITING' as A_STATUS , 0 as TRANSACTION_ID , {$lastActionDateField} as A_LAST_ACTION_DATE from `{$rootTableName}` root join `{$childTableName}` child on(child.{$sqlChildFieldName} = root.{$appInfoChildFieldName}) where {$sqlWhereFromRestrictions} "; DBG::log($sql, 'sql', "generateRefSelectSqlByFlatRelationCache"); return $sql; } public static function getBackRefList($namespace) { if (!$namespace) throw new Exception("Missing namespace"); $nsParts = explode('/', $namespace); $typeName = array_pop($nsParts); $typeName = implode("__x3A__", $nsParts) . ":{$typeName}"; return DB::getPDO()->fetchAll(" select c.ROOT_OBJECT_NS as namespace , i.id as idInstance from CRM_REF_CONFIG c join CRM_INSTANCE_CONFIG i on ( i.namespace = c.ROOT_OBJECT_NS ) where ( c.CHILD_NAME = :type_name or c.CHILD_NAME = :namespace ) and c.A_STATUS = 'NORMAL' ", [ ':type_name' => $typeName, ':namespace' => $namespace, ]); } public static function fetchRefs($namespace, $childNamespace, $primaryKey, $params = []) { // TODO: $params: limit, total if (!$namespace) throw new Exception("Missing namespace"); if (!$childNamespace) throw new Exception("Missing child namespace"); if (!$primaryKey) throw new Exception("Missing primary key"); throw new Exception("TODO: fetch refs from '{$namespace}' where primaryKey = '{$primaryKey}'"); } public static function fetchBackRefs($namespace, $primaryKey, $parentNamespace, $params = []) { // TODO: $params: limit, total if (!$namespace) throw new Exception("Missing namespace"); if (!$parentNamespace) throw new Exception("Missing parent namespace"); if (!$primaryKey) throw new Exception("Missing primary key"); $typeName = Api_WfsNs::typeName($namespace); $refTable = ACL::getRefTable($parentNamespace, $typeName); if (V::get('total', false, $params)) { return DB::getPDO()->fetchValue(" select count(*) as cnt from `{$refTable}` where REMOTE_PRIMARY_KEY = :primary_key and A_STATUS not in ('DELETED') ", [ ':primary_key' => $primaryKey ]); } throw new Exception("TODO: fetch back refs from '{$namespace}' where primaryKey({$primaryKey}) by refTable({$refTable})"); } static function generateSqlWhereFromFieldsWithRestrictions($fieldsRestrictions, $sqlTablePrefix = 't') { return InstanceConfig::generateSqlWhereFromFieldsWithRestrictions($fieldsRestrictions, $sqlTablePrefix); } static function generateSqlWhereFromFieldRestrictions($fields, $sqlTablePrefix = 't') { return InstanceConfig::generateSqlWhereFromFieldRestrictions($fields, $sqlTablePrefix); } static function getInstanceId($namespace) { return InstanceConfig::getInstanceId($namespace); } static function getInstanceConfig($namespace) { // @return Type_InstanceConfig return InstanceConfig::getInstanceConfig($namespace); } static function getInstanceTable($namespace) { // @return tableName with struct { pk, idInstance, _createdAt } return InstanceConfig::getInstanceTable($namespace); } static function getRootNamespace($namespace) { // TODO: works only for relative urls! - mv to Acl->getRootNamespace return InstanceConfig::getRootNamespace($namespace); } static function getNamespaceSiblings($namespace) { return InstanceConfig::getNamespaceSiblings($namespace); } static function getFeatureNamespaces($namespace, $pk) { return InstanceConfig::getFeatureNamespaces($namespace, $pk); } // @params $from - ( ACL | tableName | namespace | etc... - only ACL) public static function query($from, $prefix = 't') { Lib::loadClass('AclQueryBuilder'); $query = new AclQueryBuilder(); $query->from($from, $prefix); return $query; } /** * @param mixed $object - Core_AclBase or string - namespace * @return Core_AclFields */ public static function getObjectFields($object) { // TODO: try to get structure from `CRM_#CACHE_ACL_OBJECT_FIELD` // if ($object is instance Core_AclBase) { // if ($object->isStructInstalled) then get structure from `CRM_#CACHE_ACL_OBJECT_FIELD` and put into Core_AclFields // else get from $object->getFields() and put into Core_AclFields } public static function canUserReadObject($idUser, $aclOrIdZasob) { throw new Exception("TODO: canUserReadObjec({$idUser}, {$aclOrIdZasob})"); } public static function canUserCreateObject($idUser, $aclOrIdZasob) { throw new Exception("TODO: canUserCreateObjec({$idUser}, {$aclOrIdZasob})"); } public static function canUserWriteObject($idUser, $aclOrIdZasob) { throw new Exception("TODO: canUserWriteObjec({$idUser}, {$aclOrIdZasob})"); } public static function canUserReadObjectField($idUser, $aclOrIdZasob, $fieldNameOrXPath) { throw new Exception("TODO: canUserReadObjectFiel({$idUser}, {$aclOrIdZasob}, {$fieldNameOrXPath})"); } public static function canUserCreateObjectField($idUser, $aclOrIdZasob, $fieldNameOrXPath) { throw new Exception("TODO: canUserCreateObjectFiel({$idUser}, {$aclOrIdZasob}, {$fieldNameOrXPath})"); } public static function canUserWriteObjectField($idUser, $aclOrIdZasob, $fieldNameOrXPath) { throw new Exception("TODO: canUserWriteObjectFiel({$idUser}, {$aclOrIdZasob}, {$fieldNameOrXPath})"); } // TODO: replace below: // AclBase->canCreateField // AclBase->canReadField // AclBase->canReadObjectField // AclBase->canWriteField // AclBase->canWriteObjectField // AclBase->canWriteRecord // AclBase->canReadRecord }