Linked-in profile Github profile Twitter profile Curriculum vitae
Categories: PHP Projects
19th December 2016
2nd February 2024

Deft, a PHP micro-framework

A bare essentials micro-framework. With route, cache, event, plugin, markup, pdo management, and more.

I started building a PHP framework to use on small projects, with the intention of building Helper methods as required through development for the most common routines.

The focus has always been on speed, and the bare essentials to create and manage instances of things like database connections, documents, and caching pools, which could be easily accessed from all areas of the project, using minimal resources and time, oh, and trying to keep the code required, short… Not an easy task, but this is it so far. 🙄

Source code for Deft is available on GitHub! This project was started back in 2014 and currently only receives a little development. If interest in it picks up…
require 'deft.php';
$instance =& Deft::get( 'class' );

New instances of core classes Db and Config have a default configuration which can be overridden as needed, you can create overrides using the inline method
Deft::get( 'class' [, array $args] ), or using the core configuration file (see below).

Let’s start with an example MySQL database script

The defaults for a Db class instance are driver[=mysql], hostname[=localhost]dbname[=mysql], username[=root], passwordport[=3306], and table_prefix.

You can also use the main configuration file (/content/app-config.php) to customize the default database details, by adding db_ prefixed overrides. Add them manually to the config file…

'db_dbname' => 'myDatabaseName',
'db_username' => 'user',

Or programmatically, with the config instance shortcut Deft::config()

require 'deft.php';

$cfg =& Deft::config();

