]> git.mxchange.org Git - hub.git/blobdiff - inc/classes/main/database/databases/class_LocalFileDatabase.php
Code base merged from ship-simu repos
[hub.git] / inc / classes / main / database / databases / class_LocalFileDatabase.php
index 16314e1164e3557e7cd55f68bad8657b87340aea..151698c7f28b9410837921a480688c516dc4cf62 100644 (file)
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontendInterface {
+
+       // Constants for MySQL backward-compatiblity (PLEASE FIX THEM!)
+       const DB_CODE_TABLE_MISSING     = 0x000;
+       const DB_CODE_TABLE_UNWRITEABLE = 0x001;
+
        /**
         * Save path for "file database"
         */
@@ -50,8 +55,18 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
        private $alreadyConnected = false;
 
        /**
-        * The private constructor. Do never instance from outside!
-        * You need to set a local file path. The class will then validate it.
+        * Last error message
+        */
+       private $lastError = "";
+
+       /**
+        * Last exception
+        */
+       private $lastException = null;
+
+       /**
+        * The protected constructor. Do never instance from outside! You need to
+        * set a local file path. The class will then validate it.
         *
         * @return      void
         */
@@ -63,7 +78,7 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
                $this->setObjectDescription("Class for local file databases");
 
                // Create unique ID
-               $this->createUniqueID();
+               $this->generateUniqueId();
 
                // Clean up a little
                $this->removeSystemArray();
@@ -116,29 +131,32 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
                return $this->savePath;
        }
 
+       /**
+        * Getter for last error message
+        *
+        * @return      $lastError      Last error message
+        */
+       public final function getLastError () {
+               return $this->lastError;
+       }
+
+       /**
+        * Getter for last exception
+        *
+        * @return      $lastException  Last thrown exception
+        */
+       public final function getLastException () {
+               return $this->lastException;
+       }
+
        /**
         * Saves a given object to the local file system by serializing and
         * transparently compressing it
         *
-        * @param               $object                         The object we shall save to the local file system
+        * @param       $object                                 The object we shall save to the local file system
         * @return      void
-        * @throws      NullPointerException    If the object instance is null
-        * @throws      NoObjectException               If the parameter $object is not
-        *                                                              an object
         */
