Del.icio.us Links

/
July 2008
M T W T F S S
« Feb    
 123456
78910111213
14151617181920
21222324252627
28293031  

Chat Clussman

personal thoughts

1 class.pagination.php

Download this file

I’ve been meaning to simplify my work / life by creating some classes that I can use to streamline a lot of the projects that I work on. I found myself with some time this week and finally took a small step in that direction by creating a pagination class.

Up until now I’ve used a function that I wrote way back when for paging. It was clunky, kludgy, and limited. I looked around at what was available online and what I found was, for the most part, clunky, kludgy, and limited.

Starting from my existing code, I laid out some goals for how I wanted my new pagination object to work:

  • It had to be very simple to integrate. I wanted to be able to drop it into a file and have it just work.
  • The output had to be semantic, valid (X)HTML that would be easy to style with CSS.
  • I wanted options for how the links would display.
  • It needed to have options to output clean URLs (for when I’m using mod rewrite) or normal URLs with ugly query strings.
  • It needed the option of using sessions to store SQL queries since, much of the time, this would be necessary when using clean URLs.
  • It had to be drop-dead simple to configure options, such as how many pages to display per page, enabling mod rewrite functionality, enabling the use of session data, etc.

The idea for using sessions and clean URLs came from Ben Jamieson / Thyme Online. I’m also going to credit him with the idea for highly compartmentalizing the code used in the class (he has a highly compartmentalized pagination class of his own with sessions and clean URLs…) even though I remember what his code looked like when I first met him and I think this may be a case of the student becoming the master!

If you’re wondering why I wrote my own class instead of just using his, well, there were a couple of reasons:

  • I wanted the practice (I re-read the chapter on OOP in my PHP book before starting).
  • I’m an idiot: I was concerned about security and I didn’t realize the session data was only storing a session ID in the client side cookie and not the actual SQL queries. I initially wrote this class to include Alexander Valyalkin’s most excellent md5_ encryption and decryption functions.
  • There were some things I wanted to do differently.
  • And because I already had my own paging code that I wanted to adapt.

If you already have something in place to handle pagination, a lot of this code will probably look familiar — there aren’t that many ways to skin this particular cat — but hopefully this code is clean enough and reusable enough that some people will find it useful.

A Simple Example

<?php
   include_once('class.pagination.php');
   $sql = "SELECT * FROM table_name";
   $paging = new pagination();
   $result = mysql_query($paging->paginate($sql));
   while ($record = mysql_fetch_assoc())
   {
      // Output records here
   }
   print($paging->getLinks());
   print("<p>".$paging->getCount()."</p>");
?>

The above example is the simplest usage. The class is included, the object is initialized, the SQL code is passed and returned with the LIMIT clause appended (note: it will replace any existing limit clause) and the links are output.

Sample Output

For large sets of data, ten or more pages, first and last links are added to let users quickly jump to the beginning or end of the data set. Otherwise, just the pages and previous/next links are displayed. You can change that by passing an optional variable to the getLinks() function or, if you’re going to output multiple sets of paging links on a page, you can override the default format via the setDisplayOptions() function (see description of this function below for more details).

Available Functions

paginate($sql) - This function initializes several variables and returns a modified SQL statement with a LIMIT clause appended to it.

setDisplayOptions($x) - This function changes how pagination links are output for a given page. It takes a numeric value between 1 and 4:

  1. Only show the first and last links for large data sets (ten or more pages). Only show previous link when not on the first page. Only show next link when not on the last page. This is the default setting.
  2. Always show first and last links. Always show previous and next links.
  3. Never show first and last links but always show previous and next links (the Flickr option).
  4. Never show first and last links. Only show previous link when not on the first page. Only show next link when not on the last page.

You can achieve the exact same functionality by passing this variable in the getLinks() function. Both of the following examples output the same thing:

<?php
   // Example one
   $paging->setDisplayOptions(3);
   print($paging->getLinks());

   // Example two
   print($paging->getLinks(3));
?>

setPageSize($x) - Override the default number of items to display per page. The default is 25.

setModRewrite(TRUE) - The default value is FALSE. Override this if you plan to use mod_rewrite to create clean URLs. If you don’t know what this is, leave it alone.

setUseSessions(TRUE) - The default value is FALSE. Override this if you have complex SQL statements that you don’t want to pass via query strings. You’ll probably need to enable this if you’re using clean URLs.

setSessionName($name) - This just exists to prevent any possible conflicts with existing code. The default session name is ‘searchdata‘. If, by any chance, you already use a session variable with that name, you can override the name used by the pagination class.

This function can also be used if you plan to store multiple SQL queries by assigning a unique session name for each query.

