Setup

Oxygen is a framework and not a library. It follows the Hollywood principle (don't call us, we'll call you). Therefore, it expects certain things to be in the right place. This approach might be less flexible, because it cannot easily cooperate with other frameworks, but it decreases significantly the overall development time, because many things are pre-configured.

Oxygen consists of many layers and it is possible to be used partially. It is not necessary for an application to use every aspect, but to use, for example, just the basic infrastructure and ignore everything else. Or, use the MVC engine, which requires the existence of the basic infrastructure. The figure below gives a rough idea of the dependencies for each part of Oxygen.

|-----------|-----------| | ORM | | |-----------|-----------| MVC | | DAL | | |-----------|-----------------------|-----------| | Infrastructure | |-----------------------------------------------|

Setting up the basics

The basic infrastructure is the minimal configuration for Oxygen. It offers all of the following:

In order to use Oxygen in a PHP script, one has to do the following:

  1. Place Oxygen in a folder named oxy in the same directory as the script.
  2. Create the folders tmp and log, with read and right permissions, again in the same directory as the script.
  3. Write the following code in the beggining of the script

require('oxy/_.php'); Oxygen::Init();

The position of the Oxygen folder is fixed and cannot be changed. This ensures that any resource of Oxygen can always be found under the ./oxy relative directory.

The temp folder and the log folder are essential for the fluent operation of Oxygen. Their position is not fixed, and it is adviced to be put in a place that is not published to the web. In order to do that, additional initialization instruction have to be written in the script:

require('oxy/_.php'); Oxygen::SetTempFolder('../tmp'); Oxygen::SetLogFolder('../log'); Oxygen::Init();

In general, all initialization instruction have to be placed before the call to Oxygen::Init(). There are quite a few such instructions which will be presented later in this chapter.

The temp folder keeps all temporary files that Oxygen generates for caching purposes. It can also be used by the final client code. To retrieve its position, use this function:

$temp_folder = Oxygen::GetTempFolder();

On the other hand, the log folder keeps a report for each unhandled exception thrown in the application. It is also possible that these reports are sent by e-mail to the developer. To enable that, the developer's e-mail address has to be registered with an initialization instruction.

Oxygen::AddDeveloperEmail('developer@email.com');

Setting up code autoloading

Oxygen provides its own simple code autoloader which simplifies very much the development process. To autoload a class, it has to be placed in a file with the same name and the extension .php. Then the file has to be places inside one of the registered code folders. Oxygen will scan the code folders recursively, so the actual directory does not matter, as long as it is inside one of them.

To register a code folder, use this initialization instruction, before calling Oxygen::Init():

Oxygen::AddCodeFolder('app/src');

The code folders be anywhere in the disk and they do not have to be inside a published folder.

Using the autoload mechanism of Oxygen makes it easy to organise the code in modules. Essentially, each module will have its own code folder. The organization of the files inside the code folder does not matter. The folder oxy/src is registered by default and, therefore, all classes of Oxygen will be autoloaded when needed. As a result, Oxygen itself can be considered as one of the modules of the final application.

In case that two classes from different modules have the same name, then the class from the module which is register later will be used. This makes possible to override existing classes. It is even possible to override Oxygen's internal classes. However, this feature is not supported by the existing PHP IDEs and should be used with caution as it can lead to incomprehensible code. Furthermore, it is strongly disadviced to have two classes with the same name in the same module, as it is not certain which one will be loaded.

Oxygen does not support namespaces in autoloading. This may be added in a later version.

Setting up internationalization

Every Oxygen application can potentially support many languages. Each supported language has to be register by its 2-letter ISO code (http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) with an initialization instruction:

Oxygen::AddLang('en'); Oxygen::AddLang('fr');

To set the current working language, the following instruction can be used anywhere in the code. The current language affects many aspects of the interface, such as the language of the messages (obviously), but also the formatting of numbers, dates etc..

Oxygen::SetLang('fr');

If no language is registered, Oxygen will assume by default that only english is going to be used. In addition, Oxygen will set the working language by reading the query string variable lang. If the variable is missing, or its value is not among the registered languages, then the first registered language is going to be used.

Furthermore, Oxygen provides a flexible and modular dictionary system. The messages are placed as entries inside XML files. Each entry is called a dictionary lemma (lemmata in plural). All dictionary files should be registered with an initialization instruction.

Oxygen::AddDictionary('app/dictionary.xml');