-       public final function saveObject ($object) {
-               // Some tests on the parameter...
-               if (is_null($object)) {
-                       // Is null, throw exception
-                       throw new NullPointerException($object, self::EXCEPTION_IS_NULL_POINTER);
-               } elseif (!is_object($object)) {
-                       // Is not an object, throw exception
-                       throw new NoObjectException($object, self::EXCEPTION_IS_NO_OBJECT);
-               } elseif (!method_exists($object, '__toString')) {
-                       // A highly required method was not found... :-(
-                       throw new MissingMethodException(array($object, '__toString'), self::EXCEPTION_MISSING_METHOD);
-               }
-
+       public final function saveObject (FrameworkInterface $object) {
                // Get a string containing the serialized object. We cannot exchange
                // $this and $object here because $object does not need to worry
                // about it's limitations... ;-)
@@ -155,14 +173,14 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
        /**
         * Get a serialized string from the given object
         *
-        * @param               $object         The object we want to serialize and transparently
-        *                                              compress
-        * @return      $serialized     A string containing the serialzed/compressed object
+        * @param       $object                 The object we want to serialize and transparently
+        *                                                      compress
+        * @return      $serialized             A string containing the serialzed/compressed object
         * @see         ObjectLimits    An object holding limition information
         * @see         SerializationContainer  A special container class for e.g.
-        *                                                              attributes from limited objects
+        *                                                                      attributes from limited objects
         */
-       private function serializeObject ($object) {
+       private function serializeObject (FrameworkInterface $object) {
                // If there is no limiter instance we serialize the whole object
                // otherwise only in the limiter object (ObjectLimits) specified
                // attributes summarized in a special container class
@@ -187,13 +205,13 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
         * Analyses if a unique ID has already been used or not by search in the
         * local database folder.
         *
-        * @param               $uniqueID               A unique ID number which shall be checked
-        *                                              before it will be used
-        * @param               $inConstructor  If we got called in a de/con-structor or
-        *                                              from somewhere else
+        * @param       $uniqueID               A unique ID number which shall be checked
+        *                                                      before it will be used
+        * @param       $inConstructor  If we got called in a de/con-structor or
+        *                                                      from somewhere else
         * @return      $isUnused               true    = The unique ID was not found in the database,
-        *                                              false = It is already in use by an other object
-        * @throws      NoArrayCreatedException If explode() fails to create an array
+        *                                                      false = It is already in use by an other object
+        * @throws      NoArrayCreatedException         If explode() fails to create an array
         * @throws      InvalidArrayCountException      If the array contains less or
         *                                                                      more than two elements
         */
@@ -243,7 +261,7 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
 
                // Initialize the search loop
                $isValid = false;
-               while ($dataFile = $dirInstance->readDirectoryExcept(array(".", ".."))) {
+               while ($dataFile = $dirInstance->readDirectoryExcept(array(".", "..", ".htaccess", ".svn"))) {
                        // Generate FQFN for testing
                        $fqfn = sprintf("%s/%s", $pathName, $dataFile);
                        $this->setLastFile($fqfn);
@@ -284,6 +302,17 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
                $this->lastFile = $fqfn;
        }
 
+       /**
+        * Reset the last error and exception instance. This should be done after
+        * a successfull "query"
+        *
+        * @return      void
+        */
+       private final function resetLastError () {
+               $this->lastError = "";
+               $this->lastException = null;
+       }
+
        /**
         * Getter for last read file
         *
@@ -504,16 +533,149 @@ class LocalFileDatabase extends BaseDatabaseFrontend implements DatabaseFrontend
         * @param       $criteria               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 ($resultType, $tableName, Criteria $criteriaInstance) {
+               // The result is null by any errors
+               $resultData = null;
+
                // Is this criteria supported?
-               if (!$criteriaInstance instanceof LocalCriteria) {
+               if (!$criteriaInstance instanceof LocalSearchCriteria) {
                        // Not supported by this database layer
                        throw new UnsupportedCriteriaException(array($this, $criteriaInstance), self::EXCEPTION_REQUIRED_INTERFACE_MISSING);
                }
 
-               // A "select" query on local files is not that easy, so begin slowly with it...
-               $this->partialStub(sprintf("type=%s,table=%s,criteria=%s", $resultType, $tableName, $criteriaInstance));
+               // Create full path name
+               $pathName = $this->getSavePath() . $tableName . '/';
+
+               // A "select" query is not that easy on local files, so first try to
+               // find the "table" which is in fact a directory on the server
+               try {
+                       // Get a directory pointer instance
+                       $directoryInstance = FrameworkDirectoryPointer::createFrameworkDirectoryPointer($pathName);
+
+                       // Initialize the result data, this need to be rewritten e.g. if a local file cannot be read
+                       $resultData = array(
+                               'status'        => "ok",
+                               'rows'          => array()
+                       );
+
+                       // Initialize limit/skip
+                       $limitFound = 0; $skipFound = 0;
+
+                       // Read the directory with some exceptions
+                       while (($dataFile = $directoryInstance->readDirectoryExcept(array(".", "..", ".htaccess", ".svn"))) && ($limitFound < $criteriaInstance->getLimit())) {
+                               // Open this file for reading
+                               $filePointer = FrameworkFileInputPointer::createFrameworkFileInputPointer($pathName . $dataFile);
+
+                               // Get the raw data and BASE64-decode it
+                               $compressedData = base64_decode($filePointer->readLinesFromFile());
+
+                               // Close the file and throw the instance away
+                               $filePointer->closeFile();
+                               unset($filePointer);
+
+                               // Decompress it
+                               $serializedData = $this->getCompressorChannel()->getCompressor()->decompressStream($compressedData);
+
+                               // Unserialize it
+                               $dataArray = unserialize($serializedData);
+
+                               // Is this an array?
+                               if (is_array($dataArray)) {
+                                       // 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?
+                                               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
+                                                       } // END - if
+
+                                                       // Entry found!
+                                                       $resultData['rows'][]    = $dataArray;
+                                                       $limitFound++;
+                                                       break;
+                                               } // END - if
+                                       } // END - foreach
+                               } // END - if
+                       } // END - while
+
+                       // Close directory and throw the instance away
+                       $directoryInstance->closeDirectory();
+                       unset($directoryInstance);
+
+                       // Reset last error message and exception
+                       $this->resetLastError();
+               } catch (PathIsNoDirectoryException $e) {
+                       // Path not found means "table not found" for real databases...
+                       $this->lastException = $e;
+                       $this->lastError = $e->getMessage();
+
+                       // So throw an SqlException here with faked error message
+                       throw new SqlException (array($this, sprintf("Table &#39;%s&#39; not found", $tableName), self::DB_CODE_TABLE_MISSING), self::EXCEPTION_SQL_QUERY);
+               } catch (FrameworkException $e) {
+                       // Catch all exceptions and store them in last error
+                       $this->lastException = $e;
+                       $this->lastError = $e->getMessage();
+               }
+
+               // Return the gathered result
+               return $resultData;
+       }
+
+       /**
+        * "Inserts" a data set instance into a local file database folder
+        *
+        * @param       $dataSetInstance        A storeable data set
+        * @return      void
+        * @throws      SqlException    If an SQL error occurs
+        */
+       public function insertDataSet (StoreableCriteria $dataSetInstance) {
+               // Create full path name
+               $fqfn = sprintf("%s%s/%s.%s",
+                       $this->getSavePath(),
+                       $dataSetInstance->getTableName(),
+                       md5($dataSetInstance->getUniqueValue()),
+                       $this->getFileExtension()
+               );
+
+               // Try to save the request away
+               try {
+                       // Get a file pointer instance
+                       $filePointer = FrameworkFileOutputPointer::createFrameworkFileOutputPointer($fqfn, 'w');
+
+                       // Get the criteria array from the dataset
+                       $criteriaArray = $dataSetInstance->getCriteriaArray();
+
+                       // Serialize and compress it
+                       $compressedData = $this->getCompressorChannel()->getCompressor()->compressStream(serialize($criteriaArray));
+
+                       // Write this data BASE64 encoded to the file
+                       $filePointer->writeToFile(base64_encode($compressedData));
+
+                       // Close the file pointer
+                       $filePointer->closeFile();
+
+                       // Reset last error message and exception
+                       $this->resetLastError();
+               } catch (FrameworkException $e) {
+                       // Catch all exceptions and store them in last error
+                       $this->lastException = $e;
+                       $this->lastError = $e->getMessage();
+
+                       // Throw an SQL exception
+                       throw new SqlException (array($this, sprintf("Cannot write data to table &#39;%s&#39;", $tableName), self::DB_CODE_TABLE_UNWRITEABLE), self::EXCEPTION_SQL_QUERY);
+               }
        }
 }