A Plugin for Paginating in Smarty

First I’d like to apologize for the lack of updates here in the last weeks, but the days have been very busy. I’ve bought a new car (more details about that as soon as the snow disappears), written a complete publishing platform from scratch in a weekend to help out when Gamer.no got in trouble and in general done a load of stuff. Anyways, this post isn’t about all that, but rather something else I wrote some time ago.

A use case you’ll encounter very often is the act of paginating items, i.e. including a simple “jump to page x, jump to the next page, jump to the previous page” footer. If you’ve ever tried to implement the logic around this in your view, you know that it can get quite extensive. You have several other solutions, such as the PEAR_Pager, which actually looks like a good solution now (with 2.x). Anyways, this is a plugin for Smarty to make generating pagination links easier.

Download the plugin, drop it into your plugins/ folder in your Smarty library directory, and voilá, you have access to the new {paginator} element.

The module is quite configurable, but as I’ve only extended the parts I’ve had use for it our projects, it may still lack a few simple keys.

{paginator hits=$hits offset=$offset total_hits=$articlesFound class_inactive=paginatorInactive class_active=paginatorActive}

The template variables used here are hits, the number of hits shown on this page, offset, the offset from 0 and total_hits, the total number of available hits in the current list. By default the plugin appends ?hits=<hits>&offset=<offset>+<hits> to the current URL, you can give another URL through the url attribute. The class_ attributes provide the CSS classes to use for the elements that enclose the page numbers or links. See the source code (!) for more information about attributes which work.

As I mentioned previously, the plugin is written for my own personal use, so it’s not as streamlined as it could be. Feel free to update it, dissect it, break it, claim it’s yours .. or anything. I’d be happy if you submit any patches to me so I can update the link here, or simply leave a comment.

Hack aways! You can see the plugin in action at the bottom of lovethatfun.com.

Undefined symbol: php_pdo_declare_long_constant

After installing a new PDO module (PDO_PgSQL) into our compiled-from-the-ground-up version of PHP 5.2.8 (.. since RHEL4 doesn’t really stay updated, but we do), i ran head first into the following issue:


/usr/sbin/httpd: symbol lookup error: /usr/local/lib/php/extensions/no-debug-non-zts-20060613/pdo_pgsql.so: undefined symbol: php_pdo_declare_long_constant

Panic. Then tried updating pdo_mysql which actually still worked, which just led it to have the exact same problem. Luckily a bit of searching at Google pointed me to PDO_MYSQL causing Apache segfault over at the PECL bug tracker. The last comment provided the solution to the problem: a quick rebuild of PHP with –disable-pdo and then enabling pdo from PECL instead (so that PDO and the PDO plugins API actually match, instead of trying to load the wrong version into the process) solved the issue.

Be sure to build PDO from the SAME VERSION as your client libraries. Disable it in the PHP build itself if you need to build it from PECL.

Removing (dropping) a Foreign Key Constraint in PostgreSQL

Had a need to drop a Foreign Key Constraint in PostgreSQL 8.x today, and this is how you do it:

database=> \d table_name;
Table "public.table_name"
Column | Type | Modifiers
------------------+------------------------+-----------
id | integer |
field | character varying(20) |
field_description | character varying(150) |
Indexes:
[..]
Foreign-key constraints:
"table_name_id_fkey" FOREIGN KEY (id) REFERENCES other_table(id) ON DELETE CASCADE

database=> ALTER TABLE table_name DROP CONSTRAINT "table_name_id_fkey";
ALTER TABLE
database=>

As simple as that. The name of the constraint is shown when describing the table with \d under “Foreign-key constraints”, and you simply do an ALTER statement to drop the constraint.

The Power of Creative Commons

Creative Commons provides a set of tools that allow author, publishers, etc. to explicitly license their content for a broader set of fair use than regular Copyright law allows. This increases the usefulnes of the creation and allows other to build further on your own creation. Sounds scary for some people, sounds like a dream for other.

Ever since I started uploading my photos to flickr (I’m doing quite a bit of photography in my spare time), I’ve tried to make most of them available under the most free Creative Commons license. The few exceptions are photos featuring people, where I usually don’t have explicit permission from the persons to license the photo freely. I’ve also made the same exception for cars with visible license plates, as that will identify the person owning the car. Otherwise, I’ve tried to publish my photos under a Creative Commons Attribution Only license.

I See What You Did There While I probably had the same reservations as most people had when I first looked into relicensing my photos, my experiences so far has only been positive. I’m still amazed to find new ways people are using my images every now and then, and possibly the most surprising usage of any of my images were found today:

