From 72ad6c1b262f3d14612a728b7e6c12cdb1da74c5 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 5 Sep 2013 00:12:11 -0700 Subject: [PATCH] CRM-11958 - Add hook_civicrm_alterMailer (with unit-test) ---------------------------------------- * CRM-11958: New hook implementation for altering outgoing mail configuration http://issues.civicrm.org/jira/browse/CRM-11958 --- CRM/Core/Config.php | 30 +++++++--- CRM/Utils/FakeObject.php | 26 +++++++++ CRM/Utils/Hook.php | 15 +++++ tests/phpunit/CRM/Core/Config/MailerTest.php | 60 ++++++++++++++++++++ tests/phpunit/CiviTest/CiviUnitTestCase.php | 1 + 5 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 CRM/Utils/FakeObject.php create mode 100644 tests/phpunit/CRM/Core/Config/MailerTest.php diff --git a/CRM/Core/Config.php b/CRM/Core/Config.php index b39b9bff9b..be3bf7c53c 100644 --- a/CRM/Core/Config.php +++ b/CRM/Core/Config.php @@ -113,7 +113,7 @@ class CRM_Core_Config extends CRM_Core_Config_Variables { * the handle on the mail handler that we are using * @var object */ - private static $_mail = NULL; + public static $_mail = NULL; /** * We only need one instance of this object. So we use the singleton @@ -520,7 +520,7 @@ class CRM_Core_Config extends CRM_Core_Config_Variables { if ($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB || (defined('CIVICRM_MAILER_SPOOL') && CIVICRM_MAILER_SPOOL) ) { - self::$_mail = new CRM_Mailing_BAO_Spool(); + self::$_mail = self::_createMailer('CRM_Mailing_BAO_Spool', array()); } elseif ($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_SMTP) { if ($mailingInfo['smtpServer'] == '' || !$mailingInfo['smtpServer']) { @@ -550,7 +550,7 @@ class CRM_Core_Config extends CRM_Core_Config_Variables { // CRM-9349 $params['persist'] = $persist; - self::$_mail = Mail::factory('smtp', $params); + self::$_mail = self::_createMailer('smtp', $params); } elseif ($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_SENDMAIL) { if ($mailingInfo['sendmail_path'] == '' || @@ -562,16 +562,15 @@ class CRM_Core_Config extends CRM_Core_Config_Variables { $params['sendmail_path'] = $mailingInfo['sendmail_path']; $params['sendmail_args'] = $mailingInfo['sendmail_args']; - self::$_mail = Mail::factory('sendmail', $params); + self::$_mail = self::_createMailer('sendmail', $params); } elseif ($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_MAIL) { - $params = array(); - self::$_mail = Mail::factory('mail', $params); + self::$_mail = self::_createMailer('mail', array()); } elseif ($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_MOCK) { - self::$_mail = Mail::factory('mock', $params); + self::$_mail = self::_createMailer('mock', array()); } - elseif ($mailingInfo['outBound_option'] == 2) { + elseif ($mailingInfo['outBound_option'] == CRM_Mailing_Config::OUTBOUND_OPTION_DISABLED) { CRM_Core_Error::debug_log_message(ts('Outbound mail has been disabled. Click Administer >> System Setting >> Outbound Email to set the OutBound Email.', array(1 => CRM_Utils_System::url('civicrm/admin/setting/smtp', 'reset=1')))); CRM_Core_Session::setStatus(ts('Outbound mail has been disabled. Click Administer >> System Setting >> Outbound Email to set the OutBound Email.', array(1 => CRM_Utils_System::url('civicrm/admin/setting/smtp', 'reset=1')))); } @@ -584,6 +583,21 @@ class CRM_Core_Config extends CRM_Core_Config_Variables { return self::$_mail; } + /** + * @param string $driver 'CRM_Mailing_BAO_Spool' or a name suitable for Mail::factory() + * @param array $params + * @return Mail|NULL + */ + public static function _createMailer($driver, $params) { + if ($driver == 'CRM_Mailing_BAO_Spool') { + $mailer = new CRM_Mailing_BAO_Spool($params); + } else { + $mailer = Mail::factory($driver, $params); + } + CRM_Utils_Hook::hook_civicrm_alterMailer($mailer, $driver, $params); + return $mailer; + } + /** * delete the web server writable directories * diff --git a/CRM/Utils/FakeObject.php b/CRM/Utils/FakeObject.php new file mode 100644 index 0000000000..68e36bf019 --- /dev/null +++ b/CRM/Utils/FakeObject.php @@ -0,0 +1,26 @@ + function() { print "It!\n"; } + * )); + * $object->doIt(); + * @endcode + */ +class CRM_Utils_FakeObject { + function __construct($array) { + $this->array = $array; + } + + function __call($name, $arguments) { + if (isset($this->array[$name]) && is_callable($this->array[$name])) { + return call_user_func_array($this->array[$name], $arguments); + } else { + throw new Exception("Call to unimplemented method: $name"); + } + } +} \ No newline at end of file diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index 646185618d..512f3a24de 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -1349,6 +1349,21 @@ abstract class CRM_Utils_Hook { self::$_nullObject, 'civicrm_alterBarcode'); } + /** + * Modify or replace the Mailer object used for outgoing mail. + * + * @param object $mailer + * The default mailer produced by normal configuration; a PEAR "Mail" class (like those returned by Mail::factory) + * @param string $driver + * The type of the default mailer (eg "smtp", "sendmail", "mock", "CRM_Mailing_BAO_Spool") + * @param array $params + * The default mailer config options + * @see Mail::factory + */ + static function hook_civicrm_alterMailer(&$mailer, $driver, $params) { + return self::singleton()->invoke(3, $mailer, $driver, $params, self::$_nullObject, self::$_nullObject, 'civicrm_alterMailer'); + } + /** * This hook is called while building the core search query, * so hook implementers can provide their own query objects which alters/extends core search. diff --git a/tests/phpunit/CRM/Core/Config/MailerTest.php b/tests/phpunit/CRM/Core/Config/MailerTest.php new file mode 100644 index 0000000000..7365c3af0d --- /dev/null +++ b/tests/phpunit/CRM/Core/Config/MailerTest.php @@ -0,0 +1,60 @@ +int) Keep count of the #times different functions are called + */ + var $calls; + + function setUp() { + $this->calls = array( + 'civicrm_alterMailer' => 0, + 'send' => 0, + ); + parent::setUp(); + } + + function testHookAlterMailer() { + $test = $this; + $mockMailer = new CRM_Utils_FakeObject(array( + 'send' => function ($recipients, $headers, $body) use ($test) { + $test->calls['send']++; + $test->assertEquals(array('to@example.org'), $recipients); + $test->assertEquals('Subject Example', $headers['Subject']); + } + )); + + CRM_Utils_Hook::singleton()->setHook('civicrm_alterMailer', + function (&$mailer, $driver, $params) use ($test, $mockMailer) { + $test->calls['civicrm_alterMailer']++; + $test->assertTrue(is_string($driver) && !empty($driver)); + $test->assertTrue(is_array($params)); + $test->assertTrue(is_callable(array($mailer, 'send'))); + $mailer = $mockMailer; + } + ); + + $params = array(); + $params['groupName'] = 'CRM_Core_Config_MailerTest'; + $params['from'] = 'From Example '; + $params['toName'] = 'To Example'; + $params['toEmail'] = 'to@example.org'; + $params['subject'] = 'Subject Example'; + $params['text'] = 'Example text'; + $params['html'] = '

Example HTML

'; + CRM_Utils_Mail::send($params); + + $this->assertEquals(1, $this->calls['civicrm_alterMailer']); + $this->assertEquals(1, $this->calls['send']); + + // once more, just to make sure the hooks are called right #times + CRM_Utils_Mail::send($params); + CRM_Utils_Mail::send($params); + $this->assertEquals(1, $this->calls['civicrm_alterMailer']); + $this->assertEquals(3, $this->calls['send']); + } + +} diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 5006e9bde6..d4f1645dd2 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -330,6 +330,7 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase { // FIXME: look at it closer in second stage // initialize the object once db is loaded + CRM_Core_Config::$_mail = NULL; $config = CRM_Core_Config::singleton(); // when running unit tests, use mockup user framework -- 2.25.1