<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Passing Curiosity: Posts tagged drupal</title>
    <link href="https://passingcuriosity.com/tags/drupal/drupal.xml" rel="self" />
    <link href="https://passingcuriosity.com" />
    <id>https://passingcuriosity.com/tags/drupal/drupal.xml</id>
    <author>
        <name>Thomas Sutton</name>
        
        <email>me@thomas-sutton.id.au</email>
        
    </author>
    <updated>2014-05-13T00:00:00Z</updated>
    <entry>
    <title>Drupal, Search API and Apache Solr with Homebrew on OS X</title>
    <link href="https://passingcuriosity.com/2014/drupal-search-api-solr-homebrew/" />
    <id>https://passingcuriosity.com/2014/drupal-search-api-solr-homebrew/</id>
    <published>2014-05-13T00:00:00Z</published>
    <updated>2014-05-13T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Installing <a href="http://lucene.apache.org/solr/">Apache Solr</a> with <a href="http://brew.sh/">Homebrew</a> on OS X and using it
with the <a href="http://drupal.org/project/search_api">Search API</a> modules for <a href="https://drupal.org/">Drupal</a> is pretty easy.
This article will run through the process and includes a few tweaks to make
things more convenient for those like me, who do this on different projects
fairly regularly.</p>
<h2 id="installing-apache-solr">Installing Apache Solr</h2>
<p>Apache Solr is a bit of a monolith (if you use it like most people I’ve seen):
you just download it and unpack it somewhere. Indeed, this is exactly what the
homebrew formula does. Run this command to get it installed:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">brew</span> install solr</span></code></pre></div>
<p>It also includes a handy shell script to start Solr using a configuration
directory you specify on the command line. Alas, it <em>doesn’t</em> set a few
properties which would be nice to have available in our Solr configuration
files. But it <em>is</em> a very simple shell script, and we have text editors!</p>
<p>Edit the <code>solr</code> shell script brew installed (you can use <code>which solr</code> to find
it) and make it look like this:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/bin/sh</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="va">DIST_PATH</span><span class="op">=</span><span class="st">&quot;/usr/local/Cellar/solr/4.7.2/libexec/dist&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="va">CONTRIB_PATH</span><span class="op">=</span><span class="st">&quot;/usr/local/Cellar/solr/4.7.2/libexec/contrib&quot;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="bu">[</span> <span class="ot">-z</span> <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span> <span class="bu">]</span><span class="kw">;</span> <span class="cf">then</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="bu">echo</span> <span class="st">&quot;Usage: $ solr path/to/config/dir&quot;</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="bu">cd</span> /usr/local/Cellar/solr/4.7.2/libexec/example <span class="kw">&amp;&amp;</span> <span class="ex">java</span> <span class="at">-server</span> <span class="va">$JAVA_OPTS</span> <span class="dt">\</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="at">-Dsolr.solr.home</span><span class="op">=</span><span class="va">$1</span> <span class="dt">\</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;-Dsolr.dist.dir=</span><span class="va">${DIST_PATH}</span><span class="st">&quot;</span> <span class="dt">\</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;-Dsolr.contrib.dir=</span><span class="va">${CONTRIB_PATH}</span><span class="st">&quot;</span> <span class="dt">\</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="at">-jar</span> start.jar</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="cf">fi</span></span></code></pre></div>
<p>(The <code>4.7.2</code> part will change depending on the version of Solr you have
installed; make sure it’s correct.)</p>
<p>We’ve adding two new properties specify where to find the JAR files, etc. that
come in the Solr distribution. We’ll use these when we’re tweaking the Solr
configuration files that come with the Drupal modules.</p>
<h2 id="installing-drupal">Installing Drupal</h2>
<p>Now that Solr is installed, start a new Drupal site and install the Search API
modules. I’m a command line person, so I do something like this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="va">PROJECT_NAME</span><span class="op">=</span>searchdemo</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="va">PROJECT</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${HOME}</span><span class="st">/Sites/</span><span class="va">${PROJECT_NAME}</span><span class="st">&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="fu">mkdir</span> <span class="at">-p</span> <span class="st">&quot;</span><span class="va">${PROJECT}</span><span class="st">&quot;</span></span></code></pre></div>
<p>Start a new Drupal project, and download and install the Search API module and
all its friends:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> <span class="st">&quot;</span><span class="va">${PROJECT}</span><span class="st">&quot;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">drush</span> dl drupal <span class="at">--drupal-project-rename</span><span class="op">=</span>htdocs</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> htdocs</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">mysqladmin</span> create <span class="st">&quot;</span><span class="va">${PROJECT_NAME}</span><span class="st">&quot;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="ex">drush</span> site-install <span class="at">--db-url</span><span class="op">=</span>mysql://me:password@localhost/<span class="va">${PROJECT_NAME}</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="ex">drush</span> en search_api search_api_solr search_api_attachments facetapi</span></code></pre></div>
<h2 id="building-a-solr-core-for-search-api">Building a Solr core for Search API</h2>
<p>Now lets create a new Solr core for Search API to use. We’ll start with one of
the example configurations that come with Solr (watch out for the Solr version
number in this path):</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">cp</span> <span class="at">-a</span> /usr/local/Cellar/solr/4.7.2/libexec/example/solr <span class="st">&quot;</span><span class="va">${PROJECT}</span><span class="st">/solr&quot;</span></span></code></pre></div>
<p>This configuration includes a single Solr “core” called <code>collection1</code>. We’ll
duplicate that, then drop the Search API Solr configuration on top of it.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> <span class="st">&quot;</span><span class="va">${PROJECT}</span><span class="st">/solr/&quot;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="fu">mkdir</span> <span class="at">-p</span> <span class="st">&quot;</span><span class="va">${PROJECT_NAME}</span><span class="st">/&quot;</span><span class="dt">{conf</span><span class="op">,</span><span class="dt">data}</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="fu">cp</span> <span class="at">-a</span> <span class="st">&quot;collection1/conf&quot;</span>/<span class="pp">*</span> <span class="st">&quot;</span><span class="va">${PROJECT_NAME}</span><span class="st">/conf/&quot;</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="fu">cp</span> <span class="at">-a</span> <span class="va">${PROJECT}</span>/htdocs/sites/all/modules/search_api_solr/solr-conf/4.x/<span class="pp">*</span> <span class="st">&quot;</span><span class="va">${PROJECT_NAME}</span><span class="st">/conf/&quot;</span></span></code></pre></div>
<p>Now to tweak it. First, give the new core it’s own name so that Solr can
identify it correctly:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">&quot;name=</span><span class="va">${PROJECT_NAME}</span><span class="st">&quot;</span> <span class="op">&gt;</span> <span class="st">&quot;</span><span class="va">${PROJECT_NAME}</span><span class="st">/core.properties&quot;</span></span></code></pre></div>
<p>Then update the <code>solrconfig.xml</code> file that came with Search API Solr to use the
<code>solr.dist.dir</code> and <code>solr.contrib.dir</code> properties we added to the <code>solr</code> shell
script above. Basically replace any mention of <code>../../dist/</code> in your
<code>solrconfig.xml</code> file with <code>${solr.dist.dir:../../dist/}</code>. This says “use the
configured value for <code>solr.dist.dir</code> or, if there isn’t one, <code>../../dist/</code>”. It
should already be done for <code>solr.contrib.dir</code> but you might like to double
check, just in case.</p>
<p>If you want to use any optional/non-core features you’ll need to update the
<code>&lt;lib&gt;</code> tags (these are the main places you’ll need to make the <code>solr.dist.dir</code>
change) to use the correct JAR file names.</p>
<p>I’ll be using the extraction functionality to index the content of PDF and
other files, so I needed to uncomment and correct the tag for
<code>solr-cell-\d.*\.jar</code>:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode xml"><code class="sourceCode xml"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>&lt;<span class="kw">lib</span><span class="ot"> dir=</span><span class="st">&quot;${solr.dist.dir:../../../dist/}&quot;</span><span class="ot"> regex=</span><span class="st">&quot;solr-cell-\d.*\.jar&quot;</span> /&gt;</span></code></pre></div>
<h2 id="running-it">Running it</h2>
<p>Now go configure your Drupal site to use your new Apache Solr instance. You
should configure Search API to communicate with Solr at
<code>http://searchapi.dev:8983/solr/${PROJECT_NAME}</code> (you should put the real value
here, not the variable name). Then enable an index, configure it, and build
some search functionality!</p>]]></summary>
</entry>
<entry>
    <title>Drupal SEO Functionality</title>
    <link href="https://passingcuriosity.com/2013/drupal-seo/" />
    <id>https://passingcuriosity.com/2013/drupal-seo/</id>
    <published>2013-09-06T00:00:00Z</published>
    <updated>2013-09-06T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Some content management systems have a reputation for poor search engine
