Simple Pagination with the FileMaker PHP API

During one of my sessions at the recent 2010 FileMaker Developer Conference in San Diego I was asked about the pagination/navigation on a search results page that is generated by the FileMaker PHP API. They were referring to the links you might see at the top/bottom of the search results page like this:

First | Previous | Record 21 – 40 of 52 Next | Last

which are generated dynamically and use the equivalent of conditional formatting in FileMaker to display only the necessary elements. For example on the first page of the search results there is no Previous page nor can you go to the First page as you are already on it; likewise with the last page there is no Next page and no Last page, so these should not appear depending on the context of the current page.

I finally found some time to put together a simple example of how you can generate these using the FileMaker PHP API.

As with FileMaker when you perform a search via PHP/Custom Web Publishing you will generate a found set of records (or no matching records). With a large found set of records you might want to present these to the user in chunks, for example you could present 5/10/20 records per page and allow the user to navigate to the next page. This is similar to how most search engines on the web work these days. Google for example defaults to showing 10 results per page. With the FileMaker PHP API you use the setRange() method to request only part of the found set of records by passing in 2 paremeters: the first parameter is the number of records to skip past and the second parameter is the maximum number of records to return.

Say you do a search and you find 52 matching records. Using a $max value of 20 you will get records 1-20 on the first page, records 21 to 40 on the second page, and records 41 to 52 on the third (and last) page. On the first page we are skipping 0 records, on the second page we are skipping 20 records and on the third (and last) page we are skipping 40 records.

Here’s an example of how to use the setRange method:


// Set a Max value. Paging 20 records at a time
$max = 20;
$skip = $_GET['skip'];
if(!isset($skip)) { $skip = 0; }
$request->setRange($skip, $max);

Here I’ve hardcoded the $max value to 20 which means I’ll only ever get back 20 records at the most per page. For the skip value I’m using the $skip variable and if this hasn’t already been set I’m setting it to 0, which is typically done on the first page of search results. Otherwise this will be passed as a parameter in the URL and the php script will check to see if this GET variable exists. Now we need to perform the find and check for a found set of records:

// Perform the Find
$result = $request->execute();
if (FileMaker::isError($result)) {
if ($result->code = 401) {
$errorMessage = "There are no Contacts that match that request: " . ' (' . $result->code . ')';
} else {
$errorMessage = "Contacts Find Error: " . $result->getMessage() . ' (' . $result->code . ')';
}
} else {

If there are matching records we then generate some variables that will be used in the First, Previous, Next and Last links, as well as calculating the number of records found and how many were “fetched” on the current page:

If you use the previous example of 52 matching records here are the values of these variables for each of the 3 pages of search results:

  • Page 1 (records 1-20): $skip = 0, $max = 20, $found = 52, $ fetchcount = 20, $prev = -20, $next = 20, $lastskip =42, $firstrecord = 1
  • Page 2 (records 1-20): $skip = 20, $max = 20, $found = 52, $ fetchcount = 20, $prev = 0, $next = 40, $lastskip =42, $firstrecord = 21
  • Page 3 (records 1-20): $skip = 40, $max = 20, $found = 52, $ fetchcount = 12, $prev = 20, $next = 60, $lastskip =42, $firstrecord = 41

I’m also using a pipe character as a separator between the links as well which is stored in the $sepbar variable. Now we’re ready to generate the links within the HTML part of the php page: Here’s the code for the “First” link:


<?php
if ($skip != 0) {echo '<a href="?skip=0">First</a>'.$sepbar;
}
?>

As we only want to show the First link on every page except for the first page of search results we are checking the value of the $skip variable. If $skip is not equal to 0 then we are not on the first page of search results so we can show this link, along with the pipe character to give it some space between the links.

For the “Previous” link we use:

<?php
if ($prev >= 0) {
echo '<a href="?skip='.$prev.'">Previous</a>'.$sepbar;
}
?>

Here we only want to show the Previous link if there is a previous page of search results, so we can check the contents of the $prev variable which will only equal 0 on the first page of the search results.

For the “Next” link we use:


<?php
if (($skip + $max) < $found) {
echo '<a href="?skip='.$next.'">Next</a>'.$sepbar;
}
?>

Here we need to check that there actually are subsequent pages of search results, which we do by checking that the total of the $skip and $max variables is less than the total found set of records.

Finally for the “Last” link we use:


<?php
if (($skip + $fetchcount) < $found) {
echo '<a href="?skip='.$lastskip.'">Last</a>';
}
?>

Here we need to test that we are not on the last page of the search results which we do by checking that the total of the $skip and $fetchcount variables is less than the total found set of records.

If you want to display the total number of found records along with the records that you are currently viewing (e.g. “Record 21 – 40 of 52”) you can use:


Record <?php echo $firstrecord; ?> - <?php echo $lastrecord; ?> of <?php echo $found; ?>

I’d like to credit Sonja Froyen’s article Custom Web Publishing: Paginate Your Results which I used as a starting point for some of these links (no need to reinvent the wheel here). If you Google “PHP Pagination” there are thousands of other articles on different ways to generate the pagination links, including variations which show how to include the search results page numbers like Google (e.g. “Previous 1 2 3 4 5 6 7 8 9 10 11 Next”. Most of these reference MySQL as the data source but it’s relatively easy to swap the references to the FileMaker PHP API.

As some of this code won’t make sense on it’s own here’s the full php page with the HTML (remember this is a simple page that finds all of the Contacts in the DevCon sample file):

<?php
require_once 'FileMaker.php';
require_once 'connections/INT002.php';

}
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>
FileMaker DevCon INT002 Contacts
</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/glass_grey.css">
<style type="text/css">
form#auth label.error { display: none;
margin-top: 5px;
color: red;}
.appropriateError{
color: red;
}
.emphasise{
color: red;
}
</style>
</head>
<body>
<div id="container">
<!-- HEADER -->
<div id="header">
<h1>
FileMaker DevCon INT002 Contacts
</h1>
</div>
</div>
<table>
<thead>
<tr>
<th>
Customer ID                          </th>
<th>
First Name                            </th>
<th>
Last Name                            </th>
<th>
Country                            </th>
<th>
Phone Mobile                          </th>
</tr>
</thead>
<tbody>
<?php
$recnum = 1;
foreach($result->getRecords() as $contacts_search_row){
$rowclass = ($recnum % 2 == 0) ? "table_row" : "alt_row";
$recid = $contacts_search_row->getRecordId();
$pos = strpos($recid, "RID_!");
if ($pos !== false) {
$recid = substr($recid,0,5) . urlencode(substr($recid,strlen("RID_!")));
}
?>
<tr>
<td><a href='<?php echo "contactdetails.php?recid=$recid";?>'><?php echo nl2br( $contacts_search_row->getField('_kp_ContactID'))?></a></td>
<td>
<?php echo nl2br( $contacts_search_row->getField('NameFirst'))?>                            </td>
<td>
<?php echo nl2br( $contacts_search_row->getField('NameLast'))?>                            </td>
<td>
<?php echo nl2br( $contacts_search_row->getField('Country'))?>                            </td>
<td>
<?php echo nl2br( $contacts_search_row->getField('PhoneMobile'))?>                            </td>
</tr>
<?php $recnum++; } /* foreach record */?>
</tbody>
</table>
</div>
</div>
</body>
</html>

<!– Navigation Menu –>
<?php include_once ‘navigation.php’ ?><!– PAGE BODY –>
<div>
<?php
if ($errorMessage != ”) {
echo $errorMessage;
die;
}
?>
</div>
<div id=”content”>
<h1>
Contacts List                </h1>

Click on the Customer ID to view the full Contact details
<!–  Display record list page navigation controls –>
<div>

<?php
if ($skip != 0) {
echo ‘<a href=”?skip=0″>First</a>’.$sepbar;
}
?>