getSQL() - What goes up, must come down — or better put: what is input, must be output. You pass a SQL statement to the pagination object; this function returns that SQL statement to you with the LIMIT clause appended to it.

getCount() - This returns the “Displaying from x to y of z” string. It gets its own function so that it is easy to omit if don’t want to display it.

getLinks($x) - This is the meat and potatoes. This function returns the list of links for output. It accepts the same numeric option that setDisplayOptions($x) uses.

Miscellaneous Notes

Regardless of whether you use clean URLs or not, the the current page is determined by the $_GET[’page’] variable. The page variable always needs to be the last part of the query string or path. Examples:

  • domain.com/articles/title/5/
  • domain.com/article.php?name=title&page=5
  • domain.com/search.php?keywords=xyz&sort=desc&page=2

The first example above is using mod_rewrite.


To use sessions, you first have to initialize the session data with:

<?php
session_start();
?>

If you are using cookie-based sessions, you must call session_start() before anything is output to the browser. For more information on how to use session_start(), see the php.net website.


You can view the source code of this page and the associated stylesheet to see how the links are output and how I’ve styled them.

If you have suggestions regarding this class, please leave a comment. Also, this isn’t heavily tested, so if you find a bug (I’m sure there will be some) please let me know about it.

Download this file

Add this post to del.icio.us

4 The need for project planning

I’ve been working on a largish website project and I’ve been falling steadily behind schedule. The reasons for the delays fall into two categories: data conversion and code conversion. Both turned out to be more complicated than I expected.

Data Conversion (Filemaker to MySQL)

Filemaker is a weird sort of database. Instead of tables you have “layouts” that show certain fields but all fields exist in the same bucket. The database is the table. In this case the Filemaker database had hundreds of fields in it that were spread across 16 layouts and all of it needed to be converted to MySQL. Unfortunately this was not an a => b scenario for several reasons:

- A lot of calculations and data manipulation are taking place in Filemaker
- The LDML code made extensive use of lists built into Filemaker
- A lot of data had to be translated
- Certain restrictions were placed on the MySQL databases (see below)

The data conversion is part of the larger conversion from Filemaker/LDML to MySQL/PHP. On the PHP side the client already has a database structure and code built out for several of the portions of the site being converted. In those cases some data has to be split across multiple tables, so data has to be converted to new formats, and various other tweaks had to be performed.

This is a longer term project (four months). Because the data conversion will have to be done several times, I chose to write a script to handle it. Again, because it will have to be run over and over again, it first starts by emptying the existing tables and resetting all of the auto_increment counters to 1. When the site has been fully converted and is ready to relaunch, we’ll be able to run the script again and at the push of a button grab the most recent data from the previous site. Whenever data turns out to need more “massaging” during the code translation process (i.e. something turns out to be wrong) I can make the changes and re-run the script without having to perform a lot of manual labor.

I’ll outline the conversion script another day — it’s about 800 lines of code. It took about a week to write and get right and since this project is ongoing it will almost certainly require more tweaks as the project moves forward. That’s a lot more than the one day I had estimated for the conversion.

Code Conversion

Once I had the data poured into 19 MySQL tables I could start setting up the website. First thing was converting the new layout into XHTML and CSS. No problemo. The second step was to setup the new navigation structure. A little bit more work and planning here but again, no problemo. The third step was to create pages for all of the static content. This was the easiest step in the process. The fourth step was, and is, where I get my hands dirty and start mucking around with the site code.

Now, it seemed easiest to start with the pre-existing PHP modules from the client and get those up and running. Unfortunately, this is where I ran headfirst into one of my own great shortcomings. I have a hard enough time reading my own well-formatted and well-documented code. In this case I’m reading someone else’s code with functions and classes that are spread across 25 different files. Everything is being generated or manipulated by something else. Coming into this from the outside it’s very hard to figure out what is going on. For me this has led to a lot of confusion, a lot of delays, and a lot of sleepless nights.

Finally, this weekend I decided that something had to give. I was trying to take the short route and fumble through things. Define a task, tackle it, and when it doesn’t work try to trace the code back through the various files to find out why. Fix, try again, run into another problem, trace it back through, etc.

For most people this would actually work. They can just learn from doing something hands on. For me that doesn’t work. I have to first read a manual, then get hands on and refer back to the manual as I’m going along. It’s not enough for me to know how something works, I have to understand why it works.

I determined that I needed to write a manual. In doing so I would develop a deep understanding of how everything in the various files worked.

Yesterday I spent the day printing out most of a ream (500 pages) of code. I got a binder and a bunch of tabbed inserts. I created tabs for each document, hole punched everything and assembled my book. Then I started the two day process of reading the book. For each file I created an outline of each class and function. I also outlined the structure for each include. This is my table of contents and is in the front of the book.