In the norwegian local historic wiki, one of my images of two goats at Nordens Ark in Sweden is used as an example of how a Geitbåt (A goat boat) resembles the stretched neck of a goat. Amazing. If you ever go to read about the danish city of Elsinore (Helsingør) on Wikipedia (or Kronborg Castle), the image of the main land mark of the city was taken by yours truly. My images has been on cnbc.com, featured in online travel guides, in articles about how to save money on used games, in self improvement guides, in a farmer’s guide in connecticut about cows, in an english textbook and surely loads of other places. The alternative would have been that all the photos had been sitting on flickr, alone by themselves and possibly seen by .. 2 people. If that many. And one of them would have been me.

My tip: License all your stuff as freely as possible and watch the world use it in ways you never had imagined.

I like this world. And I’ll try to license my photos under the newest CC license as long as I’m finding the fun in taking pictures. Awesome.

Update: A friend of mine, Vegard, discovered that his photo of one of NSB’s BM93s is featured on the front page of Wikipedia today (21st of January, 2009). Wonder how many people have seen that image now…

Redesigning the “Sign Up Team” Form at pwned.no

I’ve spent a couple of days on and off redesigning the “sign up a team” at my tournament site, pwned.no. The currently live form is divided into two sections, depending on wether you want to sign up one of your existing teams or want to just sign up a temporarily created team — or one you haven’t created a proper team for yet:

Old signup form at pwned.no

I’m not happy about the fact that the form is actually divided into two parts, meaning that you have to read two sections to actually understand that you can sign up with an existing team – or write the name of one right there. The forms also have information that are common for both forms, so we’re duplicating a few user interface elements.

The new form still lack a bit of functionality to dynamically enable and disable the submit button based on the selection in the form, but since disabling the form made it look uglier than ugly, I haven’t added that bit yet. The screenshots also differs a bit since Opera and Firefox doesn’t quite agree on the double border CSS.

The new, complete version:

pwned-signup-new

And if you don’t have any existing teams (clans) available, the form now includes a link to the page where you can create one – and try to explains why you should do that.

pwned-signup-no-clans

Also, if you’re not logged in, you’re just presented with the simple form. I think I’m going to add a notice about signing in with a bit of text in the same gist as the create clan bit.

pwned-signup-not-admin

Hopefully this will help reduce any confusion, but luckily the form is quite small anyways. I’ve also added more proper error hilighting, both before signing up and after failing to do so for any reason. Small fixes, but they should increase usability.

Any suggestions of potential ways to enhance this form even more would of course be appreciated!

Pinouts for the Guitar Hero World Tour Wireless Controller

If you’ve ever wondered exactly which buttons correspond to which pins on the internal layout of the Xbox 360 Guitar Hero World Tour Wireless Controller, look no further! If you ever see the insides of such a controller and are wondering exactly which buttons are designated to which pins or wires, this can save you the trouble of opening both the neck and the base:

Green (A): 1 + 8
Red (B): 2 + 7
Yellow (Y): 2 + 6
Blue (X): 2 + 3
Orange (LB): 4 + 5

Attach a multimeter to measure the resistance between the two pins for each button, and you’ll see the value drop towards zero each time you press the corresponding button. This is very useful for debugging an issue where one of the buttons seems broken.

Good luck!

The Side Effect of Using Return Type To Handle Errors

I came across a curious little side effect of the issue I just posted earlier:

public function action()
{
   $id = filter_input(INPUT_POST, 'id', FILTER_SANITIZE_STRING);
	
   if(is_bool($id))
   {
      die('invalid id');
   }

   if(isset($_POST['accept']))
   {
      $this->acceptId($id);
   }
   else if(isset($_POST['reject']))
   {
      $this->rejectId($id);
   }
}

This is obviously going to do something when a POST has occured, but the method was invoked each and every time. The reason why it works? If there is no variable named ‘id’ POSTed, filter_input returns null. And null is not boolean, so the test passes. But as it’s not a POST request, neither of the two other if-tests are true, so the code silently passes through (id can contain characters here, so the filter isn’t used to just get integers).

If you’re not going to throw an error when the parameter is missing, the test is actually completely useless. This bug had hidden itself within the usage of the type to test for fault instead of actually checking the value, and did not creep out before I rewrote the if-test.

Communicating The Right Thing Through Code

