Skip to content


Writing a Php5 Mvc Framework Part 6: Flexible db connection, Load Css and Js files, Creating Front Controller, doing Method Overridding and Obullo style writing

Writing a Php5 Mvc Framework Part 6: Flexible db connection, Load Css and Js files,
Creating Front Controller, doing Method Overridding and Obullo style writing

Forget all other old parts because of ssc pattern is depreciated, very silly think ! Because of it has got a lot of disadvantages, but take it easy we learnt how to develop a framework writing a deprecated pattern :) .Please don’t use this framework before releasing the beta version.

The most important thing in this part we will learn the Obullo style writing.

Alpha 8 version changes:
- SSC pattern depreciated and removed from the framework , we use loader class as static from now on
- renamed first /controllers dir as /directories
- changed common.php get_config() function, chaged config.php file.
- added multiple db connection
- integrated css, script and js loader functions changed
- renamed SSC class as Ob class, added new Obullo class, Library Class depraciated.
- added OB_Front Controller Class and added User/Front_Contoller class for method overridding
- added obullo_style_writing option to config.php file.

Directory Structure:

Directory structure changed

Directory structure changed

Updates about directory structure
We have three diferent directories,

application/directories/ this folder contains application views, models, library, script files relating to called controller.

Directory functions:

Function Directory Description
loader::helper() .application/directories/{$controller}/helpers/ load helper file from called controller dir
loader::lib() .application/directories/{$controller}/libraries/ load library file from called controller dir
loader::lang() .application/directories/{$controller}/lang/ load language file from called controller dir
loader::model() .application/directories/{$controller}/models/ load model file from called controller dir
loader::script() .application/directories/{$controller}/scripts/ load script file from called controller dir
loader::view() .application/directories/{$controller}/views/ load view file from called controller dir
loader::css() .application/directories/{$controller}/views/css/ load .css file from called controller dir

 

- aplication/ this folder contains application views, language, models, library and script files.
Loading the files from application folders means ‘common application files’ who want these files use for different controllers.

Aplication functions:

Function Directory Description
loader::app_helper() .application/helpers/ load common helper file from /application dir
loader::app_lib() .application/libraries/ load common library file from /application dir
loader::app_lang() .application/language/ load common lang file from /application dir
loader::app_model() .application/models/ load common model file from /application dir
loader::app_script() .application/scripts/ load common script file from /application dir
loader::app_view() .application/views/ load common view file from /application dir

 

- base/ this folder just contains core files of the framework.
You can’t do any changes in this folder.This is for framework flexibility, when the framework go up the next version you just overwrite new files to /base folder.

 

Base functions:

Function Directory Description
loader::base_helper() .base/helpers/ load base (core) helper file from /base dir
loader::base_lib() .base/libraries/ load base (core) library file from /base dir
loader::base_lang() .base/lang/ load base (core) language file from /base dir
loader::base_script() .base/scripts/ load base (core) script file from /base dir

 

- source/ this folder just contains resource files like /images, /css and /js files.

Source functions:

Function Directory Description
loader::source_js() .source/js/ load js file from /source dir
loader::source_css() .source/css/ load css file from /source dir

 

Flexible get_cofig() function:

get_config() function now is very flexible, we can get all configuration files via get_static() method we use it like this

get_config( $config_filename, $variable);

forexample we want to get $robots config variable from application/config/user_agent.php file we just write config file name and variable

get_config(‘user_agent’, ‘robots’);

if config file name and config variable name is same you don’t need to write variable name.

get_config(‘config’);

<?php

/**
* Loads the (static) configuration or language files.
*
* @access    private
* @author    Ersin Güvenç
* @param     string $filename file name
* @param     string $var variable of the file
* @param     string $folder folder of the file
* @version   0.1
* @version   0.2 added $config_name param
* @version   0.3 added $var variable
* @version   0.4 renamed function as get_static ,renamed $config_name as $filename, added $folder param
* @return    array
*/
function get_static($filename = 'config', $var = '', $folder = '')
{
    static $static = array();

    if ( ! isset($static[$filename]))
    {
        if ( ! file_exists($folder.DS.$filename.EXT))
        throw new CommonException('The static file '.DS.$folder.$filename.EXT.' does not exist.');

        require($folder.DS.$filename.EXT);

        if($var == '') $var = &$filename;

        if ( ! isset($$var) OR ! is_array($$var))
        throw new CommonException('The static file '.DS.$folder.$filename.EXT.' file does not appear to be formatted correctly.');

        $static[$filename] =& $$var;
     }

    return $static[$filename];
}