<?php
if ($prev >= 0) {
echo ‘<a href=”?skip=’.$prev.'”>Previous</a>’.$sepbar;
}
?>

Record <?php echo $firstrecord; ?> – <?php echo $lastrecord; ?> of <?php echo $found; ?>

<?php
if (($skip + $max) < $found) {
echo ‘<a href=”?skip=’.$next.'”>Next</a>’.$sepbar;
}
?>

<?php
if (($skip + $fetchcount) < $found) {
echo ‘<a href=”?skip=’.$lastskip.'”>Last</a>’;
}
?>

$layouts = $fm->listLayouts();
if(FileMaker::isError($layouts)) {
// FileMaker PHP API Error — Alert User.
$errorMessage = “FileMaker PHP Error: ” . $layouts->getMessage();
} else {

// Find all Contact records
$request = $fm->newFindAllCommand(‘WebContacts’);

// Set a Max value. Paging 20 records at a time
$max = 20;

$skip = $_GET[‘skip’];
if(!isset($skip)) { $skip = 0; }
$request->setRange($skip, $max);

// Perform the Find
$result = $request->execute();

if (FileMaker::isError($result)) {
if ($result->code = 401) {
$errorMessage = “There are no Contacts that match that request: ”  . ‘ (‘ . $result->code . ‘)’;
} else {
$errorMessage = “Contacts Find Error: ” . $result->getMessage() . ‘ (‘ . $result->code . ‘)’;
}

} else {

// Get the found records and setup page navigation links
$records = $result->getRecords();
$found = $result->getFoundSetCount();
$fetchcount = $result->getFetchCount();

// $totalpages = ceil($found / $max);

$prev = $skip – $max;
$next = $skip + $max;
if(($skip + $max) > $found) {$next = $skip; }

$lastskip = $found – $max;

$firstrecord = $skip + 1;

if ($fetchcount == $max) {
$lastrecord = (($firstrecord + $fetchcount) – 1);
} else {
$lastrecord = ($skip + $fetchcount);
}

$sepbar = ” | “;

// Get the found records and setup page navigation links
$records = $result->getRecords();
$found = $result->getFoundSetCount();
$fetchcount = $result->getFetchCount();

$totalpagesceil = ceil($found / $max);
$totalpagesfloor = floor($found / $max);

$prev = $skip – $max;
$next = $skip + $max;
if(($skip + $max) > $found) {$next = $skip; }

if($totalpagesceil == $totalpagesfloor) {
$lastskip = ($totalpagesceil – 1) * $max;
} else {
$lastskip = $totalpagesfloor * $max;
}

$firstrecord = $skip + 1;

if ($fetchcount == $max) {
$lastrecord = (($firstrecord + $fetchcount) – 1);
} else {
$lastrecord = ($skip + $fetchcount);
}

$sepbar = ” | “;

}
}

Databuzz now FileMaker 11 Certified

Databuzz is pleased to announce that Andrew Duncan recently passed the FileMaker 11 Certification Exam and is now FileMaker Certified in v8, 9, 10 and 11. FileMaker Certification is your validation that you are hiring an experienced FileMaker professional who has technical knowledge of the complete FileMaker product line and has passed the “Developer Essentials for FileMaker” certification exam

FileMaker 11 Certified

Databuzz eNews – July 2010 Released

We’ve just released our eNews newsletter for July 2010. You can view it online at:

http://www.databuzz.com.au/enews/enews_072010_generic.html

If you want to be added to the newsletter mailing list just leave a comment below and we’ll add you to the list until our new automated subscription service is operational.

FileMaker Announces Schedule for FileMaker Developer Conference 2010 in San Diego