performance. Drupal, thankfully, is not one of these. With a combination of
core functionality and several contributed modules, any Drupal web-site can
have very good search engine performance.</p>
<h2 id="urls">URLs</h2>
<p>Drupal has the capacity to assign “human friendly URLs” to any page on the
web-site. With the addition of the <a href="https://drupal.org/project/pathauto">Pathauto</a> module, we can configure the
site to automatically generate “friendly” URLs based on the titles, dates,
categories, menu hierarchy, or nearly any other property of a piece of content.</p>
<p>The <a href="https://drupal.org/project/globalredirect">Global Redirect</a> and <a href="https://drupal.org/project/pathologic">Pathologic</a> modules can ensure that search
engines and visitors use only the “friendly” URL for a page, reducing or
removing the instance of duplicate content.</p>
<h2 id="search-engine-integration">Search Engine Integration</h2>
<p>The <a href="https://drupal.org/project/robotstxt">RobotsTxt</a>, <a href="https://drupal.org/project/xmlsitemap">XML Sitemap</a> and <a href="https://drupal.org/project/site_verify">Site Verification</a> modules can help
to support and manage the integration between a Drupal site and various search
engines.</p>
<h2 id="metadata">Metadata</h2>
<p>The <a href="https://drupal.org/project/metatag">Metatag</a> module allows your Drupal site to manage the metatags embedded
in the code of each page. As with “friendly” URLs, metatags can be controlled
on each individual page or generated automatically from the title, dates, and
other properties of each piece of content.</p>
<p>This module supports a range of metadata standards and formats including Dublin
Core, Facebook Open Graph, Twitter Cards.</p>
<h2 id="analytics">Analytics</h2>
<p>The <a href="https://drupal.org/project/google_analytics">Google Analytics</a> and <a href="https://drupal.org/project/google_analytics_reports">Google Analytics Reports</a> modules can integrate
support for Google Analytics more deeply into a Drupal web-site. Using these
modules we have fine-grained control of which users and which sections of a site
are tracked and even embed Google Analytics reports directly into the site.</p>
<h2 id="content">Content</h2>
<p>A Drupal web-site can enforce a range of restrictions and requirements on the
content that it manages.</p>
<p>Common concerns are alternate text for images (often called “alt text”),
resizing uploaded images appropriately, restricting formats of uploaded files,
enforcing length requirements.</p>
<p>Domain-specific requirements can also be implemented, if required.</p>
<h2 id="markup">Markup</h2>
<p>The code generated by a Drupal web-site can be customised, as required, to meet
the requirements of a project.</p>
<p>The Drupal theme which implements your custom design will meet search engine
recommendations out of the box, and can be customised to meet SEO requirements
if required.</p>
<h2 id="performance">Performance</h2>
<p>Drupal includes a range of features and considerations which help to improve
page loading times, now an important component of search engine rankings. This
includes the aggregation of Javascript and stylesheet files, content delivery
networks, and a range of application caching solutions.</p>
<p>Drupal web-sites can, depending on specific functionality, have very good
support for HTTP caching and a range of server configuration options which can
improve performance.</p>]]></summary>
</entry>
<entry>
    <title>Sydney Drupal Meetup, March 2013</title>
    <link href="https://passingcuriosity.com/2013/first-sydney-drupal-meetup/" />
    <id>https://passingcuriosity.com/2013/first-sydney-drupal-meetup/</id>
    <published>2013-03-21T00:00:00Z</published>
    <updated>2013-03-21T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>I attended my first <a href="http://www.meetup.com/drupalsydney/events/78491452/">meetup with the Sydney Drupal group</a> tonight and saw a