/**
* Get config file.
*
* @param    string $filename
* @param    string $var
* @return   array
*/
function get_config($filename = 'config', $var = '')
{
    return get_static($filename, $var, 'application'.DS.'config');
}

$config = get_config('user_agents', 'robots');  //  get $robots variable from application/config/user_agent.php
print_r($config);

// output
// Array ( [googlebot] => Googlebot [msnbot] => MSNBot [slurp] => Inktomi Slurp [yahoo] => Yahoo [askjeeves] => AskJeeves [fastcrawler] => FastCrawler [infoseek] => InfoSeek Robot 1.0 [lycos] => Lycos )

$database = get_config('database');  //  get $database variable from application/config/database.php
print_r($database['db']);

// output
// Array ( [hostname] => localhost [username] => root [password] => [database] => example_db [dbdriver] => mysql [dbh_port] => [char_set] => utf8 )

?>

Multiple Db Connection:
Multiple connection very flexible because of you can change the db variable and anything what you want.Open your /config/database.php file and add your second database config.


<?php
if( !defined('BASE') ) exit('Access Denied!');

/**
 * Obullo Framework (c) 2009.
 *
 * PHP5 MVC-Min Software for PHP 5.2.4 or newer
 * Derived from Code Igniter
 *
 * @package         obullo
 * @author          obullo.com
 * @copyright       Ersin Güvenç (c) 2009.
 * @since           Version 1.0
 * @filesource
 * @license
 */

$database['system']['active_record'] = TRUE;

$database['db']['hostname'] = "localhost";
$database['db']['username'] = "root";
$database['db']['password'] = "";
$database['db']['database'] = "example_db";
$database['db']['dbdriver'] = "mysql";
$database['db']['dbh_port'] = "";
$database['db']['char_set'] = "utf8";

// second database
$database['db2']['hostname'] = "localhost";
$database['db2']['username'] = "root";
$database['db2']['password'] = "";
$database['db2']['database'] = "texminator";
$database['db2']['dbdriver'] = "mysql";
$database['db2']['dbh_port'] = "";
$database['db2']['char_set'] = "utf8";

//----------- config/database.php ---------------//

?>

Now you can use your db2 connection like this


<?php

        // Default Connection from config file
        //------------------- db ----------------------//

        loader::database();       // default static connection

        $this->db->query('SELECT * FROM articles');
        $result = $this->db->all(assoc);

        print_r($result);
        echo '<br /><br />';

        // Custom Connection from config file
        //------------------- db2 ----------------------//

        loader::database('db2');  // second static connection

        $this->db2->query('SELECT * FROM tr_users');
        $result2 = $this->db2->all(assoc);

        print_r($result2);
        echo '<br /><br />';
?>

This is really good but if you want to a dynamic db connection without touch the db configuration file this solution will save your life.

Look at

<?php

        // Dynamic custom connection
        //------------------- db3 ----------------------//

        $params = array(
            'variable' => 'db3', // this->db3
            'hostname' => 'localhost',
            'username' => 'root',
            'password' => '',
            'database' => 'nested_model',
            'dbdriver' => 'mysql',
            'dbh_port' => '',
            'char_set' => 'utf8',
        );

        loader::database($params); // manual dynamic connection with params

        $this->db3->query('SELECT * FROM category');
        $result3 = $this->db3->all(assoc);

        print_r($result3);
        echo '<br /><br />';

?>

Good, but also you want to get db configration items.
I added a new function called db_item() and its defined in Common.php file.

Call it like this db_item(‘hostname’, ‘db2′);


<?php

echo db_item('username', 'db2');

// output
// root

// or you can get all database config variables
// call the get_config function

$database = get_config('database');

print_r($database['db2']);

// output
// Array ( [hostname] => localhost [username] => root [password] => [database] => texminator [dbdriver] => mysql [dbh_port] => [char_set] => utf8 )

?>

How to load Css and Script files

For loading source file look at run() method

<?php

