I have tried downloading domain (access) 7.x-2.5 and 7.x-3.x-dev.

To run against both but they both fail.

7.x-2.5 I get this error.

Recoverable fatal error: Argument 2 passed to db_query() must be an array, string given, called in /var/www/shopping/sites/all/modules/domain/domain_prefix/domain_prefix.module on line 41 and defined in db_query() (line 2220 of /var/www/shopping/includes/database/database.inc).

7.x-3.x-dev - it complains that the prefix table exists...

I need for instance the drupal commerce tables to exist separately per domain, I assume this module is doing this, from what I could figure out.

CommentFileSizeAuthor
#14 d7-port-981684-5297652.patch20.06 KBaskibinski

Comments

agentrickard’s picture

Title: What do I need to get this working? » Upgrade module to Drupal 7
Category: support » task

Domain Prefix has not been ported to D7 and will not work at all. You might try using the Coder module to upgrade it.

The module really needs a new maintainer for D7. It is not on my radar right now.

kultmarke’s picture

subscribe

mindgame’s picture

subscribe

agentrickard’s picture

To be clear. This was removed from the main module for D7 because I never actually use it. I originally wrote it as a proof-of-concept.

tebb’s picture

Subscribe.

sepph’s picture

I've had a look at porting Domain Prefix to D7. I could really do with it for a upcoming project as a way to avoid clashes with same named paths.

I've made some progress with it. I have it working with the Domain Access module and it's correctly re-creating any selected DB tables when set on the /admin/structure/domain/prefix page.

I'm using it to create a prefixed version of the 'url_alias' table for each domain.

I've run in to a couple of issues I can't seem to work around...

Within domain_prefix_domain_bootstrap_full I've changed the code to set the DB prefix settings using the global $databases var as the $db_prefix global no longer exists. The problem is that these prefix settings never seem to be used over the defaults set in the settings.php.

Is it possible to override the prefix settings in the $databases global??? This looks like it'll be key to getting the module to work.

The other issue I'm having is that any hook_domainpath hooks only seem to be firing on /admin/structure/domain. The documentation for this hook suggests that this will fire for all paths. The docs also mention Domain Prefix as an example of best practices implementation which I'm guessing should be removed.

agentrickard’s picture

Have you tried http://drupal.org/project/domain_path ? It is preferred if you just want to prefix url aliases.

See #1100732: domain_url_rewrite_outbound_alter() might not fire hook_domainpath() for the hook_domainpath() issue.

The docs issue is also separate and should be removed for D7.

I don't know about $databases. It should work. It's a global.

sepph’s picture

I feel a bit stupid! I'd looked at the domain_path module and was convinced that it was just forwarding from the manually set domain path to the pathauto path i.e. www.site2.blah/about-us was forwarding to www.site2.blah/about-us-0 as www.site1.blah/about-us already existed. Turns out it does exactly what I want.

Regarding the $databases global. It looks as though the database connection might be cached on bootstrap as it never uses the altered prefix settings set via the domain_bootstrap_full. If I set the prefix details in settings.php as a test it does use them.

Anyway domain_path should be all I'll need for now.

Thanks for your response.

agentrickard’s picture

domain_bootstrap_full() should load during settings.php to change those values. Might be a function registry issue.

rudiedirkx’s picture

