Object Interaction in PHP: Introduction to Aggregation, part 4

In the fourth and final article in our series covering aggregation in PHP, Alejandro Gervasio reviews the MySQLConnector and Pager classes. He then uses these classes first to build a simple database, then to display some paged results from the database.

Welcome to the final part of the series “Object Interaction in PHP: Introduction to Aggregation.” Certainly, we’ve had some hard work, but it’s been worth the gain. Implementing aggregation in PHP is one of the most powerful techniques currently available to reveal the strengths of object-oriented programming in production environments.

In the previous articles, I’ve introduced in a step-by-step process, and the concept of aggregation in an object-interactive PHP scenario, as well as its multiple possibilities for application in Web projects. The examples shown as I’ve guided you through the learning process have been numerous, ranging from simple, rather primitive interaction between basic classes, to more mature linkage of applications such as MySQL database abstraction and paging classes.

Particularly, jumping back into the flow of the examples given in the second and third parts respectively, where we’ve been strongly advised to develop the “MySQLConnector” abstraction class and the “Pager” paging class, we’re going to build a concrete example. This example will demonstrate how these two classes can be put together to work in existing or future applications.

Before we dive deeper into the example, a brief clarification is in order. The sample classes are designed to show clearly the interaction between objects, something that I personally recommend to novice-intermediate developers. Once you understand the core concepts and the theory, you can do more work with the wealth of open source projects widely available on the Web.

Having said that, let’s implement aggregation in our example. It’s going to be fun!

{mospagebreak title=Assembling classes: a brief look at the “MySQLConnector” class}

As most developers want to move quickly to the nitty-gritty of the source code, let’s show the whole list for our first class. Here’s how it looks:

class MySQLConnector {

            var $conId; // connection identifier

            var $host; // MySQL host

            var $user; // MySQL username

            var $password; // MySQL password

            var $database; // MySQL database

            var $result; // result set

            // constructor

            function MySQLConnector($host,$user,$password,$database){

                        // validate incoming parameters

                        (!empty($host))?$this->host=$host:die(‘Host parameter not valid’);

                        (!empty($user))?$this->user=$user:die(‘User parameter not valid’);

                        (!empty($password))?$this->password=$password:die(‘Password parameter not valid’);

                        (!empty($database))?$this->database=$database:die(‘Database parameter not valid’);

                        // connect to MySQL and select database

                        $this->connectDB();

            }

            // connect to MYSQL server and select database

            function connectDB(){

                        $this->conId=@mysql_connect($this->host,$this->user,$this->password) or die(‘Error connecting to the server ‘.mysql_error());

                        @mysql_select_db($this->database,$this->conId) or die(‘Error selecting database’);

            }

            // perform query

            function performQuery($query){

                        $this->result=@mysql_query($query,$this->conId) or die(‘Error performing query ‘.$query);

            }

            // fetch row

            function fetchRow(){

                        return mysql_fetch_array($this->result,MYSQL_ASSOC);

            }

            // get number of rows

            function getNumRows(){

                        return mysql_num_rows($this->result);

            }

            // get number of affected rows

            function getAffectedRows(){

                        return mysql_affected_rows($this->conId);

            }

            // get ID from last inserted row

            function getInsertID(){

                        return mysql_insert_id($this->conId);

            }

}

I hope that the above listed code refreshed your memory, because it’s been a while since the last time we reviewed this class. Taking a quick look at its definition, we can see that the class shows a few simple methods for connecting to the MySQL server, performing SQL queries, returning table rows and so forth. Also, as mentioned earlier, it presents some methods for calculating the number of rows returned by a query, as well as the rows affected by an INSERT, UPDATE or DELETE query.

Indeed, the class is easily extendable, either by adding new methods according to specific needs, or deriving a subclass, which will inherit all of the methods present in it, by adding more capacity to those present in the base class. The preferred approach will depend on your personal needs.

Fortunately, the advantage of having a set of functional classes is that they can be used as standalone packages or easily plugged into other applications. In this case, let us say we need to use this class to quickly fetch some records. Here’s a quick and dirty implementation to extract some records from a “users” table:

// include the class

require_once ‘mysqlclass.php’;

// instantiate a MySQLConnector object passing to it the connection parameters

