Use Drupal

来源:互联网 发布:微信网络答题系统 编辑:程序博客网 时间:2024/05/21 17:46

Whenever I work with a significant framework or off-the-shelfsoftware, I invariably encounter situations in which I need to do“one-off” programmatic batch tasks outside the normal flow of theapplication.

Of course, you can look at the database structure and manipulatethe data directly in a database client or through your favoriteprogramming language, but this can actually be less convenient (andless safe) then directly using the application’s API whichencapsulates and abstracts away the underlying data structure.

And often we are already familiar with this API anyway as aresult of using the framework or customizing the software.Unfortunately, its not always obvious how to invoke the applicationin an entirely programmatic way to perform these types of tasks.These methods usually exist, but they are often not welldocumented.

Today, I will explore how to do some programmatic manipulationof Drupal (specifically Drupal 6, although this approach is verysimilar in Drupal 5) showing specific examples to get you startedcreating your own scripts.

Invoking Drupal Programmatically

Invoking Drupal programmatically is surprisingly simple, withjust a few lines of code:

<?phprequire_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

The drupal_bootstrap() function can take other constants toload certain parts of Drupal. I usually just fully load Drupal toensure that I have access to the full API and can perform any taskI require.

And because we are the only ones who will see this execute, andwe want to know if anything goes wrong, we may want to set PHP’serror reporting manually by adding this just before thebootstrapping process:

error_reporting(E_ALL);

We now have access to Drupal’s API and can use it to manipulateour Drupal site programmatically.

But before we do anything interesting with this foundation, youmay be wondering how to actually execute this code. The easiest wayis to just create a PHP script in your Drupal root directoryalongside Drupal’s cron.php script, add the code you want, andnavigate to it in your browser. So, if Drupal is installed in asubdirectory called ‘drupal_example’ and we added this code to thea file in that subdirectory called ‘batch_example.php’, we wouldsimply visit this URL to invoke it:

http://www.example.com/drupal_example/batch_example.php

This may seem like an odd way to invoke a batch processingscript, especially if you are coming from another language. But asI said, this is the easiest approach, which pretty much eliminatesany possibility of things like path errors, and it allows you tospit out nicely formatted HTML.

If you really want to invoke this script on the command line, Iwould even suggest that younot do this by calling the PHPbinary, but instead pass the URL to wget, which will have the sameeffect as loading the script in your browser:

wget http://www.example.com/drupal_example/batch_example.php

In fact, this is exactly how you typically invoke the cron.phpDrupal script from your system’s cron, and obviously, we can do thesame with these batch scripts to run periodic scripts that don’tlogically fit into our custom modules, inside ahook_cron()function.

With all that out of the way, lets start actually doingsomething useful.

Querying Drupal, Outputting HTML, Email

As the name suggests, the db_query()method in the Drupal API allows you to send a query to theunderlying database, without having to manage the databaseconnection yourself. You can then usedb_fetch_object()to access the data. For illustration purposes, I am going to use atrivial query that will list the node types that have been createdin the site:

<?phperror_reporting(E_ALL);require_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);$results = db_query('select distinct type as type from node');while ($result = db_fetch_object($results)) {  echo 'A node type: ' . $result->type  . '<br />';}

During the bootstrapping process, Drupal gathers the databaseconnection information from your settings.php file and uses itbehind the scenes to execute the query.

If you want to track something in your site using a query as Idid above, you easily extend this:

<?phperror_reporting(E_ALL);require_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);$results = db_query('select distinct type as type from node')$message = 'This is the current list of node types:\n';while ($result = db_fetch_object($results)) {  $message .= "A node type: " . $result->type  . "\n";}$to='my_email@example.com';$subject="Available Types Report";if (mail($to, $subject, $message)) {  echo 'email sent';} else {  echo 'email not sent';}

Again, this can be triggered periodically by a cron job, callingthe URL of the script with wget.

But this isn’t very interesting yet. Because nodes are thefoundation of Drupal’s approach to managing content, we will mostoften want to get at node objects.

Getting Drupal Node Objects

Before we start doing anything truly useful, we need tounderstand node objects in Drupal.

Continuing with our examples above, where we are just queryingthe underlying data, we can access nodes using thenode_load()function in the Drupal API like so:

<?phperror_reporting(E_ALL);require_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);$results = db_query('select nid from node where type="page"');while ($result = db_fetch_object($results)) {  $node = node_load($result->nid);  echo 'A page title: ' . $node->title . '<br />';  echo 'created on: ' . format_date($node->created) . '<br />';  echo 'changed on: ' . format_date($node->changed, 'custom', 'Y-m-d H:i:s O') . '<br /><br />';}

I simply constructed a query for the nodes I wanted to find, inthis case, pages only, and returned the “nid” or node identifierfield. With this, I can iterate over the results, passing the nidto node_load() to instantiate the basic node object.

Once we have an instantiated node object, say, in a variablecalled “$node” we can access fields like the following that mightbe of interest:

  • $node->nid: the node’s ID.
  • $node->vid: the version ID for the node.
  • $node->type: basically, the content type, suchas a ‘page’ or ‘blog’.
  • $node->uid: the author’s user ID.
  • $node->created: the date the node was created,stored as a UNIX timestamp.
  • $node->changed: the date the node was lastupdated, stored as a UNIX timestamp.
  • $node->title: the title assigned to thenode.
  • $node->body: the entire representation of thenode.
  • $node->content['body']['#value']: the actualvalue assigned to the body.
  • $node->status: whether published/visible (= 1)or unpublished/hidden (= 0).
  • $node->sticky: no(=0) or yes (=1).
  • $node->promote: no(=0) or yes (=1).
  • $node->moderate: no(=0) or yes (=1).
  • $node->comment: disabled (=0), read only (=1).or read/write(=2).
  • $node->format: filtered HTML (=1) or full HTML(=2), and possibly others depending on your configuration.

Notice that in the example above, I used the format_date()function in the Drupal API to convert the date fields to somethinghuman readable. The two examples of format_date() suggest itsflexibility.

Now that we know how to access node fields, we can easily updatethese fields.

Batch Updating Drupal Nodes

Now things are starting to get interesting. Once you have a nodeobject, simple assignment can be used to change its values. In thefollowing example, I will disable commenting on all page nodes in asite:

<?phperror_reporting(E_ALL);require_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);$results = db_query('select nid from node where type="page"');while ($result = db_fetch_object($results)) {  $node = node_load($result->nid);  $node->comment=0;  $node = node_submit($node);  if ($node->validated) {    node_save($node);  } else {    echo 'Node: ' . $node->title . '(' . $node->nid . ') was not saved. <br />';  }}

The call to node_submit()allows installed modules to act on this node before it is saved. Sofor example, the core Drupal node module sets the creation date ofthe node. The $node->validated check makes sure thenode has finished this process successfully, and of course,node_save()actually saves the node back to the database.

Batch Creating Drupal Nodes

As long as Drupal’s machinery has something that looks and actslike a node, it will treat it as a node. So we can simply create ageneric object by callingnew StdClass(), make thenecessary assignments and save it as we did before. In thefollowing example, I will create ten story nodes:

<?phperror_reporting(E_ALL);require_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);function add_new_node($title, $type='page', $status=1, $promote=1, $format=2) {  $node = new StdClass();  $node->type = $type;  $node->status = $status;  $node->promote = $promote;  $node->format = $format;  $node->title = $title;  $node = node_submit($node);  if ($node->validated) {    node_save($node);  }}$story_num=1;while ($story_num < 11) {  add_new_node('Story number: ' . $story_num);  $story_num += 1;} 

To make this easier, I moved the node creation to a functionwith some sensible default arguments that can be overridden asneeded. This function populates a very bare-bones node, and mostlikely you will want to expand on what I’ve provided here.

Batch Deleting Drupal Nodes

As you may have guessed by now, to delete a node, we call thenode_delete()method, passing it a node identifier. So, to clean up the batchcreation script we just ran, let’s delete all story nodes createdwithing the past hour:

<?phperror_reporting(E_ALL);require_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);$hour_ago = time() - (60 * 60); // 60 minutes * 60 seconds$results = db_query('select nid from node where type="story" and created > ' . $hour_ago);while ($result = db_fetch_object($results)) {  node_delete($result->nid);  echo 'Deleted node: ' . $result->nid . '<br />';}

Much More Can Be Done…

I’ve provided a very basic overview of what you can doprogrammatically with the Drupal API, but with this foundation, youcan create more useful scripts.

In a future post, I will show how to work programmatically withCCK defined node fields.

原创粉丝点击