Issuu on Google+

Introduction • Overview • Installation Application • Overview • Libraries • Helpers Controllers • Overview • Predefined controllers • Examples Models • Overview • Database models • Examples Helpers • Overview • Predefined helpers • Examples Database • Factory • DB Interface

Introduction Overview Web Gear is a free, lightweight open source web development platform, aimed at developing fast web applications, based on a well defined MVC structure. The MVC is a programming design pattern that allows developers to easily combine the 3 elements of an application in a way that is much more flexible than each unit taken apart. It stands for Model View Controller. The model holds the data definition. Take for example the definitions of all major objects in a website. Each of them has a consistent model, which is also applied to the original object's children (classes derived from the original model). The view simply represents the user interface, which is composed of forms, labels, text inputs, checkboxes, buttons, and so on (practically, everything related to the visual part). In case of Web Gear, the views are simply HTML templates. The controller is the engine of the application. It tells the models how to behave, and the view how to display the model information.

Installation Installing the Web Gear Development Platform has never been easier. First of all, you have to download the latest distribution available. After doing that, just unzip the contents of the archive somewhere within your document root and rename the webgear-base directory to what ever you want. If you put the contents of the webgear-base directory directly into your document root (as defined by apache or which ever web server you use), then you're all done. Otherwise, you only have to make a small change to the includes/config/defs.php file. First find this line: define('BASE_URL', 'http://' . $_SERVER['SERVER_NAME'] . '/');

and change it following this rule (replacing your_directory with the actual directory name on the disk): define('BASE_URL', 'http://' . $_SERVER['SERVER_NAME'] . '/your_directory/');

Congratulations! You have successfully installed the Web Gear Development Platform!

Additional configuration All the configuration settings are defined into the includes/config/defs.php file. They're names are very expressive, so that if you want to change a setting, you don't need to look into a dictionary to do that. The most used settings are explained here, just to get you started. First of all, you might want to change the setting below to match your application name (which will be included by default in all page titles, unless you modify the header templates): define('APPLICATION_NAME', 'Default Application');

Debug settings If the debug mode is turned on, you will see every notice, warning and/or error your application

has. You can turn on and off the debug state by changing the setting below to true or false. define('DEBUG_MODE', true);