couple of interesting talks:</p>
<ol type="1">
<li><p>Chris Harrop from Acquia introduced their devcloud platform and some of the
other tools and services they offer.</p></li>
<li><p>Murray Woodman presented some performance measurements of node loading when
using <a href="http://drupal.org/project/entitycache">Entitycache</a> and other techniques.</p></li>
<li><p>Justin Randall gave a pretty thorough introduction to using XHProf to detect
and identify performance problems and regressions.</p></li>
</ol>
<h2 id="acquia">Acquia</h2>
<p>Chris’ talk about Acquia’s offerings was very short and quite high level. I was
interested to see their “checklist-style” Drupal evaluation and testing tool as
I’d was looking at a similar sort of run-the-tests-in-this-checklist tool
yesterday.</p>
<p>Also: I got a code for a free dev environment on their cloud service.</p>
<h2 id="node-weight">Node Weight</h2>
<p>The bulk of Murray’s talk was to present benchmarks of several approaches to
improving <code>entity_load</code> performance in Drupal sites.</p>
<p>He compared:</p>
<ol type="1">
<li><p>Setting <code>innodb_buffer_pool_size</code> appropriately to your machine and
workload.</p></li>
<li><p>Enabling the MySQL query cache.</p></li>
<li><p>Installing the <a href="http://drupal.org/project/entitycache">Entitycache</a> module.</p></li>
<li><p>Using APC to store cached objects.</p></li>
<li><p>Several combinations of the above.</p></li>
</ol>
<p>The biggest and quickest win was installing <em>entitycache</em> (which resulted in an
“80%” performance improvement), with the other techniques yeilding smaller
improvements.</p>
<h2 id="xhprof">XHProf</h2>
<p>Justin began his presentation with a quote:</p>
<blockquote>
<p>Don’t bring logic to a data fight.</p>
</blockquote>
<p>Analysing system performance and identifying performance problems can be
complex and real data on specific cases is more useful and more reliable than
logic. “Don’t trust your gut, use science.”</p>
<p>After a bit of good advice about performance – it’s a process not a goal;
test, and fix, client and network issues first – Justin dug into using
<a href="https://github.com/facebook/xhprof">XHProf</a> to record and analyse performance profiles of Drupal pages.</p>
<p>The XHProf extension has so small an impact on performance that you can run
it on production servers ready and waiting for a performance problem to
profile (which degrades performance by around “&lt;10%”).</p>
<p>Along with the XHProf extension are several tools to process and analyse the
recorded profiles:</p>
<ul>
<li><p>The moderately awful <a href="https://github.com/facebook/xhprof/tree/master/xhprof_html">web interface</a> which comes with the extension.</p></li>
<li><p>The <a href="http://drupal.org/project/xhprof">XHProf Drupal module</a>.</p></li>
<li><p><a href="https://github.com/msonnabaum/XHProfCLI">Mark Sonnabaum’s XHProf CLI</a> tool to aggregate multiple profiles so that
runs can be compared more reliably (when, e.g., checking for performance
regressions in a patch).</p></li>
</ul>
<p>A good tip, which hadn’t occured to me, was to use the <a href="http://php.net/auto-prepend-file"><code>auto_prepend_file</code></a>
feature in PHP to enable XHProf. This is application agnostic, does not require
changes to the application code, and ensures that your profiles include the
whole application.</p>
<p>The idea of building XHProf into my production environments, with a prepend
file configured and waiting to enable profiling (or automatically profiling,
say, 1% of requests) is intriguing.</p>
<h2 id="conclusion">Conclusion</h2>
<p>So this was a pretty good introduction to the Drupal community in Sydney, and
it was nice to see how other groups run meetups (though I gather there have
been some recent changes here).</p>]]></summary>
</entry>
<entry>
    <title>Using git repositories for platform versioning</title>
    <link href="https://passingcuriosity.com/2011/git-repositories-for-platform-versioning/" />
    <id>https://passingcuriosity.com/2011/git-repositories-for-platform-versioning/</id>
    <published>2011-08-31T00:00:00Z</published>
    <updated>2011-08-31T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>I’m not sure how widely this might be applicable but I’ve found it an
interesting problem to think about and it’s going to help iron out some
wrinkles in our workflow.</p>
<p>We have a standard platform that does a great deal of the scutwork required of
a generic CMS based on Drupal. What’s included in it doesn’t really matter
(it’s an install profile that does a bunch of stuff), just that it’s the base
of many of our projects and it is maintained as a unit and upgraded as a whole
on individual sites.</p>
<p>I currently maintain this using a bunch of git repos, a custom feature server
(which uses <code>ssh</code> tunnels to access the git repos), <code>drush make</code> and about a
dozen other moving parts which produce a new build of the platform in a
tarball. Needless to say this is tedious, error prone, and means new releases
are slower than they should be. Git to the rescue!</p>
<p>Rather than building tarballs of platform releases manually I’ll be
maintaining canonical versions in repositories and using git to manage
applying upgrades to individual projects.</p>
<h3 id="creating-a-platform">Creating a platform</h3>
<p>This first step is creating my “blessed” platform repository. To keep things
simple I’ll describe managing two platforms:</p>
<ul>
<li><p><code>6.x</code> is the current release of Drupal 6; and</p></li>
<li><p><code>7.x</code> is the current release of Drupal 7.</p></li>
</ul>
<p>As this repo is somewhat special I’m going to take some pains to make sure
it’s structured exactly as I want it. In particular, I want every branch to be
correspond to one of my platforms. This is a little tricky but it only happens
once so don’t worry too much if you find it confusing.</p>
<pre><code># Initialise a new empty repo and add the origin I'll push the result to
mkdir platform
cd platform
git init
git remote add origin git@gorilla:/platforms/drupal.git

# First, let's create the Drupal 6 branch.
git symbolic-ref HEAD refs/heads/6.x
rm .git/index
git clean -fdx
drush dl --yes --drupal-project-rename=htdocs drupal-6
git add htdocs
git commit -m 'drupal-6'
git push origin 6.x