$dbname = $cfg->get( 'db_dbname' );
if( !$dbname ) {
  $cfg->set( array(
    'db_hostname' => '',
    'db_dbname' => 'myDefaultDatabase',
    'db_username' => 'user',
    'db_table_prefix' => 'deft_'
  ) );

So we can keep future code light and get on with what we need to, keep it simple and easy to read. The instance handler of the Db class also has a shortcut Deft::database( [array $args] )

To give you an idea of how Deft has been put together. Here is a basic script that looks for a customer called John Smith, if not found, is created, then modified.

require 'deft.php';

$db =& Deft::database();

if( $db->isConnected() == false ) {
  echo $db->lastError()->getMessage();
} else {

  // Get some database records, conditions are auto sanitized
  $list = $db->getRows(
    'SELECT id FROM #_customers WHERE first_name = ? AND last_name = ?',

  // Nobody by that name...
  if( !count( $list ) ) {

    // Create record...
    $recordId = $db->insert( '#_customers', array(
      'first_name' => 'John',
      'last_name' => 'Smith'
    ) );

    // Record was created! Lets change it...
    if( $recordId ) {

      // Update the record...
      $affectedRows = $db->update( '#_customers', array(
        'last_name' => 'Bloggs'
      ), array(
        'id' => $recordId
      ) );

      // Changes were successful!
      if( $affectedRows ) {
        echo "{$affectedRows} updated!";

        // Delete the record...
        $affectedRows = $db->delete( '#_customers', array(
          'last_name' => 'Bloggs',
          'id' => $recordId
        ) );

        // Delete was successful!
        if( $affectedRows ) {
          echo "{$affectedRows} deleted!";
        } else {
          echo "Nothing deleted!";
      } else {
        echo "Nothing changed!";

Adding #_ before table names on queries will be replaced with the table_prefix when the query is parsed.

Now an example controller plugin

We’re going to capture the script, the abc value is based on the user request through the Route rule, and build a HTML5 document to wrap around it. Here is the app…

require 'deft.php';

class Example {
  function init() {
    Route::add( '[page]', array(
      'page' => '[a-z]+',
      'foo' => 'bar'
    ) );

  function initContent() {
    Deft::response()->setTitleSeparator( ' | ' );
    Deft::response()->setTitle( 'Controller example' );

    // Get requested page from route rule
    $page = Deft::request()->get( 'page' );
    if( empty( $page ) ) {
      $page = 'index';
    } elseif( $page == 'index' )

    // Capture the requested page
    $content = Deft::capture( '' . $page );
    if( is_string( $content ) )
      Deft::response()->setBody( $content );
      Http::status( 404 );

    // Add some more document content
    Deft::response()->prependBody( '<header>header stuff</header>' );
    Deft::response()->appendBody( '<footer>footer stuff</footer>' );

Deft::event()->add( 'init', array( 'Example', 'init' ) );
Deft::event()->add( 'initContent', array( 'Example', 'initContent' ) );

Then on our default page

Deft::response()->prependTitle( __( 'Welcome to index' ) );
Deft::response()->setDescription( __( 'Description of the index page for SEO' ) );

$form = Deft::form()( 'user_post' )->method( 'post' );
$form->add( FormField::Text, 'test' );
$form->add( FormField::InputSubmit );
Welcome to the site!
<?php echo Deft::request()->post( 'test' ) ?>
<?php echo $form ?>

Phrases are wrapped in the __( '...' [, $args, ...] ) function which is influenced by the Language class, this will allow for multi-lingual web apps. The wrapper uses the PHP printf() layout.

You can use Helper methods for input handling and sanitizing against XSS Deft::request()->post( 'postFieldName' ). Be sure to produce output with UTF-8 encoding in mind (default environment) if you plan on adding user input forms. The sanitizing helper methods are designed specifically to work with this encoding, which will support all your language needs anyway.

We’ll want to customize the HTML5 document we are producing, so for the sake of an example lets use the Hook class to do that, adding styles and Viewport preferences…

function addStuff() {
  Deft::response()->setVpWidth( 0 ); // 0 = device-width
  Deft::response()->setVpInitial( 1 );
  Deft::response()->addStyle( DEFT_ASSET_URL . '/master.css' );
  Deft::response()->addStyle( DEFT_ASSET_URL . '/print.css', 'print' );
  Deft::response()->addScript( DEFT_ASSET_URL . '/master.js' );

  // 'google-helper' plugin
  if( class_exists( 'Google' ) )
    Google::addFont( 'Raleway', 400 );
Deft::event()->add( 'beforeDocumentGetHead', 'addStuff' );

which would all together output something like…

<!doctype html>
<html lang="en">
  <meta name="charset" content="utf-8">
  <meta name="viewport" content="width=device-width,initial-width=1,user-scalable=yes">
  <meta name="robots" content="index,follow">
  <meta name="desription" content="Description of the index page for SEO">
  <title>Welcome to index | Controller example</title>
  <link rel="stylesheet" media="all" href="//localhost/content/asset/master.css">
  <link rel="stylesheet" media="all" href="">
  Welcome to the site!
  <form id="user_post" method="post"><div><div><input name="test" type="text"></div></div><div><div><input type="submit"></div></div></form>
  <script type="text/javascript" src="//localhost/content/asset/master.js"></script>

By default, Document uses a HTML5 template called template.html5 which you
can modify, or use filters which allow you to add attributes to the head or body elements using the Filter elementHead and elementBody. The template can be completely overridden by supplying a different template you have created Deft::response()->content( 'plugin.something.different-template' ).


See the document-optimize (combines all local asset styles, scripts and caches the rendered document output for 5 minutes), and google-helper (provides the Google class, to add Google Fonts to the document) plugins for examples.

Plugins live in the /content/plugin directory. To load plugins at Deft runtime, you will need to add the name of the plugin folder or file to the main config, under the setting name of plugins. This setting is stored as an array…

google-helper translates to /content/plugin/google-helper.php or

'plugins' => array(

or programmatically..

$cfg =& Deft::config();
$cfg->set( 'plugins', array( 'google-helper' ) );


  • array import( string $args [, ...] )
    Dot scope paths of a script relative to the libraries directory to include in the Deft environment. translates to /content/lib/path/to/lib.php
  • string getInstanceKey( string $class [, mixed $args] )
    Returns the unique key for the supplied class and arguments.
  • bool havePlugin( string $name )
    Returns loaded state of plugin. 2 = loaded, 1 = not loaded, 0 = does not exist.
  • bool haveInstance( string $key )
    Returns existence of instance by it’s unique key generated with Deft::getInstanceKey()
  • resource newInstance( string $class [, mixed $args] )
    Creates new instance of class with the supplied arguements. Will overwrite if already exists. Does not import.
  • resource get( string $scope [, mixed $args] )
    Returns existing instance for dot scope library path and arguments. Creates new instance and returns if does not exist. Imports libraries as required.
  • resource config( string $path )
    Wrapper for Deft::get( 'config' [, $args] )
  • resource database( array $args )
    Wrapper for Deft::get( 'db' [, $args] )
  • string encode( mixed $args )
    Returns object as an App encoded string. The encoding is an ASCII string translation unique to each framework installation, stored in the main config as secret. Used by the Token class for storing information in sessions and cookies.
  • mixed decode( string $string )
    Returns original object from previously encoded string.
  • mixed capture( string $scope )
    Returns output buffer of a script. Dot scope path relative to the content directory to include. translates to /content/path/to/template.php
  • void log( string $stack, array $args [, bool $replace = false ] )
    Adds log entry to $stack (organized using slashes), with provided $args. Use $replace to overwrite the entire $stack scope.
  • array getLog( [string $stack] )
    Get log entries within the requested $stack.
  • void error( mixed $args )
    Stop the app with an error message. $args are passed through __()

Deft::config() class. Accessed using Deft::config( [string $scope] )

Dot scope path of the config to load, relative to the content directory. translates to /content/path/to/config.php

  • mixed get( string $name, mixed $fallback )
    Gets value from the config.
  • void set( string|array $name [, mixed $value] )
    Sets value in config, $name can be supplied as an array of values.
  • bool remove( string $name )
    Removes a value from config.
  • bool save()
    Overwrites the config file with the current values.
  • bool getPath()
    Local path of the config file.
  • bool exists()
    Indicates if the config exists.
  • bool isReadable()
    Indicates if the config file is accessible.
  • bool isEmpty()
    Indicates if the config file has any values.

Deft::database() class. Accessed using Deft::database( [array $args] )

  • null|object lastError()
    Returns PDOException object of last error.
  • string sql( $args[, ...] )
    Returns parsed and sanitized query string.
  • resource query( $args[, ...] )
    Executes query on the database. This function passes query through sql() if conditional.
  • int insert( string $table, array $values )
    Builds INSERT query and passes to query()
  • int update( string $table, array $values, array $conditions )
    Builds UPDATE query and passes to query()
  • int delete( string $table, array $conditions )
    Builds DELETE query and passes to query()
  • string getField( int $index )
    Returns value of column $index of current row.
  • array getRow( $args[, ...] )
    Returns the first row from the query result.
  • array getRows( $args[, ...] )
    Returns all rows from the query result.
  • int numRows( $args[, ...] )
    Returns the total number of rows in the query result.
  • int affectedRows()
    Returns the number of rows affected by UPDATE, or DELETE queries.
  • int getInsertId()
    Returns the PRIMARY_KEY of the last INSERT query.


Documentation for this class has not yet been added.


  • bool add( string $name, callback $function, $priority = 10, $arg_count = 1 )
    Adds callback $function to a filter called $name, at a priority of $priority, callback supports up to $args_count arguments.
  • bool|array get( $name )
    Returns the array of functions for provided filter by priority.
  • bool clear( string $name, callback $function )
    Removes callback $function from filter point $name
  • mixed exec( string $name [, $args, ...] )
    Fires filter $name callbacks in order of priority.


  • string newCSRF()
    Creates a new token hash for CSRF use.
  • string getCSRF()
    Retrieves the unique token hash for CSRF prevention use. Creates one if does not exist.
  • Documentation for this class has not yet been completed.


  • bool add( string $name, callback $function, $priority = 10 )
    Adds callback $function to a hook called $name, at a priority of $priority.
  • bool|array get( $name )
    Returns the array of functions for provided filter by priority.
  • bool clear( string $name, callback $function )
    Removes callback $function from hook point $name
  • bool exec( string $name )
    Fires hook $name callbacks in order of priority.


Documentation for this class has not yet been added.


  • string getHash()
    Returns the token hash unique to the App framework, used as the name of the session and cookie.
  • bool save()
    Passes all data through Deft::encode() and stores in the PHP session.
  • bool saveCookie()
    Passes through save() and sets user cookie.
  • void clear()
    Clears all data and runs through saveCookie()
  • void set( string|array $name, mixed $value )
    Sets entry $name with $value, or pass an an array to $name
  • mixed get( string $name )
    Gets entry $name from the data.
  • bool hasData()
    Indicates if there is any data on the token.
  • bool isFromCookie()
    Indicates if the data was retrieved from cookie.

0 thoughts on “Deft, a PHP micro-framework”

  1. Hi, this is a comment.
    To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard.
    Commenter avatars come from Gravatar.

Leave a Reply

Your email address will not be published. Required fields are marked *