Class Test extends Controller
{
    public $sample_var = 'this is sample var !';

    function __construct()
    {
        parent::__construct();
        parent::__user();

        loader::base_helper('form');     // load helper from /base directory
        loader::base_helper('url');
    }

    function index()
    {
        loader::base_lang('calendar');
        echo ob::lang('cal_su');

        $this->title_tag = 'This is the default function test/test/index ! (defined in config/routes.php)';  // look at /User folder
        $this->head_tag  = loader::script('test');

        $data['example_var'] = 'example var works !';

        $this->body_tag  = loader::view('view_index',$data);
        loader::app_view('view_base');
    }

    function run()
    {
        $this->head_tag  = loader::source_css(array('obullo','example'));
        $this->head_tag .= loader::source_js('jquery');
        $this->head_tag .= loader::script('test');

        $this->title_tag = 'Im the Test2 Controller !';

        $data['sample_array'] = array('1','2','3','4','5');
        $data['example_var']  = 'Hello World!';

        $this->body_tag = loader::view('view_test',$data);
        loader::app_view('view_base');
    }

} //end of the class.

?>

As you can see all source file stored to $this->head_tag variable.We load the our base view file with
loader::app_view(‘view_base’); function. This function load the view_base.php file from
/application/views/ folder. And we print the $this->head_tag variable in this view.

Creating Front Controller and Method Overridding
If you want to change all core functions without touching the core of the framework we need a
user and base front controllers, i guess front controller required for framework flexibility because of
someone may want to change the calling controller operations, file constants, include functions etc..

I added an OB_Front_Controller class to base folder.


<?php

/**
 * Base Front Controller Class
 *
 * Pre-controller for calling controllers
 *
 * @package       Obullo
 * @subpackage    Base
 * @category      Front Controllers
 * @author        Ersin Güvenç
 * @link
 */
class OB_Front_Controller
{
    /**
    * Constructor
    *
    * Set Front Controller Defaults
    * Suitable for Method Overriding
    *
    * @see http://www.java2s.com/Code/Php/Class/
    * MethodoverrideforRectangleclass.htm
    *
    * @access    public
    */
    public function __construct()
    {
        require (BASE.'config'.DIRECTORY_SEPARATOR.'ob_constants'.EXT);
        require (BASE.'config'.DS.'fl_constants'.EXT);

        require (BASE.'libraries'.DS.'Errors'.EXT);
        require (BASE.'libraries'.DS.'Registry'.EXT);
        require (BASE.'libraries'.DS.'Common'.EXT);
    }