It seems you can't save prefix settings in the database, because when you create a database object, you can't change the settings anymore (the global $databases isn't used anymore after that).

And for some mystyrious (undoubtedly 'correct') reason, all useful DatabaseConnection properties are protected, so you can't change them during runtime.

Not only would the settings load during settings.php, they should be in settings.php, well before any database connection is created, Which is a problem, because the domain => domain id map is only in the database.

Nice, this new database wrapper. Very protected.

agentrickard’s picture

The new database layer should still respect the table mapping provided in the $databases global.

rudiedirkx’s picture

It does, but you can't change it after the db instances have been made (after the first query). The DBAL doesn't consult the global $databases after it's been created. Only then.

I still don't see this happening, but I might be missing something.

askibinski’s picture

Here is a first D7 patch against the dev in git. (also credits to @rudie)

Basically, the critical issue is the one @rudie describes at #10.
This boils down to around line 53 of domain_prefix.module.
Maybe somebody knows how to 'reinitialize' the $databases at that point?

Others which need work/testing (maybe these need to be split up in seperate issues)

  • domain_prefix_insert_data is broken because I didn't know howto get db_last_insert_id in D7 for that query.
  • domain_prefix.path.inc needs testing (when url_alias table is prefixed)
askibinski’s picture

Status: Active » Needs work
StatusFileSize
new20.06 KB

Forgot attaching the patch (apparantly you can't add an attachment when you edit a comment)

agentrickard’s picture

Domain path prefixing is largely deprecated in favor of Domain Path module, so I would drop support for it.

If anyone wants commit access, let me know.

rudiedirkx’s picture

But they're two entirely different things... I want to prefix my menu tables, so I can have different menu's on different domains. I'm not looking into url aliases/paths at all.

How do you suggest I specify menu's per domain without domain specific table prefixing? With the Domain Path module? I don't follow.

askibinski’s picture

@rudie I believe what @agentrickard at #15 means, is that support for domain_prefix.path.inc can be dropped in favor of domain_path module. It doesn't reflect on the other issues at #13.

Right?

agentrickard’s picture

Yes. I only mean domain_prefix.path.inc should not be a blocker, unless people need to migrate data from d6 to d7, and there is an issue open for that somewhere (likely in Domain Path.)

agentrickard’s picture

askibinski’s picture

Okay, so path.inc can be removed in favor of Domain Path.

That leaves us with the main problem described in #13.
Does anybody know about any function in http://api.drupal.org/api/drupal/includes--database--database.inc/7
that can 'reinitialize' the $databases array at runtime?

agentrickard’s picture

In the d6 version, we simply overrode that global value in settings.php using hook_domain_boostrap_full(), which lets you set the $databases array before Drupal runs any queries.

I don't see why that wouldn't work now. The only difference, AFAIK, is the _structure_ of the variable in D7.

rudiedirkx’s picture

In D6, the $databases variable is changed after the first query, because only the database knows which tables to 'override'/prefix. It works like that for D7 too.

D6 didn't have a Database and DatabaseConnection object that can't be changed after init. D7 does. I might be wrong... I don't think I am =)

agentrickard’s picture

What I'm saying is that you do this in D6:

 * To provide prefixes for specific tables, set $db_prefix as an array.
 * The array's keys are the table names and the values are the prefixes.
 * The 'default' element holds the prefix for any tables not specified
 * elsewhere in the array. Example:
 *
 *   $db_prefix = array(
 *     'default'   => 'main_',
 *     'users'     => 'shared_',
 *     'sessions'  => 'shared_',
 *     'role'      => 'shared_',
 *     'authmap'   => 'shared_',
 *   );

And the same syntax is still supported in D7.

 * For a single database configuration, the following is sufficient:
 * @code
 * $databases['default']['default'] = array(
 *   'driver' => 'mysql',
 *   'database' => 'databasename',
 *   'username' => 'username',
 *   'password' => 'password',
 *   'host' => 'localhost',
 *   'prefix' => 'main_',
 *   'collation' => 'utf8_general_ci',
 * );
 * @endcode
 *
 * You can optionally set prefixes for some or all database table names
 * by using the 'prefix' setting. If a prefix is specified, the table
 * name will be prepended with its value. Be sure to use valid database
 * characters only, usually alphanumeric and underscore. If no prefixes
 * are desired, leave it as an empty string ''.
 *
 * To have all database names prefixed, set 'prefix' as a string:
 * @code
 *   'prefix' => 'main_',
 * @endcode
 * To provide prefixes for specific tables, set 'prefix' as an array.
 * The array's keys are the table names and the values are the prefixes.
 * The 'default' element is mandatory and holds the prefix for any tables
 * not specified elsewhere in the array. Example:
 * @code
 *   'prefix' => array(
 *     'default'   => 'main_',
 *     'users'     => 'shared_',
 *     'sessions'  => 'shared_',
 *     'role'      => 'shared_',
 *     'authmap'   => 'shared_',
 *   ),
 * @endcode

I have no idea what you are talking about wrt connections. They should respect the values set here. All Domain Prefix does is introduce a dynamic way to load the prefix values.

rudiedirkx’s picture

And the only way to do that, is alter the existing connection object, because the $databases global is never used after the first database connection is made.

And this is the only way to reinit prefixes:


function domain_prefix_domain_bootstrap_full($domain) {
  $prefix = _domain_prefix_table_prefix($domain);

  // Now load the dynamic tables.
  $tables = array();
  $result = db_query("SELECT tablename FROM {domain_prefix} WHERE domain_id = :did AND status > 1", array(':did' => $domain['domain_id']));
  foreach ($result as $data) {
    $tables[] = $data->tablename;
  }

  if ( $tables ) {
    global $databases;

    $prefixes = isset($databases['default']['default']['prefix']) ? $databases['default']['default']['prefix'] : array('default' => '');
    is_array($prefixes) or $prefixes = array('default' => $prefixes);
    $preprefix = $prefixes['default'];

    foreach ($tables as $table) {
      $prefixes[$table] = $preprefix . $prefix;
    }

    $databases['default']['default']['prefix'] = $prefixes;

    $db = Database::getConnection('default', 'default'); // typeof DatabaseConnection
    $db->__construct($databases['default']['default']); // OMG REALLY??
//print_r($db);
  }

  // This function may already be loaded, see d.o/929540.
  if ( !function_exists('domain_prefix_domainpath') ) {
    // Check for prefixes of the url_alias table, and if present add hook_domainprefix().
    $count = db_query("SELECT COUNT(*) FROM {domain_prefix} WHERE status > 1 AND tablename = 'url_alias'")->fetchField();
    if ( $count ) {
      include 'domain_prefix.path.inc';
    }
  }
}

The __construct is necessary, because it calls the protected setPrefix method. It's horrible, but it works.

agentrickard’s picture

So the problem here simply the sequence in which the connections are initialized? That would make sense, and in that case re-defining the connection would seem to be the only answer.

The problem is caused because we have to bootstrap the db before loading this sequence, of course, so we initialize the connection with the default (un-prefixed) settings.

I misunderstood the problem you were trying to describe.

rudiedirkx’s picture

Do you have a better solution? (Maybe you have a closer relationshop with Drupal's DBAL.) I really don't like calling __construct manually. I also think it's not good for PDO, because PDO's constructor is executed twice as well. (And I have no idea what that does exactly.)

agentrickard’s picture

I do not have a better solution. Best to ask Crell in IRC if you can catch him.

adrift73’s picture

We use Domain Prefix on a large global website to separate menus, blocks and redirects. This is a major issue for our upgrade to D7.
Has anyone figured out better solution than the one based on __construct?

robertoguzman’s picture

Any progress porting this module to drupal 7 ?

rudiedirkx’s picture

I don't use it anymore. Pretty much anything is better than domain specific tables. I was using it for menus & items and that was a fiasco. Now I just create a menu per domain with domain_menu (sandbox).

agentrickard’s picture

@rudiedirkx Domain Menu Block does something similar, btw.

https://drupal.org/project/domain_menu_block

Not only will it give you one menu per domain, but a single block for placement.

rudiedirkx’s picture

Ah damnit, now he tells me! =) Yeah, that's even better...

segi’s picture

Assigned: Unassigned » segi

I try to port this module for D7.

segi’s picture

I think I found the solution for the main problem, how we modify the database connection info in "runtime".
I take the runtime between double quotes, because actually I stop the active connection and generate a new.

Here is my code piece:

<?php
  Database::closeConnection();
  Database::addConnectionInfo('domain_prefix_' . $counter, 'default', $databases['default']['default']);
  Database::setActiveConnection('domain_prefix_' . $counter); 
?>

It is works to me.

rudiedirkx’s picture

That's probably worse than re-executing __construct, since PDO is probably smart enough to know it doesn't need to reconnect, and only executes the code. You always do a reconnect, which is probably very inefficient. Definitely if it creates a new socket. Definitely if you're not connecting to localhost.

geek-merlin’s picture

Issue summary: View changes

@segi: did you have any success?

segi’s picture

Assigned: segi » Unassigned
gaijinu’s picture

Same question guys: any progress with the upgrade? Does anyone has a working version? I'm using the module to prefix Ubercart tables for a multisite installation. It works perfectly in D6.
Now we have to upgrade the websites to D7 and this is the only module that doesn't have a D7 port. I understand it was just a proof of concept, but it works beautifully. Any chance someone would be interested in upgrading this module to 7?
Thanks