<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Curia &#187; Web Development</title>
	<atom:link href="http://blog.curiasolutions.com/tag/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.curiasolutions.com</link>
	<description>Technology thoughts and ideas</description>
	<lastBuildDate>Mon, 12 Dec 2011 00:55:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>The long overdue &#8220;Shootout&#8221; update</title>
		<link>http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/</link>
		<comments>http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/#comments</comments>
		<pubDate>Mon, 12 Sep 2011 19:08:06 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[pylons]]></category>
		<category><![CDATA[pyramid]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=1079</guid>
		<description><![CDATA[It&#8217;s been several months since I&#8217;ve had a chance to update The Great Web Framework Shootout, but this weekend I decided that it was time to dig in and freshen things up a bit. Not only have most of the frameworks seen new releases since the last revision, but I finally decided to move all [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/' addthis:title='The long overdue &#8220;Shootout&#8221; update ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been several months since I&#8217;ve had a chance to update <em><a title="The Great Web Framework Shootout" href="http://blog.curiasolutions.com/the-great-web-framework-shootout/">The Great Web Framework Shootout</a></em>, but this weekend I decided that it was time to dig in and freshen things up a bit.</p>
<p>Not only have most of the frameworks seen new releases since the last revision, but I finally decided to move all of the tests over to Amazon&#8217;s &#8220;release&#8221; version of the Ubuntu LTS AMI.</p>
<p>Below is a quick summary of what&#8217;s new in this revision:</p>
<ul>
<li>All tests were performed on the updated Ubuntu LTS AMI (ami-fbbf7892 ubuntu-images-us/ubuntu-lucid-10.04-amd64-server-20110719.manifest.xml)</li>
<li>The updated AMI was configured with Python 2.6.5, PHP 5.3.2, Ruby 1.9.2p290, Apache 2.2.14 (default config), mod_wsgi 2.8 (embedded mode), and mod_passenger 3.0.9</li>
<li>Rails 2.x and 3.0 were dropped from the &#8220;full stack(ish)&#8221; tests in favor of Rails 3.1.</li>
<li>CakePHP 1.2 was dropped from the PHP tests in favor of 1.3, but Symfony and Yii were added as they seem to have considerable market share.</li>
<li>CakePHP&#8217;s caching engine was incorrectly configured during the last round of tests, and this has been corrected.</li>
</ul>
<p><a href="http://profiles.google.com/seedifferently" target="_blank">Circle me on Google+</a> to keep track of further updates, and feel free to contact me there with any questions or comments.</p>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/' addthis:title='The long overdue &#8220;Shootout&#8221; update ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2011/09/the-long-overdue-shootout-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python as a PHP replacement?</title>
		<link>http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/</link>
		<comments>http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 18:11:50 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=637</guid>
		<description><![CDATA[I recently sat down to coffee with a new acquaintance of mine who spends much of his time implementing F/OSS projects at non-profit organizations, and who had just stepped into a lead web developer position using PHP. After sharing pleasantries we began trading stories and talking about each of our &#8220;tools of the trade.&#8221; When [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/' addthis:title='Python as a PHP replacement? ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I recently sat down to coffee with a new acquaintance of mine who spends much of his time implementing F/OSS projects at non-profit organizations, and who had just stepped into a lead web developer position using PHP. After sharing pleasantries we began trading stories and talking about each of our &#8220;tools of the trade.&#8221; When I mentioned that I used to do most of my web development in PHP, but have spent the past year or so trying to move as completely as possible to Python, his response was: &#8220;Huh, I have never really thought of Python as a PHP replacement.&#8221;</p>
<p>Now, this guy hasn&#8217;t exactly been living under a rock for the past 10 years—his resume was quite impressive and included projects in a number of different programming languages; But as you can imagine, I was rather surprised by his response, and it made me wonder: Has the Python community really been that bad at promoting the strengths of Python for web development? Or, does the nirvana experienced by switching from a language like PHP to Python just make us so at peace with the world that we forget the hordes of developers still stuck with C-style syntax? Either way, it got me thinking about a few of the reasons why <em>I</em> decided to switch from PHP to Python; and why I not only see Python as an excellent PHP replacement, but am surprised it is such a &#8220;best-kept secret&#8221; for web development.</p>
<p>There are already plenty of pages out there discussing <a href="http://wiki.python.org/moin/PythonVsPhp" target="_blank">Python vs. PHP as a language</a>, so I probably won&#8217;t get too technical here. I also want to try avoid turning this into a &#8220;Python is better than PHP because&#8230;&#8221; rant (for more on that, please see the end of this post), so I will simply share with you a few of the main reasons why <em>I</em> decided to replace PHP with Python as <em>my</em> primary language for web development:</p>
<p><span id="more-637"></span></p>
<h4>» Python is more flexible than PHP</h4>
<p>Python was engineered from the beginning to be a general purpose programming language. PHP on the other hand was written to overcome many of the &#8220;limitations&#8221; of the <a href="http://en.wikipedia.org/wiki/Cgi-bin" target="_blank">cgi-bin</a>. This should say a lot about the &#8220;soul&#8221; of each language, but the conclusion I have come to is:</p>
<ul>
<li>PHP is meant to do web things really well</li>
<li>Python is meant to do most things really well</li>
</ul>
<p>Sure, these days you <em>could</em> write a desktop GUI in PHP, but it would most likely <em>not</em> be the right tool for the job (and you&#8217;d probably get laughed at). On a somewhat related note: many PHP developers I know find themselves switching between PHP for their website tasks, and a variety of other languages for other tasks (Shell Scripting for command-line scripts, Perl for text processing, etc.). As a Python programmer, I can typically stick to <em>one programming language</em> no matter what the task at hand requires (especially when armed with <a href="http://ipython.scipy.org/" target="_blank">iPython</a>).</p>
<p>Now, the obvious argument for PHP at this point is: &#8220;But wait, since PHP was written specifically for the web, shouldn&#8217;t that actually give it <em>more</em> credibility as the right tool for the web job?&#8221; Well, 5 or 10 years ago I might have agreed with you, but web development has changed a lot in the past few years (not to mention the introduction of Python&#8217;s <a href="http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface" target="_blank">WSGI spec</a>).</p>
<p>The internet as a platform has grown and mutated drastically and now requires much more than &#8220;a server-side extension to HTML.&#8221; We are now in an age of full-blown internet <em>applications</em>, which require a true &#8220;application-level&#8221; language. In my opinion, PHP has only recently begun to move in that direction with the v5.3 release (as well as updates expected in PHP 6). That alone should give you pause when pondering PHP&#8217;s ability to &#8220;keep up&#8221; with the growth of the web.</p>
<p>In short, the internet continues to transform into an arena that is much less of a website platform, and much more of an application platform. To me, this makes a general purpose language such as Python the obvious choice for &#8220;future-proof&#8221; internet development.</p>
<h4>» Python is typically faster than PHP, <span style="text-decoration: line-through;">even</span> especially on the web</h4>
<p>You might find PHP beating out Python in a simple &#8220;hello world&#8221;-type test, but &#8220;real-world&#8221; applications will typically run much faster in Python. In a Web 2.0 world where everyone has broadband, speed is now an important factor in keeping your visitors happy.</p>
<p>In addition to &#8220;raw, under-the-hood&#8221; speed, Python&#8217;s language philosophy means it will typically <a href="http://groups.google.com/group/comp.lang.python/msg/83907b65bdee30f6" target="_blank">scale better than PHP</a> (although this can be argued a million different ways, since scalability usually involves much more than the language).</p>
<p>I&#8217;ve already done <a href="http://blog.curiasolutions.com/2009/09/the-great-web-development-shootout/" target="_blank">benchmarks</a> comparing a few popular web frameworks, but if you&#8217;re still curious I&#8217;d suggest you <a href="http://www.google.com/search?q=is+python+or+php+faster%3F" target="_blank">dig around with Google</a> for a while.</p>
<h4>» Python is easier to read and maintain than PHP</h4>
<p>Any veteran programmer will tell you that code <em>readability</em> plays a huge factor in code <em>maintainability</em>. With that in mind, Python was designed with some pretty strict syntax rules in regards to code-blocks and whitespace. While this may initially frustrate programmers who are used to a looser &#8220;bracket-encapsulated&#8221; language, it actually forces you to write more readable (and therefore, more maintainable) code.</p>
<p>Other than readability, Python&#8217;s clean syntax also means:</p>
<ul>
<li>You can write more code with less errors (because they&#8217;re so easy to spot). This often comes as a pleasant surprise to programmers migrating from C-style languages (take <a href="http://www.python.org/about/success/esr/" target="_blank">Eric Raymond</a> for example).</li>
<li>You end up typing less — No more semicolons or brackets, and fewer parentheses.</li>
<li>Your eyes don&#8217;t have to move around as much to figure out what&#8217;s going on.</li>
<li>Your first guess about what&#8217;s happening in a code-block is usually correct.</li>
</ul>
<p>When you have time to kill, I&#8217;d recommend a stroll through <a href="http://rosettacode.org/wiki/Main_Page" target="_blank">Rosetta Code</a> to compare how different languages &#8220;look&#8221; when tackling the same problem. Unless you just love brackets, I think you&#8217;ll find the non C-style syntaxes much easier to read.</p>
<h4>» Python is more consistent than PHP</h4>
<p>Continuing somewhat in the vein of readability is the topic of consistency. Since PHP&#8217;s lack of consistency has already been studied exhaustively by the Perl folks, I will spare you my rant and suggest you <a href="http://tnx.nl/php.html" target="_blank">read theirs</a>.</p>
<p>As a side note on this topic: I often hear PHP programmers talk about how awesome PHP&#8217;s documentation is in that you can open a web browser and just type &#8220;php.net/some_function&#8221; to get help. Well, documentation recall usually isn&#8217;t that big of a deal for me (because I have a somewhat photographic memory), but I will say that after switching to Python I found myself turning to its documentation <em>significantly</em> less than I had with PHP, simply because I didn&#8217;t have to keep reminding myself whether that infrequently used function was named some_function or somefunction. With Python, the function/method I need is usually named <em>exactly</em> what I expect it to be named, and returns <em>exactly</em> what I expect it to return.</p>
<p>Oh, and don&#8217;t even get me started on PHP&#8217;s recent <a href="http://blog.fedecarg.com/2008/10/28/php-namespaces-controversy/" target="_blank">namespace</a> <a href="http://michaelkimsal.com/blog/disappointed-with-php-namespace-seperator-decision/" target="_blank">decision</a>.</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">» However, PHP still excels in a few areas «</h4>
<p>Having said all of that, there are a few areas where I believe PHP may still shine brighter than Python:</p>
<h4>» PHP hosting support <span style="text-decoration: line-through;">is</span> may be more prevalent than Python</h4>
<p>It&#8217;s practically unheard of to find yourself on a web host that doesn&#8217;t support PHP out of the box. However, this is becoming less and less of an issue since most Python web applications can now be deployed using tools such as FastCGI or mod_proxy (as opposed to the popular <a href="http://code.google.com/p/modwsgi/" target="_blank">mod_wsgi</a> setup, which often requires root access to configure). These days any &#8220;reputable&#8221; web host is probably going to support some sort of strategy for deploying Python web applications. Of course, this only really applies to shared hosting environments without root access. If you&#8217;ve got a VPS or dedicated server you&#8217;re fine.</p>
<h4>» PHP is arguably &#8220;more seasoned&#8221; on the web than Python</h4>
<p>The communities behind projects like Drupal and WordPress really stand out to me as examples of the maturity of PHP on the web. Although similar Python web projects have been slowly emerging (and <a href="http://plone.org/" target="_blank">Plone</a> has been around for years, if that&#8217;s your cup of tea), they don&#8217;t really compete yet in my opinion.</p>
<p>Of course, I am only talking about specific web projects here. Language wise, Python has been around longer than PHP. Web 2.0 framework wise, Python&#8217;s offerings have been around about as long as PHP&#8217;s (pretty much every language had its own answer to Ruby on Rails in 2005).</p>
<h4>» PHP <em>seems</em> easier than Python at first (and might be for simple deployments)</h4>
<p>There&#8217;s something magical about throwing together a few quick index.php/about.php/contact.php files and uploading them to the httpdocs directory of your webserver and it &#8220;just working.&#8221; A lot of simple websites have no need for acronyms like MVC, ORM, and DRY, and in those cases PHP is an excellent &#8220;server-side extension&#8221; to HTML. However, if and when you begin to scale, you&#8217;ll either find yourself switching to a full-blown framework, or throwing one together to help facilitate your growth. At that point, you&#8217;ll probably begin discovering the &#8220;dark corners&#8221; of PHP, and may find yourself wishing you had &#8220;done it right&#8221; the first time.</p>
<p>&nbsp;</p>
<h4 style="text-align: center;">» So, which is better? «</h4>
<p>Remember, the point of this post is to solidify the fact that Python can be an excellent PHP <em>replacement</em>. When it comes to programming languages, &#8220;better&#8221; is often more a case of personal preference than anything else. However, to <em>me</em> the points discussed above make Python the better choice when it comes to what <em>I</em> like in a web development language.</p>
<p>So, is Python a better web development language than PHP?<br />
Well, does Nike make a better shoe than Adidas?</p>
<p>The most honest answer is probably: &#8220;It depends.&#8221; Python definitely has some significant advantages over PHP in certain circumstances, but the same could probably be said of PHP in other circumstances (although limited to the web I imagine).</p>
<p>&nbsp;</p>
<p>I hope this post has encouraged you PHP programmers out there to take another look at Python. It may take some getting used to (Python&#8217;s way of doing things is inherently quite different than PHP&#8217;s), but you will probably find yourself thanking me later.</p>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/' addthis:title='Python as a PHP replacement? ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/11/python-as-a-php-replacement/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Dead-simple pagination wizardry with TurboGears 2</title>
		<link>http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/</link>
		<comments>http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 01:00:21 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=556</guid>
		<description><![CDATA[I recently had to implement pagination in a TG 2 project that I&#8217;m almost finished with. Although I had previously glanced at the paginate webhelper module, I first turned to the updated TurboGears documentation to see what was &#8220;officially&#8221; written up about this subject. A lot of work has been going into the TG docs [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/' addthis:title='Dead-simple pagination wizardry with TurboGears 2 ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I recently had to implement pagination in a TG 2 project that I&#8217;m almost finished with. Although I had previously glanced at the <a href="http://turbogears.org/2.1/docs/modules/thirdparty/webhelpers_paginate.html" target="_blank"><em>paginate</em></a> webhelper module, I first turned to the <a href="http://turbogears.org/2.1/docs/index.html" target="_blank">updated TurboGears documentation</a> to see what was &#8220;officially&#8221; written up about this subject.</p>
<p>A lot of work has been going into the TG docs in preparation for the upcoming v2.1 launch, and one little gem that was recently added was the <a href="http://turbogears.org/2.1/docs/main/Pagination/index.html" target="_blank">Pagination Quickstart</a> (thanks Lukas). While this sent me down the right path towards pagination perfection, there were a few things that came up that I felt like deserved further explanation:</p>
<ol>
<li>The <a href="http://turbogears.org/2.1/docs/modules/tgdecorators.html#tg.decorators.paginate" target="_blank">@paginate() decorator</a> is an extremely simple wrapper for the <em>paginate</em> webhelper module.</li>
<li>When paginating SQLAlchemy queries, <em>paginate</em> runs a duplicate <em>count()</em> query to figure out its current position in the data collection. While the magic of this is nice, the possible performance issues with duplicating complex SQL queries on a high-traffic website could be undesirable.</li>
<li>It&#8217;s common to have controller methods dynamically switch to a &#8220;feed template&#8221; when doing AJAX pagination. Don&#8217;t worry, <em>paginate</em> + <em>override_template</em> makes this a piece of cake!</li>
</ol>
<p>&nbsp;</p>
<blockquote><p>The @paginate() decorator makes pagination a breeze</p></blockquote>
<p>The @paginate decorator is a wrapper for the paginate module that can be added to your controller methods. Simply specify your data collection&#8217;s name as the first argument of the decorator, and pagination is &#8220;automagically&#8221; setup for you.</p>
<p>An example controller method with pagination would look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># dead-simple pagination in TurboGears 2</span>
&nbsp;
@expose<span style="color: black;">&#40;</span><span style="color: #483d8b;">'myproject.templates.posts'</span><span style="color: black;">&#41;</span>
@paginate<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;posts&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> posts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    posts = DBSession.<span style="color: black;">query</span><span style="color: black;">&#40;</span>Posts<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>posts=posts<span style="color: black;">&#41;</span></pre></div></div>

<p>Really? That was easy!</p>
<p>The documentation on this decorator seems quite clear to me, so instead of repeating its content here I will simply give you a <a href="http://turbogears.org/2.1/docs/modules/tgdecorators.html#tg.decorators.paginate" target="_blank">link for further reading</a>.</p>
<p><span id="more-556"></span>&nbsp;</p>
<blockquote><p>SQLAlchemy pagination performance wizardry</p></blockquote>
<p>The main issue here is that the paginate module has to figure out its current position in the data collection in order to be able to spit out the right &#8220;chunk&#8221; of data (as well as to provide you with fancy stuff like &#8220;page 3 of 6&#8243;). So, by default when you give it an SQLAlchemy query object, it runs a count() query to figure this out. This results in two practically identical SQL queries (one to get the total count, and the other to return your actual collection of data). While this may not be an issue on simple queries, duplicating complex queries on a high-traffic website could be disastrous.</p>
<p>Remember, magic can be unpredictable, so before we dive into this topic there are a few things you should take into consideration:</p>
<ul>
<li>This technique is not compatible with the @paginate() decorator due to the fact that the current page arg isn&#8217;t passed into the controller method when using the decorator, so be ready to get your hands dirty with the full-blown <em>paginate</em> module.</li>
<li>The SQLAlchemy all() query method results in immediate query execution. This may have undesirable side-effects.</li>
<li>I&#8217;m sure there is a cleaner/sexier way to do this, but for the sake of time and in an effort to be verbose this is what I have come up with so far. Please leave a helpful comment below if your magic is cleaner than mine.</li>
</ul>
<p>Ok, so now that we are familiar with the problem, what is a good solution? Well, a rough hack to work around this issue is to use SQLAlchemy&#8217;s limit() and offset() query methods combined with the all() method to get SQLAlchemy to return a list instead of a query object. This puts <em>paginate</em> to work on the list instead of on the database, avoiding the extra count() query. However, as tricky as this may be, there are still problems:</p>
<ol>
<li>In order for paginate to calculate a correct current position based on the &#8220;page&#8221; it thinks it&#8217;s on, you&#8217;ve got to pad the <strong>beginning</strong> of the list you send to the paginate.Page() method with enough items to accurately reflect the &#8220;current&#8221; size of the data collection.</li>
<li>In order for paginate to know there are more records waiting to be loaded, you&#8217;ve got to pad the <strong>end</strong> of the list you send to the paginate.Page() method with at least one more item than each page&#8217;s specified item limit.</li>
</ol>
<p>This may seem confusing at first, but an example controller method should help clear things up for you:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># import the paginate webhelper</span>
<span style="color: #ff7700;font-weight:bold;">from</span> webhelpers <span style="color: #ff7700;font-weight:bold;">import</span> paginate
<span style="color: #808080; font-style: italic;"># specify the number of items you want per page</span>
items_per_page = <span style="color: #ff4500;">20</span>
&nbsp;
@expose<span style="color: black;">&#40;</span><span style="color: #483d8b;">'myproject.templates.posts'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> posts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, page=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># specify the limit, plus 1 so the Page() method can tell if extra data is available</span>
    limit = items_per_page + <span style="color: #ff4500;">1</span>
    <span style="color: #808080; font-style: italic;"># specify the offset to start with</span>
    offset = <span style="color: black;">&#40;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> items_per_page
&nbsp;
    <span style="color: #808080; font-style: italic;"># if the offset is greater than 0, we have to pad the beginning of the list</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> offset: posts = <span style="color: black;">&#91;</span>x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>offset<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># otherwise we're starting at the beginning (with an empty list)</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>: posts = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># load the DB data into the list</span>
    posts.<span style="color: black;">extend</span><span style="color: black;">&#40;</span>DBSession.<span style="color: black;">query</span><span style="color: black;">&#40;</span>Posts<span style="color: black;">&#41;</span>.<span style="color: black;">limit</span><span style="color: black;">&#40;</span>limit<span style="color: black;">&#41;</span>.<span style="color: black;">offset</span><span style="color: black;">&#40;</span>offset<span style="color: black;">&#41;</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># setup the pagination object</span>
    pagination = paginate.<span style="color: black;">Page</span><span style="color: black;">&#40;</span>posts, page, items_per_page=items_per_page<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># either use tmpl_context or return the object in the return dict</span>
    tmpl_context.<span style="color: black;">pagination</span> = pagination
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>posts=pagination.<span style="color: black;">items</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Voilà! Now that you&#8217;re dealing with a list, pagination should work as expected without the extra &#8220;count()&#8221; query.</p>
<p>&nbsp;</p>
<blockquote><p>Use override_template() for dynamic template rendering</p></blockquote>
<p>AJAX pagination is a common practice and often provides a richer user experience than &#8220;static&#8221; pagination. Fortunately, AJAX pagination is almost as easy to setup as normal pagination, and only requires <a href="http://turbogears.org/2.1/docs/modules/thirdparty/webhelpers_paginate.html#can-i-use-ajax-ajah" target="_blank">a few extra tweaks</a> to an already simple configuration.</p>
<p>The only &#8220;tricky&#8221; thing here is if you&#8217;re accessing the same controller method for partial data as well as the full page. In such a case, you&#8217;ll need to have the controller method render two separate templates depending on if you&#8217;re asking for the &#8220;full&#8221; page, or just the listing of data. Don&#8217;t worry though, <em>paginate</em> automatically provides you with a &#8220;partial&#8221; arg that you can check against, and override_template() allows you to override whatever template you have defined in the @expose() decorator.</p>
<p>Modifying the previous example&#8217;s controller method for this type of functionality looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># add the override_template import</span>
<span style="color: #ff7700;font-weight:bold;">from</span> tg <span style="color: #ff7700;font-weight:bold;">import</span> override_template
&nbsp;
<span style="color: #808080; font-style: italic;"># add the &quot;partial&quot; arg to the controller method</span>
<span style="color: #ff7700;font-weight:bold;">def</span> posts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, page=<span style="color: #ff4500;">1</span>, partial=<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...snip...</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> partial:
        override_template<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">posts</span>, <span style="color: #483d8b;">'mako:myproject.templates.post_feed'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>posts=pagination.<span style="color: black;">items</span><span style="color: black;">&#41;</span></pre></div></div>

<p>More information on override_template() can be found in <a href="http://turbogears.org/2.1/docs/modules/tgdecorators.html#tg.decorators.override_template" target="_blank">the docs</a>.</p>
<p>&nbsp;</p>
<p>I hope this tutorial has been helpful. I will be submitting a TG docs pull request soon, so please leave comments if you have any suggestions or feedback.</p>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/' addthis:title='Dead-simple pagination wizardry with TurboGears 2 ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/11/dead-simple-pagination-wizardry-with-turbogears-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The great web technology shootout &#8211; Round 2: PHP deserves a helping hand</title>
		<link>http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/</link>
		<comments>http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 06:53:41 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=278</guid>
		<description><![CDATA[[A lot of the information below is out of date. Please see the new framework shootout page for the latest benchmarks.] [This post is the continuation of a series. Please read Round 1 first if you are just now joining us.] In Round 1, PHP was looking like quite the tortoise of the group. However, [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/' addthis:title='The great web technology shootout &#8211; Round 2: PHP deserves a helping hand ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p><strong>[A lot of the information below is out of date. Please see the new <a href="http://blog.curiasolutions.com/?p=963">framework shootout page</a> for the latest benchmarks.]</strong></p>
<p>[This post is the continuation of a series. Please read <a href="http://blog.curiasolutions.com/?p=172">Round 1</a> first if you are just now joining us.]</p>
<p>In <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, PHP was looking like quite the tortoise of the group. However, if you&#8217;re familiar with some of the core differences between Python &amp; PHP, you&#8217;ll know that Python has been &#8220;cheating&#8221; slightly.</p>
<p>Let me explain: By default, Python compiles each script into bytecode on its first execution, allowing this bottleneck to be skipped on subsequent runs. PHP, however does not perform this type of optimization by default (in the 5.x line at least), so the PHP interpreter must re-compile each file every time it is run. As you can imagine, this can give PHP (without an accelerator) a huge disadvantage when compared to languages such as Python.</p>
<p><strong>With this in mind, I have decided to take Round 2 to focus solely PHP.</strong> This will hopefully provide a clear picture of the benefits of PHP bytecode caching (at least when it comes to page-views — the memory benefits are a whole other story), and give you an idea of PHP&#8217;s performance with the help of an accelerator.</p>
<p>There are <a href="http://en.wikipedia.org/wiki/List_of_PHP_accelerators" target="_blank">many PHP accelerators available</a>, but I have chosen <a href="http://php.net/apc" target="_blank">APC</a> for use here (mostly due to its inclusion in the upcoming PHP 6 core).<span id="more-278"></span></p>
<h5>What you should know about Round 2:</h5>
<ol>
<li>The hardware/software platform is the same as in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>.</li>
<li>PHP has been upgraded to v5.2.9.</li>
<li>The APC tests are using APC v3.0.19.</li>
<li>ApacheBench was run with -n # -c 10, with -n usually being 5000 or 10000, depending on the test subject&#8217;s speed.</li>
<li>Each test was run several times to make sure that there were no anomalies, with the &#8220;optimum average&#8221; chosen as the numbers represented here.</li>
<li>In an attempt to try to make these tests more scientific, I am now including the source code for each test (minus the CMS tests, which were performed on a standard install).</li>
</ol>
<p>My apc.ini settings:</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;"><span style="color: #000099;">extension</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> apc.so</span>
apc.enabled <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 1</span>
apc.shm_size <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 96</span>
apc.include_once_override <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> 1</span>
apc.mmap_file_mask <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> /tmp/apc.XXXXXX</span></pre></div></div>

<blockquote>
<h4>Raw PHP &#8211; <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/09/php_test_src.zip">php_test_src.zip</a></h4>
</blockquote>
<p>To investigate the speed of &#8220;raw PHP&#8221;, I created a couple of minimal PHP scripts that printed out a simple &#8220;hello world&#8221;, and read a few lines of text from a database. Take a look at the test source code for reference.</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">4199.43</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello_db<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2524</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">2797.54</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">6618.42</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello_db<span style="color: #66cc66;">.</span>php
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2524</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">3713.99</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Right out of the gate, we can see that APC gives PHP a significant boost.</p>
<p>Of course, a script that simply does a &#8220;echo &#8216;hello world&#8217;&#8221; isn&#8217;t really practical, so let&#8217;s take a look at a couple of popular PHP frameworks to see what a full stack looks like.</p>
<blockquote>
<h4>CakePHP v1.2.5 &#8211; <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/09/cakephp_test_src.zip">cakephp_test_src.zip</a></h4>
</blockquote>
<p>CakePHP was the slowest test subject by a large margin in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, but if you take a look at the caching section of its core configuration file you can see that the developers have written it with acceleration in mind. It includes special configuration directives for not just APC, but also <a href="http://xcache.lighttpd.net/" target="_blank">Xcache</a> and <a href="http://www.danga.com/memcached/" target="_blank">Memcache</a>.</p>
<p>Still though, without acceleration CakePHP is a sad story indeed:</p>
<h5>APC Disabled &#8211; File Caching Engine (default)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">13</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">45.25</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">931</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">39.90</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello_db
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2469</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">38.80</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>However, with the help of APC things finally begin to look reasonable:</p>
<h5>APC Enabled &#8211; APC Caching Engine (in core.php)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">13</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">140.98</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">931</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">120.04</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span>hello_db
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2469</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">117.56</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, APC increases CakePHP&#8217;s speed about threefold in these examples. These results may or may not be acceptable to you (remember that we are running these tests with a concurrency of 10), but I felt much better about CakePHP after pairing it with APC.</p>
<blockquote>
<h4>Kohana v3.0 &#8211; <a href="http://blog.curiasolutions.com/wp-content/uploads/2009/09/kohana3_test_src.zip">kohana3_test_src.zip</a></h4>
</blockquote>
<p>Kohana (a divergent of CodeIgnitor) is a much more lightweight PHP framework than CakePHP, but still gives you a pretty full featureset. Since v3.0 was released shortly after <a href="http://blog.curiasolutions.com/?p=172">Round 1</a>, I decided to use the new version for the tests here in Round 2.</p>
<p>It should be noted that although file caching is enabled in a default CakePHP install, Kohana&#8217;s caching is disabled by default. I have included a couple of tests with caching disabled here to exhibit the performance of a default Kohana install.</p>
<h5>APC Disabled &#8211; Caching Disabled (default)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">86.73</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Disabled &#8211; Caching Enabled (bootstrap.php)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">180.50</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">930</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">162.27</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the Database module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellodb<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">113.92</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>helloorm<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">99.73</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, even without APC Kohana is quite a bit faster than CakePHP.</p>
<h5>APC Enabled &#8211; Caching Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">125.93</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled &#8211; Caching Enabled (bootstrap.php)</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">The <span style="color: #993333;">RETURN</span> <span style="color: #ff0000;">'hello world'</span> test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hello<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">12</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">280.67</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The template hello world test<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellos<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">930</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">253.50</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the Database module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>hellodb<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">173.28</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
The simple database <span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">QUERY</span> test <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff; font-weight: <span style="color: #006600;">bold</span>;">USING</span> the ORM module<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>helloorm<span style="color: #66cc66;">/</span><span style="color: #993333;">INDEX</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">2525</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">153.90</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Although not a threefold gain as with CakePHP, Kohana with APC+caching definitely makes a good attempt at shortening the gap seen in <a href="http://blog.curiasolutions.com/?p=172">Round 1</a> between the PHP frameworks and the offerings from other languages. Of course, if raw speed is what you&#8217;re looking for, there are <a href="http://www.doophp.com/benchmark" target="_blank">faster PHP frameworks available</a> (note that the benchmarks on that page were run on a completely different setup and should not be compared with any of the numbers here).</p>
<p><strong>Next, let&#8217;s take a look at how APC enhances the performance of a few of PHP&#8217;s heavyweights.</strong></p>
<blockquote>
<h4>WordPress v2.8.4 (default install)</h4>
</blockquote>
<p>Although I&#8217;ve heard that WordPress has a built-in caching setting, a quick glance at wp-settings.php did not reveal anything. So, there are simply two WordPress tests—with APC, and without:</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5519</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">24.80</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Document Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5519</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">74.00</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<blockquote>
<h4>Joomla v1.5.14 (default install, without sample data)</h4>
</blockquote>
<p>The results of these tests were quite disappointing to me, and made me wonder if I was doing something wrong. Sadly, it looks as though Joomla is quite the slow one of the bunch.</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Joomla Caching Disabled <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">DEFAULT</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">27.90</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Joomla Caching Enabled <span style="color: #66cc66;">&#40;</span>File<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">31.46</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Joomla Caching Disabled<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">41.27</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
Joomla Caching Enabled <span style="color: #66cc66;">&#40;</span>APC<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">4006</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">45.01</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<blockquote>
<h4>Drupal v6.14 (default install, clean URLs disabled)</h4>
</blockquote>
<p>Drupal has several caching settings, so I decided to see what each one would look like and how much of a difference &#8220;aggressive&#8221; caching made.</p>
<h5>APC Disabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Drupal Caching Disabled <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">DEFAULT</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">36.72</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Normal&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">289.69</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Aggressive&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">335.68</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<h5>APC Enabled</h5>

<div class="wp_syntax"><div class="code"><pre class="progress" style="font-family:monospace;">Drupal Caching Disabled<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">83.93</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Normal&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">498.37</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #ff0000;">&quot;Aggressive&quot;</span> Drupal Caching<span style="color: #66cc66;">:</span>
&nbsp;
<span style="color: #006600;">Document</span> Path<span style="color: #66cc66;">:</span>          <span style="color: #66cc66;">/</span>
Document <span style="color: #993333;">LENGTH</span><span style="color: #66cc66;">:</span>        <span style="color: #cc66cc;">5548</span> bytes
Requests per second<span style="color: #66cc66;">:</span>    <span style="color: #cc66cc;">564.48</span> <span style="color: #66cc66;">&#91;</span>#<span style="color: #66cc66;">/</span>sec<span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">&#40;</span>mean<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>As you can see, Drupal&#8217;s caching (especially when combined with APC) changes things drastically. These results seem to indicate that Drupal&#8217;s caching does a great job of allowing the CMS to get out of the way.</p>
<h4>Closing thoughts</h4>
<ul>
<li>The benefits of a PHP accelerator are really too good to pass up. Even without written-in caching, an accelerator can give your code a significant boost.</li>
<li>While these tests have only really explored the impact on website page-load times, a PHP accelerator typically also cuts down on the amount of memory used by your PHP scripts.</li>
<li>PHP 6 has promised to fix a lot of things, including the lack of built-in bytecode caching. It will be interesting to revisit these tests in a few years (?) to see how much optimization the new version brings to the table.</li>
</ul>
<h5>Can&#8217;t get enough of this madness? Just wait until you read <a href="http://blog.curiasolutions.com/?p=409">Round 3</a>!</h5>
<p>(Note: Please don&#8217;t leave benchmarking requests as comments. If you&#8217;d like me to take a look at your favorite framework, direct message me on twitter. Thanks!)</p>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/' addthis:title='The great web technology shootout &#8211; Round 2: PHP deserves a helping hand ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/09/the-great-web-technology-shootout-round-2-php-deserves-a-helping-hand/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Making TurboGears and Authorize.net play nice together</title>
		<link>http://blog.curiasolutions.com/2009/07/making-turbogears-and-authorize-net-play-nice-together/</link>
		<comments>http://blog.curiasolutions.com/2009/07/making-turbogears-and-authorize-net-play-nice-together/#comments</comments>
		<pubDate>Sat, 18 Jul 2009 19:18:49 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=40</guid>
		<description><![CDATA[I recently had to wire up an Authorize.net form for a TurboGears project I&#8217;m building, and since I&#8217;m a bit new to custom form validation in TG I had quite a bit of trouble figuring out the &#8220;right&#8221; way to do it. The goal was to get the form to go through two layers of [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/07/making-turbogears-and-authorize-net-play-nice-together/' addthis:title='Making TurboGears and Authorize.net play nice together ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I recently had to wire up an Authorize.net form for a TurboGears project I&#8217;m building, and since I&#8217;m a bit new to custom form validation in TG I had quite a bit of trouble figuring out the &#8220;right&#8221; way to do it.</p>
<p>The goal was to get the form to go through two layers of validation before passing:</p>
<ol>
<li>Use the validation packages provided by TG (<a href="http://toscawidgets.org/" target="_blank">tw.forms</a> and <a href="http://www.formencode.org/" target="_blank">formencode</a>)</li>
<li>If the first layer of validation passes, try to run the authorize.net charge. If this returns a response code of 1 (approved) then all validation has passed. Otherwise, invalidate the form and flash the authorize.net error.</li>
</ol>
<p>tw.forms and formencode are awesome packages, but at first glance there didn&#8217;t seem to be &#8220;one obvious way&#8221; to do things. I found the documentation and tutorials to be scant at best, and eventually went to the <a href="http://groups.google.com/group/turbogears" target="_blank">TurboGears mailing list</a> for help. In spite of the fact that I&#8217;d probably give TurboGears a &#8220;C&#8221; <em>at best</em> for its documentation (not to mention the availability of &#8220;verbose&#8221; tutorials), the folks on the mailing list and IRC channel (when it&#8217;s actually active) seem to be quite helpful.</p>
<p>Eventually (and with additional help from Google&#8217;s <a href="http://www.google.com/codesearch" target="_blank">source code search</a>) I was able to hack together something that worked as planned, and was overjoyed to observe chained validators in action. Below is some example code provided for your hacking pleasure. To download the full example file, see the links at the bottom of the post.<span id="more-40"></span></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># FancyValidator to process the Credit Card using the authorize package</span>
<span style="color: #ff7700;font-weight:bold;">class</span> ProcessCard<span style="color: black;">&#40;</span>validators.<span style="color: black;">FancyValidator</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> _to_python<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, value, state<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">from</span> authorize <span style="color: #ff7700;font-weight:bold;">import</span> aim <span style="color: #ff7700;font-weight:bold;">as</span> aim_api
&nbsp;
        <span style="color: #808080; font-style: italic;"># Setup the aim Api object.</span>
        aim = aim_api.<span style="color: black;">Api</span><span style="color: black;">&#40;</span>AUTHNET_LOGIN, AUTHNET_KEY, is_test=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Create a transaction against a credit card</span>
        result_dict = aim.<span style="color: black;">transaction</span><span style="color: black;">&#40;</span>
            amount=u<span style="color: #483d8b;">&quot;16.00&quot;</span>,
            card_num=<span style="color: #008000;">unicode</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#91;</span><span style="color: #483d8b;">'card_number'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>,
            exp_date=<span style="color: #008000;">unicode</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#91;</span><span style="color: #483d8b;">'card_expiry'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>,
            <span style="color: #808080; font-style: italic;"># ...and others...</span>
            <span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> result_dict<span style="color: black;">&#91;</span><span style="color: #483d8b;">'code'</span><span style="color: black;">&#93;</span> == <span style="color: #483d8b;">'1'</span>:
            <span style="color: #808080; font-style: italic;"># success</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> value
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #808080; font-style: italic;"># failure</span>
            <span style="color: #ff7700;font-weight:bold;">raise</span> validators.<span style="color: black;">Invalid</span><span style="color: black;">&#40;</span>result_dict<span style="color: black;">&#91;</span><span style="color: #483d8b;">'reason_text'</span><span style="color: black;">&#93;</span>, value, state<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> AuthnetForm<span style="color: black;">&#40;</span>TableForm<span style="color: black;">&#41;</span>:
    submit_text=<span style="color: #483d8b;">'Process Card'</span>
&nbsp;
    validator = validators.<span style="color: black;">Schema</span><span style="color: black;">&#40;</span>
        chained_validators = <span style="color: black;">&#91;</span>
            validators.<span style="color: black;">CreditCardValidator</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'card_type'</span>,<span style="color: #483d8b;">'card_number'</span><span style="color: black;">&#41;</span>,
            validators.<span style="color: black;">CreditCardSecurityCode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'card_type'</span>,<span style="color: #483d8b;">'card_cvv'</span><span style="color: black;">&#41;</span>,
            <span style="color: #808080; font-style: italic;"># you could also add an expiry validator, but authnet will handle this for you</span>
            ProcessCard<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: black;">&#93;</span>
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">class</span> fields<span style="color: black;">&#40;</span>WidgetsList<span style="color: black;">&#41;</span>:
        name = TextField<span style="color: black;">&#40;</span>validator=validators.<span style="color: black;">String</span><span style="color: black;">&#40;</span>not_empty=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># ...and others like address, city, state, zip...</span>
        spacer = Spacer<span style="color: black;">&#40;</span>suppress_label=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
        card_type = SingleSelectField<span style="color: black;">&#40;</span>options=<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'visa'</span>, <span style="color: #483d8b;">'Visa'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">'mastercard'</span>, <span style="color: #483d8b;">'Master Card'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">'discover'</span>, <span style="color: #483d8b;">'Discover'</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">'amex'</span>, <span style="color: #483d8b;">'American Express'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>, validator=validators.<span style="color: black;">NotEmpty</span><span style="color: black;">&#41;</span>
        card_expiry = CalendarDatePicker<span style="color: black;">&#40;</span>date_format=<span style="color: #483d8b;">&quot;%m/%Y&quot;</span>, validator=validators.<span style="color: black;">NotEmpty</span><span style="color: black;">&#41;</span>
        card_number = TextField<span style="color: black;">&#40;</span>label_text=<span style="color: #483d8b;">'Card #'</span>, validator=validators.<span style="color: black;">NotEmpty</span><span style="color: black;">&#41;</span>
        card_cvv = TextField<span style="color: black;">&#40;</span>label_text=<span style="color: #483d8b;">'CVV Code'</span>, validator=validators.<span style="color: black;">NotEmpty</span><span style="color: black;">&#41;</span>
&nbsp;
authnet_form = AuthnetForm<span style="color: black;">&#40;</span><span style="color: #483d8b;">'authnet_form'</span>, action=url<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/authnet/process/'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Links of interest:</p>
<ul>
<li><a href="http://blog.curiasolutions.com/wp-content/uploads/2009/07/authnet.py">Download the authnet.py file</a></li>
<li><a href="http://groups.google.com/group/turbogears/t/c721e2d15bb2c134" target="_blank">This post&#8217;s original Google group thread</a></li>
<li><a href="http://www.adroll.com/labs" target="_blank">The Authorize package</a></li>
</ul>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/07/making-turbogears-and-authorize-net-play-nice-together/' addthis:title='Making TurboGears and Authorize.net play nice together ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/07/making-turbogears-and-authorize-net-play-nice-together/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Firefox extensions (a.k.a. stuff I can&#8217;t live without!)</title>
		<link>http://blog.curiasolutions.com/2009/06/firefox-extensions-and-other-stuff-i-cant-live-without/</link>
		<comments>http://blog.curiasolutions.com/2009/06/firefox-extensions-and-other-stuff-i-cant-live-without/#comments</comments>
		<pubDate>Sun, 14 Jun 2009 02:49:57 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[F/OSS]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=10</guid>
		<description><![CDATA[Note: A few months ago when I started drafting this post, Firefox v3.0 had just been released and I was enjoying it immensely. I started this post with a rant against IE (still included) and a call to Sarafi users to &#8220;get with the movement&#8221;. Well, a lot has changed since then. Safari 4 is [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/06/firefox-extensions-and-other-stuff-i-cant-live-without/' addthis:title='Firefox extensions (a.k.a. stuff I can&#8217;t live without!) ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p><em>Note: A few months ago when I started drafting this post, Firefox v3.0 had just been released and I was enjoying it immensely. I started this post with a rant against IE (still included) and a call to Sarafi users to &#8220;get with the movement&#8221;. Well, a lot has changed since then. Safari 4 is really slick, Google did the unthinkable and released a browser of their own, and Internet Explorer 8 actually likes web standards. So, I am finally publishing this post with a few slight updates and edits.</em></p>
<p>I&#8217;ve been playing around with Mozilla&#8217;s latest release, and I&#8217;ve got to say: Firefox is where it&#8217;s at! If anyone out there is still using Internet Explorer, you deserve anything that comes to you by way of malware, adware, spam, viruses, etc. Seriously, get with the times and install a real browser! And to you Apple/Mac users out there: Yeah, Safari is nice, but don&#8217;t let pride keep you from branching out of familiar territory.</p>
<p>One of the great thing about Firefox is its add-ons, and I&#8217;ve decided it&#8217;s time to dedicate a post to a few of my personal favorites:<span id="more-10"></span></p>
<blockquote><p><a href="http://adblockplus.org/en/" target="_blank">Adblock Plus</a></p></blockquote>
<p>To me, Adblock Plus is THE most incredible thing about Firefox (and its #1 selling point). This add-on actually strips about 99% of &#8220;web spam&#8221; and annoying banner ads from websites *before* they load into Firefox.</p>
<p>Note: Some web sites are financed soley by revenue from visitors loading ads on their sites. Keep in mind that stripping out ads may in some cases also affect the income generated by your favorite blog/social site.</p>
<blockquote><p><a href="http://flashblock.mozdev.org/" target="_blank">Flashblock</a></p></blockquote>
<p>Similar to Adblock, Flashblock turns flash elements into &#8220;play buttons&#8221; instead of auto-playing all those crazy flash items on pages.</p>
<blockquote><p><a href="http://getfirebug.com/" target="_blank">Firebug</a></p></blockquote>
<p>To me, the 2nd most important thing about Firefox. As a web developer I&#8217;m always having to dissect a page&#8217;s DOM, or do extra debugging on a JavaScript function. Firebug gives me complete access, control and information about a web page.</p>
<blockquote><p><a href="http://tamperdata.mozdev.org/" target="_blank">Tamper Data</a></p></blockquote>
<p>A more technical add-on, Tamper Data allows you to view and modify request headers and form submits (as well as any other communication between the client &amp; server). Very geeky, but very powerful.</p>
<blockquote><p><a href="http://fireftp.mozdev.org/" target="_blank">FireFTP</a></p></blockquote>
<p>FireFTP turns Firefox into a full-featured FTP client. A must, especially if you&#8217;re a Windows user (mounting FTP sites in Windows Explorer is still weird)</p>
<p>&nbsp;</p>
<p>Honorable mention: <a href="http://code.google.com/p/sqlite-manager/" target="_blank">SQLite Manager</a>, <a href="http://chatzilla.hacksrus.com/" target="_blank">ChatZilla</a>, <a href="http://foxyproxy.mozdev.org/" target="_blank">FoxyProxy</a>, <a href="http://www.shaneliesegang.com/projects/coffee.php" target="_blank">Morning Coffee</a>, <a href="http://developer.yahoo.com/yslow/" target="_blank">YSlow</a>, <a href="http://chrispederick.com/work/user-agent-switcher/" target="_blank">User Agent Switcher</a></p>
<p>&nbsp;</p>
<p>Give these a whirl&#8230; you&#8217;ll be glad you did!</p>
<p>- Seth</p>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/06/firefox-extensions-and-other-stuff-i-cant-live-without/' addthis:title='Firefox extensions (a.k.a. stuff I can&#8217;t live without!) ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/06/firefox-extensions-and-other-stuff-i-cant-live-without/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing TurboGears 2</title>
		<link>http://blog.curiasolutions.com/2009/06/turbogears-2/</link>
		<comments>http://blog.curiasolutions.com/2009/06/turbogears-2/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 02:43:00 +0000</pubDate>
		<dc:creator>Seth</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[turbogears]]></category>

		<guid isPermaLink="false">http://blog.curiasolutions.com/?p=3</guid>
		<description><![CDATA[I&#8217;m the type of person who is a bit anal about trying to use what I think is &#8220;the right tool for the job.&#8221; This is something I think my Dad passed down to me (I can&#8217;t tell you how many times I was scolded with that phrase as a kid—usually having something to do [...]<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/06/turbogears-2/' addthis:title='Introducing TurboGears 2 ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m the type of person who is a bit anal about trying to use what I think is &#8220;the right tool for the job.&#8221; This is something I think my Dad passed down to me (I can&#8217;t tell you how many times I was scolded with that phrase as a kid—usually having something to do with me trying to hammer an object with anything but a hammer); and it influences my world of development heavily. Because of this, I often find myself using a number of different programming languages and technologies at any given time for various projects. A shell script is perfect when you need something quick &amp; dirty. PHP makes adding logic to HTML a piece of cake. And then there&#8217;s my new personal favorite: Python.</p>
<p>Ok, let me back up before I get ahead of myself&#8230;<span id="more-3"></span></p>
<p>I&#8217;ve been a web developer for over 10 years now. When it comes to web programming languages and platforms, I&#8217;ve been around the block a bit: Back in the 90s I was building shopping carts from scratch using Perl (ouch!). From Perl, I eventually migrated to PHP which usually made things much easier. From time to time I would play around with Rails; but I never could stomach Ruby&#8217;s syntax (I think it reminded me too much of Perl). Even though I never felt like I really &#8220;clicked&#8221; with PHP, I eventually settled into a few PHP frameworks I liked and finally called myself a PHP developer.</p>
<p>Then one day I stumbled across Python, and it was love at first sight. I quickly vowed that I would soon be doing 99% of my web development in my newfound favorite language, but was disappointed to discover that (at that time) the available web frameworks were either ugly or poorly documented/supported. Reluctantly I returned to PHP, unable to justify moving away from the &#8220;quick &amp; simple&#8221; nature of what I was used to with PHP and the frameworks I was used to.</p>
<p>I&#8217;m not one to give up easily though, and on a recent &#8220;re-visit&#8221; of the Python web framework scene I was excited to see that things had changed dramatically: Django&#8217;s community had exploded and its documentation looked rock-solid. Pylons had cropped up as a serious WSGI-based contender (and modeling quite a bit of it&#8217;s functionality after Rails). But what really caught my attention was the (at the time) upcoming TurboGears v2.0 release.</p>
<p>What made TG2 stand out to me was its attempt to build a &#8220;best-of-breed&#8221; module-set on top of Pylons. Mark Ramm (the current leader of TG development) has been quoted as comparing TG2 to Ubuntu in that  &#8220;TG 2 is to Pylons as Ubuntu is to Debian.&#8221; The sound of that intrigued me, and I started playing around with the TG 2 Betas (and liking what I was seeing!).</p>
<p>Recently one of my clients asked me to whip up a medium-sized project with various amounts of CRUD and Ajax. Ironically, that very same day TurboGears&#8217; v2.0 release went gold. Seeing this as my opportunity to finally begin transitioning into the Python world with a stable &#8220;next-generation&#8221; Python web-development framework, I have decided to implement my latest project using TurboGears 2. Could this be the beginning of the rest of my life?</p>
<p>I will keep you posted on my progress and what I encounter along the way (good, bad, and ugly). Keep it here for what will likely be an interesting adventure.</p>
<p>&nbsp;</p>
<p>Related links of interest:</p>
<ul>
<li><a href="http://www.turbogears.com/2.0" target="_blank">TurboGears</a></li>
<li><a href="http://www.linuxjournal.com/content/introducing-three-python-web-frameworks" target="_blank">Introducing Three Python Web Frameworks</a></li>
</ul>
<div class="addthis_toolbox addthis_default_style" addthis:url='http://blog.curiasolutions.com/2009/06/turbogears-2/' addthis:title='Introducing TurboGears 2 ' ><a class="addthis_button_google_plusone" g:plusone:size="medium" ></a><a class="addthis_counter addthis_pill_style"></a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.curiasolutions.com/2009/06/turbogears-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

