qDev Framework

Table of contents

Overview

qDev stands for "Quick Development". It's an Open Source Object-Oriented Web Application Framework written in PHP.
It simplifies repetitive tasks, hoping to make developer's life easier.

Licence

The qDev Framework is distributed under the New BSD Licence.

About

This framework was written by Alan Reid.
It's currently in a very early stage of development, but you may contact me if you have any questions, suggestions or if want to contribute.

Getting Started

MVC

qDev implements the Model-View-Controller pattern.

Model:
qDev's implementation of this layer is pretty simple. It's just a persistency layer between the Controller and the Database.

View:
Views are the presentation layer. Each view is a HTML template. qDev uses Smarty's Template Engine by default.

Controller:
These are in charge of doing your applications business logic. This is where you import libraries and do all your crazy stuff :)

Controllers

Controllers are in charge of doing your application's business logic.
Here's where you load all the necessary libraries for your application to work.

A simple Controller looks like this:

IndexController extends qDev_Controller
{
    public function indexAction()
    {
        $company = $this->company->get(34);
        ...
    }

    public function editAction($id)
    {
        $data = $this->request->post;
        $company = $this->company->update($data, $id);
        ...
    }
}

qDev URLs

qDev has a built-in Router class that automagically loads a Controller and executes the desired method (depending on the URL).

Let's see some examples:

http://myapp.com/
IndexController->indexAction()

http://myapp.com/index
IndexController->indexAction()

http://myapp.com/index/index
IndexController->indexAction()

http://myapp.com/index/index/something
IndexController->indexAction(something)

http://myapp.com/contacts/edit/43
ContactsController->editAction(43)

http://myapp.com/contacts/group/43/55
ContactsController->groupAction(43, 55)

And so on...

If you want a Controller method to be accessible for the Router, all you have to do is declare it public and append "Action" to its name.

class IndexController extends qDev_Controller {
    public function editAction($contactid) {

    }
}

Views

This is the presentation layer.
qDev works with the Smarty template engine by default. You may want to take a look at Smarty's documentation
You may disable it or use other template engine if you want (I'm working to make this easier, without hacking).

A view is basically a HTML file (or just a fragment). You can assign values to replacement variables from your Controllers and include other templates as well.

From the Controllers side, all Smarty functions are available under the view method.

IndexController extends qDev_Controller
{
    public function indexAction()
    {
        $company = $this->company->get(34);
        $this->view->assign('company', $company);
        $this->view->assign('content', 'company.phtml');
    }
}

And the template "company.phtml" would look like something like this:

{include file="header.phtml"}

<div class="results">
    {foreach from=$company item=value key=title}
        <strong>{$title}:</strong> {$value}
    {/foreach}
</div>

{include file="footer.phtml"}

The Layout template is the main template, in which the content is filled.
For instance, your "company.phtml" template would be loaded inside this layout template.

Accessing GET/POST

qDev leaves the $_GET and $_POST global variables untouched (you can use them normally).
If you want them to be sanitized (to avoid XSS attacks), all you have to do is use the Request Library:

$username = $this->request->post['username'];

Using the Library

Loading classes from the Library is very easy, and it works the same way for both, qDev's Library and your own.

If you're in a Controller, there are two ways of loading a class from the Library:

Sessions

The session is created by loading the session Library. You will then have access to the stored data.

// Accessing value
$userid = $this->session->userid;

// Storing value
$this->session->username = $username;

Benchmarking

qDev includes a small benchmarking Library to help you optimize your applications. It allows you to test multiple times before showing the results and it includes the time difference between start and stop (in seconds) and the memory usage in that period (in kb).

$this->benchmark->start('test1');

for($i = 0; $i < 10000; $i++) {
    continue;
}

$this->benchmark->stop('test1');
$this->benchmark->start('test2');

for($i = 0; $i < 1000000; $i++) {
    continue;
}

$this->benchmark->stop('test2');

// Get a single result
$test2 = $this->benchmark->get('test2');

// Get all results
$all = $this->benchmark->getAll();

Mysql

This Library is an extension of PHPs MySQLi class. It adds some functionallity, like insert, update, delete, fetchAll.
It logs all queries made and integrates to qDev's error handling Library.

Models

qDev's Model is a simple layer that interacts with the database.

$this->load('model');

$this->model->setTable('users')
            ->setPrimaryKey('userid');
            ->setFields(array(
                'userid',
                'username',
                'firstname',
                'lastname',
                'lastlogin'
            ));

// Create an entry
$userid = $this->model->create(array(
    'username' => 'john',
    'firstname' => 'John',
    'lastname' => 'Doe'
));

// Update an entry
$this->model->update(array(
    'username' => 'doe',
    'lastlogin' => time()
), array(
    'userid' => $userid
));

// Read an entry
$this->model->get(array(
    'username',
    'firstname,
    'lastname'
), array(
    'userid' => $userid
));

// Delete an entry
$this->model->delete(array('userid' => $userid));

If we define a Primary Key, we can spare the condition array and do this (works for all methods):

$this->model->delete($userid);

Creating your own Models

Of course, if you are going to use these more often, it would be useful define models and use them.
Simply add a class to the "models" folder.

Remember:

  • The class name should start with the first letter in uppercase and the keyword "Model". Eg: CompanyModel
  • The filename should be the name of the class and the keyword "Model" with the ".php" extension. Eg: CompanyModel.php
  • Your Model must extend the qDev_Model class in order to use the built-in functionallity.
  • DO NOT use PHP's constructor, use the init() method instead. If you use this, don't forget to call the parent's init() after.
// Customer Model
class CustomerModel extends qDev_Model
{
    public function init()
    {
        $this->setTable('customers')
             ->setPrimaryKey('customerid');
             ->setFields(array(
                 'userid',
                 'username',
                 'firstname',
                 'lastname',
                 'lastlogin'
             ));

        parent::init();
    }
    ...
}

You can also define relationships between tables. Doing so, will allow qDev to create the necesary joins for itself.

// Invoice Model
class InvoiceModel extends qDev_Model
{
    public $table = 'invoices',
           $primaryKey = 'invoiceid',
           $relations = array(
               'customerid' => array( // Foreign key
                   'Customer' => 'customerid', // Parent Model class name => Parent key
               )
           ),
           $fields = array(
               'invoiceid',
               'description',
               'customerid',
               'doctype',
               'docno',
               'billtype',
               'totalamount',
               'netamount',
               'tax',
               'taxtype',
               'billingdate',
               'billduedate'
           );
    }
}

