Jump to content


DB abstraction layer


8 replies to this topic

#1 Kuulest

    Advanced Member

  • Members
  • PipPipPip
  • 326 posts

Posted 29 May 2002 - 04:30 PM

Before I include my mysql wrapper code I want to talk about
reasons of its existance. So why to use abstraction layers?
Answer is quite straightforward - to make complex things
simple.
Indeed when you are working with database (vendor is
irrelevant) tasks you perform are similar (at least if we are
talking about same db model, here relational one). You open
connection, manipulate data or db structure, close connection.
So by abstracting from actual database or vendor you can
write code which would handle all this tasks on any db.

What I present below is not a *real* db abstraction layer but
merely db wrapper ie I wrapped mysql functions with my own generic
ones so that if one day I would have to make my code work with
PostgreSQL, for example, I would have to make changes
in one file only (wrapper file).

So here is the code:
Note that several constants must be declared.
mysql_db.inc
<?
/*
+------------------------------------------------------------------------------+
|   Authors: Victor Farazdagi (Kuulest)			                           |
+------------------------------------------------------------------------------+
*/
   /**
   *MySQL wrapper functions:
   */
  function db_connect() {
    global $db_link;
    if (isset($db_link)) return $db_link;
    if (USE_PCONNECT) @$db_link = mysql_pconnect(DB_HOST, DB_LOGIN, DB_PASS);
    else @$db_link = mysql_connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD);

    if ($db_link) @mysql_select_db(DB_DATABASE);
    return $db_link;
  }

  function db_close() {
    global $db_link;

    $result = mysql_close($db_link);
    
    return $result;
  }

  function db_error() {
    global $db_link;
   
   return mysql_error();
  }

  function db_query($db_query) {
    global $db_link;

    $result = mysql_query($db_query, $db_link);

    return $result;
  }

  function db_fetch_array($db_query) {

    $result = mysql_fetch_array($db_query);

    return $result;
  }
   
  function db_fetch_row($db_query) {

    $result = mysql_fetch_row($db_query);

    return $result;
  }
  function db_num_rows($db_query) {

    $result = mysql_num_rows($db_query);

    return $result;
  }

  function db_data_seek($db_query, $row_number) {

    $result = mysql_data_seek($db_query, $row_number);

    return $result;
  }

  function db_insert_id() {

    $result = mysql_insert_id();

    return $result;
  }

  function db_free_result($db_query) {

    $result = mysql_free_result($db_query);

    return $result;
  }
?>


So, since I use db_connect() instead of mysql_connect(),
for example, I would be able to connect to another
kind of db simply by changing code in my wrapper.
Therefore, shifting from one db to another will be merely
reduced to including different wrappers for different
databases(mysql_db.inc for MySQL, postgre_db.inc for
PostgreSQL etc)

Hope this gives you an idea,
Any comments are welcome,
Yours Kuulest

#2 heddesheimer

    Advanced Member

  • Members
  • PipPipPip
  • 116 posts

Posted 29 May 2002 - 08:10 PM

Good point Kuulest. I do the same for my code but I'm using a class instead of a function wrapper.

It's the same result but you can store local data (like the link resource or other stuff) within the class to keep things simpler. I use the constructor for the connect and go straight ahead with calls like:
$result = $db->query("select * from table");

Marian

#3 PHPlugin

    Advanced Member

  • Members
  • PipPipPip
  • 487 posts

Posted 08 June 2002 - 06:15 PM

Hi!

I thought with PHP 4.2.x its now not hm .. hoe can I say...

I think global variables are not used anymore?

And Marian,
i want to learn some things about classes!
I can look up all that stuff at php.net,
but there are no examples!
For what do I need them?

Can you post a little code example?

THX!

#4 heddesheimer

    Advanced Member

  • Members
  • PipPipPip
  • 116 posts

Posted 09 June 2002 - 07:20 AM

Articles on Classes in PHP:
http://phpbuilder.co...od19990601.php3

http://www.zorka.com/index.php/phptutorial...n/event=index/5

http://www.devshed.com/Server_Side/PHP/Bac...lass/page1.html

#5 Guest_cr33p_*

  • Guests

Posted 13 June 2002 - 07:21 PM

I use the same thing as a class. But in my class there is a number of functions that simplifies most common functions. There are function like extractRow() which fetches array and then extracts all variables so that you can use them without
$row[] = db->fetch_array();
someHowUse($row['fieldname']);

Abstraction class can also give more detailed description of errors.

like
Function dbQuery($query, $link_id = '') {
   if (empty($link_id)) $link_id = (empty($this->db_link_id) ? $this->dbConnect() : $this->db_link_id);
   if ($this->DEBUG == 'On') {
      echo   '<hr>Function name: <b>dbQuery($query)</b><br>'
            .'$query = '.$query.'<hr>';
   }
   if (empty($query)) { return FALSE;}
   if ($this->QUERY_DEBUG == 'Off') {
      $result = @mysql_query($query, $link_id) or die ('Query failed: Please contact the webmaster');
   } else {
      $result = @mysql_query($query, $link_id) or die('Query failed: '
                  .'<li>errorno='.mysql_errno()
                  .'<li>error='.mysql_error()
                  .'<li>query='.$query);
   }
   return $result;
}

