composer.json - Move ezc components from packages to composer.json
[civicrm-core.git] / CRM / Utils / Hook.php
index e96d7c473febd63610f72840abe371445da57fd9..ced92c3d6d69b10b616e831bd737b23bb662fb62 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.6                                                |
+ | CiviCRM version 4.7                                                |
  +--------------------------------------------------------------------+
  | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
@@ -29,8 +29,6 @@
  *
  * @package CiviCRM_Hook
  * @copyright CiviCRM LLC (c) 2004-2015
- * $Id: $
- *
  */
 abstract class CRM_Utils_Hook {
 
@@ -44,9 +42,9 @@ abstract class CRM_Utils_Hook {
 
   // by default - place content below existing content
   const SUMMARY_BELOW = 1;
-  // pace hook content above
+  // place hook content above
   const SUMMARY_ABOVE = 2;
-  // create your own summarys
+  // create your own summaries
   const SUMMARY_REPLACE = 3;
 
   static $_nullObject = NULL;
@@ -69,6 +67,11 @@ abstract class CRM_Utils_Hook {
    */
   private $commonCiviModules = array();
 
+  /**
+   * @var CRM_Utils_Cache_Interface
+   */
+  protected $cache;
+
   /**
    * Constructor and getter for the singleton instance.
    *
@@ -81,12 +84,19 @@ abstract class CRM_Utils_Hook {
     if (self::$_singleton == NULL || $fresh) {
       $config = CRM_Core_Config::singleton();
       $class = $config->userHookClass;
-      require_once str_replace('_', DIRECTORY_SEPARATOR, $config->userHookClass) . '.php';
       self::$_singleton = new $class();
     }
     return self::$_singleton;
   }
 
+  public function __construct() {
+    $this->cache = CRM_Utils_Cache::create(array(
+      'name' => 'hooks',
+      'type' => array('ArrayCache'),
+      'prefetch' => 1,
+    ));
+  }
+
   /**
    * Invoke hooks.
    *
@@ -189,51 +199,60 @@ abstract class CRM_Utils_Hook {
     // to reproduce the issue are pretty intricate.
     $result = array();
 
-    if ($civiModules !== NULL) {
-      foreach ($civiModules as $module) {
-        $fnName = "{$module}_{$fnSuffix}";
-        if (function_exists($fnName)) {
-          $fResult = array();
-          switch ($numParams) {
-            case 0:
-              $fResult = $fnName();
-              break;
-
-            case 1:
-              $fResult = $fnName($arg1);
-              break;
-
-            case 2:
-              $fResult = $fnName($arg1, $arg2);
-              break;
-
-            case 3:
-              $fResult = $fnName($arg1, $arg2, $arg3);
-              break;
-
-            case 4:
-              $fResult = $fnName($arg1, $arg2, $arg3, $arg4);
-              break;
-
-            case 5:
-              $fResult = $fnName($arg1, $arg2, $arg3, $arg4, $arg5);
-              break;
-
-            case 6:
-              $fResult = $fnName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6);
-              break;
-
-            default:
-              CRM_Core_Error::fatal(ts('Invalid hook invocation'));
-              break;
-          }
-
-          if (!empty($fResult) &&
-            is_array($fResult)
-          ) {
-            $result = array_merge($result, $fResult);
+    $fnNames = $this->cache->get($fnSuffix);
+    if (!is_array($fnNames)) {
+      $fnNames = array();
+      if ($civiModules !== NULL) {
+        foreach ($civiModules as $module) {
+          $fnName = "{$module}_{$fnSuffix}";
+          if (function_exists($fnName)) {
+            $fnNames[] = $fnName;
           }
         }
+        $this->cache->set($fnSuffix, $fnNames);
+      }
+    }
+
+    foreach ($fnNames as $fnName) {
+      $fResult = array();
+      switch ($numParams) {
+        case 0:
+          $fResult = $fnName();
+          break;
+
+        case 1:
+          $fResult = $fnName($arg1);
+          break;
+
+        case 2:
+          $fResult = $fnName($arg1, $arg2);
+          break;
+
+        case 3:
+          $fResult = $fnName($arg1, $arg2, $arg3);
+          break;
+
+        case 4:
+          $fResult = $fnName($arg1, $arg2, $arg3, $arg4);
+          break;
+
+        case 5:
+          $fResult = $fnName($arg1, $arg2, $arg3, $arg4, $arg5);
+          break;
+
+        case 6:
+          $fResult = $fnName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6);
+          break;
+
+        default:
+          CRM_Core_Error::fatal(ts('Invalid hook invocation'));
+          break;
+      }
+
+      if (!empty($fResult) &&
+        is_array($fResult)
+      ) {
+        $result = array_merge($result, $fResult);
       }
     }
 
@@ -276,8 +295,8 @@ abstract class CRM_Utils_Hook {
    */
   public static function pre($op, $objectName, $id, &$params) {
     $event = new \Civi\Core\Event\PreEvent($op, $objectName, $id, $params);
-    \Civi\Core\Container::singleton()->get('dispatcher')->dispatch("hook_civicrm_pre", $event);
-    \Civi\Core\Container::singleton()->get('dispatcher')->dispatch("hook_civicrm_pre::$objectName", $event);
+    \Civi::service('dispatcher')->dispatch("hook_civicrm_pre", $event);
+    \Civi::service('dispatcher')->dispatch("hook_civicrm_pre::$objectName", $event);
     return self::singleton()
       ->invoke(4, $op, $objectName, $id, $params, self::$_nullObject, self::$_nullObject, 'civicrm_pre');
   }
@@ -300,8 +319,8 @@ abstract class CRM_Utils_Hook {
    */
   public static function post($op, $objectName, $objectId, &$objectRef) {
     $event = new \Civi\Core\Event\PostEvent($op, $objectName, $objectId, $objectRef);
-    \Civi\Core\Container::singleton()->get('dispatcher')->dispatch("hook_civicrm_post", $event);
-    \Civi\Core\Container::singleton()->get('dispatcher')->dispatch("hook_civicrm_post::$objectName", $event);
+    \Civi::service('dispatcher')->dispatch("hook_civicrm_post", $event);
+    \Civi::service('dispatcher')->dispatch("hook_civicrm_post::$objectName", $event);
     return self::singleton()
       ->invoke(4, $op, $objectName, $objectId, $objectRef, self::$_nullObject, self::$_nullObject, 'civicrm_post');
   }
@@ -384,25 +403,6 @@ abstract class CRM_Utils_Hook {
     );
   }
 
-  /**
-   * This hook is invoked during all CiviCRM form validation. An array of errors
-   * detected is returned. Else we assume validation succeeded.
-   *
-   * @param string $formName
-   *   The name of the form.
-   * @param array &$fields the POST parameters as filtered by QF
-   * @param array &$files the FILES parameters as sent in by POST
-   * @param array &$form the form object
-   *
-   * @return mixed
-   *   formRule hooks return a boolean or
-   *                           an array of error messages which display a QF Error
-   */
-  public static function validate($formName, &$fields, &$files, &$form) {
-    return self::singleton()
-      ->invoke(4, $formName, $fields, $files, $form, self::$_nullObject, self::$_nullObject, 'civicrm_validate');
-  }
-
   /**
    * This hook is invoked during all CiviCRM form validation. An array of errors
    * detected is returned. Else we assume validation succeeded.
@@ -640,6 +640,7 @@ abstract class CRM_Utils_Hook {
    *   The contactID for whom the dashboard is being rendered.
    *
    * @return null
+   * @deprecated Use tabset() instead.
    */
   public static function tabs(&$tabs, $contactID) {
     return self::singleton()->invoke(2, $tabs, $contactID,
@@ -766,8 +767,9 @@ abstract class CRM_Utils_Hook {
   }
 
   /**
-   * This hook is called when CiviCRM needs to edit/display a custom field with options (select, radio, checkbox,
-   * adv multiselect)
+   * This hook is called when CiviCRM needs to edit/display a custom field with options
+   *
+   * @deprecated in favor of hook_civicrm_fieldOptions
    *
    * @param int $customFieldID
    *   The custom field ID.
@@ -778,8 +780,7 @@ abstract class CRM_Utils_Hook {
    *              to be careful to not overwrite the array.
    *   Only add/edit/remove the specific field options you intend to affect.
    * @param bool $detailedFormat
-   *   If true,.
-   *                the options are in an ID => array ( 'id' => ID, 'label' => label, 'value' => value ) format
+   *   If true, the options are in an ID => array ( 'id' => ID, 'label' => label, 'value' => value ) format
    * @param array $selectAttributes
    *   Contain select attribute(s) if any.
    *
@@ -792,6 +793,23 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * Hook for modifying field options
+   *
+   * @param string $entity
+   * @param string $field
+   * @param array $options
+   * @param array $params
+   *
+   * @return mixed
+   */
+  public static function fieldOptions($entity, $field, &$options, $params) {
+    return self::singleton()->invoke(5, $entity, $field, $options, $params,
+      self::$_nullObject, self::$_nullObject,
+      'civicrm_fieldOptions'
+    );
+  }
+
   /**
    *
    * This hook is called to display the list of actions allowed after doing a search.
@@ -803,7 +821,7 @@ abstract class CRM_Utils_Hook {
    * @param array $tasks
    *   The current set of tasks for that custom field.
    *   You can add/remove existing tasks.
-   *   Each task needs to have a title (eg 'title'  => ts( 'Add Contacts to Group')) and a class
+   *   Each task needs to have a title (eg 'title'  => ts( 'Group - add contacts')) and a class
    *   (eg 'class'  => 'CRM_Contact_Form_Task_AddToGroup').
    *   Optional result (boolean) may also be provided. Class can be an array of classes (not sure what that does :( ).
    *   The key for new Task(s) should not conflict with the keys for core tasks of that $objectType, which can be
@@ -998,6 +1016,21 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * This hook is called after getting the content of the mail and before tokenizing it.
+   *
+   * @param array $content
+   *   Array fields include: html, text, subject
+   *
+   * @return mixed
+   */
+  public static function alterMailContent(&$content) {
+    return self::singleton()->invoke(1, $content,
+      self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_alterMailContent'
+    );
+  }
+
   /**
    * This hook is called when rendering the Manage Case screen.
    *
@@ -1046,6 +1079,8 @@ abstract class CRM_Utils_Hook {
   /**
    * This hooks allows to change option values.
    *
+   * @deprecated in favor of hook_civicrm_fieldOptions
+   *
    * @param array $options
    *   Associated array of option values / id
    * @param string $name
@@ -1188,7 +1223,7 @@ abstract class CRM_Utils_Hook {
    *                  fieldHeaders    - field headers
    *                  fields          - import fields
    *
-   * @return void
+   * @return mixed
    */
   public static function import($object, $usage, &$objectRef, &$params) {
     return self::singleton()->invoke(4, $object, $usage, $objectRef, $params,
@@ -1265,8 +1300,8 @@ abstract class CRM_Utils_Hook {
    * @param array $selector
    *   the selector object. Allows you access to the context of the search
    *
-   * @return void
-   *   modify the header and values object to pass the data u need
+   * @return mixed
+   *   modify the header and values object to pass the data you need
    */
   public static function searchColumns($objectName, &$headers, &$rows, &$selector) {
     return self::singleton()->invoke(4, $objectName, $headers, $rows, $selector,
@@ -1340,7 +1375,7 @@ abstract class CRM_Utils_Hook {
    *   float $x x position in user units
    *   float $y y position in user units
    *   boolean $reseth if true reset the last cell height (default true).
-   *   int $stretch stretch carachter mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if
+   *   int $stretch stretch character mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if
    *                necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if
    *                necessary</li><li>4 = forced character spacing</li></ul>
    *   boolean $ishtml set to true if $txt is HTML content (default = false).
@@ -1533,6 +1568,22 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * This hook is called when a CiviMail mailing has completed
+   *
+   * @param int $mailingId
+   *   Mailing ID
+   *
+   * @return mixed
+   */
+  public static function postMailing($mailingId) {
+    return self::singleton()->invoke(1, $mailingId,
+      self::$_nullObject, self::$_nullObject,
+      self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_postMailing'
+    );
+  }
+
   /**
    * This hook is called when Settings specifications are loaded.
    *
@@ -1627,13 +1678,13 @@ abstract class CRM_Utils_Hook {
     self::singleton()
       ->invoke(2, $exception, $request, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_unhandled_exception');
     // == 4.4 ==
-    //$event = new stdClass();
-    //$event->exception = $exception;
-    //CRM_Core_LegacyErrorHandler::handleException($event);
+    // $event = new stdClass();
+    // $event->exception = $exception;
+    // CRM_Core_LegacyErrorHandler::handleException($event);
 
     // == 4.5+ ==
     $event = new \Civi\Core\Event\UnhandledExceptionEvent($exception, self::$_nullObject);
-    \Civi\Core\Container::singleton()->get('dispatcher')->dispatch("hook_civicrm_unhandled_exception", $event);
+    \Civi::service('dispatcher')->dispatch("hook_civicrm_unhandled_exception", $event);
   }
 
   /**
@@ -1760,11 +1811,30 @@ abstract class CRM_Utils_Hook {
    * @return mixed
    * @see Mail::factory
    */
-  public static function alterMail(&$mailer, $driver, $params) {
+  public static function alterMailer(&$mailer, $driver, $params) {
     return self::singleton()
       ->invoke(3, $mailer, $driver, $params, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_alterMailer');
   }
 
+  /**
+   * Deprecated: Misnamed version of alterMailer(). Remove post-4.7.x.
+   * 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
+   *
+   * @return mixed
+   * @see Mail::factory
+   * @deprecated
+   */
+  public static function alterMail(&$mailer, $driver, $params) {
+    return CRM_Utils_Hook::alterMailer($mailer, $driver, $params);
+  }
+
   /**
    * This hook is called while building the core search query,
    * so hook implementers can provide their own query objects which alters/extends core search.
@@ -1803,7 +1873,7 @@ abstract class CRM_Utils_Hook {
    * @param int $otherCaseId
    * @param bool $changeClient
    *
-   * @return void
+   * @return mixed
    */
   public static function pre_case_merge($mainContactId, $mainCaseId = NULL, $otherContactId = NULL, $otherCaseId = NULL, $changeClient = FALSE) {
     return self::singleton()
@@ -1819,7 +1889,7 @@ abstract class CRM_Utils_Hook {
    * @param int $otherCaseId
    * @param bool $changeClient
    *
-   * @return void
+   * @return mixed
    */
   public static function post_case_merge($mainContactId, $mainCaseId = NULL, $otherContactId = NULL, $otherCaseId = NULL, $changeClient = FALSE) {
     return self::singleton()
@@ -1884,7 +1954,7 @@ abstract class CRM_Utils_Hook {
    */
   public static function caseChange(\Civi\CCase\Analyzer $analyzer) {
     $event = new \Civi\CCase\Event\CaseChangeEvent($analyzer);
-    \Civi\Core\Container::singleton()->get('dispatcher')->dispatch("hook_civicrm_caseChange", $event);
+    \Civi::service('dispatcher')->dispatch("hook_civicrm_caseChange", $event);
 
     self::singleton()->invoke(1, $analyzer,
       self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
@@ -1917,6 +1987,31 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * Modify the CiviCRM container - add new services, parameters, extensions, etc.
+   *
+   * @code
+   * use Symfony\Component\Config\Resource\FileResource;
+   * use Symfony\Component\DependencyInjection\Definition;
+   *
+   * function mymodule_civicrm_container($container) {
+   *   $container->addResource(new FileResource(__FILE__));
+   *   $container->setDefinition('mysvc', new Definition('My\Class', array()));
+   * }
+   * @endcode
+   *
+   * Tip: The container configuration will be compiled/cached. The default cache
+   * behavior is aggressive. When you first implement the hook, be sure to
+   * flush the cache. Additionally, you should relax caching during development.
+   * In `civicrm.settings.php`, set define('CIVICRM_CONTAINER_CACHE', 'auto').
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   * @see http://symfony.com/doc/current/components/dependency_injection/index.html
+   */
+  public static function container(\Symfony\Component\DependencyInjection\ContainerBuilder $container) {
+    self::singleton()->invoke(1, $container, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_container');
+  }
+
   /**
    * @param array <CRM_Core_FileSearchInterface> $fileSearches
    * @return mixed
@@ -1928,8 +2023,24 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * Check system status.
+   *
+   * @param array $messages
+   *   Array<CRM_Utils_Check_Message>. A list of messages regarding system status.
+   * @return mixed
+   */
+  public static function check(&$messages) {
+    return self::singleton()
+      ->invoke(1, $messages, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_check');
+  }
+
   /**
    * This hook is called when a query string of the CSV Batch export is generated.
+   *
+   * @param string $query
+   *
+   * @return mixed
    */
   public static function batchQuery(&$query) {
     return self::singleton()->invoke(1, $query, self::$_nullObject,
@@ -1940,6 +2051,11 @@ abstract class CRM_Utils_Hook {
 
   /**
    * This hook is called when the entries of the CSV Batch export are mapped.
+   *
+   * @param array $results
+   * @param array $items
+   *
+   * @return mixed
    */
   public static function batchItems(&$results, &$items) {
     return self::singleton()->invoke(2, $results, $items,