execSql(" create table if not exists `CRM_INSTANCE_CONFIG` ( `id` int(11) not null AUTO_INCREMENT, `namespace` varchar(255) NOT NULL DEFAULT '', `rootNamespace` varchar(255) NOT NULL DEFAULT '', `idInstanceBase` int(11) NOT NULL DEFAULT 0, `_createdAt` datetime NOT NULL, UNIQUE KEY `namespace` (`namespace`), KEY `rootNamespace` (`rootNamespace`), PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin2 "); } static function getInstanceTable($namespace) { // @returns tableName with struct { pk, idInstance, _createdAt } $conf = self::getInstanceConfig($namespace); if (!empty($conf['idInstanceBase'])) return "CRM__#INSTANCE_TABLE__{$conf['idInstanceBase']}"; $rootNs = $conf['rootNamespace']; $rootConf = self::getInstanceConfig($rootNs); $instanceTableName = "CRM__#INSTANCE_TABLE__{$rootConf['id']}"; if (!empty($rootConf['idInstance'])) { $affected = DB::getPDO()->update("CRM_INSTANCE_CONFIG", 'rootNamespace', $rootNs, [ 'idInstanceBase' => $rootConf['id'] ]); return $instanceTableName; } // TODO: fetch primaryKeyType - TODO: store primaryKey and primaryKeyType in SystemObject item $pkType = 'int'; DB::getPDO()->exec(" CREATE TABLE IF NOT EXISTS `{$instanceTableName}` ( `pk` int(11) NOT NULL COMMENT 'primary key' , `idInstance` int(11) NOT NULL , `_createdAt` datetime NOT NULL , KEY `pk` (`pk`) , KEY `idInstance` (`idInstance`) ) ENGINE=MyISAM DEFAULT CHARSET=latin2 COMMENT='{$rootNs} #INSTANCE'; "); $affected = DB::getPDO()->update("CRM_INSTANCE_CONFIG", 'rootNamespace', $rootNs, [ 'idInstanceBase' => $rootConf['id'] ]); return $instanceTableName; } static function getInstanceConfig($namespace) { // @returns { id, namespace, rootNamespace, idInstanceBase, _createdAt } try { $conf = self::fetchInstanceConfig($namespace); } catch (Exception $e) { self::createInstanceConfigTable(); // TODO:?: `_tableInstalled` tinyint(1) not null default 0, $conf = self::fetchInstanceConfig($namespace); } if (!$conf) { $id = DB::getPDO()->insert("CRM_INSTANCE_CONFIG", [ 'namespace' => $namespace, 'rootNamespace' => self::getRootNamespace($namespace), '_createdAt' => 'NOW()', ]); $conf = self::fetchInstanceConfig($namespace); } if (!$conf) throw new Exception("Instance not found in config table '{$namespace}'"); return $conf; } static function fetchInstanceConfig($namespace) { return DB::getPDO()->fetchFirst(" select c.* from `CRM_INSTANCE_CONFIG` c where c.namespace = :namespace ", [ ':namespace' => $namespace ]); } static function getRootNamespace($namespace) { // TODO: works only for relative urls! - mv to Acl->getRootNamespace Lib::loadClass('SchemaFactory'); try { $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace); } catch (Exception $e) { throw new Exception("Object not installed '{$namespace}'"); } if (!$objectItem['isStructInstalled']) throw new Exception("Object structure not installed '{$namespace}'"); if ($objectItem['idDatabase'] != DB::getPDO()->getZasobId()) { if ('StorageAcl' === $objectItem['_type']) { DBG::log("getRootNamespace..."); return $objectItem['namespace']; } else { throw new Exception("Only default_db supported"); // TODO: support more Sources } } return "default_db/{$objectItem['_rootTableName']}"; } static function getNamespaceSiblings($namespace) { return array_map(function ($row) { return $row['namespace']; }, DB::getPDO()->fetchAll(" select s.namespace from CRM_INSTANCE_CONFIG c join CRM_INSTANCE_CONFIG s on ( s.rootNamespace = c.rootNamespace and s.namespace != c.rootNamespace ) where c.namespace = :namespace ", [ 'namespace' => $namespace ])); } static function getFeatureNamespaces($namespace, $pk) { $instanceTable = self::getInstanceTable($namespace); return array_map(function ($row) { return $row['namespace']; }, DB::getPDO()->fetchAll(" select c.namespace from `{$instanceTable}` i join `CRM_INSTANCE_CONFIG` c on ( c.id = i.idInstance ) where i.pk = :pk ", [ 'pk' => $pk, ])); } }