I recently utilized CakePHP's ability to automatically adjust view parameters based on the requested extension in the URI. This makes it really easy to specify a JSON formatted response by just tacking ".json" to the end of the URI. When I discovered this handy little feature of Cake's, I was praising the framework for such a quick and useful feature. Until things went wrong, of course.
I do most of my development in Chromium, but noticed when I was testing my code for the new JSON responses, data wasn't showing up properly in Firefox. I didn't think much of it and figured I would return to the issue once I could focus on browser compatibility. I eventually, however, found myself at that point in development. I discovered that returning only a sliver of the normal response data lead Firefox to respond properly. I also found Chromium was hitting it's own, significantly higher, limit. Firefox was capping the JSON response at 4096 bytes, whereas Chromium was somewhere in the area of 305kB. The Chromium limit was practically reasonable for my application, but there was no way I could dodge Firefox's measly 4kB cap. But wait, there's no way Firefox limits all AJAX responses to 4kB, right? Gmail can't possibly operate on an army of tiny 4kB responses, so what am I doing wrong?
Courtesy of Firebug, I compared responses and noticed something peculiar, my server's JSON responses contained the entire data contents in the headers of the response itself. After some Googling, it seems response header fields have a size limit. In Firefox that limit is, you guessed it, 4096 bytes. As I found, CakePHP's automatic handling of JSON extensions takes the view variables and places them directly in the headers. Not only that, but my JSON views were returning the json_encode()'ed result of my data, so the response contained the same data in two places. Without much time available for finding a proper way to make Cake stop adding data in the headers, I decided to go back and do it the ol' fashioned way, by myself. I got rid of Cake's router line for Router::parseExtensions('json'); left my controller action alone, and changed my view to:
[php]<?php
$this->layout = 'ajax';
Configure::write('debug', 0);
header('conten-type:text/x-json');
header('cache-control:no-store,no-cache,max-age=0,must-revalidate');
echo json_encode($results);
?>[/php]
And with that, both Firefox and Chromium now accept responses greater than 4kB and 305kB respectively. I'm still sprinting to finish this project, so I haven't had time to investigate if the core Cake team knows about this issue. I plan to revisit after project launch and see if I can learn more about this strange behavior.
Saturday, December 4, 2010
Monday, November 29, 2010
Sorting Related HABTM Model Data With Cake's Containable Behavior
Quite some time ago, Felix Geisendörfer created a behavior for CakePHP called `Containable`, which has since been added to CakePHP's core. I read about it and it always looked pretty interesting, but I dropped out of the CakePHP realm for a few years while I was busy completing my CSE degree. But now I'm back, and I stumbled upon a need to sort related data from a HABTM relationship. My heart filled with dread as I contemplated the ways to do this, mostly with CakePHP trickery and slow performing SQL queries. But luckily, Containable came to the rescue! I found a blog post that was extremely helpful, but it was written for the pagination helper, which I wasn't using. So below is the solution rewritten for regular find() calls to a model. Here's what my association looks like:
And I needed to make it so that when retrieving an event, the associated Image data was sorted by a specific field. Here's how to do that using Containable:
[php]public function myAction($order) {
$this->Event->Behaviors->attach('Containable');
$this->Event->contain(array(
'Image' => array(
'order' => $order
)
));
$event = $this->Event->find('first');
$this->set(compact('event'));
}[/php]
Well that was easy... hopefully I just saved you from a world of hurt.
Event hasAndBelongsToMany Image
And I needed to make it so that when retrieving an event, the associated Image data was sorted by a specific field. Here's how to do that using Containable:
[php]public function myAction($order) {
$this->Event->Behaviors->attach('Containable');
$this->Event->contain(array(
'Image' => array(
'order' => $order
)
));
$event = $this->Event->find('first');
$this->set(compact('event'));
}[/php]
Well that was easy... hopefully I just saved you from a world of hurt.
Sunday, November 28, 2010
PHP Ternary Reference Assignment
I'm a fan of CakePHP, but some times it can do some goofy things. One such example is the afterFind() Model callback, whose $results parameter may contain data in two different formats depending on how the find results were retrieved elsewhere in the code. This breaks the blackbox concept of functions in which the function shouldn't care less of what happens outside it's scope. Because of this oddity, you have to support either the model data existing in the $results array under a key named after the model, or the data existing directly in the $results array as simple key/value pairs. I attempted to make this easy to deal with by doing the following:
[php]$res = ($primary)
? &$result['MyModel']
: &$result;[/php]
But for whatever reason, PHP fails with an "unexpected &" error after the ternary `?` operator. The ternary syntax is just a shorthand I use for a really easy if-then, so I decided to expand it and see what happens.
[php]if($primary) {
$res = &$result['MyModel'];
} else {
$res = &$result;
}[/php]
This code runs without a hitch. So then what's happening? Your guess is as good as mine. I honestly can't discern what's making PHP break on the ternary version. Although the ternary syntax is rather simple and can be considered synonymous to the if-then code, PHP seems to handle them differently and consequently breaks reference assignment when using ternary.
[php]$res = ($primary)
? &$result['MyModel']
: &$result;[/php]
But for whatever reason, PHP fails with an "unexpected &" error after the ternary `?` operator. The ternary syntax is just a shorthand I use for a really easy if-then, so I decided to expand it and see what happens.
[php]if($primary) {
$res = &$result['MyModel'];
} else {
$res = &$result;
}[/php]
This code runs without a hitch. So then what's happening? Your guess is as good as mine. I honestly can't discern what's making PHP break on the ternary version. Although the ternary syntax is rather simple and can be considered synonymous to the if-then code, PHP seems to handle them differently and consequently breaks reference assignment when using ternary.
Thursday, October 7, 2010
Deleting Duplicate Rows in SQL Server Based on a Single Column
An import from a client's product list resulted in some incorrectly duplicated products. Normally this would be easy to sort out, except that the duplicates differed by a category column, so the good ol' DISTINCT keyword was of no help. This would also have been easy to do if working with MySQL by using a GROUP BY clause to select a row by distinct instances of a particular column. SQL Server, however, is another story. As I found, if you try the GROUP BY trick, SQL Server will whine.
I found some reasoning for this online, which is all well and good, except that MySQL does this like a champ and makes life easier as a result. So off I went to find a solution for SQL Server... I eventually stumbled on a page from the SQL Authority, by Pinal Dave (a very humble guy, judging by the title of his site). The gem, however, wasn't the post itself but a comment by Madhivanan further down the page. Thanks to Madhivanan, I came up with the following solution.
Server: Msg 8120, Level 16, State 1, Line 1
Column 'ItemNumber' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I found some reasoning for this online, which is all well and good, except that MySQL does this like a champ and makes life easier as a result. So off I went to find a solution for SQL Server... I eventually stumbled on a page from the SQL Authority, by Pinal Dave (a very humble guy, judging by the title of his site). The gem, however, wasn't the post itself but a comment by Madhivanan further down the page. Thanks to Madhivanan, I came up with the following solution.
DELETE t FROM(select (row_number() over (partition by ItemNumberorder by ItemID)) as cnt, * from Item) as tWHERE t.cnt > 1
This snippet will give you a count of how many times a particular item number appears in my database's Item table. We isolate only the ones that appear more than once and delete them from the table. Not as simple as using a GROUP BY, but it gets the job done.
Friday, March 26, 2010
Hyperterminal Replacement For Linux
This is a little gem I found recently when I needed to communicate with my OpenLog board. A lot of tutorials want you to pull up HyperTerminal in Windows to talk to OpenLog over the USB->UART bridge. My biggest problem with this is that I'm primarily a Linux user, where HyperTerminal is unavailable. That's all well and good, however, I'll just boot into my Windows 7 install and do it, right? Wrong. Windows 7 no longer ships with HyperTerminal. I jumped back to my Ubuntu Linux install and started hunting for a HyperTerminal replacement. The best solution I ended up finding was a command-line application called minicom. This handy little app is a bit to get the hang of, but once you're using it, it works like a charm. Here's a quick rundown of connecting to a serial device over USB using Minicom.
Wednesday, March 24, 2010
Flashing OpenLog Firmware in Ubuntu Linux
I recently hit a bug in the Sparkfun OpenLog v1.1 firmware that left the device useless. I found out the hard way that version 1.1 only supports up to 255 log files. Once it hits this limit the firmware doesn't know what to do with itself and loops endlessly. This even prevents you from entering command mode where you could otherwise reset the log number. Nate Seidle at SparkFun quickly released an update, v1.2, to correct this problem I was having. But now I had to figure out how to flash the firmware on my OpenLog. It turns out the process is extremely easy in Ubuntu, but the GitHub documentation targets mostly Windows, so I decided to document the process for Ubuntu users from start to finish here.
Labels:
arduino,
linux,
OpenLog,
Programming,
sparkfun,
Technology,
ubuntu
Thursday, January 14, 2010
8-bits of Processing Goodness
The last semester of my undergrad program in CSE is finally here! This semester I have a Senior Design course where students form their own groups and come up with an idea related to the curriculum and implement it. Now if only I had an idea of what to design...
I've been participating in autocross events for years and have always wished I could afford a data acquisition system like those you see used in Formula 1, Indy, Le Mans, and/or NASCAR. With a DAQ, I'd be able to see exactly what my car is doing at an event and use that information to help me drive the course faster on my next run. Hopefully.
That got me thinking. Surely I'm not the only amateur autocrosser wishing for an affordable data acquisition system made for the weekend warrior. In fact, LOTS of people across the nation, and across the globe would probably love such a system. I didn't know of any that existed on a college student budget, so I figured why not make one? It just so happens this senior design semester is the perfect time to get started. But where to begin?
I've been participating in autocross events for years and have always wished I could afford a data acquisition system like those you see used in Formula 1, Indy, Le Mans, and/or NASCAR. With a DAQ, I'd be able to see exactly what my car is doing at an event and use that information to help me drive the course faster on my next run. Hopefully.
That got me thinking. Surely I'm not the only amateur autocrosser wishing for an affordable data acquisition system made for the weekend warrior. In fact, LOTS of people across the nation, and across the globe would probably love such a system. I didn't know of any that existed on a college student budget, so I figured why not make one? It just so happens this senior design semester is the perfect time to get started. But where to begin?
Labels:
arduino,
Cars,
electronics,
School,
senior design,
Technology
Subscribe to:
Posts (Atom)