X-Git-Url: https://git.mxchange.org/?p=core.git;a=blobdiff_plain;f=inc%2Fclasses%2Fmain%2Fdatabase%2Fdatabases%2Fclass_LocalFileDatabase.php;h=7aa3fb359f983740957752b205021412b220bbd4;hp=9c9c00bde531870addff78e18f3611f25ea5919f;hb=ccc1db45751c976264513b8c51884e39f8214b12;hpb=70cb8ef9a893f8676290c77b0b83d53363b6914c diff --git a/inc/classes/main/database/databases/class_LocalFileDatabase.php b/inc/classes/main/database/databases/class_LocalFileDatabase.php index 9c9c00bd..7aa3fb35 100644 --- a/inc/classes/main/database/databases/class_LocalFileDatabase.php +++ b/inc/classes/main/database/databases/class_LocalFileDatabase.php @@ -2,7 +2,11 @@ /** * Database backend class for storing objects in locally created files. * - * This class serializes objects and saves them to local files. + * This class serializes arrays stored in the dataset instance and saves them + * to local files. Every file (except 'info') represents a single line. Every + * directory within the 'db' (base) directory represents a table. + * + * A configurable 'file_io_class' is being used as "storage backend". * * @author Roland Haeder * @version 0.0.0 @@ -23,15 +27,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontendInterface { - // Constants for MySQL backward-compatiblity (PLEASE FIX THEM!) - const DB_CODE_TABLE_MISSING = 0x100; - const DB_CODE_TABLE_UNWRITEABLE = 0x101; - const DB_CODE_DATA_FILE_CORRUPT = 0x102; - - // Status results - const RESULT_OKAY = 'ok'; - +class LocalFileDatabase extends BaseDatabaseBackend implements DatabaseBackendInterface { /** * The file's extension */ @@ -89,6 +85,12 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend // Set the compressor channel $databaseInstance->setCompressorChannel($compressorInstance); + // Get a file IO handler + $fileIoInstance = ObjectFactory::createObjectByConfiguredName('file_io_class'); + + // ... and set it + $databaseInstance->setFileIoInstance($fileIoInstance); + // "Connect" to the database $databaseInstance->connectToDatabase(); @@ -110,7 +112,7 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend /** * Getter for last read file * - * @return $lastFile The last read file's name with full path + * @return $lastFile The last read file's name with full path */ public final function getLastFile () { return $this->lastFile; @@ -119,7 +121,7 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend /** * Setter for contents of the last read file * - * @param $contents An array with header and data elements + * @param $contents An array with header and data elements * @return void */ private final function setLastFileContents (array $contents) { @@ -161,14 +163,14 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend * @return $dataArray */ private function getDataArrayFromFile ($fqfn) { - // Get a file pointer - $fileInstance = FrameworkFileInputPointer::createFrameworkFileInputPointer($fqfn); + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Reading elements from database file ' . $fqfn . ' ...'); - // Get the raw data and BASE64-decode it - $compressedData = base64_decode($fileInstance->readLinesFromFile()); + // Init compressed data + $compressedData = $this->getFileIoInstance()->loadFileContents($fqfn); + $compressedData = $compressedData['data']; // Close the file and throw the instance away - $fileInstance->closeFile(); unset($fileInstance); // Decompress it @@ -177,6 +179,10 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend // Unserialize it $dataArray = unserialize($serializedData); + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Read ' . count($dataArray) . ' elements from database file ' . $fqfn . '.'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataArray=' . print_r($dataArray, TRUE)); + // Finally return it return $dataArray; } @@ -190,22 +196,20 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend */ private function writeDataArrayToFqfn ($fqfn, array $dataArray) { // Debug message - /* NOISY-DEBUG: */ $this->debugOutput('DATABASE: Flushing ' . count($dataArray) . ' elements to database file ' . $fqfn . ' ...'); - - // Get a file pointer instance - $fileInstance = FrameworkFileOutputPointer::createFrameworkFileOutputPointer($fqfn, 'w'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Flushing ' . count($dataArray) . ' elements to database file ' . $fqfn . ' ...'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataArray=' . print_r($dataArray, TRUE)); // Serialize and compress it $compressedData = $this->getCompressorChannel()->getCompressor()->compressStream(serialize($dataArray)); - // Write this data BASE64 encoded to the file - $fileInstance->writeToFile(base64_encode($compressedData)); + // Write data + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Writing ' . strlen($compressedData) . ' bytes ...'); - // Close the file pointer - $fileInstance->closeFile(); + // Write this data BASE64 encoded to the file + $this->getFileIoInstance()->saveFile($fqfn, $compressedData); // Debug message - /* NOISY-DEBUG: */ $this->debugOutput('DATABASE: Flushing ' . count($dataArray) . ' elements to database file completed.'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Flushing ' . count($dataArray) . ' elements to database file completed.'); } /** @@ -304,13 +308,13 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend * Starts a SELECT query on the database by given return type, table name * and search criteria * - * @param $tableName Name of the database table - * @param $criteria Local search criteria class - * @return $resultData Result data of the query + * @param $tableName Name of the database table + * @param $searchInstance Local search criteria class + * @return $resultData Result data of the query * @throws UnsupportedCriteriaException If the criteria is unsupported * @throws SqlException If an 'SQL error' occurs */ - public function querySelect ($tableName, LocalSearchCriteria $criteriaInstance) { + public function querySelect ($tableName, LocalSearchCriteria $searchInstance) { // The result is null by any errors $resultData = NULL; @@ -325,8 +329,8 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend // Initialize the result data, this need to be rewritten e.g. if a local file cannot be read $resultData = array( - BaseDatabaseFrontend::RESULT_INDEX_STATUS => LocalfileDatabase::RESULT_OKAY, - BaseDatabaseFrontend::RESULT_INDEX_ROWS => array() + BaseDatabaseBackend::RESULT_INDEX_STATUS => self::RESULT_OKAY, + BaseDatabaseBackend::RESULT_INDEX_ROWS => array() ); // Initialize limit/skip @@ -335,7 +339,7 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend $idx = 1; // Read the directory with some exceptions - while (($dataFile = $directoryInstance->readDirectoryExcept(array('.', '..', '.htaccess', '.svn', 'info.' . $this->getFileExtension()))) && (($limitFound < $criteriaInstance->getLimit()) || ($criteriaInstance->getLimit() == 0))) { + while (($dataFile = $directoryInstance->readDirectoryExcept(array('.', '..', '.htaccess', '.svn', 'info.' . $this->getFileExtension()))) && (($limitFound < $searchInstance->getLimit()) || ($searchInstance->getLimit() == 0))) { // Does the extension match? if (substr($dataFile, -(strlen($this->getFileExtension()))) !== $this->getFileExtension()) { // Skip this file! @@ -344,39 +348,46 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend // Read the file $dataArray = $this->getDataArrayFromFile($pathName . $dataFile); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',dataArray='.print_r($dataArray, TRUE)); // Is this an array? if (is_array($dataArray)) { + // Default is nothing found + $isFound = TRUE; + // Search in the criteria with FMFW (First Matches, First Wins) foreach ($dataArray as $key => $value) { - // Get criteria element - $criteria = $criteriaInstance->getCriteriaElemnent($key); - - // Is the criteria met? - //* NOISY-DEBUG: */ $this->debugOutput('DATABASE: criteria[' . gettype($criteria) . ']=' . $criteria . ',()=' . strlen($criteria) . ',value=' . $value . ',()=' . strlen($value)); - if ((!is_null($criteria)) && ($criteria == $value)) { - // Shall we skip this entry? - if ($criteriaInstance->getSkip() > 0) { - // We shall skip some entries - if ($skipFound < $criteriaInstance->getSkip()) { - // Skip this entry - $skipFound++; - break; - } // END - if + // Make sure value is not bool + assert(!is_bool($value)); + + // Found one entry? + $isFound = (($isFound === TRUE) && ($searchInstance->isCriteriaMatching($key, $value))); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: key=' . $key . ',value=' . $value . ',isFound=' . intval($isFound)); + } // END - foreach + + // Is all found? + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: isFound=' . intval($isFound) . ',limitFound=' . $limitFound . ',limit=' . $searchInstance->getLimit()); + if ($isFound === TRUE) { + // Shall we skip this entry? + if ($searchInstance->getSkip() > 0) { + // We shall skip some entries + if ($skipFound < $searchInstance->getSkip()) { + // Skip this entry + $skipFound++; + break; } // END - if + } // END - if - // Set id number - $dataArray[$this->getIndexKey()] = $idx; + // Set id number + $dataArray[$this->getIndexKey()] = $idx; - // Entry found! - //* NOISY-DEBUG: */ $this->debugOutput('DATABASE: indexKey=' . $this->getIndexKey() . ',idx=' . $idx . ',dataArray=' . print_r($dataArray, true)); - $resultData[BaseDatabaseFrontend::RESULT_INDEX_ROWS][] = $dataArray; + // Entry found! + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: indexKey=' . $this->getIndexKey() . ',idx=' . $idx . ',dataArray=' . print_r($dataArray, TRUE)); + $resultData[BaseDatabaseBackend::RESULT_INDEX_ROWS][] = $dataArray; - // Count found entries up - $limitFound++; - break; - } // END - if - } // END - foreach + // Count found entries up + $limitFound++; + } // END - if } else { // Throw an exception here throw new SqlException(array($this, sprintf("File '%s' contains invalid data.", $dataFile), self::DB_CODE_DATA_FILE_CORRUPT), self::EXCEPTION_SQL_QUERY); @@ -415,11 +426,11 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend * @throws SqlException If an SQL error occurs */ public function queryInsertDataSet (StoreableCriteria $dataSetInstance) { - // Create full path name - $fqfn = $this->generateFqfnFromDataSet($dataSetInstance, md5($dataSetInstance->getUniqueValue())); - // Try to save the request away try { + // Create full path name + $fqfn = $this->generateFqfnFromDataSet($dataSetInstance, md5($dataSetInstance->getUniqueValue())); + // Write the data away $this->writeDataArrayToFqfn($fqfn, $dataSetInstance->getCriteriaArray()); @@ -458,54 +469,67 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend $skipFound = 0; // Get the criteria array from the dataset - $criteriaArray = $dataSetInstance->getCriteriaArray(); + $searchArray = $dataSetInstance->getCriteriaArray(); // Get search criteria $searchInstance = $dataSetInstance->getSearchInstance(); // Read the directory with some exceptions - while (($dataFile = $directoryInstance->readDirectoryExcept(array('.', '..', '.htaccess', '.svn', 'info.' . $this->getFileExtension()))) && ($limitFound < $searchInstance->getLimit())) { + while (($dataFile = $directoryInstance->readDirectoryExcept(array('.', '..', '.htaccess', '.svn', 'info.' . $this->getFileExtension()))) && (($limitFound < $searchInstance->getLimit()) || ($searchInstance->getLimit() == 0))) { // Does the extension match? if (substr($dataFile, -(strlen($this->getFileExtension()))) !== $this->getFileExtension()) { + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',getFileExtension()=' . $this->getFileExtension() . ' - SKIPPED!'); // Skip this file! continue; } // END - if // Open this file for reading $dataArray = $this->getDataArrayFromFile($pathName . $dataFile); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',dataArray='.print_r($dataArray, TRUE)); // Is this an array? if (is_array($dataArray)) { + // Default is nothing found + $isFound = TRUE; + // Search in the criteria with FMFW (First Matches, First Wins) foreach ($dataArray as $key => $value) { - // Get criteria element - $criteria = $searchInstance->getCriteriaElemnent($key); - - // Is the criteria met? - if ((!is_null($criteria)) && ($criteria == $value)) { - // Shall we skip this entry? - if ($searchInstance->getSkip() > 0) { - // We shall skip some entries - if ($skipFound < $searchInstance->getSkip()) { - // Skip this entry - $skipFound++; - break; - } // END - if + // Make sure value is not bool + assert(!is_bool($value)); + + // Found one entry? + $isFound = (($isFound === TRUE) && ($searchInstance->isCriteriaMatching($key, $value))); + } // END - foreach + + // Is all found? + if ($isFound === TRUE) { + // Shall we skip this entry? + if ($searchInstance->getSkip() > 0) { + // We shall skip some entries + if ($skipFound < $searchInstance->getSkip()) { + // Skip this entry + $skipFound++; + break; } // END - if + } // END - if - // Entry found, so update it - foreach ($criteriaArray as $criteriaKey => $criteriaValue) { - $dataArray[$criteriaKey] = $criteriaValue; - } // END - foreach + // Entry found, so update it + foreach ($searchArray as $searchKey => $searchValue) { + // Make sure the value is not bool again + assert(!is_bool($searchValue)); - // Write the data to a local file - $this->writeDataArrayToFqfn($pathName . $dataFile, $dataArray); + // Debug message + add/update it + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: criteriaKey=' . $searchKey . ',criteriaValue=' . $searchValue); + $dataArray[$searchKey] = $searchValue; + } // END - foreach - // Count it - $limitFound++; - break; - } // END - if - } // END - foreach + // Write the data to a local file + $this->writeDataArrayToFqfn($pathName . $dataFile, $dataArray); + + // Count found entries up + $limitFound++; + } // END - if } // END - if } // END - while