Skip to content


Creating a PHP5 MVC Framework part4: Integrating CI Active Record to Obullo PDO Class, Routing Impromevents and Advanced Loader Functions

Alpha 3 version Core Changes:

- common.php register_base(); and register(); functions changed.
- OB_DB_active_record class integrated to Obullo DB Class (added CRUD operations Insert, Update, Delete)
- router works like this from now on : /directory/controller/method/params
- /controllers directory structure completely changed
- added /application/resources and /base/views directories
- added new loader functions: loader::base_library(); , loader::base_helper(); , loader::base_view();
- added Library filexibility: user can use “extends Library” or ob::instance() functionality inside the library class.
- added secure “pdo like queries” for DB class

Directory structure:

New Directory Structure

New Directory Structure

Router Impromevents:
We have a new drirectory system each controllers have /models, /views/ and /helpers directory also we can put inside /lang , /js and /scripts directories in the /controllers folder.I will tell them later.

So router functionality changed we call the controllers such as : /directory/controller/method/params, with this way developers can easily edit /models, /views and /helpers files from the /controllers folder

New loader functions:
I guess every Code Igniter developers sometime don’t understand that the ‘application’ and ’system’
library files where does come from ! In Obullo we have separated loader file functions like this..

loader::helper(); // load helper from /application directory
loader::base_helper(); // load helper from /base directory (text, string, file, array etc..)

loader::library(); // load library from /application directory (user libraries)
loader::base_library(); // load library from /base directory (session, email,encrypt etc..)

loader::view(); // load view file from /application directory
loader::base_view(); // load base view files from /base directory (like base html, popup or email msg templates)

And the application doesn’t have to use file_exists() function both of for /base and /applications folders because of we use different codes for call them and we do memory possession.

Look at base view:
this is the base template for every controllers which located in base/views/base_view.php
we put here just common (base) templates.

If a loader function has a prefix like this loader::base_x() that means file comes from /base folder elseif function just loader::x(); and this means file comes from application folder.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Expires" content="Fri, Jan 01 1900 00:00:00 GMT">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Lang" content="en">
<meta name="author" content="">
<meta http-equiv="Reply-to" content="@.com">
<meta name="generator" content="PhpED 5.8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="creation-date" content="01/01/2009">
<meta name="revisit-after" content="15 days">

<title><?php echo $title_tag; ?></title>
<link rel="stylesheet" type="text/css" href="<?= $this->base_url.''.$this->base_css ?>my.css">

</head>

<body>

<?php echo $body_content; ?>

</body>

</html>

and look at /controllers/test/test.php


Class Test extends Controller
{

    public $sample_var  = 'you can use $this->variable from view';
    public $sample_var2 = 'you can use $this->variable from model';    

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

        // top constructor for every controllers.
        parent::__user();

        loader::helper('test');      // load helper from /application/ directory
        loader::base_helper('text'); // load helper from /base directory

        loader::library('mylibrary');
        loader::base_library('cookie');
    }                               

    function index()
    {
        $data = user::header();

        // change the title
        $data['title_tag'] = 'Im the Test Controller !';

        $data['body_content'] = "<br /><br />";
        $data['body_content'].= "<b>Directory:</b> test/ &nbsp;<b>Controller:</b> test/ &nbsp;<b>Method:</b> /run &nbsp;<br /><br />";
        $data['body_content'].= "Click and run test contoller  <a href='http://localhost/obullo/index.php/test/test/run'>  /test/test/run </a>";
        $data['body_content'].= "<br /><br />";

        $data['body_content'].= "<br /><br />";
        $data['body_content'].= "<b>Directory:</b> test/ &nbsp;<b>Controller:</b> test2/ &nbsp;<b>Method:</b> /run  &nbsp;<b>Params:</b> /hello/3 <br /><br />";
        $data['body_content'].= "Click and run test2 contoller  <a href='http://localhost/obullo/index.php/test/test_2/run/hello/3'>  /test/test_2/run/hello/3 </a>";
        $data['body_content'].= "<br /><br />";

        loader::base_view('view_base',$data);
    }

    function run()
    {
        $data = user::header();
        $data['title_tag'] = 'Im the Test2 Controller !';  

        $this->mylibrary->test_ssc();
        //$this->model_test->test();

        // System static function
        echo ob::ip();  

        echo '<br />Run function succesfully works.<br /><br />';

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

        $data['body_content'] = loader::view('view_test',$data,true);
        loader::base_view('view_base',$data);

    }

} //end of the class.

Output of the test controller

output of the test controller

output of the test controller

Using Active Record:
Active record class is very long so i will just tell how we can use it.
None prepared query example


<?php