$db=&new MySQLConnector(‘host’,'user’,'password’,'database’);

// build the query

$sql=’SELECT fname,lname FROM users’;

// perform query

$db->performQuery($sql);

// display the results

while($row=$db->fetchRow()){

            echo ‘First Name :’.$row['fname'].’ Last Name :’. $row['lname'].’<br />’;

}

// display total number of results

echo ‘Total number of results :’.$db->getNumRows();

The above example shows how easy it is to use the class to perform some of the most common operations associated with MySQL. We instantiated a new “MySQLConnector” class, then performed a simple “SELECT” statement to retrieve records from a hypothetical “users” table, displaying the “firstname” and “lastname” fields included in each table row. After displaying the results, we indicated the total number of rows returned by the query. It’s simple and straightforward.

Now that we’ve gained a more intimate knowledge of the functionality of this class, let’s take the next step, and list the complete source code for the “Pager” class. Just keep reading.

{mospagebreak title=Assembling classes (continued): the “Pager” class at glance}

I’m not going to explain once again how this class works, because it was thoroughly covered in the previous articles in this series. Just let me to say that it aggregates the “MySQLConnector” object, accepting it as a parameter. It later uses the methods offered by this first object to execute SQL queries, display paged result sets and finally, generate the proper paging links.

As usual, here’s the source code:

class Pager {

            var $db; // MySQLConnector object

            var $query; // SQL query

            var $numRecs; // number of records per page

            var $output=”; // dynamic output

            function Pager(&$db,$query,$numRecs=5){

                        $this->db=&$db;

                        (preg_match(“/^SELECT/”,$query))?$this->query=$query:die(‘Invalid query ‘.$query);

                        (is_int($numRecs)&&$numRecs>0)?$this->numRecs=$numRecs:die(‘Invalid number of records’);

            }

            function displayRecords($page){

                        // calculate total number of records using MySQLConnector object

                        if(!$totalRecs=$this->db->getNumRows($this->db->performQuery($this->query))){

                                   die(‘Cannot retrieve records from database’);

                        }

                        // calculate number of pages

                        $numPages=ceil($totalRecs/$this->numRecs);

                        // validate page pointer $page

                        if(!preg_match(“/^d{1,2}$/”,$page)||$page<1||$page>$numPages){

                                   $page=1;

                        }

                        // retrieve result set using MySQLConnector object

                        $this->db->performQuery($this->query.’ LIMIT ‘.($page-1)*$this->numRecs.’,’.$this->numRecs);

                        while($rows=&$this->db->fetchRow()){

                                   foreach($rows as $row){

                                               $this->output.=$row.’&nbsp;’;

                                   }

                                   $this->output.=’<br />’;

                        }

                        $this->output.=’<div>’;

                        // create previous link

                        if($page>1){

                                   $this->output.=’<a href=”‘.$_SERVER['PHP_SELF'].’?page=’.($page-1).’”>&lt;&lt;Previous</a>&nbsp;’;

                        }

                        // create numbered links

                        for($i=1;$i<=$numPages;$i++){

                                   ($i!=$page)?$this->output.=’<a href=”‘.$_SERVER['PHP_SELF'].’?page=’.$i.’”>’.$i.’</a>&nbsp;’:$this->output.=$i.’&nbsp;’;

                        }

                        // create next link

                        if($page<$numPages){

                                   $this->output.=’&nbsp;<a href=”‘.$_SERVER['PHP_SELF'].’?page=’.($page+1).’”>Next&gt;&gt;</a> ‘;

                        }

                        $this->output.=’</div>’;

                        // return generated output

                        return $this->output;

            }

}

The only thing to be pointed out here is how we use the methods of the “MySQLConnector” object to perform the tasks inherent to the “Pager” class. Generally speaking, as a rule of thumb, when one object aggregates another one, the first object is passed as a reference to the second, in order to address some performance issues.

Of course, the possible overhead caused to the server will depend strongly on how applications use the objects involved in the interaction process. For instance, if multiple objects are sharing the same object for connecting to a database, probably the server will suffer a heavy load when the application is used by numerous users. While this may sound like a common sense thing, it’s important to know where to implement aggregation in projects.

Having listed the source code for each developed class, it’s time to build an illustrative example for proper implementation. Just turn the page and keep reading.

{mospagebreak title=Putting the classes to work: a practical example}

To begin with, let’s set up a simple database to store the name of a few articles, and include one simple table. This table will contain three basic fields, called “articleid”, “name” and “site’, which reference respectively, the ID for each article, the story name, and finally the name of the site where the article was published. Sounds simple, doesn’t it?

In first place, let’s create the table “articles”:

CREATE TABLE articles

(

articleidINTUNSIGNED NOT NULLAUTO_INCREMENT PRIMARYKEY,

name VARCHAR(60) NOT NULL,

site VARCHAR(60) NOT NULL

);

As you can see, the table definition shows a simple structure where the first field is the table’s primary key, specified as being of the AUTO_INCREMENT type. The subsequent fields are defined to hold string values, as mentioned before: the article’s name and the site where it was originally published.

What’s our next step? We need to populate the table with some data related to the articles, so let’s perform a multi-row INSERT operation, in order to fill the database table with records:

INSERT INTO articles VALUES

(NULL,”Regular Expressions in JavaScript”,”Devarticles.com”),

(NULL,”Preloading HTML content withCSS”,”Devarticles.com”),

(NULL,”Handling Events with theDOM- Part 1″,”Devarticles.com”),

(NULL,”Handling Events with theDOM- Part 2″,”Devarticles.com”),

(NULL,”Handling Events with theDOM- Part 3″,”Devarticles.com”),

(NULL,”Output Caching with PHP”,”Devshed.com”),

(NULL,”Introduction toCSSPositioning Properties Part 1″,”Devarticles.com”),

(NULL,”Introduction toCSSPositioning Properties Part 2″,”Devarticles.com”),

(NULL,”Introduction toCSSPositioning Properties Part 3″,”Devarticles.com”),

(NULL,”Matching Div heights withCSSand JavaScript”,”Devarticles.com”),

(NULL,”Customizing Styles: User-controlled Style Sheets Part 1″,”Devarticles.com”),

(NULL,”Customizing Styles: User-controlled Style Sheets Part 2″,”Devarticles.com”),

(NULL,”Customizing Styles: User-controlled Style Sheets Part 3″,”Devarticles.com”),

(NULL,”Div-based layout withCSS”,”Devarticles.com”),

(NULL,”Building friendly pop-up windows”,”Devarticles.com”),

(NULL,”Building accessible web forms”,”Devarticles.com”),

(NULL,”Building a Template Parser class with PHP – Part 1″,”Devshed.com”),

(NULL,”Building a Template Parser class with PHP – Part 2″,”Devshed.com”),

(NULL,”A quick look at Cross-Site Scripting”,”Devshed.com”),

(NULL,”Email Address verification with PHP”,”Devshed.com”),

(NULL,”CSSshorthand at a glance”,”Devarticles.com”),

(NULL,”Creating pop-up notes withCSSand JavaScript”,”Devarticles.com”),

(NULL,”Controllable Navigation bars with JavaSCript – Part 1″,”Devarticles.com”),

(NULL,”Controllable Navigation bars with JavaSCript – Part 2″,”Devarticles.com”);

Okay, we’ve populated some records specifying NULL values for the “articleid” field, adding the corresponding story name, as well as the name of the site where the article was posted. Now, we have some data to play with. Let’s put the classes together to display some paged results. It’s as simple as this:

// include the classes

require_once ‘mysqlclass.php’;

require_once ‘pagerclass.php’;

// instantiate a MySQLConnector object

$db=&new MySQLConnector(‘host’,'user’,'password’,'articles’);

// build query

$sql=”SELECT articleid,name FROM articles WHERE site=’Devarticles.com’”;

// instantiate a Pager object that aggregates the “MySQLConnector object

$pg=&new Pager($db,$sql);

// display paged result set

echo $pg->displayRecords($_GET['page']);

With just a few lines of code we’re in business, displaying nicely paged records. If you look at the code above, you can see that we first included the class files, and then instantiated a “MySQLConnector” object, which handles all of the operations related to MySQL.

After that, we build a regular SELECT statement to retrieve all of the articles that were published at “Devarticles.com”, and instantiate a “Pager” object, passing to it the query itself and the “MySQLConnector” object. Doing so, the second object aggregates the first one, for performing internally the given query and returning a paged result.

By spicing up the output with some CSS declarations, this is what I get on my browser, after executing the above script:

Probably this is not the “coolest” visual presentation, but the classes are doing their jobs quite well. We’ve obtained a decent paged result set in conjunction with all of the paging links. Isn’t aggregation remarkably powerful? I’m sure you’ll agree.

Conclusion

That’s all for now. Hopefully, our round trip exploring the core concepts and practical application of aggregation in PHP has been highly rewarding, and given you a more intimate grounding in the subject. However, this is only the start. There is plenty of room to experiment and find the right way to implement a powerful, well-defined object interaction in the real world. The more you learn about Object Oriented Programming, the faster your classes will get connected properly, saving you from the hard work of rewriting code. Once you have a few classes worked out, it’s as easy as building a wall with bricks. See you soon!

Google+ Comments

Google+ Comments