Using git to deploy website code

Jow Maller outlines a straightforward system for using git to manage code from development copies and branches through production. The fact that deployment to live is automated, but I’d be worried about broken or unreviewed code getting deployed unintentionally. I think the best way to prevent that is to have live be its own branch, and then pushing changes to the live branch once they’ve been reviewed, tested, and blessed.

While his approach doesn’t require moving or redeploying the live site, I don’t think that works when you’re using Drupal.  You’ll want to track drupal core, sites/all, and your local site’s folders in different branches, per this setup.

The key idea in this system is that the web site exists on the server as a pair of repositories; a bare repository alongside a conventional repository containing the live site. Two simple Git hooks link the pair, automatically pushing and pulling changes between them.

A web-focused Git workflow | Joe Maller

isolani – Javascript: Breaking the Web with hash-bangs

Iisolani provides a thorough dissectin of how these new-fangled #! urls you are seeing all over the newest sites on the web are prone to breaking both the web experience and a site itself.  I think I see a hint of “we-know-better” from the developers rushing out these new sites and re-designs. HT: Jason Lefkowitz

Gawker, like Twitter before it, built their new site to be totally dependent on JavaScript, even down to the page URLs. The JavaScript failed to load, so no content appeared, and every URL on the page was broken. In terms of site brittleness, Gawker’s new implementation got turned up to 11.

isolani – Javascript: Breaking the Web with hash-bangs

JSON supplanting XML

Lessons: Use Cases matter, and programmers (the users in this case) will choose tools that are both simple, in that they are not complicated/over-engineered, and easy to use, requiring little setup and code to accomplish a task.  For parsing data with PHP, constrast using something like SimpleXML or DOMDocument (which is light-years better than where we were in parsing XML just 5 years ago), to just doing json_encode() or json_decode().

In particular, JSON shines as a programming language-independent representation of typical programming language data structures.  This is an incredibly important use case and it would be hard to overstate how appallingly bad XML is for this.

James Clark’s Random Thoughts: XML vs the Web

NetBeans: Creating a unified diff patch

While trying to submit a patch to a drupal project, I ran into a problem creating a unified diff that could be suspected.  It turns out that the way I was using the built in Subversion diff tool in NetBeans wasn't the way to go.  Now, on the command line, I'm used to doing a "svn diff myfile.php > myfile.patch" to have a useable patch with the latest changes to a file.  In NetBeans, I was thinking the same way, calling up a diff and then saving the output as a patch file – but that omitted crucial information like the name of the file to patch.

After hunting through the menus for a bit, I found the Export Diff Patch option in the Team menu.  This is what you should use to create a unified patch that other developers can use. If you have the focus on a single file, it will generate a patch for just that file.  If you click on a directory in your project and then create a patch it will include all changes for that folder.

NetBeans 6.9 is out.

There's a new release of the the one full-blown IDE that I've managed to stick with.  If Eclipse doesn't fit your style, give Netbeans a spin – I like its inline code completion, the source-code beautifier, and the integration with SVN and Mercurial.  I particularly find the source control usability much better than Eclipse.

After bug fixing period NetBeans 6.9 final build is available. You can download it as usual from NetBeans site. What is new, you can read in this document and also you can watch some new features in NetBeans 6.9 Overview video.

NetBeans for PHP : weblog

Make them Interact!

The more that a team can interact and iterate, the better you're final product can be.  In my ideal world, I'd skip a detailed wireframing exercise and get to building a prototype as soon as possible.  Its so much easier to explain what is difficult to build if there's something to click on.  Or you might learn that what you thought was hard turns out to be easy, or vice-versa.  Finally, if you already know if you are using Sharepoint, Drupal, or anything else, you're front-end designer has to know assumptions the platform makes, how it manages content, and other implementation details.

In my practical experience, I find that teams are more efficient when roles overlap and people understand what is happening outside of their silo.

Developers and Designers « Content Here

More Parameters != More Better

Guilty as charged – my very early code was littered with functions with horrendously long signatures. All the worse in PHP, which doesn’t have a meaningful way to overload functions. Too many parameters means your function is likely trying to do too many things, instead of doing any one thing well.

A simple way to make your code better: Stop adding more parameters

Parameters are good, but there are some things that you need to consider when creating functions with parameters, or when adding parameters to existing ones.

An example of using anonymous functions with PHP

If you’re not familiar with them, anonymous functions seem to be a term of art that very advanced programmers throw around to make others feel dumb.  Until now, my closest experience has been in using them with jQuery and javascript, but tonight I found a use for them in PHP.   If you don’t read the wikipedia article linked before, let me pull out a quote that reflects the "Aha!" moment I had tonight. 