While trying to fix a larger bug in a module I never had touched before, I came across the following code. While technically correct (it does what it’s supposed to do, and there is no way to currently get it to do something wrong (.. an update on just that), does have a serious flaw:

$result = get_entry($id);
if(is_bool($result))
{
    die('bailing out');
}

Hopefully you can see the error in what the code communicates; namely that the return type from the function is used to what should be considered an error.

While this works as the only way the function can return a boolean value is if it returns false, the person reading the code at a later date will wonder what the code is supposed to do – he or she might not have any knowledge about how the method works. Maybe the method just sets up some resource, a global variable (.. no, don’t do that. DON’T.), etc, but the code does not communicate what we really expect.

As PHP is dynamically typed, checking for type before comparing is perfectly OK, as long as you’re not counting “no returned elements” as an error. The following code more clearly communicates it intent (=== in PHP is comparison based on both type and content, which means that both the type of the variable and the content of it have to match. 0 === “0” will be considered false.):

$result = get_entry($id);
if($result === false)
{
    die('bailing out');
}

Or if you’re interested in getting to know if the element returned is actually considered false (such as an empty array, an empty string, etc), just drop one of the equal signs:

$result = get_entry($id);
if($result == false)
{
    die('bailing out');
}

I’m also not fond of using die() as a method for stopping a faulty request, as that should be properly logged and dealt with in the best manner possible, but I’ll leave that for a later post.

Plans for 2009 – and seven things

Magne has posted his plans for 2009, and as this networking on teh intarwebs thing work, he’s asking his readers to do the same. It’s obviously easy to convince me to do stuff, so here goes nothing:

  • Listen to more amazing music: I’ve finally gotten a proper stereo in our new house, so I’m finding myself just listening to great music.
  • Attempt to keep up on my reading habits, which has dwindled a bit in the last months of 2008.
  • I’m doing Grenserittet and Birkebeinerrittet in August this year too, so I’m getting ready for starting the bicycle season as soon as the snow disappears. Even got new warm underwear for christmas, so I’m starting early! (If I just could remember to get my running shoes too, I might actually start even earlier!)
  • Keep the updates of my blog running, but attempt to start a more focused blog together with Christer.
  • Take more responsibility.
  • Launch at least one new product concept and idea.
  • Launch three new areas of content on pwned.no.
  • Finish more games. I’m really good a starting games, but not really good at finishing them.

Hopefully that covers the issues Magne were talking about, so then we head over to our next networking-on-teh-intarwebs-issue; Christer’s challenge to post seven things people might not know about me (this challenge has been all over Planet PHP for a few days, so people are probably getting bored..):

  1. I studied 2 years at NTNU before heading down south and finishing my master’s degree at HIOF within the field of digital maps and cartography. While in Trondheim I worked as a Oracle (Orakeltjenesten), so I’m a Orakel Emeritus.
  2. I played football for two years when I was 10 and 12. I even managed to be the score the most goals for our team, the 2nd team of Rolvsøy IF, in a season: 3.
  3. I drove a Volvo 340 for a year; a very nice car, but with five (.. or six) people in the car, even the smallest hill became a climb to save our lives..
  4. I’ve competed at The Gathering in different demoscene categories every year since 1997, except 2008. I’ve been less active in the norwegian demoscene during the last year, but that might change in the future.
  5. I’ve played Counter-Strike and Battlefield 2 semiserious for MESED, a clan that I’ve been running since 2000. I were also participating at CPL Copenhagen in 2003 (The Cyberathlete Professional League), where we actually managed to score a draw (and two losses).
  6. I’ve participated in several amateur movie projects (no, not those kind of movies), both as an “actor” and as an editor. I still occasionally edit gaming movies for MESED.
  7. I started up and ran (together with Geir) Vision of Chaos, a computer party in Norway. We managed to get 250-300 visitors in 1999, 2001 and 2002 before I called it quit. We always said we were going to do another party in 2010, as we could call that VoC MMX. The problem is that people no longer know what MMX is.. I also ran a web site for parties and organizing, called partai.org. Maybe we’ll rescue that some day too.

Like that, and that’s the way it is.

jQuery – IE triggers several click events

Strange problem occurred today, one of the very rare occasions were the behaviour of jQuery differed between Internet Explorer and Firefox. I’ve been trying to create a minimal example that replicates the behaviour, but have failed so far.

The problem was that in IE a click event triggered several times, which led an element to be expanded and then contracted again. This did not happen in Firefox. I found out that the problem was that I had placed my jQuery segment further inside the loop than I meant to, leading to code being duplicated four or five times through the page. After removing the duplicated function names and binds to .click(), everything worked as it should.

If you get several events triggered in Internet Explorer, but not in Firefox, check that you’re not accidentally binding the same function several times (.. while creating a minimized example that does this, I got the expected behaviour in both browsers, so I’m not completely sure of the reason). It might be worth a try as a fix, tho.