    /**
    * Run the Application
    *
    * @access public
    */
    public function run()
    {
        ini_set('display_errors', config_item('display_errors'));
        date_default_timezone_set(config_item('timezone_set'));

        $Uri    = base_register('URI');
        $Router = base_register('Router');

        header('Content-type: text/html;charset='.config_item('charset')); // UTF-8

        $GLOBALS['d']   = $Router->fetch_directory();   // Get requested directory
        $GLOBALS['c']   = $Router->fetch_class();       // Get requested controller
        $GLOBALS['m']   = $Router->fetch_method();      // Get requested method

        // Check the controller exists or not
        if ( ! file_exists(DIR.$GLOBALS['d'].DS.'controllers'.DS.$GLOBALS['c'].EXT))
        {
            if($Router->query_string) show_404("{$GLOBALS['c']}/{$GLOBALS['m']}");

            throw new CommonException('Unable to load your default controller.
            Please make sure the controller specified in your Routes.php file is valid.');
        }

        require (BASE.'libraries'.DS.'Ob'.EXT);
        require (BASE.'libraries'.DS.'Loader'.EXT);
        require (BASE.'libraries'.DS.'Obullo'.EXT);
        require (BASE.'libraries'.DS.'Controller'.EXT);
        require (BASE.'libraries'.DS.'Model'.EXT);

        // call the controller.
        require (DIR.$GLOBALS['d'].DS.'controllers'.DS.$GLOBALS['c'].EXT);

        if ( ! class_exists($GLOBALS['c'])
            OR $GLOBALS['m'] == 'controller'
            OR strncmp($GLOBALS['m'], '_', 1) == 0
            OR in_array(strtolower($GLOBALS['m']), array_map('strtolower', get_class_methods('Controller')))
            )
        {
            show_404("{$GLOBALS['c']}/{$GLOBALS['m']}");
        }

        // If Everyting ok Declare Called Controller !
        $OB = new $GLOBALS['c']();

        // Check method exist or not
        if ( ! in_array(strtolower($GLOBALS['m']), array_map('strtolower', get_class_methods($OB))))
        {
            show_404("{$GLOBALS['c']}/{$GLOBALS['m']}");
        }

        // Call the requested method.                1       2       3
        // Any URI segments present (besides the directory/class/function)
        // will be passed to the method for convenience
        call_user_func_array(array($OB, $GLOBALS['m']), array_slice($Uri->rsegments, 3));

        // Close the pdo connection ..
        if (class_exists('DB') AND isset($OB->db))
        $OB->db = NULL;

        // Close your custom db connections if its exists !
        // ..$OB->db2 = NULL;
        // .

    }

}  // end class.

/*
|--------------------------------------------------------------------------
| Custom User Front Controller
|--------------------------------------------------------------------------
|
| User can create own Front Controller who want extend
| and do method overridding for base OB_Front_Controller library
|
*/
require('application'.DIRECTORY_SEPARATOR.'user'.DIRECTORY_SEPARATOR.'Front_Controller'.EXT);

// END Front Controller class

/* End of file Front_Controller.php */
/* Location: ./base/libraries/Front_Controller.php */

?>

I also added a Front_Controller class to aplication/User folder.By the way don’t forget you can edit all files in the
/User folder.Open the Front Controller class and overwrite to existing methods.
This known as method overridding in the PHP language.


<?php
if( !defined('BASE') ) exit('Access Denied!');

/**
* This is your front controller class you can change it.
* It extends to Base Front Controller Class.
* You will just do method overriding.
*
* @see  Method Overridding
* @link http://www.java2s.com/Code/Php/Class/
* MethodoverrideforRectangleclass.htm
*/

Class Front_Controller extends OB_Front_Controller
{
    public function __construct()
    {
        // remove parent code
        // copy base/base/OB_Front_Controller  __construct()
        // method contents and paste here !
        // and customize this contents !
        parent::__construct();
    }

    public function run()
    {
        // remove parent code
        // copy base/base/OB_Front_Controller run()
        // method contents and paste here !
        // and customize this contents !
        parent::run();
    }

}
// end of the class.

?>

And this is index.php file its changed.


<?php

/**
|--------------------------------------------------------------------------
| Obullo Framework (c) 2009 - 2010.
|--------------------------------------------------------------------------
|
| @VERSION 1.0 @alpha8  (Current)
|
| PHP5 MVC-min Software for PHP 5.2.4 or newer
| Derived from Code Igniter.
|
| @license public
| @see     license.txt
*/

// --------------------------------------------------------------------

define('EXT',  '.php');
define('BASE', 'base'. DIRECTORY_SEPARATOR);
require(BASE . 'libraries' . DIRECTORY_SEPARATOR . 'Front_Controller.php');

$application = new Front_Controller();
$application->run();

// --------------------------------------------------------------------

?>

Maybe you had trouble why we use the front controller ? Because of someone may want to call the controllers directly or want to setup a rest server, i thought front controller required in a framework if you want to do a rest server outside of the framework structure, just create a Front_controller2 class under the /user folder, copy index.php and save it as server.php in the root. Server.php will be your custom front controller now you can do all rest request to server.php.

Obullo style writing
i added a config['obullo_style_writing'] option into /config/config.php file.While this option is true you can call all base libraries as static.

Look at directories/controllers/test/test_input.php


Class Test_input extends Controller
{
    function __construct()
    {
        parent::__construct();
        parent::__user();

        loader::base_helper('form');
        loader::base_lib('session');
        loader::database();
    }                               

    function index()
    {
        $this->title_tag = 'Input and Session Class Test !! ';
        $this->head_tag  = loader::source_css('example'); 

        session::set('test','this is a test session variable !');

        $this->body_tag  = session::get('test').'<br /><br />';

        if(input::post('username'))
        $this->body_tag .= '<b>username: </b>' . input::post('username');

        $this->body_tag .= form_open('test/test_input');
        $this->body_tag .= form_input('username', input::post('username'));
        $this->body_tag .= form_submit('send','Send');
        $this->body_tag .= form_close();

        loader::app_view('view_base');
    }

} //end of the class.

As you see above the code, we can call all base libraries via library name.In this example we called session and input classes as static.You can call all other base libraries which is exists in the .base/shortcuts folder owing to loader::shortcut() function that called before from .base/obullo/Conrtoller.php file.

This is the .base/obullo/Contoller.php file , all base library shortcut classes automaticaly initialize in there.


