With the basic structure for our Framework in place, it is time to start adding functionality to it. In this tutorial we will create a template manager and database handler, bringing us a step closer to a powerful Framework fit for use for almost any project. If you haven’t already, be sure to review Part 1 of this series first!
MVC: Tweak the structure
In the first part of this tutorial, we created a folder called controllers to store the business logic for our applications. As daok pointed out in a comment, this isn’t the best place for all of the business logic, and that a model should be used to store this logic. Previously, I have always used the database itself as the model in the majority of my applications, however, seperating this out a little more will make our framework even more powerful, and easier to extend.
So, what is MVC? MVC is a design pattern (as was the Singleton and Registry patterns we looked at in part 1), and it stands for Model View Controller, and the aim of this pattern is to seperate the business logic, user interface actions and the user interface from one another. Although we are not going to do anything with our models and controllers just yet, let’s update our frameworks folder structure to include the “models” folder. The model will contain the main business logic, and the controller will deal with user interaction (e.g. submitting data, such as a comment). NB: Our __autoload function does not need to be changed.

Database Handler
Most websites and web applications which make use of PHP also make use of a database engine, such as MySQL. If we keep all of our database related functions in the same place, then we can (in theory) easily change the database engine we use. We can also make certain operations easier, such as inserting records, updating records or deleting records from the database. It can also make it easier when dealing with multiple database connections.
So…what should our database handler do:
- Manage connections to the database
- Try to provide some level of abstraction from the database
- Cache queries so we can use them later
- Make common database operations easier
Let’s look at the code for our database handler, then we will discuss it afterwards.
<?php
/**
* Database management and access class
* This is a very basic level of abstraction
*/
class database {
/**
* Allows multiple database connections
* probably not used very often by many applications, but still useful
*/
private $connections = array();
/**
* Tells the DB object which connection to use
* setActiveConnection($id) allows us to change this
*/
private $activeConnection = 0;
/**
* Queries which have been executed and then "saved for later"
*/
private $queryCache = array();
/**
* Data which has been prepared and then "saved for later"
*/
private $dataCache = array();
/**
* Record of the last query
*/
private $last;
/**
* Hello
*/
public function __construct()
{
}
/**
* Create a new database connection
* @param String database hostname
* @param String database username
* @param String database password
* @param String database we are using
* @return int the id of the new connection
*/
public function newConnection( $host, $user, $password, $database )
{
$this->connections[] = new mysqli( $host, $user, $password, $database );
$connection_id = count( $this->connections )-1;
if( mysqli_connect_errno() )
{
trigger_error('Error connecting to host. '.$this->connections[$connection_id]->error, E_USER_ERROR);
}
return $connection_id;
}
/**
* Close the active connection
* @return void
*/
public function closeConnection()
{
$this->connections[$this->activeConnection]->close();
}
/**
* Change which database connection is actively used for the next operation
* @param int the new connection id
* @return void
*/
public function setActiveConnection( int $new )
{
$this->activeConnection = $new;
}
/**
* Store a query in the query cache for processing later
* @param String the query string
* @return the pointed to the query in the cache
*/
public function cacheQuery( $queryStr )
{
if( !$result = $this->connections[$this->activeConnection]->query( $queryStr ) )
{
trigger_error('Error executing and caching query: '.$this->connections[$this->activeConnection]->error, E_USER_ERROR);
return -1;
}
else
{
$this->queryCache[] = $result;
return count($this->queryCache)-1;
}
}
/**
* Get the number of rows from the cache
* @param int the query cache pointer
* @return int the number of rows
*/
public function numRowsFromCache( $cache_id )
{
return $this->queryCache[$cache_id]->num_rows;
}
/**
* Get the rows from a cached query
* @param int the query cache pointer
* @return array the row
*/
public function resultsFromCache( $cache_id )
{
return $this->queryCache[$cache_id]->fetch_array(MYSQLI_ASSOC);
}
/**
* Store some data in a cache for later
* @param array the data
* @return int the pointed to the array in the data cache
*/
public function cacheData( $data )
{
$this->dataCache[] = $data;
return count( $this->dataCache )-1;
}
/**
* Get data from the data cache
* @param int data cache pointed
* @return array the data
*/
public function dataFromCache( $cache_id )
{
return $this->dataCache[$cache_id];
}
/**
* Delete records from the database
* @param String the table to remove rows from
* @param String the condition for which rows are to be removed
* @param int the number of rows to be removed
* @return void
*/
public function deleteRecords( $table, $condition, $limit )
{
$limit = ( $limit == '' ) ? '' : ' LIMIT ' . $limit;
$delete = "DELETE FROM {$table} WHERE {$condition} {$limit}";
$this->executeQuery( $delete );
}
/**
* Update records in the database
* @param String the table
* @param array of changes field => value
* @param String the condition
* @return bool
*/
public function updateRecords( $table, $changes, $condition )
{
$update = "UPDATE " . $table . " SET ";
foreach( $changes as $field => $value )
{
$update .= "`" . $field . "`='{$value}',";
}
// remove our trailing ,
$update = substr($update, 0, -1);
if( $condition != '' )
{
$update .= "WHERE " . $condition;
}
$this->executeQuery( $update );
return true;
}
/**
* Insert records into the database
* @param String the database table
* @param array data to insert field => value
* @return bool
*/
public function insertRecords( $table, $data )
{
// setup some variables for fields and values
$fields = "";
$values = "";
// populate them
foreach ($data as $f => $v)
{
$fields .= "`$f`,";
$values .= ( is_numeric( $v ) && ( intval( $v ) == $v ) ) ? $v."," : "'$v',";
}
// remove our trailing ,
$fields = substr($fields, 0, -1);
// remove our trailing ,
$values = substr($values, 0, -1);
$insert = "INSERT INTO $table ({$fields}) VALUES({$values})";
$this->executeQuery( $insert );
return true;
}
/**
* Execute a query string
* @param String the query
* @return void
*/
public function executeQuery( $queryStr )
{
if( !$result = $this->connections[$this->activeConnection]->query( $queryStr ) )
{
trigger_error('Error executing query: '.$this->connections[$this->activeConnection]->error, E_USER_ERROR);
}
else
{
$this->last = $result;
}
}
/**
* Get the rows from the most recently executed query, excluding cached queries
* @return array
*/
public function getRows()
{
return $this->last->fetch_array(MYSQLI_ASSOC);
}
/**
* Gets the number of affected rows from the previous query
* @return int the number of affected rows
*/
public function affectedRows()
{
return $this->$this->connections[$this->activeConnection]->affected_rows;
}
/**
* Sanitize data
* @param String the data to be sanitized
* @return String the sanitized data
*/
public function sanitizeData( $data )
{
return $this->connections[$this->activeConnection]->real_escape_string( $data );
}
/**
* Deconstruct the object
* close all of the database connections
*/
public function __deconstruct()
{
foreach( $this->connections as $connection )
{
$connection->close();
}
}
}
?>
Before discussing this in more detail, I should point out that this database handler is very basic. We could provide complete abstraction by not executing queries directly, but instead constructing queries based on paramaters to a query function, and then executing it.
Our delete, insert and update record methods make it easier to perform some common tasks (as I mentioned above we could extend this to do much much more), by only providing information such as the table name, an array of fields and coresponding values, limit values and conditions. Queries can also be “cached” so that we can do things with them later. I find this feature (as well as the ability to “cache” arrays of data) is very handy when combined with a template manager, as we can easily iterate through rows of data and populate it into our templates with little fuss, as you will see when we look at the template manager.
// insert record
$registry->getObject('db')->insertRecords( 'testTable', array('name'=>'Michael' ) );
// update a record
$registry->getObject('db')->updateRecords( 'testTable', array('name'=>'MichaelP' ), 'ID=2' );
// delete a record (well, upto 5 in this case)
$registry->getObject('db')->deleteRecords( 'testTable', "name='MichaelP'", 5 );
We can also work with multiple database connections relatively easily, so long as we switch between the appropriate connections when we need to (although this won’t work when caching queries and retrieving them via our template manager without further work), for example, the code snippet below would allow us to delete records from two databases.
// our second database connection (let's assume we already have a connection to our main DB)
$newConnection = $registry->getObject('db')->newConnection('localhost', 'root', 'password', 'secondDB');
// delete from the primary db connection
$registry->getObject('db')->deleteRecords( 'testTable', "name='MichaelP'", 5 );
// change our active db connection, to allow future queries to be on the second connection
$registry->getObject('db')->setActiveConnection( $newConnection );
// delete from the secondary db connection
$registry->getObject('db')->deleteRecords( 'testTable', "name='MichaelP'", 5 );
// revert the active connection so future queries are on the primary db connection
$registry->getObject('db')->setActiveConnection( 0 );
How might we want to extend this class?
- Full abstraction
- Make use of inheritance, create an interface and have database classes inherit from it, each for different database engines
- Store the connection ID’s along with the query when caching queries
- Improve data sanitizing, depending on the type of data we wish to sanitize
Template Manager
The template manager will handle all of the output, it needs to be able to work with various different template files, replace placeholders (I call them tags) with data and iterate through parts of the template with multiple rows of data from the database.
To make things easier, we will make use of a page class to contain the content related to the page, this also makes it easier for us to extend this and add features to it later. The template manager will manage this object.
<?php
// prevent this file being called directly
if ( ! defined( 'PCAFW' ) )
{
echo 'This file can only be called via the main index.php file, and not directly';
exit();
}
/**
* Template manager class
*/
class template {
private $page;
/**
* Hello!
*/
public function __construct()
{
include( APP_PATH . '/PCARegistry/objects/page.class.php');
$this->page = new Page();
}
/**
* Add a template bit onto our page
* @param String $tag the tag where we insert the template e.g. {hello}
* @param String $bit the template bit (path to file, or just the filename)
* @return void
*/
public function addTemplateBit( $tag, $bit )
{
if( strpos( $bit, 'skins/' ) === false )
{
$bit = 'skins/' . PCARegistry::getSetting('skin') . '/templates/' . $bit;
}
$this->page->addTemplateBit( $tag, $bit );
}
/**
* Put the template bits into our page content
* Updates the pages content
* @return void
*/
private function replaceBits()
{
$bits = $this->page->getBits();
foreach( $bits as $tag => $template )
{
$templateContent = file_get_contents( $bit );
$newContent = str_replace( '{' . $tag . '}', $templateContent, $this->page->getContent() );
$this->page->setContent( $newContent );
}
}
/**
* Replace tags in our page with content
* @return void
*/
private function replaceTags()
{
// get the tags
$tags = $this->page->getTags();
// go through them all
foreach( $tags as $tag => $data )
{
if( is_array( $data ) )
{
if( $data[0] == 'SQL' )
{
// it is a cached query...replace DB tags
$this->replaceDBTags( $tag, $data[1] );
}
elseif( $data[0] == 'DATA' )
{
// it is some cached data...replace data tags
$this->replaceDataTags( $tag, $data[1] );
}
}
else
{
// replace the content
$newContent = str_replace( '{' . $tag . '}', $data, $this->page->getContent() );
// update the pages content
$this->page->setContent( $newContent );
}
}
}
/**
* Replace content on the page with data from the DB
* @param String $tag the tag defining the area of content
* @param int $cacheId the queries ID in the query cache
* @return void
*/
private function replaceDBTags( $tag, $cacheId )
{
$block = '';
$blockOld = $this->page->getBlock( $tag );
// foreach record relating to the query...
while ($tags = PCARegistry::getObject('db')->resultsFromCache( $cacheId ) )
{
$blockNew = $blockOld;
// create a new block of content with the results replaced into it
foreach ($tags as $ntag => $data)
{
$blockNew = str_replace("{" . $ntag . "}", $data, $blockNew);
}
$block .= $blockNew;
}
$pageContent = $this->page->getContent();
// remove the seperator in the template, cleaner HTML
$newContent = str_replace( '<!-- START ' . $tag . ' -->' . $blockOld . '<!-- END ' . $tag . ' -->', $block, $pageContent );
// update the page content
$this->page->setContent( $newContent );
}
/**
* Replace content on the page with data from the cache
* @param String $tag the tag defining the area of content
* @param int $cacheId the datas ID in the data cache
* @return void
*/
private function replaceDataTags( $tag, $cacheId )
{
$block = $this->page->getBlock( $tag );
$blockOld = $block;
while ($tags = PCARegistry::getObject('db')->dataFromCache( $cacheId ) )
{
foreach ($tags as $tag => $data)
{
$blockNew = $blockOld;
$blockNew = str_replace("{" . $tag . "}", $data, $blockNew);
}
$block .= $blockNew;
}
$pageContent = $this->page->getContent();
$newContent = str_replace( $blockOld, $block, $pageContent );
$this->page->setContent( $newContent );
}
/**
* Get the page object
* @return Object
*/
public function getPage()
{
return $this->page;
}
/**
* Set the content of the page based on a number of templates
* pass template file locations as individual arguments
* @return void
*/
public function buildFromTemplates()
{
$bits = func_get_args();
$content = "";
foreach( $bits as $bit )
{
if( strpos( $bit, 'skins/' ) === false )
{
$bit = 'skins/' . PCARegistry::getSetting('skin') . '/templates/' . $bit;
}
if( file_exists( $bit ) == true )
{
$content .= file_get_contents( $bit );
}
}
$this->page->setContent( $content );
}
/**
* Convert an array of data (i.e. a db row?) to some tags
* @param array the data
* @param string a prefix which is added to field name to create the tag name
* @return void
*/
public function dataToTags( $data, $prefix )
{
foreach( $data as $key => $content )
{
$this->page->addTag( $key.$prefix, $content);
}
}
public function parseTitle()
{
$newContent = str_replace('<title>', '<title>'. $page->getTitle(), $this->page->getContent() );
$this->page->setContent( $newContent );
}
/**
* Parse the page object into some output
* @return void
*/
public function parseOutput()
{
$this->replaceBits();
$this->replaceTags();
$this->parseTitle();
}
}
?>
So, what exactly does this class do?
Creates our page object, and bases it from template files, the page object contains the content and information which is needed to make-up the HTML of the page. We then buildFromTemplate(‘templatefile.tpl.php’, ‘templatefile2.tpl.php’) to get the initial content for our page, this method takes any number of template files as its arguments, and stitches them together in order, useful for header, content and footer templates.
Manages the content associated with the page by helping the page object maintain a record of data to be replaced into the page, and also additional template bits which need to be incorporated into the page (addTemplateBit(‘userbar’,'usertoolsbar.tpl.php’)).
Adds data and content to the page by performing various replace operations on the page content, including retrieving results from a cached query and adding them to the page.
The template file needs to mark within itself where a cached query needs to be retrieved and the data from the query replaced. When the template manager encounters a tag to replace which is a query, it gets the chunk of the page where it needs to iterate through by calling getBlock(‘block’) on the page object. This chunk of content is then copied for each record in the query, and has tags within it replaced with the results from the query. We will take a look at how this looks in the template later in this tutorial.
Template Manager: Page
The page object is managed by the template manager, and it used to contain all of the details related to the page. This leaves the template manager free to manage, while making it easier for us to extend the functionality of this at a later date.
<?php
/**
* This is our page object
* It is a seperate object to allow some interesting extra functionality to be added
* Some ideas: passwording pages, adding page specific css/js files, etc
*/
class page {
// room to grow later?
private $css = array();
private $js = array();
private $bodyTag = '';
private $bodyTagInsert = '';
// future functionality?
private $authorised = true;
private $password = '';
// page elements
private $title = '';
private $tags = array();
private $postParseTags = array();
private $bits = array();
private $content = "";
/**
* Constructor...
*/
function __construct() { }
public function getTitle()
{
return $this->title;
}
public function setPassword( $password )
{
$this->password = $password;
}
public function setTitle( $title )
{
$this->title = $title;
}
public function setContent( $content )
{
$this->content = $content;
}
public function addTag( $key, $data )
{
$this->tags[$key] = $data;
}
public function getTags()
{
return $this->tags;
}
public function addPPTag( $key, $data )
{
$this->postParseTags[$key] = $data;
}
/**
* Get tags to be parsed after the first batch have been parsed
* @return array
*/
public function getPPTags()
{
return $this->postParseTags;
}
/**
* Add a template bit to the page, doesnt actually add the content just yet
* @param String the tag where the template is added
* @param String the template file name
* @return void
*/
public function addTemplateBit( $tag, $bit )
{
$this->bits[ $tag ] = $bit;
}
/**
* Get the template bits to be entered into the page
* @return array the array of template tags and template file names
*/
public function getBits()
{
return $this->bits;
}
/**
* Gets a chunk of page content
* @param String the tag wrapping the block ( <!-- START tag --> block <!-- END tag --> )
* @return String the block of content
*/
public function getBlock( $tag )
{
preg_match ('#<!-- START '. $tag . ' -->(.+?)<!-- END '. $tag . ' -->#si', $this->content, $tor);
$tor = str_replace ('<!-- START '. $tag . ' -->', "", $tor[0]);
$tor = str_replace ('<!-- END ' . $tag . ' -->', "", $tor);
return $tor;
}
public function getContent()
{
return $this->content;
}
}
?>
How can this class be extended and improved?
- PostParseTags: You may wish to have tags replaced after most of the page has been parsed, maybe content in the database contains tags which need to be parsed.
- Passworded pages: Assign a password to a page, check to see if the user has the password in a cookie or a session to allow them to see the page.
- Restricted pages (although we need our authentication components first!)
- Altering the
- Dynamically adding references to javascript and css files based on the page or application.
Load core objects
Now that we have some objects which our registry is going to store for us, we need to tell the registry which objects these are. I’ve created a method in the PCARegistry object called loadCoreObjects which (as it says) loads the core objects. This means can can just call this from our index.php file to load the registry with these objects.
public function storeCoreObjects()
{
$this->storeObject('database', 'db' );
$this->storeObject('template', 'template' );
}
This method can be altered later to encorporate the other core objects the registry should load, of course there may be objects which we want our registry to manage, but only depending on the application the framework is used for. These objects would be loaded outside of this method.
Some Data
So that we can demonstrate the new features added to our framework, we need a database to make use of the database handler, and some of the template management functions (where we replace a block of content with the rows in the database).
The demonstration site we will make with our framework by the end of this series of tutorials is a website with a members directory, so let’s make a very basic database table for members profiles, containing an ID, name, and email address.

Obviously, we need a few rows of data in this table!
A quick template
In order for anything to be displayed, we need a basic template, where we will list the data from our members table.
<html>
<head>
<title> Powered by PCA Framework</title>
</head>
<body>
<h1>Our Members</h1>
<p>Below is a list of our members:</p>
<ul>
<!-- START members -->
<li>{name} {email}</li>
<!-- END members -->
</ul>
</body>
</html>
The START members and END members HTML comments denote the members block (which is obtained via the getBlock() method on the page), this is where the template manager will iterate through the records in the database and display them.
Framework in use
Now, we need to bring this all together, with our index.php file:
// require our registry
require_once('PCARegistry/pcaregistry.class.php');
$registry = PCARegistry::singleton();
// store those core objects
$registry->storeCoreObjects();
// create a database connection
$registry->getObject('db')->newConnection('localhost', 'root', '', 'pcaframework');
// set the default skin setting (we will store these in the database later...)
$registry->storeSetting('default', 'skin');
// populate our page object from a template file
$registry->getObject('template')->buildFromTemplates('main.tpl.php');
// cache a query of our members table
$cache = $registry->getObject('db')->cacheQuery('SELECT * FROM members');
// assign this to the members tag
$registry->getObject('template')->getPage()->addTag('members', array('SQL', $cache) );
// set the page title
$registry->getObject('template')->getPage()->setTitle('Our members');
// parse it all, and spit it out
$registry->getObject('template')->parseOutput();
print $registry->getObject('template')->getPage()->getContent();
If we now view this page in our web browser, the results of the query are displayed on the page:

Coming in part 3…
In part three we will take a slight detour from the development side of our Framework, and look at how to design with our framework in mind, and how to slice up HTML templates so that they are suitable for our framework. When we start to build our first application with our framework, we will look in more detail at some of the workings of these classes. Finally, thank you for your comments last time!
- Subscribe to the NETTUTS RSS Feed for more daily web development tuts and articles.




RoyalSlider – Touch-Enable ... only $12.00 
Great article and comments!! I’ve learned alot from both, but for all those that still don’t get it, Michael summed it up when he said “here is just a method to slot things together, my code should just be used as a guide.” All the other suggestions and improvements are very helpful but lets not bash MP for any short comings of this Tut/framework so far. It’s really just a way to help us structure our apps and make improvements as we each individually see needed!…
@MP – I don’t know if you’ve thought about scalability in the framework. I don’t know alot about it but my friend tells me that it’s useful to code your app from the beginning with one db connection for reads and one for writes, in case you need to have your db servers set up where one is dedicated to writes in the future. Do you have any recommendations for doing that? Although I suppose that with this framework that change should be easy to make in the future should you ever need it, right?
Thanks again, I’m eagerly looking forward to the rest of the series!
Hats off to you guys.
Great stuff. When is the part 3 ..
Ajith
this is really good tutorial…when you will publish the third?
This is a great tutorial but the suspense is killing me, when’s part 3 going to be released?
Ah this is delicious, thank you kindly!
Great! I can’t wait part 3 anymore, please come soon… Thanks
Michael,
I am seriously on the edge of my seat waiting for part 3. I am using a very similar method (much more extended) for my school project which was inspired by your first tut. I can’t wait to implement my designers work into the framework. Any idea when the next tut is coming?
@Joey – Michael’s currently working on it. It shouldn’t be too much longer. :)
Hey!
Great Tut!!! Can’t wait for part 3.
But there is an mistake in the template class / function replaceBits() in line 52:
$templateContent = file_get_contents( $bit );
should be
$templateContent = file_get_contents( $template );
Best regards
r3l4x
we are waiting for part 3 so we can start designing our own framework “”PHPonTrack” :)
thanks for the part 1 and part 2
regards
salman sadiq
Part 3 coming anytime soon?
Great tutorial!
Where is the part 3?
Part 3? Pretty Please!
Hey guys. As soon as Michael sends me Part 3, we’ll post it ASAP!
Hey,
Sorry about the delay everyone, my business partner has written part 3 (as it is design related) but it we have had a busy couple of weeks, I’ve only just finished going through it. It’s just been emailed to Jeffery so hopefully it will be on the site soon.
Just an FYI: I’m going to block write the next few instalments asap, so we don’t have any delays like this again.
Sweet, Michael. Looking forward to reading it. It’s a nice inspiration to learn about design patterns.
Hi Michael,
Thanks a lot, I’m really enjoying this tute and am finding it handy. Looking forward to the rest :)
Heya! It’s been a few weeks since last comment on update? Where’s PT3 lurking? :>
I don’t know, I’m guessing Jeffery is waiting for an empty slot in the tutorials schedule?
Please….. i wait part 3 for weeks, and …..
Any news on part 3??
Hope it comes soon!
I have Part 3 scheduled for next week.
Thanks, this tutorial is fantastic :)
Very useful and education tutorial. You explain it very clearly- really helping me wrap my brain around OOP in PHP. I’ll definitely recommend this series as a must-read to my friends!
Thanks for your hard work and sharing your knowledge with us.
Part 3 should be great.
good job man,
i dont know how you do that but it’s perfect for me, ilike it and waiting, waiting for the great part :). Thank
Great tutorial,
It’s also a good start to understand the capabilities of major frameworks like code igniter and Zend.
This tutorial gives you a great view of the idea behind the MVC structure. Definitly when you are a php rookie.
Greetings from the Netherlands (Groningen)
Please how I call function addTemplateBit ??? If I use in index this one : $registry->getObject(‘template’)->addTemplateBit(‘userbar’,'usertoolsbar.tpl.php’); … and put to template : {userbar} , so nothing displayed. Plsease help I use this framework for my personal CMS system. I so much need this. THANKS !
found a slight typo in the code on line 49 of the template.class.php file you wrote:
$templateContent = file_get_contents($bit);
$bit isn’t defined yet $bits is.
So what’s correct?
How do I use insertRecords()?
Thanks a lot for those tutorials, it’s really interesting to build a framework from scratch!
I’ve just noticed a slight problem with the database class. After destructing the object, the connections will still be opened. This is due to the fact that there isn’t any magic method called __deconstruct. The actual destructor method is __destruct. Your __deconstruct method has to be called explicitly in the code to close the connections, which makes it pretty useless. The reason it doesn’t triggers any errors is because PHP believes you want to call a method __deconstruct and not build a destructor ;)
Still, this is a great tutorial! Looking forward for part IV and V!
without storing the database object how you called it?? will it work?? in the database example..
You sure are the man, i wish you all the best.
Thank you for taking time to show a oop app.
Fantastic article, Michael Peacock. You are my hero. ;)
Just wanted to point out a minor adjustment for those who are integrating their own error reporting into the database class.
In the method: newConnection(), this:
$this->connections[$connection_id]->error
Doesn’t actually return an error – errors that occur when connecting to the database are returned with:
$this->connections[$connection_id]->connect_error
Or before 5.2.9:
mysqli_connect_error()
Great tutorial thanks
a very nice database class indeed. i just noticed that sanitizedata was not used inside the class so we don’t have to call it in the model/controller. is it also a good thing if we use utf8_encode along with sanitizedata. thanks..
ummm help i get this error.
Fatal error: Call to undefined method PCARegistry::storeCoreObjects() in C:\cefx\www\c\index.php on line 37
For my opinion there is a bug in the template.class.php at the function “replaceDataTags”. Parsing output created a endless loop in this function.
That’s how I corrected this function:
private function replaceDataTags( $tag, $cacheId )
{
$block = $this->page->getBlock( $tag );
$blockOld = $block;
$blockNew = $blockOld;
$tags = Registry::getObject(‘db’)->dataFromCache( $cacheId );
foreach($tags as $tag => $data)
{
$blockNew = str_replace(“{” . $tag . “}”, $data, $blockNew);
}
$block = $blockNew;
$pageContent = $this->page->getContent();
$newContent = str_replace( $blockOld, $block, $pageContent );
$this->page->setContent( $newContent );
}
nice tutorial but few things could be improved.
–use magic methods to overload loaded class methods.
–type hinting so stupid bugs don’t pop up out of now where.
–for error reporting and storing and overall greatness of Exceptions should be added .
oh and your useing the oldschool way of the singleton not that it is bad but less of a headache.
public static function singleton
{
if(! self::$instance instanceof self)
{
self::$instance = new self;
}
then in your register/(aka..set function) you can then set the registry instance and make a vokable instance for each class, methods, properties etc…
so when you call your other classes methods/properties/functionilty you can use one key word such as $load or whatever you would like to call all classes/methods/functionaility etc…
this is to make it more userfreandly and easy to understand and work with and will push towards a RAD framework
Great tutorial!
Have you considered adding some live PHP class diagrams to your code? Please think about.
Хорошая статейка!
First, congratulations for a good article. In programming more than in anything else, there are multiple ways to implement functionality and I will indicate here my personal preferences. The example provided in this tutorial is very clear and very practical. In other words it works well for what it is meant to do.
Personally, I tend to isolate functionality into classes. For example, to me, the connection is one thing and the database is another. Some non-database objects may need direct access to the connection without requiring the services of the database object and this is why I prefer the two kept separately.
I will also give my two bobs about templating. In my own work, an object is implemented as visible or not very early in the chain of inheritance. Eventually, the objects know how to write html through a very simple html writer and they can also Show() themselves to a buffer. That buffered output is simply inserted into template files like this Write()?>. it is actually a bit more complicated because my objects are not globals, the Application object is the only object that the template can access. This said, the power of the PHP language itself is very much underestimated when it comes to templating. I see developer going through incredible lengths to make a templating engines do backward somersaults when in reality, a web page is a static page into which you insert html objects at particular locations. If your framework produces objects that can write themselves into html, then the templating exercise becomes very simple. I have incredibly complex objects, for example a grid with sortable columns and pagination connected to a data source (MySQL, flat file, etc.,..) but that complexity has been absorbed through consistent design within the framework and that complex object still results in a simple Write()?> in my templates.
Thanks again for the good work and I hope I have added to the never ending framework debate. I will some day take the time to publish my own framework to increase the pool of ideas out there. I might wait for multiple inheritance to get rid of all the interfaces.
The tags I inserted in my last message were sanitized to the point of not making sense. for example it is not Write() but object->Write
function parseTitle() in template.class.php may not work :)
and anyone can help me know: what’ s bit? what’s tag?
Hello, from already very good site, good post … I just wanted to ask a question ….. I am developing my own framework and there is something I do not understand, what is the engine of the algorithm used to display the data in the view without having to use php script in sight.
For example what I did is: first to open the file with file_get_content lleerlo ();, then I do is create a small algorithm that takes data from my database and use str_replace ($ foo, $ replacer, $ file ) (the $ parameters are the script you put in a comment in sight, $ replacer is the code extract from the database and $ file is the file you read with file_get_content ();) to replace the data I wrote as a comment at the hearing by those in the database … I show them correctly but I include them within the template … greetings and I hope I explained it well … Greetings from Argentina