DEBUG and QUERY_DEBUG are class constants.
On production stage they QUERY_DEBUG = "on"
When the project is complete I set them both to "Off"
DEBUG is used only to troubleshoot scripts, to know where the error has occured.

#6 Guest_nickuk_*

  • Guests

Posted 14 January 2003 - 06:05 PM

hi ppl,

Just wondered if i could get some feedback on a class i've been working on below for database interaction...it's my first stab at working with objects and i wondered if anyone could see any bad coding or ways to improve it :)
at the moment it only has the main tasks i need to perform in my projects but there are things that could be added. i've spent a cpl of days on it so should i continue or give up now lol

<?
#######
# Author and copyright Nicholas Bennett
# Web: [url=http://www.nclbennett.tk]http://www.nclbennett.tk[/url]
# Email: nclbennett@hotmail.com
# Created: 10/01/03
# Version: 1.0.0
#######

if(!defined("DB_LAYER"))
{
   define("DB_LAYER", true);

   class db
   {
	  var $conn_id;   // Hold the MySQL link identifier.
	  var $rs;	  // Holds the result set and all associated info

	  /**
	   * db::db()
	   *
	   * @param $server string
	   * @param $username string
	   * @param $password string
	   * @param $database string
	   * @param $persistent true or false
	   * @return a positive MySQL link identifier on success, or display a message on error.
	   */
	  function db($host, $username, $password, $database, $persistent = true)
	  {
		 $this->persistant = $persistant;
		 if( $this->persistant )
		 {
			$this->conn_id = @mysql_pconnect($host, $username, $password);
		 }
		 else
		 {
			$this->conn_id = @mysql_connect($host, $username, $password);
		 }
		 if( $this->conn_id )
		 {
			if( $database != "" )
			{
			   if(@mysql_select_db($database, $this->conn_id))
			   {
				  return $this->conn_id;
			   }
			   else
			   {
				  if($this->persistant)
				  {
					 @mysql_close($this->conn_id);
				  }
				  $this->error("Failed to connect to database");
			   }
			}
			else
			{
			   $this->error("No database selected");
			}
		 }
		 else
		 {
			$this->error("Could not connect to server");
		 }
	  }

	  /**
	   * db::query()
	   * 
	   * @param $result_id string
	   * @param $query string
	   * @return TRUE on sucess, or FALSE on error.
	   */
	  function query($result_id, $query)
	  {
		 if( $this->conn_id )
		 {
			$this->rs['sql'][$result_id] = $query;
			$this->rs['result'][$result_id] = @mysql_query($query, $this->conn_id);
			$this->rs['err_msg'][$result_id] = @mysql_error($this->conn_id);
			$this->rs['err_no'][$result_id] = @mysql_errno($this->conn_id);
			if( $this->rs['result'][$result_id] )
			{
			   $this->rs['num_rows'][$result_id] = @mysql_num_rows($this->rs['result'][$result_id]);

			   // If there was an insert, delete or update see how many rows were affected
			   // (Also, If there there was an insert take note of the insert_id)
			   $query_type = array("insert","delete","update");

			   foreach ( $query_type as $word )
			   {
				  if ( preg_match("/^$word/i", $query) )
				  {
					 $this->rs['affected'][$result_id] = @mysql_affected_rows($this->conn_id);
					 if ( $word == "insert" )
					 {
						$this->rs['inserted_id'][$result_id] = @mysql_insert_id($this->conn_id);
					 }
				  }
			   }
			  return true;
			}
		 }
		 else
		 {
			return false;
		 }
	  }

	  /**
	   * db::result()
	   * 
	   * @param $query
	   * @return 
	   */
	  function result($query)
	  {
		 if( $this->conn_id )
		 {
			return @mysql_result(mysql_query($query), 0);
		 }
	    return false;
	  }

	  /**
	   * db::getRow()
	   * 
	   * @param $result_id
	   * @param $result_type
	   * @return an array that corresponds to the fetched row, or FALSE if there are no more rows.
	   */
	  function getRow($result_id, $result_type=MYSQL_ASSOC)
	  {
		 if( $this->conn_id && $this->rs['result'][$result_id] )
		 {
			return @mysql_fetch_array($this->rs['result'][$result_id], $result_type);
		 }
	    return false;
	  }

	  /**
	   * db::close()
	   * Free the result sets from memory and close the connection if not a persistant connection
	   * @return TRUE on success, or FALSE on error.
	   */
	  function close()
	  {
		 if( $this->conn_id )
		 {
			if( $this->rs )
			{
			   if( is_array($this->rs) )
			   {
				  while(list($k,) = each($this->rs['result']))
				  {
					 @mysql_free_result($this->rs['result'][$k]);
				  }
			   }
			   else
			   {
				  @mysql_free_result($this->rs['result']);
			   }
			}
			if( !$this->persistent )
			{
			   $result = @mysql_close($this->conn_id);
			}
			return true;
		 }
		 else
		 {
			return false;
		 }
	  }

	  /**
	   * db::error()
	   * 
	   * @param $msg
	   * @return HALT script and display error message.
	   */
	  function error($msg){
		 die(sprintf("<H3>Sorry we seem to be experiencing technical difficulties displaying the information you requested. The error encountered was <i>%s</i>.<BR>Please reload this page or try again later.</H3>", $msg));
	  }

	  /**
	   * db::affected()
	   * 
	   * @param $result_id
	   * @return the number of affected rows of the last query sent to the MySQL server
	   */
	  function affected($result_id)
	  {
		 return $this->rs['affected'][$result_id];
	  }
	  /**
	   * db::num_rows()
	   * 
	   * @param $result_id
	   * @return the number of rows in a result set.
	   */
	  function num_rows($result_id)
	  {
		 return $this->rs['num_rows'][$result_id];
	  }
	  /**
	   * db::inserted_id()
	   * 
	   * @param $result_id string
	   * @return the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
	   */
	  function inserted_id($result_id)
	  {
		 return $this->rs['inserted_id'][$result_id];
	  }

   } // End of db class

} // End of not defined

