Implementing a “pending close” state in OSTicket


posted | about 6 minutes to read

Over the last few days, I’ve started to realize that the best way to learn something is just to dive in headfirst and try to do things.

Recent example: osTicket, the PHP-based ticket system we’re implementing at work. I hate to harp on it, but it’s just so cool. Anyway, my boss wanted to add a “custom code” feature to the system – make it so staff couldn’t close a ticket until a user signed off on it. At the time, I looked at the problem and said “err, new PHP function writing? I don’t even know the language!” I mulled it over for a week, thought about how I’d implement it, and when I came into work today I had a solid idea of the actual workflow of the “pending-closed” status. Here’s my thought process:

  1. User ticks a checkbox when responding to ticket which indicates ticket is ready to close.

  2. System moves ticket to “Pending Closed” status.

  3. Staff see a new column in their ticket view labeled “Pending Closed” where they can close this ticket.

  4. Staff cannot close tickets that are not “Pending Closed” status.

So what steps did I actually have to take to do this? Oh boy, that was fun.

Fair warning that I’ll be talking “technically” in the next few paragraphs, apologies if things get weird. I’ll do my best to explain!

The first step was pretty easy. Simply add the checkbox to the form. Getting the system to actually switch the status, however…that was less fun. The way the system works is by calling a function that uses parts of the submitted comment form to update the actual SQL database. The first order of business, then, was actually figuring out where the value was and how to set it to “pending” instead of, say, “open”. I wrote a function to do this, but it didn’t seem to work:

function pending() {
  $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), status='.db_input('pending');
  $sql.=' WHERE ticket_id='.db_input($this->getId());
  return (db_query($sql) && db_affected_rows());
}

Turned out that the status field was an “enum()” field in the SQL database with allowed values “open” and “closed”. What that meant was that my little script there wouldn’t run – it would set the value to blank, but not to pending. I had to edit the SQL table so that “pending” was allowed as an option.

Now that I had my function, I had to integrate it into the actual ticket form. I named my checkbox item in the form “labeltoclose” and tried to set up a check on submit to change the status, basically asking if the element existed in the set of data I was passing to the message post function:

if ($vars['labeltoclose'])
  $this->pending();`

Weird. Whenever I submitted a comment as a user, it would ALWAYS set the status to pending, regardless of whether I clicked the button. Well, alright. Let’s try testing if the value exists in the set of data I’m passing back:

if (isset($vars['labeltoclose']))
  $this->pending();`

Well, now it doesn’t go through at all! This is weird…

Anyway, this trial and error went on for a while until I figured out that maybe the checkbox wasn’t actually getting passed to the process that was checking to see if the checkbox was checked. I wrote up a quick line and inserted it in to see what was actually getting processed:

echo '<pre>'; print_r($_POST); echo '</pre>'';
echo '<pre>'; print_r($vars); echo '</pre>';`

I looked at the output that these commands gave me and the checkbox wasn’t getting passed in. One line of code later (check to see if the box was checked, if so pass it to the message post function), and my conditional was working again:

if (isset($_POST['labeltoclose']))
  $vars['labeltoclose']='on';

So this took care of the frontend. Clients could select that a ticket was ready to be closed, but what could staff do with those tickets? As it turned out, nothing. They couldn’t even SEE pending tickets. This was an interesting one, but fortunately rather easy to figure out. There were existing filters on getting open and closed tickets, so it was just a matter of copying a code block and pasting it, making sure that it referenced pending tickets instead. Similarly, adding conditionals to any reference of “Close a Ticket” meant that staff couldn’t even view the close buttons unless a ticket was set to pending. (Granted, another function had to be written in PHP to check whether a ticket was pending – but this was surprisingly easy! There was already a function written which just got the ticket status without checking it, and separate functions returned whether that ticket was open or closed. Copying one of those functions and modifying it to check for Pending was the work of seconds.)

Then came the fine tuning, and that’s where things got tougher. All of the other ticket statuses displayed the number of tickets with that status next to them, but pending wouldn’t! The function didn’t support it. I took a look at it, and it had a massive SQL query in it. Scary, but I knew if I modified it that I could make the function work without having to write any entirely new code – I could just make the same function call and just ask for pending tickets instead of, say, closed tickets.

Fortunately, SQL is ridiculously logical. I looked at what the query looked like, and simply appended on some entries relating to my “pending” status. Saved the new query (with a backup of the old one! I didn’t want to accidentally leave myself with a broken SQL query!) and refreshed the page – sure enough, I now had a number count for pending tickets.

The system isn’t done, of course. No system is. I’ll probably be asked at some point to add another feature, and that’s fine. After doing this, I know I can. It’s just a matter of knowing how the system works. Could I write a new PHP application from scratch? Probably not, but if after just a couple days of working with the language I can do what I’ve done, I don’t think it’d be a huge struggle to learn.

The other big takeaway here is that it’s not necessarily about knowing a language. It’s about knowing how code works in a general sense. Anyone can learn a language – it’s figuring out how to USE that language that’s important. It’s like if I knew every word in the English language but not any of the grammar. Right now, for me, I feel like I’m pretty up to speed on grammar and syntax (i.e., programmatic thinking) and just need to work on my vocabulary – so that’s perhaps the next step.