Another useful service that Harmoni provides is the "StorageHandler". As you may have figured out from the name of the service, the StorageHandler manages your file storing on your server. Currently, Harmoni allows you to handle files in 3 ways:
1) Store and handle the files in a database, maintaining a virtual hierarchy with paths and names
2) Store and handle the files on a file system
3) Store and handle the files in an array, maintaining a virtual hierarchy
The process of storing a file on the server is based on the concept of a storable. The storable is an object which holds the file you want to handle and has access to methods that directly access your file. So, a storable "wraps up" the file you want to handle/store, and the details(source,target etc..) of the storage.
One kind of storable that one can create is a "FileStorable". This will be used when the file you want to store is on a file system, fully specified by a path name. In order to be able to create a FileStorable make sure you include the following lines in your code:
require_once("path/to/harmoni/harmoni.inc.php");
require_once("path/to/harmoni/core/storageHandler/Storables/FileStorable.class.php");
Once you include those files, in order to create the FileStorable out of the file on your file system simply write:
$file =& new FileStorable($basepath,$path,$name);
Where $basepath is the path to the base directory of the file, $path is path to the file and $name is the name of the file. One example might look like:
$file =& new FileStorable("/home/","pictures/","greece.jpeg");
Now you have created an object that the StorageHandler can handle. All you have specified, is the path to the file.
The DatabaseStorable is the storable that will handle a file stored in a database. The DatabaseStorable class can handle a file in a database only if the file is stored in a table with the columns:
*nameColumn
*pathColumn
*dataColumn
*sizeColumn
Of course, they can have any name but they should store the name, the virtual path, the data and the size of the file.
Now, before you create the DatabaseStorable you need to specify the specifications of the file in your database. So, first connect to your database:
$dbHandler =& Services::requireService("DBHandler");
$dbIndex = $dbHandler->addDatabase(
new MySQLDatabase(
"localhost",
"myDB",
"user",
"password")
);
$dbHandler->connect($dbIndex);
...where as an example we use a MySQL Database and a database "myDB" with user "user" and password "password". Now that we connected to the database, we need to store the location of our file that is going to be used by the DatabaseStorable. This is achieved through the use of a DatabaseStorableDataContainer. Usage:
...previous code here....
require_once("/path/to/harmoni/core/storageHandler/Storables/DatabaseStorableDataContainer.class.php");
$databasecontainer =& new DatabaseStorableDataContainer();
$databasecontainer->set("dbIndex",$dbIndex);
$databasecontainer->set("dbTable",$storage);
$databasecontainer->set("pathColumn",$path);
$databasecontainer->set("nameColumn",$filename);
$databasecontainer->set("sizeColumn",$size);
$databasecontainer->set("dataColumn",$data);
So, firstly we included the file needed to use the "DatabaseStorableDataContainer" class. Then we created an object of that class and then we set the details of the location of our file in the database
//This line scecifies the database that the file is in.
$databasecontainer->set("dbIndex",$dbIndex);
//This line scecifies the table that the file is in.
$databasecontainer->set("dbTable",$storage);
//This line scecifies the column of the table that holds the path of the file.
$databasecontainer->set("pathColumn",$path);
//This line scecifies the column of the table that holds the name of the file.
$databasecontainer->set("nameColumn",$filename);
//This line scecifies the column of the table that holds the size of the file.
$databasecontainer->set("sizeColumn",$size);
//This line scecifies the column of the table that holds the data of the file.
$databasecontainer->set("dataColumn",$data);
Now that we have specified where the file is we can create the DatabaseStorable including the appropriate file and using the appropriate code. So:
require_once("/path/to/harmoni/core/storageHandler/Storables/DatabaseStorable.class.php");
$file =& new DatabaseStorable($databasecontainer,"/harmoni/is/very/","cool.txt");
...where $databasecontainer is the DatabaseStorableDataContainer created above, the second argument is the path of the file and the third parameter is the name of the file. Putting it all together, we have:
//Let's suppose we have a file called "text.txt" stored in a table "myT" in a PostgreSQL database "myD".
//The table "myT" has four columns: "filename", "size", "path", "data" and the entry that represents the file
//"text.txt" has those columns filled with the correspondent data. So:
//require_once the appropriate files:
require_once("harmoni/harmoni.inc.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorableDataContainer.class.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorable.class.php");
//connect to the database using a DBHandler
$dbHandler =& Services::requireService("DBHandler");
$dbIndex = $dbHandler->addDatabase(
new PostgreSQLDatabase(
"localhost",
"myD",
"user",
"password")
);
$dbHandler->connect($dbIndex);
//specify the location of "text.txt" through the DatabaseStorableDataContainer
$databasecontainer =& new DatabaseStorableDataContainer();
$databasecontainer->set("dbIndex",$dbIndex);
$databasecontainer->set("dbTable","myT");
$databasecontainer->set("pathColumn","path");
$databasecontainer->set("nameColumn","filename");
$databasecontainer->set("sizeColumn","size");
$databasecontainer->set("dataColumn","data");
//..and now that you know where it is make the DatabaseStorable
$file =& new DatabaseStorable($databasecontainer,"/path/to/","text.txt");
A VirtualStorable is a wrapper for another kind of storable. It stores a storable whose attributes you can use but not change. It is used by the StorageHandler itself.
Its constructor is
VirtualStorable(string $basePath, object& $Storable)
For the functions that you can call on a VirtualStorable look at the PHPDoc.
Now that we learnt how to create storables out of files in our file system or our database we proceed with the ultimate goal of storing them at the desired location. The next step towards this, is the creation of a storage method. The storage method will have to know where and how to store our storable. Let's first look at the FileStorageMethod:
The FileStorageMethod stores a storable in the desired location in the file system. But the user will not call the FileStorageMethod to actually store the storable. It will be called by the StorageHandler. What the user needs to specify, is the actual path the storable will be stored. So, if we want to store our file to the path "/home/myname/files/" we need to create a FileStorage method with this parameter. The code would look like:
require_once("/path/to/harmoni/harmoni.inc.php");
require_once("/path/to/harmoni/core/storageHandler/StorageMethods/FileStorageMethod.class.php");
$method =& new FileStorageMethod("/home/myname/files/");
That's it! We have created the method that will store our storable at the specified path. The DatabaseStorageMethod is slightly more complicated but still as simple as the FileStorageMethod. Let's take a look at it.
The DatabaseStorageMethod makes use of the DatabaseStorableDataContainer that was introduced when talking about the DatabaseStorables. Again, all the method needs to know is where to store the storable. So, firstly we create a DatabaseStorableDataContainer where we specify where we want the method to store out storables. Let's look at the code:
require_once("harmoni/harmoni.inc.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorableDataContainer.class.php");
//connect to a MySQL database using a DBHandler
$dbHandler =& Services::requireService("DBHandler");
$dbIndex = $dbHandler->addDatabase(
new MySQLDatabase(
"localhost",
"myD",
"user",
"password")
);
$dbHandler->connect($dbIndex);
//specify the desired location that we want to store the storable
//assume we want our storage target to be in a MySQL Database
//in the table "MyT" and the columns "path","filename","size" and "data
$databasecontainer =& new DatabaseStorableDataContainer();
$databasecontainer->set("dbIndex",$dbIndex);
$databasecontainer->set("dbTable","myT");
$databasecontainer->set("pathColumn","path");
$databasecontainer->set("nameColumn","filename");
$databasecontainer->set("sizeColumn","size");
$databasecontainer->set("dataColumn","data");
Now we just create the DatabaseStorageMethod using:
require_once("/path/to/harmoni/core/storageHandler/StorageMethods/DatabaseStorageMethod.class.php");
...previous code goes here...
$method =& new DatabaseStorageMethod($databasecontainer);
...and this method will store your storables in the database table specified by the DatabaseStorableDataContainer.
Ok, so now we know how to make a storable of our file, we know how to create a method to store our file. But how do we put those together? That is where the StorageHandler comes into the game.It is the StorageHandler that "wraps up" everything and is called by the end user. Now, the storageHandler is called using the following code:
require_once("harmoni/harmoni.inc.php");
require_once("harmoni/core/storageHandler/StorageHandler.class.php");
$storagehandler =& Services::requireService("Storage");
And with the variable "$storagehandler" we can use the methods of the storageHandler class such as "store", "retrieve", "copy", "delete" etc.. In order for our storagehandler to be able to use those functions, it needs a method of storage. So before using the storagehandler to handle storables, we need to add a method to it. The method can be any of the methods described above which specifies the way of handling the files. Let's see an example of how we would use a FileStorable and store it our database using a DatabaseStorageMethod.
//Let's suppose there is an image file in our file system in the directory /home/myname/myfiles/ called
// "mypict.jpeg". We want to store it in a MySQL Database in the table "MyT" which has columns "filename"
//"size", "path" and "data".
//first let's include the appropriate files
require_once("harmoni/harmoni.inc.php");
require_once("harmoni/core/storageHandler/Storables/FileStorable.class.php");
require_once("harmoni/core/storageHandler/StorageHandler.class.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorableDataContainer.class.php");
require_once("harmoni/core/storageHandler/StorageMethods/DatabaseStorageMethod.class.php");
//Now let's make a FileStorable to be able to use our file
$file =& new FileStorable("/home/myname/","myfiles/","mypict.jpeg");
//Now let's specify the location in the database that we want to store our file
$dbHandler =& Services::requireService("DBHandler");
$dbIndex = $dbHandler->addDatabase(
new MySQLDatabase(
"localhost",
"MyD",
"user",
"password")
);
$dbHandler->connect($dbIndex);
$databasecontainer =& new DatabaseStorableDataContainer();
$databasecontainer->set("dbIndex",$dbIndex);
$databasecontainer->set("dbTable","MyT");
$databasecontainer->set("pathColumn","path");
$databasecontainer->set("nameColumn","filename");
$databasecontainer->set("sizeColumn","size");
$databasecontainer->set("dataColumn","data");
//Now let's create the method that will store out FileStorable using the
//DatabaseStorableDataContainer just created.
$method =& new DatabaseStorageMethod($databasecontainer);
//now let's use the StorageHandler service
$storagehandler =& Services::requireService("Storage");
//and let the StorageHandler know what method to use to store files
//(for the moment ignore the second parameter)
$storagehandler->addMethod($method,"/");
//finally let's store our file in the database
$storagehandler->store($file,"/home/storedFiles/","mypict_copied.jpeg");
//...and we are done! The original picture is stored in the database specified
//with path "/home/storedFiles/" and name "mypict_copied.jpeg".
In order to be able to store a file in the database, you need to have the four columns specified above that will store the name, the path, the size and the data of the file.
Let's look at the same example, but this time let's go the other way around: let's store a file from a database to a location in the file system:
//Let's suppose there is an file in our database in the table "MyT" with path "/home/myfiles/", called
// "myFile.doc". We want to store it in our file system with path "/home/storedFiles/myFile_copied.doc"
//first let's include the appropriate files
//(be careful, they are not the same as the previous example)
require_once("harmoni/harmoni.inc.php");
require_once("harmoni/core/storageHandler/StorageHandler.class.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorableDataContainer.class.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorable.class.php");
require_once("harmoni/core/storageHandler/StorageMethods/FileStorageMethod.class.php");
//Let's specify the location in the database that the file we want to store is
$dbHandler =& Services::requireService("DBHandler");
$dbIndex = $dbHandler->addDatabase(
new MySQLDatabase(
"localhost",
"MyD",
"user",
"password")
);
$dbHandler->connect($dbIndex);
$databasecontainer =& new DatabaseStorableDataContainer();
$databasecontainer->set("dbIndex",$dbIndex);
$databasecontainer->set("dbTable","MyT");
$databasecontainer->set("pathColumn","path");
$databasecontainer->set("nameColumn","filename");
$databasecontainer->set("sizeColumn","size");
$databasecontainer->set("dataColumn","data");
//Now let's create the DatabaseStorable from the file with path /home/myFiles and name myFile.doc
//which is stored in the database location
//specified by the variable "$databasecontainer"
$file =& new DatabaseStorable($databasecontainer,"/home/myFiles/", "myFile.doc");
//now let's use the StorageHandler service
$storagehandler =& Services::requireService("Storage");
//create the method that we will use to store our file to the filesystem
$method =& new FileStorageMethod("/home/storedFiles/");
//and let the StorageHandler know what method to use to store files
//(for the moment ignore the second parameter)
$storagehandler->addMethod($method,"/");
//finally let's store our file in the file system
$storagehandler->store($file,"","myFile_copied.doc");
//...and we are done! The original picture is stored in the file system
//with path "/home/storedFiles/" and name "myFile_copied.doc" or
//the full path "/home/storedFiles/myFile_copied.doc"
But what is the second parameter that we pass to the "addMethod" function? The storageHandler has a method associated each path. It has to have a method associated with the root path "/" and then it can have as many methods associated with other paths. What this means is, for our file system (either a real file system on the server or a virtual on the database) we can associate methods with paths. For example, suppose we have a file system with a path /home/users/myname/myfiles. Let's say that whenever we want to store something in a folder up to "myfiles/" we want to store it in the file system. But whenever we want to add a file in the "myfiles/" folder we want to store it in a database. In order to do that we need to create a FileStorageMethod and associate it with the root folder "/" and then create a DatabaseStorageMethod and associate it with the folder "myfiles/". The way we do that is, when adding the method to the storageHandler, we pass a second argument specifying the path we want to associate it with. Thus, whenever the user wants to store something in a given path, the storageHandler "looks" whether you have defined a method associated with that path and uses it. If there is none defined, the "/" method is used.
Let's modify the first example where we stored a file from the file system to the database so that whenever we want to store at a given location we use a FileStorage method
//Let's suppose there is an image file in our file system in the directory /home/myname/myfiles/ called
// "mypict.jpeg". We want to store it in a MySQL Database in the table "MyT" which has columns "filename"
//"size", "path" and "data".
//first let's include the appropriate files
require_once("harmoni/harmoni.inc.php");
require_once("harmoni/core/storageHandler/Storables/FileStorable.class.php");
require_once("harmoni/core/storageHandler/StorageHandler.class.php");
require_once("harmoni/core/storageHandler/Storables/DatabaseStorableDataContainer.class.php");
require_once("harmoni/core/storageHandler/StorageMethods/DatabaseStorageMethod.class.php");
//Now let's make a FileStorable to be able to use our file
$file =& new FileStorable("/home/myname/","myfiles/","mypict.jpeg");
//Now let's specify the location in the database that we want to store our file
$dbHandler =& Services::requireService("DBHandler");
$dbIndex = $dbHandler->addDatabase(
new MySQLDatabase(
"localhost",
"MyD",
"user",
"password")
);
$dbHandler->connect($dbIndex);
$databasecontainer =& new DatabaseStorableDataContainer();
$databasecontainer->set("dbIndex",$dbIndex);
$databasecontainer->set("dbTable","MyT");
$databasecontainer->set("pathColumn","path");
$databasecontainer->set("nameColumn","filename");
$databasecontainer->set("sizeColumn","size");
$databasecontainer->set("dataColumn","data");
//Now let's create the method that will store out FileStorable using the
//DatabaseStorableDataContainer just created.
$method =& new DatabaseStorageMethod($databasecontainer);
//this is the second method that will be called whenever
//we store a file at the location "/home/myname/myfiles"
$method2 =& new FileStorageMethod("");
//now let's use the StorageHandler service
$storagehandler =& Services::requireService("Storage");
//and let the StorageHandler know what method to use to store files
//(for the moment ignore the second parameter)
$storagehandler->addMethod($method,"/");
//add the second method to the storageHandler
$storagehandler->addMethod($method2,"/home/myname/myfiles");
//finally let's store our file (in the database)
$storagehandler->store($file,"/home/storedFiles/","mypict_copied.jpeg");
//and let's also store it at "/home/myname/myfiles"
$storagehandler->store($file,"/home/myname/myfiles/","mypict_copied.jpeg");
//...and we are done! The original picture is stored in the database specified
//with path "/home/storedFiles/" and name "mypict_copied.jpeg" using $method
//and it is also stored in the file system with path "/home/myname/myfiles" using
//$method2.
This way we can specify in the beginning (or in a config file) what method to use for storing at each path, and then maintaining a file system, without necessary knowledge where all the files are stored. We will still have a file system to find our files.
The storageHandler has many functions which can be seen at the PHPDoc and here we mention the most important.
A very useful function defined in the storageHandler class is the function "retrieve()". Whenever you want to retrieve a file from your file system you can just use the retrieve function specifying the path of the file, which will look for the appropriate method to find that file. For example:
//getting the file "mytext.txt" from the directory "/home/myname/files"
//without needing to know where the file is stored
$filename=& $storagehandler->retrieve("/home/myname/files/","mytext.txt");
//and printing its contents on the browser
print $filename->getData();
Other functions included in the StorageHandler class include:
//Removes the file specified by $name and $path from all applicable StorageMethods.
delete(string $path, string $name)
//Gets the total number of Storables under $path.
getCount(string $path, [boolean $recursive])
//Gets the size of either a path or a file.
getSizeOf(string $path, [string $name])
Once we have defined a method for a certain path, we can define as many backup methods as we want. What do we mean by backup? The backup method is a different method (FileStorageMethod or DatabaseStorageMethod) with different specifications that will be called whenever the StorageHandler handles a storable in that path. Thus, the storables will be stored in the backup method too. A backup method can be added to the StorageHandler using the following code:
..previous code goes here and necessary files are included..
$primarymethod = new FileStorageMethod();
$storageHandler =& Services::requireService("Storage");
$storageHandler->addMethod($primarymethod,"/");
//assuming we have created an object $databasecontainer that stores the details of the database
$backupmethod = new DatabaseStorageMethod($databasecontainer);
$storageHandler->addBackupMethod($backupmethod,"/");
This way, anytime we use our storageHandler to store,delete, move or anyhow handle a storable, the backupMethod will be called too and make the appropriate changes to its own file system.
The subtle point in the backupMethod was omitted in the previous example though. A backupMethod can take a third parameter which specifies what type of backup method you want. The possible values are "MIRROR_SHALLOW" and "MIRROR_DEEP". If you omit it, the method type is set to "MIRROR_SHALLOW". What the type specifies, is how you want to backupmethod to "mirror" the file system. The "MIRROR_DEEP" type will save all its files stored under its path. The "MIRROR_SHALLOW" type will only save the files that would be stored on the primary server.