-
-
Notifications
You must be signed in to change notification settings - Fork 825
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
CRM-20845: create alterMailingRecipients hook #10673
Conversation
monishdeb
commented
Jul 16, 2017
•
edited by civicrm-builder
Loading
edited by civicrm-builder
- CRM-20845: create alterMailingRecipients hook
Submitted documentation as PR civicrm/civicrm-dev-docs#221 |
f9de170
to
356c268
Compare
Code looks nice. |
If you're using Mosaico/FlexMailer, does this new hook still have the expected effect? |
@totten I think the new hook has an effect because via that hook we can build and select mail-recipients by manipulating filters. Later stored in mail_recipients table for delivery and delivered by Flexmailer as per the code $flexMailer = new \Civi\FlexMailer\FlexMailer(array(
'mailing' => \CRM_Mailing_BAO_Mailing::findById($job->mailing_id),
...
));
return $flexMailer->run(); |
I've tested this hook with multiple customizations and it's working as intended. |
0327cb2
to
25eb2af
Compare
@lcdservices after the refactoring changes done to |
@Monish I reviewed the changes and they look fine. We already had changed the hook to have only 3 params in a previous round of edits on this. Would be great if we can get this merged. |
Thanks @lcdservices , also I have updated the doc PR civicrm/civicrm-dev-docs#221 @eileenmcnaughton @mlutfy @colemanw can you please review and merge this PR? |
I am reviewing this one today. @totten any thoughts about Monish's comment about Flexmailer compatibility? |
CRM/Mailing/BAO/Mailing.php
Outdated
); | ||
} | ||
|
||
// Allow user to alter query responsible to fetch mailing recipients before build, | ||
// by changing the mail filters identified $params | ||
CRM_Utils_Hook::alterMailingRecipients($mailingObj, $params, 'pre'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have mixed feelings here -- mostly over what makes a good contract for this. First consideration: do SQL expressions represent a supportable/maintainable contract?
On one hand, you might say "no" because there's many possible symbols in SQL. I like how $params['filters']
gives a name to each condition; the list of names is short and concrete. If you want to remove a criterion, you can do that without understanding the particular SQL involved. But there's really not much you can do with that.
On the other hand, this hook doesn't really hide the SQL -- if you want to add a new condition or change a condition, then you'll have to understand the list of tables/aliases/fields in play. And if you're going to have that responsibility, then we should probably go all the way: pass a CRM_Utils_SQL_Select
object to give access to the full list of params/joins/groupings/subqueries.
As an alternative, consider changing the list of SQL strings ($params['filters']
) to a list of SQL objects -- i.e. totten@6995c3e (with totten@3ed9641). This allows the custom filter to benefit from escaping data, joining, etc.
<?php
// Ex: Remove a criterion by name
unset($criteria['is_deceased']);
// Ex: Add a filter based on subtype. Use some data provided by the site admin (with string-escaping).
$criteria['my_extra_criterion'] = CRM_Utils_SQL_Select::fragment()
->where('civicrm_contact.contact_sub_type IN (@subtypes)')
->param('subtypes', Civi::settings()->get('myextension_mailable_subtypes'));
// Ex: Add a filter based on Drupal role. Use some data provided by the admin (with numeric-validation).
$criteria['my_extra_criterion'] = CRM_Utils_SQL_Select::fragment()
->join('civicrm_uf_match', 'INNER JOIN civicrm_uf_match WHERE civicrm_uf_match.contact_id = civicrm_contact.id')
->join('users_roles', 'INNER JOIN users_roles ON civicrm_uf_match.uf_id = users_roles.uid AND rid IN (#allowedRoles)')
->param('allowedRoles', Civi::settings()->get('myextension_drupal_role_ids'));
Of course, you need to know/assume some things about SQL query. (Ex: You assume that the civicrm_contact
record is named civicrm_contact
and not contact_a
or contact_b
or recipient
.) But that was also true when passing SQL strings.
CRM/Mailing/BAO/Mailing.php
Outdated
@@ -367,6 +377,8 @@ public static function getRecipients($mailingID) { | |||
$mailingGroup->reset(); | |||
$mailingGroup->query(" DROP TEMPORARY TABLE $excludeTempTablename "); | |||
$mailingGroup->query(" DROP TEMPORARY TABLE $includedTempTablename "); | |||
|
|||
CRM_Utils_Hook::alterMailingRecipients($mailingObj, $params, 'post'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continuing thoughts on contract, the second question: What are you supposed to do in post
?
Is the idea that one would directly INSERT
/DELETE
records from civicrm_mailing_recipients
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a consumer, I guess I can see how that's kind'a nice -- i.e. you don't have think at all about how the main query-building works; you can just do your own thing.
OTOH, recall this: the CiviMail UI shows a preview of the #recipients, and it actually executes getRecipients()
but performs a ROLLBACK
. This was sort of a quick hack that people have periodically complained about, but it was easier than rewriting getRecipients()
. Can we ever get rid of that hack?
As of today, the answer is, "Yes, if we spend a while refactoring."
If we change the contract so that hook_civicrm_alterMailingRecipients
relies on direct manipulation of the civicrm_mailing_recipients
table, then the answer is "No, we can't cleanup the weird ROLLBACK without breaking the contract."
@totten a few things, as we are already using this for NYSS in production and have several use cases:
for reference, you can see our implementation of this hook here: as you can see, we have six different steps we walk through when constructing the recipient list after the core function has handled the base construction. |
@totten w.r.t to the 5th point made by @lcdservices
This is the PR https://github.com/civicrm/civicrm-core/pull/11142/files which contain the refactoring changes made earlier, where rollbacks are avoided and now
Nope it doesn't rollback now, see here |
OK, good point. The process now actually commits the full list while editing the mailing - so "Previewing" the recipient just means "show the currently save list of recipients".
Six/half-dozen -- based on the example and based on the design of the |
Thanks @totten for suggesting your patch which I have now included in my PR and also updated the unit-test to work with the new changes. Updated the doc PR civicrm/civicrm-dev-docs#221 and I think the example will be enough, telling about how to use SQL fragments to override/change the filters. @lcdservices in this new change we will now use SQL fragments which is flexible enough to consider subqueries too. I have added an example in UT which filters contact that is deceased and has a tag - "Tagged". Please have a look. |
Jenkins test this please |
27703f4
to
07b93bf
Compare
@totten your suggestions appear to have been acted on & this is requiring your re-review |
@totten per above - I think this is waiting on you after your feedback was responded to |
@totten ^^ |
@monishdeb you might rebase this - although that shouldn't prevent @totten from confirming status |
@eileenmcnaughton rebased it and the extended test passed. |
OK - pending @totten |
@totten can you please clarify why you still have reservations about this - it's obviously in your too hard basket - I'm happy to close it if it's really not going anywhere (given it's been almost a year) |
I discussed this with @seamuslee001 & we agreed not to hold this up further on efforts to get @totten to respond. In summary the PR has been fairly thoroughly tested by @lcdservices, unit tests have been added & code feedback responded to - merging |
Thanks @eileenmcnaughton |
thanks @eileenmcnaughton |