Vanilla 1 Documentation Archive

 
 
vanilla:integration:drupal
Table of Contents

Drupal Integration

The following integration guide was made using Drupal 5.2 and Vanilla 1.1.2 on August 11, 2007. I set about integrating Drupal and Vanilla because although I love the Drupal project and feel that it is working toward being a complete site management system, at the moment, I find that the core forum module is lacking in features. Vanilla is modular (extensible) like Drupal and has a similar clean URL schema, they seem to be born for each other (it is a big surprise that it has taken so long for a working integration to be implemented).

Much of this guide (the structure, and some of the examples) were lifted straight from Mark’s document vanilla:integration:wordpress

File Integration

I was developing this for a site which will go live in a few months, but have used a generic naming convention for the sake of this integration document.

I installed Drupal (5.2) to the root of my website:

/path/to/root/

I then unzipped Vanilla (1.1.2) into a sub-directory called “Vanilla-1.1.2”, like so:

/path/to/root/Vanilla-1.1.2/

Database Integration

Installation

After installing Drupal to the root, I then set about running the installer for Vanilla. This is done in the normal way, though, make sure you use the same database as your Drupal install, you want the Vanilla and Drupal database tables to be in the same Database.

One thing to note, is that during the Vanilla install, you will be asked for administrator username and passwords. You can enter anything during this install, as eventually we will be dropping the Vanilla user table in favour of the Drupal one.

Merging Databases

Next step is to make sure that both of our Databases are merged, we will start with the users tables. Mark built Vanilla so that it does not directly reference any database tables (it uses configuration files to map them to variables), so this first step is quite simple.

Open the following file for viewing:

/path/to/root/Vanilla-1.1.2/appg/database.php

It is a list of all of the database tables that are mapped (at the top) into an array, and (more substantially) all of the columns that are mapped thereafter.

Note that we do not want to edit this file. We shall use it as a template by copying all the fields we want to alter into a file under the Vanilla conf(iguration) directory also called database.php:

/path/to/root/Vanilla-1.1.2/conf/database.php

After a fresh install my /path/to/root/Vanilla-1.1.2/conf/database.php looked like this:

<?php
// Database Configuration Settings
$Configuration['DATABASE_HOST'] = 'localhost';
$Configuration['DATABASE_NAME'] = 'drupal';
$Configuration['DATABASE_USER'] = 'mysql_user';
$Configuration['DATABASE_PASSWORD'] = 'mysql_password';
?>

I will start by re-referencing the Users table to our Drupal one:

<?php
// Database Configuration Settings
$Configuration['DATABASE_HOST'] = 'localhost';
$Configuration['DATABASE_NAME'] = 'drupal';
$Configuration['DATABASE_USER'] = 'mysql_user';
$Configuration['DATABASE_PASSWORD'] = 'mysql_password';
 
/* Drupal Integration */
 
// Map Vanilla to Drupal's user table
$DatabaseTables['User'] = 'users';
?>

Now I need to map the rest of the user columns

?php
// Database Configuration Settings
$Configuration['DATABASE_HOST'] = 'localhost';
$Configuration['DATABASE_NAME'] = 'drupal';
$Configuration['DATABASE_USER'] = 'mysql_user';
$Configuration['DATABASE_PASSWORD'] = 'mysql_password';
 
/* Drupal Integration */
 
// Map Vanilla to Drupal's user table
$DatabaseTables['User'] = 'users';
 
// Map existing Drupal columns to Vanilla
$DatabaseColumns['User']['UserID'] = 'uid';
$DatabaseColumns['User']['Name'] = 'name';
$DatabaseColumns['User']['Password'] = 'pass';
$DatabaseColumns['User']['Email'] = 'mail';
$DatabaseColumns['User']['DateFirstVisit'] = 'created';
 
$DatabaseColumns['User']['Icon'] = 'picture';
 
// Finish the rest of the columns
$DatabaseColumns['User']['user_nicename'] = 'user_nicename';
$DatabaseColumns['User']['user_url'] = 'user_url';
$DatabaseColumns['User']['user_activation_key'] = 'user_activation_key';
$DatabaseColumns['User']['user_status'] = 'user_status';
$DatabaseColumns['User']['display_name'] = 'display_name';
?>

Finally, we need to Drupal’s sessions table, your final product should end up looking something like this:

?php
// Database Configuration Settings
$Configuration['DATABASE_HOST'] = 'localhost';
$Configuration['DATABASE_NAME'] = 'drupal';
$Configuration['DATABASE_USER'] = 'mysql_user';
$Configuration['DATABASE_PASSWORD'] = 'mysql_password';
 
/* Drupal Integration */
 
// Map Vanilla to Drupal's user table
$DatabaseTables['User'] = 'users';
 
// Map existing Drupal columns to Vanilla
$DatabaseColumns['User']['UserID'] = 'uid';
$DatabaseColumns['User']['Name'] = 'name';
$DatabaseColumns['User']['Password'] = 'pass';
$DatabaseColumns['User']['Email'] = 'mail';
$DatabaseColumns['User']['DateFirstVisit'] = 'created';
 
$DatabaseColumns['User']['Icon'] = 'picture';
 
// Finish the rest of the columns
$DatabaseColumns['User']['user_nicename'] = 'user_nicename';
$DatabaseColumns['User']['user_url'] = 'user_url';
$DatabaseColumns['User']['user_activation_key'] = 'user_activation_key';
$DatabaseColumns['User']['user_status'] = 'user_status';
$DatabaseColumns['User']['display_name'] = 'display_name';
 
// Map Vanilla to Drupal's sessions table
$DatabaseTables['Sessions'] = 'sessions';
 
// and the columns
$DatabaseColumns['Sessions']['UserID'] = 'uid';
$DatabaseColumns['Sessions']['SessionID'] = 'sid';
?>

Now we actually need to place the Vanilla user table fields that don’t exist into the Drupal’s users table:

ALTER TABLE users
  ADD `RoleID` int(2) NOT NULL DEFAULT '3',
  ADD `StyleID` int(3) NOT NULL DEFAULT '1',
  ADD `CustomStyle` varchar(255) DEFAULT NULL,
  ADD `FirstName` varchar(50) NOT NULL DEFAULT '',
  ADD `LastName` varchar(50) NOT NULL DEFAULT '',
  ADD `VerificationKey` varchar(50) NOT NULL DEFAULT '',
  ADD `EmailVerificationKey` varchar(50) DEFAULT NULL,
  ADD `Email` varchar(200) NOT NULL DEFAULT '',
  ADD `UtilizeEmail` enum('1','0') NOT NULL DEFAULT '0',
  ADD `ShowName` enum('1','0') NOT NULL DEFAULT '1',
  ADD `Icon` varchar(255) DEFAULT NULL,
  ADD `Attributes` text NULL,
  ADD `CountVisit` int(8) NOT NULL DEFAULT '0',
  ADD `CountDiscussions` int(8) NOT NULL DEFAULT '0',
  ADD `CountComments` int(8) NOT NULL DEFAULT '0',
  ADD `DateLastActive` datetime NOT NULL DEFAULT '2006-06-06 00:00:00',
  ADD `RemoteIp` varchar(100) NOT NULL DEFAULT '',
  ADD `LastDiscussionPost` datetime DEFAULT NULL,
  ADD `DiscussionSpamCheck` int(11) NOT NULL DEFAULT '0',
  ADD `LastCommentPost` datetime DEFAULT NULL,
  ADD `CommentSpamCheck` int(11) NOT NULL DEFAULT '0',
  ADD `UserBlocksCategories` enum('1','0') NOT NULL DEFAULT '0',
  ADD `DefaultFormatType` varchar(20) DEFAULT NULL,
  ADD `Discovery` text,
  ADD `Preferences` text,
  ADD `SendNewApplicantNotifications` enum('1','0') NOT NULL DEFAULT '0';

One thing to take note of is the second line of my query:

ADD `RoleID` int(2) NOT NULL DEFAULT '3',

Notice that I gave it a default of 3? That is because the “member” RoleID in Vanilla is 3. This will make it so that new users added by the Drupal “create a new user” form will automatically be added to the member role on the forum.

Integrating Authentication

Now we come to the crux of this document. What you wanted to do, was get your installs talking to each other, you wanted to have one log in, for both of your installs (you wouldn’t be here if you didn’t). Vanilla makes this fairly simple, it provides a set of modules for handling “people” (as it likes to call users) and, more importantly, it has one specifically for authenticating users, which I have altered to serve our means.

Before we make a new Authenticator, we need to add set some configuration variables about our Drupal install in the following file:

/path/to/root/Vanilla-1.1.2/conf/settings.php

Add to the bottom:

// Drupal Configuration
$Configuration['DRUPAL_PATH'] = '/path/to/root/';
$configuration['DRUPAL_SITE'] = 'default';