Class Test_db extends Controller
{

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

        parent::__user();

        loader::database();
    }                                                      

    function index()
    {
        echo '<p></p>';

        // Without prepare (standart query)
        $this->db->select("*");
        $this->db->join('comments','cm_article_id = article_id','left');
        $this->db->where('article_id','1');
        $query = $this->db->get('articles');
        $all = $query->all(assoc);
        print_r($all);

        echo '<br /><br /><b>last query:</b> ' . $this->db->last_query();

     }

/* OUTPUT:
Array ( [0] => Array ( [article_id] => 1 [title] => baslik [article] => metjk kdanf a.di nalf a f [link] => this-the-link [cm_article_id] => 1 [cm_comment] => blablabla test comment.... 1 ) [1] => Array ( [article_id] => 1 [title] => baslik [article] => metjk kdanf a.di nalf a f [link] => this-the-link [cm_article_id] => 1 [cm_comment] => HELLo THis Is test COmment .... 2 ) ) 

last query: SELECT * FROM (articles) LEFT JOIN comments ON cm_article_id = article_id WHERE article_id = '1' 

*/

?>

Active Record prepared query example.
When you use $this->db->prep(); method at the top of your db codes this means you are use pdo prepare functions.And when you use the $this->db->prep() and $this->db->get() function together incase $this->db->get() function will not do a query beacuse of $this->db->excute() function will do the real query..


<?php

Class Test_db extends Controller
{

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

        parent::__user();

        loader::database();
    }                                                      

    function index()
    {
        $this->db->prep();   // tell to db class use pdo prepare
        $this->db->select("*");
        $this->db->join('comments','cm_article_id = article_id','left');
        $this->db->where('article_id',':id');
        $this->db->get('articles'); // when you declare prep() method (at the top)
                                    // db->get() method automatically be passive (its not do a query.)

        $this->db->exec(array(':id'=> 2 )); // this is the real query
        $a = $this->db->all(assoc);
        print_r($a).'<br />';

        // change the value
        $this->db->exec(array(':id'=> 5 ));
        $b = $this->db->all(assoc);
        print_r($b).'<br />';

        echo '<p></p>';
        echo '<b>last query:</b> ' . $this->db->last_query(true);
                                     // true means prepared last query

        echo '<p></p>';

    }

} //end of the class.

/* OUTPUT:
Array ( [0] => Array ( [article_id] => 2 [title] => i See dead peoPle [article] => i see bla bla bla blab bla [link] => i-see-dead-people [cm_article_id] => [cm_comment] => ) ) Array ( [0] => Array ( [article_id] => 5 [title] => çğü._eğş08ÀØñ [article] => [link] => cgu-_egs08aqn-2 [cm_article_id] => [cm_comment] => ) )
last query: SELECT * FROM (articles) LEFT JOIN comments ON cm_article_id = article_id WHERE article_id ='5'
*/

?>

Active Record prepared like query examples:

Using %like% operators and changing the value is the problem with pdo.Look at this article http://stackoverflow.com/questions/583336/how-do-i-create-a-pdo-parameterized-query-with-a-like-statement-in-php

It shows putting the like operators inside of the query but we use it inside of the db class for security reason.

We use 3 like contants for managing ‘like’ queries:

both| = ‘% string %’
before| = ‘% string’
after| = ’string %’


<?php

Class Test_db extends Controller
{

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

        //parent::__user();

        loader::database();
    }                                                      

    function index()
    {
        // we use 3 like contants for managing 'like' queries
        // both|     = '% %'
        // before|   = '% '
        // after|    = ' %'

        $this->db->prep();   // tell to db class use pdo prepare
        $this->db->select("*");
        $this->db->join('comments','cm_article_id = article_id','left');
        $this->db->where('article_id',':id');
        $this->db->like('article',':like');
        $this->db->get('articles');

        $exec = array(
        ':id'   => 2,
        ':like' => 'both|see',  // both| is a predefined constant ('see' is just value)
        );                      // it produces secure '%see%'
        $this->db->exec($exec);

        $a = $this->db->all(assoc);
        print_r($a).'<br />'; 

        echo '<br /><b>last query:</b> '.$this->db->last_query(true);

        // change the value

        echo '<p></p>';

        $exec = array(
        ':id'   => 2,
        ':like' => 'before|bla', // before| is a predefined constant
        );                      // it produces secure '%bla'
        $this->db->exec($exec);

        $a = $this->db->all(assoc);
        print_r($a).'<br />';

        echo '<br /><b>last query:</b> '.$this->db->last_query(true);

        echo '<p></p>';

    }

/* OUTPUT:

Array ( [0] => Array ( [article_id] => 2 [title] => i See dead peoPle [article] => i see bla bla bla blab bla [link] => i-see-dead-people [cm_article_id] => [cm_comment] => ) ) 

last query: SELECT * FROM (articles) LEFT JOIN comments ON cm_article_id = article_id WHERE article_id ='2' AND article LIKE '%see%'
Array ( [0] => Array ( [article_id] => 2 [title] => i See dead peoPle [article] => i see bla bla bla blab bla [link] => i-see-dead-people [cm_article_id] => [cm_comment] => ) ) 

last query: SELECT * FROM (articles) LEFT JOIN comments ON cm_article_id = article_id WHERE article_id ='2' AND article LIKE '%bla'
*/

} //end of the class.