?>

example:

<?

// Create the database object
$db = new db("localhost", "username", "password", "dbname", false);

// send a query to the mysql server assign the query name as query1
// reason for this is to allow more than one query and not overwrite the previous one
$db->query("query1", "SELECT firstname, lastname FROM TABLE1");

while($row = $db->getRow("query1")){
     echo($row['firstname']." ".$row['lastname']);
}

// close connection and free up memory
$db->close();
?>

once again thanks in advanced for any feedback, much appreciated :thumb:

#7 Guest_poff_*

  • Guests

Posted 24 August 2003 - 09:23 AM

Wow guys.

Aren't you just re-inventing the wheel?

Try out PEAR::DB

It's done and bundled with php now.

#8 Guest_stodge_*

  • Guests

Posted 05 September 2003 - 02:48 AM

This is how I use my database class:

$DatabaseManager = &wsDatabaseManager::GetInstance();

// Retrieve a connection to the database.
$Connection = $DatabaseManager->GetConnection();

// Perform the query from the string.
$rs = $Connection->ExecuteQuery($q);

I specify the database driver to use in the config file. That way the driver can be switched in the config file and seamlessly a different database can be used.

Essentially you retrieve a connection from the DatabaseManager, and you execute queries and updates through the connection. A wsQueryResultSet or wsUpdateResultSet is returned accordingly.

My aim was to completely hide the interaction between PHP and mySQL from the developer.

Here's an example from my News program. It retrieves the latest items from the database and stores them for the "theme engine" (simplified engine I must say!) to retrieve and display them.

	function &FindLatestNews($limit)
	{
  // Return an array of all of the pages, grouped by name.
  $config = &wsConfig::GetInstance();
  $prefix = $config->GetValue("table_name_prefix");

  $q =    "select * from " . $prefix .
    "news order by timestamp desc limit $limit";

  // Retrieve the instance of the database manager.
  $DatabaseManager = &wsDatabaseManager::GetInstance();

  // Retrieve a connection to the database.
  $Connection = $DatabaseManager->GetConnection();

   // Perform the query from the string.
  $rs = $Connection->ExecuteQuery($q);

  $items = new wsArray();

  $NewsObject = $rs->GetObject();
  
  while ($NewsObject)
  {
  	$newsItem = new wsNews();
  	$newsItem->PopulateFrom($NewsObject);
  	$newsItem->ClearUpdate();
  	$items->PushBack($newsItem);
  	
  	$NewsObject = $rs->GetObject();
  }
  
  return $items;
	}

Comments welcome of course!

Cheers
stodge (not logged in)

#9 Guest_yaffa l._*

  • Guests

Posted 26 July 2005 - 03:35 AM

i need to perform the following code:

<?php
  $db = new COM("ADODB.Connection");
  $dsn = "DRIVER={MySQL ODBC 3.51 Driver}; SERVER=ttzzyy;DATABASE=xy;UID=z;PWD=z;";
  $db->Open($dsn);

  $rs = $db->Execute("SELECT * FROM who", $db);

while ($row = mysql_fetch_array($rs))

{
     echo $rs->Fields['lon']->Value."<BR>";
     $rs->MoveNext();
 
}

when i do this i am told Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource

i nkow that the mysql_fetch_array is wrong but i dont know what to do.  any ideas?





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users