# Now, let's take care of the Drupal 7 branch.
git symbolic-ref HEAD refs/heads/7.x
rm .git/index
git clean -fdx
drush dl --yes --drupal-project-rename=htdocs drupal-7
git add htdocs
git commit -m 'drupal-7'
git push origin 7.x</code></pre>
<p>This sequence is a little verbose (the <code>rm</code> and <code>git clean</code> for Drupal 6
aren’t strictly necessary) but it should be obvious how I can add additional
platforms.</p>
<p>Assuming that the repo at <code>git@gorilla:/platforms/drupal.git</code> was newly
<code>init</code>ed, it should now contain a <code>6.x</code> branch containing Drupal 6 and a <code>7.x</code>
branch containing Drupal 7.</p>
<p>For safety’s sake, it’d probably be a good idea to have push restrictions on
the platform repository to prevent accidental and illicit modifications
flowing back from projects into platforms. It’s outside the scope of this
document to describe how to do this but you probably want to use <code>gitolite</code> or
something else with fine-grained access control (i.e. not gitosis).</p>
<h3 id="starting-a-project">Starting a project</h3>
<p>Now that my platforms are available in git I can use them as the starting
point for a new project. I just clone the right branch from the platform repo
and I’m off!</p>
<pre><code>git clone --origin platform --branch 6.x git@gorilla:/platforms/drupal example.com
cd example.com
git checkout -b master</code></pre>
<p>It’s a bit confusing at first glance, so I’ll break that down a bit. First I
clone the platform repository with the <code>git clone</code> command. Instead of letting
it use default values I’m telling it what to call the <em>origin</em> remote in the
new repository (<code>platform</code> instead of <code>origin</code>) and which branch to clone
(<code>6.x</code> instead of the default <code>HEAD</code> in the remote). Running this command will
create a new repository in <code>example.com/</code> with a remote called <code>platform</code> and
a single branch called <code>6.x</code> (based on the <code>6.x</code> in <code>platform</code>).</p>
<p>I recommend using the <code>6.x</code> branch exclusively for pulling in new releases of
the platform so I also create a <code>master</code> branch to work on with the next git
command does.</p>
<p>Now <code>example.com</code> has two branches: <code>6.x</code> where I can pull in new releases of
the platform, and <code>master</code> where I’ll be working on the <em>example.com</em> site.</p>
<h3 id="upgrading-a-project">Upgrading a project</h3>
<p>Upgrading a project to run on the latest version of it’s platform should be a
simple matter of pulling the appropriate branch and merging the changes into
<code>master</code>.</p>
<pre><code>cd example.com
git checkout 6.x
git pull
git checkout master
git merge 6.x</code></pre>
<p>Here I checkout the “platform” branch (<code>6.x</code> as in the example above) and pull
in any remote changes. Then I checkout the <code>master</code> branch and merge the
changes in the updated <code>6.x</code> branch.</p>
<p>Unless I’ve been a naughty boy and modified files that are “owned” by the
platform this shouldn’t result in so much as a merge conflict.</p>
<h3 id="conclusion">Conclusion</h3>
<p>I haven’t rolled this new method out at work yet but it’s in the pipeline. I’m
quite excited by it and I think it’ll help make what’s currently tedious and
error prone into something of a NOOP. Hopefully the rest of the team agrees!</p>
<p>Have you done something similar? Have I missed some serious consideration? Is
this all old hat and I should get with the programme? I’d love to hear any
comments or feedback on the approach I’ve described.</p>]]></summary>
</entry>
<entry>
    <title>Drupal 7: theming forms with tables</title>
    <link href="https://passingcuriosity.com/2011/drupal-7-forms-tables/" />
    <id>https://passingcuriosity.com/2011/drupal-7-forms-tables/</id>
    <published>2011-07-11T00:00:00Z</published>
    <updated>2011-07-11T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>There are a few different ways to use tables to layout Drupal 7
forms. The most commonly described method (indeed, it’s used in the
core [tableselect][1] form field type) is to create a custom form
field type that can process it’s children and render as a table. This
is pretty limiting (<code>tableselect</code>, for instance, is pretty much just a
select field).</p>
<p>Another approach is to use <code>#prefix</code> and <code>#suffix</code> to wrap each field
in the table with the appropriate HTML tags to build the table. This,
though, means that changing the weights of elements, adding and
removing elements, or making pretty much any change to the form might
result in invalid or completely broken markup.</p>
<p>The approach I think is best is to treat the table similarly to the
way the forms API handles fieldsets: as a container with multiple
fields within it. This can be a little tricky to get working, but
seems to do the trick for me. The approach works like this:</p>
<p>Create a new form element that will be the table:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="va">$form</span>[<span class="st">'people'</span>] <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#prefix'</span> =&gt; <span class="st">'&lt;div id=&quot;people&quot;&gt;'</span><span class="ot">,</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#suffix'</span> =&gt; <span class="st">'&lt;/div&gt;'</span><span class="ot">,</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#tree'</span> =&gt; <span class="kw">TRUE</span><span class="ot">,</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#theme'</span> =&gt; <span class="st">'table'</span><span class="ot">,</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#header'</span> =&gt; <span class="dt">array</span>(t(<span class="st">'First name'</span>)<span class="ot">,</span> t(<span class="st">'Family name'</span>))<span class="ot">,</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#rows'</span> =&gt; <span class="dt">array</span>()<span class="ot">,</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>)<span class="ot">;</span></span></code></pre></div>
<p>Then loop over your data to create the rows in the table. This is a
little tricky: if you just put your fields straight into
<code>$form['people']['#rows']</code> then FAPI won’t see them (remember that it
won’t traverse array components begining with a <code>#</code>) and so won’t
process them. On the other hand, you <em>could</em> name your array
<code>$form['people']['rows']</code> but then the FAPI will generate quite noisy
field names and add additional values which will confuse
<code>theme_table()</code> when it comes time to render the whole lot.</p>
<p>Instead, we’ll use references to build both include the fields in the
form (though in a way that they won’t be actually output) <em>and</em> put
them in <code>$form['people']['#rows']</code> so the table will be rendered
nicely. This is possible mainly through the use of references!</p>
<p>Assuming you’ve got an array <code>$people</code> containing your data you can
loop over them to add the rows to your table like so (and yes, I know
this could be structured better):</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> (<span class="va">$i</span> <span class="op">=</span> <span class="dv">0</span><span class="ot">;</span> <span class="va">$i</span> <span class="op">&lt;</span> <span class="fu">count</span>(<span class="va">$people</span>)<span class="ot">;</span> <span class="va">$i</span><span class="op">++</span>) {</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Build the fields for this row in the table. We'll be adding</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="co">// these to the form several times, so it's easier if they are</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">// individual variables rather than in an array.</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="va">$fname</span> <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#id'</span> =&gt; <span class="st">'people-'</span> <span class="op">.</span> <span class="va">$i</span> <span class="op">.</span> <span class="st">'-fname'</span><span class="ot">,</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#type'</span> =&gt; <span class="st">'textfield'</span><span class="ot">,</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#default_value'</span> =&gt; <span class="va">$people</span>[<span class="va">$i</span>][<span class="st">'fname'</span>]<span class="ot">,</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="va">$sname</span> <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#id'</span> =&gt; <span class="st">'people-'</span> <span class="op">.</span> <span class="va">$i</span> <span class="op">.</span> <span class="st">'-sname'</span><span class="ot">,</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#type'</span> =&gt; <span class="st">'textfield'</span><span class="ot">,</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#default_value'</span> =&gt; <span class="va">$people</span>[<span class="va">$i</span>][<span class="st">'sname'</span>]<span class="ot">,</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Include the fields so they'll be rendered and named</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">// correctly, but they'll be ignored here when rendering as</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">// we're using #theme =&gt; table.</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>  <span class="co">//</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Note that we're using references to the variables, not just</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">// copying the values into the array.</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a>  <span class="va">$form</span>[<span class="st">'people'</span>][] <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>    <span class="st">'fname'</span> =&gt; <span class="op">&amp;</span><span class="va">$fname</span><span class="ot">,</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>    <span class="st">'sname'</span> =&gt; <span class="op">&amp;</span><span class="va">$sname</span><span class="ot">,</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Now add references to the fields to the rows that</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `theme_table()` will use.</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a>  <span class="co">//</span></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a>  <span class="co">// As we've used references, the table will use the very same</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a>  <span class="co">// field arrays as the FAPI used above.</span></span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a>  <span class="va">$form</span>[<span class="st">'people'</span>][<span class="st">'#rows'</span>][] <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true" tabindex="-1"></a>    <span class="dt">array</span>(<span class="st">'data'</span> =&gt; <span class="op">&amp;</span><span class="va">$fname</span>)<span class="ot">,</span></span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true" tabindex="-1"></a>    <span class="dt">array</span>(<span class="st">'data'</span> =&gt; <span class="op">&amp;</span><span class="va">$sname</span>)<span class="ot">,</span></span>
<span id="cb2-40"><a href="#cb2-40" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-41"><a href="#cb2-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-42"><a href="#cb2-42" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Because we've used references we need to `unset()` our</span></span>
<span id="cb2-43"><a href="#cb2-43" aria-hidden="true" tabindex="-1"></a>  <span class="co">// variables. If we don't then every iteration of the loop will</span></span>
<span id="cb2-44"><a href="#cb2-44" aria-hidden="true" tabindex="-1"></a>  <span class="co">// just overwrite the variables we created the first time</span></span>
<span id="cb2-45"><a href="#cb2-45" aria-hidden="true" tabindex="-1"></a>  <span class="co">// through leaving us with a form with 3 copies of the same fields.</span></span>
<span id="cb2-46"><a href="#cb2-46" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-47"><a href="#cb2-47" aria-hidden="true" tabindex="-1"></a>  <span class="kw">unset</span>(<span class="va">$fname</span>)<span class="ot">;</span></span>
<span id="cb2-48"><a href="#cb2-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">unset</span>(<span class="va">$sname</span>)<span class="ot">;</span></span>
<span id="cb2-49"><a href="#cb2-49" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Now you should have a form full of fields all laid out nicely in a
table. Hoorah!</p>]]></summary>
</entry>
<entry>
    <title>Planning for DrupalDownunder</title>
    <link href="https://passingcuriosity.com/2011/planning-for-drupaldownunder/" />
    <id>https://passingcuriosity.com/2011/planning-for-drupaldownunder/</id>
    <published>2011-01-12T00:00:00Z</published>
    <updated>2011-01-12T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>While Brisbane and Queensland are in the grip of some fairly serious flooding