By default, general script failures will not be shown. By general script failures we mean startup errors that are treated using exceptions (like an invalid controller or action is requested, or a library cannot be loaded). Instead, a not found page will be shown (which you can customize in the templates/PageNotFound/Index.html file. Parse errors, notices and warnings are always shown, when debug mode is on. Remember to set this to true when going live, so that you'll not stand and watch at a blank page if something goes wrong. define('DISPLAY_404_CUSTOM_PAGE', true);

Mod_rewrite By default, you will have some sort of search engine friendly URLs, which are calculated by putting together the controller name and the controller action that is to be called. We also provide you a very basic rewriting engine, if you want to have more control over your page naming, which you can customize in the file defined for routes (includes/config/routes.ini is the default file for that). This file has to stay into the includes/config/ directory and MUST be an ini file! define('ROUTES_CONFIG_FILE', 'routes.ini');

You can add your own rules in it, following the pattern below. The only disadvantage is that you can only use a single level of files (meaning that you can have links like, but you can't have links like [yourpage.html] controller = ControllerName action = ActionToCall title = "Your page title"

If you have the mod_rewrite Apache module installed on your server, then you have to turn on the setting below, in order to get clean links (without index.php in them) from the links helper. define('MOD_REWRITE_ENABLED', true);

Here are the settings that MUST go into your .htaccess file defined for your application: Options +FollowSymLinks RewriteEngine On RewriteCond $1 !^(index\.php|admin|resources|uploads|robots\.txt|sitemap\.xml) RewriteRule ^(.*)$ index.php/$1 [QSA,L]

NOTE that you can't access other paths via URL than the ones defined in the third rule. If you need to have a downloads directory that you need to make available for everyone, just add |downloads after all the files in the third .htaccess rule. Don't forget to escape any non-letter character with a backslash (except the pipe separators, of course).

Other settings Usually, you will not need to change the application paths. However, if you want to use other paths than the default ones, you can find all the definitions under the PATH CONSTANTS section of the configuration file. If you do that, remember to also get the URL CONSTANTS in sync with the

new paths. All the other settings are explained in they're specific section. Template settings can be found in the Template library documentation, for example, session settings in the Session library documentation, and so on.

Application Overview This class represents the main application engine. It handles loading of custom modules and libraries, their initialization, and it defines methods for easy library loading, as well as URL redirection. It is automatically loaded by the bootstrap file (index.php) upon startup. The Application class is declared final. That means you cannot extend it. Also, all of its methods are static, meaning that you cannot create instances of this class. Its methods are available from within any controller, helper, or template file.

Common methods string Application::getApplicationName()

Returns the current application name. This is initially set at startup with the value of the APPLICATION_NAME constant, defined in the includes/config/defs.php file. void Application::setApplicationName(string applicationName)

Sets the application name. Can be called from any place, as the rest of the methods in this class. Registry Application::getRoutes()

Returns a Registry object containing all routes defined in includes/config/routes.ini. void Application::run()

First, this method checks that everything is alright with the system configuration, after which proceeds loading libraries, configuring them, parsing the user defined routes, and dispatching the user requested action. void Application::redirect(string url)

Redirects the user to a given URL. This method will send a HTTP header, therefore cannot be used within template files. void Application::stop([int error_code = 0])

Stops the application execution, exiting with the given code. An error code of 0 means that the application stopped without errors.

Libraries mixed Application::getLibrary(string name)

Returns an instance of the requested library, if that library was previously loaded, and an instance of it has been created. Registry Application::getLibraries()

Returns a Registry object containing all the libraries loaded up to that point.

Loading a library Libraries can be loaded at any point in your application, after the action has been dispatched to the controller. The method prototype looks like this: mixed Application::loadLibrary(string name[, array params = array()[, string directory = null[, bool return_instance = false]]])

Parameters • name: the library to load. The source file has to be placed in the includes/libraries/ directory and must be named name.php. Also, the class defined within this source file must be called name • params: additional parameters that you want to be passed in to the library constructor upon initialization (this is only taken in account if return_instance is true) • directory: the subdirectory within the includes/libraries/ directory which contains the source file for the requested library. Example: if you want to load a library that is named "Test", and it's source file resides in a directory called "MyLib" within the includes/libraries/ directory, then you will pass in the name Test, and the directory MyLib • return_instance: if this parameters is set to true, an instance of the library will be created and stored into the Application internal data store for caching purposes. The next time you request the same library, this instance will be returned Return values • boolean: if the return_instance parameter is true, an object of type name will be returned • object: if the return_instance parameter is false, a boolean value will be returned. true means that the library has been successfully loaded, while false is returned if any error occured This method will always throw an IOException exception if the library source file was not found.

Helpers Helper Application::getHelper(string name)

Returns the helper identified by the requested name, if it was loaded, or null otherwise. Registry Application::getHelpers()

Returns a Registry object containing all the helpers loaded up to that point. The returned value is a collection of Helper objects.

Loading a helper object Helpers can be loaded at any point in your application, after the action has been dispatched to the controller. The method prototype looks like this: Helper Application::loadHelper(string name[, array params = array()])

Parameters • name: the helper to load. The source file has to be placed in the includes/helpers/ directory and must be named name.php. Also, the class defined within this source file must be called name_Helper and MUST extend the base class Helper • params: additional parameters that you want to be passed in to the helper object constructor upon initialization

Return values • Helper: an instance of the requested helper object will be returned This method will always throw an IOException exception if the library source file was not found, or a Base_Exception exception if the file doesn't contain a class (or the class does not extend the Helper class).

Controllers Overview The controller handles a user's action and performs all the low-level operations. Thus, only one instance of a controller is generally present. You can instantiate another controller from within an existing controller, but that is rarely required and implies a set of actions that must be taken by the programmer in order to control the flow of the application. The controller only processes user input and does action specific operations. It does NOT produce any output all by itself, although it might look just like that at a first glance. The first time a controller is started, it runs its own internal procedures (like creating some shortcuts of the libraries inside of it, for easier manipulation). After doing that (which is completely transparent to both the programmer and the user), the control flow is passed on to the programmer, whom is free to do whatever he/she likes. All controllers must reside into the includes/controllers/ directory. There is only one thing you might want to know before actually diving into the controller's world, and that is: an action represents a subset of instructions executed on a single request (given the fact that the HTTP protocol is stateless). An action is simply defined as a class method, but can become very powerful as the application grows. Don't think of an action as a boundary. You will see how much you can do from within an action as we explain the common methods and show you some examples.

Common methods string Controller->getName()

Returns a string representing the controller's name (the class name, without the _Controller suffix). string Controller->getAction()

Returns a string representing the controller action that is being executed (without the Action suffix). mixed Controller->render([string mode = 'echo'])

This method is called after the action finished its execution, prior to the call to the __destruct() method of the controller. Parameters • mode: the rendering mode. If the output from this controller is required later in the script, set this to return. The default mode is to echo the output, instead of returning it Return values • string: if the mode is set to return, this method will return the generated output • void: if the mode is set to echo, this method will print the generated output to the screen, and nothing will be returned

Predefined controllers The WebGear Development Platform comes with a few predefined controllers out of the box. That happens so that you have a base to start from, but also to help you in developing your own applications.

The "Default" controller As its name implies, this is the default system controller and its Index action will be called by default when accessing your base application URL. You will see what the Index action does in the next section, Examples. For now, just keep in mind the fact that this is where all the action takes place in a default installation. If you installed the platform into YOUR_DOCUMENT_ROOT/your_application_name/, and you access http://yourwebsite/your_application_name/, the Index action of this controller will be called.

The "Helpers" controller This controller provides some helper actions, directly accesible via URL. Unlike a regular controller, this one does not parse template files (see the Templating section for more information). Instead, output is generated (or not) from within its methods (actions). An example of its usage is serving as an AJAX request callback function. An exception is made from the rule here, but only so that you have access to all the resources in a regular controller, even though it doesn't do anything useful alone. void Helpers_Controller->LoadJSDefsAction([array params = array()])

This method will help you when writing your Javascript code, if it is included into your template. You can include it like this: <script type="text/javascript" src="<?php echo WEBSITE_URL . 'Helpers/LoadJSDefs/'; ?>"></script>

After including that line into your template's header file, you will be able to write scripts independent of their location. This script will export all the URL constants from the includes/config/defs.php as global variables in Javascript. So, after including the file, you will be able to use the constant WEBSITE_URL (and all the other _URL suffixed constants) in Javascript, as you would use it in your controller or template file from PHP.

The "PageNotFound" controller This controller only has one action, the Index action, and will only be called if you're trying to access an invalid controller (or an invalid/non-existing controller action). If you want this page to take place of the default "Page not found" error page of Apache for example, you will need to place a rule into your .htaccess file that instructs the web server to call this action if a page is not found. Also, this controller overrides the default render method defined in the controller blueprint, so that it will parse its own complete HTML template file (which is templates/PageNotFound/Index.html).

Examples The following example will show you how to write your own controllers. But first of all, a couple

of notes are required. • The controller source file and the controller class name MUST be identical. • The controller class name MUST be suffixed with _Controller (or in case of admin controllers, _Admin_Controller is the required suffix). • Controller actions MUST be suffixed with Action. • Controller actions MUST be declared as public. Let's start with the beginning. As said before, all controllers reside into the includes/controllers/ directory. So, let's go into that directory and create a new php file called MyController.php. Now, open the file to declare our controller: <?php class MyController_Controller extends Controller { }

That's it! You have created your first controller. But it's not really complete yet, since no templates are defined for it. You can try to access, but you will get an error saying that the template file for the Index action of the controller was not found. The Index action is inherited from the base controller class, therefore it is automatically executed if you don't specify any action. Let's create a template for the index action, by going into the templates/ directory and creating a directory named exactly as the controller. Inside it, create a HTML file named exactly as the controller action you want to execute (Index in our case). By now you should have the following structure into your templates/ directory: templates/ MyController/ Index.html

There might be some other files and directories, but we excluded them, so it doesn't get confusing. If you refresh the page you accessed earlier, you should now see the HTML content you wrote into the newly created file. A global variable called $controller is made available into the templates. This is not a global PHP variable, but a variable accessible from every template file you write. Every public method defined into the controllers base class(includes/controllers/Controller.php) is available from within any template file (check the Overview page). Also, in controller specific templates (like the Index.html file created earlier), you also have access to the current controller's public methods. So, if you defined a method called myMethod into the controller created earlier (MyController), which had the following definition: public function myMethod() { return 'my method output'; }

then you could call that method into your Index.html file created earlier, and it would output "my method output": <p>My method says: <php echo $controller->myMethod(); ?><p>

Models Overview Models are objects specialized for a specific action. They simply represent a data structure, so you don't have to rewrite the same logic over and over again to achieve a specific goal. Models are specific to your application. The models can interoperate and may make use of the core libraries, although if that is needed, they need to specifically load the libraries and/or other models they need to use. That is easily achievable using a simple require_once statement. All models must be placed into the includes/models/ directory by default, in order to ensure easy application decoupling, if needed.

Database models Database models are objects specialized in working with database structures. They represent table rows in a database table and optionally define relationships within tables. Database models are stored into the includes/models/database/ by default and are automatically loaded by the database connector in use upon startup (this behavior is defined only within the MySQL connector, which is the default database connector used by the platform. If you develop your own connector, you can use your own model loading logic.). The platform also comes with an example model, named "Example", so you can see how you can programatically define a database table. When writing your own database models, keep the following suggestions in mind: â&#x20AC;˘ Name the source file just like the table in the database, so you don't get confused. â&#x20AC;˘ Suffix your model class name with _Record. â&#x20AC;˘ The MySQL models loaded by the MySQL connector (the default connector provided) MUST extend the DB_Record class in order to be automatically loaded.

Model methods NOTE that these methods are MySQL specific, and are directly related to the default connector provided by us (PDO-MySQL). Currently, the models only support basic CRUD (Create Read Update Delete) operations. They do NOT provide relationships (yet). string Record->getTable()

Returns the table name this rows belongs to. Registry Record->getFields()

Returns all the table fields. If a row has been loaded, the data will be available in the object returned by this method. string Record->getTablePrefix()

Returns the row's table prefix if it was set, or an empty string otherwise.

string Record->getFieldsPrefix()

Returns the row's fields prefix, or an empty string if no prefix is used. void Record->setUp()

This method defines the table meta data and the fields used. See the examples section for more information. boolean Registry->find(int id)

This method is only available for rows that have a primary key that is auto incremented. If there's no row with the given id into the table, the internal data storage container is reset (all the data set on the object will be gone). If the row is found, the internal data storage container will be populated with the values of the row from the table. boolean Registry->insert()

In order to run this method, you must populate the row fields first, excluding the id row (the nonnull fields are mandatory). If the insert is successful, the id property of the row will be set to the id of the newly inserted row, the rest of the fields remaining intact. If the insert failed for what ever reason, an exception will be thrown (DatabaseConnectionException, DatabaseQueryException or DatabaseParameterBindingException). void Registry->update()

Updates an existing row only if changes were made to the object. The Record class has an instance monitor to detect if any field has changed and if it did, it only updates the modified field. void Registry->delete()

Deletes the current row from the database and clears the internal data storage container, if the row has an auto incremented primary key. Otherwise, an exception will be thrown. array Registry->toArray()

Returns an array representation of the current row. The field names are prefixed with the field prefix. The Record class also provides shortcuts (__get and __set method overrides for accessing the fields of the row it represents). Therefore, the following is possible: echo $record->name; // will give you the value of the name field $record->name = 'Your name'; // will set the value of the name field

IMPORTANT NOTE: When accessing the field names using the notation above, do not specify the field prefix. The code above will work even if you have set your fields prefix to something like "pref_". If you do try to access the field with the prefix, the code will generate a Base_Exception exception. Another interesting magical utility of the Record class is searching by a single field (feature available by overriding the __call method). Considering the snippet above, you can do the following: $names = $record->findByName('John');

Observe the camelCased notation. The call above will return an array containing all the database rows whose name field value is "John" (a collection of stdClass objects). An important note here is

that the search is exact. Here's the actual query that will be run against the database: SELECT * FROM table WHERE name='John'

Examples In order to create and use a model, you must first define its fields and some other common data. All models are stored into includes/models/database/ by default. Let's change to that directory and create a model by duplicating the default Example.php file. You can use what ever naming convention you like for your models, but we recommend using the table name (without the prefix) as the source file name. By now, your directory structure should look like this: includes/ models/ database/ Example.php YourTable.php

Into the YourTable.php file, rename the class name (Example_Record) with YourTable_Record. You will see that we have a public method override: setUp. This must be defined by every record, since it establishes table information about the current row and defines the fields of that row. Also, make sure that: parent::setUp()

is called before anything else in this method. We need to set the table prefix (optionally), the table name (mandatory) and the fields prefix (optional) first of all: $this->setTablePrefix('your_table_prefix'); // can be ommitted if your table does not have a prefix $this->setTableName('your_table_name'); $this->setFieldsPrefix('your_fields_prefix'); // if set, all fields into this table must be prefixed with this string

Now, you need to define your fields names and types. That is pretty easy, just keep in mind that only INT (and other derived types) must have a type of PDO::PARAM_INT, all others must be declared as PDO::PARAM_STR (yes, even floats and doubles!). Suppose your table structure looks like this: // Table "names" id INT(8) fullname VARCHAR(128) age INT(8)

The following definitions would be required: $this->addField(array('name' => 'id', 'type' => PDO::PARAM_INT)); $this->addField(array('name' => 'fullname', 'type' => PDO::PARAM_STR)); $this->addField(array('name' => 'age', 'type' => PDO::PARAM_INT));

That's it! You can now perform basic CRUD operations using the newly created model.

Helpers Overview Helpers are objects that help you achieve a specific goal by making use of the system libraries and/ or models (or none, for that matter). The difference between our framework's and others' helpers is that you must explicitly specify what libraries the helper uses and then use them. There is no extra loading of stuff you might not ever need. Just keeping it simple, but at the same time, fast and efficient. Loading and accessing helpers is described in detail here.

Predefined helpers There are some helpers that we included in the base distribution to provide you with a starting point. They are described below.

Links Helper This helper assists you in building links for your website. Of course, for more complex links, you might need additional methods. The point is, by using helpers, you only need to make a change in only one place, and it will be reflected in the whole application/website. boolean Links_Helper->isHomepage()

Returns true if the page you are viewing is the homepage (that means if the controller name is Default, and the action is Index), false otherwise. string Links_Helper->buildURL([string controller_name = 'Default'[, string controller_action = 'Index'[, array uriParts = array()[, string queryString = ''[, int type = 0]]]]])

Parameters • controller_name: The controller name • controller_action: The controller action • uriParts: The parts of the URI to be appended to the URL (action parameters in the form of param_name => param_value) • queryString: The query string to append to the URL • type: The type of the URL (0 - website, 1 - admin panel) Returns the string representation of the target URL.

Template Helper void Template_Helper->addStylesheet(string src[, string rel = 'stylesheet'[, string media = 'screen'[, array extra = array()]]])

Stores a stylesheet to the internal stylesheet collection for later parsing. Parameters • src: The URL to the stylesheet • rel: The relationship type with the document

• media: The type of media this stylesheet should be loaded for • extra: Any number of extra parameters to be added to the link element (a key => value mapping) void Template_Helper->addScript(string src[, array extra = array()])

Stores a javascript external script file pointer to the internal scripts collection for later parsing. Parameters • src: The URL to the script file • extra: Any number of extra parameters to be added to the link element (a key => value mapping). By default, only the type attribute is automatically added, having a value of text/javascript. string Template_Helper->loadStylesheets()

Parses the internal collection of stylesheets and returns the HTML output for it. string Template_Helper->loadJavascripts()

Parses the internal collection of javascript scripts and returns the HTML output for it.

Examples In this part you will learn how to write your own custom helpers that perform what you want them to. All helpers are stored into includes/helpers by default. Let's change to that directory and create a helper by creating a file called MyHelper.php. By now, your directory structure should look like this: includes/ helpers/ Links.php Template.php MyHelper.php

Now, for the system to be able to load your helper dynamically (to be able to call Application::loadHelper on your helper), you need to name your helper class exactly as your helper's source file, adding the prefix _Helper. So, let's open the newly created file and create the class: class MyHelper_Helper extends Helper { // the code for your helper will go here }

Let's load this fresh helper into our main application. Go to a controller action of your choice (Default/Index is used for simplicity), and add the following line in it: Application::loadHelper('MyHelper');

The helper is now ready for use. Now, let's say you want to use the DB library into this newly created helper. Suppose we want to fetch all people from a database table and return them. We'll add the following method to the helper: public function getPeople() { return $this->libraries->DB->query('SELECT * FROM people');


Ok, notice that the loaded libraries are available into the helper via $this->libraries->library_alias. Let's load the DB library (from our Default/Index action, after Application::loadHelper('MyHelper') has been called): Application::getHelper('MyHelper')->using('DB', $this->DB);

And that's about it. You can now go into your templates/Default/Index.html file and call $Helpers>MyHelper->getPeople(). You will get what you asked for. Your basic helper is now finished. Just add your methods in it and call them from your controller. Check out the using() helper's method. Its syntax is as follows: $Helper_Instance->using('library_alias', $object_instance)

Your object will be available into your helper as: $this->libraries->library_alias

Database Factory The DB_Factory class allows you to create a new database library (or connector, as referenced sometimes) object instance. It only creates an object, which it returns to you for manipulation. You can feed it the name of the connector you'd wish to take control of (always spawns a new instance), by default (and only) being "mysql". It must be the suffix of the connector's file name (which it also is a part of the connector's class name declaration). The database connectors are located into the includes/libraries/Database/connectors/ directory. Always. After calling DB_Factory::getInstance([string name = 'mysql'])

you must explicitly set the connector's parameters in order to successfully establish a connection to your database. Check the next pages for reference.

Database Interface The DB interface defines common methods for connectors loadable by the DB_Factory class. That means all the connectors must implement this interface in order to be pluggable into the core system. The methods it requires to be defined are described below. array DB::getQueryStack()

Returns an array containing all the queries executed up to that point. string DB::getLastQuery()

Returns the last query executed by the current connector. int DB::getLastInsertID()

Returns the ID of the last row inserted into the database (resulting from running an INSERT query). If no INSERT query has been run, this method will return the special value null. array DB::getResults()

Returns the results of the last successful query that might return a result. If no results are found, an empty array will be returned. If the query is incorrect, a DatabaseConnectionException exception is thrown.

Framework Manual