From your controller, you will have access to other tables data, joined by the Foreign keys you specify.

IndexController extends qDev_Controller
{
    public function indexAction()
    {
        $invoice = $this->invoice->get(31);
        print_r($invoice);
    }
}
stdClass Object
(
    [invoiceid] => 31
    [description] => Test
    [customerid] => 1
    [doctype] => 80
    [docno] => 20345101293
    [billtype] => 1
    [totalamount] => 1210.0000
    [netamount] => 1000.0000
    [tax] => 210.0000
    [taxtype] => 2
    [billingdate] => 2010-08-31 00:00:00
    [billduedate] => 2010-09-30 00:00:00
    [customers_customerid] => 1
    [customers_company] => Test SA
    [customers_cuit] => 12123456781
    [customers_address] => Av. del Libertador 1123
    [customers_zipcode] => 2345
    [customers_city] => Capital Federal
    [customers_province] => Buenos Aires
    [customers_country] => Argentina
    [customers_userid] => 1 )

Creating your own Library classes

Simply add a class to the "Library" folder.

Remember:

  • The class name should start with the first letter in uppercase. Eg: Benchmark
  • The filename should be the name of the class with the ".php" extension. Eg: Benchmark.php
  • If you want to access other classes of the Library, you must add the public property $qdev to your class.
  • If you want to access the config settings, you must add the public property $config to your class.
  • DO NOT use PHP's constructor, use the init() method instead. If you use this, don't forget to call the parent's init() after.

You can even extend other libraries to make your life easier, to enhace them or changing default behavior by overwriting them.

// Company Library
class Session exends qDev_Session
{
    public function init() {
        $this->session->joindate = time();
        parent::init();
    }

    public function foo() {
        return;
    }
    ...
}

Guidelines for qDev hackers

Simply create a class in qDevs "Library" folder.
In case your implementation requires more than one class, you can create a folder with the main classes name and put all other related classes together.

Remember:

  • The class name should start with "qDev_" and followed by the name with the first letter in uppercase. Eg: qDev_Benchmark
  • The filename should be the name of the class without the "qDev_" with the ".php" extension. Eg: Benchmark.php
  • If you want to access other classes of the Library, you must add the public property $qdev to your class.
  • If you want to access the config settings, you must add the public property $config to your class.
  • DO NOT use PHP's constructor, use the init() method instead. If you use this, don't forget to call the parent's init() after.