Exemplo n.º 1
0
 public function processConfig($xml)
 {
     $return = false;
     $xmlObj = $xml instanceof SimpleXMLElement ? $xml : simplexml_load_string($xml);
     if (!$this->getFileInPath(self::DEFAULT_CONFIG_SCHEMA)) {
         $this->throwException('Schema document ' . self::DEFAULT_CONFIG_SCHEMA . ' not found in path');
     }
     dom_import_simplexml($xmlObj)->ownerDocument->schemaValidate($this->getFileInPath(self::DEFAULT_CONFIG_SCHEMA)) or $this->throwException('Invalid configuration (failed schema check)');
     $options = self::defaultOptions();
     $dataTypeMap = array(self::OPTION_GRID_CLASS => array(), self::VALUE_GLOBAL => array());
     $grids = array();
     $gridClasses = array();
     $gridCommands = array();
     $gridParameters = array();
     $columns = array();
     $keys = array();
     $uniqueKeys = array();
     $references = array();
     $referenceAliases = array();
     if (isset($xmlObj->Options)) {
         foreach ($xmlObj->Options->children() as $option) {
             switch ($option->getName()) {
                 // Handle all the bools together, since they're all processed the same way.
                 case self::OPTION_CACHE_REFERENCED_GRIDS:
                 case self::OPTION_CACHE_REFERENCED_GRID_SETS:
                 case self::OPTION_DEBUG:
                 case self::OPTION_LINK_UNPUBLISHED_REFERENCE_COLUMNS:
                 case self::OPTION_OVERWRITE_ON_LOAD:
                 case self::OPTION_PERMIT_DDL:
                 case self::OPTION_PERPETUATE_AUTO_LINKS:
                 case self::OPTION_PUBLISH_ALL_COLUMNS:
                 case self::OPTION_PUBLISH_DEPENDENCIES:
                 case self::OPTION_RELOAD_AFTER_PUBLISH:
                 case self::OPTION_TYPED_GRID_CLASSES:
                     $options[$option->getName()] = (string) $option == self::VALUE_TRUE ? true : false;
                     break;
                 case self::OPTION_COLUMN_CLASS:
                     $className = (string) $option;
                     $this->checkColumnClass($className);
                     $options[self::OPTION_COLUMN_CLASS] = $className;
                     break;
                 case self::OPTION_GRID_CLASS:
                     $className = (string) $option;
                     $this->checkGridClass($className);
                     $options[self::OPTION_GRID_CLASS] = $className;
                     break;
                 case self::OPTION_PAGE_SIZE:
                     $options[$option->getName()] = (int) $option;
                     break;
                 case self::OPTION_TYPED_GRID_CLASSES_PREFIX:
                     $options[self::OPTION_TYPED_GRID_CLASSES_PREFIX] = (string) $option;
                     break;
                 case 'DataTypeMap':
                     $dataTypeMap[self::VALUE_GLOBAL] = $this->parseDataTypeMap($option);
                     break;
                 default:
                     $this->throwException('Unrecognized option "' . $option->getName() . '"');
                     break;
             }
         }
     }
     if (isset($xmlObj->Repository)) {
         if (isset($xmlObj->Repository->Cache)) {
             $cacheXml = $xmlObj->Repository->Cache;
             $cacheClass = (string) $cacheXml->attributes()->class;
             if (!class_exists($cacheClass)) {
                 // Attempt to load
                 if ($file = self::getFileInPath($cacheClass . '.php')) {
                     include $file;
                 }
                 // Check one more time
                 if (!class_exists($cacheClass)) {
                     $this->throwException('Cache class "' . $cacheClass . '" is not defined');
                 }
             }
             $settings = array();
             foreach ($cacheXml->Parameter as $parameterXml) {
                 $settings[(string) $parameterXml->attributes()->name] = isset($parameterXml->attributes()->value) ? (string) $parameterXml->attributes()->value : (string) $parameterXml;
             }
             $cache = call_user_func(array($cacheClass, 'createInstance'), $this);
             $cache->initialize($settings);
             $this->Cache($cache);
         }
         $readDataStore = null;
         $writeDataStore = null;
         $readXml = null;
         $writeXml = null;
         if (isset($xmlObj->Repository->DataStore)) {
             $readXml = $writeXml = $xmlObj->Repository->DataStore;
         } else {
             $readXml = $xmlObj->Repository->ReadDataStore;
             $writeXml = $xmlObj->Repository->WriteDataStore;
         }
         foreach (array('read' => $readXml, 'write' => $writeXml) as $storeType => $dataStoreXml) {
             if ($storeType == 'write' && $writeXml === $readXml) {
                 continue;
             }
             $settings = array();
             foreach ($dataStoreXml->Parameter as $parameterXml) {
                 $settings[(string) $parameterXml->attributes()->name] = ((string) $parameterXml->attributes()->encrypted == self::VALUE_TRUE ? self::VALUE_ENC_PREFIX : '') . (isset($parameterXml->attributes()->value) ? (string) $parameterXml->attributes()->value : (string) $parameterXml);
             }
             $className = self::DATA_STORE_CLASS;
             if (isset($dataStoreXml->attributes()->class)) {
                 $className = (string) $dataStoreXml->attributes()->class;
                 if (empty($className) || !class_exists($className)) {
                     $this->throwException('Undefined ' . self::DATA_STORE_CLASS . ' class "' . $className . '" requested');
                 }
                 if ($className != self::DATA_STORE_CLASS && !in_array(self::DATA_STORE_CLASS, class_parents($className))) {
                     trigger_error('Requested DataStore class "' . $className . '" does not appear to inherit from ' . self::DATA_STORE_CLASS . ' - I hope you know what you\'re doing', E_USER_WARNING);
                 }
             } else {
                 switch (strtolower((string) $dataStoreXml->attributes()->type)) {
                     // Using just-in-time require_once calls in the event that lazy loading
                     // has not been enabled on this system.  Should be negligible with
                     // regard to performance.
                     case 'custom':
                         $this->throwException('Custom data store requested but no class set');
                         break;
                     case 'mssql':
                     case 'sqlserver':
                         require_once ($className = 'MSSQLDataStore') . '.php';
                         break;
                     case 'mysql':
                         require_once ($className = 'MySQLDataStore') . '.php';
                         break;
                     case 'mysqli':
                         if (!version_compare(PHP_VERSION, '5.3.0', '>=')) {
                             $this->throwException('The MySQLi interface is available only in PHP version 5.3.0 or greater (current version is ' . PHP_VERSION . ')');
                         }
                         // TODO: Write these files.
                         require_once ($className = 'MySQLiDataStore') . '.php';
                         break;
                     case 'odbc':
                         require_once ($className = 'ODBCDataStore') . '.php';
                         break;
                     case 'oci':
                     case 'oracle':
                         require_once ($className = 'OracleDataStore') . '.php';
                         break;
                     case 'postgres':
                         require_once ($className = 'PostgresDataStore') . '.php';
                         break;
                     case 'sqlite':
                         require_once ($className = 'SQLiteDataStore') . '.php';
                         break;
                     default:
                         $this->throwException('Unrecognized data store type "' . (string) $dataStoreXml->attributes()->type . '" requested');
                         break;
                 }
             }
             $dataStore = call_user_func(array($className, 'createInstance'), $this);
             $dataStore->initialize($storeType == 'write' || $writeXml === $readXml ? true : false, $settings);
             if ($storeType == 'read') {
                 $this->ReadDataStore($dataStore);
             }
             if ($storeType == 'write' || $writeXml === $readXml) {
                 $this->WriteDataStore($dataStore);
             }
         }
     }
     foreach ($xmlObj->Grids->Grid as $gridXml) {
         $gridName = $this->xmlObjKeyName($gridXml);
         if (!$gridName) {
             $this->throwException('Could not extract a suitable grid name');
         }
         if (isset($grids[$gridName])) {
             $this->throwException('Duplicate grid name ' . $gridName);
         }
         // TODO: Auto-pruning or just-in-time generation, so as not to have empty
         // arrays all over the place?
         $grids[$gridName] = (string) $gridXml->attributes()->dataName;
         $columns[$gridName] = array();
         $keys[$gridName] = array();
         $uniqueKeys[$gridName] = array();
         $references[$gridName] = array();
         if ($className = (string) $gridXml->attributes()->class) {
             if ($className == self::VALUE_NONE) {
                 $className = self::DEFAULT_GRID_CLASS;
             }
             $gridClasses[$gridName] = $className;
         } else {
             if ($options[self::OPTION_TYPED_GRID_CLASSES]) {
                 $gridClasses[$gridName] = $options[self::OPTION_TYPED_GRID_CLASSES_PREFIX] . $gridName;
             }
         }
         foreach ($gridXml->Columns->Column as $columnXml) {
             $columnName = $this->xmlObjKeyName($columnXml);
             if (!$columnName) {
                 $this->throwException('Could not extract a suitable column name');
             }
             if (isset($columns[$gridName][$columnName])) {
                 $this->throwException('Duplicate column name ' . $columnName . ' on grid ' . $gridName);
             }
             if (isset($columnXml->attributes()->class) || strtoupper((string) $columnXml->attributes()->type) == Column::TYPE_CLASS) {
                 if (!isset($columnXml->attributes()->class)) {
                     $this->throwException('Column attribute "class" must be defined for type ' . Column::TYPE_CLASS);
                 }
                 $className = (string) $columnXml->attributes()->class;
                 if ($className != self::VALUE_NONE) {
                     $this->checkColumnClass($className);
                 }
             }
             $columns[$gridName][$columnName] = $columnXml;
             // We want this one to hang around.
         }
         if (isset($gridXml->Commands)) {
             foreach ($gridXml->Commands->Command as $commandXml) {
                 $command = new PersistenceCommand();
                 $command->setCommand((string) $commandXml->CommandText);
                 $command->setType($this->makeKeyName((string) $commandXml->attributes()->type));
                 if (isset($commandXml->attributes()->context)) {
                     $command->setContext($this->makeKeyName((string) $commandXml->attributes()->context));
                 }
                 if (isset($commandXml->attributes()->placeholder)) {
                     $command->setPlaceholder((string) $commandXml->attributes()->placeholder);
                 }
                 if (isset($commandXml->CommandText->attributes()->type)) {
                     $command->setCommandType((string) $commandXml->CommandText->attributes()->type);
                 }
                 if (isset($commandXml->CommandParameter)) {
                     foreach ($commandXml->CommandParameter as $parameterXml) {
                         $command->addParameter($this->makeKeyName((string) $parameterXml->attributes()->column), isset($parameterXml->attributes()->placeholder) ? (string) $parameterXml->attributes()->placeholder : null);
                     }
                 }
                 if (!isset($gridCommands[$gridName])) {
                     $gridCommands[$gridName] = array();
                 }
                 if (!isset($gridCommands[$gridName][$command->getType()])) {
                     $gridCommands[$gridName][$command->getType()] = array();
                 }
                 $gridCommands[$gridName][$command->getType()][] = $command;
             }
         }
         if (isset($gridXml->DataStoreParameters)) {
             $parameters = array();
             foreach ($gridXml->DataStoreParameters->Parameter as $parameterXml) {
                 $parameters[(string) $parameterXml->attributes()->name] = isset($parameterXml->attributes()->value) ? (string) $parameterXml->attributes()->value : (string) $parameterXml;
             }
             if (count($parameters) > 0) {
                 $gridParameters[$gridName] = $parameters;
             }
         }
         if (isset($gridXml->DataTypeMap)) {
             $dataTypeMap[self::DEFAULT_GRID_CLASS][$gridName] = $this->parseDataTypeMap($gridXml->DataTypeMap);
         }
         if (isset($gridXml->Keys)) {
             if (isset($gridXml->Keys->Primary)) {
                 $keyArray = array();
                 foreach ($gridXml->Keys->Primary->Key as $xmlKey) {
                     $keyName = $this->makeKeyName((string) $xmlKey->attributes()->column);
                     if (!$keyName) {
                         $this->throwException('Invalid key name ' . (string) $xmlKey->attributes()->column . ' in ' . $gridName);
                     }
                     $keyArray[] = $keyName;
                 }
                 if (count($keyArray) <= 0) {
                     $this->throwException('No suitable primary keys defined for grid ' . $gridName);
                 } else {
                     if (count($keyArray) == 1) {
                         // One key and only one key, which is nice
                         $keys[$gridName] = array_shift($keyArray);
                     } else {
                         $keys[$gridName] = $keyArray;
                     }
                 }
             }
             if (isset($gridXml->Keys->Unique)) {
                 foreach ($gridXml->Keys->Unique as $xmlUnique) {
                     $keyArray = array();
                     foreach ($xmlUnique->Key as $xmlKey) {
                         $keyName = $this->makeKeyName((string) $xmlKey->attributes()->column);
                         if (!$keyName) {
                             $this->throwException('Invalid key name ' . (string) $xmlKey->attributes()->column . ' in ' . $gridName);
                         }
                         $keyArray[] = $keyName;
                     }
                     if (count($keyArray) <= 0) {
                         $this->throwException('No suitable unique keys defined for grid ' . $gridName);
                     } else {
                         if (count($keyArray) == 1) {
                             // One key and only one key, which is nice
                             $uniqueKeys[$gridName][] = array_shift($keyArray);
                         } else {
                             $uniqueKeys[$gridName][] = $keyArray;
                         }
                     }
                 }
             }
             if (count($keys[$gridName]) == 0 && count($uniqueKeys[$gridName]) == 0) {
                 trigger_error('No primary or unique keys defined for grid ' . $gridName . ', object update will be impossible', E_USER_WARNING);
             }
             if (isset($gridXml->Keys->Foreign)) {
                 foreach ($gridXml->Keys->Foreign->Key as $xmlKey) {
                     $targetGrid = $this->makeKeyName((string) $xmlKey->attributes()->referenceGrid);
                     if (!$targetGrid) {
                         $this->throwException('Invalid referenceGrid ' . (string) $xmlKey->attributes()->referenceGrid . ' in foreign key under grid ' . $gridName);
                     }
                     if ($xmlKey->attributes()->referenceGridAlias) {
                         $alias = $this->makeKeyName((string) $xmlKey->attributes()->referenceGridAlias);
                         if (!isset($referenceAliases[$gridName])) {
                             $referenceAliases[$gridName] = array();
                         }
                         if (isset($referenceAliases[$gridName][$alias])) {
                             $this->throwException('Duplicate referenceGridAlias "' . $alias . '"');
                         }
                         $referenceAliases[$gridName][$alias] = $targetGrid;
                         $targetGrid .= self::VALUE_SEPARATOR . $alias;
                     }
                     $columnName = $this->makeKeyName((string) $xmlKey->attributes()->column);
                     if (!$columnName || !isset($columns[$gridName][$columnName])) {
                         $this->throwException('Invalid column reference ' . (string) $xmlKey->attributes()->column . ' in foreign key under grid ' . $gridName);
                     }
                     if (!isset($references[$gridName][$targetGrid]) || !is_array($references[$gridName][$targetGrid])) {
                         $references[$gridName][$targetGrid] = array();
                     }
                     if (isset($references[$gridName][$targetGrid][$columnName])) {
                         $this->throwException('Duplicate column reference ' . $columnName . ' in foreign key under grid ' . $gridName);
                     }
                     $targetColumnName = isset($xmlKey->attributes()->referenceColumn) ? $this->makeKeyName((string) $xmlKey->attributes()->referenceColumn) : $columnName;
                     $references[$gridName][$targetGrid][$columnName] = $targetColumnName;
                 }
             }
         }
         $this->cacheCall('new' . $gridName, '_newGrid', $gridName);
     }
     // TODO: Where/how to cache this, as identified by the resource initially fed to
     // us (in order to rapidly reload on successive iterations)?
     $this->_config = array(self::ARKEY_COLUMNS => $columns, self::ARKEY_DATATYPEMAP => $dataTypeMap, self::ARKEY_GRIDS => $grids, self::ARKEY_GRID_CLASSES => $gridClasses, self::ARKEY_GRID_COMMANDS => $gridCommands, self::ARKEY_GRID_PARAMETERS => $gridParameters, self::ARKEY_KEYS => $keys, self::ARKEY_OPTIONS => $options, self::ARKEY_REFERENCES => $references, self::ARKEY_REFERENCE_ALIASES => $referenceAliases, self::ARKEY_UNIQUEKEYS => $uniqueKeys);
     $this->setInitialized();
     // Now use those values to finalize the relationships.
     try {
         $this->initializeKeys();
     } catch (TorporException $e) {
         $this->setInitialized(false);
         throw $e;
     }
     return true;
 }