(DRUPAL_SITE has a default of “default” so unless you know otherwise, you shouldn’t need to change it)

What the following file will do for you. It will provide you the means to log in with Drupal and for your session to persist over to Vanilla. What the following document will not do for you. It will not provide you with the means to log in using Vanilla what so ever. This is a one way street, once you have it installed and working, it is suggested that you remove your people.php file from the root and remove all reference to it in your Vanilla theme (I am writing an extension to provide a Drupal-esque login form for Vanilla, which may be of use to you).

The default Vanilla Authenticator can be found at:

/path/to/root/Vanilla-1.1.2/library/People/People.Class.Authenticator.php

I then made a copy of it to:

/path/to/root/Vanilla-1.1.2/library/People/People.Class.DrupalAuthenticator.php

I can then alter it so that it can:

After some fiddling about, and a couple of stray Drupal integration documents (unrelated to Vanilla) around the net (which I will soon dig the links out from my history to) I managed to knock up this:

<?php
/*
* Copyright 2003 Mark O'Sullivan
* This file is part of People: The Lussumo User Management System.
* Lussumo's Software Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
* Lussumo's Software Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with Vanilla; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
* The latest source code is available at www.lussumo.com
* Contact Mark O'Sullivan at mark [at] lussumo [dot] com
* 
* Description: Drupal authentication interface. Written in part by Adam Dunkley (adam [at] webality [dot] co [dot] uk).
* Applications utilizing this file: Vanilla;
*/
class Authenticator {
   var $Context;
 
   
   function Authenticator(&$Context) {   
      $this->Context = &$Context;
   }
   
   function GetIdentity() {
  
      if (!session_id()) {
         session_set_cookie_params(0, $this->Context->Configuration['COOKIE_PATH'], $this->Context->Configuration['COOKIE_DOMAIN']);
         session_start();
      }
	
      // We have a guest till proven a member
      $UserID = 0;
 
		 
      /* Get Info From Drupal Install */
		
      // We need to switch off error_reporting temporarily to 
      // stop complaints from settings.php's use of ini_set
      $ini = ini_get("error_reporting");
      ini_set("error_reporting", 0);
 
      // Include the Drupal settings
      include($this->Context->Configuration['DRUPAL_PATH'].'sites/'.$this->Context->Configuration['DRUPAL_SITE'].'settings.php');
 
      ini_set("error_reporting", $ini);
      
      $SessKey = 'PHPSESSID';
      
      foreach ($_COOKIE as $Key => $Value) {
      	if(substr_count(ltrim($Key, 'SESS'), 'SESS') != 1 && substr_count($Key, 'SESS') == 1) {
      		$SessKey = $Key;
      	}
      }
 
      // Let's find our session in the DB (remember, you need to alter the core to stop it from
      // trying to force a prefix onto Drupal's "sessions" table)
      $s = $this->Context->ObjectFactory->NewContextObject($this->Context, 'SqlBuilder');
      $s->SetMainTable('User', 'u');
      $s->AddJoin('Sessions', 's', 'UserID', 'u', 'UserID', 'inner join', null, 's');
      $s->AddSelect('UserID', 'u');
      $s->AddWhere('s', 'SessionID', '', FormatStringForDatabaseInput($_COOKIE[$SessKey]), '=');
 
      $Result = $this->Context->Database->Select($s,
         'Authenticator',
         'GetIdentity',
         'An error occurred while attempting to validate your remember me credentials');
	
      if ($Result) {
 
         while ($rows = $this->Context->Database->GetRow($Result)) {
            $UserID = ForceInt($rows['UserID'], 0);
         }
 
         if ($UserID > 0) {
 
            // 1. Update the user's information
            $this->UpdateLastVisit($UserID);
			  
            // 2. Log the user's IP address
            $this->LogIp($UserID);
         }
 
      }
			 
      // If it has now been found, set up the session.
      $this->AssignSessionUserID($UserID);
      return $UserID;
   }
	
   // All methods below this point are specific to this authenticator and
   // should not be treated as interface methods. The only required interface
   // properties and methods appear above.
   
   function AssignSessionUserID($UserID) {
      if ($UserID > 0) {
         @$_SESSION[$this->Context->Configuration['SESSION_USER_IDENTIFIER']] = $UserID;
      }
   }
	
