<?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"
	>

<channel>
	<title>sacha chua :: enterprise 2.0 consultant, storyteller, geek &#187; drupal</title>
	<atom:link href="http://sachachua.com/wp/category/drupal/feed/" rel="self" type="application/rss+xml" />
	<link>http://sachachua.com/wp</link>
	<description>I help people connect through blogs, wikis, other Web 2.0 tools. I'm also writing a book about Emacs.</description>
	<pubDate>Thu, 28 Aug 2008 06:53:18 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.1</generator>
	<language>en</language>
			<item>
		<title>Running groups of Drupal tests from the command line</title>
		<link>http://sachachua.com/wp/2008/08/19/running-groups-of-drupal-tests-from-the-command-line/</link>
		<comments>http://sachachua.com/wp/2008/08/19/running-groups-of-drupal-tests-from-the-command-line/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 07:26:20 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[drush]]></category>

		<category><![CDATA[patch]]></category>

		<category><![CDATA[simpletest]]></category>

		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5074</guid>
		<description><![CDATA[I&#039;ve written about using drush to evaluate PHP statements in the Drupal context using the command line before, and it turns out that Drush is also quite useful for running Simpletest scripts. Drush comes with a module that allows you to display all the available tests with &#034;drush test list&#034;, run all the tests with [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve written about using <a href="http://www.drupal.org/projects/drush">drush</a> to <a href="http://sachachua.com/wp/2008/08/05/drupal-shell-quickly-evaluating-php-statements-in-a-drupal-context/">evaluate PHP statements in the Drupal context using the command line</a> before, and it turns out that Drush is also quite useful for running Simpletest scripts. Drush comes with a module that allows you to display all the available tests with &#034;drush test list&#034;, run all the tests with &#034;drush test run&#034;, or run specified tests with &#034;drush test run test1,test2&#034;.</p>
<p>&#039;Course, I wanted to run groups of tests and tests matching regular expressions, so I defined two new commands:</p>
<dl>
<dt>drush test run re <em>regular-expression</em></dt>
<dd>Run all tests matching a regular expression that uses ereg(..) to match.</dd>
<dd>Ex: drush test run re Example.*</dd>
<dt>drush test run group <em>group1,group2&#8230;</em></dt>
<dd>Run all tests matching the given groups</dd>
<dd>Ex: drush test run group Example</dd>
</dl>
<p>Here&#039;s the patch to make it happen:</p>
<pre>
Index: drush_simpletest.module
===================================================================
--- drush_simpletest.module	(revision 884)
+++ drush_simpletest.module	(working copy)
@@ -12,9 +12,13 @@
 function drush_simpletest_help($section) {
   switch ($section) {
       case 'drush:test run':
-        return t("Usage drush [options] test run<classes>.\n\nRun the specified specified unit tests. If </classes><classes> is omitted, all tests are run. </classes><classes> should be a list of classes separated by a comma. For example: PageCreationTest,PageViewTest.");
+        return t("Usage drush [options] test run </classes><classes>.\n\nRun the specified unit tests. If </classes><classes> is omitted, all tests are run. </classes><classes> should be a list of classes separated by a comma. For example: PageCreationTest,PageViewTest.");
       case 'drush:test list':
         return t("Usage drush [options] test list.\n\nList the available tests. Use drush test run command to run them. ");
+      case 'drush:test group':
+        return t("Usage drush [options] test group <groups>.\n\nRun all unit tests in the specified groups. For example: drush test group Group1,Group2");
+      case 'drush:test re':
+        return t("Usage drush [options] test re <regular expression>.\n\nRun all unit tests matching this regular expression. For example: drush test re Page.*");
   }
 }

@@ -30,10 +34,18 @@
     'callback' => 'drush_test_list',
     'description' => 'List the available Simpletest test classes.',
   );
+  $items['test re'] = array(
+    'callback' => 'drush_test_re',
+    'description' => 'Run one or more Simpletest tests based on regular expressions.',
+  );
+  $items['test group'] = array(
+    'callback' => 'drush_test_group',
+    'description' => 'Run one or more Simpletest test groups.',
+  );
   return $items;
 }

-function drush_test_list() {
+function drush_test_get_list() {
   simpletest_load();
   // TODO: Refactor simpletest.module so we don't copy code from DrupalUnitTests
   $files = array();
@@ -60,6 +72,11 @@
       $rows[] = array($class, $info['name'], truncate_utf8($info['desc'], 30, TRUE, TRUE));
     }
   }
+  return $rows;
+}
+
+function drush_test_list() {
+  $rows = drush_test_get_list();
   return drush_print_table($rows, 0, TRUE);
 }

@@ -75,3 +92,31 @@
   }
   return $result;
 }