(please consider donating to the <a href="http://www.qld.gov.au/floods/donate.html">Queensland state government relief
fund</a>) the official word is that
<a href="http://drupaldownunder.org/flood-update">DrupalDownunder will be going ahead</a> so I’ve been going through
the programme and narrowing down the sessions I want to see. There are a few
bits and pieces I’m not sure of, but my weekend is going to look something
like this:</p>
<p>On Saturday there’re two keynote sessions and five slots with competing
sessions.</p>
<ol type="1">
<li><p>The <a href="http://drupaldownunder.org/session/exportables">Exportables</a> session
by <a href="http://drupal.org/user/35266">Simon Hobbs</a> will no doubt help in my quest to develop a
reliable and efficient workflow at work.</p></li>
<li><p><a href="http://drupal.org/user/15091">Allie Micka</a>’s keynote <a href="http://drupaldownunder.org/session/allie-mickas-keynote">Running a Drupal business and
contributing to Drupal
sustainably</a> is a
keynote and sounds interesting enough, if not quite my cup of tea.</p></li>
<li><p><a href="http://drupal.org/user/116305">Dave Hall</a>’s <a href="http://drupaldownunder.org/session/building-distributions-drupal-7">Building Distributions with Drupal
7</a> will,
again, help in my quest for standardisation and automation to simplify
workflows.</p></li>
<li><p><a href="http://drupal.org/user/188162">Josh Waihi</a>’s keynote <a href="http://drupaldownunder.org/session/keynote-goodbye-centralization-hello-distribution-introduction-git">Goodbye Centralization, Hello
Distribution: An Introduction to
Git</a>,
is an introduction to git (which I already use and am relatively familiar
with).</p></li>
<li><p>Given the number of times I’ve been asked about options for paid
membership, the <a href="http://drupaldownunder.org/session/paid-membership-sites">Paid Membership
Sites</a> session by
<a href="http://drupal.org/user/279264">Chris Hood</a> will scratch an itch of mine (which other people have
been tickling).</p></li>
<li><p>As I’ve implemented two or three custom CCK fields (and others on my team
have implemented another few), <a href="http://drupal.org/user/86970">Ivan Zugec</a>’s session on <a href="http://drupaldownunder.org/session/fields-core-how-create-custom-field">Fields
in Core: How to create a custom
field</a>
is sure to be interesting.</p></li>
<li><p><a href="http://drupal.org/user/1">Dries</a>’ keynote session with <a href="http://drupaldownunder.org/session/dries-keynote">details to
come</a> is by Dries. And a
keynote. And by Dries.</p></li>
</ol>
<p>My choices on Sunday are less clear cut in spite of having a choice in only
four slots:</p>
<ol type="1">
<li><p>I expect <a href="http://drupal.org/user/446626">John Zornig</a> session about <a href="http://drupaldownunder.org/session/building-document-management-system-drupal">Building a document
management system in
Drupal</a>
to be inspiring when combined with my recent interest in Solr-based search.</p></li>
<li><p>Both <a href="http://drupaldownunder.org/session/turbo-charge-your-drupal-site">Turbo charge your Drupal
site</a> by
<a href="http://drupal.org/user/370574">Kim Pepper</a> and <a href="http://drupaldownunder.org/session/fancy-pants-wysiwyg-editing">Fancy Pants WYSIWYG
Editing</a> by
<a href="http://twitter.com/boztek">Boris Gordon</a> sound interesting and useful.</p></li>
<li><p><a href="http://drupaldownunder.org/session/session-dries">Session by Dries</a>.</p></li>
<li><p>I’ve got a bunch of projects coming up at work that need payment solutions
of various types so <a href="http://drupaldownunder.org/session/session-allie-micka">The Payment api and its framework approach to module
development</a> by <a href="http://drupal.org/user/15091">Allie
Micka</a> will obviously be useful, but I’m personally interested in
systems administration and performance so <a href="http://drupaldownunder.org/session/horizontally-scaling-drupal">Horizontally Scaling
Drupal</a> by
<a href="http://drupal.org/user/116305">Dave Hall</a> sounds interesting. <a href="http://drupaldownunder.org/session/simple-page-layouts-and-customisations-using-views-cck-and-css">Simple page layouts and
customisations using Views, CCK and
CSS</a>
by <a href="http://drupal.org/user/1042818">Dale Baldwin</a> sounds a bit entry level.</p></li>
<li><p>Both <a href="http://drupaldownunder.org/session/case-studies-nswgov-and-abc">Case-Study: ABC Dig
Music</a> by
<a href="http://drupal.org/user/254857">David Peterson</a> and <a href="http://drupaldownunder.org/session/migrating-drupal-web-environment">Migrating to a Drupal Web
Environment</a>
by <a href="http://drupal.org/user/895162">Fiona Bush</a> sound like they’ll have interesting insights. I’ll
probably go Fiona’s session, if only because I went to ANU for a while.</p></li>
<li><p><a href="http://twitter.com/outlandishjosh">Josh Koenig</a>’s keynote session <a href="http://drupaldownunder.org/session/josh-koenigs-keynote">details to
come</a>.</p></li>
<li><p><a href="http://drupaldownunder.org/session/lightning-talks">Lightning talks</a> are
alway good (or, at least, over quickly).</p></li>
</ol>
<p>Now that I’ve thought about it these plans will be making their way into my
calendar.</p>]]></summary>
</entry>
<entry>
    <title>Going Further with Litecal</title>
    <link href="https://passingcuriosity.com/2010/going-further-with-litecal/" />
    <id>https://passingcuriosity.com/2010/going-further-with-litecal/</id>
    <published>2010-07-06T00:00:00Z</published>
    <updated>2010-07-06T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>My <a href="/2010/using-litecal/">last article</a> was a quick introduction to the