   function LogIp($UserID) {
      if ($this->Context->Configuration['LOG_ALL_IPS']) {
         $s = $this->Context->ObjectFactory->NewContextObject($this->Context, 'SqlBuilder');
         $s->SetMainTable('IpHistory', 'i');
         $s->AddFieldNameValue('UserID', $UserID);
         $s->AddFieldNameValue('RemoteIp', GetRemoteIp(1));
         $s->AddFieldNameValue('DateLogged', MysqlDateTime());
 
         $this->Context->Database->Insert($s,
            'Authenticator',
            'LogIp',
            'An error occurred while logging your IP address.',
            false); // fail silently
      }
   }
	
   function SetCookieCredentials($CookieUserID, $VerificationKey) {
      // Note: 2592000 is 60*60*24*30 or 30 days
      setcookie($this->Context->Configuration['COOKIE_USER_KEY'],
         $CookieUserID,
         time()+2592000,
         $this->Context->Configuration['COOKIE_PATH'],
         $this->Context->Configuration['COOKIE_DOMAIN']);
      setcookie($this->Context->Configuration['COOKIE_VERIFICATION_KEY'],
         $VerificationKey,
         time()+2592000,
         $this->Context->Configuration['COOKIE_PATH'],
         $this->Context->Configuration['COOKIE_DOMAIN']);
   }
	
   function UpdateLastVisit($UserID, $VerificationKey = '') {
      $s = $this->Context->ObjectFactory->NewContextObject($this->Context, 'SqlBuilder');
      $s->SetMainTable('User', 'u');
      $s->AddFieldNameValue('DateLastActive', MysqlDateTime());
      if ($VerificationKey != '') $s->AddFieldNameValue('VerificationKey', $VerificationKey);
      $s->AddFieldNameValue('CountVisit', 'CountVisit + 1', 0);
      $s->AddWhere('u', 'UserID', '', $UserID, '=');
 
      $this->Context->Database->Update($s,
         'Authenticator',
         'UpdateLastVisit',
         'An error occurred while updating your profile.',
         false); // fail silently
   }
   
   function Authenticate() { 
      return 1;
   }
   
   function DeAuthenticate() {
      return 1;
   }
}
?>

It is quite basic, but it suffices at getting us logged in. But not without one alteration to the core (dun dun duunnn).

There was one problem that I encountered with the creation of this script. Which is that I needed (or felt I needed) to use SqlBuilder (there is probably a way to query the database directly which will avoid this hack) to query the sessions table of Drupal which we mapped earlier. The only problem is, is that Vanilla demands that all database tables be given a prefix (LUM_ by default) unless they are the User table (which is why we didn’t have to do anything crazy with that table). So I altered the following file:

/path/to/root/Vanilla-1.1.2/library/Framework/Framework.Functions.php

From:

523 function GetTableName($Key, &$TableCollection, $Prefix) {
524 	if ($Key == "User") {
525		return $TableCollection[$Key];
526	} else {
527		return $Prefix.$TableCollection[$Key];
528	}
529 }

To:

523 function GetTableName($Key, &$TableCollection, $Prefix) {
524    if ($Key == "User" || $Key == "Sessions") {
525       return $TableCollection[$Key];
526    } else {
527       return $Prefix.$TableCollection[$Key];
528    }
529 }

The check that stops it appending the table prefix to the User table now applies to the Sessions table too.

Now all you need to do, is to switch this Authenticator on, by editing the following file:

/path/to/root/Vanilla-1.1.2/conf/settings.php

and adding to the end (below the other Drupal Configuration variables):

$Configuration['AUTHENTICATION_MODULE'] = 'People/People.Class.DrupalAuthenticator.php';

Et Voila. Try logging into Drupal and seeing if it works.

Administrator Account

You will now find that you no longer have administrator privileges for Vanilla. So let us rectify that. Assuming that your Drupal user ID is 1 (though you may want to check this), you just need to run the following query on your database to give yourself Administrator rights:

UPDATE users SET RoleID = 4 WHERE uid = 1;

Now you should find that you have your admin rights for Vanilla back.

Conclusion

There have been a few headaches on the way (and probable a few glitches that I haven’t seen since completing it this morning), but the Drupal/Vanilla (Drupilla as I like to call it) integration works very well indeed. I have made substantial theme changes to my Vanilla install to make it look and act in a similar way to Drupal (which I will extend upon another time), and am in the process of writing a set of extensions that tighten the integration of the two even further.

Watch this space.

 
 
 
 
vanilla/integration/drupal.txt · Last modified: 2009/03/28 14:19
Vanilla 1 Documentation archive (Wiki by DokuWiki)