Archive for July, 2009

Getting Things Done by David Allen

Sunday, July 19th, 2009

I’m about 2/3 of the way through Getting Things Done (GTD) by David Allen. You know it’s a good book when it makes me want to DO things. I haven’t quite had the time to look at implementing it yet (ironically) but when I do, I will be taking a good look at Remember The Milk (RTM), Google Calendar (GCal), Firefox Bookmarks, and my own physical filing system to see how I can incorporate GTD.

I’ve found that I’m most productive when my calendar and tasks are immediately available wherever I go. Unfortunately, there’s no RTM app for Symbian Phones (I have the e51) and I have to manually sync my phone’s calendar with GCal. Not the best system, but maaaybe I can justify purchasing an Android-capable phone if it happens to have the productivity apps I need.

Pagination component for the Skeleton Framework

Sunday, July 19th, 2009

Arborint and I have been hard at work on a pagination component that can be used standalone or as part of the Skeleton framework. We’re looking for feedback from other developers, so take a look and let us know what you think.

Executive Summary
We made these classes first and foremost to make it drop-dead easy to paginate data. Our goal was not to make a one size fits all solution, but rather to provide a layered range of solutions in which developers can pick and choose to tailor the classes to their needs.

Specific Goals

  • Account for as many use cases as possible
  • Stay flexible for extendability
  • Take care of the messy details of pagination: url generation, maintaining state, dealing with the request.

Basics
The base object in this pagination system is a Value Object that holds the values for the list and does the necessary calculations. This class can be used alone, but you are required to initialize it.

$pager = new A_Pagination_Core($datasource);
$pager->setCurrentPage(intval($_GET['mypagevar']));
$pager->setNumItems(intval($_GET['mycountvar']));

This component also provides a class that extends the Core class and initializes itself from the request so you don’t have to. This class adds a process() method that will initialize the object for you:

$pager = new A_Pagination_Request($datasource);
$pager->process();

This Core object does the necessary calculation and will return page numbers for the current first, last, next and previous pages, plus a range of page numbers around the current page. These are intended to provide the basic functionality on which to build classes to render paginated output.

This class takes a Datasource object passed to the constructor. These Datasources comply to a simple Adapter interface. This component will provide Adapters for arrays, PDO, MySQL, etc. A getItems() method is provided to retrieve the records for the currently displayed page.

The basic methods in its interface are:

class A_Pagination_Core {
function __construct($datasource)
function isPage($number)
function getPage($number)
function getCurrentPage()
function getFirstPage()
function getLastPage()
function getPageRange()
function getNumItems()
function getItems()
}

This component is not monolithic. There are several levels of classes that use a Core object and provide support for rendering output. The lowest level of output support uses page numbers from a Core object and builds URLs. Using this class you can have complete control of your template:

$url = new A_Pagination_Helper_Url($pager);
$out .= ‘<a href=”‘ . $url->previous() . ‘”>Prev</> “;
$out .= ‘<a href=”‘ . $url->next(’Next’) . ‘”>Next</> “;

The next level of output support uses page numbers from a Core object and builds complete links (<a> tags). You an pass the name of a CSS class to this object to control link style:

$link = new A_Pagination_Helper_Link($pager);
$out .= $link->previous(’Prev’, ‘mylinkclass’);
$out .= $link->next(’Next’, ‘mylinkclass’);

Use Case Example
Here is an example of combining the classes to do a basic paginated list with links:

// create a data object that has the interface needed by the Pager object
$datasource = new Datasource();

// create a request processor to set pager from GET parameters
$pager = new A_Pagination_Request($datasource);

// initialize using values from $_GET
$pager->process();

// create a “standard” view object to create pagination links
include ‘A/Pagination/View/Standard.php’;
$view = new A_Pagination_View_Standard($pager);

// display the data
echo ‘<table border=”1″>’;
foreach ($pager->getItems() as $row) {
echo ‘<tr>’;
echo ‘<td>’ . $row['id'] . ‘</td><td>’ . $row['name'] . ‘</td>’;
echo ‘</tr>’;
}
echo ‘</table>’;

// display the pagination links
echo $view->render();

Additional Features

  • There are a number of examples that show different ways the classes can be used — from do-it-yourself to standalone.
  • There is support for ORDER BY functionality to sort the list. There are methods to generate column heading links to sort any column ascending/descending. Sort order is maintained while paging.
  • The total number of items in the datasource is persisted RESTfully so, for example, COUNT() is only called one for database datasources.
  • Request parameter names can be changed to remove conflicts and allow multiple pagers on one page.
  • Pagination state values can be saved in the session if you want to be able to resume in the list where you left off — when editing records in CRUD for example.

Feedback Wanted

  • Do these classes provide everything you need for pagination?
  • What modifications would you make before using this in a project?
  • What can we do to improve the code?

Discussions

This component is being discussed on two forums: SitePoint and the DevNetwork. Feel free to join in the discussion.

DataGrid
For the most automated use case, we will be providing a DataGrid that takes care of all HTML once the core classes have been finalized.

A long time coming

Sunday, July 19th, 2009

Been meaning to start a blog on my site for a while. I don’t have the time to write a blog app, so for now I’ve installed WordPress. Feel free to ridicule me in the comments in a later post (I’ve disabled comments on this post due to the number of spam posts I’ve received– curious to see if they start spamming my second-to-last post. Amateurs.