Anonymous functions can be used to contain functionality that need not be named and possibly for short-term use.

A sorting and filtering example

While true anonymous functions won’t be available until PHP 5.3, you can use create_function to generate functions on the fly by passing them a signature and string containing valid php code.  These functions are perfect for use with array sorting functions like usort or uasort as well as array_filter.

For this example, suppose we have the following data:

<ol><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="re0">$sam</span> <span class="sy0">=</span> <span class="kw2">new</span> StdClass<span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$sam</span><span class="sy0">-&gt;</span><span class="me1">minutes_played</span> <span class="sy0">=</span> <span class="nu0">1300</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$sam</span><span class="sy0">-&gt;</span><span class="me1">goals</span> <span class="sy0">=</span> <span class="nu0">5</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="re0">$sam</span><span class="sy0">-&gt;</span><span class="me1">fouls</span> <span class="sy0">=</span> <span class="nu0">10</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="re0">$max</span> <span class="sy0">=</span> <span class="kw2">new</span> StdClass<span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$max</span><span class="sy0">-&gt;</span><span class="me1">minutes_played</span> <span class="sy0">=</span> <span class="nu0">1900</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$max</span><span class="sy0">-&gt;</span><span class="me1">goals</span> <span class="sy0">=</span> <span class="nu0">6</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="re0">$max</span><span class="sy0">-&gt;</span><span class="me1">fouls</span> <span class="sy0">=</span> <span class="nu0">10</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="re0">$joe</span> <span class="sy0">=</span> <span class="kw2">new</span> StdClass<span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$joe</span><span class="sy0">-&gt;</span><span class="me1">minutes_played</span> <span class="sy0">=</span> <span class="nu0">1100</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$joe</span><span class="sy0">-&gt;</span><span class="me1">goals</span> <span class="sy0">=</span> <span class="nu0">4</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="re0">$joe</span><span class="sy0">-&gt;</span><span class="me1">fouls</span> <span class="sy0">=</span> <span class="nu0">8</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="re0">$team</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span><span class="re0">$sam</span><span class="sy0">,</span> <span class="re0">$max</span><span class="sy0">,</span> <span class="re0">$joe</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol>

You’ve been tasked with reporting on the data, specifically, finding who has the most minutes, goals, and fouls. Traditionally, you’d be inclined to write three functions that sort the array by field you are interested, and return the elements with the highest values. It’s a bit of a brute force approach, but let’s see how we can do this with a single function. Below is that function.