The file oxy/dictionary.xml, which contains the lemmata of Oxygen itself, is registed by default. Like code folders, if a lemma exists in more than one dictionaries, then the later is going to be used. This means that it is possible to override lemmata, even Oxygen's internal ones.

The file oxy/dictionary.xml can be used as an example for building other dictionary files. As a convention, the translation of all lemmata begins with a capital letter. In addition, the lemmata whose name begins with Msg, should include the ending punctuation, like a period, an exclamation mark or a question mark.

Setting up the Database Abstraction Layer and the Object Relational Mapper

The Database Abstraction Layer (DAL) is a simple vendor-independent library which gives access to a database. In addition, it provides a simple upgrade mechanism, which help keeping the database in sync with the code. On the other hand the Object Relational Mapper (ORM), is built on top of the DAL and provides the automatical loading data from the database into objects and saving them back.

To setup the DAL, without the upgrade mechanism, all one has to do is connect to a database with the following function, which has to come after Oxygen::Init().

Database::Connect('server','schema','username','password',Database::MYSQL);

However, it is adviced to use the upgrade mechanism as well. It works with upgrade scripts that have to be registered before connecting to the database with a managed connection. Upon connecting to the database in a managed way, DAL will check it the database is up to date and will apply any upgrade scripts necessary.

Database::AddUpgradeFile('app/_upgrade.php'); Database::ConnectManaged('server','schema','username','password',Database::MYSQL);

The file oxy/_upgrade.php is registered by default. This file will create the tables used by Oxygen, if they don't exist, or it will upgrade them to match the version the code expects. This file can be used as a guideline in order to build other upgrade files. Keep in mind that these files have to be forward compatible. This means that they cannot depend on any code coming from the modules, because this is subject to change.

Oxygen uses the prefix oxy_ to all of its tables to avoid collisions and keep things modular. It is adviced to use a different prefix for each other module as well.

For further info on the DAL part see that related chapter: DAL.

The ORM needs little extra general configuration. Apart from the fields stored in the database, each object of the ORM has a folder in the hard disk to keep attached files such as images. All these folders are kept inside a central folder. By default, the data folder is dat. However, it is strongly adviced to be place in a position which is not published to the web, as this is a security threat. That can be done with an initialization instruction, before Oxygen::Init().

Oxygen::SetDataFolder('../dat');

In general, ORM is a subset of the DAL and covers the majority of Data Manipulation Language (DML) commands. However, it does not cover the Data Definition Language (DDL) commands as well as some edge cases of DML. As a rule of thumb, DAL should only be used inside the database upgrade. For the rest of the code, relying only on ORM will make the code more maintainable.

For further info on the ORM part see that related chapter: ORM.

Setting up the MVC

The Model-View-Controller pattern is quite a popular way to separate the concepts of an application. There are many alternative implementations, optimized for web or for desktop applications with various degrees of strictness. Oxygen uses an architecture that minimizes the development time, by sacrificing some flexibility.

For Oxygen, all web requests should be handled by the one central PHP script. This is the main controller, which will assign the work to an Action. The action to be used is determined from the query string variable action. The final actions are classes that extend the abstract class Action by implementing the missing methods. The name of all final actions have to begin with Action. When the value of the query string variable is, for example, Login, then the ActionLogin class is going to be used. If the query string variable is missing, a default action is going to be used. By default, this is Home, however, it can be changed with this initialization instruction:

Oxygen::SetDefaultActionName('MyHome');

The actual execution of the controller and the actions is done with the function Oxygen::Go() which has to be placed after all initialization is finished. The actions are divided into two big categories: those which use the entire browser page (called modal or normal actions) and the those who do not. Modal actions will be rendered inside a template which is also defined in the entry PHP script, after Oxygen::Go(). If the current action is not a modal one, the execution of the script will stop at the end of Oxygen::Go(). If it is a modal action, the script will continue with rendering the template.

The template is nothing but regular HTML code with two extra intructions. Oxygen::GetHead() will return all the necessary HTML code that has to be placed inside the header and Oxygen::GetContend() will return the actual results of the action called.

In general, the structure of the entry PHP script will look like this:

| |----------------|-------------------------------------------------------------------| | | | | | | | | | | | ... | | | | | Template | | | | ... | | | | | | ... | | | | | | | |----------------|-------------------------------------------------------------------| ]]>

For further info on the MVC part see that related chapter: Actions.