Paging with PHP

I trolled around the interwebz for a good 3 hours the other night looking for this.
I wanted to page through my mysql query’s resultset rather than display what could potentially be thousands of records on a single page. I wanted to limit the results per page to a certain, low number and display “Previous/Next Page” links at the end of that limited count.

Although I have to say that such a task is done very simply in asp.NET, I thoroughly enjoyed the challenge of doing it in PHP.

The first thing we need to do is find where the start of the page will be in the resultset. To do this, we pass a value to use in the mysql query. This value will just contain a number to indicate which page we’re on.

$page = $_GET[‘page’];
if (!isset($page)) {
header(‘Location: /mysite/index.php?page=1′);
}

$sql = ‘SELECT * FROM articles LIMIT ‘.($page – 1) * 10.’, 10′;
$result = $dbh->prepare($sql);
$result->execute();

foreach ($result->fetch() as $row) {
// Build each
here to display results.
}

$sql = ‘SELECT COUNT(*) FROM articles’
$result = $dbh->execute($sql);
$count = $result->fetch();

if ($page > 1) {
echo ‘Previous‘;
}
if ($count > $page) {
echo ‘Next‘;
}

The code might not be 100% accurate as I just wrote this off the top of my head. I hope it gives you an idea how to do this anyway.

Good luck!

- L

New Address

Hey everybody!

I’ve recently started my web hosting company so I’m going to be moving my blog onto my own domain.
I’ll be designing it myself and I’m really excited to get going, watch this space for more info.

-L

ASP.NET Menu Controls in Google Chrome

As is the case most of the time, I’m posting now to tell you about a problem I’ve just fixed.

The Problem

My asp.NET Menu Control was rendering perfectly in IE 7, but looked completely horrid in Chrome. My submenus also weren’t displaying on mouseover.

My code was fine because the menu did work perfectly in IE 7. The problem must, therefore, be with the browser.
Based on what I’ve found online researching this problem, it seems that ASP.NET renders controls in a specific way to allow for backward compatibility with older browsers. As it turns out, ASP.NET doesn’t have a “definition” for Google Chrome that tells it what the browser’s capabilities are. The end result being that the server renders the control incorrectly because ASP.NET doesn’t know what Chrome can do.

The Solution

Given the explanation above, the solution seems obvious: Tell ASP.NET what Chrome can do.
To do this, you can follow these steps:

  1. Add the App_Browsers folder to your website
  2. Create a new Browsers file in this folder and call it Chrome.browser
  3. Comment out everything in the file and replace it with this:
1 <browsers>
2 <browser refID=safari1plus>
3 <controlAdapters>
4 <adapter controlType=System.Web.UI.WebControls.Menu adapterType=“” />
5 </controlAdapters>
6 </browser>
7 </browsers>

All this basically does (as far as I can logically understand) is tell the server that Chrome can handle the Menu Control’s full functionality.

Happy Coding!

/Logan

Simple Multi-Threading

We’ve all installed programs on our computers and seen different things happening on the screen right?
Progress bars counting to 100%… Labels changing to show us what file is being worked on… Did you ever wonder how to do that? If you like essentially useless, but attractive stuff like that as much as I do, you’re answer is definitely going to be “YES!”

Using an installer as an example, the simple theory behind it is that the installer runs on (at least) two different threads. When working with threads, imagine the execution of the application flows like a river; a single passage of the water from point A to point B.
If the river should split down another tributary, though, some of the water goes in a different direction, doesn’t it? That’s what threads do, it basically allows you to split an application up, so that it can do more things at any given time.

Let’s get into a simple example…

The following code opens a connection to a database and writes the selected data into a ListBox control (not a practical application, as most people won’t go looking through a full table’s worth of data in a ListBox, but it shows you what threading actually does quite nicely on the form).
The data access will be done on a separate thread, while another thread counts from 0 while the data access thread is still busy.
So, we’ll have 3 threads:

  1. The main thread that builds and controls the form
  2. The 2nd thread that queries the database and modifies the ListBox
  3. The 3rd thread that makes the Label count while thread 2 is busy

