-
-
Notifications
You must be signed in to change notification settings - Fork 828
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dispatch hook to allow modifying API4 SQL #32466
Conversation
🤖 Thank you for contributing to CiviCRM! ❤️ We will need to test and review this PR. 👷 Introduction for new contributors...
Quick links for reviewers...
|
Interesting idea @braders. Some thoughts in no particular order:
public static function renderWpFieldSql(array $field): string {
if (... wordpress database is different) {
return "`$wpDatabaseName`.{$field['sql_name']}";
}
return $field['sql_name'];
} |
Thanks @colemanw. Good spot on the Adding the database name to
Because the backticks wrap
I don't think using For context, this is the code I'm current using to test the new hook I'm suggesting:
|
I agree with Coleman that this is an interesting idea but I wonder if it should be more that rather than operating on the generated SQL that the hook dispatches the Api4Query class instead Then the listener could do like $query->getWhere() and loop through and call like $query->setWhere or something like that sort of pattern. In this it would be a bit closer to how Drupal Views is modified by civicrm entity to deal with having civicrm tables in a separate schema https://github.com/eileenmcnaughton/civicrm_entity/blob/4.0.x/src/Hook/QueryHooks.php#L27 |
@braders ok I see what you're talking about now with the joins. I also get where you're coming from wrt adding a "quick fix" sort of hook that gets the job done without much fuss up front. However, we've been burned in the past by adding these sorts of overly-simplistic hooks that expose deeply internal functions. For example, our dedupe code is a right mess due to the sql queries all being exposed to hooks, which makes improving the queries nearly impossible as hooks out there in the wild could be doing literally anything and there's no way to know what changes would break them IMO what's needed is for Api4 to understand which database each table belongs to, so it can properly prefix each one. |
Overview
Dispatch hook to allow modifying API4 SQL.
Before
Any API4 request gets boiled down to a SQL query, based on the fields being selected, joined, updated etc. Extension authors have little opportunity to modify this final SQL, which is needed for a small number of advanced use-cases.
After
A hook
civi.api4.generatedSql
has been introduced (Question: is there a better name for this?). The SQL query is passed in by reference, allowing it to be edited.Comments
You might be wondering why I'd want this...
I've been experimenting with making WordPress tables available through API4/ SearchKit/ FormBuilder (in theory the same would be possible with Drupal or Joomla too). This leads to some really interesting use-cases. For example, here I've added a tab to the contact screen, showing WordPress usermetadata associated with the contact's user (via joining

uf_match
):There are any number of use-cases this unblocks. For example, showing WooCommerce orders, WordPress comments or Caldera Forms submissions against a CiviCRM contact summary, creating reports combining WooCommerce income with CiviCRM contribution income etc.
The catch is that the WordPress and CiviCRM database are often different. From the installation guide:
So whilst CiviCRM would usually create a query like this:
I need to be able to add the database name for the WordPress table(s):
The addition of
civi.api4.generatedSql
allows for that. It does require doing some string manipulation, which isn't particuarly nice, but as this is a very niche requirement it's fine (I could have opened a PR allowing the API to natively add the database name, but that would have been a much bigger PR, and felt overkill for such a niche use-case).There are likely to also be other use-cases for
civi.api4.generatedSql
that I've not thought of.