Pages

Tuesday, February 16, 2016

Arbitrary "OR" SQL Queries

I was working on a Drupal migration project today using the Migrate module where I needed to import only select user roles from the source (Drupal 6) database.
The Migrate module allows for a custom query to select only the user roles that need to be imported. In my case, the two roles I wanted to import had role IDs of 4 and 6. So, how do I write a query using the Drupal Database API to do this? Turns out there's a pretty elegant answer. Rather than writing something like:
SELECT * FROM role r WHERE rid=4 OR rid=6;
The proper way of writing the select query is:
$query = parent::query();
$ored = db_or();
$ored
->condition('rid', 4)
->condition('rid', 6);
$query->condition($ored);

Note the elegant "db_or()" function that returns a DatabaseCondition object. Add the two conditions to this object, and they're automagically "or"ed.

Drush Lock: Freeze the version of a Module during 'drush up'

Every so often I will find myself needing to update lots of Drupal modules but not one in particular. Perhaps I have patched the module, or perhaps there is a new version of the theme that I know will break my site layout.
Drush can save you from this dilemma, as of version 4.x - yes, it's true!
Just use:
drush up --lock=omega
Assuming Omega is the project that needs to keep the same version number. Omega will not be updated until you reverse the lock.
drush up --unlock=omega
You can also just:
drush up omega
If you want to.

Where did the catpath and termpath tokens go in pathauto?

In the old days of web design, we had to put all of our files in folders, so having a path like example.com/category/sweaters/cashmere/winter-special.html was really common. You could also remove any part of the path and be sure you would get an index page, such as example.com/category/sweaters/index.html.
In a front-controller CMS like Drupal, all the paths are arbitrary, so a hierarchical folder structure has to be faked with URL Aliases. Luckily the community maintains two modules to round out this functionality in Token and Pathauto, along with the excellent Entity API module and the Entity Tokens that comes bundled with it. However, Tokens were completely (and necessarily) rewritten from Drupal 6 to Drupal 7, and some of the cool things you could do with pathauto to emulate old-school folder structures became less transparent.
After a few minutes of searching the issue queue, lo and behold, a replacement for Drupal 6's "catpath" token:
category/[term:parent:url:path]/[term:name]
If your taxonomy is properly arranged in a hierarchy, this acts as a recursive loop to generate the terms that should be properly nested. That means that example.com/sweaters/cashmere/ should show you all the nodes tagged with cashmere, and likewise for example.com/sweaters.
OK, but what about the nodes? No problem there either:
category/[node:category:url:path]/[node:title]
Again, this creates a recursive loop where the path of the node depends on the path of the term, and that depends on its parent terms. (if you'd like to add .html to the end, that is fine too).
The pattern is different depending on the name of your vocabulary. In a site upgraded from Drupal 6, the word "category" will be replaced by a vocabulary ID.
category/[node:taxonomy-vocabulary-2:url:path]/[node:title]
if your field has multiple values you may need to address the term with a delta:
category/[node:taxonomy-vocabulary-2:0:url:path]/[node:title]
Last but not least, if you want absolute control over which term is used you may also want to check out Dave Ried's Taxonomy Entity Index module.
BTW I never used to like putting "category" in front of my URL aliases, but there is a good round up of some security holes you may open by not putting some static text in front of pathauto patterns: Pathauto Patterns that can be Dangerous

Drupal Text Formats and Content for Test Nodes

When building a Drupal-based website or theme, you will invariably create some test nodes of a content type that has at least one text area field. You should then add some example text, to see how those fields will look on the website. But beyond those nodes focused on styling, you may find it necessary or advisable to create a large number of additional test nodes of that content type. When you begin this process, you may wonder whether it would be best to add placeholder text (such as the venerable "Lorem ipsum") or leave those fields empty. Also, are there any ramifications of choosing one text format or another?
If a text area contains no content, then no text format is associated with that particular node's text area, and changes to the text format setting (made through the user interface) are not retained. However, if placeholder text is added to the field, then users who do not have permission for the chosen text format, will naturally not be able to edit the text. Consequently, you or someone else would be forced to change the text formats on all of the problematic nodes — manually or with database commands. On the other hand, if you leave those text areas empty, then those users can add whatever text they want, and specify any of the text formats for which they have permissions.