FileMaker, Inc. have announced the sessions and workshops schedule for the FileMaker Developer Conference 2010, the largest annual gathering of worldwide FileMaker independent and corporate database developers, trainers and users. This year’s conference will be at the Sheraton San Diego Hotel & Marina, August 15 to 18, 2010.
This year’s conference will feature more than 80 sessions and workshops, the most ever offered, led by recognized FileMaker experts. Key sessions will focus on FileMaker database development best practices and techniques including FileMaker Server configuration, content sharing between FileMaker and Microsoft Office, FileMaker and the Cloud, working with calculations and more. Conference sessions and workshops will also include detailed information about designing databases on a large scale and displaying information through reports.
Databuzz is pleased to announce that Andrew Duncan will be presenting two sessions at this year’s conference. The first session is titled “Integrating SMS/TXT Messaging to Your FileMaker Solution Session” and is part of the Integration/Web stream. In this session attendees will learn how to integrate the ability to send SMS messages directly into your FileMaker solution. The session will cover:
  • what is required to start sending SMS messages from FileMaker Pro – how to use simple FileMaker Pro native technologies to send an SMS (e.g. scripts steps, Script Triggers and Web Viewers)
  • when to consider using external plug-ins instead of native technologies and which plug-ins to use
  • when to consider using a hardware modem and how to configure ESS for this
  • how to receive incoming SMS messages directly into your FileMaker Pro solution
The second session is also part of the Integration/Web stream and is titled  “Building a FileMaker Pro/Custom Web Publishing Solution for Internal and External Users”. Many FileMaker in-house solutions often require limited access by external parties that do not use FileMaker Pro. In this session we will walk you through how to approach the development of a “hybrid” solution that has 2 types of users: in-house staff using FileMaker Pro and external customers/users using Custom Web Publishing. Find out when and how to use the FileMaker API for PHP to give access to external users to your FileMaker solution. Several case studies will demonstrate how these problems have been solved and what lessons we have learned along the way (things I know now that I wish I had known then).

Attendees can save US $200 on the conference price by registering by May 21, 2010. You can get all the details at the DevCon website

Databuzz now FileMaker 10 Certified

We’re pleased to announce that Andrew Duncan recently sat the FileMaker 10 Certification exam and passed!

certified-10-logo_2clr_small

We aim to maintain our certification with each new version of FileMaker that is released. FileMaker Certification lets our customers know that we’re experts in the FileMaker industry and is the only credential sponsored by FileMaker Inc

FileMaker Pro 10 – Script Triggers

I’m in the process of updating one of my main solutions that previously used script triggering via the zippScript plugin under FM9 with FM10 native script triggers. zippScript worked really well and was a great all round script triggering plugin but one thing it couldn’t handle was keystroke based script triggers which are native in FM10. For many years I’ve yearned for a way to update a field that counts both the number of characters entered and the number of allowable characters remaining (this is for an SMS solution that has a max of 160 characters in the message field). With FM10 this is now a snap and combined with conditional formatting you can do some nice interface tricks (e.g. make the count field red when it exceeds a limit) and show a dialog when you hit 160 characters etc. I’ve put together a simple demo file for anyone that’s interested at:

http://www.databuzz.com.au/downloads/DB_SMS_Count.zip

I’ll hopefully have some more demo files online shortly.

Do you Twitter?

We’ve been reading a lot about Twitter lately and have now joined the Twitter community. You can see us on Twitter at http://twitter.com/databuzz or just click the Twitter logo below.

If we see that you’ve started following us we’ll endeavour to follow you also.

Databuzz eNews – December 2008 Released

We’ve just released our eNews newsletter for December 2008. You can view it online at:

http://www.databuzz.com.au/enews/enews_122008_generic.html

If you want to be added to the newsletter mailing list just leave a comment below and we’ll add you to the list until our new automated subscription service is operational.

We’re FileMaker 9 Certified!

Andrew Duncan finally found time to sit for the FileMaker 9 Certification exam today and we’re pleased to announce that he passed with flying colours. We aim to maintain our certification with each new version of FileMaker that is released. FileMaker Certification lets our customers know that we’re experts in the FileMaker industry and is the only credential sponsored by FileMaker Inc.

 

FileMaker 9 Certified!

Latest Databuzz Newsletter Now Online

We’ve just released our latest eNews for October 2008. You can read it online at:

http://www.databuzz.com.au/enews/enews_102008_generic.html