<code>litecal</code> module. In this article, I’ll show how to go further with Litecal to
create more complete user interfaces. You’ll see how to use associate related
events by colour, how to add additional displays of the same data, and a few
tips on themeing Litecal.</p>
<hr />
<h3 id="using-colour-in-the-calendar">Using colour in the calendar</h3>
<p>Most of us are familiar with programs like iCal which use colour “link”
related events together on a calendar. One way to make a Litecal-based view
immediately more usable is to implement this technique. Thankfully it’s rather
easy to do thanks, once again, to <a href="http://developmentseed.org/">Development Seed</a> and their
<a href="http://code.developmentseed.org/node/176">Seed</a> module. Seed contains useful code and customisations for Litecal
and a number of other modules. The name suggests that it’s intended for
semi-internal use (maybe just Open Atrium, I’m not sure), but it’s GPL and the
awesome people at DS released it so I don’t feel too bad in making use of it.</p>
<p>Do the usual dance of downloading, unpacking and installing the module from
the link above (Seed depends on <a href="http://drupal.org/project/context">Context</a>, so install that too). Once
that’s done, you’ll need to return to the view you created in the last
article.</p>
<p>Go back and edit your calendar. Select the Calendar display, update the <em>Style
options</em> and change <em>Color by</em> to <code>field_event_location_value</code>. Once you’ve
updated (or saved) the display, Litecal will use Seed to assign a colour to
each event displayed on <em>the calendar based on the value of the location
field</em>. Events at the same location (where “same” means “has the same CRC32”)
will have the same colour! Seed only supports 16 colours but this should be
enough for most purposes and the colours themselves are easily overridden in
your theme stylesheet.</p>
<p>As great as this is (and you’ll have to agree, it is pretty awesome) there are
a few little niggles. First, when Seed is installed Litecal might get confused
and fail to render events in the <em>Live Preview</em> (this might just be Theme
Developer, though). Second, Seed doesn’t just add support for colours to
Litecal; it also overrides the user picture template and a bunch of other
stuff that you probably want left alone. Third, it’s adding Context for no
particular reason (at least in this demo).</p>
<p>I’m still a bit puzzled by the first issue, but the others are readily solved
by pulling the colouring code out of Seed (look for the theme functions with
<code>crayon</code> in their names) and whacking it in another module, but you’ll also
need to tweak the code of Litecal (look for the <code>module_exists('seed')</code>). I
hope that this colouring functionality will be merged into Litecal itself at
some point, or at least pulled out into a module that doesn’t do a bunch of
other stuff too.</p>
<h3 id="additional-displays">Additional displays</h3>
<p>A calendar by itself is great for little things – “Yes, I’m free on Friday
13th” – but might not be enough in cases where users need more complete
information at a glance. That’s why so many calendar applications also display
events in a list or table view. With a pretty feature-full calendar, this list
view is next on the list! The goal is to add a table with the most pertinent
details about each event below the calendar display.</p>
<p>Having though of just this combination of use cases, Views makes this an
absolute cinch. Go back to your view and add a new <em>Attachment</em> display.
Change the name of your new display and override the <em>Style</em>, setting it to
<em>Table</em> (sorted by the Date field).</p>
<p>Edit the <em>Attachment settings</em> like this:</p>
<ul>
<li><p><em>Inherit arguments</em> should be <em>yes</em> (so that the table displays the same
month as the calendar).</p></li>
<li><p><em>Postition</em> should be <em>After</em> (it’ll look a bit odd before the calendar).</p></li>
<li><p><em>Attach to</em> the calendar display you created in the first article.</p></li>
</ul>
<p>There are a few more tweaks you might like to make at this point:</p>
<ul>
<li><p>Add <em>Sort criteria</em> in the <em>Default</em> display so that the events are sorted
by <em>Content: Date</em> in ascending order. This might help keep things
consistent in the event that you need to display the pager.</p></li>
<li><p>Add <em>Filters</em> on <em>Date: Date (node)</em> to list only upcoming events in the
table (those where <em>To date</em> is greater than or equal to now).</p></li>
</ul>
<p>Other alternatives include:</p>
<ul>
<li>Using Panels instead of attachment Views to link the table to the calendar.
This makes using the pager slightly simpler.</li>
</ul>
<h3 id="themeing-litecal">Themeing Litecal</h3>
<p>Given that it’s called “Key”, it’d be nice if the table display was actually a
key for the calendar display. You can add a column with the same colour as is
used in the calendar quite with a simple change to the view and a less simple
change to your theme.</p>
<p>If you looked at the colouring code in Seed and the way it’s invoke from
Litecal, you probably noticed that it’s fairly simple: get the “key” value,
feed it to the colour picker code (<code>theme('crayon', $key)</code>) and use the result
to add a class to the element.</p>
<p>If you followed the instructions above, your calendar entries are colour coded
according to the location field. To add the correct colour to the table,
you’ll need to add a new column containing this value and then use the theme
layer to turn this into a coloured splotch.</p>
<p>Edit your “Key” display and add a new <em>Content: Location</em> field. Re-order the
fields and move this new column to the top of the list as you want the
colour-coding to be the first item in each row. Save that and then load the
view in your browser. Using whatever inspector tool your web-browser provides
(or “View Source” if you’re a sadist), determine the [longest] class on the
cells in the new column. Mine is: <code>views-field-field-event-location-value-1</code>.</p>
<p>This class is generated based on two facts: it is a view field, and the field
being displayed is <code>field-event-location-value-1</code>. You can use this to work
out what the theme function you are about to write should be called. It will
be something like this:</p>
<pre><code>`&lt;prefix&gt;_views_view_field__&lt;view_name&gt;__attachment__&lt;field_name&gt;`</code></pre>
<p>where <code>&lt;prefix&gt;</code> is your theme name (or theme engine name), <code>&lt;view_name&gt;</code> is
the name you assigned your view when you created it, and <code>&lt;field_name&gt;</code> is the
name used in the class above (but with <code>_</code>s instead of <code>-</code>s).</p>
<p>Fill in the three blanks (you can almost always use <code>phptemplate</code> for the
prefix and expect it to work!) and add a function like this to the
<code>template.php</code> in your theme:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span> phptemplate_views_view_field__events_calendar__attachment__field_event_location_value_1(<span class="va">$view</span><span class="ot">,</span> <span class="va">$field</span><span class="ot">,</span> <span class="va">$row</span>)</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>{</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Get the &quot;key&quot;. This is just the value that would be displayed in the </span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">// table cell if we weren't messing with things.</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="va">$text</span> <span class="op">=</span> <span class="va">$view</span>-&gt;field[<span class="va">$field</span>-&gt;options[<span class="st">'id'</span>]]-&gt;advanced_render(<span class="va">$row</span>)<span class="ot">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="va">$class</span> <span class="op">=</span> <span class="st">&quot;crayon crayon-&quot;</span>theme(<span class="st">'seed_crayon'</span><span class="ot">,</span> <span class="va">$text</span>)<span class="ot">;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Create a span with the class </span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>  <span class="va">$r</span> <span class="op">=</span> <span class="st">&quot;&lt;span class='</span><span class="va">$class</span><span class="st">' style='display:block;height:5px;width:15px;'&gt;&lt;/span&gt;&quot;</span><span class="ot">;</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="va">$r</span><span class="ot">;</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Once this new function is in place you will need to refresh your theme caches
(just hitting “Save” on <code>/admin/build/themes</code> will do the trick). And now your
calendar page should look something like this:</p>
<figure>
<img src="/files/2010/07/litecal-themed-calendar.jpg" alt="The finished calendar" />
<figcaption aria-hidden="true">The finished calendar</figcaption>
</figure>]]></summary>
</entry>
<entry>
    <title>Using Litecal</title>
    <link href="https://passingcuriosity.com/2010/using-litecal/" />
    <id>https://passingcuriosity.com/2010/using-litecal/</id>
    <published>2010-07-05T00:00:00Z</published>
    <updated>2010-07-05T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p><a href="http://code.developmentseed.org/litecal/node/285">litecal</a> is a small Drupal module written by <a href="http://www.developmentseed.org/">Development Seed</a>
