dev/core#2141 - Add hook_civicrm_alterMailStore
authorTim Otten <totten@civicrm.org>
Fri, 30 Oct 2020 23:01:42 +0000 (16:01 -0700)
committerTim Otten <totten@civicrm.org>
Mon, 2 Nov 2020 03:53:42 +0000 (19:53 -0800)
commitf928a0b0df809420de307c8428aa0fddeae2feb9
tree8e1fc533e86d072365e80afc356ed7b4e1174405
parent4e93513a0be5ccbd2f2a1b2e86b34d0231d295e5
dev/core#2141 - Add hook_civicrm_alterMailStore

Overview
--------

The CiviCRM "MailStore" layer is used for importing email messages from
various sources (IMAP, POP3, Maildir, etc).  There is a built-in list with a
handful of drivers (`CRM_Mailing_MailStore_Imap`, etc).

This patch adds a hook for manipulating those drivers.

Before
------

It's not possible for an extension to add a driver, modify a driver, etc.

After
-----

It is now possible to add/modify/replace drivers. Here are two examples.

(1) To supplement the IMAP authentication with a dynamic token for XOAuth2:

```php
function hook_civicrm_alterMailStore(&$mailSettings) {
  if (...$mailSettings requires oauth...) {
    $mailSettings['auth'] = 'XOAuth2';
    $mailSettings['password'] = $myOauthSystem->getToken(...);
  }
}
```

(2) To add a new protocol `FIZZBUZZ`, you would:

1. Register a value in the OptionGroup `mail_protocol`.
2. Create a driver class (eg `CRM_Mailing_MailStore_FizzBuzz` extends `CRM_Mailing_MailStore`)
3. Use the hook to activate the class:

  ```php
  function hook_civicrm_alterMailStore(&$mailSettings) {
    if ($mailSettings['protocol'] === 'FIZZBUZZ') {
      $mailSettings['factory'] = function ($mailSettings) {
        return new CRM_Mailing_MailStore_FizzBuzz(...);
      };
    }
  }
  ```

Technical Details
-----------------

This adds a unit-test with examples of basic/non-hook behavior and hooked behavior.

In reading the diff for `getStore()`, note that it  previously had a long
'switch()' to handle instantiation.  I tried to make the change in a way that
you could see some continuity - e.g. it's still the same basic `switch()`.

The change is to basically wrap the bits inside a function:

* Before: `case 'FOO': return new Foo(...)`
* After: `case 'FOO': return ['factory' => function(...) { return new Foo(...); }]`
CRM/Mailing/MailStore.php
CRM/Utils/Hook.php
tests/phpunit/CRM/Mailing/MailStoreTest.php [new file with mode: 0644]