class_LocalFileDatabase.php

Go to the documentation of this file.
00001 <?php
00026 class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontendInterface {
00027 
00028         // Constants for MySQL backward-compatiblity (PLEASE FIX THEM!)
00029         const DB_CODE_TABLE_MISSING     = 0x100;
00030         const DB_CODE_TABLE_UNWRITEABLE = 0x101;
00031         const DB_CODE_DATA_FILE_CORRUPT = 0x102;
00032 
00036         private $savePath = "";
00037 
00041         private $fileExtension = "serialized";
00042 
00046         private $lastFile = "";
00047 
00051         private $lastContents = array();
00052 
00056         private $alreadyConnected = false;
00057 
00061         private $lastError = "";
00062 
00066         private $lastException = null;
00067 
00071         private $tableInfo = array();
00072 
00076         private $indexKey = "__idx";
00077 
00084         protected function __construct() {
00085                 // Call parent constructor
00086                 parent::__construct(__CLASS__);
00087 
00088                 // Clean up a little
00089                 $this->removeNumberFormaters();
00090                 $this->removeSystemArray();
00091         }
00092 
00102         public final static function createLocalFileDatabase ($savePath, FileIoHandler $ioInstance) {
00103                 // Get an instance
00104                 $dbInstance = new LocalFileDatabase();
00105 
00106                 // Set save path and IO instance
00107                 $dbInstance->setSavePath($savePath);
00108                 $dbInstance->setFileIoInstance($ioInstance);
00109 
00110                 // "Connect" to the database
00111                 $dbInstance->connectToDatabase();
00112 
00113                 // Return database instance
00114                 return $dbInstance;
00115         }
00116 
00123         public final function setSavePath ($savePath) {
00124                 // Secure string
00125                 $savePath = (string) $savePath;
00126 
00127                 // Set save path
00128                 $this->savePath = $savePath;
00129         }
00130 
00136         public final function getSavePath () {
00137                 return $this->savePath;
00138         }
00139 
00145         public final function getLastError () {
00146                 return $this->lastError;
00147         }
00148 
00154         public final function getLastException () {
00155                 return $this->lastException;
00156         }
00157 
00164         private final function setLastFile ($fqfn) {
00165                 // Cast string and set it
00166                 $this->lastFile = (string) $fqfn;
00167         }
00168 
00175         private final function resetLastError () {
00176                 $this->lastError = "";
00177                 $this->lastException = null;
00178         }
00179 
00185         public final function getLastFile () {
00186                 return $this->lastFile;
00187         }
00188 
00195         private final function setLastFileContents (array $contents) {
00196                 // Set array
00197                 $this->lastContents = $contents;
00198         }
00199 
00205         public final function getLastContents () {
00206                 return $this->lastContents;
00207         }
00208 
00214         public final function getFileExtension () {
00215                 return $this->fileExtension;
00216         }
00217 
00223         public final function getIndexKey () {
00224                 return $this->indexKey;
00225         }
00226 
00233         private function getDataArrayFromFile ($fqfn) {
00234                 // Get a file pointer
00235                 $fileInstance = FrameworkFileInputPointer::createFrameworkFileInputPointer($fqfn);
00236 
00237                 // Get the raw data and BASE64-decode it
00238                 $compressedData = base64_decode($fileInstance->readLinesFromFile());
00239 
00240                 // Close the file and throw the instance away
00241                 $fileInstance->closeFile();
00242                 unset($fileInstance);
00243 
00244                 // Decompress it
00245                 $serializedData = $this->getCompressorChannel()->getCompressor()->decompressStream($compressedData);
00246 
00247                 // Unserialize it
00248                 $dataArray = unserialize($serializedData);
00249 
00250                 // Finally return it
00251                 return $dataArray;
00252         }
00253 
00261         private function writeDataArrayToFqfn ($fqfn, array $dataArray) {
00262                 // Get a file pointer instance
00263                 $fileInstance = FrameworkFileOutputPointer::createFrameworkFileOutputPointer($fqfn, 'w');
00264 
00265                 // Serialize and compress it
00266                 $compressedData = $this->getCompressorChannel()->getCompressor()->compressStream(serialize($dataArray));
00267 
00268                 // Write this data BASE64 encoded to the file
00269                 $fileInstance->writeToFile(base64_encode($compressedData));
00270 
00271                 // Close the file pointer
00272                 $fileInstance->closeFile();
00273         }
00274 
00281         private function getContentsFromTableInfoFile (StoreableCriteria $dataSetInstance) {
00282                 // Default content is no data
00283                 $infoArray = array();
00284 
00285                 // Create FQFN for getting the table information file
00286                 $fqfn = $this->getSavePath() . $dataSetInstance->getTableName() . '/info.' . $this->getFileExtension();
00287 
00288                 // Get the file contents
00289                 try {
00290                         $infoArray = $this->getDataArrayFromFile($fqfn);
00291                 } catch (FileNotFoundException $e) {
00292                         // Not found, so ignore it here
00293                 }
00294 
00295                 // ... and return it
00296                 return $infoArray;
00297         }
00298 
00305         private function createTableInfoFile (StoreableCriteria $dataSetInstance) {
00306                 // Create FQFN for creating the table information file
00307                 $fqfn = $this->getSavePath() . $dataSetInstance->getTableName() . '/info.' . $this->getFileExtension();
00308 
00309                 // Get the data out from dataset in a local array
00310                 $this->tableInfo[$dataSetInstance->getTableName()] = array(
00311                         'primary'      => $dataSetInstance->getPrimaryKey(),
00312                         'created'      => time(),
00313                         'last_updated' => time()
00314                 );
00315 
00316                 // Write the data to the file
00317                 $this->writeDataArrayToFqfn($fqfn, $this->tableInfo[$dataSetInstance->getTableName()]);
00318         }
00319 
00326         private function updatePrimaryKey (StoreableCriteria $dataSetInstance) {
00327                 // Get the information array from lower method
00328                 $infoArray = $this->getContentsFromTableInfoFile($dataSetInstance);
00329 
00330                 // Is the primary key there?
00331                 if (!isset($this->tableInfo['primary'])) {
00332                         // Then create the info file
00333                         $this->createTableInfoFile($dataSetInstance);
00334                 } elseif (($this->getConfigInstance()->readConfig('db_update_primary_forced') === "Y") && ($dataSetInstance->getPrimaryKey() != $this->tableInfo['primary'])) {
00335                         // Set the array element
00336                         $this->tableInfo[$dataSetInstance->getTableName()]['primary'] = $dataSetInstance->getPrimaryKey();
00337 
00338                         // Update the entry
00339                         $this->updateTableInfoFile($dataSetInstance);
00340                 }
00341         }
00342 
00349         public function connectToDatabase () {
00350         }
00351 
00363         public function querySelect ($resultType, $tableName, LocalSearchCriteria $criteriaInstance) {
00364                 // The result is null by any errors
00365                 $resultData = null;
00366 
00367                 // Create full path name
00368                 $pathName = $this->getSavePath() . $tableName . '/';
00369 
00370                 // A "select" query is not that easy on local files, so first try to
00371                 // find the "table" which is in fact a directory on the server
00372                 try {
00373                         // Get a directory pointer instance
00374                         $directoryInstance = FrameworkDirectoryPointer::createFrameworkDirectoryPointer($pathName);
00375 
00376                         // Initialize the result data, this need to be rewritten e.g. if a local file cannot be read
00377                         $resultData = array(
00378                                 'status'        => "ok",
00379                                 'rows'          => array()
00380                         );
00381 
00382                         // Initialize limit/skip
00383                         $limitFound = 0;
00384                         $skipFound = 0;
00385                         $idx = 1;
00386 
00387                         // Read the directory with some exceptions
00388                         while (($dataFile = $directoryInstance->readDirectoryExcept(array(".", "..", ".htaccess", ".svn", "info." . $this->getFileExtension()))) && ($limitFound < $criteriaInstance->getLimit())) {
00389                                 // Does the extension match?
00390                                 if (substr($dataFile, -(strlen($this->getFileExtension()))) !== $this->getFileExtension()) {
00391                                         // Skip this file!
00392                                         continue;
00393                                 } // END - if
00394 
00395                                 // Read the file
00396                                 $dataArray = $this->getDataArrayFromFile($pathName . $dataFile);
00397 
00398                                 // Is this an array?
00399                                 if (is_array($dataArray)) {
00400                                         // Search in the criteria with FMFW (First Matches, First Wins)
00401                                         foreach ($dataArray as $key => $value) {
00402                                                 // Get criteria element
00403                                                 $criteria = $criteriaInstance->getCriteriaElemnent($key);
00404 
00405                                                 // Is the criteria met?
00406                                                 if ((!is_null($criteria)) && ($criteria == $value))  {
00407 
00408                                                         // Shall we skip this entry?
00409                                                         if ($criteriaInstance->getSkip() > 0) {
00410                                                                 // We shall skip some entries
00411                                                                 if ($skipFound < $criteriaInstance->getSkip()) {
00412                                                                         // Skip this entry
00413                                                                         $skipFound++;
00414                                                                         break;
00415                                                                 } // END - if
00416                                                         } // END - if
00417 
00418                                                         // Set id number
00419                                                         $dataArray[$this->getIndexKey()] = $idx;
00420 
00421                                                         // Entry found!
00422                                                         $resultData['rows'][] = $dataArray;
00423 
00424                                                         // Count found entries up
00425                                                         $limitFound++;
00426                                                         break;
00427                                                 } // END - if
00428                                         } // END - foreach
00429                                 } else {
00430                                         // Throw an exception here
00431                                         throw new SqlException(array($this, sprintf("File &#39;%s&#39; contains invalid data.", $dataFile), self::DB_CODE_DATA_FILE_CORRUPT), self::EXCEPTION_SQL_QUERY);
00432                                 }
00433 
00434                                 // Count entry up
00435                                 $idx++;
00436                         } // END - while
00437 
00438                         // Close directory and throw the instance away
00439                         $directoryInstance->closeDirectory();
00440                         unset($directoryInstance);
00441 
00442                         // Reset last error message and exception
00443                         $this->resetLastError();
00444                 } catch (PathIsNoDirectoryException $e) {
00445                         // Path not found means "table not found" for real databases...
00446                         $this->lastException = $e;
00447                         $this->lastError = $e->getMessage();
00448 
00449                         // So throw an SqlException here with faked error message
00450                         throw new SqlException (array($this, sprintf("Table &#39;%s&#39; not found", $tableName), self::DB_CODE_TABLE_MISSING), self::EXCEPTION_SQL_QUERY);
00451                 } catch (FrameworkException $e) {
00452                         // Catch all exceptions and store them in last error
00453                         $this->lastException = $e;
00454                         $this->lastError = $e->getMessage();
00455                 }
00456 
00457                 // Return the gathered result
00458                 return $resultData;
00459         }
00460 
00468         public function queryInsertDataSet (StoreableCriteria $dataSetInstance) {
00469                 // Create full path name
00470                 $fqfn = sprintf("%s%s/%s.%s",
00471                         $this->getSavePath(),
00472                         $dataSetInstance->getTableName(),
00473                         md5($dataSetInstance->getUniqueValue()),
00474                         $this->getFileExtension()
00475                 );
00476 
00477                 // Try to save the request away
00478                 try {
00479                         // Write the data away
00480                         $this->writeDataArrayToFqfn($fqfn, $dataSetInstance->getCriteriaArray());
00481 
00482                         // Update the primary key
00483                         $this->updatePrimaryKey($dataSetInstance);
00484 
00485                         // Reset last error message and exception
00486                         $this->resetLastError();
00487                 } catch (FrameworkException $e) {
00488                         // Catch all exceptions and store them in last error
00489                         $this->lastException = $e;
00490                         $this->lastError = $e->getMessage();
00491 
00492                         // Throw an SQL exception
00493                         throw new SqlException (array($this, sprintf("Cannot write data to table &#39;%s&#39;", $tableName), self::DB_CODE_TABLE_UNWRITEABLE), self::EXCEPTION_SQL_QUERY);
00494                 }
00495         }
00496 
00504         public function queryUpdateDataSet (StoreableCriteria $dataSetInstance) {
00505                 // Create full path name
00506                 $pathName = $this->getSavePath() . $dataSetInstance->getTableName() . '/';
00507 
00508                 // Try all the requests
00509                 try {
00510                         // Get a file pointer instance
00511                         $directoryInstance = FrameworkDirectoryPointer::createFrameworkDirectoryPointer($pathName);
00512 
00513                         // Initialize limit/skip
00514                         $limitFound = 0;
00515                         $skipFound = 0;
00516 
00517                         // Get the criteria array from the dataset
00518                         $criteriaArray = $dataSetInstance->getCriteriaArray();
00519 
00520                         // Get search criteria
00521                         $searchInstance = $dataSetInstance->getSearchInstance();
00522 
00523                         // Read the directory with some exceptions
00524                         while (($dataFile = $directoryInstance->readDirectoryExcept(array(".", "..", ".htaccess", ".svn", "info." . $this->getFileExtension()))) && ($limitFound < $searchInstance->getLimit())) {
00525                                 // Does the extension match?
00526                                 if (substr($dataFile, -(strlen($this->getFileExtension()))) !== $this->getFileExtension()) {
00527                                         // Skip this file!
00528                                         continue;
00529                                 }
00530 
00531                                 // Open this file for reading
00532                                 $dataArray = $this->getDataArrayFromFile($pathName . $dataFile);
00533 
00534                                 // Is this an array?
00535                                 if (is_array($dataArray)) {
00536                                         // Search in the criteria with FMFW (First Matches, First Wins)
00537                                         foreach ($dataArray as $key => $value) {
00538                                                 // Get criteria element
00539                                                 $criteria = $searchInstance->getCriteriaElemnent($key);
00540 
00541                                                 // Is the criteria met?
00542                                                 if ((!is_null($criteria)) && ($criteria == $value))  {
00543 
00544                                                         // Shall we skip this entry?
00545                                                         if ($searchInstance->getSkip() > 0) {
00546                                                                 // We shall skip some entries
00547                                                                 if ($skipFound < $searchInstance->getSkip()) {
00548                                                                         // Skip this entry
00549                                                                         $skipFound++;
00550                                                                         break;
00551                                                                 } // END - if
00552                                                         } // END - if
00553 
00554                                                         // Entry found, so update it
00555                                                         foreach ($criteriaArray as $criteriaKey => $criteriaValue) {
00556                                                                 $dataArray[$criteriaKey] = $criteriaValue;
00557                                                         } // END - foreach
00558 
00559                                                         // Write the data to a local file
00560                                                         $this->writeDataArrayToFqfn($pathName . $dataFile, $dataArray);
00561 
00562                                                         // Count it
00563                                                         $limitFound++;
00564                                                         break;
00565                                                 } // END - if
00566                                         } // END - foreach
00567                                 } // END - if
00568                         } // END - while
00569 
00570                         // Close the file pointer
00571                         $directoryInstance->closeDirectory();
00572 
00573                         // Update the primary key
00574                         $this->updatePrimaryKey($dataSetInstance);
00575 
00576                         // Reset last error message and exception
00577                         $this->resetLastError();
00578                 } catch (FrameworkException $e) {
00579                         // Catch all exceptions and store them in last error
00580                         $this->lastException = $e;
00581                         $this->lastError = $e->getMessage();
00582 
00583                         // Throw an SQL exception
00584                         throw new SqlException (array($this, sprintf("Cannot write data to table &#39;%s&#39;", $dataSetInstance->getTableName()), self::DB_CODE_TABLE_UNWRITEABLE), self::EXCEPTION_SQL_QUERY);
00585                 }
00586         }
00587 
00595         public function getPrimaryKeyOfTable ($tableName) {
00596                 // Default key is null
00597                 $primaryKey = null;
00598 
00599                 // Does the table information exist?
00600                 if (isset($this->tableInfo[$tableName])) {
00601                         // Then return the primary key
00602                         $primaryKey = $this->tableInfo[$tableName]['primary'];
00603                 } // END - if
00604 
00605                 // Return the column
00606                 return $primaryKey;
00607         }
00608 }
00609 
00610 // [EOF]
00611 ?>

Generated on Mon Dec 8 01:06:45 2008 for Ship-Simulator by  doxygen 1.5.6