to provide a lightweight calendar display for Drupal sites. Like the larger
and more powerful <a href="http://drupal.org/project/calendar">calendar</a> module, <code>litecal</code> is depends on both
the Views and Date API modules. Unlike <code>calendar</code>, <code>litecal</code> is relatively
small and quite easy to understand. The rest of this post will guide you
through installing and using <code>litecal</code> to create a calendar of events on
your Drupal site.</p>
<hr />
<h3 id="installing-litecal">Installing <code>litecal</code></h3>
<p>As mentioned above, <code>litecal</code> has a number of dependancies. You’ll need to
download and install the following modules:</p>
<ol type="1">
<li><a href="http://code.developmentseed.org/litecal/node/285">Litecal</a> itself.</li>
<li><a href="http://drupal.org/project/cck">Content</a> and Text - to store the event data.</li>
<li><a href="http://drupal.org/project/date">Date</a> and Date API - to process and store date data.</li>
<li><a href="http://drupal.org/project/views">Views</a> - to display the calendar.</li>
</ol>
<p>Once you’ve installed the modules you may need to configure them (you’ll need
to have set the site timezone, if nothing else), and then move on to the next
step.</p>
<h3 id="creating-the-node-type">Creating the node type</h3>
<p>Before you can display events on a calendar, you’ll need somewhere to store
them so the first step is creating a new content type.</p>
<figure>
<img src="/files/2010/07/litecal-event-type.jpg" alt="Create an event content type" />
<figcaption aria-hidden="true">Create an event content type</figcaption>
</figure>
<p>Next you’ll need to add a few fields to it. You can store the event name and
description in the <code>title</code> and <code>body</code> fields, but you’ll need to add a new
text field for the location and a new date field for the date. Make sure that:</p>
<ul>
<li>The date field is required (you can’t have an event with no date).</li>
<li>The “to date” is optional.</li>
<li>At least year, month and day are selected under granularity.</li>
</ul>
<p>When you’re done you should have something like the following:</p>
<figure>
<img src="/files/2010/07/litecal-type-fields.jpg" alt="Manage fields on calendar event" />
<figcaption aria-hidden="true">Manage fields on calendar event</figcaption>
</figure>
<p>Now that you’ve got a <em>Calendar Event</em> node type, create a few dummy nodes so
that there’s something to display on the calendar. Four or five should do it,
but make sure that a few are <em>this month</em> and one or two in past or future
months, or your calendar will be a bit empty!</p>
<figure>
<img src="/files/2010/07/litecal-create-nodes.jpg" alt="Create some Calendar Event nodes" />
<figcaption aria-hidden="true">Create some Calendar Event nodes</figcaption>
</figure>
<h3 id="creating-the-view">Creating the view</h3>
<p>Now you need to create a view to display the calendar events in a calendar.
Create a new view for nodes and add the following:</p>
<ol type="1">
<li><p>A filter <code>Node: Type = Calendar Event</code>.</p></li>
<li><p>A <code>Date: Date (node)</code> argument (select the <em>Current date</em> as default
argument, <em>Month</em> granularity, both <em>From</em> and <em>To</em> dates, and <em>OR</em>
method).</p></li>
<li><p>A <code>Content: Date - From date</code> field from your content type, a <code>Content:     Location</code> field, and a <code>Node: Title</code> field.</p></li>
</ol>
<p>Your view should look something like this:</p>
<figure>
<img src="/files/2010/07/litecal-create-view.jpg" alt="Create a view" />
<figcaption aria-hidden="true">Create a view</figcaption>
</figure>
<p>Now add a new <code>Page</code> display to the view, set its <em>Name</em> to <code>Calendar</code>, the
<em>Path</em> to <code>calendar</code>, and override the <em>Style</em> and set it to <code>Litecal</code> (leave
the style options as the default values).</p>
<figure>
<img src="/files/2010/07/litecal-calendar-display.jpg" alt="Add a calendar display" />
<figcaption aria-hidden="true">Add a calendar display</figcaption>
</figure>
<p>Save the view, then select the correct display under <em>Live Preview</em> and you
should see the dummy nodes you created earlier on a calendar of the current
month. If not, then you’ve missed a step above (perhaps the default value or
granularity for the argument?).</p>
<figure>
<img src="/files/2010/07/litecal-preview.jpg" alt="The calendar in live preview" />
<figcaption aria-hidden="true">The calendar in live preview</figcaption>
</figure>
<p>You should also be able to visit <code>/calendar</code> and see the same calendar as a
page:</p>
<figure>
<img src="/files/2010/07/litecal-calendar-page.jpg" alt="The calendar in a page" />
<figcaption aria-hidden="true">The calendar in a page</figcaption>
</figure>
<h3 id="conclusion">Conclusion</h3>
<p>You’ve seen how easy it is to get started with the <code>litecal</code> module. In the
next post, I’m going to introduce a few more sophisticated ways you can use
<code>litecal</code> to build more complete user interface.</p>]]></summary>
</entry>
<entry>
    <title>In Wellington for LCA2010 and DrupalSouth</title>
    <link href="https://passingcuriosity.com/2010/lca2010-and-drupalsouth/" />
    <id>https://passingcuriosity.com/2010/lca2010-and-drupalsouth/</id>
    <published>2010-01-15T00:00:00Z</published>
    <updated>2010-01-15T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>I’m currently in Wellington, New Zealand for <a href="http://www.lca2010.org.nz/">linux.conf.au 2010</a> and