Exemplo n.º 2
0
 protected function checkCommandType(PersistenceCommand $command)
 {
     $writeCommand = false;
     $ddl = false;
     $firstWord = strtoupper(preg_replace('/^[\\s\\n]*([^\\s]+)\\s?.*$/s', '$1', $command->getCommand()));
     switch ($firstWord) {
         case 'BEGIN':
         case 'CALL':
         case 'EXECUTE':
         case 'PREPARE':
             trigger_error('Use of stored procedure prevents checking for write access/DDL; continuing at your peril...', E_USER_WARNING);
         case 'DESC':
         case 'DESCRIBE':
         case 'SELECT':
         case 'SET':
         case 'SHOW':
             break;
         case 'ALTER':
         case 'CREATE':
         case 'DROP':
         case 'RENAME':
             $ddl = true;
         case 'DELETE':
         case 'INSERT':
         case 'LOAD':
         case 'UPDATE':
         case 'REPLACE':
         case 'TRUNCATE':
             $writeCommand = true;
             break;
         default:
             $this->throwException('Unrecognized command "' . $firstWord . '" requested');
             break;
     }
     if (!$this->isWritable() && ($writeCommand || $command->getType() == PersistenceCommand::TYPE_PUBLISH)) {
         $this->throwException('Write command (' . $firstWord . ') requested on an unwritable data store');
     }
     if (!$this->getTorpor()->permitDDL() && $ddl) {
         $this->throwException('Data Defintion Language is not permitted by current settings');
     }
     return true;
 }