<ol><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="co4">/**</span></div></li><li class="li1"><div class="de1"><span class="co4"> * Returns an array of all elements in the array that have the highest value in a given field.</span></div></li><li class="li1"><div class="de1"><span class="co4"> * @param string field</span></div></li><li class="li2"><div class="de2"><span class="co4"> * @param array stats data</span></div></li><li class="li1"><div class="de1"><span class="co4"> * @return array</span></div></li><li class="li1"><div class="de1"><span class="co4"> */</span></div></li><li class="li1"><div class="de1"><span class="kw2">public</span> <span class="kw2">function</span> findMaxStat<span class="br0">(</span><span class="re0">$field</span><span class="sy0">,</span> <span class="re0">$data</span><span class="br0">)</span></div></li><li class="li1"><div class="de1"><span class="br0">{</span></div></li><li class="li2"><div class="de2"><span class="co1">// sorting comparision</span></div></li><li class="li1"><div class="de1"><span class="re0">$sort_code</span> <span class="sy0">=</span> <span class="st_h">'</span></div></li><li class="li1"><div class="de1"><span class="st_h">        if ($a-&gt;'</span> <span class="sy0">.</span> <span class="re0">$field</span> <span class="sy0">.</span> <span class="st_h">' == $b-&gt;'</span> <span class="sy0">.</span> <span class="re0">$field</span> <span class="sy0">.</span> <span class="st_h">') return 0;</span></div></li><li class="li1"><div class="de1"><span class="st_h">        return ($a-&gt;'</span> <span class="sy0">.</span> <span class="re0">$field</span> <span class="sy0">.</span> <span class="st_h">' &lt; $b-&gt;'</span> <span class="sy0">.</span> <span class="re0">$field</span> <span class="sy0">.</span> <span class="st_h">' ? -1 : 1);</span></div></li><li class="li1"><div class="de1"><span class="st_h">'</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1"><span class="co1">// get the data sorted highest to lowest by the field we desire.</span></div></li><li class="li1"><div class="de1"><a href="http://www.php.net/usort"><span class="kw3">usort</span></a><span class="br0">(</span><span class="re0">$data</span><span class="sy0">,</span> <a href="http://www.php.net/create_function"><span class="kw3">create_function</span></a><span class="br0">(</span><span class="st_h">'$a,$b'</span><span class="sy0">,</span> <span class="re0">$sort_code</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$data</span> <span class="sy0">=</span> <a href="http://www.php.net/array_reverse"><span class="kw3">array_reverse</span></a><span class="br0">(</span><span class="re0">$data</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2"><span class="co1">// remove all elements of the array that do not match the max value</span></div></li><li class="li1"><div class="de1"><span class="re0">$max</span> <span class="sy0">=</span> <span class="re0">$data</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="sy0">-&gt;</span><span class="re0">$field</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$filter_code</span> <span class="sy0">=</span> <span class="st_h">'return ($a-&gt;'</span> <span class="sy0">.</span> <span class="re0">$field</span> <span class="sy0">.</span> <span class="st_h">' == '</span> <span class="sy0">.</span> <span class="re0">$max</span> <span class="sy0">.</span> <span class="st_h">');'</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="re0">$values</span> <span class="sy0">=</span> <a href="http://www.php.net/array_filter"><span class="kw3">array_filter</span></a><span class="br0">(</span><span class="re0">$data</span><span class="sy0">,</span> <a href="http://www.php.net/create_function"><span class="kw3">create_function</span></a><span class="br0">(</span><span class="st_h">'$a'</span><span class="sy0">,</span> <span class="re0">$filter_code</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2"><span class="kw1">return</span> <span class="re0">$values</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol>

What’s going on here? 

  1. First, to use the function we simply pass it the field for which we want to get the maximum value and our data array. 
  2. Line 11, defines the body of a function that will be used to sort the array by that field.  You’ll have to follow closely the use of quotes to build this string.  If we’re looking for most minutes, then the code for this function would look like ‘if $a->minutes == $b->minutes) return 0’ and so on, where $field is replaced by the string ‘minutes’; 
  3. Lines 17 and 18 do the hard work, usort uses our anonymous function to sort the data and then reverse it so that it’s ordered from highest to lowest.  You could also achieve this by changing what th $sort_code function returns and eliminating the call to array_reverse altogether.
  4. In line 21, We get our maximum value for the field we care about from the first element in our sorted array.
  5. Lines 22-23 are here to ensure that we return all the elements that have the max value of our field.  This acocunts for situations where more than one element may be "tied for first place", so to speak.
  6. Finally, we return the values that we’ve found.

What’s the big deal here?  Well, with one function we quickly get the rows we care about.

<ol><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="co1">// returns $sam and $joe</span></div></li><li class="li1"><div class="de1"><span class="re0">$max_fouls</span> <span class="sy0">=</span> findMaxStat<span class="br0">(</span><span class="st_h">'fouls'</span><span class="sy0">,</span> <span class="re0">$team</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="co1">// returns $max</span></div></li><li class="li2"><div class="de2"><span class="re0">$max_minutes</span> <span class="sy0">=</span> findMaxStat<span class="br0">(</span><span class="st_h">'minutes_played'</span><span class="sy0">,</span> <span class="re0">$team</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="co1">// returns $max</span></div></li><li class="li1"><div class="de1"><span class="re0">$max_goals</span> <span class="sy0">=</span> findMaxStat<span class="br0">(</span><span class="st_h">'goals'</span><span class="sy0">,</span> <span class="re0">$team</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol>

More importantly, if we add more fields to our data, we don’t have to write more code!

Conclusion

Used correctly, anonymous functions provide very customized functionality that can save you from having to write more code. Also, by learning to use PHP’s built-in array manipulation functions, you’ll quickly learn how to slice and dice nested arrays and arrays of objects without resorting to complicated loops and if statements. I’m not sure what the performance implications might be of using the technique, but if it saves you from writing long, complicated code-blocks it’s worth the trade off.  There’s a lot of existing discussion about create_function, and its impact on memory usage and DANGER!

Writing an intelligent hook_nodeapi function in Drupal