 /**
 * Obullo Controller
 *
 * @package        Obullo
 * @subpackage   Base.libraries
 * @category        Libraries
 * @version         1.0
 * @version         1.1 renamed Register as base_register
 * @version         1.2 added 'extends to ob'
 * @version         1.3 added __autoloader()
 * @version         1.4 removed __autoloader()
 * @version         1.5 added loader::shortcut()
 * @deprecated      self::__autoloader()
 */   

Class Controller extends ob
{
    function __construct()
    {
        // warning ! parent::__construct()
        // must be at the top otherwise
        // __autoloader functionality does not work !
        parent::__construct();

        $this->ob_init();

        log_message('debug', "Controller Class Initialized");
    }

    function ob_init()
    {
        $Classes = array(
                            'config'    => 'Config',
                            'input'     => 'Input',
                            'lang'      => 'Lang',
                            'router'    => 'Router',
                            'uri'       => 'URI',
                            'content'   => 'Content',
                        );

        // Auto load default base libraries.
        foreach ($Classes as $public_var => $Class)
        {
            $this->$public_var = base_register($Class);
        }

        // Auto load default base shortcuts
        if(config_item('obullo_style_writing'))
        {
            loader::shortcut('config');
            loader::shortcut('input');
            loader::shortcut('lang');
            loader::shortcut('uri');
        }

    } //end function.

} //end class.

also when you use the loader::base_lib() function in a file, this function also load automaticaly its shortcut file which before defined in the base/shortcut folder.

Quote comes from .base/obullo/loader.php file.

<?php

    /**
    * loader::base_lib();
    *
    * load base libraries from /base folder.
    *
    * @param    mixed $class
    * @param    mixed $static_or_params
    * @return   self::_library()
    */
    public static function base_lib($class, $static_or_params = NULL)
    {
        self::_library($class, $static_or_params, TRUE); 

        self::shortcut($class);
    }

?>

if you still think like ‘this is not enough for me’ , i added a helpers folder to application/user/ directory.You can also call your custom libraries as static from this folder.

Like this

loader::user_helper(‘your_class_helper’);

Quote comes from directories/test/test.php file.


<?php

    function user_helper()
    {
        loader::user_helper('user');     // load class helper from /user directory
        loader::lib('test_lib');   

        echo user::test_lib();

        echo '<br /><br />';
    }

?>

i added a user.php static class to application/user folder that means i can call my test_lib.php library as static that defined before in the directories/test/libraries folder.


<?php
/**
* Class helpers must be static,
* and class name must be contain lowercase letters.
*/
    Class user
    {

        public static function test_lib()
        {
            return ob::instance()->test_lib->test();
        }

    }

?>

Download Obullo Framework 1.0 @alpha8

Many thanks to who read this article , please tell me your ideas or questions .. anything about it..
i will keep your ideas /* copyright @author */ blocks in this framework… ;)

  • Facebook
  • Digg
  • Delicious
  • Google Bookmarks
  • Technorati Favorites
  • Yahoo Bookmarks
  • Webnews
  • Technotizie
  • Taggly
  • Linkatopia
  • Ping
  • StumbleUpon
  • Twitter
  • Share/Bookmark

Posted in php articles.

Tagged with , , , , , , .


2 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. SlammedDime says

    Just in the last two weeks I decided to write my own framework from scratch, not only to help me learn more about OOP in PHP, but to understand exactly what was happening and how. Your tutorials really helped me in writing my own and understanding the inner workings. Thanks for the time/effort you’ve invested.

  2. Boabramah Ernest says

    I think obullo an inspirational thing for all those who begiining to delve into developing thier own framework from scratch. I think the main focus should be to understand the internal working of obullo. I personally have been trying to craps the basics. And hoping to creat some online video tutorials for the community. All those who love to see obullo at the top should help.



Some HTML is OK

or, reply to this post via trackback.