?>

How it works in framework : Look at DB .php exec function at line 1546


<?php

// quoted from DB.php

    /**
    * Execute prepared query
    *
    * @author   Ersin Güvenç
    * @author   you..
    * @version  0.1
    * @version  0.2 added secure like conditions support
    * @param    array $array bindValue or bindParam arrays
    * @param    boolean $bindParam switch Default bindValue
    * @return   void | NULL
    */
    public function exec($array = NULL, $bindParam = FALSE)
    {
        if($this->last_sql != NULL AND $this->exec_count == 0)
        $this->query($this->last_sql);

        // this is a security reason, if developer use like operator,
        // add % % operators inside of exec func.
        if(count($this->ar_like) > 0)
        {
            $new_array = $array;
            $array = array();
            foreach($new_array as $key=>$val)
            {
                if(strpos($val,'both|') === 0)
                {
                    $val = substr(self::escape_like($val),5);
                    $val = '%'."{$val}".'%';
                }

                if(strpos($val,'before|') === 0)
                {
                    $val = substr(self::escape_like($val),7);
                    $val = '%'."{$val}";
                }

                if(strpos($val,'after|') === 0)
                {
                    $val = substr(self::escape_like($val),6);
                    $val = "{$val}".'%';
                }

                $array[$key] = $val;

            }
        }

        if(is_array($array))
        {
            switch ($bindParam)
            {
               case TRUE:
                $this->_bindParams($array);
                $this->last_values = $array;
                 break;

               default:
               $this->_bindValues($array);
               $this->last_values = $array;
            }
        }

        // if no query builded by active record
        // switch to pdo::statement
        $this->PQ->execute();

        // reset prepare variable
        $this->prepare = FALSE;

        ++$this->exec_count; 

        return NULL;
    }

?>

We escape any possible sql injection using with like operators.This function also automatically use pdo bindValues() or bindParams() functions if data come from outside you should just determine incoming data types. (for $_POST, $_GET operations)

like this


<?php
        $this->db->prep();   // tell to db class use pdo prepare
        $this->db->select("*");
        $this->db->join('comments','cm_article_id = article_id','left');
        $this->db->where('article_id',':id');
        $this->db->like('article',':like');
        $this->db->get('articles');

        $exec = array(
        ':id'   => (int)$this->input->post('id'),
        ':like' => 'both|'.(string)$this->input->post('see'),
        );
        $this->db->exec($exec);

        $a = $this->db->all(assoc);
        print_r($a).'<br />'; 

?>

Above the example more secure way.Obullo db class automatically do PDO bindValues() for every prepared query.If developer forgot to set data type of post variables default data type will be string.

Also if you want use PDO bindParams() instead of default bindValues() function, you just use it like this:

$this->db->exec($exec,true); // use bindParams() func

Insert and Update data:
We use pdo exec() functions for update and insert operations in db class and it returns automatically affected rows so you don’t have to do extra effort for fetching affected rows.


<?php

// Insert

        $data = array(
                    'title'       => 'article title..',
                    'description' => 'article description ..',
                    'link'        => 'article-link',
                    );       

        $affected_rows = $this->db->insert('articles',$data);
        echo 'Affected Rows: ' . $affected_rows;

// Output:  1

// Update

        $data = array(
                    'title'       => 'new article title..',
                    'description' => 'new article description ..',
                    'link'        => 'new article-link',
                    );       

        $this->db->where('article_id', 1);  // safe query
        $affected_rows = $this->db->update('articles',$data);
        echo 'Affected Rows: ' . $affected_rows;

// Output:  1

?>

Please login/register for download

Download Obullo Framework 1.0 @alpha 3

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

Posted in php articles.

Tagged with , , , , , , , , .


5 Responses

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

  1. way says

    Fantastic work Ersin, feeling happy to see the next part of your very interesting framework. The next days I will test the new code.
    Keep going dude, you are definitly on the right track ;)

  2. Namaless says

    Good!

    One question: is possible to use php5 autoloading?

  3. admin says

    you means like Code Igniter autoloading system (auto load helpers, libraries..) or you just means php5 __autoload magic functionality ?

  4. Zares says

    The autoloading for php5 is well realized in Madeam framefork…

  5. admin says

    do u know which file used autoload in this framework its very complex ? and someone asked this question before. (look at http://develturk.com/contact/). We use base_register() and register() functions instead of __autoload() you should use this way its more filexible.



Some HTML is OK

or, reply to this post via trackback.



Easy AdSense by Unreal