For Drupal module developers, the hook_nodeapi function affords a lot of flexibility for interacting with nodes at various operation.  If you just start pasting or writing code, you’ll quickly end up with a giant, messy switch statement.  But there is a simpel way to keep your code nicely organized.  First, lets take a look at what operations we can affect:

  • “alter”: the $node->content array has been rendered, so the node body or teaser is filtered and now contains HTML. This op should only be used when text substitution, filtering, or other raw text operations are necessary.
  • “delete”: The node is being deleted.
  • “delete revision”: The revision of the node is deleted. You can delete data associated with that revision.
  • “insert”: The node is being created (inserted in the database).
  • “load”: The node is about to be loaded from the database. This hook can be used to load additional data at this time.
  • “prepare”: The node is about to be shown on the add/edit form.
  • “prepare translation”: The node is being cloned for translation. Load additional data or copy values from $node->translation_source.
  • “print”: Prepare a node view for printing. Used for printer-friendly view in book_module
  • “rss item”: An RSS feed is generated. The module can return properties to be added to the RSS item generated for this node. See comment_nodeapi() and upload_nodeapi() for examples. The $node passed can also be modified to add or remove contents to the feed item.
  • “search result”: The node is displayed as a search result. If you want to display extra information with the result, return it.
  • “presave”: The node passed validation and is about to be saved. Modules may use this to make changes to the node before it is saved to the database.
  • “update”: The node is being updated.
  • “update index”: The node is being indexed. If you want additional information to be indexed which is not already visible through nodeapi “view”, then you should return it here.
  • “validate”: The user has just finished editing the node and is trying to preview or submit it. This hook can be used to check the node data. Errors should be set with form_set_error().
  • “view”: The node content is being assembled before rendering. The module may add elements $node->content prior to rendering. This hook will be called after hook_view(). The format of $node->content is the same as used by Forms API.

That’s 15 operations, multiplied by the number of content types on your site, that’s potentially 15N cases we’ll have to account for.  If you want your code to run regardless of the content type, thats another 15 cases.  How much do you like spaghetti?

Our own function naming convention to the rescue

By using a simple naming convention, we can make sure that a) we can drop in code to run for any operation and/or content type b) encapsulate the code within its own function.  To do this, your actual hook_nodeapi implementation will simply delagate execution to these other functions.  First, if a function named module_nodeapi_operation exists, we’ll call it.  Then if the function module_nodeapi_operation_content-type exists, execute it.

Let’s assume you have a module foo, the hook_nodeapi function looks like:

 

  1. <?php
  2. /**
  3. * Implementation of hook_nodeapi that delegates operations to other functions
  4. * @see http://api.drupal.org/api/function/hook_nodeapi/6
  5. * @author Oscar Merida
  6. */
  7. function foo_nodeapi(&$node, $op,$a3 = NULL, $a4 = NULL)
  8. {
  9. // our own all too clever function api
  10. // first call foo_$op if it exists
  11. // then call foo_$op_$node->type if it exists
  12. $f_base = ‘foo_nodeapi_’ . $op;
  13. if (function_exists($f_base))
  14. {
  15. $f_base(&$node, $a3, $a4);
  16. }
  17. $f_content = $f_base . ‘_’ . $node->type;
  18. if (function_exists($f_content))
  19. {
  20. $f_content(&$node, $a3, $a4);
  21. }
  22. }

If you need to alter something about all nodes before they are saved, you would create a function named foo_nodeapi_presave.

  1. <?php
  2. function foo_nodeapi_presave(&$node, $op, $a3, $a4)
  3. {
  4. // do something to all nodes before they are saved
  5. }

Likewise, to affect what is loaded with a story node, we need a function named foo_nodeapi_load_story:

  1. <?php
  2. function foo_nodeapi_load_story(&$node, $op, $a3, $a4)
  3. {
  4. // do something to story nodes when they are loaded
  5. }

Caveats

Keep in mind that both functions are called, but the content type specific one is called after the more general one so you can undo/override the latter. As a side note, I was trying to use the presave operation to set the value of a CCK Text field if it was empty. Since the order of hook calls depend on the weight of the module in the system table, I had to make sure the content module had a higher weight than my own. If you’re trying to set the value of a CCK field but it’s not being saved, you’ll have to do the same.

Tips for working with jquery

I’m a fan of jQuery because it promotes unobtrusive markup and functionality and has a wealth of plugins to take care of common web development/ajax functionality. Marc Grabanski offers some tips for working with it effectively. I’ll need to look at livequery in some apps I’ve put together. If you need to attach events to elements, and re-attach the same events when parts of the page are updated, it should make keeping track of it all a lot easier. My tip for working with jQuery? Use Firefox with Firebug to inspect the page and debug ajax requests.

5 Tips for Better jQuery Code: jQuery, Tutorial

I’ve been coding using jQuery since shortly after it came out, and well — I’ve been using it almost every work day. Here is a few tips that have saved me time.