+
+function drush_test_re($expression) {
+  if (!$expression) {
+    die('You must specify a regular expression.');
+  }
+  $rows = drush_test_get_list();
+  $tests = array();
+  foreach ($rows as $row) {
+    if (ereg($expression, $row[0])) {
+      $tests[] = $row[0];
+    }
+  }
+  simpletest_run_tests($tests, 'text');
+  return $result;
+}
+
+function drush_test_group($groups) {
+  $rows = drush_test_get_list();
+  $tests = array();
+  $groups = explode(',', $groups);
+  foreach ($rows as $row) {
+    if (in_array($row[1], $groups)) {
+      $tests[] = $row[0];
+    }
+  }
+  simpletest_run_tests($tests, 'text');
+  return $result;
+}
</regular></groups></classes></pre>
<p>That makes running tests so much easier and more fun!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/drupal' rel='tag' target='_self'>drupal</a>, <a class='technorati-link' href='http://technorati.com/tag/drush' rel='tag' target='_self'>drush</a>, <a class='technorati-link' href='http://technorati.com/tag/patch' rel='tag' target='_self'>patch</a>, <a class='technorati-link' href='http://technorati.com/tag/simpletest' rel='tag' target='_self'>simpletest</a>, <a class='technorati-link' href='http://technorati.com/tag/testing' rel='tag' target='_self'>testing</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/19/running-groups-of-drupal-tests-from-the-command-line/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal 5: Migrating a production database to a QA server</title>
		<link>http://sachachua.com/wp/2008/08/08/drupal-5-migrating-a-production-database-to-a-qa-server/</link>
		<comments>http://sachachua.com/wp/2008/08/08/drupal-5-migrating-a-production-database-to-a-qa-server/#comments</comments>
		<pubDate>Fri, 08 Aug 2008 20:37:25 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[development]]></category>

		<category><![CDATA[drupal]]></category>

		<category><![CDATA[makefile]]></category>

		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5059</guid>
		<description><![CDATA[Building on the configuration management strategy I described last time, I wrote some scripts to make it easier for other developers to migrate the production database to the QA server or to get a copy of the production database for their local system. I needed to consider the following factors:

Domain name changes: Because we use [...]]]></description>
			<content:encoded><![CDATA[<p>Building on the <a href="http://sachachua.com/wp/2008/07/06/configuration-management-with-drupal-multiple-developers-live-site/">configuration management strategy</a> I described last time, I wrote some scripts to make it easier for other developers to migrate the production database to the QA server or to get a copy of the production database for their local system. I needed to consider the following factors:</p>
<ul>
<li><b>Domain name changes</b>: Because we use Domain Access to serve multiple subdomains using a single Drupal installation and shared sign-on, we needed to make sure that all instances of the domain root are replaced and the correct domain_root is set. For example, the site URLs might be:<br />
<table>
<tr>
<th>Production</th>
<th>QA</th>
<th>Local</th>
</tr>
<tr>
<td>example.com</td>
<td>qa.example.com</td>
<td>local.example.com</td>
</tr>
<tr>
<td>foo.example.com</td>
<td>foo.qa.example.com</td>
<td>foo.local.example.com</td>
</tr>
<tr>
<td>bar.example.com</td>
<td>bar.qa.example.com</td>
<td>bar.local.example.com</td>
</tr>
</table>
</li>
<li><b>Privacy concerns</b>: The QA database and local copies of the database should not contain sensitive user information. All users aside from the administrator should be removed from the system, and all content on site should be limited to editorial content.</li>
<li><b>Efficiency</b>: We don&#039;t need data like access logs or watchdog logs in QA or for local testing. This saves quite a lot of time and space during the data migration process.</li>
</ul>
<p>Here&#039;s how I did it:</p>
<ol>
<li>I identified tables I needed to copy over and tables that I could just leave empty. I did this by going through the output of &#034;SHOW TABLES&#034; in a MySQL console.</li>
<li>In my Makefile, I declared a DB_DATA variable that contained a list of tables I wanted to copy.
</li>
<li>I wrote a backup_partial target in my Makefile that issued a series of commands:
<pre>
mysqldump -u ${DB_USER} --password=${DB_PASSWORD} ${DB} --no-data > partial.dump  # export the schema
mysqldump -u ${DB_USER} --password=${DB_PASSWORD} ${DB} --opt --complete-insert ${DB_DATA} >> partial.dump # Dump some of the data
mysqldump -u ${DB_USER} --password=${DB_PASSWORD} ${DB} --opt --complete-insert --where='uid< =1' users users_roles >> partial.dump # Dump the admin and anonymous users
echo "UPDATE node SET uid=1;" >> partial.dump # Set all the node authors to admin
echo "REPLACE INTO search_index_queue (nid, module, timestamp)  select nid, type, unix_timestamp(now()) FROM node;" >> partial.dump # Prepare for reindexing
</pre>
</li>
<li>I wrote a shell script on an internal server that accepted an argument (the domain to translate to) and performed the following steps:
<ol>
<li>ssh into the production server and run make with my backup_partial target, compressing the resulting partial.dump</li>
<li>scp the partial.dump.gz from the production server onto the internal server</li>
<li>unpack partial.dump.gz</li>
<li>figure out what $DOMAIN is supposed to be based on the arguments
</li>
<li>run <kbd>perl -pi -e "s/example.com/$DOMAIN/" partial.dump</kbd>
</li>
<li>load partial.dump into my database</li>
<li>run cron.php if it can</li>
</ol>
</li>
<li>I added two buttons to my web-based deploy script: one button to migrate the production database to the QA server, one button to make a copy of the production database for the domain &#034;local.example.com&#034;. Both buttons call </li>
<li>I created multisite settings.php in my Drupal directory (ex: sites/local.example.com and sites/qa.example.com). The production settings go in default/settings.php, and the multisite settings.php override it like this:

<div class="wp_syntax"><div class="code"><pre class="php"><span style="color: #000033;">$conf</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'domain_root'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'local.example.com'</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000033;">$cookie_domain</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'.'</span> <span style="color: #339933;">.</span> <span style="color: #000033;">$conf</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'domain_root'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></div></div>

<p>$conf allows you to override Drupal variables returned by variable_get.</li>
</ol>
<p>So now, I can click on a button to migrate a sanitized copy of the production database to the QA server or to my local system. Sweet!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/makefile' rel='tag' target='_self'>makefile</a>, <a class='technorati-link' href='http://technorati.com/tag/mysql' rel='tag' target='_self'>mysql</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/08/drupal-5-migrating-a-production-database-to-a-qa-server/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal, Emacs, and templates: Module update functions</title>
		<link>http://sachachua.com/wp/2008/08/06/drupal-emacs-and-templates-module-update-functions/</link>
		<comments>http://sachachua.com/wp/2008/08/06/drupal-emacs-and-templates-module-update-functions/#comments</comments>
		<pubDate>Wed, 06 Aug 2008 19:00:46 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[template]]></category>

		<category><![CDATA[yasnippet]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5044</guid>
		<description><![CDATA[Drupal&#039;s coding conventions make it easier to hook into system behavior, but they also result in a lot of repetitive typing. For example, you can run code when upgrading a module by putting the code in a function named modulename_update_N() in your module&#039;s install file. I found myself scrolling up and copy-pasting stuff too many [...]]]></description>
			<content:encoded><![CDATA[<p>Drupal&#039;s coding conventions make it easier to hook into system behavior, but they also result in a lot of repetitive typing. For example, you can run code when upgrading a module by putting the code in a function named <i>modulename</i>_update_<i>N</i>() in your module&#039;s install file. I found myself scrolling up and copy-pasting stuff too many times, so I decided to automate it instead.</p>
<p>I&#039;ve been using <a href="http://sachachua.com/wp/2008/07/26/yet-another-snippet-mode-for-emacs/">yasnippet</a> for my Emacs templates. All I needed to do to automate that little update bit was to write some code that figured out what the next update number should be. Here&#039;s the snippet file I&#039;ve just added (~/elisp/snippets/php-mode/drupal-mode/_update):</p>
<pre>
function `(sacha/drupal-module-name)`_update_`(sacha/drupal-module-update-number)`() {
  $ret = array();
  $0
  $ret[] = array(
    'success' => true,
    'query' => '$1',
  );
  return $ret;
}
</pre>
<p>The relevant functions from my ~/.emacs:</p>
<pre>
(defun sacha/drupal-module-update-number ()
  "Return the number of the next module update function.
This is one more than the highest number used so far.
This function should be called in a module's .install file."
  (save-excursion
    (save-restriction
      (widen)
      (goto-char (point-min))
      (let ((module-name (sacha/drupal-module-name))
	    (max 0))
	(while (re-search-forward
		(concat "function[ \t\n]+" module-name "_update_\\([0-9]+\\)") nil t)
	  (setq max (max (string-to-number (match-string 1)) max)))
	(number-to-string (1+ max))))))

(defun sacha/drupal-module-name ()
  "Return the Drupal module name for .module and .install files."
  (file-name-sans-extension (file-name-nondirectory (buffer-file-name))))
</pre>
<p>I can&#039;t think of how I&#039;d do that in Eclipse. =) Don&#039;t get me wrong&#8211;I still like Eclipse&#8211;but I heart being able to hack my editor on the fly.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/template' rel='tag' target='_self'>template</a>, <a class='technorati-link' href='http://technorati.com/tag/yasnippet' rel='tag' target='_self'>yasnippet</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/06/drupal-emacs-and-templates-module-update-functions/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal shell: quickly evaluating PHP statements in a Drupal context</title>
		<link>http://sachachua.com/wp/2008/08/05/drupal-shell-quickly-evaluating-php-statements-in-a-drupal-context/</link>
		<comments>http://sachachua.com/wp/2008/08/05/drupal-shell-quickly-evaluating-php-statements-in-a-drupal-context/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 21:25:26 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[drush]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=5042</guid>
		<description><![CDATA[I often find myself needing to variable_set something temporarily, just to try things out. The drush module provides a command-line interface that solves this problem with a little more hacking. To minimize the effect on my source tree, I&#039;ve unpacked it into the sites directory for my local installation and enabled it in my test [...]]]></description>
			<content:encoded><![CDATA[<p>I often find myself needing to variable_set something temporarily, just to try things out. The <a href="http://drupal.org/project/drush">drush</a> module provides a command-line interface that solves this problem with a little more hacking. To minimize the effect on my source tree, I&#039;ve unpacked it into the sites directory for my local installation and enabled it in my test database. After I enabled the main drush module and the related modules, I tweaked drush_tools to include an insecure-but-useful eval command. Here it is:</p>

<div class="wp_syntax"><div class="code"><pre class="diff"><span style="color: #888822;">--- sites/local.example.com/modules/drush/drush_tools.module.orig    <span style="">2008</span><span style="">-08</span><span style="">-05</span> <span style="">17</span>:<span style="">18</span>:<span style="">48.000000000</span> <span style="">-0400</span></span>
<span style="color: #888822;">+++ sites/local.example.com/modules/drush/drush_tools.module    <span style="">2008</span><span style="">-08</span><span style="">-05</span> <span style="">17</span>:<span style="">18</span>:<span style="">55.000000000</span> <span style="">-0400</span></span>
<span style="color: #440088;">@@ <span style="">-46</span>,<span style="">6</span> <span style="">+46</span>,<span style="">10</span> @@</span>
     'callback' =&gt; 'drush_tools_sync',
     'description' =&gt; 'Rsync the Drupal tree to/from another server using ssh'
   <span style="">&#41;</span>;
<span style="color: #00b000;">+  $items<span style="">&#91;</span>'eval'<span style="">&#93;</span> = array<span style="">&#40;</span></span>
<span style="color: #00b000;">+    'callback' =&gt; 'drush_tools_eval',</span>
<span style="color: #00b000;">+    'description' =&gt; 'Evaluate a command',</span>
<span style="color: #00b000;">+  <span style="">&#41;</span>;</span>
   return $items;
 <span style="">&#125;</span>
&nbsp;
<span style="color: #440088;">@@ <span style="">-156</span>,<span style="">3</span> <span style="">+160</span>,<span style="">6</span> @@</span>
   <span style="">&#125;</span>
 <span style="">&#125;</span>
&nbsp;
<span style="color: #00b000;">+function drush_tools_eval<span style="">&#40;</span>$command<span style="">&#41;</span> <span style="">&#123;</span></span>
<span style="color: #00b000;">+  eval<span style="">&#40;</span>$command<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+<span style="">&#125;</span></span></pre></div></div>

<p>I also added an alias to my ~/.bashrc along the lines of:</p>
<pre>
alias drush='php ~/drupal/sites/local.example.com/modules/drush/drush.php -r ~/drupal -l http://local.example.com'
</pre>
<p>where ~/drupal is my multisite Drupal directory root.</p>
<p>After I loaded the alias with &#034;source ~/.bashrc&#034;, I can now execute PHP statements in my Drupal context with commands like:</p>
<pre>
drush eval "variable_set('hello', 'world');"
</pre>
<p>Good stuff!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/drush' rel='tag' target='_self'>drush</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/08/05/drupal-shell-quickly-evaluating-php-statements-in-a-drupal-context/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Development kaizen: Deployment and testing</title>
		<link>http://sachachua.com/wp/2008/07/29/development-kaizen-deployment-and-testing/</link>
		<comments>http://sachachua.com/wp/2008/07/29/development-kaizen-deployment-and-testing/#comments</comments>
		<pubDate>Tue, 29 Jul 2008 13:54:39 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[kaizen]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/29/development-kaizen-deployment-and-testing/</guid>
		<description><![CDATA[I got back yesterday to a still-empty defect list, so I decided to spend the day working on some infrastructure to help my team work more effectively. 
Thinking about what could make the most difference in the other developers&#039; productivity, I decided to invest time into making it easier for them to deploy code to [...]]]></description>
			<content:encoded><![CDATA[<p>I got back yesterday to a still-empty defect list, so I decided to spend the day working on some infrastructure to help my team work more effectively. </p>
<p>Thinking about what could make the most difference in the other developers&#039; productivity, I decided to invest time into making it easier for them to deploy code to the testing server. I had written a Makefile target that efficiently transferred only the updated files, but the other developers worked on Microsoft Windows and did not have all the necessary tools. I spent the morning writing a web-based interface for them: a password-protected PHP script that displayed a list of recent revisions and allowed people to deploy a selected revision to a separate server. Behind the scenes, it was a mess of bubblegum and string. To work around various limitations, I strung together sudo and suid and rsync and ssh key-based authentication. It wasn&#039;t pretty, but it worked. I e-mailed instructions to my team members, and they started using it right away.</p>
<p>After solving that problem, I focused on improving our tests. Fixing one bug often led to creating or recreating another, and these regression errors resulted in back-and-forth communication and wasted time. I explored the <a href="http://drupal.org/project/simpletest">Simpletest</a> automated testing framework for Drupal, and found out that I could write both unit tests and Web-based tests using the framework. However, I had a hard time figuring out why several of my Web-based tests consistently failed. I found out that the latest version of Simpletest for Drupal 5 did not understand the Location: header, which we use extensively in order to direct people to different subdomains and external sites. I fixed it and wrote a number of tests for one of our key modules. By the time I was ready to pack up and go home, I&#039;d gotten into the swing of writing test cases.</p>
<p>Easier deployment and automated testing go a long way towards making a project almost a joy to work on. I&#039;m glad I spent some time paving the way for my team and for other projects to come. =) Kaizen: relentless improvement.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/29/development-kaizen-deployment-and-testing/feed/</wfw:commentRss>
		</item>
		<item>
		<title>From Eclipse to Emacs: Drupal development with Subversion, tags, templates, and xdebug</title>
		<link>http://sachachua.com/wp/2008/07/29/from-eclipse-to-emacs-drupal-development-with-subversion-tags-templates-and-xdebug/</link>
		<comments>http://sachachua.com/wp/2008/07/29/from-eclipse-to-emacs-drupal-development-with-subversion-tags-templates-and-xdebug/#comments</comments>
		<pubDate>Tue, 29 Jul 2008 13:33:01 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[emacs]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/29/from-eclipse-to-emacs-drupal-development-with-subversion-tags-templates-and-xdebug/</guid>
		<description><![CDATA[Yesterday, I started working on my Drupal project in Emacs. I can&#039;t believe I hadn&#039;t moved to Emacs earlier. =)
I really like being able to diff a file with C-x v = (vc-diff) and check in a file with C-x v v (vc-next-action). I also like the way that svn-status (from psvn.el) lets me examine [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday, I started working on my Drupal project in Emacs. I can&#039;t believe I hadn&#039;t moved to Emacs earlier. =)</p>
<p>I really like being able to diff a file with C-x v = (vc-diff) and check in a file with C-x v v (vc-next-action). I also like the way that svn-status (from psvn.el) lets me examine a directory tree, mark a set of files, and commit them&#8211;all without using the mouse. I probably should&#039;ve set up keyboard shortcuts for these in Eclipse, but Eclipse made it too easy to just use the mouse. Emacs encourages you to use the keyboard, and it&#039;s easy to customize any keyboard shortcut.</p>
<p>php-mode&#039;s C-c . (php-show-arglist) works beautifully with the TAGS file that I&#039;d set up using Exuberant Ctags, so I don&#039;t need to do anything special in order to get function definitions. Definition functions for PHP functions would be nice. In the meantime, there&#039;s C-c C-f (php-search-documentation).</p>
<p>The yasnippet template engine came in handy when I was writing test cases. I updated <a href="http://sachachua.com/notebook/elisp/snippets/php-mode/drupal-mode/dmodule">my module template</a> to include the simpletest hook, added a <a href="http://sachachua.com/notebook/elisp/snippets/php-mode/drupal-mode/test">test case template</a>, and added a template for the <a href="http://sachachua.com/notebook/elisp/snippets/php-mode/drupal-mode/_simpletest">simpletest hook</a> as well. Yay dynamic templates!</p>
<p>And I just got Xdebug working with <a href="http://www.emacswiki.org/cgi-bin/wiki/PhpMode">PhpMode and Geben</a>&#8230; Sweet!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/29/from-eclipse-to-emacs-drupal-development-with-subversion-tags-templates-and-xdebug/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal: Patching simpletest for Drupal 5 to understand the Location header</title>
		<link>http://sachachua.com/wp/2008/07/28/drupal-patching-simpletest-for-drupal-5-to-understand-the-location-header/</link>
		<comments>http://sachachua.com/wp/2008/07/28/drupal-patching-simpletest-for-drupal-5-to-understand-the-location-header/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 20:38:04 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/28/drupal-patching-simpletest-for-drupal-5-to-understand-the-location-header/</guid>
		<description><![CDATA[Automated testing is part of good programmer hygiene. I wanted to write tests for both functions and Web-based interfaces in our Drupal project, but one of the tests I wrote was always failing. Many prints and var_debugs later, I found out that it was because simpletest didn&#039;t do anything with Location: headers, which happen when [...]]]></description>
			<content:encoded><![CDATA[<p>Automated testing is part of good programmer hygiene. I wanted to write tests for both functions and Web-based interfaces in our Drupal project, but one of the tests I wrote was always failing. Many prints and var_debugs later, I found out that it was because simpletest didn&#039;t do anything with Location: headers, which happen when you drupal_goto an external site. Here&#039;s a first pass at fixing that behavior - patch sites/all/modules/simpletest/simpletest/browser.php:</p>

<div class="wp_syntax"><div class="code"><pre class="diff">Index: browser.php
===================================================================
<span style="color: #888822;">--- browser.php	<span style="">&#40;</span>revision <span style="">753</span><span style="">&#41;</span></span>
<span style="color: #888822;">+++ browser.php	<span style="">&#40;</span>working copy<span style="">&#41;</span></span>
<span style="color: #440088;">@@ <span style="">-321</span>,<span style="">6</span> <span style="">+321</span>,<span style="">22</span> @@</span>
&nbsp;
         $this-&gt;_history-&gt;recordEntry<span style="">&#40;</span>
                 $this-&gt;_page-&gt;getUrl<span style="">&#40;</span><span style="">&#41;</span>,
                 $this-&gt;_page-&gt;getRequestData<span style="">&#40;</span><span style="">&#41;</span><span style="">&#41;</span>;
<span style="color: #00b000;">+        $counter = <span style="">0</span>;</span>
<span style="color: #00b000;">+        $url = $this-&gt;_page-&gt;_headers-&gt;_location;</span>
<span style="color: #00b000;">+        if <span style="">&#40;</span>$url<span style="">&#41;</span> <span style="">&#123;</span></span>
<span style="color: #00b000;">+          $url = &amp;new SimpleURL<span style="">&#40;</span>$url<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+        <span style="">&#125;</span></span>
<span style="color: #00b000;">+        while <span style="">&#40;</span>$url &amp;&amp; $counter &lt; <span style="">10</span><span style="">&#41;</span> <span style="">&#123;</span></span>
<span style="color: #00b000;">+          $this-&gt;_page = &amp;$this-&gt;_fetch<span style="">&#40;</span>$url, $parameters<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+          $this-&gt;_history-&gt;recordEntry<span style="">&#40;</span></span>
<span style="color: #00b000;">+            $this-&gt;_page-&gt;getUrl<span style="">&#40;</span><span style="">&#41;</span>,</span>
<span style="color: #00b000;">+            $this-&gt;_page-&gt;getRequestData<span style="">&#40;</span><span style="">&#41;</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+          $url = $this-&gt;_page-&gt;_headers-&gt;_location;</span>
<span style="color: #00b000;">+          if <span style="">&#40;</span>$url<span style="">&#41;</span> <span style="">&#123;</span></span>
<span style="color: #00b000;">+            $url = &amp;new SimpleURL<span style="">&#40;</span>$url<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+          <span style="">&#125;</span></span>
<span style="color: #00b000;">+          $counter++;</span>
<span style="color: #00b000;">+        <span style="">&#125;</span></span>
         return $this-&gt;_page-&gt;getRaw<span style="">&#40;</span><span style="">&#41;</span>;
     <span style="">&#125;</span></pre></div></div>

<p>(update: okay, let&#039;s try diff syntax highlighting with wp-syntax&#8230;)</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/28/drupal-patching-simpletest-for-drupal-5-to-understand-the-location-header/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Kaizen: What would make our Drupal lives better?</title>
		<link>http://sachachua.com/wp/2008/07/28/kaizen-what-would-make-our-drupal-lives-better/</link>
		<comments>http://sachachua.com/wp/2008/07/28/kaizen-what-would-make-our-drupal-lives-better/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 11:38:17 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[kaizen]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/28/kaizen-what-would-make-our-drupal-lives-better/</guid>
		<description><![CDATA[Kaizen: relentless improvement.
We&#039;re getting ready for the next phase of our Drupal project, and it&#039;s a good time to think about how we can make our process better.

Automated builds: I have a few Makefile commands related to pushing the latest development source code to the testing server, but the other developers can&#039;t use the commands [...]]]></description>
			<content:encoded><![CDATA[<p><i>Kaizen</i>: relentless improvement.</p>
<p>We&#039;re getting ready for the next phase of our Drupal project, and it&#039;s a good time to think about how we can make our process better.</p>
<ul>
<li><b>Automated builds</b>: I have a few Makefile commands related to pushing the latest development source code to the testing server, but the other developers can&#039;t use the commands on Microsoft Windows. However, they have access to another Linux-based server. If I can simplify the deployment process (maybe a password-protected webpage that allows you to choose which revision to deploy?), then they won&#039;t be held up when I go on vacation.</li>
<li><b>Automated testing</b>: We used <b>simpletest</b> for a few pieces of functionality, but we don&#039;t have anything close to coverage. I&#039;d like to learn how to write proper tests for Drupal so that I can avoid regression errors, which I often made during development.</li>
<li><b>Switching between hosts</b>: Because we use Domain Access, I can&#039;t just use a local domain name and a copy of the server&#039;s database. My current approach is to use the same domain name as on the testing server, and then keep editing /etc/hosts to switch back and forth. An alternative might be to create a Makefile target that grabs the server&#039;s database, runs it through sed to translate all the domain names to my local domain, and restores the database from this translated file. That way, I don&#039;t need to edit /etc/hosts all the time.
</li>
<li><b>Coding environment</b>: I&#039;m thinking of moving my development from Eclipse to Emacs in order to be able to customize my environment more effectively. I&#039;ll post more notes about it as I figure out what works for me and what doesn&#039;t. It&#039;s a good excuse to learn even more about Emacs&#8230;</li>
</ul>
<p>What worked well:</p>
<ul>
<li>Source code control, I love you <i>so</i> much, even if you&#039;re Subversion.
</li>
<li>Adding a CSS person to our team meant that the other developer and I were much less stressed out about cross-browser issues. Hooray!</li>
<li>Using a defect-tracking system was infinitely better than sending e-mail around, even if that defect-tracking system was ClearQuest. <img src='http://sachachua.com/wp/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </li>
</ul>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/28/kaizen-what-would-make-our-drupal-lives-better/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Please vote for my about-me/sitemap slideshow on Slideshare!</title>
		<link>http://sachachua.com/wp/2008/07/25/please-vote-for-my-about-mesitemap-slideshow-on-slideshare/</link>
		<comments>http://sachachua.com/wp/2008/07/25/please-vote-for-my-about-mesitemap-slideshow-on-slideshare/#comments</comments>
		<pubDate>Fri, 25 Jul 2008 12:14:58 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[emacs]]></category>

		<category><![CDATA[sketchcast]]></category>

		<category><![CDATA[sketches]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/25/please-vote-for-my-about-mesitemap-slideshow-on-slideshare/</guid>
		<description><![CDATA[Only 7 days left for the Slideshare World&#039;s Best Presentation Contest, and I&#039;d love it if y&#039;all came out and voted for my about-me presentation&#8211;if only because I found a way to fit both Drupal and Emacs into my rhyming self-introduction! =)
It&#039;s only one minute and 25 seconds, and it&#039;ll probably make you smile. Plus, [...]]]></description>
			<content:encoded><![CDATA[<p>Only 7 days left for the <b>Slideshare World&#039;s Best Presentation Contest,</b> and I&#039;d love it if y&#039;all came out and voted for <a href="http://www.slideshare.net/sachac/hello-im-sacha-chua/">my about-me presentation</a>&#8211;if only because I found a way to fit both <b>Drupal</b> and <b>Emacs</b> into my rhyming self-introduction! =)</p>
<p>It&#039;s only one minute and 25 seconds, and it&#039;ll probably make you smile. Plus, it&#039;s a (mostly) working sitemap, and how cool is that? <img src='http://sachachua.com/wp/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> The prize for this category is an iPod Touch, which (if I win it) I will promptly put to good use. After all, if I used my Nintendo DS to make a presentation, what might I do with something like the iPod Touch? <img src='http://sachachua.com/wp/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Honorable mention would get me a copy of Presentation Zen book, which I liked so much I bought it already, so I&#039;d be happy to raffle it off and keep just the warm and fuzzy feelings that my fledgling sketching and writing skills got noticed. Want it? Leave a comment on this entry (just one comment is fine), and I&#039;ll pick a random commenter if I win the book.</p>
<p>In addition to either blog posts about doing interesting things with the iPod Touch or a chance at winning a free book, you&#039;ll also get the satisfaction of supporting a geek in an area dominated by graphic designers. =) (Not that graphic designers can&#039;t be geeks, of course.)</p>
<p>Anyway, please vote for my presentation! =) Voting ends on July 31, 2008.</p>
<p><a href="http://www.slideshare.net/sachac/hello-im-sacha-chua"><img src="http://public.slideshare.net/images/banner_wide.gif" width=269 height=98/></a><br /><a href="http://www.slideshare.net/contest">World&#039;s Best Presentation Contest</a></p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/25/please-vote-for-my-about-mesitemap-slideshow-on-slideshare/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal: Adding a footer to all of your system e-mail</title>
		<link>http://sachachua.com/wp/2008/07/23/drupal-adding-a-footer-to-all-of-your-system-e-mail/</link>
		<comments>http://sachachua.com/wp/2008/07/23/drupal-adding-a-footer-to-all-of-your-system-e-mail/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 20:27:10 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/23/drupal-adding-a-footer-to-all-of-your-system-e-mail/</guid>
		<description><![CDATA[Drupal&#039;s hook system is making me almost as happy as Emacs&#039; hook system does. =)
There&#039;s a hook_mail_alter function that allows you to modify any message your system sends. Example:

function mymodule_mail_alter($mailkey, &#38;$to, &#38;$subject, &#38;$body, &#38;$from, &#38;$headers) {
   $body .= "\n\n" . t('This is a system-generated email, please do not reply to this message');
}

You gotta [...]]]></description>
			<content:encoded><![CDATA[<p>Drupal&#039;s hook system is making me almost as happy as Emacs&#039; hook system does. =)</p>
<p>There&#039;s a hook_mail_alter function that allows you to modify any message your system sends. Example:</p>
<pre>
function mymodule_mail_alter($mailkey, &amp;$to, &amp;$subject, &amp;$body, &amp;$from, &amp;$headers) {
   $body .= "\n\n" . t('This is a system-generated email, please do not reply to this message');
}
</pre>
<p>You gotta love developers who plan for extensibility and put all sorts of hooks into the code&#8230;</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/23/drupal-adding-a-footer-to-all-of-your-system-e-mail/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal: Testing multisite/domain-access Drupal locally and on a testing server</title>
		<link>http://sachachua.com/wp/2008/07/22/drupal-testing-multisitedomain-access-drupal-locally-and-on-a-testing-server/</link>
		<comments>http://sachachua.com/wp/2008/07/22/drupal-testing-multisitedomain-access-drupal-locally-and-on-a-testing-server/#comments</comments>
		<pubDate>Tue, 22 Jul 2008 15:09:54 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/22/drupal-testing-multisitedomain-access-drupal-locally-and-on-a-testing-server/</guid>
		<description><![CDATA[We&#039;re using Domain Access to manage a number of related subdomains on a single server. I prefer to develop and test locallly, then push my changes out to a testing server so that other people can try the system. I use the same domain names on my computer and on the test server so that [...]]]></description>
			<content:encoded><![CDATA[<p>We&#039;re using <a href="http://drupal.org/project/domain">Domain Access</a> to manage a number of related subdomains on a single server. I prefer to develop and test locallly, then push my changes out to a testing server so that other people can try the system. I use the same domain names on my computer and on the test server so that I don&#039;t have to make any changes in the database. To switch between them, I comment or uncomment a line like</p>
<pre>127.0.0.1 example.com sub1.example.com sub2.example.com</pre>
<p>in my /etc/hosts file.</p>
<p>However, Firefox caches the domain name information, and it can be confusing to figure out which server I&#039;m on. The following setup makes this much easier:</p>
<ol>
<li> Install <a href="https://addons.mozilla.org/en-US/firefox/addon/2166">Domain Details</a> to show the IP address of the server in your status bar. Good for a quick check - am I on 127.0.0.1 or elsewhere? (NOTE: I  started with <a href="https://addons.mozilla.org/en-US/firefox/addon/590">ShowIP</a>, but it looks like ShowIP caches the information.)</li>
<li> Install the <a href="https://addons.mozilla.org/en-US/firefox/addon/1801">Clear Cache Button</a> extension.</li>
<li> Restart your browser and customize your toolbar. Add the Clear Cache button. Click on this before switching sites.</li>
</ol>
<p>In an ideal world, I&#039;ll have a plugin that automatically twiddles my DNS entries, too. =)</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/22/drupal-testing-multisitedomain-access-drupal-locally-and-on-a-testing-server/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Configuration management with Drupal - Multiple developers, live site</title>
		<link>http://sachachua.com/wp/2008/07/06/configuration-management-with-drupal-multiple-developers-live-site/</link>
		<comments>http://sachachua.com/wp/2008/07/06/configuration-management-with-drupal-multiple-developers-live-site/#comments</comments>
		<pubDate>Sun, 06 Jul 2008 19:07:43 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/07/06/configuration-management-with-drupal-multiple-developers-live-site/</guid>
		<description><![CDATA[We&#039;ve moved into the next phase of our development. External users now have access to our testing server, and theylle be busy not only filing bugs but also creating editorial content. This means that we can&#039;t just drop the database and recreate everything from scratch. (Darn!) However, we still need a way to make sure [...]]]></description>
			<content:encoded><![CDATA[<p>We&#039;ve moved into the next phase of our development. External users now have access to our testing server, and theylle be busy not only filing bugs but also creating editorial content. This means that we can&#039;t just drop the database and recreate everything from scratch. (Darn!) However, we still need a way to make sure that:
<ul>
<li>developers have a consistent environment for development and testing, so all changes need to be checked into the Subversion source code control system</li>
<li>all significant changes are captured so that we can deploy the tested system on the production server</li>
</ul>
<p>Here&#039;s our current plan:
<ul>
<li><b>Editorial changes</b> (creating new nodes, editing existing nodes) happen on the testing server. Developers can test their local systems with real data by downloading a data dump from the testing server and loading it locally.</li>
<li><b>Code changes that don&#039;t require database updates </b>can be pushed to the testing server after local testing.</li>
<li><b>Code changes that require database changes or one-time administrative actions </b>can be handled in modules&#039; .install files as modulename_update_somenumber() and _install() functions. This can be tested locally by loading a data dump from the testing server and then running update.php. It should also be tested from a fresh install. If the change works locally, then the testing server can be updated. (Make sure to run update.php on the testing server as well).</li>
</ul>
<p>When we deploy the system to production, we&#039;ll review all the content, remove the test data, and push the data and the code to the live site.</p>
<p>See <a href="http://heyrocker.com/drupal/content/deployment-and-change-management-problem">http://heyrocker.com/drupal/content/deployment-and-change-management-problem</a> for more analysis.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/07/06/configuration-management-with-drupal-multiple-developers-live-site/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hooray, figured out Drupal 5 multi-step registration form with validation and invites</title>
		<link>http://sachachua.com/wp/2008/06/30/hooray-figured-out-drupal-5-multi-step-registration-form-with-validation-and-invites/</link>
		<comments>http://sachachua.com/wp/2008/06/30/hooray-figured-out-drupal-5-multi-step-registration-form-with-validation-and-invites/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 20:45:23 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/30/hooray-figured-out-drupal-5-multi-step-registration-form-with-validation-and-invites/</guid>
		<description><![CDATA[The validation of multi-step forms in Drupal 5 was much less scary than I thought it would be, or maybe I lucked out by basing my code on something that already worked. =) 
I had spent last Thursday and Friday searching the Internet for people&#039;s blog posts about the topic. I came across exact descriptions [...]]]></description>
			<content:encoded><![CDATA[<p>The validation of multi-step forms in Drupal 5 was much less scary than I thought it would be, or maybe I lucked out by basing my code on something that already worked. =) </p>
<p>I had spent last Thursday and Friday searching the Internet for people&#039;s blog posts about the topic. I came across exact descriptions of the problems I encountered, but no solutions&#8211;only notes about critical bugs in Drupal 5. Asking the developers in #drupal didn&#039;t yield any tips, either. They told me to get ready for a world of pain.</p>
<p>Then I remembered that the <a href="http://drupal.org/project/password-reset">password-reset</a> module used a multi-step form, and validation actually worked. I had already incorporated part of the source code into one of my modules, and it was easy to extend that example. I defined a new multi-step form in my PHP code as a replacement for the system form in user/register. There were some complications around the fact that other modules modify the behavior of user_register, but I got the code to validate and submit the data. And it worked!</p>
<p>No code snippet, sorry. Too many interactions for me to explain neatly. Some hints:
<ul>
<li>You can use logic to set the value of $step.</li>
<li>Pass information to the next step using hidden fields.</li>
<li>Make sure the step field is included in your form template. Watch out for this if you&#039;ve got a form template that specifies all the fields explicitly.</li>
<li>Captcha uses hook_form_alter to add a captcha based on the form_id. It doesn&#039;t know about steps. You&#039;ll need your own hook_form_alter to unset the captcha if you don&#039;t need it on the other steps. Make sure your module runs after captcha by changing the weights in the system table.</li>
</ul>
<p>So now I have a multi-step form that can skip step 1 (employee verification) if a valid invite code is provided, asks for CAPTCHA once, and does all the validation and user registration magic. Hooray!</p>
<p></p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/30/hooray-figured-out-drupal-5-multi-step-registration-form-with-validation-and-invites/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Programmatically creating CCK nodes in PHP (interaction with the Path module)</title>
		<link>http://sachachua.com/wp/2008/06/12/programmatically-creating-cck-nodes-in-php-interaction-with-the-path-module/</link>
		<comments>http://sachachua.com/wp/2008/06/12/programmatically-creating-cck-nodes-in-php-interaction-with-the-path-module/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 02:29:28 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[drupal cck]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/12/programmatically-creating-cck-nodes-in-php-interaction-with-the-path-module/</guid>
		<description><![CDATA[I&#039;ve been experimenting with the Drupal Content Construction Kit, which promised to be a more flexible way to deal with custom node types in the Drupal content management system. However, I&#039;m a finicky sort of person who likes being able to reproduce the setup from a fresh start, and CCK isn&#039;t well-known for that. In [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve been experimenting with the <a href="http://drupal.org/project/cck">Drupal Content Construction Kit</a>, which promised to be a more flexible way to deal with custom node types in the Drupal content management system. However, I&#039;m a finicky sort of person who likes being able to reproduce the setup from a fresh start, and CCK isn&#039;t well-known for that. In fact, CCK nodes aren&#039;t well-known for being easy to move from one server to another.</p>
<p>Following the instructions for <a href="http://www.civicactions.com/blog/cck_import_and_update">programmatically creating, inserting, and updating CCK nodes</a> will get you most of the way there. Here are some of the gotchas you&#039;ll want to watch out for.</p>
<p>I was using Path to define aliases for my nodes and the path aliases were just not getting created. After lots and lots of tracing with XDebug, I found out that it was checking for user_access, but no user was active during the installation process. Solution: create the admin user and load it into a global $user variable.</p>
<p>I also spent a fair bit of time being very annoyed with CCK and creating nodes programmatically in my install profile. Turns out that you first need to use install_add_content_type to create the base node type, _then_ follow the instructions to drupal_execute the form that adds custom fields.</p>
<p>Here&#039;s a quick sketch of the code:</p>
<pre>
function profilename_profile_final() {
  // lots of other code here
  install_add_user('admin', 'admin', 'admin@example.com', array(), 1);
  global $user;
  $user = user_load(array('uid' =&gt; 1));
  install_add_content_type(array(
    // take this from Install Profile Wizard
  ));
  node_get_types('types', NULL, TRUE);  // flush cache
  $content = array();
  $content['type'] = array(
   // take this from content copy export
  );
  $content['fields'] = array(
   // take this from content copy export
  );
    _install_create_content($content);
}
function _install_create_content($content) {
  global $_install_macro;
  $type_name = $content['type']['type'];
  $_install_macro[$type_name] = $content;
  include_once drupal_get_path('module', 'node') .'/content_types.inc';
  include_once drupal_get_path('module', 'content') .'/content_admin.inc';
  $macro = 'global $_install_macro; $content = $_install_macro['. $type_name .'];';
  drupal_execute('content_copy_import_form', array('type_name' =&gt; $type_name, 'macro' =&gt; $macro));
  content_clear_type_cache();
}
</pre>
<p>Now I feel more confident about CCK&#8230;</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/drupal+cck' rel='tag' target='_self'>drupal cck</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/12/programmatically-creating-cck-nodes-in-php-interaction-with-the-path-module/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Setting up your Drupal development environment</title>
		<link>http://sachachua.com/wp/2008/06/11/setting-up-your-drupal-development-environment/</link>
		<comments>http://sachachua.com/wp/2008/06/11/setting-up-your-drupal-development-environment/#comments</comments>
		<pubDate>Wed, 11 Jun 2008 14:00:12 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[geek]]></category>

		<category><![CDATA[development]]></category>

		<category><![CDATA[eclipse]]></category>

		<category><![CDATA[ide]]></category>

		<category><![CDATA[xdebug]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/?p=4921</guid>
		<description><![CDATA[People found the 7-minute impromptu braindump I gave at last night&#039;s Drupal Toronto meetup useful enough to vote it the best talk, so I thought I&#039;d write it up. =)

Development
Use source code control. No, seriously. Use it. Religiously. It&#039;s going to save you someday. CVS is popular. Subversion is also easy to set up. It&#039;s [...]]]></description>
			<content:encoded><![CDATA[<p>People found the 7-minute impromptu braindump I gave at last night&#039;s Drupal Toronto meetup useful enough to vote it the best talk, so I thought I&#039;d write it up. =)</p>

<b>Development
</b><ul><li><b>Use source code control.</b> No, seriously. Use it. Religiously. It&#039;s going to save you someday. CVS is popular. Subversion is also easy to set up. It&#039;s a must when you&#039;re working with other people, but even if you&#039;re on your own, it&#039;s really handy to be able to go back to previous versions or to check your changes.
</li><li><b>Get to know your integrated development environment (IDE).</b> For example, I use Eclipse + PHP Development Toolkit (PDT) + Xdebug, and the keyboard shortcuts save me so much time and make it easier for me to think about my code instead of thinking about editing my code. F3 to jump to a function definition, Ctrl-Shift-R to open a file by typing part of the filename, Ctrl-space to complete text&#8230; I&#039;ve also gotten XDebug integration to work, so I can step through code and examine variables without putting var_dump everywhere. Know your tools.</li><li><b>Add the XDebug extension to your PHP installation.</b> Even if you don&#039;t get XDebug integrated with Eclipse, you&#039;ll like the new and improved var_dump and other debugging functions. I&#039;ve heard good things about Zend Debugger, too.</li><li><b>Put your entire Drupal directory into your project in the IDE, </b>not just your site-specific code. You can even check your entire Drupal directory into your source code control repository. This makes it easier to look up functions in Drupal core, not just your sites/all/modules directory. You _could_ version-control just your site-specific code (profiles/, sites/, etc.), but set-up becomes a little more complicated.</li><li><b>Use an installation profile to manage your configuration.</b> Experiment with things using the administration interface, then create/update an installation profile that sets up a brand-new Drupal installation. This will save you lots of time and head-scratching when you need to reproduce your setup.
</li><li><b>Make starting from scratch easier, and do it often.</b> I have a Makefile that drops my database and recreates it, resets my settings.php, and even opens up a Firefox browser that uses my installation profile to set everything up from scratch. <i>Drupal 5:</i> Copy your settings.php to settings-default.php or something like that before you install your system, then copy settings-default.php over settings.php when you want to refresh your setup. <i>Drupal 6:</i> Delete settings.php when you want to refresh your setup.</li></ul><b>Firefox</b>  
<ul><li><b>Use multiple profiles.</b> You can start completely independent Firefox processes by using profiles. For example, you could have your default profile with all the bells and whistles, and a test profile with just FireBug. You can log in as different users, too. Use this command to start a new Firefox process: <kbd>firefox -ProfileManager -no-remote
</kbd></li><li><b>Install and use <a href="http://www.google.com/url?sa=t&amp;ct=res&amp;cd=1&amp;url=https%3A%2F%2Faddons.mozilla.org%2Ffirefox%2Faddon%2F1843&amp;ei=itRPSPeOCpG6iAGOirS3DQ&amp;usg=AFQjCNFeeiIXBngB6nyWDODclEE-XJPNfQ&amp;sig2=GIkUM0P6b-DG4VOTn4I1BQ">FireBug</a>.</b> Best web development extension ever. I use this to examine the document object model, debug my CSS rules, experiment with my CSS and HTML on the fly, and monitor the network requests.</li><li><b>Set up quick searches for drupal.org and php.net</b>. You can define quick searches by creating bookmarks that use keywords and %s placeholders in Location:. Example: Do a quick Google-search of Drupal.org by adding a bookmark with<b> Location:</b> <b>http://google.com/search?q=inurl:drupal.org+%s</b> and <b>Keyword:</b> <b>gd</b> (short for Google Drupal). To use your new quick search, type Ctrl-L or Alt-D to get to the address bar, then type <b>gd</b> <i>keywords. </i>Set up ways to search php.net and drupal.org/project, too. =)
</li></ul><b>Multi-site / virtual hosts
</b><ul><li><b>Simplify switching between your computer and your remote server.</b> If you&#039;ve set up your local system for virtual hosts and you have a remote server for testing, you&#039;ll want to be able to switch between testing locally and testing remotely. Set up your local system to respond to all the domain names for the site (ex: example.com, foo.example.com, bar.example.com) <i>and</i> a local subdomain (ex: local.example.com). Set up your remote server to respond to all the domain names for the site (example.com, foo.example.com, bar.example.com) <i>and</i> a remote subdomain (ex: test.example.com). Then set up your /etc/hosts (c:\windows\system32\drivers\etc\hosts on Microsoft Windows) to look like this:

<pre>
127.0.0.1 localhost local.example.com
remote.server.ip.address test.example.com

127.0.0.1 example.com foo.example.com bar.example.com
#remote.server.ip.address example.com foo.example.com bar.example.com
</pre>
local.example.com will always resolve to your computer, test.example.com will always resolve to the other computer, and everything else depends on which line is active. # comments out a line. When you want to switch to testing on the remote server, add # to the beginning of the line for 127.0.0.1 example.com&#8230; and remove # from the line for your remote server. If you want to automate this even further, write a script that swaps different /etc/hosts files around.</li></ul>

Hope that helps! I&#039;d love to find out what you&#039;ve done to tweak your environment. Feel free to share your tips here!
<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/development' rel='tag' target='_self'>development</a>, <a class='technorati-link' href='http://technorati.com/tag/drupal' rel='tag' target='_self'>drupal</a>, <a class='technorati-link' href='http://technorati.com/tag/eclipse' rel='tag' target='_self'>eclipse</a>, <a class='technorati-link' href='http://technorati.com/tag/ide' rel='tag' target='_self'>ide</a>, <a class='technorati-link' href='http://technorati.com/tag/xdebug' rel='tag' target='_self'>xdebug</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/11/setting-up-your-drupal-development-environment/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal meetup in Toronto later - 7:00 at the Drake</title>
		<link>http://sachachua.com/wp/2008/06/10/drupal-meetup-in-toronto-later-700-at-the-drake/</link>
		<comments>http://sachachua.com/wp/2008/06/10/drupal-meetup-in-toronto-later-700-at-the-drake/#comments</comments>
		<pubDate>Tue, 10 Jun 2008 17:52:13 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[drupal toronto]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/10/drupal-meetup-in-toronto-later-700-at-the-drake/</guid>
		<description><![CDATA[Instead of self-defense and yoga classes today, I&#039;m going to the Lullabot meetup for Drupal developers over at the Drake  (1150 Queen St W, 7:00 PM - 10:00 PM).
Should be fun. =)



Technorati Tags: drupal toronto


]]></description>
			<content:encoded><![CDATA[<p>Instead of self-defense and yoga classes today, I&#039;m going to the <a href="http://groups.drupal.org/node/11942">Lullabot meetup for Drupal developers</a> over at the <a href="http://maps.google.ca/maps?f=q&#038;hl=en&amp;geocode=&amp;q=1150+Queen+St+W.+Toronto+ON&amp;sll=49.891235,-97.15369&amp;sspn=33.601713,81.474609&amp;ie=UTF8&amp;z=16&amp;iwloc=addr">Drake </a> (1150 Queen St W, 7:00 PM - 10:00 PM).</p>
<p>Should be fun. =)</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/drupal+toronto' rel='tag' target='_self'>drupal toronto</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/10/drupal-meetup-in-toronto-later-700-at-the-drake/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Notes on backporting modules from Drupal 6 to Drupal 5</title>
		<link>http://sachachua.com/wp/2008/06/10/notes-on-backporting-modules-from-drupal-6-to-drupal-5/</link>
		<comments>http://sachachua.com/wp/2008/06/10/notes-on-backporting-modules-from-drupal-6-to-drupal-5/#comments</comments>
		<pubDate>Tue, 10 Jun 2008 17:46:42 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/10/notes-on-backporting-modules-from-drupal-6-to-drupal-5/</guid>
		<description><![CDATA[I needed a web statistics module for a Drupal-based project at work, and integrating an external web statistics module seemed to be the way to go in terms of performance and features. BAWstats integrates the popular AWstats web statistics analyzer into Drupal. The module was developed for Drupal 6, so I spent a few hours [...]]]></description>
			<content:encoded><![CDATA[<p>I needed a web statistics module for a Drupal-based project at work, and integrating an external web statistics module seemed to be the way to go in terms of performance and features. <a href="http://drupal.org/project/bawstats">BAWstats</a> integrates the popular AWstats web statistics analyzer into Drupal. The module was developed for Drupal 6, so I spent a few hours backporting it to Drupal 5. I don&#039;t know if I can send a patch back (might have to do some paperwork), but anyway, here are some notes so that (a) I can remember how to do this in the future, and (b) it might save you some time.</p>
<p><b>Backporting from Drupal 6 to Drupal 5: Change the menu items</b></p>
<ul>
<li> Move the menu path from the array key to the <b>path</b> attribute.
</li>
<li> Rename
<p>page callback to <b>callback</b> and <b>page arguments</b> to <b>callback arguments</b>.</p>
</li>
<li> Remove the <b>file</b> and <b>file path</b> attributes. Move the included files to include_once lines for now, and look for instances of <b>include</b> that need to be changed to <b>include_once</b>. Read the included files to check for unintended execution.</li>
<li> Change tokenized menu items (%/%/%) to ones that dynamically build the menu path (arg(1) . &#039;/&#039; . arg(2) . &#039;/&#039; . arg(3)). Don&#039;t forget - this shouldn&#039;t be cached.</li>
<li> Change <kbd>'access arguments' =&gt; array(</kbd> to <kbd>'access' => user_access(</kbd> or something similar.</li>
</ul>
<p>Those were most of the changes I needed to make in order to backport bawstats to Drupal 5. Seems to work so far&#8230; =) More notes when I run into other things!</p>

<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/10/notes-on-backporting-modules-from-drupal-6-to-drupal-5/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal makes me feel like Bruce Lee + Jackie Chan</title>
		<link>http://sachachua.com/wp/2008/06/02/drupal-makes-me-feel-like-bruce-lee-jackie-chan/</link>
		<comments>http://sachachua.com/wp/2008/06/02/drupal-makes-me-feel-like-bruce-lee-jackie-chan/#comments</comments>
		<pubDate>Tue, 03 Jun 2008 01:28:15 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[sketches]]></category>

		<category><![CDATA[drupal sketches]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/02/drupal-makes-me-feel-like-bruce-lee-jackie-chan/</guid>
		<description><![CDATA[



Technorati Tags: drupal sketches


]]></description>
			<content:encoded><![CDATA[<p><img src="http://sachachua.com/notebook/colors/20080602-drupal.png" alt="Fast. Powerful. And having a heck of a lot of fun." /></p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/drupal+sketches' rel='tag' target='_self'>drupal sketches</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/02/drupal-makes-me-feel-like-bruce-lee-jackie-chan/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal: Storing data in the user profile</title>
		<link>http://sachachua.com/wp/2008/06/02/drupal-storing-data-in-the-user-profile/</link>
		<comments>http://sachachua.com/wp/2008/06/02/drupal-storing-data-in-the-user-profile/#comments</comments>
		<pubDate>Mon, 02 Jun 2008 17:09:36 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[drupal newbie]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/02/drupal-storing-data-in-the-user-profile/</guid>
		<description><![CDATA[If you want to store data in the user profile, here&#039;s an example of a quick and dirty way to do it:

global $user;
if ($user) {
  $array = array('fieldname' =&#62; 'value_to_save');
  user_save($user, $array);
}

Then access it with $user-&#62;fieldname. For more configurability, check out the Profile module.



Technorati Tags: drupal newbie


]]></description>
			<content:encoded><![CDATA[<p>If you want to store data in the user profile, here&#039;s an example of a quick and dirty way to do it:</p>
<pre>
global $user;
if ($user) {
  $array = array('fieldname' =&gt; 'value_to_save');
  user_save($user, $array);
}
</pre>
<p>Then access it with <code><b>$user-&gt;fieldname</b></code>. For more configurability, check out the <a href="http://drupal.org/handbook/modules/profile">Profile module</a>.</p>

<!-- start wp-tags-to-technorati 0.95 -->

<p class='technorati-tags'>Technorati Tags: <a class='technorati-link' href='http://technorati.com/tag/drupal+newbie' rel='tag' target='_self'>drupal newbie</a></p>

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/02/drupal-storing-data-in-the-user-profile/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal: Adding lines to settings.php in an installation profile</title>
		<link>http://sachachua.com/wp/2008/06/02/drupal-adding-lines-to-settingsphp-in-an-installation-profile-2/</link>
		<comments>http://sachachua.com/wp/2008/06/02/drupal-adding-lines-to-settingsphp-in-an-installation-profile-2/#comments</comments>
		<pubDate>Mon, 02 Jun 2008 15:35:54 +0000</pubDate>
		<dc:creator>Sacha Chua</dc:creator>
		
		<category><![CDATA[drupal]]></category>

		<category><![CDATA[geek]]></category>

		<guid isPermaLink="false">http://sachachua.com/wp/2008/06/02/drupal-adding-lines-to-settingsphp-in-an-installation-profile-2/</guid>
		<description><![CDATA[Installation profiles can make it easier for you to test and reproduce your configuration. But what if you need to do more than what Install Profile Wizard detects? For example, parts of the Domain Access module ask you  to add lines to your sites/default/settings.php. Fortunately, PHP allows you to set up your install profile [...]]]></description>
			<content:encoded><![CDATA[<p>Installation profiles can make it easier for you to <a href="http://sachachua.com/wp/2008/06/01/drupal-lather-rinse-repeat-cleaner-development-with-installation-profiles-and-makefiles/">test and reproduce your configuration</a>. But what if you need to do more than what Install Profile Wizard detects? For example, parts of the <a href="http://drupal.org/project/domain">Domain Access</a> module ask you  to add lines to your <b>sites/default/settings.php</b>. Fortunately, PHP allows you to set up your install profile to write to files during installation.</p>

<p>Here&#039;s the code I added to the end of the <i>profilename</i>_profile_final() function:</p>

<pre>
    // Add the following to the end of settings.php
    $file = fopen("sites/default/settings.php", "a");
    if ($file) {
      fputs($file, "\$cookie_domain = '.transitions2.org';\n");
      fputs($file, "require_once './sites/all/modules/domain/domain_conf/settings_domain_conf.inc';\n");
      fputs($file, "require_once './sites/all/modules/domain/domain_prefix/settings_domain_prefix.inc';\n");
      fclose($file);
    } else {
      drupal_set_message("Can't add domain-related lines to sites/default/settings.php");
    }
</pre>

Hope it helps!
<!-- start wp-tags-to-technorati 0.95 -->

<!-- end wp-tags-to-technorati -->
]]></content:encoded>
			<wfw:commentRss>http://sachachua.com/wp/2008/06/02/drupal-adding-lines-to-settingsphp-in-an-installation-profile-2/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
