Allow queries to be altered by other modules

Created on 22 February 2024, 4 months ago
Updated 23 February 2024, 4 months ago

Problem/Motivation

You cannot easily modify queries by other modules.

Our goal is to solve per prefix table problem in Drupal 10 but we think this feature may be useful for other purpose.

Origin

Drupal 10 has deprecated per table prefix. https://www.drupal.org/node/2768219 β†’
There might be a better way to solve this problem but we could not find any workaround in the docs.

Proposed resolution

Fire an event before queries to allow query string changes by other modules.

Usage Example

Declare EventSubscriber on my_module.services.yml:

my_module.alter_legacy_queries:
    class: Drupal\my_module\EventSubscriber\AlterLegacyQueries
    tags:
      - { name: 'event_subscriber' }
    arguments:
      - '@config.factory'

Create the event subscriber:

<?php

namespace Drupal\my_module\EventSubscriber;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\xnttdb\Event\AlterQueryStringEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Alter external entities legacy queries.
 */
class AlterLegacyQueries implements EventSubscriberInterface {

  /**
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  private ConfigFactoryInterface $config;

  /**
   * Constructor.
   */
  public function __construct(ConfigFactoryInterface $config) {

    $this->config = $config;
  }

  /**
   * On External Entity Query
   *
   * @param \Drupal\xnttdb\Event\AlterQueryStringEvent $event
   */
  public function onExternalEntityQueryString(AlterQueryStringEvent $event) : void {

    $legacyTables = $this->config->get('my_module')->get('legacy_table_replacements');
    $query = $event->getQuery();
    foreach ($legacyTables as $key => $name) {
      // Note we are using :table_one on our queries.
      $query = str_replace(':' . $key, $name, $query);
    }
    $event->setQuery($query);
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() : array {

    $events[AlterQueryStringEvent::XNTTDB_ALTER_QUERY_STRING][] = ['onExternalEntityQueryString'];

    return $events;
  }

}

Add relevant config via yml or on each domain settings.php:

$config['my_module']['legacy_table_replacements'] = [
  'table_one' => 'xx_table_one',
  'table_two' => 'xx_table_two',
];

Our case

- We have a backend with complex prefix per domain in Drupal 6 (not same prefix for all tables even on same domain).
- Many strategies may work for this problem (domain config, for example) but we find this one clear and powerful for other use cases

✨ Feature request
Status

Postponed: needs info

Version

1.0

Component

Code

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @anothergasteizone
  • Status changed to Postponed: needs info 4 months ago
  • πŸ‡«πŸ‡·France guignonv

    Sounds fair enough for me. I reviewed your patch (btw thx for the short syntax for list assignment ;-) ) but without testing (I'm missing time for that...).

    Can you confirm that your patch fully solves your problem or does it need more work?
    I ask because the event is not fired before every query issued by xnttdb (2 queries over 5). You may also want to alter all the queries (count/create/update/delete/placeholders/etc. queries)?

    Regarding the "cost" of firing event, I think it's not a big deal in the case of xnttdb compared to the flexibility it can bring. I don't see major security issues there as well since an other installed module is needed to alter queries. I am for the feature you propose, I just need to make sure it is complete before merging (see my previous question). :-)

    As a side note, I'm not sure I completely understand what you are trying to achieve (I used per-table prefixing in D6, D7 and D8) but I hope you also considered just using dbxschema module with an additional module of your own, or maybe create another xntt module that inherits xnttdb and manage queries above xnttdb? For instance, I've also created the "chado light" (chadol) module that hides the complexity of xnttdb SQL queries behind the scene and auto-generates those queries for the user through a user friendly interface (in the case of a Chado database schema which is used in bioinformatics research). Depending on what your goal is, it could be an alternative to consider, if not already. ;-)

Production build 0.69.0 2024