The form will consist of a Button, a Label, and a ListBox. I’m keeping the names of these controls as the Visual Studio defaults for clarity.

‘ Imports and Global Variables
1 Imports System.Threading
2 Imports System.Data
3 Imports System.Data.SqlClient
4  
5 Private DS As New DataSet
6 Private DA As New SqlDataAdapter
7  
8 Private t1 As Thread
9 Private t2 As Thread
10  
11 Private SetTextDelegate As SetTextCallBack = _
New SetTextCallBack(AddressOf SetTextMethod)
12 Private AddItemDelegate As AddItemCallBack = _
New AddItemCallBack(AddressOf AddItemMethod)
13 Delegate Sub SetTextCallBack(ByVal Text As String)
14 Delegate Sub AddItemCallBack(ByVal Item As String)

We’re creating 2 threads here. Thread t1 will perform the data access and add items to the ListBox, and thread t2 will just update the Label’s text while t1 is working. This is just for a visual indication that things are actually working.

I’ve already covered connections to SQL Data Sources in my blog, and, since it’s a lot of code, I won’t be including it in this post. Just know that even though we’re working with threads here, there’s nothing different that needs to be done to the code that connects to the database and populates the dataset.

Next we’re going to write the button click event handler, this is just going to set the threads up and start them.

1 Private Sub Button1_Click(ByVal Sender As Object, ByVal e As System.EventArgs) Handles Me.Button1.Click
2     t1 = New Thread(New ThreadStart(AddressOf GetData))
3     t2 = New Thread(New ThreadStart(AddressOf ProgressCounter))
4     t1.Start
5     t2.Start
6 End Sub

When we set the threads in lines 2 and 3, we use AddressOf to tell the threads what code they’re supposed to handle. Lines 11 – 14 in the global declarations are used for interacting with form elements, because controls can’t be accessed from a thread that they weren’t created on.

Now, let’s write the code that t1 will use:

1 Private Sub GetData()
2     ‘ SQL Data Access code goes here
3 Dim CurrentRow As String = Nothing
4 For i As Integer = 0 To DS.Tables(0).Rows.Count – 1
5     CurrentRow = DS.Tables(0).Rows(i)(1).ToString
6     Thread.Sleep(400)
7      Me.Invoke(Me.AddItemDelegate, New Object() {CurrentRow})
8 Next i
9 End Sub

Here, we’re simply looping through the DataSet, and, on each, we’re storing the value in the specified cell. We’re then passing that value to the delegate sub which will use it to execute the next procedure to add it to the ListBox.

1 Private Sub AddItemMethod(ByVal Item As String)
2     ListBox1.BeginUpdate()
3     ListBox1.Items.Add(Item)
4     ListBox1.EndUpdate()
5 End Sub

That’s it for the first thread. The main part of the application is now done, now, let’s get to the 2nd thread:

1 Private Sub ProgressCounter()
2     Dim i As Integer = 0
3     While Not t1.IsAlive = False
4         Me.Invoke(Me.SetTextDelegate, New Object() {i.ToString})
5         i = i + 1
6     End While
7 End Sub
8  
9 Public Sub SetTextMethod(ByVal Text As String)
10     Label1.Text = Text
11 End Sub

Very simple, we’re just storing an integer value and passing it to our delegate so that the delegate can write it to the label.

Lastly, know that a typical application on a 32-bit platform has capacity for 250 threads. You generally shouldn’t need to use more than 10 though (if that). Managing a lot of threads does become quite a nightmare, so be very sure about what your application needs to do before you go crazy creating threads. Also, don’t worry about writing code to close your threads. They will close themselves when they complete execution (i.e. when they’re done working).

In my next post, I’ll show you how to make a delegate procedure modify the text value of any control on your form, so watch this space!

-L

[ASP.NET] Horizontal Submenu from XML