then <a href="http://wellington2010.drupalsouth.net.nz/">DrupalSouth</a>. It’s going to be a pretty awesome week! I’m
looking forward to getting back up to speed with Linux which I’ve used only
superficially for the last few years after switching, on a lark, to FreeBSD
and then to Mac OS X.</p>
<p>I’m looking forward to seeing just how much Linux has changed since I last
built my own kernel (circa 2003).</p>
<p>I’ll be going to the <a href="http://blogs.tucs.org.au/oplm">Open programming languages</a>, <a href="http://multicorenz.wordpress.com/lca2010-miniconf/">Multicore and
Parallel Computing</a>, <a href="http://miniconf.osda.asn.au/">Data Storage &amp; Retrieval</a>, and <a href="http://sysadmin.miniconf.org/">System
Administration</a> miniconfs. Session wise, I intend to look in on most
of the kernel and low-level user space talks that I can.</p>
<p>After LCA per se is done (but during open day, unfortunately) I’ll be at
DrupalSouth to pick up some more Drupal-fu by osmosis.</p>
<p>If you’re interested, you can see more LCA and Drupal specific articles in the
<a href="/lca/">LCA archive</a> and <a href="/drupal/">Drupal archive</a>.</p>]]></summary>
</entry>
<entry>
    <title>Hierarchical Rights in Drupal</title>
    <link href="https://passingcuriosity.com/2009/hierarchical-rights-in-drupal/" />
    <id>https://passingcuriosity.com/2009/hierarchical-rights-in-drupal/</id>
    <published>2009-03-05T00:00:00Z</published>
    <updated>2009-03-05T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>I discovered a blog post called <a href="http://www.garfieldtech.com/blog/hierarchical-acls">More flexible rights
management?</a> by Larry
Garfield at some point over the last three days (that being how long Safari
has been running). Having a few thoughts about it and a pressing need to write
a blog post for today, I’ll get them down “on paper” and call it a job done.
Larry references Markus Wolff and his description (in a post called <a href="http://blog.wolff-hamburg.de/archives/25-A-pragmatic-approach-to-rights-management.html">A
pragmatic approach to rights
management</a>)
of an permissions management system. Markus’ system (he in turn references a
former boss, but I shall ascribe it to him anyway) looks like this:</p>
<ul>
<li><p>Rights are denoted by dot-separated, reverse hierarchical names (e.g:
‘’Application.Component.Subcomponent.Right’’).</p></li>
<li><p>Permissions can specify rights with wild-cards (e.g. ’’Application.*’’).</p></li>
<li><p>Rights can also be negated (e.g. ’‘-Application.Shutdown’’).</p></li>
</ul>
<p>Thus a user who can do anything <em>except</em> shut the application down might have
a permissions list like:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>    <span class="va">$user</span>-&gt;perm <span class="op">=</span> <span class="dt">array</span>(<span class="st">&quot;Application.*&quot;</span><span class="ot">,</span> <span class="st">&quot;-Application.Shutdown&quot;</span>)<span class="ot">;</span></span></code></pre></div>
<p>As such schemes go this one is adequate, but as a replacement for Drupal’s
current system it’s not that crash hot. In fact, all it brings to the table is
a little more convenience: it is no more expressive than the current system.
Now convenience is a pretty cool thing and the Drupal permissions system could
really, <em>really</em>, <strong>really</strong> do with some more convenience, but if there’s to
be a new system, I’d much rather see something genuinely more powerful.</p>
<p>My suggestion is this: rather than have a single hierarchy of rights which
jumbles variously the rights, the objects, and the implementers of both into
one great big messy tree, why not have rights permissions be a tuple of a
right and an object specifier. This will result in two smaller, less
complicated trees the paths of which can be clearly and easily interpreted.
With this scheme, many of the permissions seen on most Drupal sites would be
replaced with a much smaller collection of rights and a similarly small number
of object specifiers.</p>
<p>The current system includes five permissions (create, delete own, delete any,
edit own, and edit any) for each and every content type. In my suggested
system, these would be replaces with just those five rights which would, when
granted, be applied to particular object specifiers. The “edit any story
content” permission might become “(Core.EditAny, Node.Story)”, for example.</p>
<p>One advantage such a scheme would have is in breaking down some of the super
permissions like the various “administer …” permissions. Rather than
creating large numbers of new permissions, it would be possible to grant
“Core.Administer” right to a particular group of settings. Again, this will
reduce the large number of permissions (approaching one per module) and
replace them with a single reusable permission applied to a range of domains.
The “administer menu” permission might be replaced with “(Core.Administer,
Menu)” or, more excitingly, with “(Core.Administer, Menu.PrimaryLinks)”.</p>
<p>Having written a little about this, I’m not entirely sure that it’s a good
idea or a good fit for Drupal. Such a flexible system would certainly have a
smaller UI (in terms of screen real-estate) than the current approach, but it
would be more complex. It would make core more powerful, but it wouldn’t
obviate the need for third-party modules to augment or replace the system when
it can’t implement a required policy. In fact it’s a stupid idea, so forget
about it and lets all just pretend that I didn’t say anything.</p>]]></summary>
</entry>

</feed>
