Exemple #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;
 }
 public function parseCommand(PersistenceCommand $command, Grid $grid, $final = true)
 {
     $commandText = $command->getCommand();
     $placeholder = $command->getPlaceholder();
     if (empty($commandText)) {
         $this->throwException('Invalid command text (empty)');
     }
     $parameters =& $command->getParameters();
     foreach ($parameters as $index => $parameter) {
         $parameterPlaceholder = null;
         if (strpos($parameter, Torpor::VALUE_SEPARATOR)) {
             // WARNING: Magic Number, splitting into at most 2 members, which allows for the possible
             // existence of VALUE_SEPARATOR in the remaining code (which we won't falsely detect, because
             // if there's a placeholder at all regardless of whether VALUE_SEPARATOR exists in it, we've
             // used that same value as a glue betwixt us and it, so this detection and split routine is
             // redundancy safe).
             list($parameter, $parameterPlaceholder) = explode(Torpor::VALUE_SEPARATOR, $parameter, 2);
         }
         if (!$grid->hasColumn($parameter)) {
             if (!$final) {
                 continue;
             }
             $this->throwException('Unknown parameter "' . $parameter . '" (no matching column on ' . $grid->_getObjName() . ' grid)');
         }
         if (!empty($parameterPlaceholder)) {
             if (strpos($commandText, $parameterPlaceholder) === false) {
                 $this->throwException('Named placeholder "' . $parameterPlaceholder . '" not found in ' . $grid->_getObjName() . ' grid command: ' . $commandText);
             }
             // Replace all instances.
             $commandText = str_replace($parameterPlaceholder, $this->autoQuoteColumn($grid->Column($parameter)), $commandText);
             if (!$final) {
                 unset($parameters[$index]);
             }
         } else {
             if (!empty($placeholder)) {
                 if (strpos($commandText, $placeholder) === false) {
                     $this->throwException('Placeholder "' . $placeholder . '" not found in ' . $grid->_getObjName() . ' grid command: ' . $commandText);
                 }
                 // Replace only a single instance.
                 $commandText = substr_replace($commandText, $this->autoQuoteColumn($grid->Column($parameter)), strpos($commandText, $placeholder), strlen($placeholder));
                 if (!$final) {
                     unset($parameters[$index]);
                 }
             } else {
                 $this->throwException('Empty bind variable, cannot parse ' . $parameter . ' into ' . $grid->_getObjName() . ' grid command: ' . $commandText);
             }
         }
     }
     if ($final && !empty($placeholder) && strpos($commandText, $placeholder) !== false) {
         $this->throwException('Un-parsed placeholders found in ' . $grid->_getObjName() . ' grid command: ' . $commandText);
     }
     return $commandText;
 }