In my last post I showed you a workaround that allowed you to create a horizontal submenu when you clicked on a MenuItem from another menu on the same page. That example hard-coded the MenuItem definitions into the code file, and I said that I’d be demonstrating how to create a horizontal submenu from a sitemap file. While attempting this, I got hit in the face by an error that has to do with hierarchy which I researched only to find that most people suggest it would be easier to find another alternative rather than try to solve the problem.

My alternative was to create a custom xml file that contains property definitions for the MenuItem class (namely Text and NavigateURL). Here it is:

<name>Visual Basic.NET</name>

1 <?xml version=1.0encoding=utf-8?>
2 <CategoriesMenu>
3 <item>
4 <id>0</id>
5 <name>VBScript</name>
6 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
7 </item>
8 <item>
9 <id>1</id>
10
11 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
12 </item>
13 <item>
14 <id>2</id>
15 <name>ASP.NET</name>
16 <url>~/Articles/List.aspx?t=cat&amp;r=vbs</url>
17 </item>
18 </CategoriesMenu>

Unfortunately, here’s where the frustration kicked in (mostly because I have very little experience working with XML). I had a lot of problems figuring out how to get the right values out of the XML and into my menu where I needed them. Good thing for you, I’ve spared you the aggravation by fighting through it for you.

Basically, we need to select each <name> and <url> element outlined in the XML and use the text inside of those as our menu definition properties. It took a few hours, but I managed it; here’s how:

<col style="width: 760 Continue reading

[ASP.NET] Horizontal Drop down Menu

I really like multi-level menus; they save space, but still allow you to put the same amount of content on your page.
ASP.NET is the only technology I know of that comes with its own menu that supports multiple menus, and it also allows you to change the menu’s orientation (Horizontal or Vertical). It’s great!

Sadly though, it does have one drawback, all “pop out” menus are fixed vertically, and there’s no way (that I’ve found) to change that. You just can’t get a menu/submenu pair that looks like this:

Home Categories Contact Us
VBScript Visual Basic.NET ASP.NET

 This type of menu cannot be designed with a standard ASP.NET menu control. So, here’s my workaround to get the same effect.
I’m keeping this simple, we’re not going to go into making it look pretty or anything, just the cold hard functionality of it; you can play with colors and design later.

For now, we won’t be using a sitemap, I’ll go into that soon as it requires modification of the web.config file and it’s quite a bit to go into.

Hard-coded Menu

First, create 2 menu controls on your page (Default names Menu1, and Menu2); set the orientation for both of them to Horizontal.
Next, populate the first menu (be sure to leave menu2 blank):

MenuItem Text MenuItem Value
Home Home
Categories Categories
Contact Us Contact Us

 Add the following to your code file:

1 Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles Menu1.MenuItemClick
2     Select Case e.Item.Value ‘ You could also use e.Item.Name
3         Case “Categories”
4             Dim m1 As New MenuItem
5             m1.Text = “VBScript”
6             m1.Value = “VBScript”
7             m1.NavigateUrl = “Articles/List.aspx?Type=Cat&Ref=VBS”
8  
9             Dim m2 As New MenuItem
10             m2.Text = “Visual Basic.NET”
11             m2.Value = “Visual Basic.NET”
12             m2.NavigateUrl = “Articles/List.aspx?Type=Cat&Ref=VBnet”
13  
14             Dim m3 As New MenuItem
15             m3.Text = “ASP.NET”
16             m3.Value = “ASP.NET”
17             m3.NavigateUrl = “Articles/List.aspx?Type=Cat&Ref=ASPnet”
18  
19             Menu2.Items.Add(m1)
20             Menu2.Items.Add(m2)
21             Menu2.Items.Add(m3)
22     End Select
23 End Sub

 Basically, we’re populating a static menu on the fly. Because the page loads while the menu is empty, it doesn’t start off visible. This changes when we add items, so we don’t even need to tell VB to hide the menu on page load.

It’s not an elegant solution by any stretch of the imagination, but it works. My next post will show you how to do the same thing by using sitemaps.

Until then…

-L