Now I have a much greater understanding of what is going on because I’ve read through everything once. I also now have a quick reference to any section of code without having to open five different files to track function calls. At a glance I can see what is going on and if I’m passing data to a function in the correct format or using a function in the correct way. This took two days and it could have saved me weeks of sleepless nights.

Planning and organization are incredibly important when working on projects. It may seem like wasted time but in the end it saves more time than it consumes.

Add this post to del.icio.us

1 Just Plain Weird

More Firefox commercials here.

Add this post to del.icio.us

AJAX Tutorials

Monkey Bites has a quick post up called “A heap of AJAX tutorials” which links to 30 tutorials + one.

Add this post to del.icio.us

1 SXSW Update

Flickr photo stream

I’ve temporarily added the Flickr Flash app to display my SXSW photo stream below the menu on this site. Temporary because I don’t like the Javascript implementation but I don’t have time to put up anything else right now.

Microformats presentation by Tantek Çelik

I saw these applications on Jakob Heuser’s laptop and thought they were cool:

Textmate (Text Editor for OS X)

It first grabbed my attention because Jakob had edited his color schemes to be colored text on a black background. Silly reason I know but it took me back to my days of programming MUDs back in college.

The functionality took me back too. It was the best of both worlds with the syntax highlighting and robust features of a GUI editor and the aliasing system of Linux. I’m not saying I’m going to replace my BBEdit, but I’m definitely going to play around with Textmate.

Adium X (Messenger for OS X)

I have no idea about this one but it looked interesting and I saw it at the same time that I saw Textmate, so I want to check it out too.

Add this post to del.icio.us

2 SXSW Panel: Beyond Folksonomies - Knitting Tag Clouds for Grandma

This panel defined folksonomy and the current state of tagging. During the course of the conversation there were a few suggestions on ways to improve upon the current state of affairs, which is what the panel was really about. I wanted to expand on that part of the conversation.

It seems to me that every time a cool new technology or idea comes around, we jump on the bandwagon with such enthusiasm that we leave behind everything that came before. When the discussion repeatedly turned to letting non-power-users rely on or draw from the knowledge of the group, either in the form of automatic tagging or keyword suggestions, people questioned how any one person could rely on the opinions of another. While I agree that no system is perfect (systems are, after all, created by imperfect humans), it seems to me that we’ve been developing methods of quantifying trust for a long time.

When I buy something on eBay I’m reasonably assured that I’m buying from a reputable seller. The same goes for opinions on Epinions. Does anybody remember when Epinions was the cool new kid that would empower the masses? I still use the site when making purchasing decisions. For that matter, look at any peer-to-peer network.

Simple ideas tend to be the best ideas. That’s my corollary to Occum’s Razor. Simple methods of user ranking can create a trust mechanism that would allow novice users to rely on the wisdom of experts. This could easily allow for experts in specific areas (Jazz was mentioned during the panel).

I want to repeat one suggestion that was brought up during the panel: tagging should be incorporated directly into the browser (and operating systems). Regular bookmarking should take advantage of tags. This should not replace categorization but rather be offered as an option to it. Just because you think it is better doesn’t mean it has to replace something people have already learned to use. There is something to be said for the efficiency of knowledge already learned.

That suggestion led directly to something that I have not heard mentioned by anyone despite it being extremely obvious. In fact, it hadn’t occurred to me until the panel. Tagging has been around since the early days of the web. It has been done by the experts in each subject area and it has been done to a vast quantity of what is out there. I’m talking about keywords. Remember meta-tags?

Why has nobody created a bookmark plugin or web utility bookmarklet that automatically includes meta-data with the link URL? This should be automated in every browser and bookmarking website and, at the very least, include the two most common meta-tags: description and keywords. Relying on past lessons learned: bookmark searching should be able to very easily include or exclude metadata in order to deal with keyword spamming (there we go re-using past knowledge to enhance the trust of the system…).

I’ll leave off there. Hopefully other attendees (and the panelists themselves) can offer more suggestions or point out the flaws in mine. The evolution of ideas is best accomplished through collaboration.

Related Links:
Panel Listing on SXSW
Beyond Folksonomies (great resource page)

Add this post to del.icio.us

Google Search Changes

Over the last year I’ve noticed changes to how Google searches. It stopped telling me that “the” and “of” were common words. It started searching for phrases first, then words. Now I can get different search results for the same words by putting them in a different order.

For example:

turning of the screw” vs “of the screw turning

Google has become the first search engine to work the way my brain does.

Add this post to del.icio.us