Merge remote-tracking branch 'upstream/4.5' into 4.5-master-2015-03-09-21-44-34
authorkurund <kurund@civicrm.org>
Mon, 9 Mar 2015 16:27:45 +0000 (21:57 +0530)
committerkurund <kurund@civicrm.org>
Mon, 9 Mar 2015 16:27:45 +0000 (21:57 +0530)
Conflicts:
CRM/Contact/Page/AJAX.php
CRM/Core/Form.php
CRM/Core/Page/AJAX.php
sql/civicrm_generated.mysql
xml/version.xml

17 files changed:
1  2 
CRM/Activity/Page/AJAX.php
CRM/Batch/Page/AJAX.php
CRM/Campaign/Page/AJAX.php
CRM/Contact/Page/AJAX.php
CRM/Core/Form.php
CRM/Core/Page/AJAX.php
CRM/Core/xml/Menu/Contact.xml
CRM/Financial/Page/AJAX.php
CRM/Group/Page/AJAX.php
CRM/Mailing/BAO/Component.php
CRM/Mailing/BAO/Mailing.php
CRM/Mailing/Form/Component.php
CRM/Mailing/Page/AJAX.php
CRM/Pledge/Page/AJAX.php
api/v3/MailingComponent.php
api/v3/MessageTemplate.php
templates/CRM/Contact/Page/View/Summary.js

index dc6b5323ba1e0d57a6fc2c2d565c3e0636e98f8c,3ef11f8ac7837a0448526c8425c193aeb5c4758e..5e11dc87b1ecb1a336e924cbb1bd2b906baf0f00
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
   * This class contains all the function that are called using AJAX (jQuery)
   */
  class CRM_Activity_Page_AJAX {
 -  static function getCaseActivity() {
 -    $caseID    = CRM_Utils_Type::escape($_GET['caseID'], 'Integer');
 +  public static function getCaseActivity() {
 +    $caseID = CRM_Utils_Type::escape($_GET['caseID'], 'Integer');
      $contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer');
 -    $userID    = CRM_Utils_Type::escape($_GET['userID'], 'Integer');
 -    $context   = CRM_Utils_Type::escape(CRM_Utils_Array::value('context', $_GET), 'String');
 +    $userID = CRM_Utils_Type::escape($_GET['userID'], 'Integer');
 +    $context = CRM_Utils_Type::escape(CRM_Utils_Array::value('context', $_GET), 'String');
  
      $sortMapper = array(
 -      0 => 'display_date', 1 => 'ca.subject', 2 => 'ca.activity_type_id',
 -      3 => 'acc.sort_name', 4 => 'cc.sort_name', 5 => 'ca.status_id',
 +      0 => 'display_date',
 +      1 => 'ca.subject',
 +      2 => 'ca.activity_type_id',
 +      3 => 'acc.sort_name',
 +      4 => 'cc.sort_name',
 +      5 => 'ca.status_id',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
      $params = $_POST;
      $activities = CRM_Case_BAO_Case::getCaseActivity($caseID, $params, $contactID, $context, $userID);
  
      $iFilteredTotal = $iTotal = $params['total'];
 -    $selectorElements = array('display_date', 'subject', 'type', 'with_contacts', 'reporter', 'status', 'links', 'class');
 +    $selectorElements = array(
 +      'display_date',
 +      'subject',
 +      'type',
 +      'with_contacts',
 +      'reporter',
 +      'status',
 +      'links',
 +      'class',
 +    );
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($activities, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
  
 -  static function getCaseGlobalRelationships() {
 +  public static function getCaseGlobalRelationships() {
      $sortMapper = array(
 -      0 => 'sort_name', 1 => 'phone', 2 => 'email',
 +      0 => 'sort_name',
 +      1 => 'phone',
 +      2 => 'email',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
      $params = $_POST;
      //CRM-14466 initialize variable to avoid php notice
      $sortSQL = "";
      if ($sort && $sortOrder) {
 -      $sortSQL = $sort .' '.$sortOrder;
 +      $sortSQL = $sort . ' ' . $sortOrder;
      }
  
      // get the activities related to given case
      $iFilteredTotal = $iTotal = $relGlobalTotalCount;
      $selectorElements = array('sort_name', 'phone', 'email');
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($relGlobal, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
  
 -  static function getCaseClientRelationships() {
 -    $caseID    = CRM_Utils_Type::escape($_GET['caseID'], 'Integer');
 +  public static function getCaseClientRelationships() {
 +    $caseID = CRM_Utils_Type::escape($_GET['caseID'], 'Integer');
      $contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer');
  
      $sortMapper = array(
 -      0 => 'relation', 1 => 'name', 2 => 'phone', 3 => 'email'
 +      0 => 'relation',
 +      1 => 'name',
 +      2 => 'phone',
 +      3 => 'email',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : 'relation';
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : 'relation';
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
      $params = $_POST;
      if ($sort && $sortOrder) {
 -      $sortSQL = $sort .' '.$sortOrder;
 +      $sortSQL = $sort . ' ' . $sortOrder;
      }
  
      // Retrieve ALL client relationships
  
      // sort clientRelationships array using jquery call params
      foreach ($clientRelationships as $key => $row) {
 -      $sortArray[$key]  = $row[$sort];
 +      $sortArray[$key] = $row[$sort];
      }
      $sort_type = "SORT_" . strtoupper($sortOrder);
      array_multisort($sortArray, constant($sort_type), $clientRelationships);
      $clientRelationships = array_slice($allClientRelationships, $offset, $rowCount, TRUE);
  
      // after sort we can update username fields to be a url
 -    foreach($clientRelationships as $key => $value) {
 -      $clientRelationships[$key]['name'] = '<a href='.CRM_Utils_System::url('civicrm/contact/view',
 -       'action=view&reset=1&cid='.$clientRelationships[$key]['cid']).'>'.$clientRelationships[$key]['name'].'</a>';
 +    foreach ($clientRelationships as $key => $value) {
 +      $clientRelationships[$key]['name'] = '<a href=' . CRM_Utils_System::url('civicrm/contact/view',
 +          'action=view&reset=1&cid=' . $clientRelationships[$key]['cid']) . '>' . $clientRelationships[$key]['name'] . '</a>';
      }
  
      $iFilteredTotal = $iTotal = $params['total'] = count($allClientRelationships);
      $selectorElements = array('relation', 'name', 'phone', 'email');
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($clientRelationships, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
  
  
 -  static function getCaseRoles() {
 -    $caseID    = CRM_Utils_Type::escape($_GET['caseID'], 'Integer');
 +  public static function getCaseRoles() {
 +    $caseID = CRM_Utils_Type::escape($_GET['caseID'], 'Integer');
      $contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer');
  
      $sortMapper = array(
 -      0 => 'relation', 1 => 'name', 2 => 'phone', 3 => 'email', 4 => 'actions'
 +      0 => 'relation',
 +      1 => 'name',
 +      2 => 'phone',
 +      3 => 'email',
 +      4 => 'actions',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : 'relation';
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : 'relation';
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
      $params = $_POST;
      if ($sort && $sortOrder) {
 -      $sortSQL = $sort .' '.$sortOrder;
 +      $sortSQL = $sort . ' ' . $sortOrder;
      }
  
      $caseRelationships = CRM_Case_BAO_Case::getCaseRoles($contactID, $caseID);
      $caseTypeName = CRM_Case_BAO_Case::getCaseType($caseID, 'name');
      $xmlProcessor = new CRM_Case_XMLProcessor_Process();
 -    $caseRoles    = $xmlProcessor->get($caseTypeName, 'CaseRoles');
 +    $caseRoles = $xmlProcessor->get($caseTypeName, 'CaseRoles');
  
      $hasAccessToAllCases = CRM_Core_Permission::check('access all cases and activities');
  
      // move/transform caseRoles array data to caseRelationships
      // for sorting and display
      // CRM-14466 added cid to the non-client array to avoid php notice
 -    foreach($caseRoles as $id => $value) {
 +    foreach ($caseRoles as $id => $value) {
        if ($id != "client") {
          $rel = array();
          $rel['relation'] = $value;
          $rel['email'] = '';
          $rel['source'] = 'caseRoles';
          $caseRelationships[] = $rel;
 -      } else {
 -        foreach($value as $clientRole) {
 +      }
 +      else {
 +        foreach ($value as $clientRole) {
            $relClient = array();
            $relClient['relation'] = 'Client';
            $relClient['name'] = $clientRole['sort_name'];
  
      // sort clientRelationships array using jquery call params
      foreach ($caseRelationships as $key => $row) {
 -      $sortArray[$key]  = $row[$sort];
 +      $sortArray[$key] = $row[$sort];
      }
  
      $sort_type = "SORT_" . strtoupper($sortOrder);
        list($typeLabel) = explode('<', $row['relation']);
        // view user links
        if (!empty($row['cid'])) {
 -        $row['name'] = '<a class="view-contact" title="'. ts('View Contact') .'" href='.CRM_Utils_System::url('civicrm/contact/view',
 -          'action=view&reset=1&cid='.$row['cid']).'>'.$row['name'].'</a>';
 +        $row['name'] = '<a class="view-contact" title="' . ts('View Contact') . '" href=' . CRM_Utils_System::url('civicrm/contact/view',
 +            'action=view&reset=1&cid=' . $row['cid']) . '>' . $row['name'] . '</a>';
        }
        // email column links/icon
        if ($row['email']) {
 -        $row['email'] = '<a class="crm-hover-button crm-popup" href="'.CRM_Utils_System::url('civicrm/activity/email/add', 'reset=1&action=add&atype=3&cid='.$row['cid']).'&caseid='.$caseID.'" title="'. ts('Send an Email') . '"><span class="icon email-icon"></span></a>';
 +        $row['email'] = '<a class="crm-hover-button crm-popup" href="' . CRM_Utils_System::url('civicrm/activity/email/add', 'reset=1&action=add&atype=3&cid=' . $row['cid']) . '&caseid=' . $caseID . '" title="' . ts('Send an Email') . '"><span class="icon ui-icon-mail-closed"></span></a>';
        }
        // edit links
        $row['actions'] = '';
        if ($hasAccessToAllCases) {
          $contactType = empty($row['relation_type']) ? '' : (string) CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', $row['relation_type'], 'contact_type_b');
          $contactType = $contactType == 'Contact' ? '' : $contactType;
 -        switch($row['source']) {
 -        case 'caseRel':
 -          $row['actions'] =
 -            '<a href="#editCaseRoleDialog" title="'. ts('Reassign %1', array(1 => $typeLabel)) .'" class="crm-hover-button case-miniform" data-contact_type="' . $contactType . '" data-rel_type="'. $row['relation_type'] .'" data-rel_id="'. $row['rel_id'] .'"data-key="'. CRM_Core_Key::get('civicrm/ajax/relation') .'">'.
 -              '<span class="icon edit-icon"></span>'.
 -            '</a>'.
 -            '<a href="#deleteCaseRoleDialog" title="'. ts('Remove %1', array(1 => $typeLabel)) .'" class="crm-hover-button case-miniform" data-contact_type="' . $contactType . '" data-rel_type="'.$row['relation_type'].'" data-key="'. CRM_Core_Key::get('civicrm/ajax/delcaserole') .'">'.
 -              '<span class="icon delete-icon"></span>'.
 -            '</a>';
 -          break;
 -
 -        case 'caseRoles':
 -          $row['actions'] =
 -            '<a href="#editCaseRoleDialog" title="'. ts('Assign %1', array(1 => $typeLabel)) .'" class="crm-hover-button case-miniform" data-contact_type="' . $contactType . '" data-rel_type="'. $row['relation_type'] .'" data-key="'. CRM_Core_Key::get('civicrm/ajax/relation') .'">'.
 -              '<span class="icon edit-icon"></span>'.
 -            '</a>';
 -          break;
 +        switch ($row['source']) {
 +          case 'caseRel':
 +            $row['actions']
 +              = '<a href="#editCaseRoleDialog" title="' . ts('Reassign %1', array(1 => $typeLabel)) . '" class="crm-hover-button case-miniform" data-contact_type="' . $contactType . '" data-rel_type="' . $row['relation_type'] . '" data-rel_id="' . $row['rel_id'] . '"data-key="' . CRM_Core_Key::get('civicrm/ajax/relation') . '">' .
 +              '<span class="icon ui-icon-pencil"></span>' .
 +              '</a>' .
 +              '<a href="#deleteCaseRoleDialog" title="' . ts('Remove %1', array(1 => $typeLabel)) . '" class="crm-hover-button case-miniform" data-contact_type="' . $contactType . '" data-rel_type="' . $row['relation_type'] . '" data-key="' . CRM_Core_Key::get('civicrm/ajax/delcaserole') . '">' .
 +              '<span class="icon delete-icon"></span>' .
 +              '</a>';
 +            break;
 +
 +          case 'caseRoles':
 +            $row['actions']
 +              = '<a href="#editCaseRoleDialog" title="' . ts('Assign %1', array(1 => $typeLabel)) . '" class="crm-hover-button case-miniform" data-contact_type="' . $contactType . '" data-rel_type="' . $row['relation_type'] . '" data-key="' . CRM_Core_Key::get('civicrm/ajax/relation') . '">' .
 +              '<span class="icon ui-icon-pencil"></span>' .
 +              '</a>';
 +            break;
          }
        }
        $idx++;
      $iFilteredTotal = $iTotal = $params['total'] = count($allCaseRelationships);
      $selectorElements = array('relation', 'name', 'phone', 'email', 'actions');
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($caseRelationships, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
  
 -  static function convertToCaseActivity() {
 +  public static function convertToCaseActivity() {
      $params = array('caseID', 'activityID', 'contactID', 'newSubject', 'targetContactIds', 'mode');
      $vals = array();
      foreach ($params as $param) {
    }
  
    /**
 -   * @param $params
 +   * @param array $params
     *
     * @return array
     */
 -  static function _convertToCaseActivity($params) {
 +  public static function _convertToCaseActivity($params) {
      if (!$params['activityID'] || !$params['caseID']) {
        return (array('error_msg' => 'required params missing.'));
      }
       */
  
      if (in_array($params['mode'], array(
 -      'move', 'file'))) {
 +      'move',
 +      'file',
 +    ))) {
        $caseActivity = new CRM_Case_DAO_CaseActivity();
        $caseActivity->case_id = $params['caseID'];
        $caseActivity->activity_id = $otherActivity->id;
        }
        else {
          $otherActivity->subject = ts('(Filed on case %1)', array(
 -            1 => $params['caseID']
 +            1 => $params['caseID'],
            )) . ' ' . $otherActivity->subject;
        }
        $otherActivity->activity_date_time = $actDateTime;
      $src_params = array(
        'activity_id' => $mainActivityId,
        'contact_id' => $sourceContactID,
 -      'record_type_id' => $sourceID
 +      'record_type_id' => $sourceID,
      );
      CRM_Activity_BAO_ActivityContact::create($src_params);
  
        $targ_params = array(
          'activity_id' => $mainActivityId,
          'contact_id' => $value,
 -        'record_type_id' => $targetID
 +        'record_type_id' => $targetID,
        );
        CRM_Activity_BAO_ActivityContact::create($targ_params);
      }
        $assigneeParams = array(
          'activity_id' => $mainActivityId,
          'contact_id' => $value,
 -        'record_type_id' => $assigneeID
 +        'record_type_id' => $assigneeID,
        );
        CRM_Activity_BAO_ActivityContact::create($assigneeParams);
      }
      return (array('error_msg' => $error_msg, 'newId' => $mainActivity->id));
    }
  
 -  static function getContactActivity() {
 +  public static function getContactActivity() {
      $contactID = CRM_Utils_Type::escape($_POST['contact_id'], 'Integer');
      $context = CRM_Utils_Type::escape(CRM_Utils_Array::value('context', $_GET), 'String');
  
      // get the contact activities
      $activities = CRM_Activity_BAO_Activity::getContactActivitySelector($params);
  
 +    foreach ($activities as $key => $value) {
 +      //Check if recurring activity
 +      if (!empty($value['is_recurring_activity'])) {
 +        if ($key == $value['is_recurring_activity']) {
 +          $activities[$key]['activity_type'] = $activities[$key]['activity_type'] . '<br/><span class="bold">Recurring Activity - (Parent)</span>';
 +        }
 +        else {
 +          $activities[$key]['activity_type'] = $activities[$key]['activity_type'] . '<br/><span class="bold">Recurring Activity - (Child)</span>';
 +        }
 +      }
 +    }
 +
      // store the activity filter preference CRM-11761
      $session = CRM_Core_Session::singleton();
      $userID = $session->get('userID');
          $domainID,
          TRUE
        );
 -      if ( $cacheKey ) {
 +      if ($cacheKey) {
          CRM_Core_BAO_Setting::flushCache($cacheKey);
        }
  
        $activityFilter = array(
 -        'activity_type_filter_id' => empty($params['activity_type_id']) ? '' :
 -          CRM_Utils_Type::escape($params['activity_type_id'], 'Integer'),
 -        'activity_type_exclude_filter_id' => empty($params['activity_type_exclude_id']) ? '' :
 -          CRM_Utils_Type::escape($params['activity_type_exclude_id'], 'Integer'),
 +        'activity_type_filter_id' => empty($params['activity_type_id']) ? '' : CRM_Utils_Type::escape($params['activity_type_id'], 'Integer'),
 +        'activity_type_exclude_filter_id' => empty($params['activity_type_exclude_id']) ? '' : CRM_Utils_Type::escape($params['activity_type_exclude_id'], 'Integer'),
        );
  
        CRM_Core_BAO_Setting::setItem(
  
      $iFilteredTotal = $iTotal = $params['total'];
      $selectorElements = array(
 -      'activity_type', 'subject', 'source_contact',
 -      'target_contact', 'assignee_contact',
 -      'activity_date', 'status','links', 'class',
 +      'activity_type',
 +      'subject',
 +      'source_contact',
 +      'target_contact',
 +      'assignee_contact',
 +      'activity_date',
 +      'status',
 +      'links',
 +      'class',
      );
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($activities, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
 -}
  
 +}
diff --combined CRM/Batch/Page/AJAX.php
index 6c66b66bd2e940f561e6f03ecd0965b8596a9356,238a0514d6ec007b78f764ec12ee761b67665de9..0bea0dcb5296468715c01bc77e60d2823577fdb1
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -39,9 -39,9 +39,9 @@@
  class CRM_Batch_Page_AJAX {
  
    /**
 -   * Save record
 +   * Save record.
     */
 -  function batchSave() {
 +  public function batchSave() {
      // save the entered information in 'data' column
      $batchId = CRM_Utils_Type::escape($_POST['batch_id'], 'Positive');
  
@@@ -52,9 -52,9 +52,9 @@@
    }
  
    /**
 -   * Retrieve records
 +   * Retrieve records.
     */
 -  static function getBatchList() {
 +  public static function getBatchList() {
      $sortMapper = array(
        0 => 'batch.title',
        1 => 'batch.type_id',
        5 => '',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    =
 -      isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  =
 -      isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      =
 -      isset($_REQUEST['iSortCol_0']) ?
 -      CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) :
 -      NULL;
 -    $sortOrder =
 -      isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
 -    $context   =
 -      isset($_REQUEST['context']) ? CRM_Utils_Type::escape($_REQUEST['context'], 'String') : NULL;
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +    $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
 +    $context = isset($_REQUEST['context']) ? CRM_Utils_Type::escape($_REQUEST['context'], 'String') : NULL;
  
      $params = $_REQUEST;
      if ($sort && $sortOrder) {
@@@ -81,7 -88,7 +81,7 @@@
  
      if ($context != 'financialBatch') {
        // data entry status batches
 -      $params['status_id'] = CRM_Core_OptionGroup::getValue('batch_status','Data Entry', 'name');
 +      $params['status_id'] = CRM_Core_OptionGroup::getValue('batch_status', 'Data Entry', 'name');
      }
  
      $params['context'] = $context;
          'links',
        );
      }
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($batches, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
 -}
  
 +}
index 0d7b5e2f8897c92318d25e50d0c232bb89ea1353,1387b2f3ccfc6c49125461e856208d71c9fcfc20..79a47cc4defcf75f1e62156f0c081da450934c0a
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
@@@ -37,7 -37,7 +37,7 @@@
   */
  class CRM_Campaign_Page_AJAX {
  
 -  static function registerInterview() {
 +  public static function registerInterview() {
      $fields = array(
        'result',
        'voter_id',
@@@ -53,8 -53,8 +53,8 @@@
        $params[$fld] = CRM_Utils_Array::value($fld, $_POST);
      }
      $params['details'] = CRM_Utils_Array::value('note', $_POST);
 -    $voterId           = $params['voter_id'];
 -    $activityId        = $params['activity_id'];
 +    $voterId = $params['voter_id'];
 +    $activityId = $params['activity_id'];
  
      $customKey = "field_{$voterId}_custom";
      foreach ($_POST as $key => $value) {
      CRM_Utils_JSON::output($result);
    }
  
 -  static function loadOptionGroupDetails() {
 +  public static function loadOptionGroupDetails() {
  
 -    $id       = CRM_Utils_Array::value('option_group_id', $_POST);
 -    $status   = 'fail';
 +    $id = CRM_Utils_Array::value('option_group_id', $_POST);
 +    $status = 'fail';
      $opValues = array();
  
      if ($id) {
  
      $surveyId = CRM_Utils_Array::value('survey_id', $_POST);
      if ($surveyId) {
 -      $survey            = new CRM_Campaign_DAO_Survey();
 -      $survey->id        = $surveyId;
 +      $survey = new CRM_Campaign_DAO_Survey();
 +      $survey->id = $surveyId;
        $survey->result_id = $id;
        if ($survey->find(TRUE)) {
          if ($survey->recontact_interval) {
      CRM_Utils_JSON::output($result);
    }
  
 -  function voterList() {
 +  public function voterList() {
      //get the search criteria params.
      $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST));
  
  
      //format multi-select group and contact types.
      foreach (array(
 -      'group', 'contact_type') as $param) {
 +               'group',
 +               'contact_type',
 +             ) as $param) {
        $paramValue = CRM_Utils_Array::value($param, $params);
        if ($paramValue) {
          unset($params[$param]);
  
      $voterClauseParams = array();
      foreach (array(
 -      'campaign_survey_id', 'survey_interviewer_id', 'campaign_search_voter_for') as $fld) {
 +               'campaign_survey_id',
 +               'survey_interviewer_id',
 +               'campaign_search_voter_for',
 +             ) as $fld) {
        $voterClauseParams[$fld] = CRM_Utils_Array::value($fld, $params);
      }
  
          $groups = CRM_Utils_Array::value('group', $params);
          if ($campaignId && CRM_Utils_System::isNull($groups)) {
            $campaignGroups = CRM_Campaign_BAO_Campaign::getCampaignGroups($campaignId);
 -          foreach ($campaignGroups as $id => $group) $params['group'][$id] = 1;
 +          foreach ($campaignGroups as $id => $group) {
 +            $params['group'][$id] = 1;
 +          }
          }
  
          //apply filter of survey contact type for search.
  
      // get the data table params.
      $dataTableParams = array(
 -      'sEcho' => array('name' => 'sEcho',
 +      'sEcho' => array(
 +        'name' => 'sEcho',
          'type' => 'Integer',
          'default' => 0,
        ),
        $$pName = $pValues['default'];
        if (!empty($_POST[$pValues['name']])) {
          $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']);
 -        if ($pName == 'sort')$$pName = $selectorCols[$$pName];
 +        if ($pName == 'sort') {
 +          $$pName = $selectorCols[$$pName];
 +        }
        }
      }
  
      $iTotal = $searchCount;
  
      $selectorCols = array(
 -      'contact_type', 'sort_name', 'street_address',
 -      'street_name', 'street_number', 'street_unit',
 +      'contact_type',
 +      'sort_name',
 +      'street_address',
 +      'street_name',
 +      'street_number',
 +      'street_unit',
      );
  
      $extraVoterColName = 'is_interview_conducted';
        );
        while ($result->fetch()) {
          $contactID = $result->contact_id;
 -        $typeImage = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ?
 -          $result->contact_sub_type : $result->contact_type,
 +        $typeImage = CRM_Contact_BAO_Contact_Utils::getImage($result->contact_sub_type ? $result->contact_sub_type : $result->contact_type,
            FALSE,
            $result->contact_id
          );
            $voterExtraColHtml .= "&nbsp;<span id='success_msg_{$contactID}' class='ok' style='display:none;'>$msg</span>";
          }
          elseif ($searchVoterFor == 'gotv') {
 -          $surveyActId       = $result->survey_activity_id;
 +          $surveyActId = $result->survey_activity_id;
            $voterExtraColHtml = '<input type="checkbox" id="survey_activity[' . $surveyActId . ']" name="survey_activity[' . $surveyActId . ']" value=' . $surveyActId . ' onClick="processVoterData( this, \'gotv\' );" />';
 -          $msg               = ts('Vote Recorded');
 +          $msg = ts('Vote Recorded.');
            $voterExtraColHtml .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span id='success_msg_{$surveyActId}' class='ok' style='display:none;'>$msg</span>";
          }
          else {
 -          $surveyActId       = $result->survey_activity_id;
 +          $surveyActId = $result->survey_activity_id;
            $voterExtraColHtml = '<input type="checkbox" id="survey_activity[' . $surveyActId . ']" name="survey_activity[' . $surveyActId . ']" value=' . $surveyActId . ' onClick="processVoterData( this, \'release\' );" />';
 -          $msg               = ts('Vote Recorded');
 +          $msg = ts('Vote Recorded.');
            $voterExtraColHtml .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span id='success_msg_{$surveyActId}' class='ok' style='display:none;'>$msg</span>";
          }
          $searchRows[$contactID][$extraVoterColName] = $voterExtraColHtml;
  
      $iFilteredTotal = $iTotal;
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
  
 -  function processVoterData() {
 +  public function processVoterData() {
      $status = NULL;
      $operation = CRM_Utils_Type::escape($_POST['operation'], 'String');
      if ($operation == 'release') {
          }
        }
        if ($createActivity) {
 -        $isReserved        = CRM_Utils_String::strtoboolstr(CRM_Utils_Type::escape($_POST['isReserved'], 'String'));
 -        $activityStatus    = CRM_Core_PseudoConstant::activityStatus('name');
 +        $isReserved = CRM_Utils_String::strtoboolstr(CRM_Utils_Type::escape($_POST['isReserved'], 'String'));
 +        $activityStatus = CRM_Core_PseudoConstant::activityStatus('name');
          $scheduledStatusId = array_search('Scheduled', $activityStatus);
          if ($isReserved) {
            $surveyValues = array();
      CRM_Utils_JSON::output(array('status' => $status));
    }
  
 -  function allActiveCampaigns() {
 +  public function allActiveCampaigns() {
      $currentCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns();
 -    $campaigns        = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, TRUE, FALSE, TRUE);
 -    $options          = array(
 -      array('value' => '',
 +    $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, TRUE, FALSE, TRUE);
 +    $options = array(
 +      array(
 +        'value' => '',
          'title' => ts('- select -'),
 -      ));
 +      ),
 +    );
      foreach ($campaigns as $value => $title) {
        $class = NULL;
        if (!array_key_exists($value, $currentCampaigns)) {
      CRM_Utils_JSON::output($results);
    }
  
 -  function campaignGroups() {
 +  public function campaignGroups() {
      $surveyId = CRM_Utils_Request::retrieve('survey_id', 'Positive',
        CRM_Core_DAO::$_nullObject, FALSE, NULL, 'POST'
      );
        $campGroups = CRM_Core_PseudoConstant::group();
      }
      $groups = array(
 -      array('value' => '',
 +      array(
 +        'value' => '',
          'title' => ts('- select -'),
 -      ));
 +      ),
 +    );
      foreach ($campGroups as $grpId => $title) {
        $groups[] = array(
          'value' => $grpId,
    /**
     * Retrieve campaigns as for campaign dashboard.
     *
 -   **/
 -  function campaignList() {
 +   */
 +  public function campaignList() {
      //get the search criteria params.
      $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST));
  
  
      // get the data table params.
      $dataTableParams = array(
 -      'sEcho' => array('name' => 'sEcho',
 +      'sEcho' => array(
 +        'name' => 'sEcho',
          'type' => 'Integer',
          'default' => 0,
        ),
        }
      }
      foreach (array(
 -      'sort', 'offset', 'rowCount', 'sortOrder') as $sortParam) {
 +               'sort',
 +               'offset',
 +               'rowCount',
 +               'sortOrder',
 +             ) as $sortParam) {
        $params[$sortParam] = $$sortParam;
      }
  
      $searchCount = CRM_Campaign_BAO_Campaign::getCampaignSummary($params, TRUE);
 -    $campaigns   = CRM_Campaign_Page_DashBoard::getCampaignSummary($params);
 -    $iTotal      = $searchCount;
 +    $campaigns = CRM_Campaign_Page_DashBoard::getCampaignSummary($params);
 +    $iTotal = $searchCount;
  
      if ($searchCount > 0) {
        if ($searchCount < $offset) {
  
      $iFilteredTotal = $iTotal;
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
    /**
     * Retrieve survey for survey dashboard.
     *
 -   **/
 -  function surveyList() {
 +   */
 +  public function surveyList() {
      //get the search criteria params.
      $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST));
  
  
      // get the data table params.
      $dataTableParams = array(
 -      'sEcho' => array('name' => 'sEcho',
 +      'sEcho' => array(
 +        'name' => 'sEcho',
          'type' => 'Integer',
          'default' => 0,
        ),
        }
      }
      foreach (array(
 -      'sort', 'offset', 'rowCount', 'sortOrder') as $sortParam) {
 +               'sort',
 +               'offset',
 +               'rowCount',
 +               'sortOrder',
 +             ) as $sortParam) {
        $params[$sortParam] = $$sortParam;
      }
  
 -    $surveys     = CRM_Campaign_Page_DashBoard::getSurveySummary($params);
 +    $surveys = CRM_Campaign_Page_DashBoard::getSurveySummary($params);
      $searchCount = CRM_Campaign_BAO_Survey::getSurveySummary($params, TRUE);
 -    $iTotal      = $searchCount;
 +    $iTotal = $searchCount;
  
      if ($searchCount > 0) {
        if ($searchCount < $offset) {
  
      $iFilteredTotal = $iTotal;
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
    /**
     * Retrieve petitions for petition dashboard.
     *
 -   **/
 -  function petitionList() {
 +   */
 +  public function petitionList() {
      //get the search criteria params.
      $searchParams = explode(',', CRM_Utils_Array::value('searchCriteria', $_POST));
  
  
      // get the data table params.
      $dataTableParams = array(
 -      'sEcho' => array('name' => 'sEcho',
 +      'sEcho' => array(
 +        'name' => 'sEcho',
          'type' => 'Integer',
          'default' => 0,
        ),
        }
      }
      foreach (array(
 -      'sort', 'offset', 'rowCount', 'sortOrder') as $sortParam) {
 +               'sort',
 +               'offset',
 +               'rowCount',
 +               'sortOrder',
 +             ) as $sortParam) {
        $params[$sortParam] = $$sortParam;
      }
  
 -    $petitions   = CRM_Campaign_Page_DashBoard::getPetitionSummary($params);
 +    $petitions = CRM_Campaign_Page_DashBoard::getPetitionSummary($params);
      $searchCount = CRM_Campaign_BAO_Petition::getPetitionSummary($params, TRUE);
 -    $iTotal      = $searchCount;
 +    $iTotal = $searchCount;
  
      if ($searchCount > 0) {
        if ($searchCount < $offset) {
  
      $iFilteredTotal = $iTotal;
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
 -}
  
 +}
index 26c4fc749874b7aba067d75e7582cd6bd182e077,21dbe7ef0d6dcab09fa45daff59281b9f8695aa0..0da9dd3698176d151dc5572bf41880b3e15d1e9e
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
@@@ -46,68 -46,11 +46,11 @@@ class CRM_Contact_Page_AJAX 
    const AUTOCOMPLETE_TTL = 21600; // 6hr; 6*60*60
  
    /**
-    * @deprecated
-    */
-   public static function getContactList() {
-     // if context is 'customfield'
-     if (CRM_Utils_Array::value('context', $_GET) == 'customfield') {
-       return self::contactReference();
-     }
-     $params = array('version' => 3, 'check_permissions' => TRUE);
-     // String params
-     // FIXME: param keys don't match input keys, using this array to translate
-     $whitelist = array(
-       's' => 'name',
-       'fieldName' => 'field_name',
-       'tableName' => 'table_name',
-       'context' => 'context',
-       'rel' => 'rel',
-       'contact_sub_type' => 'contact_sub_type',
-       'contact_type' => 'contact_type',
-     );
-     foreach ($whitelist as $key => $param) {
-       if (!empty($_GET[$key])) {
-         $params[$param] = $_GET[$key];
-       }
-     }
-     //CRM-10687: Allow quicksearch by multiple fields
-     if (!empty($params['field_name'])) {
-       if ($params['field_name'] == 'phone_numeric') {
-         $params['name'] = preg_replace('/[^\d]/', '', $params['name']);
-       }
-       if (!$params['name']) {
-         CRM_Utils_System::civiExit();
-       }
-     }
-     // Numeric params
-     $whitelist = array(
-       'limit',
-       'org',
-       'employee_id',
-       'cid',
-       'id',
-       'cmsuser',
-     );
-     foreach ($whitelist as $key) {
-       if (!empty($_GET[$key]) && is_numeric($_GET[$key])) {
-         $params[$key] = $_GET[$key];
-       }
-     }
-     $result = civicrm_api('Contact', 'getquick', $params);
-     CRM_Core_Page_AJAX::autocompleteResults(CRM_Utils_Array::value('values', $result), 'data');
-   }
-   /**
-    * Ajax callback for custom fields of type ContactReference.
+    * Ajax callback for custom fields of type ContactReference
     *
     * Todo: Migrate contact reference fields to use EntityRef
     */
 -  static function contactReference() {
 +  public static function contactReference() {
      $name = CRM_Utils_Array::value('term', $_GET);
      $name = CRM_Utils_Type::escape($name, 'String');
      $cfID = CRM_Utils_Type::escape($_GET['id'], 'Positive');
      }
  
      $list = array_keys(CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
 -        'contact_reference_options'
 -      ), '1');
 +      'contact_reference_options'
 +    ), '1');
  
      $return = array_unique(array_merge(array('sort_name'), $list));
  
      }
  
      if (!empty($action)) {
 -      $excludeGet = array('reset', 'key', 'className', 'fnName', 'json', 'reset', 'context', 'timestamp', 'limit', 'id', 's', 'q', 'action');
 +      $excludeGet = array(
 +        'reset',
 +        'key',
 +        'className',
 +        'fnName',
 +        'json',
 +        'reset',
 +        'context',
 +        'timestamp',
 +        'limit',
 +        'id',
 +        's',
 +        'q',
 +        'action',
 +      );
        foreach ($_GET as $param => $val) {
          if (empty($val) ||
            in_array($param, $excludeGet) ||
        $contactList[] = array('id' => $value['id'], 'text' => implode(' :: ', $view));
      }
  
-     CRM_Utils_System::civiExit(json_encode($contactList));
+     CRM_Utils_JSON::output($contactList);
    }
  
    /**
 -   * Function to fetch PCP ID by PCP Supporter sort_name, also displays PCP title and associated Contribution Page title
 +   * Fetch PCP ID by PCP Supporter sort_name, also displays PCP title and associated Contribution Page title
     */
 -  static function getPCPList() {
 -    $name  = CRM_Utils_Array::value('term', $_GET);
 -    $name  = CRM_Utils_Type::escape($name, 'String');
 +  public static function getPCPList() {
 +    $name = CRM_Utils_Array::value('term', $_GET);
 +    $name = CRM_Utils_Type::escape($name, 'String');
      $limit = '10';
  
      $where = ' AND pcp.page_id = cp.id AND pcp.contact_id = cc.id';
      CRM_Utils_JSON::output($results);
    }
  
 -  static function relationship() {
 +  public static function relationship() {
      $relType = CRM_Utils_Request::retrieve('rel_type', 'Positive', CRM_Core_DAO::$_nullObject, TRUE);
      $relContactID = CRM_Utils_Request::retrieve('rel_contact', 'Positive', CRM_Core_DAO::$_nullObject, TRUE);
      $relationshipID = CRM_Utils_Array::value('rel_id', $_REQUEST); // this used only to determine add or update mode
  
      $ret = array('is_error' => 0);
  
 -    foreach($clientList as $sourceContactID) {
 +    foreach ($clientList as $sourceContactID) {
        $relationParams = array(
          'relationship_type_id' => $relType . '_a_b',
          'contact_check' => array($relContactID => 1),
          $caseRelationships->contact_id_a = $sourceContactID;
          $caseRelationships->find();
  
 -        while($caseRelationships->fetch()) {
 +        while ($caseRelationships->fetch()) {
            $relationIds['relationship'] = $caseRelationships->id;
            $relationIds['contactTarget'] = $relContactID;
          }
        }
  
        // create new or update existing relationship
 -      $return = CRM_Contact_BAO_Relationship::create($relationParams, $relationIds);
 +      $return = CRM_Contact_BAO_Relationship::createMultiple($relationParams, $relationIds);
  
        if (!empty($return[4][0])) {
          $relationshipID = $return[4][0];
          $ret = array(
            'is_error' => 1,
            'error_message' => ts('The relationship type definition for the case role is not valid for the client and / or staff contact types. You can review and edit relationship types at <a href="%1">Administer >> Option Lists >> Relationship Types</a>.',
 -            array(1 => CRM_Utils_System::url('civicrm/admin/reltype', 'reset=1')))
 +            array(1 => CRM_Utils_System::url('civicrm/admin/reltype', 'reset=1'))),
          );
        }
      }
    }
  
    /**
 -   * Function to fetch the custom field help
 +   * Fetch the custom field help.
     */
 -  static function customField() {
 -    $fieldId          = CRM_Utils_Type::escape($_REQUEST['id'], 'Integer');
 -    $params           = array('id' => $fieldId);
 +  public static function customField() {
 +    $fieldId = CRM_Utils_Type::escape($_REQUEST['id'], 'Integer');
 +    $params = array('id' => $fieldId);
      $returnProperties = array('help_pre', 'help_post');
 -    $values           = array();
 +    $values = array();
  
      CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomField', $params, $values, $returnProperties);
      CRM_Utils_JSON::output($values);
    }
  
 -  static function groupTree() {
 +  public static function groupTree() {
+     header('Content-Type: application/json');
      $gids = CRM_Utils_Type::escape($_GET['gids'], 'String');
      echo CRM_Contact_BAO_GroupNestingCache::json($gids);
      CRM_Utils_System::civiExit();
    }
  
-   /**
-    * @deprecated
-    * Old quicksearch function. No longer used in core.
-    * @todo: Remove this function and associated menu entry in CiviCRM 5
-    */
-   public static function search() {
-     $json = TRUE;
-     $name = CRM_Utils_Array::value('name', $_GET, '');
-     if (!array_key_exists('name', $_GET)) {
-       $name = CRM_Utils_Array::value('s', $_GET) . '%';
-       $json = FALSE;
-     }
-     $name = CRM_Utils_Type::escape($name, 'String');
-     $whereIdClause = '';
-     if (!empty($_GET['id'])) {
-       $json = TRUE;
-       if (is_numeric($_GET['id'])) {
-         $id = CRM_Utils_Type::escape($_GET['id'], 'Integer');
-         $whereIdClause = " AND civicrm_contact.id = {$id}";
-       }
-       else {
-         $name = $_GET['id'];
-       }
-     }
-     $elements = array();
-     if ($name || isset($id)) {
-       $name = $name . '%';
-       //contact's based of relationhip type
-       $relType = NULL;
-       if (isset($_GET['rel'])) {
-         $relation = explode('_', $_GET['rel']);
-         $relType = CRM_Utils_Type::escape($relation[0], 'Integer');
-         $rel = CRM_Utils_Type::escape($relation[2], 'String');
-       }
-       //shared household info
-       $shared = NULL;
-       if (isset($_GET['sh'])) {
-         $shared = CRM_Utils_Type::escape($_GET['sh'], 'Integer');
-         if ($shared == 1) {
-           $contactType = 'Household';
-           $cName = 'household_name';
-         }
-         else {
-           $contactType = 'Organization';
-           $cName = 'organization_name';
-         }
-       }
-       // contacts of type household
-       $hh = $addStreet = $addCity = NULL;
-       if (isset($_GET['hh'])) {
-         $hh = CRM_Utils_Type::escape($_GET['hh'], 'Integer');
-       }
-       //organization info
-       $organization = $street = $city = NULL;
-       if (isset($_GET['org'])) {
-         $organization = CRM_Utils_Type::escape($_GET['org'], 'Integer');
-       }
-       if (isset($_GET['org']) || isset($_GET['hh'])) {
-         $json = FALSE;
-         $splitName = explode(' :: ', $name);
-         if ($splitName) {
-           $contactName = trim(CRM_Utils_Array::value('0', $splitName));
-           $street = trim(CRM_Utils_Array::value('1', $splitName));
-           $city = trim(CRM_Utils_Array::value('2', $splitName));
-         }
-         else {
-           $contactName = $name;
-         }
-         if ($street) {
-           $addStreet = "AND civicrm_address.street_address LIKE '$street%'";
-         }
-         if ($city) {
-           $addCity = "AND civicrm_address.city LIKE '$city%'";
-         }
-       }
-       if ($organization) {
-         $query = "
- SELECT CONCAT_WS(' :: ',sort_name,LEFT(street_address,25),city) 'sort_name',
- civicrm_contact.id 'id'
- FROM civicrm_contact
- LEFT JOIN civicrm_address ON ( civicrm_contact.id = civicrm_address.contact_id
-                                 AND civicrm_address.is_primary=1
-                              )
- WHERE civicrm_contact.contact_type='Organization' AND organization_name LIKE '%$contactName%'
- {$addStreet} {$addCity} {$whereIdClause}
- ORDER BY organization_name ";
-       }
-       elseif ($shared) {
-         $query = "
- SELECT CONCAT_WS(':::' , sort_name, supplemental_address_1, sp.abbreviation, postal_code, cc.name )'sort_name' , civicrm_contact.id 'id' , civicrm_contact.display_name 'disp' FROM civicrm_contact LEFT JOIN civicrm_address ON (civicrm_contact.id =civicrm_address.contact_id AND civicrm_address.is_primary =1 )LEFT JOIN civicrm_state_province sp ON (civicrm_address.state_province_id =sp.id )LEFT JOIN civicrm_country cc ON (civicrm_address.country_id =cc.id )WHERE civicrm_contact.contact_type ='{$contactType}' AND {$cName} LIKE '%$name%' {$whereIdClause} ORDER BY {$cName} ";
-       }
-       elseif ($hh) {
-         $query = "
- SELECT CONCAT_WS(' :: ' , sort_name, LEFT(street_address,25),city) 'sort_name' , location_type_id 'location_type_id', is_primary 'is_primary', is_billing 'is_billing', civicrm_contact.id 'id'
- FROM civicrm_contact
- LEFT JOIN civicrm_address ON (civicrm_contact.id =civicrm_address.contact_id AND civicrm_address.is_primary =1 )
- WHERE civicrm_contact.contact_type ='Household'
- AND household_name LIKE '%$contactName%' {$addStreet} {$addCity} {$whereIdClause} ORDER BY household_name ";
-       }
-       elseif ($relType) {
-         if (!empty($_GET['case'])) {
-           $query = "
- SELECT distinct(c.id), c.sort_name
- FROM civicrm_contact c
- LEFT JOIN civicrm_relationship ON civicrm_relationship.contact_id_{$rel} = c.id
- WHERE c.sort_name LIKE '%$name%'
- AND civicrm_relationship.relationship_type_id = $relType
- GROUP BY sort_name
- ";
-         }
-       }
-       else {
-         $query = "
- SELECT sort_name, id
- FROM civicrm_contact
- WHERE sort_name LIKE '%$name'
- {$whereIdClause}
- ORDER BY sort_name ";
-       }
-       $limit = 10;
-       if (isset($_GET['limit'])) {
-         $limit = CRM_Utils_Type::escape($_GET['limit'], 'Positive');
-       }
-       $query .= " LIMIT 0,{$limit}";
-       $dao = CRM_Core_DAO::executeQuery($query);
-       if ($shared) {
-         while ($dao->fetch()) {
-           echo $dao->sort_name;
-           CRM_Utils_System::civiExit();
-         }
-       }
-       else {
-         while ($dao->fetch()) {
-           if ($json) {
-             $elements[] = array(
-               'name' => addslashes($dao->sort_name),
-               'id' => $dao->id,
-             );
-           }
-           else {
-             echo $elements = "$dao->sort_name|$dao->id|$dao->location_type_id|$dao->is_primary|$dao->is_billing\n";
-           }
-         }
-         //for adding new household address / organization
-         if (empty($elements) && !$json && ($hh || $organization)) {
-           echo CRM_Utils_Array::value('s', $_GET);
-         }
-       }
-     }
-     if (isset($_GET['sh'])) {
-       echo "";
-       CRM_Utils_System::civiExit();
-     }
-     if (empty($elements)) {
-       $name = str_replace('%', '', $name);
-       $elements[] = array(
-         'name' => $name,
-         'id' => $name,
-       );
-     }
-     if ($json) {
-       echo json_encode($elements);
-     }
-     CRM_Utils_System::civiExit();
-   }
    /**
 -   * Function to delete custom value
 -   *
 +   * Delete custom value.
     */
 -  static function deleteCustomValue() {
 +  public static function deleteCustomValue() {
+     header('Content-Type: text/plain');
      $customValueID = CRM_Utils_Type::escape($_REQUEST['valueID'], 'Positive');
      $customGroupID = CRM_Utils_Type::escape($_REQUEST['groupID'], 'Positive');
  
    }
  
    /**
 -   * Function to perform enable / disable actions on record.
 -   *
 +   *  check the CMS username.
     */
 -  static function enableDisable() {
 -    $op        = CRM_Utils_Type::escape($_REQUEST['op'], 'String');
 -    $recordID  = CRM_Utils_Type::escape($_REQUEST['recordID'], 'Positive');
 -    $recordBAO = CRM_Utils_Type::escape($_REQUEST['recordBAO'], 'String');
 -
 -    $isActive = NULL;
 -    if ($op == 'disable-enable') {
 -      $isActive = TRUE;
 -    }
 -    elseif ($op == 'enable-disable') {
 -      $isActive = FALSE;
 -    }
 -    $status = array('status' => 'record-updated-fail');
 -    if (isset($isActive)) {
 -      // first munge and clean the recordBAO and get rid of any non alpha numeric characters
 -      $recordBAO = CRM_Utils_String::munge($recordBAO);
 -      $recordClass = explode('_', $recordBAO);
 -
 -      // make sure recordClass is namespaced (we cant check CRM since extensions can also use this)
 -      // but it should be at least 3 levels deep
 -      if (count($recordClass) >= 3) {
 -        require_once (str_replace('_', DIRECTORY_SEPARATOR, $recordBAO) . ".php");
 -        $method = 'setIsActive';
 -
 -        if (method_exists($recordBAO, $method)) {
 -          $updated = call_user_func_array(array($recordBAO, $method),
 -            array($recordID, $isActive)
 -          );
 -          if ($updated) {
 -            $status = array('status' => 'record-updated-success');
 -          }
 -
 -          // call hook enableDisable
 -          CRM_Utils_Hook::enableDisable($recordBAO, $recordID, $isActive);
 -        }
 -      }
 -      CRM_Utils_JSON::output($status);
 -    }
 -  }
 -
 -  /**
 -     *Function to check the CMS username
 -     *
 -    */
    static public function checkUserName() {
      $signer = new CRM_Utils_Signer(CRM_Core_Key::privateKey(), array('for', 'ts'));
      if (
        || !$signer->validate($_REQUEST['sig'], $_REQUEST)
      ) {
        $user = array('name' => 'error');
-       echo json_encode($user);
-       CRM_Utils_System::civiExit();
+       CRM_Utils_JSON::output($user);
      }
  
      $config = CRM_Core_Config::singleton();
      if (isset($errors['cms_name']) || isset($errors['name'])) {
        //user name is not availble
        $user = array('name' => 'no');
-       echo json_encode($user);
+       CRM_Utils_JSON::output($user);
      }
      else {
        //user name is available
        $user = array('name' => 'yes');
-       echo json_encode($user);
+       CRM_Utils_JSON::output($user);
      }
+     // Not reachable: JSON::output() above exits.
      CRM_Utils_System::civiExit();
    }
  
    /**
 -   *  Function to get email address of a contact
 +   *  Function to get email address of a contact.
     */
 -  static function getContactEmail() {
 +  public static function getContactEmail() {
      if (!empty($_REQUEST['contact_id'])) {
        $contactID = CRM_Utils_Type::escape($_REQUEST['contact_id'], 'Positive');
        if (!CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::EDIT)) {
        }
        list($displayName,
          $userEmail
 -      ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
 +        ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
+       header('Content-Type: text/plain');
        if ($userEmail) {
          echo $userEmail;
        }
          }
        }
        else {
 -              $cid = CRM_Utils_Array::value('cid', $_GET);
 -              if ($cid) {
 +        $cid = CRM_Utils_Array::value('cid', $_GET);
 +        if ($cid) {
            //check cid for interger
            $contIDS = explode(',', $cid);
            foreach ($contIDS as $contID) {
              CRM_Utils_Type::escape($contID, 'Integer');
            }
            $queryString = " cc.id IN ( $cid )";
 -              }
 +        }
        }
  
        if ($queryString) {
@@@ -680,10 -477,11 +445,10 @@@ LIMIT {$offset}, {$rowCount
              CRM_Utils_Array::value('cid', $_GET)
            );
  
 -
            $dao = CRM_Core_DAO::executeQuery($query);
  
            while ($dao->fetch()) {
 -              //working here
 +            //working here
              $result[] = array(
                'text' => '"' . $dao->name . '" <' . $dao->email . '>',
                'id' => (CRM_Utils_Array::value('id', $_GET)) ? "{$dao->id}::{$dao->email}" : '"' . $dao->name . '" <' . $dao->email . '>',
            }
          }
          if ($result) {
-           echo json_encode($result);
+           CRM_Utils_JSON::output($result);
          }
        }
      }
      CRM_Utils_System::civiExit();
    }
  
 -  static function getContactPhone() {
 +  public static function getContactPhone() {
  
      $queryString = NULL;
      //check for mobile type
        $queryString = " ( cc.sort_name LIKE '%$name%' OR cp.phone LIKE '%$name%' ) ";
      }
      else {
 -      $cid = CRM_Utils_Array::value('cid', $_GET);
 -      if ($cid) {
 +      $cid = CRM_Utils_Array::value('cid', $_GET);
 +      if ($cid) {
          //check cid for interger
          $contIDS = explode(',', $cid);
          foreach ($contIDS as $contID) {
@@@ -762,13 -560,13 +527,13 @@@ LIMIT {$offset}, {$rowCount
      }
  
      if ($result) {
-       echo json_encode($result);
+       CRM_Utils_JSON::output($result);
      }
      CRM_Utils_System::civiExit();
    }
  
  
 -  static function buildSubTypes() {
 +  public static function buildSubTypes() {
      $parent = CRM_Utils_Array::value('parentId', $_REQUEST);
  
      switch ($parent) {
      CRM_Utils_JSON::output($subTypes);
    }
  
 -  static function buildDedupeRules() {
 +  public static function buildDedupeRules() {
      $parent = CRM_Utils_Array::value('parentId', $_REQUEST);
  
      switch ($parent) {
    }
  
    /**
 -   * Function used for CiviCRM dashboard operations
 +   * Function used for CiviCRM dashboard operations.
     */
 -  static function dashboard() {
 +  public static function dashboard() {
      $operation = CRM_Utils_Type::escape($_REQUEST['op'], 'String');
  
      switch ($operation) {
    }
  
    /**
 -   * Function to retrieve signature based on email id
 +   * Retrieve signature based on email id.
     */
 -  static function getSignature() {
 +  public static function getSignature() {
      $emailID = CRM_Utils_Type::escape($_REQUEST['emailID'], 'Positive');
 -    $query   = "SELECT signature_text, signature_html FROM civicrm_email WHERE id = {$emailID}";
 -    $dao     = CRM_Core_DAO::executeQuery($query);
 +    $query = "SELECT signature_text, signature_html FROM civicrm_email WHERE id = {$emailID}";
 +    $dao = CRM_Core_DAO::executeQuery($query);
  
      $signatures = array();
      while ($dao->fetch()) {
    }
  
    /**
 -   * Function to process dupes.
 -   *
 +   * Process dupes.
     */
 -  static function processDupes() {
 +  public static function processDupes() {
      $oper = CRM_Utils_Type::escape($_REQUEST['op'], 'String');
 -    $cid  = CRM_Utils_Type::escape($_REQUEST['cid'], 'Positive');
 -    $oid  = CRM_Utils_Type::escape($_REQUEST['oid'], 'Positive');
 +    $cid = CRM_Utils_Type::escape($_REQUEST['cid'], 'Positive');
 +    $oid = CRM_Utils_Type::escape($_REQUEST['oid'], 'Positive');
  
      if (!$oper || !$cid || !$oid) {
        return;
      CRM_Utils_JSON::output(array('status' => ($status) ? $oper : $status));
    }
  
 -  static function getDedupes() {
 +  public static function getDedupes() {
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = 'sort_name';
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = 'sort_name';
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
 -    $gid         = isset($_REQUEST['gid']) ? CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer') : 0;
 -    $rgid        = isset($_REQUEST['rgid']) ? CRM_Utils_Type::escape($_REQUEST['rgid'], 'Integer') : 0;
 +    $gid = isset($_REQUEST['gid']) ? CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer') : 0;
 +    $rgid = isset($_REQUEST['rgid']) ? CRM_Utils_Type::escape($_REQUEST['rgid'], 'Integer') : 0;
      $contactType = '';
      if ($rgid) {
        $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type');
      }
  
 -    $cacheKeyString   = "merge {$contactType}_{$rgid}_{$gid}";
 -    $searchRows       = array();
 +    $cacheKeyString = "merge {$contactType}_{$rgid}_{$gid}";
 +    $searchRows = array();
      $selectorElements = array('src', 'dst', 'weight', 'actions');
  
 -
      $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND
                                                               pn.entity_id2 = de.contact_id2 )";
      $where = "de.id IS NULL";
            $mergeParams .= "&gid={$gid}";
          }
  
 -        $searchRows[$mainId]['actions'] = CRM_Utils_System::href(ts('merge'), 'civicrm/contact/merge', $mergeParams);
 -        $searchRows[$mainId]['actions'] .= "&nbsp;|&nbsp; <a id='notDuplicate' href='#' onClick=\"processDupes( {$main['srcID']}, {$main['dstID']}, 'dupe-nondupe', 'dupe-listing'); return false;\">" . ts('not a duplicate') . "</a>";
 +        $searchRows[$mainId]['actions'] = '<a class="action-item crm-hover-button" href="' . CRM_Utils_System::url('civicrm/contact/merge', $mergeParams) . '">' . ts('merge') . '</a>';
 +        $searchRows[$mainId]['actions'] .= "<a class='action-item crm-hover-button crm-notDuplicate' href='#' onClick=\"processDupes( {$main['srcID']}, {$main['dstID']}, 'dupe-nondupe', 'dupe-listing'); return false;\">" . ts('not a duplicate') . "</a>";
        }
        else {
          $searchRows[$mainId]['actions'] = '<em>' . ts('Insufficient access rights - cannot merge') . '</em>';
        }
      }
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
  
      CRM_Utils_System::civiExit();
    }
  
    /**
 -   * Function to retrieve a PDF Page Format for the PDF Letter form
 +   * Retrieve a PDF Page Format for the PDF Letter form.
     */
 -  function pdfFormat() {
 +  public function pdfFormat() {
      $formatId = CRM_Utils_Type::escape($_REQUEST['formatId'], 'Integer');
  
      $pdfFormat = CRM_Core_BAO_PdfFormat::getById($formatId);
    }
  
    /**
 -   * Function to retrieve Paper Size dimensions
 +   * Retrieve Paper Size dimensions.
     */
 -  static function paperSize() {
 +  public static function paperSize() {
      $paperSizeName = CRM_Utils_Type::escape($_REQUEST['paperSizeName'], 'String');
  
      $paperSize = CRM_Core_BAO_PaperSize::getByName($paperSizeName);
      CRM_Utils_JSON::output($paperSize);
    }
  
 -  static function selectUnselectContacts() {
 -    $name         = CRM_Utils_Array::value('name', $_REQUEST);
 -    $cacheKey     = CRM_Utils_Array::value('qfKey', $_REQUEST);
 -    $state        = CRM_Utils_Array::value('state', $_REQUEST, 'checked');
 +  /**
 +   * Used to store selected contacts across multiple pages in advanced search.
 +   */
 +  public static function selectUnselectContacts() {
 +    $name = CRM_Utils_Array::value('name', $_REQUEST);
 +    $cacheKey = CRM_Utils_Array::value('qfKey', $_REQUEST);
 +    $state = CRM_Utils_Array::value('state', $_REQUEST, 'checked');
      $variableType = CRM_Utils_Array::value('variableType', $_REQUEST, 'single');
  
      $actionToPerform = CRM_Utils_Array::value('action', $_REQUEST, 'select');
    }
  
    /**
 -   * @param $name
 +   * @param string $name
     *
     * @return string
     */
 -  static function _convertToId($name) {
 +  public static function _convertToId($name) {
      if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) {
        $cId = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
      }
      return $cId;
    }
  
 -  static function getAddressDisplay() {
 +  public static function getAddressDisplay() {
      $contactId = CRM_Utils_Array::value('contact_id', $_REQUEST);
      if (!$contactId) {
        $addressVal["error_message"] = "no contact id found";
      }
      else {
 -      $entityBlock =
 -        array(
 -          'contact_id' => $contactId,
 -          'entity_id' => $contactId,
 -        );
 +      $entityBlock = array(
 +        'contact_id' => $contactId,
 +        'entity_id' => $contactId,
 +      );
        $addressVal = CRM_Core_BAO_Address::getValues($entityBlock);
      }
  
    }
  
    /**
 -   * Function to retrieve contact relationships
 +   * Retrieve contact relationships.
     */
    public static function getContactRelationships() {
      $contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer');
      $context = CRM_Utils_Type::escape($_GET['context'], 'String');
 +    $relationship_type_id = CRM_Utils_Type::escape($_GET['relationship_type_id'], 'Integer', FALSE);
  
      if (!CRM_Contact_BAO_Contact_Permission::allow($contactID)) {
        return CRM_Utils_System::permissionDenied();
        10 => '',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
      $params = $_POST;
  
      $params['contact_id'] = $contactID;
      $params['context'] = $context;
 +    if ($relationship_type_id) {
 +      $params['relationship_type_id'] = $relationship_type_id;
 +    }
  
      // get the contact relationships
      $relationships = CRM_Contact_BAO_Relationship::getContactRelationshipSelector($params);
        'is_active',
      );
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($relationships, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
 +
  }
diff --combined CRM/Core/Form.php
index 1bf6a2f24d6c2159027b5f6b877f46ebc75cbb62,47303ba3b41849283824c71d1dc7aa02bf0fcf57..3b70af47c69f4118805d96baaf0d3abfc1d9a022
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   * This is our base form. It is part of the Form/Controller/StateMachine
@@@ -74,7 -74,7 +74,7 @@@ class CRM_Core_Form extends HTML_QuickF
    protected $_action;
  
    /**
 -   * the renderer used for this form
 +   * The renderer used for this form
     *
     * @var object
     */
@@@ -96,7 -96,7 +96,7 @@@
    protected $_dateFields = array();
  
    /**
 -   * cache the smarty template for efficiency reasons
 +   * Cache the smarty template for efficiency reasons
     *
     * @var CRM_Core_Smarty
     */
    public $controller;
  
    /**
 -   * constants for attributes for various form elements
 +   * Constants for attributes for various form elements
     * attempt to standardize on the number of variations that we
     * use of the below form elements
     *
     * @var const string
     */
 -  CONST ATTR_SPACING = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
 +  const ATTR_SPACING = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
  
    /**
     * All checkboxes are defined with a common prefix. This allows us to
     *
     * @var string|int
     */
 -  CONST CB_PREFIX = 'mark_x_', CB_PREFIY = 'mark_y_', CB_PREFIZ = 'mark_z_', CB_PREFIX_LEN = 7;
 +  const CB_PREFIX = 'mark_x_', CB_PREFIY = 'mark_y_', CB_PREFIZ = 'mark_z_', CB_PREFIX_LEN = 7;
  
    /**
     * @internal to keep track of chain-select fields
    private $_chainSelectFields = array();
  
    /**
 -   * Constructor for the basic form page
 +   * Constructor for the basic form page.
     *
     * We should not use QuickForm directly. This class provides a lot
     * of default convenient functions, rules and buttons
     *
 -   * @param object $state State associated with this form
 +   * @param object $state
 +   *   State associated with this form.
     * @param \const|\enum|int $action The mode the form is operating in (None/Create/View/Update/Delete)
 -   * @param string $method The type of http method used (GET/POST)
 -   * @param string $name The name of the form if different from class name
 +   * @param string $method
 +   *   The type of http method used (GET/POST).
 +   * @param string $name
 +   *   The name of the form if different from class name.
     *
     * @return \CRM_Core_Form
 -   * @access public
     */
 -  function __construct(
 +  public function __construct(
      $state = NULL,
      $action = CRM_Core_Action::NONE,
      $method = 'post',
 -    $name   = NULL
 +    $name = NULL
    ) {
  
      if ($name) {
      $this->assign('snippet', CRM_Utils_Array::value('snippet', $_GET));
    }
  
 -  static function generateID() {
 +  public static function generateID() {
    }
  
    /**
     * Add one or more css classes to the form
 -   * @param $className
 +   * @param string $className
     */
    public function addClass($className) {
      $classes = $this->getAttribute('class');
    }
  
    /**
 -   * register all the standard rules that most forms potentially use
 +   * Register all the standard rules that most forms potentially use.
     *
     * @return void
 -   * @access private
 -   *
     */
 -  function registerRules() {
 +  public function registerRules() {
      static $rules = array(
 -      'title', 'longTitle', 'variable', 'qfVariable',
 -      'phone', 'integer', 'query',
 -      'url', 'wikiURL',
 -      'domain', 'numberOfDigit',
 -      'date', 'currentDate',
 -      'asciiFile', 'htmlFile', 'utf8File',
 -      'objectExists', 'optionExists', 'postalCode', 'money', 'positiveInteger',
 -      'xssString', 'fileExists', 'autocomplete', 'validContact',
 +      'title',
 +      'longTitle',
 +      'variable',
 +      'qfVariable',
 +      'phone',
 +      'integer',
 +      'query',
 +      'url',
 +      'wikiURL',
 +      'domain',
 +      'numberOfDigit',
 +      'date',
 +      'currentDate',
 +      'asciiFile',
 +      'htmlFile',
 +      'utf8File',
 +      'objectExists',
 +      'optionExists',
 +      'postalCode',
 +      'money',
 +      'positiveInteger',
 +      'xssString',
 +      'fileExists',
 +      'autocomplete',
 +      'validContact',
      );
  
      foreach ($rules as $rule) {
     * @param string $label
     * @param string|array $attributes (options for select elements)
     * @param bool $required
 -   * @param array $extra (attributes for select elements)
 +   * @param array $extra
 +   *   (attributes for select elements).
     *
     * @return HTML_QuickForm_Element could be an error object
 -   * @access public
     */
 -  function &add($type, $name, $label = '',
 +  public function &add(
 +    $type, $name, $label = '',
      $attributes = '', $required = FALSE, $extra = NULL
    ) {
      if ($type == 'select' && is_array($extra)) {
    }
  
    /**
 -   * This function is called before buildForm. Any pre-processing that
 +   * called before buildForm. Any pre-processing that
     * needs to be done for buildForm should be done here
     *
     * This is a virtual function and should be redefined if needed
     *
 -   * @access public
     *
     * @return void
 -   *
     */
 -  function preProcess() {}
 +  public function preProcess() {
 +  }
  
    /**
 -   * This function is called after the form is validated. Any
 +   * called after the form is validated. Any
     * processing of form state etc should be done in this function.
     * Typically all processing associated with a form should be done
     * here and relevant state should be stored in the session
     *
     * This is a virtual function and should be redefined if needed
     *
 -   * @access public
     *
     * @return void
 -   *
     */
 -  function postProcess() {}
 +  public function postProcess() {
 +  }
  
    /**
 -   * This function is just a wrapper, so that we can call all the hook functions
 -   * @param bool $allowAjax - FIXME: This feels kind of hackish, ideally we would take the json-related code from this function
 +   * just a wrapper, so that we can call all the hook functions
 +   * @param bool $allowAjax
 +   *   FIXME: This feels kind of hackish, ideally we would take the json-related code from this function.
     *                          and bury it deeper down in the controller
     */
 -  function mainProcess($allowAjax = TRUE) {
 +  public function mainProcess($allowAjax = TRUE) {
      $this->postProcess();
      $this->postProcessHook();
  
      // Respond with JSON if in AJAX context (also support legacy value '6')
 -    if ($allowAjax && !empty($_REQUEST['snippet']) && in_array($_REQUEST['snippet'], array(CRM_Core_Smarty::PRINT_JSON, 6))) {
 +    if ($allowAjax && !empty($_REQUEST['snippet']) && in_array($_REQUEST['snippet'], array(
 +          CRM_Core_Smarty::PRINT_JSON,
 +          6,
 +        ))
 +    ) {
        $this->ajaxResponse['buttonName'] = str_replace('_qf_' . $this->getAttribute('id') . '_', '', $this->controller->getButtonName());
        $this->ajaxResponse['action'] = $this->_action;
        if (isset($this->_id) || isset($this->id)) {
    }
  
    /**
 -   * The postProcess hook is typically called by the framework
 +   * The postProcess hook is typically called by the framework.
     * However in a few cases, the form exits or redirects early in which
     * case it needs to call this function so other modules can do the needful
     * Calling this function directly should be avoided if possible. In general a
     * better way is to do setUserContext so the framework does the redirect
 -   *
     */
 -  function postProcessHook() {
 +  public function postProcessHook() {
      CRM_Utils_Hook::postProcess(get_class($this), $this);
    }
  
     * buildForm associated with QuickForm_Page. This allows us to put
     * preProcess in front of the actual form building routine
     *
 -   * @access public
     *
     * @return void
 -   *
     */
 -  function buildQuickForm() {}
 +  public function buildQuickForm() {
 +  }
  
    /**
     * This virtual function is used to set the default values of
     *
     * access        public
     *
 -   * @return array reference to the array of default values
 -   *
 +   * @return array|NULL
 +   *   reference to the array of default values
     */
 -  function setDefaultValues() {}
 +  public function setDefaultValues() {
 +    return NULL;
 +  }
  
    /**
     * This is a virtual function that adds group and global rules to
     * the form. Keeping it distinct from the form to keep code small
     * and localized in the form building code
     *
 -   * @access public
     *
     * @return void
 -   *
     */
 -  function addRules() {}
 +  public function addRules() {
 +  }
  
    /**
 -   * Performs the server side validation
 -   * @access    public
 +   * Performs the server side validation.
     * @since     1.0
 -   * @return    boolean   true if no error found
 +   * @return bool
 +   *   true if no error found
     * @throws    HTML_QuickForm_Error
     */
 -  function validate() {
 +  public function validate() {
      $error = parent::validate();
  
      $this->validateChainSelectFields();
     * Core function that builds the form. We redefine this function
     * here and expect all CRM forms to build their form in the function
     * buildQuickForm.
 -   *
     */
 -  function buildForm() {
 +  public function buildForm() {
      $this->_formBuilt = TRUE;
  
      $this->preProcess();
  
 +    CRM_Utils_Hook::preProcess(get_class($this), $this);
 +
      $this->assign('translatePermission', CRM_Core_Permission::check('translate CiviCRM'));
  
      if (
      $this->addRules();
  
      //Set html data-attribute to enable warning user of unsaved changes
 -    if ($this->unsavedChangesWarn === true
 -        || (!isset($this->unsavedChangesWarn)
 -           && ($this->_action & CRM_Core_Action::ADD || $this->_action & CRM_Core_Action::UPDATE)
 -           )
 -        ) {
 -          $this->setAttribute('data-warn-changes', 'true');
 +    if ($this->unsavedChangesWarn === TRUE
 +      || (!isset($this->unsavedChangesWarn)
 +        && ($this->_action & CRM_Core_Action::ADD || $this->_action & CRM_Core_Action::UPDATE)
 +      )
 +    ) {
 +      $this->setAttribute('data-warn-changes', 'true');
      }
    }
  
    /**
     * Add default Next / Back buttons
     *
 -   * @param array   array of associative arrays in the order in which the buttons should be
 -   *                displayed. The associate array has 3 fields: 'type', 'name' and 'isDefault'
 -   *                The base form class will define a bunch of static arrays for commonly used
 -   *                formats
 +   * @param array $params
 +   *   Array of associative arrays in the order in which the buttons should be
 +   *   displayed. The associate array has 3 fields: 'type', 'name' and 'isDefault'
 +   *   The base form class will define a bunch of static arrays for commonly used
 +   *   formats.
     *
     * @return void
 -   *
 -   * @access public
 -   *
     */
 -  function addButtons($params) {
 -    $prevnext = array();
 -    $spacing = array();
 +  public function addButtons($params) {
 +    $prevnext = $spacing = array();
      foreach ($params as $button) {
 -      $js = CRM_Utils_Array::value('js', $button);
 -      $isDefault = CRM_Utils_Array::value('isDefault', $button, FALSE);
 -      if ($isDefault) {
 -        $attrs = array('class' => 'crm-form-submit default');
 -      }
 -      else {
 -        $attrs = array('class' => 'crm-form-submit');
 +      $attrs = array('class' => 'crm-form-submit') + (array) CRM_Utils_Array::value('js', $button);
 +
 +      if (!empty($button['class'])) {
 +        $attrs['class'] .= ' ' . $button['class'];
        }
  
 -      if ($js) {
 -        $attrs = array_merge($js, $attrs);
 +      if (!empty($button['isDefault'])) {
 +        $attrs['class'] .= ' default';
        }
  
 -      if ($button['type'] === 'cancel') {
 +      if (in_array($button['type'], array('upload', 'next', 'submit', 'done', 'process', 'refresh'))) {
 +        $attrs['class'] .= ' validate';
 +        $defaultIcon = 'check';
 +      }
 +      else {
          $attrs['class'] .= ' cancel';
 +        $defaultIcon = $button['type'] == 'back' ? 'triangle-1-w' : 'close';
        }
  
        if ($button['type'] === 'reset') {
        }
        else {
          if (!empty($button['subName'])) {
 -          $buttonName = $this->getButtonName($button['type'], $button['subName']);
 -        }
 -        else {
 -          $buttonName = $this->getButtonName($button['type']);
 +          if ($button['subName'] == 'new') {
 +            $defaultIcon = 'plus';
 +          }
 +          if ($button['subName'] == 'done') {
 +            $defaultIcon = 'circle-check';
 +          }
 +          if ($button['subName'] == 'next') {
 +            $defaultIcon = 'circle-triangle-e';
 +          }
          }
  
          if (in_array($button['type'], array('next', 'upload', 'done')) && $button['name'] === ts('Save')) {
 -          $attrs = array_merge($attrs, (array('accesskey' => 'S')));
 +          $attrs['accesskey'] = 'S';
          }
 +        $icon = CRM_Utils_Array::value('icon', $button, $defaultIcon);
 +        if ($icon) {
 +          $attrs['crm-icon'] = $icon;
 +        }
 +        $buttonName = $this->getButtonName($button['type'], CRM_Utils_Array::value('subName', $button));
          $prevnext[] = $this->createElement('submit', $buttonName, $button['name'], $attrs);
        }
        if (!empty($button['isDefault'])) {
    }
  
    /**
 -   * getter function for Name
 +   * Getter function for Name.
     *
     * @return string
 -   * @access public
     */
 -  function getName() {
 +  public function getName() {
      return $this->_name;
    }
  
    /**
 -   * getter function for State
 +   * Getter function for State.
     *
     * @return object
 -   * @access public
     */
 -  function &getState() {
 +  public function &getState() {
      return $this->_state;
    }
  
    /**
 -   * getter function for StateType
 +   * Getter function for StateType.
     *
     * @return int
 -   * @access public
     */
 -  function getStateType() {
 +  public function getStateType() {
      return $this->_state->getType();
    }
  
    /**
 -   * getter function for title. Should be over-ridden by derived class
 +   * Getter function for title. Should be over-ridden by derived class
     *
     * @return string
 -   * @access public
     */
 -  function getTitle() {
 +  public function getTitle() {
      return $this->_title ? $this->_title : ts('ERROR: Title is not Set');
    }
  
    /**
 -   * setter function for title.
 +   * Setter function for title.
     *
 -   * @param string $title the title of the form
 +   * @param string $title
 +   *   The title of the form.
     *
     * @return void
 -   * @access public
     */
 -  function setTitle($title) {
 +  public function setTitle($title) {
      $this->_title = $title;
    }
  
    /**
 -   * Setter function for options
 +   * Setter function for options.
     *
 -   * @param mixed
 +   * @param mixed $options
     *
     * @return void
 -   * @access public
     */
 -  function setOptions($options) {
 +  public function setOptions($options) {
      $this->_options = $options;
    }
  
    /**
 -   * getter function for link.
 +   * Getter function for link.
     *
     * @return string
 -   * @access public
     */
 -  function getLink() {
 +  public function getLink() {
      $config = CRM_Core_Config::singleton();
      return CRM_Utils_System::url($_GET[$config->userFrameworkURLVar],
        '_qf_' . $this->_name . '_display=true'
    }
  
    /**
 -   * boolean function to determine if this is a one form page
 +   * Boolean function to determine if this is a one form page.
     *
 -   * @return boolean
 -   * @access public
 +   * @return bool
     */
 -  function isSimpleForm() {
 +  public function isSimpleForm() {
      return $this->_state->getType() & (CRM_Core_State::START | CRM_Core_State::FINISH);
    }
  
    /**
 -   * getter function for Form Action
 +   * Getter function for Form Action.
     *
     * @return string
 -   * @access public
     */
 -  function getFormAction() {
 +  public function getFormAction() {
      return $this->_attributes['action'];
    }
  
    /**
 -   * setter function for Form Action
 +   * Setter function for Form Action.
     *
 -   * @param string
 +   * @param string $action
     *
     * @return void
 -   * @access public
     */
 -  function setFormAction($action) {
 +  public function setFormAction($action) {
      $this->_attributes['action'] = $action;
    }
  
    /**
 -   * render form and return contents
 +   * Render form and return contents.
     *
     * @return string
 -   * @access public
     */
 -  function toSmarty() {
 +  public function toSmarty() {
      $this->preProcessChainSelectFields();
      $renderer = $this->getRenderer();
      $this->accept($renderer);
    }
  
    /**
 -   * getter function for renderer. If renderer is not set
 +   * Getter function for renderer. If renderer is not set
     * create one and initialize it
     *
     * @return object
 -   * @access public
     */
 -  function &getRenderer() {
 +  public function &getRenderer() {
      if (!isset($this->_renderer)) {
        $this->_renderer = CRM_Core_Form_Renderer::singleton();
      }
    }
  
    /**
 -   * Use the form name to create the tpl file name
 +   * Use the form name to create the tpl file name.
     *
     * @return string
 -   * @access public
     */
 -  function getTemplateFileName() {
 +  public function getTemplateFileName() {
      $ext = CRM_Extension_System::singleton()->getMapper();
      if ($ext->isExtensionClass(CRM_Utils_System::getClassName($this))) {
        $filename = $ext->getTemplateName(CRM_Utils_System::getClassName($this));
        $tplname = $ext->getTemplatePath(CRM_Utils_System::getClassName($this)) . DIRECTORY_SEPARATOR . $filename;
      }
      else {
 -      $tplname = str_replace('_',
 -        DIRECTORY_SEPARATOR,
 -        CRM_Utils_System::getClassName($this)
 +      $tplname = strtr(
 +        CRM_Utils_System::getClassName($this),
 +        array(
 +          '_' => DIRECTORY_SEPARATOR,
 +          '\\' => DIRECTORY_SEPARATOR,
 +        )
        ) . '.tpl';
      }
      return $tplname;
     * A wrapper for getTemplateFileName that includes calling the hook to
     * prevent us from having to copy & paste the logic of calling the hook
     */
 -  function getHookedTemplateFileName() {
 +  public function getHookedTemplateFileName() {
      $pageTemplateFile = $this->getTemplateFileName();
      CRM_Utils_Hook::alterTemplateFile(get_class($this), $this, 'page', $pageTemplateFile);
      return $pageTemplateFile;
     * i.e. we dont override
     *
     * @return string
 -   * @access public
     */
 -  function overrideExtraTemplateFileName() {
 +  public function overrideExtraTemplateFileName() {
      return NULL;
    }
  
    /**
 -   * Error reporting mechanism
 +   * Error reporting mechanism.
     *
 -   * @param string  $message Error Message
 -   * @param int     $code    Error Code
 -   * @param CRM_Core_DAO $dao     A data access object on which we perform a rollback if non - empty
 +   * @param string $message
 +   *   Error Message.
 +   * @param int $code
 +   *   Error Code.
 +   * @param CRM_Core_DAO $dao
 +   *   A data access object on which we perform a rollback if non - empty.
     *
     * @return void
 -   * @access public
     */
 -  function error($message, $code = NULL, $dao = NULL) {
 +  public function error($message, $code = NULL, $dao = NULL) {
      if ($dao) {
        $dao->query('ROLLBACK');
      }
    }
  
    /**
 -   * Store the variable with the value in the form scope
 -   *
 -   * @param  string name  : name  of the variable
 -   * @param  mixed  value : value of the variable
 +   * Store the variable with the value in the form scope.
     *
 -   * @access public
 +   * @param string $name
 +   *   Name of the variable.
 +   * @param mixed $value
 +   *   Value of the variable.
     *
     * @return void
 -   *
     */
 -  function set($name, $value) {
 +  public function set($name, $value) {
      $this->controller->set($name, $value);
    }
  
    /**
 -   * Get the variable from the form scope
 +   * Get the variable from the form scope.
     *
 -   * @param  string name  : name  of the variable
 -   *
 -   * @access public
 +   * @param string $name
 +   *   Name of the variable
     *
     * @return mixed
 -   *
     */
 -  function get($name) {
 +  public function get($name) {
      return $this->controller->get($name);
    }
  
    /**
 -   * getter for action
 +   * Getter for action.
     *
     * @return int
 -   * @access public
     */
 -  function getAction() {
 +  public function getAction() {
      return $this->_action;
    }
  
    /**
 -   * setter for action
 +   * Setter for action.
     *
 -   * @param  int  $action the mode we want to set the form
 +   * @param int $action
 +   *   The mode we want to set the form.
     *
     * @return void
 -   * @access public
     */
 -  function setAction($action) {
 +  public function setAction($action) {
      $this->_action = $action;
    }
  
    /**
 -   * assign value to name in template
 +   * Assign value to name in template.
     *
 -   * @param $var
 -   * @param mixed $value value of varaible
 +   * @param string $var
 +   *   Name of variable.
 +   * @param mixed $value
 +   *   Value of variable.
     *
 -   * @internal param array|string $name name  of variable
     * @return void
 -   * @access public
     */
 -  function assign($var, $value = NULL) {
 +  public function assign($var, $value = NULL) {
      self::$_template->assign($var, $value);
    }
  
    /**
 -   * assign value to name in template by reference
 +   * Assign value to name in template by reference.
     *
 -   * @param $var
 -   * @param mixed $value value of varaible
 +   * @param string $var
 +   *   Name of variable.
 +   * @param mixed $value
 +   *   Value of varaible.
     *
 -   * @internal param array|string $name name  of variable
     * @return void
 -   * @access public
     */
 -  function assign_by_ref($var, &$value) {
 +  public function assign_by_ref($var, &$value) {
      self::$_template->assign_by_ref($var, $value);
    }
  
    /**
 -   * appends values to template variables
 +   * Appends values to template variables.
     *
     * @param array|string $tpl_var the template variable name(s)
 -   * @param mixed $value the value to append
 +   * @param mixed $value
 +   *   The value to append.
     * @param bool $merge
     */
 -  function append($tpl_var, $value=NULL, $merge=FALSE) {
 +  public function append($tpl_var, $value = NULL, $merge = FALSE) {
      self::$_template->append($tpl_var, $value, $merge);
    }
  
    /**
 -   * Returns an array containing template variables
 +   * Returns an array containing template variables.
     *
     * @param string $name
     *
 -   * @internal param string $type
     * @return array
     */
 -  function get_template_vars($name=null) {
 +  public function get_template_vars($name = NULL) {
      return self::$_template->get_template_vars($name);
    }
  
    /**
 -   * @param $name
 +   * @param string $name
     * @param $title
     * @param $values
     * @param array $attributes
     *
     * @return HTML_QuickForm_group
     */
 -  function &addRadio($name, $title, $values, $attributes = array(), $separator = NULL, $required = FALSE) {
 +  public function &addRadio($name, $title, $values, $attributes = array(), $separator = NULL, $required = FALSE) {
      $options = array();
      $attributes = $attributes ? $attributes : array();
      $allowClear = !empty($attributes['allowClear']);
      unset($attributes['allowClear']);
 -    $attributes += array('id_suffix' => $name);
 +    $attributes['id_suffix'] = $name;
      foreach ($values as $key => $var) {
        $options[] = $this->createElement('radio', NULL, NULL, $var, $key, $attributes);
      }
    }
  
    /**
 -   * @param $id
 +   * @param int $id
     * @param $title
     * @param bool $allowClear
     * @param null $required
     * @param array $attributes
     */
 -  function addYesNo($id, $title, $allowClear = FALSE, $required = NULL, $attributes = array()) {
 +  public function addYesNo($id, $title, $allowClear = FALSE, $required = NULL, $attributes = array()) {
      $attributes += array('id_suffix' => $id);
 -    $choice   = array();
 +    $choice = array();
      $choice[] = $this->createElement('radio', NULL, '11', ts('Yes'), '1', $attributes);
      $choice[] = $this->createElement('radio', NULL, '11', ts('No'), '0', $attributes);
  
    }
  
    /**
 -   * @param $id
 +   * @param int $id
     * @param $title
     * @param $values
     * @param null $other
     * @param string $separator
     * @param bool $flipValues
     */
 -  function addCheckBox($id, $title, $values, $other = NULL,
 -    $attributes       = NULL, $required = NULL,
 +  public function addCheckBox(
 +    $id, $title, $values, $other = NULL,
 +    $attributes = NULL, $required = NULL,
      $javascriptMethod = NULL,
 -    $separator        = '<br />', $flipValues = FALSE
 +    $separator = '<br />', $flipValues = FALSE
    ) {
      $options = array();
  
      }
    }
  
 -  function resetValues() {
 +  public function resetValues() {
      $data = $this->controller->container();
      $data['values'][$this->_name] = array();
    }
  
    /**
 -   * simple shell that derived classes can call to add buttons to
 +   * Simple shell that derived classes can call to add buttons to
     * the form with a customized title for the main Submit
     *
 -   * @param string $title title of the main button
 +   * @param string $title
 +   *   Title of the main button.
     * @param string $nextType
 +   *   Button type for the form after processing.
     * @param string $backType
     * @param bool|string $submitOnce If true, add javascript to next button submit which prevents it from being clicked more than once
     *
 -   * @internal param string $type button type for the form after processing
     * @return void
 -   * @access public
     */
 -  function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
 +  public function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
      $buttons = array();
      if ($backType != NULL) {
        $buttons[] = array(
    }
  
    /**
 -   * @param $name
 +   * @param string $name
     * @param string $from
     * @param string $to
     * @param string $label
     * @param bool $required
     * @param bool $displayTime
     */
 -  function addDateRange($name, $from = '_from', $to = '_to', $label = 'From:', $dateFormat = 'searchDate', $required = FALSE, $displayTime = FALSE) {
 +  public function addDateRange($name, $from = '_from', $to = '_to', $label = 'From:', $dateFormat = 'searchDate', $required = FALSE, $displayTime = FALSE) {
      if ($displayTime) {
        $this->addDateTime($name . $from, $label, $required, array('formatType' => $dateFormat));
        $this->addDateTime($name . $to, ts('To:'), $required, array('formatType' => $dateFormat));
 -    } else {
 +    }
 +    else {
        $this->addDate($name . $from, $label, $required, array('formatType' => $dateFormat));
        $this->addDate($name . $to, ts('To:'), $required, array('formatType' => $dateFormat));
      }
    }
  
    /**
 -   * Adds a select based on field metadata
 +   * Adds a select based on field metadata.
     * TODO: This could be even more generic and widget type (select in this case) could also be read from metadata
     * Perhaps a method like $form->bind($name) which would look up all metadata for named field
 -   * @param $name - field name to go on the form
 -   * @param array $props - mix of html attributes and special properties, namely
 +   * @param $name
 +   *   Field name to go on the form.
 +   * @param array $props
 +   *   Mix of html attributes and special properties, namely.
     *   - entity (api entity name, can usually be inferred automatically from the form class)
     *   - field (field name - only needed if different from name used on the form)
     *   - option_url - path to edit this option list - usually retrieved automatically - set to NULL to disable link
     *   - placeholder - set to NULL to disable
     *   - multiple - bool
 +   *   - context - @see CRM_Core_DAO::buildOptionsContext
     * @param bool $required
     * @throws CRM_Core_Exception
     * @return HTML_QuickForm_Element
     */
 -  function addSelect($name, $props = array(), $required = FALSE) {
 +  public function addSelect($name, $props = array(), $required = FALSE) {
      if (!isset($props['entity'])) {
        $props['entity'] = CRM_Utils_Api::getEntityName($this);
      }
        $options = $props['options'];
      }
      else {
 -      $info = civicrm_api3($props['entity'], 'getoptions', array('field' => $props['field']));
 +      $info = civicrm_api3($props['entity'], 'getoptions', $props);
        $options = $info['values'];
      }
      if (!array_key_exists('placeholder', $props)) {
 -      $props['placeholder'] = $required ? ts('- select -') : ts('- none -');
 +      $props['placeholder'] = $required ? ts('- select -') : CRM_Utils_Array::value('context', $props) == 'search' ? ts('- any -') : ts('- none -');
      }
      // Handle custom field
      if (strpos($name, 'custom_') === 0 && is_numeric($name[7])) {
        list(, $id) = explode('_', $name);
        $label = isset($props['label']) ? $props['label'] : CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', 'label', $id);
        $gid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', 'option_group_id', $id);
 -      $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $gid);
 +      if (CRM_Utils_Array::value('context', $props) != 'search') {
 +        $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $gid);
 +      }
      }
      // Core field
      else {
        $info = civicrm_api3($props['entity'], 'getfields');
 -      foreach($info['values'] as $uniqueName => $fieldSpec) {
 +      foreach ($info['values'] as $uniqueName => $fieldSpec) {
          if (
            $uniqueName === $props['field'] ||
            CRM_Utils_Array::value('name', $fieldSpec) === $props['field'] ||
          }
        }
        $label = isset($props['label']) ? $props['label'] : $fieldSpec['title'];
 -      $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : $props['data-option-edit-path'] = CRM_Core_PseudoConstant::getOptionEditUrl($fieldSpec);
 +      if (CRM_Utils_Array::value('context', $props) != 'search') {
 +        $props['data-option-edit-path'] = array_key_exists('option_url', $props) ? $props['option_url'] : $props['data-option-edit-path'] = CRM_Core_PseudoConstant::getOptionEditUrl($fieldSpec);
 +      }
      }
      $props['class'] = (isset($props['class']) ? $props['class'] . ' ' : '') . "crm-select2";
      $props['data-api-entity'] = $props['entity'];
      $props['data-api-field'] = $props['field'];
 -    CRM_Utils_Array::remove($props, 'label', 'entity', 'field', 'option_url', 'options');
 +    CRM_Utils_Array::remove($props, 'label', 'entity', 'field', 'option_url', 'options', 'context');
      return $this->add('select', $name, $label, $options, $required, $props);
    }
  
    /**
     * Add a widget for selecting/editing/creating/copying a profile form
     *
 -   * @param string $name HTML form-element name
 -   * @param string $label Printable label
 -   * @param string $allowCoreTypes only present a UFGroup if its group_type includes a subset of $allowCoreTypes; e.g. 'Individual', 'Activity'
 -   * @param string $allowSubTypes only present a UFGroup if its group_type is compatible with $allowSubypes
 +   * @param string $name
 +   *   HTML form-element name.
 +   * @param string $label
 +   *   Printable label.
 +   * @param string $allowCoreTypes
 +   *   Only present a UFGroup if its group_type includes a subset of $allowCoreTypes; e.g. 'Individual', 'Activity'.
 +   * @param string $allowSubTypes
 +   *   Only present a UFGroup if its group_type is compatible with $allowSubypes.
     * @param array $entities
 -   * @param bool $default //CRM-15427
 +   * @param bool $default
 +   *   //CRM-15427.
     */
 -  function addProfileSelector($name, $label, $allowCoreTypes, $allowSubTypes, $entities, $default = FALSE) {
 +  public function addProfileSelector($name, $label, $allowCoreTypes, $allowSubTypes, $entities, $default = FALSE) {
      // Output widget
      // FIXME: Instead of adhoc serialization, use a single json_encode()
      CRM_UF_Page_ProfileEditor::registerProfileScripts();
    }
  
    /**
 -   * @param $name
 +   * @param string $name
     * @param $label
     * @param $attributes
     * @param bool $forceTextarea
     */
 -  function addWysiwyg($name, $label, $attributes, $forceTextarea = FALSE) {
 +  public function addWysiwyg($name, $label, $attributes, $forceTextarea = FALSE) {
      // 1. Get configuration option for editor (tinymce, ckeditor, pure textarea)
      // 2. Based on the option, initialise proper editor
      $editorID = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
        'editor_id'
      );
      $editor = strtolower(CRM_Utils_Array::value($editorID,
 -        CRM_Core_OptionGroup::values('wysiwyg_editor')
 -      ));
 +      CRM_Core_OptionGroup::values('wysiwyg_editor')
 +    ));
      if (!$editor || $forceTextarea) {
        $editor = 'textarea';
      }
    }
  
    /**
 -   * @param $id
 +   * @param int $id
     * @param $title
     * @param null $required
     * @param null $extra
     */
 -  function addCountry($id, $title, $required = NULL, $extra = NULL) {
 +  public function addCountry($id, $title, $required = NULL, $extra = NULL) {
      $this->addElement('select', $id, $title,
        array(
 -        '' => ts('- select -')) + CRM_Core_PseudoConstant::country(), $extra
 +        '' => ts('- select -'),
 +      ) + CRM_Core_PseudoConstant::country(), $extra
      );
      if ($required) {
        $this->addRule($id, ts('Please select %1', array(1 => $title)), 'required');
    }
  
    /**
 -   * @param $name
 +   * @param string $name
     * @param $label
     * @param $options
     * @param $attributes
     * @param null $required
     * @param null $javascriptMethod
     */
 -  function addSelectOther($name, $label, $options, $attributes, $required = NULL, $javascriptMethod = NULL) {
 +  public function addSelectOther($name, $label, $options, $attributes, $required = NULL, $javascriptMethod = NULL) {
  
      $this->addElement('select', $name . '_id', $label, $options, $javascriptMethod);
  
    /**
     * @return CRM_Core_Smarty
     */
 -  static function &getTemplate() {
 +  public static function &getTemplate() {
      return self::$_template;
    }
  
    /**
     * @param $elementName
     */
 -  function addUploadElement($elementName) {
 +  public function addUploadElement($elementName) {
      $uploadNames = $this->get('uploadNames');
      if (!$uploadNames) {
        $uploadNames = array();
    /**
     * @return string
     */
 -  function buttonType() {
 +  public function buttonType() {
      $uploadNames = $this->get('uploadNames');
      $buttonType = (is_array($uploadNames) && !empty($uploadNames)) ? 'upload' : 'next';
      $this->assign('buttonType', $buttonType);
     *
     * @return null
     */
 -  function getVar($name) {
 +  public function getVar($name) {
      return isset($this->$name) ? $this->$name : NULL;
    }
  
     * @param $name
     * @param $value
     */
 -  function setVar($name, $value) {
 +  public function setVar($name, $value) {
      $this->$name = $value;
    }
  
    /**
 -   *  Function to add date
 -   *  @param string $name   name of the element
 -   *  @param string $label  label of the element
 -   *  @param array  $attributes key / value pair
 +   * Add date.
     *
 -   // if you need time
 -   *  $attributes = array ( 'addTime' => true,
 -   *                        'formatType' => 'relative' or 'birth' etc check advanced date settings
 -   *                      );
 -   *  @param boolean $required  true if required
 +   * @code
 +   * // if you need time
 +   * $attributes = array(
 +   *   'addTime' => true,
 +   *   'formatType' => 'relative' or 'birth' etc check advanced date settings
 +   * );
 +   * @endcode
     *
 +   * @param string $name
 +   *   Name of the element.
 +   * @param string $label
 +   *   Label of the element.
 +   * @param bool $required
 +   *   True if required.
 +   * @param array $attributes
 +   *   Key / value pair.
     */
 -  function addDate($name, $label, $required = FALSE, $attributes = NULL) {
 +  public function addDate($name, $label, $required = FALSE, $attributes = NULL) {
      if (!empty($attributes['formatType'])) {
        // get actual format
        $params = array('name' => $attributes['formatType']);
    }
  
    /**
 -   *  Function that will add date and time
 +   *  Function that will add date and time.
     */
 -  function addDateTime($name, $label, $required = FALSE, $attributes = NULL) {
 +  public function addDateTime($name, $label, $required = FALSE, $attributes = NULL) {
      $addTime = array('addTime' => TRUE);
      if (is_array($attributes)) {
        $attributes = array_merge($attributes, $addTime);
    }
  
    /**
 -   * add a currency and money element to the form
 +   * Add a currency and money element to the form.
     */
 -  function addMoney($name,
 +  public function addMoney(
 +    $name,
      $label,
 -    $required        = FALSE,
 -    $attributes      = NULL,
 -    $addCurrency     = TRUE,
 -    $currencyName    = 'currency',
 +    $required = FALSE,
 +    $attributes = NULL,
 +    $addCurrency = TRUE,
 +    $currencyName = 'currency',
      $defaultCurrency = NULL,
 -    $freezeCurrency  = FALSE
 +    $freezeCurrency = FALSE
    ) {
      $element = $this->add('text', $name, $label, $attributes, $required);
      $this->addRule($name, ts('Please enter a valid amount.'), 'money');
    }
  
    /**
 -   * add currency element to the form
 +   * Add currency element to the form.
     */
 -  function addCurrency($name = 'currency',
 -    $label           = NULL,
 -    $required        = TRUE,
 +  public function addCurrency(
 +    $name = 'currency',
 +    $label = NULL,
 +    $required = TRUE,
      $defaultCurrency = NULL,
 -    $freezeCurrency  = FALSE
 +    $freezeCurrency = FALSE
    ) {
      $currencies = CRM_Core_OptionGroup::values('currencies_enabled');
      $options = array('class' => 'crm-select2 eight');
    }
  
    /**
 -   * Create a single or multiple entity ref field
 +   * Create a single or multiple entity ref field.
     * @param string $name
     * @param string $label
 -   * @param array $props mix of html and widget properties, including:
 -   *  - select - params to give to select2 widget
 -   *  - entity - defaults to contact
 -   *  - create - can the user create a new entity on-the-fly?
 +   * @param array $props
 +   *   Mix of html and widget properties, including:.
 +   *   - select - params to give to select2 widget
 +   *   - entity - defaults to contact
 +   *   - create - can the user create a new entity on-the-fly?
     *             Set to TRUE if entity is contact and you want the default profiles,
     *             or pass in your own set of links. @see CRM_Core_BAO_UFGroup::getCreateLinks for format
     *             note that permissions are checked automatically
 -   *  - api - array of settings for the getlist api wrapper
 +   *   - api - array of settings for the getlist api wrapper
     *          note that it accepts a 'params' setting which will be passed to the underlying api
 -   *  - placeholder - string
 -   *  - multiple - bool
 -   *  - class, etc. - other html properties
 +   *   - placeholder - string
 +   *   - multiple - bool
 +   *   - class, etc. - other html properties
     * @param bool $required
     *
 -   * @access public
     * @return HTML_QuickForm_Element
     */
 -  function addEntityRef($name, $label = '', $props = array(), $required = FALSE) {
 +  public function addEntityRef($name, $label = '', $props = array(), $required = FALSE) {
      require_once "api/api.php";
      $config = CRM_Core_Config::singleton();
      // Default properties
     * BAO layer. In this case fields are checked against the $_datefields defined for the form
     * and if time is defined it is incorporated
     *
 -   * @param array $params input params from the form
 +   * @param array $params
 +   *   Input params from the form.
     *
     * @todo it would probably be better to work on $this->_params than a passed array
     * @todo standardise the format which dates are passed to the BAO layer in & remove date
     * handling from BAO
     */
 -  function convertDateFieldsToMySQL(&$params){
 -    foreach ($this->_dateFields as $fieldName => $specs){
 -      if(!empty($params[$fieldName])){
 +  public function convertDateFieldsToMySQL(&$params) {
 +    foreach ($this->_dateFields as $fieldName => $specs) {
 +      if (!empty($params[$fieldName])) {
          $params[$fieldName] = CRM_Utils_Date::isoToMysql(
            CRM_Utils_Date::processDate(
 -          $params[$fieldName],
 -          CRM_Utils_Array::value("{$fieldName}_time", $params), TRUE)
 +            $params[$fieldName],
 +            CRM_Utils_Array::value("{$fieldName}_time", $params), TRUE)
          );
        }
 -      else{
 -        if(isset($specs['default'])){
 +      else {
 +        if (isset($specs['default'])) {
            $params[$fieldName] = date('YmdHis', strtotime($specs['default']));
          }
        }
    /**
     * @param $elementName
     */
 -  function removeFileRequiredRules($elementName) {
 +  public function removeFileRequiredRules($elementName) {
      $this->_required = array_diff($this->_required, array($elementName));
      if (isset($this->_rules[$elementName])) {
        foreach ($this->_rules[$elementName] as $index => $ruleInfo) {
    }
  
    /**
 -   * Function that can be defined in Form to override or
 +   * Function that can be defined in Form to override or.
     * perform specific action on cancel action
 -   *
 -   * @access public
     */
 -  function cancelAction() {}
 +  public function cancelAction() {
 +  }
  
    /**
 -   * Helper function to verify that required fields have been filled
 +   * Helper function to verify that required fields have been filled.
     * Typically called within the scope of a FormRule function
     */
 -  static function validateMandatoryFields($fields, $values, &$errors) {
 +  public static function validateMandatoryFields($fields, $values, &$errors) {
      foreach ($fields as $name => $fld) {
        if (!empty($fld['is_required']) && CRM_Utils_System::isNull(CRM_Utils_Array::value($name, $values))) {
          $errors[$name] = ts('%1 is a required field.', array(1 => $fld['title']));
  
    /**
     * Get contact if for a form object. Prioritise
 -   *  - cid in URL if 0 (on behalf on someoneelse)
 +   *   - cid in URL if 0 (on behalf on someoneelse)
     *      (@todo consider setting a variable if onbehalf for clarity of downstream 'if's
 -   *  - logged in user id if it matches the one in the cid in the URL
 -   *  - contact id validated from a checksum from a checksum
 -   *  - cid from the url if the caller has ACL permission to view
 -   *  - fallback is logged in user (or ? NULL if no logged in user) (@todo wouldn't 0 be more intuitive?)
 +   *   - logged in user id if it matches the one in the cid in the URL
 +   *   - contact id validated from a checksum from a checksum
 +   *   - cid from the url if the caller has ACL permission to view
 +   *   - fallback is logged in user (or ? NULL if no logged in user) (@todo wouldn't 0 be more intuitive?)
     *
 -   * @return mixed NULL|integer
 +   * @return NULL|int
     */
 -  function getContactID() {
 +  public function getContactID() {
      $tempID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
 -    if(isset($this->_params) && isset($this->_params['select_contact_id'])) {
 +    if (isset($this->_params) && isset($this->_params['select_contact_id'])) {
        $tempID = $this->_params['select_contact_id'];
      }
 -    if(isset($this->_params, $this->_params[0]) && !empty($this->_params[0]['select_contact_id'])) {
 +    if (isset($this->_params, $this->_params[0]) && !empty($this->_params[0]['select_contact_id'])) {
        // event form stores as an indexed array, contribution form not so much...
        $tempID = $this->_params[0]['select_contact_id'];
      }
        }
      }
      // check if user has permission, CRM-12062
 -    else if ($tempID && CRM_Contact_BAO_Contact_Permission::allow($tempID)) {
 +    elseif ($tempID && CRM_Contact_BAO_Contact_Permission::allow($tempID)) {
        return $tempID;
      }
  
      return $userID;
    }
  
 - /**
 -  * Get the contact id of the logged in user
 -  */
 -  function getLoggedInUserContactID() {
 +  /**
 +   * Get the contact id of the logged in user.
 +   */
 +  public function getLoggedInUserContactID() {
      // check if the user is logged in and has a contact ID
      $session = CRM_Core_Session::singleton();
      return $session->get('userID');
    }
  
    /**
 -   * add autoselector field -if user has permission to view contacts
 +   * Add autoselector field -if user has permission to view contacts
     * If adding this to a form you also need to add to the tpl e.g
     *
     * {if !empty($selectable)}
     * </div>
     * {/if}
     *
 -   * @param array $profiles ids of profiles that are on the form (to be autofilled)
 +   * @param array $profiles
 +   *   Ids of profiles that are on the form (to be autofilled).
     * @param array $autoCompleteField
     *
 -   * @internal param array $field metadata of field to use as selector including
 -   *  - name_field
 -   *  - id_field
 -   *  - url (for ajax lookup)
 +   *   - name_field
 +   *   - id_field
 +   *   - url (for ajax lookup)
     *
     * @todo add data attributes so we can deal with multiple instances on a form
     */
 -  function addAutoSelector($profiles = array(), $autoCompleteField = array()) {
 +  public function addAutoSelector($profiles = array(), $autoCompleteField = array()) {
      $autoCompleteField = array_merge(array(
 -        'id_field' => 'select_contact_id',
 -        'placeholder' => ts('Select someone else ...'),
 -        'show_hide' => TRUE,
 -        'api' => array('params' => array('contact_type' => 'Individual'))
 -      ), $autoCompleteField);
 +      'id_field' => 'select_contact_id',
 +      'placeholder' => ts('Select someone else ...'),
 +      'show_hide' => TRUE,
 +      'api' => array('params' => array('contact_type' => 'Individual')),
 +    ), $autoCompleteField);
  
 -    if($this->canUseAjaxContactLookups()) {
 +    if ($this->canUseAjaxContactLookups()) {
        $this->assign('selectable', $autoCompleteField['id_field']);
 -      $this->addEntityRef($autoCompleteField['id_field'], NULL, array('placeholder' => $autoCompleteField['placeholder'], 'api' => $autoCompleteField['api']));
 +      $this->addEntityRef($autoCompleteField['id_field'], NULL, array(
 +          'placeholder' => $autoCompleteField['placeholder'],
 +          'api' => $autoCompleteField['api'],
 +        ));
  
        CRM_Core_Resources::singleton()->addScriptFile('civicrm', 'js/AlternateContactSelector.js', 1, 'html-header')
 -      ->addSetting(array(
 -      'form' => array('autocompletes' => $autoCompleteField),
 -      'ids' => array('profile' => $profiles),
 -      ));
 +        ->addSetting(array(
 +          'form' => array('autocompletes' => $autoCompleteField),
 +          'ids' => array('profile' => $profiles),
 +        ));
      }
    }
  
    /**
 -   *
     */
 -  function canUseAjaxContactLookups() {
 +  public function canUseAjaxContactLookups() {
      if (0 < (civicrm_api3('contact', 'getcount', array('check_permissions' => 1))) &&
 -      CRM_Core_Permission::check(array(array('access AJAX API', 'access CiviCRM')))) {
 -        return TRUE;
 -      }
 +      CRM_Core_Permission::check(array(array('access AJAX API', 'access CiviCRM')))
 +    ) {
 +      return TRUE;
 +    }
    }
  
    /**
     * that small pieces of duplication are not being refactored into separate functions because their only shared parent
     * is this form. Inserting a class FrontEndForm.php between the contribution & event & this class would allow functions like this
     * and a dozen other small ones to be refactored into a shared parent with the reduction of much code duplication
 +   *
 +   * @param $onlinePaymentProcessorEnabled
     */
 -  function addCIDZeroOptions($onlinePaymentProcessorEnabled) {
 +  public function addCIDZeroOptions($onlinePaymentProcessorEnabled) {
      $this->assign('nocid', TRUE);
      $profiles = array();
 -    if($this->_values['custom_pre_id']) {
 +    if ($this->_values['custom_pre_id']) {
        $profiles[] = $this->_values['custom_pre_id'];
      }
 -    if($this->_values['custom_post_id']) {
 -      $profiles[] = $this->_values['custom_post_id'];
 +    if ($this->_values['custom_post_id']) {
 +      $profiles = array_merge($profiles, (array) $this->_values['custom_post_id']);
      }
 -    if($onlinePaymentProcessorEnabled) {
 +    if ($onlinePaymentProcessorEnabled) {
        $profiles[] = 'billing';
      }
 -    if(!empty($this->_values)) {
 +    if (!empty($this->_values)) {
        $this->addAutoSelector($profiles);
      }
    }
    /**
     * Set default values on form for given contact (or no contact defaults)
     *
 -   * @param mixed $profile_id (can be id, or profile name)
 -   * @param integer $contactID
 +   * @param mixed $profile_id
 +   *   (can be id, or profile name).
 +   * @param int $contactID
     *
     * @return array
     */
 -  function getProfileDefaults($profile_id = 'Billing', $contactID = NULL) {
 -    try{
 +  public function getProfileDefaults($profile_id = 'Billing', $contactID = NULL) {
 +    try {
        $defaults = civicrm_api3('profile', 'getsingle', array(
          'profile_id' => (array) $profile_id,
          'contact_id' => $contactID,
    }
  
    /**
 -   * Sets form attribute
 +   * Sets form attribute.
     * @see CRM.loadForm
     */
 -  function preventAjaxSubmit() {
 +  public function preventAjaxSubmit() {
      $this->setAttribute('data-no-ajax-submit', 'true');
    }
  
    /**
 -   * Sets form attribute
 +   * Sets form attribute.
     * @see CRM.loadForm
     */
 -  function allowAjaxSubmit() {
 +  public function allowAjaxSubmit() {
      $this->removeAttribute('data-no-ajax-submit');
    }
  
    /**
 -   * Sets page title based on entity and action
 +   * Sets page title based on entity and action.
     * @param string $entityLabel
     */
 -  function setPageTitle($entityLabel) {
 +  public function setPageTitle($entityLabel) {
      switch ($this->_action) {
        case CRM_Core_Action::ADD:
          CRM_Utils_System::setTitle(ts('New %1', array(1 => $entityLabel)));
          break;
 +
        case CRM_Core_Action::UPDATE:
          CRM_Utils_System::setTitle(ts('Edit %1', array(1 => $entityLabel)));
          break;
 +
        case CRM_Core_Action::VIEW:
        case CRM_Core_Action::PREVIEW:
          CRM_Utils_System::setTitle(ts('View %1', array(1 => $entityLabel)));
          break;
 +
        case CRM_Core_Action::DELETE:
          CRM_Utils_System::setTitle(ts('Delete %1', array(1 => $entityLabel)));
          break;
     */
    public function addChainSelect($elementName, $settings = array()) {
      $props = $settings += array(
 -      'control_field' => str_replace(array('state_province', 'StateProvince', 'county', 'County'), array('country', 'Country', 'state_province', 'StateProvince'), $elementName),
 +      'control_field' => str_replace(array('state_province', 'StateProvince', 'county', 'County'), array(
 +          'country',
 +          'Country',
 +          'state_province',
 +          'StateProvince',
 +        ), $elementName),
        'data-callback' => strpos($elementName, 'rovince') ? 'civicrm/ajax/jqState' : 'civicrm/ajax/jqCounty',
        'label' => strpos($elementName, 'rovince') ? ts('State/Province') : ts('County'),
        'data-empty-prompt' => strpos($elementName, 'rovince') ? ts('Choose country first') : ts('Choose state first'),
     */
    private function preProcessChainSelectFields() {
      foreach ($this->_chainSelectFields as $control => $target) {
-       $targetField = $this->getElement($target);
-       $targetType = $targetField->getAttribute('data-callback') == 'civicrm/ajax/jqCounty' ? 'county' : 'stateProvince';
-       $options = array();
-       // If the control field is on the form, setup chain-select and dynamically populate options
-       if ($this->elementExists($control)) {
-         $controlField = $this->getElement($control);
-         $controlType = $targetType == 'county' ? 'stateProvince' : 'country';
-         $targetField->setAttribute('class', $targetField->getAttribute('class') . ' crm-chain-select-target');
-         $css = (string) $controlField->getAttribute('class');
-         $controlField->updateAttributes(array(
-           'class' => ($css ? "$css " : 'crm-select2 ') . 'crm-chain-select-control',
-           'data-target' => $target,
-         ));
-         $controlValue = $controlField->getValue();
-         if ($controlValue) {
-           $options = CRM_Core_BAO_Location::getChainSelectValues($controlValue, $controlType, TRUE);
-           if (!$options) {
-             $targetField->setAttribute('placeholder', $targetField->getAttribute('data-none-prompt'));
+       // The 'target' might get missing if extensions do removeElement() in a form hook.
+       if ($this->elementExists($target)) {
+         $targetField = $this->getElement($target);
+         $targetType = $targetField->getAttribute('data-callback') == 'civicrm/ajax/jqCounty' ? 'county' : 'stateProvince';
+         $options = array();
+         // If the control field is on the form, setup chain-select and dynamically populate options
+         if ($this->elementExists($control)) {
+           $controlField = $this->getElement($control);
+           $controlType = $targetType == 'county' ? 'stateProvince' : 'country';
+           $targetField->setAttribute('class', $targetField->getAttribute('class') . ' crm-chain-select-target');
+           $css = (string) $controlField->getAttribute('class');
+           $controlField->updateAttributes(array(
+             'class' => ($css ? "$css " : 'crm-select2 ') . 'crm-chain-select-control',
+             'data-target' => $target,
+           ));
+           $controlValue = $controlField->getValue();
+           if ($controlValue) {
+             $options = CRM_Core_BAO_Location::getChainSelectValues($controlValue, $controlType, TRUE);
+             if (!$options) {
+               $targetField->setAttribute('placeholder', $targetField->getAttribute('data-none-prompt'));
+             }
 -          } else {
++          } 
++          else {
+             $targetField->setAttribute('placeholder', $targetField->getAttribute('data-empty-prompt'));
+             $targetField->setAttribute('disabled', 'disabled');
            }
          }
+         // Control field not present - fall back to loading default options
          else {
-           $targetField->setAttribute('placeholder', $targetField->getAttribute('data-empty-prompt'));
-           $targetField->setAttribute('disabled', 'disabled');
+           $options = CRM_Core_PseudoConstant::$targetType();
          }
+         if (!$targetField->getAttribute('multiple')) {
+           $options = array('' => $targetField->getAttribute('placeholder')) + $options;
+           $targetField->removeAttribute('placeholder');
+         }
+         $targetField->_options = array();
+         $targetField->loadArray($options);
        }
-       // Control field not present - fall back to loading default options
-       else {
-         $options = CRM_Core_PseudoConstant::$targetType();
-       }
-       if (!$targetField->getAttribute('multiple')) {
-         $options = array('' => $targetField->getAttribute('placeholder')) + $options;
-         $targetField->removeAttribute('placeholder');
-       }
-       $targetField->_options = array();
-       $targetField->loadArray($options);
      }
    }
  
     */
    private function validateChainSelectFields() {
      foreach ($this->_chainSelectFields as $control => $target) {
-       if ($this->elementExists($control)) {
+       if ($this->elementExists($control) && $this->elementExists($target)) {
 -        $controlValue = (array)$this->getElementValue($control);
 +        $controlValue = (array) $this->getElementValue($control);
          $targetField = $this->getElement($target);
          $controlType = $targetField->getAttribute('data-callback') == 'civicrm/ajax/jqCounty' ? 'stateProvince' : 'country';
 -        $targetValue = array_filter((array)$targetField->getValue());
 +        $targetValue = array_filter((array) $targetField->getValue());
          if ($targetValue || $this->getElementError($target)) {
            $options = CRM_Core_BAO_Location::getChainSelectValues($controlValue, $controlType, TRUE);
            if ($targetValue) {
        }
      }
    }
 -}
  
 +}
diff --combined CRM/Core/Page/AJAX.php
index 21adef2cefd486c6d9b94c2a2ae1196b9744d8f6,315b8fba3d4f8bcb4bbad31c27054dfa1ce93d33..69ae14537d2d2556023502e63f0203315a8b7423
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
  class CRM_Core_Page_AJAX {
  
    /**
 -   * function to call generic ajax forms
 +   * Call generic ajax forms.
     *
 -   * @static
 -   * @access public
     */
 -  static function run() {
 +  public static function run() {
      $className = CRM_Utils_Type::escape($_REQUEST['class_name'], 'String');
      $type = '';
      if (!empty($_REQUEST['type'])) {
@@@ -73,7 -75,7 +73,7 @@@
          // FIXME: This is done to maintain current wire protocol, but it might be
          // simpler to just require different 'types' for pages and forms
          if (preg_match('/^CRM_[a-zA-Z0-9]+_Page_Inline_/', $className)) {
 -          $page = new $className;
 +          $page = new $className();
            $page->run();
          }
          else {
@@@ -81,7 -83,6 +81,7 @@@
            $wrapper->run($className);
          }
          break;
 +
        default:
          CRM_Core_Error::debug_log_message('Unsupported inline request type: ' . var_export($type, TRUE));
      }
    }
  
    /**
 -   * function to change is_quick_config priceSet to complex
 +   * Change is_quick_config priceSet to complex.
     *
 -   * @static
 -   * @access public
     */
 -  static function setIsQuickConfig() {
 +  public static function setIsQuickConfig() {
      $id = $context = NULL;
      if (!empty($_REQUEST['id'])) {
        $id = CRM_Utils_Type::escape($_REQUEST['id'], 'Integer');
      // return false if $id is null and
      // $context is not civicrm_event or civicrm_contribution_page
      if (!$id || !in_array($context, array('civicrm_event', 'civicrm_contribution_page'))) {
 -      return false;
 +      return FALSE;
      }
      $priceSetId = CRM_Price_BAO_PriceSet::getFor($context, $id, NULL);
      if ($priceSetId) {
        }
      }
      if (!$result) {
 -      $priceSetId = null;
 +      $priceSetId = NULL;
      }
      CRM_Utils_JSON::output($priceSetId);
    }
    /**
     * Determine whether the request is for a valid class/method name.
     *
 -   * @param string $type 'method'|'class'|''
 -   * @param string $className 'Class_Name'
 -   * @param string $fnName method name
 +   * @param string $type
 +   *   'method'|'class'|''.
 +   * @param string $className
 +   *   'Class_Name'.
 +   * @param string $fnName
 +   *   Method name.
     *
     * @return bool
     */
 -  static function checkAuthz($type, $className, $fnName = null) {
 +  public static function checkAuthz($type, $className, $fnName = NULL) {
      switch ($type) {
        case 'method':
          if (!preg_match('/^CRM_[a-zA-Z0-9]+_Page_AJAX$/', $className)) {
            return FALSE;
          }
          return class_exists($className);
 +
        default:
          return FALSE;
      }
     * Outputs the CiviCRM standard json-formatted page/form response
     * @param array|string $response
     */
 -  static function returnJsonResponse($response) {
 +  public static function returnJsonResponse($response) {
      // Allow lazy callers to not wrap content in an array
      if (is_string($response)) {
        $response = array('content' => $response);
    }
  
    /**
 -   * Set headers appropriate for a js file
 +   * Set headers appropriate for a js file.
 +   *
 +   * @param int|NULL $ttl
 +   *   Time-to-live (seconds).
     */
 -  static function setJsHeaders() {
 -    // Encourage browsers to cache for a long time - 1 year
 -    $year = 60*60*24*364;
 -    header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + $year));
 +  public static function setJsHeaders($ttl = NULL) {
 +    if ($ttl === NULL) {
 +      // Encourage browsers to cache for a long time - 1 year
 +      $ttl = 60 * 60 * 24 * 364;
 +    }
 +    header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
      header('Content-Type:     application/javascript');
 -    header("Cache-Control: max-age=$year, public");
 +    header("Cache-Control: max-age=$ttl, public");
    }
  
-   /**
-    * Send autocomplete results to the client. Input can be a simple or nested array.
-    * @param array $results
-    *   If nested array, also provide:.
-    * @param string $val
-    *   Array key to use as the value.
-    * @param string $key
-    *   Array key to use as the key.
-    * @deprecated
-    */
-   public static function autocompleteResults($results, $val = 'label', $key = 'id') {
-     $output = array();
-     if (is_array($results)) {
-       foreach ($results as $k => $v) {
-         if (is_array($v)) {
-           echo $v[$val] . '|' . $v[$key] . "\n";
-         }
-         else {
-           echo "$v|$k\n";
-         }
-       }
-     }
-     CRM_Utils_System::civiExit();
-   }
  }
 -
index 1dab01874ec708ac04fa7d371b0391a30264ec19,fb60205d36b9773dd6b0ccc8025409b6dabdfaec..729452ed1ace019f2ac4336dbd1dc861c2b34cbb
@@@ -47,7 -47,7 +47,7 @@@
       <title>Get Image File</title>
       <page_callback>CRM_Contact_Page_ImageFile</page_callback>
       <access_arguments>*always allow*</access_arguments>
 -  </item>  
 +  </item>
    <item>
       <path>civicrm/contact/search/basic</path>
       <title>Find Contacts</title>
       <title>CiviCRM Blog</title>
       <page_callback>CRM_Dashlet_Page_Blog</page_callback>
    </item>
-   <item>
-     <path>civicrm/ajax/search</path>
-     <page_callback>CRM_Contact_Page_AJAX::search</page_callback>
-     <access_arguments>access CiviCRM</access_arguments>
- </item>
  <item>
       <path>civicrm/ajax/relation</path>
       <page_callback>CRM_Contact_Page_AJAX::relationship</page_callback>
       <access_arguments>access CiviCRM</access_arguments>
       <page_type>3</page_type>
  </item>
 -<item>
 -     <path>civicrm/ajax/ed</path>
 -     <page_callback>CRM_Contact_Page_AJAX::enableDisable</page_callback>
 -     <access_arguments>access CiviCRM</access_arguments>
 -     <page_type>3</page_type>
 -</item>
  <item>
       <path>civicrm/ajax/cmsuser</path>
       <page_callback>CRM_Contact_Page_AJAX::checkUserName</page_callback>
index f5698efeb691f36d7fad0f9ee81c52eda2e7842a,a069036e9f2d4535438a84cb2af3f3cb1c10230a..f9e194520b2b14fc111e7762a28927ae329daa9a
@@@ -1,7 -1,8 +1,7 @@@
  <?php
 -
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -24,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
   * This class contains all the function that are called using AJAX
   */
  class CRM_Financial_Page_AJAX {
 -  /*
 -   * Function to get financial accounts of required account relationship
 +
 +  /**
 +   * get financial accounts of required account relationship.
     * $financialAccountType array with key account relationship and value financial account type option groups
     *
 -   */
 -  /**
     * @param $config
     */
 -  static function jqFinancial($config) {
 +  public static function jqFinancial($config) {
      if (!isset($_GET['_value']) ||
 -      empty($_GET['_value'])) {
 +      empty($_GET['_value'])
 +    ) {
        CRM_Utils_System::civiExit();
      }
      $defaultId = NULL;
@@@ -63,7 -64,6 +63,7 @@@
          '7' => 4, //cost of sales
          '8' => 1, //premium inventory
          '9' => 3, //discount account is
 +        '10' => 2, //sales tax liability
        );
        $financialAccountType = CRM_Utils_Array::value($_GET['_value'], $financialAccountType);
        $result = CRM_Contribute_PseudoConstant::financialAccount(NULL, $financialAccountType);
      }
      $elements = array(
        array(
 -        'name'  => ts('- select -'),
 +        'name' => ts('- select -'),
          'value' => 'select',
 -      )
 +      ),
      );
  
 -    if (!empty($result)){
 +    if (!empty($result)) {
        foreach ($result as $id => $name) {
          $selectedArray = array();
          if ($id == $defaultId) {
            $selectedArray['selected'] = 'Selected';
          }
          $elements[] = array(
 -          'name'  => $name,
 +          'name' => $name,
            'value' => $id,
          ) + $selectedArray;
        }
    /**
     * @param $config
     */
 -  static function jqFinancialRelation($config) {
 +  public static function jqFinancialRelation($config) {
      if (!isset($_GET['_value']) ||
 -      empty($_GET['_value'])) {
 +      empty($_GET['_value'])
 +    ) {
        CRM_Utils_System::civiExit();
      }
  
  
      $elements = array(
        array(
 -        'name'  => ts('- Select Financial Account Relationship -'),
 +        'name' => ts('- Select Financial Account Relationship -'),
          'value' => 'select',
 -      )
 +      ),
      );
  
      $countResult = count($financialAccountType[$financialAccountTypeId]);
      if (!empty($result)) {
        foreach ($result as $id => $name) {
 -        if (in_array($id, $financialAccountType[$financialAccountTypeId])  && $_GET['_value'] != 'select') {
 -          if ($countResult != 1){
 +        if (in_array($id, $financialAccountType[$financialAccountTypeId]) && $_GET['_value'] != 'select') {
 +          if ($countResult != 1) {
              $elements[] = array(
 -              'name'  => $name,
 +              'name' => $name,
                'value' => $id,
              );
            }
            else {
              $elements[] = array(
 -              'name'     => $name,
 -              'value'    => $id,
 +              'name' => $name,
 +              'value' => $id,
                'selected' => 'Selected',
              );
            }
          }
 -        elseif ($_GET['_value'] == 'select'){
 +        elseif ($_GET['_value'] == 'select') {
            $elements[] = array(
 -            'name'  => $name,
 +            'name' => $name,
              'value' => $id,
            );
          }
    /**
     * @param $config
     */
 -  static function jqFinancialType($config) {
 -    if (! isset($_GET['_value']) ||
 -      empty($_GET['_value'])) {
 +  public static function jqFinancialType($config) {
 +    if (!isset($_GET['_value']) ||
 +      empty($_GET['_value'])
 +    ) {
        CRM_Utils_System::civiExit();
      }
  
    /**
     * Callback to perform action on batch records.
     */
 -  static function assignRemove() {
 +  public static function assignRemove() {
      $op = CRM_Utils_Type::escape($_POST['op'], 'String');
      $recordBAO = CRM_Utils_Type::escape($_POST['recordBAO'], 'String');
      foreach ($_POST['records'] as $record) {
        }
      }
  
 -    $entityID  = CRM_Utils_Array::value('entityID', $_POST);
 +    $entityID = CRM_Utils_Array::value('entityID', $_POST);
      $methods = array(
        'assign' => 'addBatchEntity',
        'remove' => 'removeBatchEntity',
      if ($recordClass[0] == 'CRM' && count($recordClass) >= 3) {
        foreach ($records as $recordID) {
          $params = array();
 -        $ids = null;
 +        $ids = NULL;
          switch ($op) {
            case 'assign':
            case 'remove':
              $recordPID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $recordID, 'payment_instrument_id');
              $batchPID = CRM_Core_DAO::getFieldValue('CRM_Batch_DAO_Batch', $entityID, 'payment_instrument_id');
 -            $paymentInstrument =  CRM_Core_OptionGroup::getLabel('payment_instrument',$batchPID);
 +            $paymentInstrument = CRM_Core_OptionGroup::getLabel('payment_instrument', $batchPID);
              if ($op == 'remove' || ($recordPID == $batchPID && $op == 'assign') || !isset($batchPID)) {
                $params = array(
                  'entity_id' => $recordID,
                );
              }
              else {
 -              $response = array('status' => ts("This batch is configured to include only transactions using %1 payment method. If you want to include other transactions, please edit the batch first and modify the Payment Method.", array( 1 => $paymentInstrument)));
 +              $response = array('status' => ts("This batch is configured to include only transactions using %1 payment method. If you want to include other transactions, please edit the batch first and modify the Payment Method.", array(1 => $paymentInstrument)));
              }
              break;
 +
            case 'close':
              // Update totals when closing a batch
              $params = $totals[$recordID];
      CRM_Utils_JSON::output($response);
    }
  
 -  static function getFinancialTransactionsList() {
 -    $sortMapper =
 -      array(
 -        0 => '', 1 => '', 2 => 'sort_name',
 -        3 => 'amount', 4 => 'trxn_id', 5 => 'transaction_date', 6 => 'payment_method', 7 => 'status', 8 => 'name',
 -      );
 +  public static function getFinancialTransactionsList() {
 +    $sortMapper = array(
 +      0 => '',
 +      1 => '',
 +      2 => 'sort_name',
 +      3 => 'amount',
 +      4 => 'trxn_id',
 +      5 => 'transaction_date',
 +      6 => 'payment_method',
 +      7 => 'status',
 +      8 => 'name',
 +    );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
 -    $context   = isset($_REQUEST['context']) ? CRM_Utils_Type::escape($_REQUEST['context'], 'String') : NULL;
 -    $entityID  = isset($_REQUEST['entityID']) ? CRM_Utils_Type::escape($_REQUEST['entityID'], 'String') : NULL;
 +    $context = isset($_REQUEST['context']) ? CRM_Utils_Type::escape($_REQUEST['context'], 'String') : NULL;
 +    $entityID = isset($_REQUEST['entityID']) ? CRM_Utils_Type::escape($_REQUEST['entityID'], 'String') : NULL;
      $notPresent = isset($_REQUEST['notPresent']) ? CRM_Utils_Type::escape($_REQUEST['notPresent'], 'String') : NULL;
 -    $statusID  = isset($_REQUEST['statusID']) ? CRM_Utils_Type::escape($_REQUEST['statusID'], 'String') : NULL;
 -    $search    = isset($_REQUEST['search']) ? TRUE : FALSE;
 +    $statusID = isset($_REQUEST['statusID']) ? CRM_Utils_Type::escape($_REQUEST['statusID'], 'String') : NULL;
 +    $search = isset($_REQUEST['search']) ? TRUE : FALSE;
  
      $params = $_POST;
      if ($sort && $sortOrder) {
        $params['sortBy'] = $sort . ' ' . $sortOrder;
      }
  
 -    $returnvalues =
 -      array(
 -        'civicrm_financial_trxn.payment_instrument_id as payment_method',
 -        'civicrm_contribution.contact_id as contact_id',
 -        'civicrm_contribution.id as contributionID',
 -        'contact_a.sort_name',
 -        'civicrm_financial_trxn.total_amount as amount',
 -        'civicrm_financial_trxn.trxn_id as trxn_id',
 -        'contact_a.contact_type',
 -        'contact_a.contact_sub_type',
 -        'civicrm_financial_trxn.trxn_date as transaction_date',
 -        'name',
 -        'civicrm_contribution.currency as currency',
 -        'civicrm_financial_trxn.status_id as status',
 -        'civicrm_financial_trxn.check_number as check_number',
 -      );
 +    $returnvalues = array(
 +      'civicrm_financial_trxn.payment_instrument_id as payment_method',
 +      'civicrm_contribution.contact_id as contact_id',
 +      'civicrm_contribution.id as contributionID',
 +      'contact_a.sort_name',
 +      'civicrm_financial_trxn.total_amount as amount',
 +      'civicrm_financial_trxn.trxn_id as trxn_id',
 +      'contact_a.contact_type',
 +      'contact_a.contact_sub_type',
 +      'civicrm_financial_trxn.trxn_date as transaction_date',
 +      'name',
 +      'civicrm_contribution.currency as currency',
 +      'civicrm_financial_trxn.status_id as status',
 +      'civicrm_financial_trxn.check_number as check_number',
 +    );
  
 -    $columnHeader =
 -      array(
 -        'contact_type' => '',
 -        'sort_name' => ts('Contact Name'),
 -        'amount'   => ts('Amount'),
 -        'trxn_id'  => ts('Trxn ID'),
 -        'transaction_date' => ts('Received'),
 -        'payment_method' => ts('Payment Method'),
 -        'status'  => ts('Status'),
 -        'name' => ts('Type'),
 -      );
 +    $columnHeader = array(
 +      'contact_type' => '',
 +      'sort_name' => ts('Contact Name'),
 +      'amount' => ts('Amount'),
 +      'trxn_id' => ts('Trxn ID'),
 +      'transaction_date' => ts('Received'),
 +      'payment_method' => ts('Payment Method'),
 +      'status' => ts('Status'),
 +      'name' => ts('Type'),
 +    );
  
      if ($sort && $sortOrder) {
        $params['sortBy'] = $sort . ' ' . $sortOrder;
      $params['rp'] = $rowCount;
  
      $params['context'] = $context;
 -    $params['offset']   = ($params['page'] - 1) * $params['rp'];
 +    $params['offset'] = ($params['page'] - 1) * $params['rp'];
      $params['rowCount'] = $params['rp'];
 -    $params['sort']     = CRM_Utils_Array::value('sortBy', $params);
 -    $params['total']    = 0;
 +    $params['sort'] = CRM_Utils_Array::value('sortBy', $params);
 +    $params['total'] = 0;
  
      // get batch list
      if (isset($notPresent)) {
          }
          $row[$financialItem->id][$columnKey] = $financialItem->$columnKey;
          if ($columnKey == 'sort_name' && $financialItem->$columnKey) {
 -          $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=".$financialItem->contact_id);
 -          $row[$financialItem->id][$columnKey] = '<a href='.$url.'>'.$financialItem->$columnKey.'</a>';
 +          $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=" . $financialItem->contact_id);
 +          $row[$financialItem->id][$columnKey] = '<a href=' . $url . '>' . $financialItem->$columnKey . '</a>';
          }
          elseif ($columnKey == 'payment_method' && $financialItem->$columnKey) {
            $row[$financialItem->id][$columnKey] = CRM_Core_OptionGroup::getLabel('payment_instrument', $financialItem->$columnKey);
            if ($row[$financialItem->id][$columnKey] == 'Check') {
 -            $row[$financialItem->id][$columnKey] = $row[$financialItem->id][$columnKey].' ('.$financialItem->check_number.')';
 +            $row[$financialItem->id][$columnKey] = $row[$financialItem->id][$columnKey] . ' (' . $financialItem->check_number . ')';
            }
          }
          elseif ($columnKey == 'amount' && $financialItem->$columnKey) {
            $row[$financialItem->id][$columnKey] = CRM_Utils_Money::format($financialItem->$columnKey, $financialItem->currency);
          }
          elseif ($columnKey == 'transaction_date' && $financialItem->$columnKey) {
 -          $row[$financialItem->id][$columnKey] =  CRM_Utils_Date::customFormat($financialItem->$columnKey);
 +          $row[$financialItem->id][$columnKey] = CRM_Utils_Date::customFormat($financialItem->$columnKey);
          }
          elseif ($columnKey == 'status' && $financialItem->$columnKey) {
            $row[$financialItem->id][$columnKey] = CRM_Core_OptionGroup::getLabel('contribution_status', $financialItem->$columnKey);
          }
        }
 -      if ($statusID == CRM_Core_OptionGroup::getValue('batch_status','Open')) {
 +      if ($statusID == CRM_Core_OptionGroup::getValue('batch_status', 'Open')) {
          if (isset($notPresent)) {
            $js = "enableActions('x')";
 -          $row[$financialItem->id]['check'] = "<input type='checkbox' id='mark_x_". $financialItem->id."' name='mark_x_". $financialItem->id."' value='1' onclick={$js}></input>";
 +          $row[$financialItem->id]['check'] = "<input type='checkbox' id='mark_x_" . $financialItem->id . "' name='mark_x_" . $financialItem->id . "' value='1' onclick={$js}></input>";
            $row[$financialItem->id]['action'] = CRM_Core_Action::formLink(
              CRM_Financial_Form_BatchTransaction::links(),
 -            null,
 +            NULL,
              array(
                'id' => $financialItem->id,
                'contid' => $financialItem->contributionID,
 -              'cid' => $financialItem->contact_id
 +              'cid' => $financialItem->contact_id,
              ),
              ts('more'),
              FALSE,
          }
          else {
            $js = "enableActions('y')";
 -          $row[$financialItem->id]['check'] = "<input type='checkbox' id='mark_y_". $financialItem->id."' name='mark_y_". $financialItem->id."' value='1' onclick={$js}></input>";
 +          $row[$financialItem->id]['check'] = "<input type='checkbox' id='mark_y_" . $financialItem->id . "' name='mark_y_" . $financialItem->id . "' value='1' onclick={$js}></input>";
            $row[$financialItem->id]['action'] = CRM_Core_Action::formLink(
              CRM_Financial_Page_BatchTransaction::links(),
 -            null,
 +            NULL,
              array(
                'id' => $financialItem->id,
                'contid' => $financialItem->contributionID,
 -              'cid' => $financialItem->contact_id
 +              'cid' => $financialItem->contact_id,
              ),
              ts('more'),
              FALSE,
          unset($links['remove']);
          $row[$financialItem->id]['action'] = CRM_Core_Action::formLink(
            $links,
 -          null,
 +          NULL,
            array(
              'id' => $financialItem->id,
              'contid' => $financialItem->contributionID,
 -            'cid' => $financialItem->contact_id
 +            'cid' => $financialItem->contact_id,
            ),
            ts('more'),
            FALSE,
            $financialItem->id
          );
        }
 -      $row[$financialItem->id]['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage(CRM_Utils_Array::value('contact_sub_type',$row[$financialItem->id]) ? CRM_Utils_Array::value('contact_sub_type',$row[$financialItem->id]) : CRM_Utils_Array::value('contact_type',$row[$financialItem->id]) ,false, $financialItem->contact_id);
 +      $row[$financialItem->id]['contact_type'] = CRM_Contact_BAO_Contact_Utils::getImage(CRM_Utils_Array::value('contact_sub_type', $row[$financialItem->id]) ? CRM_Utils_Array::value('contact_sub_type', $row[$financialItem->id]) : CRM_Utils_Array::value('contact_type', $row[$financialItem->id]), FALSE, $financialItem->contact_id);
        $financialitems = $row;
      }
  
 -    $iFilteredTotal = $iTotal =  $params['total'];
 -    $selectorElements =
 -      array(
 -        'check', 'contact_type', 'sort_name',
 -        'amount', 'trxn_id', 'transaction_date', 'payment_method', 'status', 'name', 'action',
 -      );
 +    $iFilteredTotal = $iTotal = $params['total'];
 +    $selectorElements = array(
 +      'check',
 +      'contact_type',
 +      'sort_name',
 +      'amount',
 +      'trxn_id',
 +      'transaction_date',
 +      'payment_method',
 +      'status',
 +      'name',
 +      'action',
 +    );
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($financialitems, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
  
 -  static function bulkAssignRemove() {
 +  public static function bulkAssignRemove() {
      $checkIDs = $_REQUEST['ID'];
      $entityID = CRM_Utils_Type::escape($_REQUEST['entityID'], 'String');
 -    $action   = CRM_Utils_Type::escape($_REQUEST['action'], 'String');
 +    $action = CRM_Utils_Type::escape($_REQUEST['action'], 'String');
      foreach ($checkIDs as $key => $value) {
 -      if ((substr($value,0,7) == "mark_x_" && $action == 'Assign') || (substr($value,0,7) == "mark_y_" && $action == 'Remove')) {
 -        $contributions = explode("_",$value);
 +      if ((substr($value, 0, 7) == "mark_x_" && $action == 'Assign') || (substr($value, 0, 7) == "mark_y_" && $action == 'Remove')) {
 +        $contributions = explode("_", $value);
          $cIDs[] = $contributions[2];
        }
      }
  
      $batchPID = CRM_Core_DAO::getFieldValue('CRM_Batch_DAO_Batch', $entityID, 'payment_instrument_id');
 -    $paymentInstrument =  CRM_Core_OptionGroup::getLabel('payment_instrument',$batchPID);
 +    $paymentInstrument = CRM_Core_OptionGroup::getLabel('payment_instrument', $batchPID);
      foreach ($cIDs as $key => $value) {
        $recordPID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $value, 'payment_instrument_id');
 -      if ($action == 'Remove' || ($recordPID == $batchPID && $action == 'Assign')  || !isset($batchPID)) {
 -        $params =
 -          array(
 -            'entity_id' => $value,
 -            'entity_table' => 'civicrm_financial_trxn',
 -            'batch_id' => $entityID,
 -          );
 +      if ($action == 'Remove' || ($recordPID == $batchPID && $action == 'Assign') || !isset($batchPID)) {
 +        $params = array(
 +          'entity_id' => $value,
 +          'entity_table' => 'civicrm_financial_trxn',
 +          'batch_id' => $entityID,
 +        );
          if ($action == 'Assign') {
            $updated = CRM_Batch_BAO_Batch::addBatchEntity($params);
          }
        $status = array('status' => 'record-updated-success');
      }
      else {
 -      $status = array('status' => ts("This batch is configured to include only transactions using %1 payment method. If you want to include other transactions, please edit the batch first and modify the Payment Method.", array( 1 => $paymentInstrument)));
 +      $status = array('status' => ts("This batch is configured to include only transactions using %1 payment method. If you want to include other transactions, please edit the batch first and modify the Payment Method.", array(1 => $paymentInstrument)));
      }
      CRM_Utils_JSON::output($status);
    }
  
 -  static function getBatchSummary() {
 +  public static function getBatchSummary() {
      $batchID = CRM_Utils_Type::escape($_REQUEST['batchID'], 'String');
      $params = array('id' => $batchID);
      $batchInfo = CRM_Batch_BAO_Batch::retrieve($params, $value);
      $batchTotals = CRM_Batch_BAO_Batch::batchTotals(array($batchID));
 -    $batchSummary =
 -      array(
 -        'created_by' => CRM_Contact_BAO_Contact::displayName($batchInfo->created_id),
 -        'status' => CRM_Core_OptionGroup::getLabel('batch_status', $batchInfo->status_id),
 -        'description' => $batchInfo->description,
 -        'payment_instrument' => CRM_Core_OptionGroup::getLabel('payment_instrument', $batchInfo->payment_instrument_id),
 -        'item_count' => $batchInfo->item_count,
 -        'assigned_item_count' => $batchTotals[$batchID]['item_count'],
 -        'total' => CRM_Utils_Money::format($batchInfo->total),
 -        'assigned_total' => CRM_Utils_Money::format($batchTotals[$batchID]['total']),
 -        'opened_date' => CRM_Utils_Date::customFormat($batchInfo->created_date),
 -      );
 +    $batchSummary = array(
 +      'created_by' => CRM_Contact_BAO_Contact::displayName($batchInfo->created_id),
 +      'status' => CRM_Core_OptionGroup::getLabel('batch_status', $batchInfo->status_id),
 +      'description' => $batchInfo->description,
 +      'payment_instrument' => CRM_Core_OptionGroup::getLabel('payment_instrument', $batchInfo->payment_instrument_id),
 +      'item_count' => $batchInfo->item_count,
 +      'assigned_item_count' => $batchTotals[$batchID]['item_count'],
 +      'total' => CRM_Utils_Money::format($batchInfo->total),
 +      'assigned_total' => CRM_Utils_Money::format($batchTotals[$batchID]['total']),
 +      'opened_date' => CRM_Utils_Date::customFormat($batchInfo->created_date),
 +    );
  
      CRM_Utils_JSON::output($batchSummary);
    }
 +
  }
diff --combined CRM/Group/Page/AJAX.php
index 2a346f8eac9c2a9065ec764e8cb599a6526c1b89,4b2aa2029b29f06135e37088fcf1b122ee9c558a..ce150a1422aa140ef1f41c01ed147134165ba779
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
   * This class contains the functions that are called using AJAX (jQuery)
   */
  class CRM_Group_Page_AJAX {
 -  static function getGroupList() {
 +  /**
 +   * Get list of groups.
 +   *
 +   * @return array
 +   */
 +  public static function getGroupList() {
      $params = $_REQUEST;
  
      if (isset($params['parent_id'])) {
        // requesting child groups for a given parent
        $params['page'] = 1;
 -      $params['rp']   = 0;
 +      $params['rp'] = 0;
        $groups = CRM_Contact_BAO_Group::getGroupListSelector($params);
  
        CRM_Utils_JSON::output($groups);
      }
      else {
        $sortMapper = array(
 -        0 => 'groups.title', 1 => 'count', 2 => 'createdBy.sort_name', 3 => '',
 -        4 => 'groups.group_type', 5 => 'groups.visibility',
 +        0 => 'groups.title',
 +        1 => 'count',
 +        2 => 'createdBy.sort_name',
 +        3 => '',
 +        4 => 'groups.group_type',
 +        5 => 'groups.visibility',
        );
  
 -      $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -      $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -      $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -      $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +      $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +      $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +      $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +      $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
        $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
        if ($sort && $sortOrder) {
@@@ -82,7 -73,7 +82,7 @@@
        // go ahead with flat hierarchy, CRM-12225
        if (empty($groups)) {
          $groupsAccessible = CRM_Core_PseudoConstant::group();
 -        $parentsOnly      = CRM_Utils_Array::value('parentsOnly', $params);
 +        $parentsOnly = CRM_Utils_Array::value('parentsOnly', $params);
          if (!empty($groupsAccessible) && $parentsOnly) {
            // recompute group list with flat hierarchy
            $params['parentsOnly'] = 0;
  
        $iFilteredTotal = $iTotal = $params['total'];
        $selectorElements = array(
 -        'group_name', 'count', 'created_by', 'group_description',
 -        'group_type', 'visibility', 'org_info', 'links', 'class',
 +        'group_name',
 +        'count',
 +        'created_by',
 +        'group_description',
 +        'group_type',
 +        'visibility',
 +        'org_info',
 +        'links',
 +        'class',
        );
  
        if (empty($params['showOrgInfo'])) {
          unset($selectorElements[6]);
        }
 -     //add setting so this can be tested by unit test
 -     //@todo - ideally the portion of this that retrieves the groups should be extracted into a function separate
 -     // from the one which deals with web inputs & outputs so we have a properly testable & re-usable function
 -      if(!empty($params['is_unit_test'])) {
 +      //add setting so this can be tested by unit test
 +      //@todo - ideally the portion of this that retrieves the groups should be extracted into a function separate
 +      // from the one which deals with web inputs & outputs so we have a properly testable & re-usable function
 +      if (!empty($params['is_unit_test'])) {
          return array($groups, $iFilteredTotal);
        }
+       header('Content-Type: application/json');
        echo CRM_Utils_JSON::encodeDataTableSelector($groups, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
        CRM_Utils_System::civiExit();
      }
    }
 -}
  
 +}
index 7a632418a3b67a246a42d7b281bbadac26837a5b,3da5da0dbcaeb0dc2a9431a4f498dfce99bd8d81..05d87cee7dd55a23739fac1fa183dea383bdf9a6
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
  class CRM_Mailing_BAO_Component extends CRM_Mailing_DAO_Component {
  
    /**
 -   * class constructor
 +   * Class constructor.
     */
 -  function __construct() {
 +  public function __construct() {
      parent::__construct();
    }
  
    /**
 -   * Takes a bunch of params that are needed to match certain criteria and
 -   * retrieves the relevant objects. Typically the valid params are only
 -   * contact_id. We'll tweak this function to be more full featured over a period
 -   * of time. This is the inverse function of create. It also stores all the retrieved
 -   * values in the default array
 +   * Fetch object based on array of properties.
     *
 -   * @param array $params   (reference ) an assoc array of name/value pairs
 -   * @param array $defaults (reference ) an assoc array to hold the flattened values
 +   * @param array $params
 +   *   (reference ) an assoc array of name/value pairs.
 +   * @param array $defaults
 +   *   (reference ) an assoc array to hold the flattened values.
     *
 -   * @return object CRM_Core_BAO_LocaationType object
 -   * @access public
 -   * @static
 +   * @return CRM_Core_BAO_LocaationType
     */
 -  static function retrieve(&$params, &$defaults) {
 +  public static function retrieve(&$params, &$defaults) {
      $component = new CRM_Mailing_DAO_Component();
      $component->copyValues($params);
      if ($component->find(TRUE)) {
    }
  
    /**
 -   * update the is_active flag in the db
 +   * Update the is_active flag in the db.
     *
 -   * @param int      $id        id of the database record
 -   * @param boolean  $is_active value we want to set the is_active field
 +   * @param int $id
 +   *   Id of the database record.
 +   * @param bool $is_active
 +   *   Value we want to set the is_active field.
     *
 -   * @return Object             DAO object on sucess, null otherwise
 -   * @static
 +   * @return Object
 +   *   DAO object on sucess, null otherwise
     */
 -  static function setIsActive($id, $is_active) {
 +  public static function setIsActive($id, $is_active) {
      return CRM_Core_DAO::setFieldValue('CRM_Mailing_DAO_Component', $id, 'is_active', $is_active);
    }
  
    /**
 -   * Create and Update mailing component
 +   * Create and Update mailing component.
     *
 -   * @param array $params (reference ) an assoc array of name/value pairs
 -   * @param array $ids (deprecated) the array that holds all the db ids
 +   * @param array $params
 +   *   (reference ) an assoc array of name/value pairs.
 +   * @param array $ids
 +   *   (deprecated) the array that holds all the db ids.
     *
 -   * @return object CRM_Mailing_BAO_Component object
 +   * @return CRM_Mailing_BAO_Component
     *
 -   * @access public
 -   * @static
     */
 -  static function add(&$params, $ids = array()) {
 +  public static function add(&$params, $ids = array()) {
      $id = CRM_Utils_Array::value('id', $params, CRM_Utils_Array::value('id', $ids));
      $component = new CRM_Mailing_DAO_Component();
-     $component->id = $id;
+     if ($id) {
+       $component->id = $id;
+       $component->find(TRUE);
+     }
      $component->copyValues($params);
      if (empty($id) && empty($params['body_text'])) {
        $component->body_text = CRM_Utils_String::htmlToText(CRM_Utils_Array::value('body_html', $params));
      }
  
-     if ($component->is_default && !empty($id)) {
-       CRM_Core_DAO::executeQuery("UPDATE civicrm_mailing_component SET is_default = 0 WHERE component_type ='{$component->component_type}' AND id <> $id");
+     if ($component->is_default) {
+       if (!empty($id)) {
+         $sql = 'UPDATE civicrm_mailing_component SET is_default = 0 WHERE component_type = %1 AND id <> %2';
+         $sqlParams = array(
+           1 => array($component->component_type, 'String'),
+           2 => array($id, 'Positive'),
+         );
+       }
+       else {
+         $sql = 'UPDATE civicrm_mailing_component SET is_default = 0 WHERE component_type = %1';
+         $sqlParams = array(
+           1 => array($component->component_type, 'String'),
+         );
+       }
+       CRM_Core_DAO::executeQuery($sql, $sqlParams);
      }
  
      $component->save();
      return $component;
    }
 +
  }
index 19e43393c733091fc566ab9f46578b1d291ed083,d826725971e8f7b76376bec2494773ca0ee4cebd..94e7f7f40a09f0009d11d25e383d70608a695f5e
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
@@@ -89,32 -89,31 +89,32 @@@ class CRM_Mailing_BAO_Mailing extends C
    private $_domain = NULL;
  
    /**
 -   * class constructor
 +   * Class constructor
     */
 -  function __construct() {
 +  public function __construct() {
      parent::__construct();
    }
  
    /**
 -   * @param $job_id
 -   * @param null $mailing_id
 +   * @param int $job_id
 +   * @param int $mailing_id
     * @param null $mode
     *
     * @return int
     */
 -  static function &getRecipientsCount($job_id, $mailing_id = NULL, $mode = NULL) {
 +  public static function &getRecipientsCount($job_id, $mailing_id = NULL, $mode = NULL) {
      // need this for backward compatibility, so we can get count for old mailings
      // please do not use this function if possible
      $eq = self::getRecipients($job_id, $mailing_id);
      return $eq->N;
    }
  
 -  // note that $job_id is used only as a variable in the temp table construction
 -  // and does not play a role in the queries generated
    /**
 -   * @param $job_id
 -   * @param null $mailing_id
 +   * note that $job_id is used only as a variable in the temp table construction
 +   * and does not play a role in the queries generated
 +   * @param int $job_id
 +   *   (misnomer) a nonce value used to name temporary tables.
 +   * @param int $mailing_id
     * @param null $offset
     * @param null $limit
     * @param bool $storeRecipients
     *
     * @return CRM_Mailing_Event_BAO_Queue|string
     */
 -  static function &getRecipients(
 +  public static function &getRecipients(
      $job_id,
      $mailing_id = NULL,
      $offset = NULL,
      $mailingGroup = new CRM_Mailing_DAO_MailingGroup();
  
      $mailing = CRM_Mailing_BAO_Mailing::getTableName();
 -    $job     = CRM_Mailing_BAO_MailingJob::getTableName();
 -    $mg      = CRM_Mailing_DAO_MailingGroup::getTableName();
 -    $eq      = CRM_Mailing_Event_DAO_Queue::getTableName();
 -    $ed      = CRM_Mailing_Event_DAO_Delivered::getTableName();
 -    $eb      = CRM_Mailing_Event_DAO_Bounce::getTableName();
 +    $job = CRM_Mailing_BAO_MailingJob::getTableName();
 +    $mg = CRM_Mailing_DAO_MailingGroup::getTableName();
 +    $eq = CRM_Mailing_Event_DAO_Queue::getTableName();
 +    $ed = CRM_Mailing_Event_DAO_Delivered::getTableName();
 +    $eb = CRM_Mailing_Event_DAO_Bounce::getTableName();
  
      $email = CRM_Core_DAO_Email::getTableName();
      if ($mode == 'sms') {
      $group = CRM_Contact_DAO_Group::getTableName();
      $g2contact = CRM_Contact_DAO_GroupContact::getTableName();
  
 +    $m = new CRM_Mailing_DAO_Mailing();
 +    $m->id = $mailing_id;
 +    $m->find(TRUE);
 +
 +    $email_selection_method = $m->email_selection_method;
 +    $location_type_id = $m->location_type_id;
 +
 +    // Note: When determining the ORDER that results are returned, it's
 +    // the record that comes last that counts. That's because we are
 +    // INSERT'ing INTO a table with a primary id so that last record
 +    // over writes any previous record.
 +    switch ($email_selection_method) {
 +      case 'location-exclude':
 +        $location_filter = "($email.location_type_id != $location_type_id)";
 +        // If there is more than one email that doesn't match the location,
 +        // prefer the one marked is_bulkmail, followed by is_primary.
 +        $order_by = "ORDER BY $email.is_bulkmail, $email.is_primary";
 +        break;
 +
 +      case 'location-only':
 +        $location_filter = "($email.location_type_id = $location_type_id)";
 +        // If there is more than one email of the desired location, prefer
 +        // the one marked is_bulkmail, followed by is_primary.
 +        $order_by = "ORDER BY $email.is_bulkmail, $email.is_primary";
 +        break;
 +
 +      case 'location-prefer':
 +        $location_filter = "($email.is_bulkmail = 1 OR $email.is_primary = 1 OR $email.location_type_id = $location_type_id)";
 +
 +        // ORDER BY is more complicated because we have to set an arbitrary
 +        // order that prefers the location that we want. We do that using
 +        // the FIELD function. For more info, see:
 +        // https://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_field
 +        // We assign the location type we want the value "1" by putting it
 +        // in the first position after we name the field. All other location
 +        // types are left out, so they will be assigned the value 0. That
 +        // means, they will all be equally tied for first place, with our
 +        // location being last.
 +        $order_by = "ORDER BY FIELD($email.location_type_id, $location_type_id), $email.is_bulkmail, $email.is_primary";
 +        break;
 +
 +      case 'automatic':
 +        // fall through to default
 +      default:
 +        $location_filter = "($email.is_bulkmail = 1 OR $email.is_primary = 1)";
 +        $order_by = "ORDER BY $email.is_bulkmail";
 +    }
 +
      /* Create a temp table for contact exclusion */
      $mailingGroup->query(
        "CREATE TEMPORARY TABLE X_$job_id
      );
  
      /* Add all the members of groups excluded from this mailing to the temp
 -         * table */
 +     * table */
  
      $excludeSubGroup = "INSERT INTO        X_$job_id (contact_id)
                      SELECT  DISTINCT    $g2contact.contact_id
      $mailingGroup->query($excludeSubGroup);
  
      /* Add all unsubscribe members of base group from this mailing to the temp
 -         * table */
 +     * table */
  
      $unSubscribeBaseGroup = "INSERT INTO        X_$job_id (contact_id)
                      SELECT  DISTINCT    $g2contact.contact_id
      $mailingGroup->query($unSubscribeBaseGroup);
  
      /* Add all the (intended) recipients of an excluded prior mailing to
 -         * the temp table */
 +     * the temp table */
  
      $excludeSubMailing = "INSERT IGNORE INTO X_$job_id (contact_id)
                      SELECT  DISTINCT    $eq.contact_id
@@@ -290,7 -241,7 +290,7 @@@ WHERE  c.group_id = {$groupDAO->id
      );
  
      /* Get the group contacts, but only those which are not in the
 -         * exclusion temp table */
 +     * exclusion temp table */
  
      $query = "REPLACE INTO       I_$job_id (email_id, contact_id)
  
                          AND             $contact.do_not_email = 0
                          AND             $contact.is_opt_out = 0
                          AND             $contact.is_deceased = 0
 -                        AND            ($email.is_bulkmail = 1 OR $email.is_primary = 1)
 +                        AND             $location_filter
                          AND             $email.email IS NOT NULL
                          AND             $email.email != ''
                          AND             $email.on_hold = 0
                          AND             $mg.mailing_id = {$mailing_id}
                          AND             X_$job_id.contact_id IS null
 -                    ORDER BY $email.is_bulkmail";
 +                    $order_by";
  
      if ($mode == 'sms') {
        $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name');
 -      $query      = "REPLACE INTO       I_$job_id (phone_id, contact_id)
 +      $query = "REPLACE INTO       I_$job_id (phone_id, contact_id)
  
                      SELECT DISTINCT     $phone.id as phone_id,
                                          $contact.id as contact_id
                          AND             $contact.do_not_email = 0
                          AND             $contact.is_opt_out = 0
                          AND             $contact.is_deceased = 0
 -                        AND            ($email.is_bulkmail = 1 OR $email.is_primary = 1)
 +                        AND             $location_filter
                          AND             $email.on_hold = 0
                          AND             $mg.mailing_id = {$mailing_id}
                          AND             X_$job_id.contact_id IS null
 -                    ORDER BY $email.is_bulkmail";
 +                    $order_by";
  
      if ($mode == 'sms') {
        $query = "REPLACE INTO       I_$job_id (phone_id, contact_id)
@@@ -426,19 -377,19 +426,19 @@@ WHERE      $mg.entity_table = '$group
  
        $smartGroupInclude = "
  INSERT IGNORE INTO I_$job_id (email_id, contact_id)
 -SELECT     e.id as email_id, c.id as contact_id
 +SELECT     civicrm_email.id as email_id, c.id as contact_id
  FROM       civicrm_contact c
 -INNER JOIN civicrm_email e                ON e.contact_id         = c.id
 +INNER JOIN civicrm_email                ON civicrm_email.contact_id         = c.id
  INNER JOIN civicrm_group_contact_cache gc ON gc.contact_id        = c.id
  LEFT  JOIN X_$job_id                      ON X_$job_id.contact_id = c.id
  WHERE      gc.group_id = {$groupDAO->id}
    AND      c.do_not_email = 0
    AND      c.is_opt_out = 0
    AND      c.is_deceased = 0
 -  AND      (e.is_bulkmail = 1 OR e.is_primary = 1)
 -  AND      e.on_hold = 0
 +  AND      $location_filter
 +  AND      civicrm_email.on_hold = 0
    AND      X_$job_id.contact_id IS null
 -ORDER BY   e.is_bulkmail
 +$order_by
  ";
        if ($mode == 'sms') {
          $smartGroupInclude = "
@@@ -499,11 -450,11 +499,11 @@@ AND    $mg.mailing_id = {$mailing_id
                          AND             $contact.do_not_email = 0
                          AND             $contact.is_opt_out = 0
                          AND             $contact.is_deceased = 0
 -                        AND             ($email.is_bulkmail = 1 OR $email.is_primary = 1)
 +                        AND             $location_filter
                          AND             $email.on_hold = 0
                          AND             $mg.mailing_id = {$mailing_id}
                          AND             X_$job_id.contact_id IS null
 -                    ORDER BY $email.is_bulkmail";
 +                    $order_by";
      if ($mode == "sms") {
        $query = "REPLACE INTO       I_$job_id (phone_id, contact_id)
                      SELECT DISTINCT     $phone.id as phone_id,
@@@ -623,17 -574,21 +623,17 @@@ ORDER BY   i.contact_id, i.{$tempColumn
    }
  
    /**
 -   *
 -   * Returns the regex patterns that are used for preparing the text and html templates
 -   *
 -   * @access private
 -   *
 -   **/
 +   * Returns the regex patterns that are used for preparing the text and html templates.
 +   */
    private function &getPatterns($onlyHrefs = FALSE) {
  
      $patterns = array();
  
 -    $protos  = '(https?|ftp)';
 +    $protos = '(https?|ftp)';
      $letters = '\w';
 -    $gunk    = '\{\}/#~:.?+=&;%@!\,\-';
 -    $punc    = '.:?\-';
 -    $any     = "{$letters}{$gunk}{$punc}";
 +    $gunk = '\{\}/#~:.?+=&;%@!\,\-';
 +    $punc = '.:?\-';
 +    $any = "{$letters}{$gunk}{$punc}";
      if ($onlyHrefs) {
        $pattern = "\\bhref[ ]*=[ ]*([\"'])?(($protos:[$any]+?(?=[$punc]*[^$any]|$)))([\"'])?";
      }
      $patterns[] = '\\\\\{\w+\.\w+\\\\\}|\{\{\w+\.\w+\}\}';
      $patterns[] = '\{\w+\.\w+\}';
  
 -    $patterns = '{' . join('|', $patterns) . '}im';
 +    $patterns = '{' . implode('|', $patterns) . '}im';
  
      return $patterns;
    }
  
    /**
 -   *  returns an array that denotes the type of token that we are dealing with
 -   *  we use the type later on when we are doing a token replcement lookup
 +   * Returns an array that denotes the type of token that we are dealing with
 +   * we use the type later on when we are doing a token replacement lookup
     *
 -   *  @param string $token       The token for which we will be doing adata lookup
 +   * @param string $token
 +   *   The token for which we will be doing adata lookup.
     *
 -   *  @return array $funcStruct  An array that holds the token itself and the type.
 +   * @return array
 +   *   An array that holds the token itself and the type.
     *                             the type will tell us which function to use for the data lookup
     *                             if we need to do a lookup at all
     */
 -  function &getDataFunc($token) {
 +  public function &getDataFunc($token) {
      static $_categories = NULL;
      static $_categoryString = NULL;
      if (!$_categories) {
     * Prepares the text and html templates
     * for generating the emails and returns a copy of the
     * prepared templates
 -   *
 -   * @access private
 -   *
 -   **/
 +   */
    private function getPreparedTemplates() {
      if (!$this->preparedTemplates) {
 -      $patterns['html']    = $this->getPatterns(TRUE);
 +      $patterns['html'] = $this->getPatterns(TRUE);
        $patterns['subject'] = $patterns['text'] = $this->getPatterns();
 -      $templates           = $this->getTemplates();
 +      $templates = $this->getTemplates();
  
        $this->preparedTemplates = array();
  
        foreach (array(
 -        'html', 'text', 'subject') as $key) {
 +                 'html',
 +                 'text',
 +                 'subject',
 +               ) as $key) {
          if (!isset($templates[$key])) {
            continue;
          }
  
 -        $matches        = array();
 -        $tokens         = array();
 +        $matches = array();
 +        $tokens = array();
          $split_template = array();
  
          $email = $templates[$key];
    }
  
    /**
 +   * Retrieve a ref to an array that holds the email and text templates for this email
 +   * assembles the complete template including the header and footer
 +   * that the user has uploaded or declared (if they have dome that)
     *
 -   *  Retrieve a ref to an array that holds the email and text templates for this email
 -   *  assembles the complete template including the header and footer
 -   *  that the user has uploaded or declared (if they have dome that)
 -   *
 -   *
 -   * @return array reference to an assoc array
 -   * @access private
 -   *
 -   **/
 +   * @return array
 +   *   reference to an assoc array
 +   */
    private function &getTemplates() {
      if (!$this->templates) {
        $this->getHeaderFooter();
            $template[] = $this->footer->body_text;
          }
  
 -        $this->templates['text'] = join("\n", $template);
 +        $this->templates['text'] = implode("\n", $template);
        }
  
        if ($this->body_html) {
            $template[] = $this->footer->body_html;
          }
  
 -        $this->templates['html'] = join("\n", $template);
 +        $this->templates['html'] = implode("\n", $template);
  
          // this is where we create a text template from the html template if the text template did not exist
          // this way we ensure that every recipient will receive an email even if the pref is set to text and the
        if ($this->subject) {
          $template = array();
          $template[] = $this->subject;
 -        $this->templates['subject'] = join("\n", $template);
 +        $this->templates['subject'] = implode("\n", $template);
        }
      }
      return $this->templates;
     *  this function needs to have some sort of a body assigned
     *  either text or html for this to have any meaningful impact
     *
 -   * @return array               reference to an assoc array
 -   * @access public
 -   *
 -   **/
 +   * @return array
 +   *   reference to an assoc array
 +   */
    public function &getTokens() {
      if (!$this->tokens) {
  
     * Returns the token set for all 3 parts as one set. This allows it to be sent to the
     * hook in one call and standardizes it across other token workflows
     *
 -   * @return array               reference to an assoc array
 -   * @access public
 -   *
 -   **/
 +   * @return array
 +   *   reference to an assoc array
 +   */
    public function &getFlattenedTokens() {
      if (!$this->flattenedTokens) {
        $tokens = $this->getTokens();
     *  structures to represent the order in which tokens were found from left to right, top to bottom.
     *
     *
 -   * @param str $prop     name of the property that holds the text that we want to scan for tokens (html, text)
 -   * @access private
 +   * @param string $prop name of the property that holds the text that we want to scan for tokens (html, text).
 +   *   Name of the property that holds the text that we want to scan for tokens (html, text).
     *
     * @return void
     */
    }
  
    /**
 -   * Generate an event queue for a test job
 -   *
 -   * @params array $params contains form values
 +   * Generate an event queue for a test job.
     *
 -   * @param $testParams
 +   * @param array $testParams
 +   *   Contains form values.
     *
     * @return void
 -   * @access public
     */
    public function getTestRecipients($testParams) {
      if (array_key_exists($testParams['test_group'], CRM_Core_PseudoConstant::group())) {
 -      $contacts = civicrm_api('contact','get', array(
 -        'version' =>3,
 -        'group' => $testParams['test_group'],
 -         'return' => 'id',
 -           'options' => array('limit' => 100000000000,
 -          ))
 -       );
 +      $contacts = civicrm_api('contact', 'get', array(
 +          'version' => 3,
 +          'group' => $testParams['test_group'],
 +          'return' => 'id',
 +          'options' => array(
 +            'limit' => 100000000000,
 +          ),
 +        )
 +      );
  
        foreach (array_keys($contacts['values']) as $groupContact) {
          $query = "
@@@ -959,7 -917,12 +959,7 @@@ ORDER BY   civicrm_email.is_bulkmail DE
    }
  
    /**
 -   * Retrieve the header and footer for this mailing
 -   *
 -   * @param void
 -   *
 -   * @return void
 -   * @access private
 +   * Load this->header and this->footer.
     */
    private function getHeaderFooter() {
      if (!$this->header and $this->header_id) {
     * is placed on the values received, so they do not need to follow the verp
     * convention.
     *
 -   * @param array  $headers         Array of message headers to update, in-out
 -   * @param string $prefix          Prefix for the message ID, use same prefixes as verp
 +   * @param array $headers
 +   *   Array of message headers to update, in-out.
 +   * @param string $prefix
 +   *   Prefix for the message ID, use same prefixes as verp.
     *                                wherever possible
 -   * @param string $job_id          Job ID component of the generated message ID
 -   * @param string $event_queue_id  Event Queue ID component of the generated message ID
 -   * @param string $hash            Hash component of the generated message ID.
 +   * @param string $job_id
 +   *   Job ID component of the generated message ID.
 +   * @param string $event_queue_id
 +   *   Event Queue ID component of the generated message ID.
 +   * @param string $hash
 +   *   Hash component of the generated message ID.
     *
     * @return void
     */
 -  static function addMessageIdHeader(&$headers, $prefix, $job_id, $event_queue_id, $hash) {
 -    $config           = CRM_Core_Config::singleton();
 -    $localpart        = CRM_Core_BAO_MailSettings::defaultLocalpart();
 -    $emailDomain      = CRM_Core_BAO_MailSettings::defaultDomain();
 +  public static function addMessageIdHeader(&$headers, $prefix, $job_id, $event_queue_id, $hash) {
 +    $config = CRM_Core_Config::singleton();
 +    $localpart = CRM_Core_BAO_MailSettings::defaultLocalpart();
 +    $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
      $includeMessageId = CRM_Core_BAO_MailSettings::includeMessageId();
  
      if ($includeMessageId && (!array_key_exists('Message-ID', $headers))) {
        $headers['Message-ID'] = '<' . implode($config->verpSeparator,
 -        array(
 -          $localpart . $prefix,
 -          $job_id,
 -          $event_queue_id,
 -          $hash,
 -        )
 -      ) . "@{$emailDomain}>";
 +          array(
 +            $localpart . $prefix,
 +            $job_id,
 +            $event_queue_id,
 +            $hash,
 +          )
 +        ) . "@{$emailDomain}>";
      }
    }
  
    /**
 -   * static wrapper for getting verp and urls
 +   * Static wrapper for getting verp and urls.
     *
 -   * @param int $job_id ID of the Job associated with this message
 -   * @param int $event_queue_id ID of the EventQueue
 -   * @param string $hash Hash of the EventQueue
 -   * @param string $email Destination address
 +   * @param int $job_id
 +   *   ID of the Job associated with this message.
 +   * @param int $event_queue_id
 +   *   ID of the EventQueue.
 +   * @param string $hash
 +   *   Hash of the EventQueue.
 +   * @param string $email
 +   *   Destination address.
     *
 -   * @return array (reference) array    array ref that hold array refs to the verp info and urls
 +   * @return array
 +   *   (reference) array    array ref that hold array refs to the verp info and urls
     */
 -  static function getVerpAndUrls($job_id, $event_queue_id, $hash, $email) {
 +  public static function getVerpAndUrls($job_id, $event_queue_id, $hash, $email) {
      // create a skeleton object and set its properties that are required by getVerpAndUrlsAndHeaders()
 -    $config         = CRM_Core_Config::singleton();
 -    $bao            = new CRM_Mailing_BAO_Mailing();
 -    $bao->_domain   = CRM_Core_BAO_Domain::getDomain();
 +    $config = CRM_Core_Config::singleton();
 +    $bao = new CRM_Mailing_BAO_Mailing();
 +    $bao->_domain = CRM_Core_BAO_Domain::getDomain();
      $bao->from_name = $bao->from_email = $bao->subject = '';
  
      // use $bao's instance method to get verp and urls
    }
  
    /**
 -   * get verp, urls and headers
 +   * Get verp, urls and headers
     *
 -   * @param int $job_id ID of the Job associated with this message
 -   * @param int $event_queue_id ID of the EventQueue
 -   * @param string $hash Hash of the EventQueue
 -   * @param string $email Destination address
 +   * @param int $job_id
 +   *   ID of the Job associated with this message.
 +   * @param int $event_queue_id
 +   *   ID of the EventQueue.
 +   * @param string $hash
 +   *   Hash of the EventQueue.
 +   * @param string $email
 +   *   Destination address.
     *
     * @param bool $isForward
     *
 -   * @return array (reference) array    array ref that hold array refs to the verp info, urls, and headers@access private
 +   * @return array
 +   *   array ref that hold array refs to the verp info, urls, and headers
     */
    private function getVerpAndUrlsAndHeaders($job_id, $event_queue_id, $hash, $email, $isForward = FALSE) {
      $config = CRM_Core_Config::singleton();
  
      foreach ($verpTokens as $key => $value) {
        $verp[$key] = implode($config->verpSeparator,
 -        array(
 -          $localpart . $value,
 -          $job_id,
 -          $event_queue_id,
 -          $hash,
 -        )
 -      ) . "@$emailDomain";
 +          array(
 +            $localpart . $value,
 +            $job_id,
 +            $event_queue_id,
 +            $hash,
 +          )
 +        ) . "@$emailDomain";
      }
  
      //handle should override VERP address.
    }
  
    /**
 -   * Compose a message
 -   *
 -   * @param int $job_id ID of the Job associated with this message
 -   * @param int $event_queue_id ID of the EventQueue
 -   * @param string $hash Hash of the EventQueue
 -   * @param string $contactId ID of the Contact
 -   * @param string $email Destination address
 -   * @param string $recipient To: of the recipient
 -   * @param boolean $test Is this mailing a test?
 +   * Compose a message.
 +   *
 +   * @param int $job_id
 +   *   ID of the Job associated with this message.
 +   * @param int $event_queue_id
 +   *   ID of the EventQueue.
 +   * @param string $hash
 +   *   Hash of the EventQueue.
 +   * @param string $contactId
 +   *   ID of the Contact.
 +   * @param string $email
 +   *   Destination address.
 +   * @param string $recipient
 +   *   To: of the recipient.
 +   * @param bool $test
 +   *   Is this mailing a test?.
     * @param $contactDetails
     * @param $attachments
 -   * @param boolean $isForward Is this mailing compose for forward?
 -   * @param string $fromEmail email address of who is forwardinf it.
 +   * @param bool $isForward
 +   *   Is this mailing compose for forward?.
 +   * @param string $fromEmail
 +   *   Email address of who is forwardinf it.
     *
     * @param null $replyToEmail
     *
     * @return Mail_mime               The mail object
 -   * @access public
     */
 -  public function &compose($job_id, $event_queue_id, $hash, $contactId,
 +  public function &compose(
 +    $job_id, $event_queue_id, $hash, $contactId,
      $email, &$recipient, $test,
      $contactDetails, &$attachments, $isForward = FALSE,
      $fromEmail = NULL, $replyToEmail = NULL
  
        if (!$contact || is_a($contact, 'CRM_Core_Error')) {
          CRM_Core_Error::debug_log_message(ts('CiviMail will not send email to a non-existent contact: %1',
 -            array(1 => $contactId)
 -          ));
 +          array(1 => $contactId)
 +        ));
          // setting this because function is called by reference
          //@todo test not calling function by reference
          $res = NULL;
      $pEmails = array();
  
      foreach ($pTemplates as $type => $pTemplate) {
 -      $html           = ($type == 'html') ? TRUE : FALSE;
 +      $html = ($type == 'html') ? TRUE : FALSE;
        $pEmails[$type] = array();
 -      $pEmail         = &$pEmails[$type];
 -      $template       = &$pTemplates[$type]['template'];
 -      $tokens         = &$pTemplates[$type]['tokens'];
 -      $idx            = 0;
 +      $pEmail = &$pEmails[$type];
 +      $template = &$pTemplates[$type]['template'];
 +      $tokens = &$pTemplates[$type]['tokens'];
 +      $idx = 0;
        if (!empty($tokens)) {
          foreach ($tokens as $idx => $token) {
            $token_data = $this->getTokenData($token, $html, $contact, $verp, $urls, $event_queue_id);
      if ($text && ($test || $contact['preferred_mail_format'] == 'Text' ||
          $contact['preferred_mail_format'] == 'Both' ||
          ($contact['preferred_mail_format'] == 'HTML' && !array_key_exists('html', $pEmails))
 -      )) {
 -      $textBody = join('', $text);
 +      )
 +    ) {
 +      $textBody = implode('', $text);
        if ($useSmarty) {
          $textBody = $smarty->fetch("string:$textBody");
        }
  
      if ($html && ($test || ($contact['preferred_mail_format'] == 'HTML' ||
            $contact['preferred_mail_format'] == 'Both'
 -        ))) {
 -      $htmlBody = join('', $html);
 +        ))
 +    ) {
 +      $htmlBody = implode('', $html);
        if ($useSmarty) {
          $htmlBody = $smarty->fetch("string:$htmlBody");
        }
        // CRM-9833
        // something went wrong, lets log it and return null (by reference)
        CRM_Core_Error::debug_log_message(ts('CiviMail will not send an empty mail body, Skipping: %1',
 -          array(1 => $email)
 -        ));
 +        array(1 => $email)
 +      ));
        $res = NULL;
        return $res;
      }
  
      $mailingSubject = CRM_Utils_Array::value('subject', $pEmails);
      if (is_array($mailingSubject)) {
 -      $mailingSubject = join('', $mailingSubject);
 +      $mailingSubject = implode('', $mailingSubject);
      }
      $mailParams['Subject'] = $mailingSubject;
  
      );
      $mailParams['toEmail'] = $email;
  
+     // Add job ID to mailParams for external email delivery service to utilise
+     $mailParams['job_id'] = $job_id;
      CRM_Utils_Hook::alterMailParams($mailParams, 'civimail');
  
      // CRM-10699 support custom email headers
      foreach ($mailParams as $paramKey => $paramValue) {
        //exclude values not intended for the header
        if (!in_array($paramKey, array(
 -        'text', 'html', 'attachments', 'toName', 'toEmail'))) {
 +        'text',
 +        'html',
 +        'attachments',
 +        'toName',
 +        'toEmail',
 +      ))
 +      ) {
          $headers[$paramKey] = $paramValue;
        }
      }
     *
     * get mailing object and replaces subscribeInvite,
     * domain and mailing tokens
 -   *
     */
    public static function tokenReplace(&$mailing) {
      $domain = CRM_Core_BAO_Domain::getDomain();
     *
     *  getTokenData receives a token from an email
     *  and returns the appropriate data for the token
 -   *
     */
    private function getTokenData(&$token_a, $html = FALSE, &$contact, &$verp, &$urls, $event_queue_id) {
 -    $type  = $token_a['type'];
 +    $type = $token_a['type'];
      $token = $token_a['token'];
 -    $data  = $token;
 +    $data = $token;
  
      $useSmarty = defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY ? TRUE : FALSE;
  
      elseif ($type == 'url') {
        if ($this->url_tracking) {
          $data = CRM_Mailing_BAO_TrackableURL::getTrackerURL($token, $this->id, $event_queue_id);
 +        if (!empty($html)) {
 +          $data = htmlentities($data);
 +        }
        }
        else {
          $data = $token;
     * Return a list of group names for this mailing.  Does not work with
     * prior-mailing targets.
     *
 -   * @return array        Names of groups receiving this mailing
 -   * @access public
 +   * @return array
 +   *   Names of groups receiving this mailing
     */
    public function &getGroupNames() {
      if (!isset($this->id)) {
        return array();
      }
 -    $mg      = new CRM_Mailing_DAO_MailingGroup();
 +    $mg = new CRM_Mailing_DAO_MailingGroup();
      $mgtable = CRM_Mailing_DAO_MailingGroup::getTableName();
 -    $group   = CRM_Contact_BAO_Group::getTableName();
 +    $group = CRM_Contact_BAO_Group::getTableName();
  
      $mg->query("SELECT      $group.title as name FROM $mgtable
                      INNER JOIN  $group ON $mgtable.entity_id = $group.id
    }
  
    /**
 -   * function to add the mailings
 +   * Add the mailings.
     *
 -   * @param array $params reference array contains the values submitted by the form
 -   * @param array $ids    reference array contains the id
 +   * @param array $params
 +   *   Reference array contains the values submitted by the form.
 +   * @param array $ids
 +   *   Reference array contains the id.
     *
 -   * @access public
 -   * @static
     *
 -   * @return object
 +   * @return CRM_Mailing_DAO_Mailing
     */
 -  static function add(&$params, $ids = array()) {
 +  public static function add(&$params, $ids = array()) {
      $id = CRM_Utils_Array::value('mailing_id', $ids, CRM_Utils_Array::value('id', $params));
  
      if ($id) {
        CRM_Utils_Hook::pre('create', 'Mailing', NULL, $params);
      }
  
 -    $mailing            = new CRM_Mailing_DAO_Mailing();
 -    $mailing->id        = $id;
 +    $mailing = new static();
 +    if ($id) {
 +      $mailing->id = $id;
 +      $mailing->find(TRUE);
 +    }
      $mailing->domain_id = CRM_Utils_Array::value('domain_id', $params, CRM_Core_Config::domainID());
  
      if (!isset($params['replyto_email']) &&
     * Construct a new mailing object, along with job and mailing_group
     * objects, from the form values of the create mailing wizard.
     *
 -   * @params array $params        Form values
 +   * This function is a bit evil. It not only merges $params and saves
 +   * the mailing -- it also schedules the mailing and chooses the recipients.
 +   * Since it merges $params, it's also the only place to correctly trigger
 +   * multi-field validation. It should be broken up.
 +   *
 +   * In the mean time, use-cases which break under the weight of this
 +   * evil may find reprieve in these extra evil params:
 +   *
 +   *  - _skip_evil_bao_auto_recipients_: bool
 +   *  - _skip_evil_bao_auto_schedule_: bool
 +   *  - _evil_bao_validator_: string|callable
 +   *
 +   * </twowrongsmakesaright>
 +   *
 +   * @params array $params
 +   *   Form values.
     *
 -   * @param $params
 +   * @param array $params
     * @param array $ids
     *
 -   * @return object $mailing      The new mailing object
 -   * @access public
 -   * @static
 +   * @return object
 +   *   $mailing      The new mailing object
 +   * @throws \Exception
     */
    public static function create(&$params, $ids = array()) {
 +    // WTH $ids
 +    if (empty($ids) && isset($params['id'])) {
 +      $ids['mailing_id'] = $ids['id'] = $params['id'];
 +    }
  
      // CRM-12430
      // Do the below only for an insert
        );
        if (isset($domain['from_email'])) {
          $domain_email = $domain['from_email'];
 -        $domain_name  = $domain['from_name'];
 +        $domain_name = $domain['from_name'];
        }
        else {
          $domain_email = 'info@EXAMPLE.ORG';
 -        $domain_name  = 'EXAMPLE.ORG';
 +        $domain_name = 'EXAMPLE.ORG';
        }
        if (!isset($params['created_id'])) {
          $session =& CRM_Core_Session::singleton();
          // load the default config settings for each
          // eg reply_id, unsubscribe_id need to use
          // correct template IDs here
 -        'override_verp'   => TRUE,
 +        'override_verp' => TRUE,
          'forward_replies' => FALSE,
 -        'open_tracking'   => TRUE,
 -        'url_tracking'    => TRUE,
 -        'visibility'      => 'Public Pages',
 -        'replyto_email'   => $domain_email,
 -        'header_id'       => CRM_Mailing_PseudoConstant::defaultComponent('header_id', ''),
 -        'footer_id'       => CRM_Mailing_PseudoConstant::defaultComponent('footer_id', ''),
 -        'from_email'      => $domain_email,
 -        'from_name'       => $domain_name,
 +        'open_tracking' => TRUE,
 +        'url_tracking' => TRUE,
 +        'visibility' => 'Public Pages',
 +        'replyto_email' => $domain_email,
 +        'header_id' => CRM_Mailing_PseudoConstant::defaultComponent('header_id', ''),
 +        'footer_id' => CRM_Mailing_PseudoConstant::defaultComponent('footer_id', ''),
 +        'from_email' => $domain_email,
 +        'from_name' => $domain_name,
          'msg_template_id' => NULL,
 -        'created_id'      => $params['created_id'],
 -        'approver_id'     => NULL,
 -        'auto_responder'  => 0,
 -        'created_date'    => date('YmdHis'),
 -        'scheduled_date'  => NULL,
 -        'approval_date'   => NULL,
 +        'created_id' => $params['created_id'],
 +        'approver_id' => NULL,
 +        'auto_responder' => 0,
 +        'created_date' => date('YmdHis'),
 +        'scheduled_date' => NULL,
 +        'approval_date' => NULL,
        );
  
        // Get the default from email address, if not provided.
      $groupTypes = array('include' => 'Include', 'exclude' => 'Exclude', 'base' => 'Base');
      foreach (array('groups', 'mailings') as $entity) {
        foreach (array('include', 'exclude', 'base') as $type) {
 -        if (isset($params[$entity]) && !empty($params[$entity][$type]) &&
 -          is_array($params[$entity][$type])) {
 -          foreach ($params[$entity][$type] as $entityId) {
 -            $mg->reset();
 -            $mg->mailing_id   = $mailing->id;
 -            $mg->entity_table = ($entity == 'groups') ? $groupTableName : $mailingTableName;
 -            $mg->entity_id    = $entityId;
 -            $mg->group_type   = $groupTypes[$type];
 -            $mg->save();
 -          }
 +        if (isset($params[$entity][$type])) {
 +          self::replaceGroups($mailing->id, $groupTypes[$type], $entity, $params[$entity][$type]);
          }
        }
      }
  
      if (!empty($params['search_id']) && !empty($params['group_id'])) {
        $mg->reset();
 -      $mg->mailing_id   = $mailing->id;
 +      $mg->mailing_id = $mailing->id;
        $mg->entity_table = $groupTableName;
 -      $mg->entity_id    = $params['group_id'];
 -      $mg->search_id    = $params['search_id'];
 -      $mg->search_args  = $params['search_args'];
 -      $mg->group_type   = 'Include';
 +      $mg->entity_id = $params['group_id'];
 +      $mg->search_id = $params['search_id'];
 +      $mg->search_args = $params['search_args'];
 +      $mg->group_type = 'Include';
        $mg->save();
      }
  
      // check and attach and files as needed
      CRM_Core_BAO_File::processAttachment($params, 'civicrm_mailing', $mailing->id);
  
 +    // If we're going to autosend, then check validity before saving.
 +    if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null' && !empty($params['_evil_bao_validator_'])) {
 +      $cb = Civi\Core\Resolver::singleton()->get($params['_evil_bao_validator_']);
 +      $errors = call_user_func($cb, $mailing);
 +      if (!empty($errors)) {
 +        $fields = implode(',', array_keys($errors));
 +        throw new CRM_Core_Exception("Mailing cannot be sent. There are missing or invalid fields ($fields).", 'cannot-send', $errors);
 +      }
 +    }
 +
      $transaction->commit();
  
 -    /**
 -     * create parent job if not yet created
 -     * condition on the existence of a scheduled date
 -     */
 -    if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null') {
 +    // Create parent job if not yet created.
 +    // Condition on the existence of a scheduled date.
 +    if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null' && empty($params['_skip_evil_bao_auto_schedule_'])) {
        $job = new CRM_Mailing_BAO_MailingJob();
        $job->mailing_id = $mailing->id;
        $job->status = 'Scheduled';
        $job->is_test = 0;
  
 -      if ( !$job->find(TRUE) ) {
 +      if (!$job->find(TRUE)) {
          $job->scheduled_date = $params['scheduled_date'];
          $job->save();
        }
  
        // Populate the recipients.
 -      $mailing->getRecipients($job->id, $mailing->id, NULL, NULL, TRUE, FALSE);
 +      if (empty($params['_skip_evil_bao_auto_recipients_'])) {
 +        self::getRecipients($job->id, $mailing->id, NULL, NULL, TRUE, FALSE);
 +      }
      }
  
      return $mailing;
    }
  
    /**
 -   * get hash value of the mailing
 +   * @param CRM_Mailing_DAO_Mailing $mailing
 +   *   The mailing which may or may not be sendable.
 +   * @return array
 +   *   List of error messages.
 +   */
 +  public static function checkSendable($mailing) {
 +    $errors = array();
 +    foreach (array('subject', 'name', 'from_name', 'from_email') as $field) {
 +      if (empty($mailing->{$field})) {
 +        $errors[$field] = ts('Field "%1" is required.', array(
 +          1 => $field,
 +        ));
 +      }
 +    }
 +    if (empty($mailing->body_html) && empty($mailing->body_text)) {
 +      $errors['body'] = ts('Field "body_html" or "body_text" is required.');
 +    }
 +
 +    if (!CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'disable_mandatory_tokens_check')) {
 +      $header = $mailing->header_id && $mailing->header_id != 'null' ? CRM_Mailing_BAO_Component::findById($mailing->header_id) : NULL;
 +      $footer = $mailing->footer_id && $mailing->footer_id != 'null' ? CRM_Mailing_BAO_Component::findById($mailing->footer_id) : NULL;
 +      foreach (array('body_html', 'body_text') as $field) {
 +        if (empty($mailing->{$field})) {
 +          continue;
 +        }
 +        $str = ($header ? $header->{$field} : '') . $mailing->{$field} . ($footer ? $footer->{$field} : '');
 +        $err = CRM_Utils_Token::requiredTokens($str);
 +        if ($err !== TRUE) {
 +          foreach ($err as $token => $desc) {
 +            $errors["{$field}:{$token}"] = ts('This message is missing a required token - {%1}: %2',
 +              array(1 => $token, 2 => $desc)
 +            );
 +          }
 +        }
 +      }
 +    }
 +
 +    return $errors;
 +  }
 +
 +  /**
 +   * Replace the list of recipients on a given mailing.
 +   *
 +   * @param int $mailingId
 +   * @param string $type
 +   *   'include' or 'exclude'.
 +   * @param string $entity
 +   *   'groups' or 'mailings'.
 +   * @param array <int> $entityIds
 +   * @throws CiviCRM_API3_Exception
 +   */
 +  public static function replaceGroups($mailingId, $type, $entity, $entityIds) {
 +    $values = array();
 +    foreach ($entityIds as $entityId) {
 +      $values[] = array('entity_id' => $entityId);
 +    }
 +    civicrm_api3('mailing_group', 'replace', array(
 +      'mailing_id' => $mailingId,
 +      'group_type' => $type,
 +      'entity_table' => ($entity == 'groups') ? CRM_Contact_BAO_Group::getTableName() : CRM_Mailing_BAO_Mailing::getTableName(),
 +      'values' => $values,
 +    ));
 +  }
 +
 +  /**
 +   * Get hash value of the mailing.
 +   *
 +   * @param $id
     *
 +   * @return null|string
     */
    public static function getMailingHash($id) {
      $hash = NULL;
     * Generate a report.  Fetch event count information, mailing data, and job
     * status.
     *
 -   * @param int $id The mailing id to report
 -   * @param boolean $skipDetails whether return all detailed report
 +   * @param int $id
 +   *   The mailing id to report.
 +   * @param bool $skipDetails
 +   *   Whether return all detailed report.
     *
     * @param bool $isSMS
     *
 -   * @return array        Associative array of reporting data
 -   * @access public
 -   * @static
 +   * @return array
 +   *   Associative array of reporting data
     */
    public static function &report($id, $skipDetails = FALSE, $isSMS = FALSE) {
      $mailing_id = CRM_Utils_Type::escape($id, 'Integer');
        'delivered' => CRM_Mailing_Event_BAO_Delivered::getTableName(),
        'opened' => CRM_Mailing_Event_BAO_Opened::getTableName(),
        'reply' => CRM_Mailing_Event_BAO_Reply::getTableName(),
 -      'unsubscribe' =>
 -      CRM_Mailing_Event_BAO_Unsubscribe::getTableName(),
 +      'unsubscribe' => CRM_Mailing_Event_BAO_Unsubscribe::getTableName(),
        'bounce' => CRM_Mailing_Event_BAO_Bounce::getTableName(),
        'forward' => CRM_Mailing_Event_BAO_Forward::getTableName(),
        'url' => CRM_Mailing_BAO_TrackableURL::getTableName(),
 -      'urlopen' =>
 -      CRM_Mailing_Event_BAO_TrackableURLOpen::getTableName(),
 +      'urlopen' => CRM_Mailing_Event_BAO_TrackableURLOpen::getTableName(),
        'component' => CRM_Mailing_BAO_Component::getTableName(),
        'spool' => CRM_Mailing_BAO_Spool::getTableName(),
      );
  
 -
      $report = array();
      $additionalWhereClause = " AND ";
      if (!$isSMS) {
        $report['component'][] = array(
          'type' => $components[$mailing->type],
          'name' => $mailing->name,
 -        'link' =>
 -        CRM_Utils_System::url('civicrm/mailing/component',
 +        'link' => CRM_Utils_System::url('civicrm/mailing/component',
            "reset=1&action=update&id={$mailing->id}"
          ),
        );
      while ($mailing->fetch()) {
        $row = array();
        if (isset($mailing->group_id)) {
 -        $row['id']   = $mailing->group_id;
 +        $row['id'] = $mailing->group_id;
          $row['name'] = $mailing->group_title;
          $row['link'] = CRM_Utils_System::url('civicrm/group/search',
 -                       "reset=1&force=1&context=smog&gid={$row['id']}"
 +          "reset=1&force=1&context=smog&gid={$row['id']}"
          );
        }
        else {
 -        $row['id']      = $mailing->mailing_id;
 -        $row['name']    = $mailing->mailing_name;
 +        $row['id'] = $mailing->mailing_id;
 +        $row['name'] = $mailing->mailing_name;
          $row['mailing'] = TRUE;
 -        $row['link']    = CRM_Utils_System::url('civicrm/mailing/report',
 -                          "mid={$row['id']}"
 +        $row['link'] = CRM_Utils_System::url('civicrm/mailing/report',
 +          "mid={$row['id']}"
          );
        }
  
      $report['jobs'] = array();
      $report['event_totals'] = array();
      $elements = array(
 -      'queue', 'delivered', 'url', 'forward',
 -      'reply', 'unsubscribe', 'optout', 'opened', 'bounce', 'spool',
 +      'queue',
 +      'delivered',
 +      'url',
 +      'forward',
 +      'reply',
 +      'unsubscribe',
 +      'optout',
 +      'opened',
 +      'bounce',
 +      'spool',
      );
  
      // initialize various counters
        );
  
        foreach (array(
 -          'scheduled_date', 'start_date', 'end_date') as $key) {
 +                 'scheduled_date',
 +                 'start_date',
 +                 'end_date',
 +               ) as $key) {
          $row[$key] = CRM_Utils_Date::customFormat($row[$key]);
        }
        $report['jobs'][] = $row;
      while ($mailing->fetch()) {
        $report['click_through'][] = array(
          'url' => $mailing->url,
 -        'link' =>
 -        CRM_Utils_System::url(
 +        'link' => CRM_Utils_System::url(
            'civicrm/mailing/report/event',
            "reset=1&event=click&mid=$mailing_id&uid={$mailing->id}"
          ),
 -        'link_unique' =>
 -        CRM_Utils_System::url(
 +        'link_unique' => CRM_Utils_System::url(
            'civicrm/mailing/report/event',
            "reset=1&event=click&mid=$mailing_id&uid={$mailing->id}&distinct=1"
          ),
        ),
      );
  
 -
      $actionLinks = array(CRM_Core_Action::VIEW => array('name' => ts('Report')));
      if (CRM_Core_Permission::check('view all contacts')) {
 -      $actionLinks[CRM_Core_Action::ADVANCED] =
 -        array(
 -          'name' => ts('Advanced Search'),
 -          'url' => 'civicrm/contact/search/advanced',
 -        );
 +      $actionLinks[CRM_Core_Action::ADVANCED] = array(
 +        'name' => ts('Advanced Search'),
 +        'url' => 'civicrm/contact/search/advanced',
 +      );
      }
      $action = array_sum(array_keys($actionLinks));
  
      $report['event_totals']['actionlinks'] = array();
      foreach (array(
 -        'clicks', 'clicks_unique', 'queue', 'delivered', 'bounce', 'unsubscribe',
 -        'forward', 'reply', 'opened', 'optout',
 -      ) as $key) {
 -      $url          = 'mailing/detail';
 +               'clicks',
 +               'clicks_unique',
 +               'queue',
 +               'delivered',
 +               'bounce',
 +               'unsubscribe',
 +               'forward',
 +               'reply',
 +               'opened',
 +               'optout',
 +             ) as $key) {
 +      $url = 'mailing/detail';
        $reportFilter = "reset=1&mailing_id_value={$mailing_id}";
        $searchFilter = "force=1&mailing_id=%%mid%%";
        switch ($key) {
    }
  
    /**
 -   * Get the count of mailings
 +   * Get the count of mailings.
     *
     * @param
     *
 -   * @return int              Count
 -   * @access public
 +   * @return int
 +   *   Count
     */
    public function getCount() {
      $this->selectAdd();
    }
  
    /**
 -   * @param $id
 +   * @param int $id
     *
     * @throws Exception
     */
 -  static function checkPermission($id) {
 +  public static function checkPermission($id) {
      if (!$id) {
        return;
      }
      if (!in_array($id, $mailingIDs)) {
        CRM_Core_Error::fatal(ts('You do not have permission to access this mailing report'));
      }
 -    return;
    }
  
    /**
     *
     * @return string
     */
 -  static function mailingACL($alias = NULL) {
 +  public static function mailingACL($alias = NULL) {
      $mailingACL = " ( 0 ) ";
  
      $mailingIDs = self::mailingACLIDs();
  
      if (!empty($mailingIDs)) {
        $mailingIDs = implode(',', $mailingIDs);
 -      $tableName  = !$alias ? self::getTableName() : $alias;
 +      $tableName = !$alias ? self::getTableName() : $alias;
        $mailingACL = " $tableName.id IN ( $mailingIDs ) ";
      }
      return $mailingACL;
    }
  
    /**
 -   * returns all the mailings that this user can access. This is dependent on
 +   * Returns all the mailings that this user can access. This is dependent on
     * all the groups that the user has access to.
     * However since most civi installs dont use ACL's we special case the condition
     * where the user has access to ALL groups, and hence ALL mailings and return a
     * value of TRUE (to avoid the downstream where clause with a list of mailing list IDs
     *
 -   * @return boolean | array - TRUE if the user has access to all mailings, else array of mailing IDs (possibly empty)
 -   * @static
 +   * @return bool|array
 +   *   TRUE if the user has access to all mailings, else array of mailing IDs (possibly empty).
     */
 -  static function mailingACLIDs() {
 +  public static function mailingACLIDs() {
      // CRM-11633
      // optimize common case where admin has access
      // to all mailings
@@@ -2435,25 -2265,22 +2438,25 @@@ LEFT JOIN civicrm_mailing_group g ON g.
    }
  
    /**
 -   * Get the rows for a browse operation
 +   * Get the rows for a browse operation.
     *
 -   * @param int $offset The row number to start from
 -   * @param int $rowCount The nmber of rows to return
 -   * @param string $sort The sql string that describes the sort order
 +   * @param int $offset
 +   *   The row number to start from.
 +   * @param int $rowCount
 +   *   The nmber of rows to return.
 +   * @param string $sort
 +   *   The sql string that describes the sort order.
     *
     * @param null $additionalClause
 -   * @param null $additionalParams
 +   * @param array $additionalParams
     *
 -   * @return array            The rows
 -   * @access public
 +   * @return array
 +   *   The rows
     */
    public function &getRows($offset, $rowCount, $sort, $additionalClause = NULL, $additionalParams = NULL) {
      $mailing = self::getTableName();
 -    $job     = CRM_Mailing_BAO_MailingJob::getTableName();
 -    $group   = CRM_Mailing_DAO_MailingGroup::getTableName();
 +    $job = CRM_Mailing_BAO_MailingJob::getTableName();
 +    $group = CRM_Mailing_DAO_MailingGroup::getTableName();
      $session = CRM_Core_Session::singleton();
  
      $mailingACL = self::mailingACL();
    }
  
    /**
 -   * Function to show detail Mailing report
 +   * Show detail Mailing report.
     *
     * @param int $id
     *
     * @return string
 -   * @static
 -   * @access public
     */
 -  static function showEmailDetails($id) {
 +  public static function showEmailDetails($id) {
      return CRM_Utils_System::url('civicrm/mailing/report', "mid=$id");
    }
  
    /**
 -   * Delete Mails and all its associated records
 +   * Delete Mails and all its associated records.
     *
 -   * @param  int  $id id of the mail to delete
 +   * @param int $id
 +   *   Id of the mail to delete.
     *
     * @return void
 -   * @access public
 -   * @static
     */
    public static function del($id) {
      if (empty($id)) {
     * Delete Jobss and all its associated records
     * related to test Mailings
     *
 -   * @param  int  $id id of the Job to delete
 +   * @param int $id
 +   *   Id of the Job to delete.
     *
     * @return void
 -   * @access public
 -   * @static
     */
    public static function delJob($id) {
      if (empty($id)) {
    /**
     * @return array
     */
 -  function getReturnProperties() {
 +  public function getReturnProperties() {
      $tokens = &$this->getTokens();
  
      $properties = array();
    }
  
    /**
 -   * Function to build the  compose mail form
 +   * Build the  compose mail form.
     *
 -   * @param   $form
 +   * @param CRM_Core_Form $form
     *
     * @return void
 -   * @access public
     */
    public static function commonCompose(&$form) {
      //get the tokens.
  
      $templates = array();
  
 -    $textFields = array('text_message' => ts('HTML format'), 'sms_text_message' => ts('SMS Message'));
 +    $textFields = array('text_message' => ts('HTML Format'), 'sms_text_message' => ts('SMS Message'));
      $modePrefixes = array('Mail' => NULL, 'SMS' => 'SMS');
  
      if ($className != 'CRM_SMS_Form_Upload' && $className != 'CRM_Contact_Form_Task_SMS' &&
        $className != 'CRM_Contact_Form_Task_SMS'
      ) {
        $form->addWysiwyg('html_message',
 -        ts('HTML format'),
 +        ts('HTML Format'),
          array(
 -          'cols' => '80', 'rows' => '8',
 +          'cols' => '80',
 +          'rows' => '8',
            'onkeyup' => "return verify(this)",
          )
        );
        }
        $form->add('textarea', $id, $label,
          array(
 -          'cols' => '80', 'rows' => '8',
 +          'cols' => '80',
 +          'rows' => '8',
            'onkeyup' => "return verify(this, '{$prefix}')",
          )
        );
    }
  
    /**
 -   * Function to build the  compose PDF letter form
 +   * Build the  compose PDF letter form.
     *
 -   * @param   $form
 +   * @param CRM_Core_Form $form
     *
     * @return void
 -   * @access public
     */
    public static function commonLetterCompose(&$form) {
      //get the tokens.
        $tokens = array_merge(CRM_Core_SelectValues::contributionTokens(), $tokens);
      }
  
 -    if(method_exists($form, 'listTokens')) {
 +    if (method_exists($form, 'listTokens')) {
        $tokens = array_merge($form->listTokens(), $tokens);
      }
  
        $form->assign('templates', TRUE);
        $form->add('select', 'template', ts('Select Template'),
          array(
 -          '' => ts('- select -')) + $form->_templates, FALSE,
 +          '' => ts('- select -'),
 +        ) + $form->_templates, FALSE,
          array('onChange' => "selectValue( this.value,'' );")
        );
        $form->add('checkbox', 'updateTemplate', ts('Update Template'), NULL);
      );
      $form->add('text', 'saveTemplateName', ts('Template Title'));
  
 -
      $form->addWysiwyg('html_message',
        ts('Your Letter'),
        array(
 -        'cols' => '80', 'rows' => '8',
 +        'cols' => '80',
 +        'rows' => '8',
          'onkeyup' => "return verify(this)",
        )
      );
    }
  
    /**
 -   * Get the search based mailing Ids
 +   * Get the search based mailing Ids.
     *
 -   * @return array $mailingIDs, searched base mailing ids.
 -   * @access public
 +   * @return array
 +   *   , searched base mailing ids.
     */
    public function searchMailingIDs() {
      $group = CRM_Mailing_DAO_MailingGroup::getTableName();
@@@ -2804,18 -2634,15 +2807,18 @@@ SELECT  $mailing.id as mailing_i
    /**
     * Get the content/components of mailing based on mailing Id
     *
 -   * @param $report array of mailing report
 +   * @param array $report
 +   *   of mailing report.
     *
 -   * @param $form reference of this
 +   * @param $form
 +   *   Reference of this.
     *
     * @param bool $isSMS
     *
 -   * @return array $report array content/component.@access public
 +   * @return array
 +   *   array content/component.
     */
 -  static function getMailingContent(&$report, &$form, $isSMS = FALSE) {
 +  public static function getMailingContent(&$report, &$form, $isSMS = FALSE) {
      $htmlHeader = $textHeader = NULL;
      $htmlFooter = $textFooter = NULL;
  
    }
  
    /**
 -   * @param $jobID
 +   * @param int $jobID
     *
     * @return mixed
     */
 -  static function overrideVerp($jobID) {
 +  public static function overrideVerp($jobID) {
      static $_cache = array();
  
      if (!isset($_cache[$jobID])) {
@@@ -2889,14 -2716,12 +2892,14 @@@ WHERE  civicrm_mailing_job.id = %
     * @return bool
     * @throws Exception
     */
 -  static function processQueue($mode = NULL) {
 +  public static function processQueue($mode = NULL) {
      $config = &CRM_Core_Config::singleton();
 -    //   CRM_Core_Error::debug_log_message("Beginning processQueue run: {$config->mailerJobsMax}, {$config->mailerJobSize}");
  
      if ($mode == NULL && CRM_Core_BAO_MailSettings::defaultDomain() == "EXAMPLE.ORG") {
 -      throw new CRM_Core_Exception(ts('The <a href="%1">default mailbox</a> has not been configured. You will find <a href="%2">more info in the online user and administrator guide</a>', array(1 => CRM_Utils_System::url('civicrm/admin/mailSettings', 'reset=1'), 2 => "http://book.civicrm.org/user/advanced-configuration/email-system-configuration/")));
 +      throw new CRM_Core_Exception(ts('The <a href="%1">default mailbox</a> has not been configured. You will find <a href="%2">more info in the online user and administrator guide</a>', array(
 +            1 => CRM_Utils_System::url('civicrm/admin/mailSettings', 'reset=1'),
 +            2 => "http://book.civicrm.org/user/advanced-configuration/email-system-configuration/",
 +          )));
      }
  
      // check if we are enforcing number of parallel cron jobs
        $cronLock->release();
      }
  
 - //   CRM_Core_Error::debug_log_message('Ending processQueue run');
      return TRUE;
    }
  
    /**
 -   * @param $mailingID
 +   * @param int $mailingID
     */
    private static function addMultipleEmails($mailingID) {
      $sql = "
@@@ -2967,7 -2793,7 +2970,7 @@@ AND    e.id NOT IN ( SELECT email_id FR
     *
     * @return mixed
     */
 -  static function getMailingsList($isSMS = FALSE) {
 +  public static function getMailingsList($isSMS = FALSE) {
      static $list = array();
      $where = " WHERE ";
      if (!$isSMS) {
@@@ -2994,11 -2820,11 +2997,11 @@@ ORDER BY civicrm_mailing.name"
    }
  
    /**
 -   * @param $mid
 +   * @param int $mid
     *
     * @return null|string
     */
 -  static function hiddenMailingGroup($mid) {
 +  public static function hiddenMailingGroup($mid) {
      $sql = "
  SELECT     g.id
  FROM       civicrm_mailing m
@@@ -3008,25 -2834,24 +3011,25 @@@ WHERE      g.is_hidden = 
  AND        mg.group_type = 'Include'
  AND        m.id = %1
  ";
 -    $params = array( 1 => array( $mid, 'Integer' ) );
 +    $params = array(1 => array($mid, 'Integer'));
      return CRM_Core_DAO::singleValueQuery($sql, $params);
    }
  
    /**
 -   * This function is a wrapper for ajax activity selector
 +   * wrapper for ajax activity selector.
     *
 -   * @param  array   $params associated array for params record id.
 +   * @param array $params
 +   *   Associated array for params record id.
     *
 -   * @return array   $contactActivities associated array of contact activities
 -   * @access public
 +   * @return array
 +   *   associated array of contact activities
     */
    public static function getContactMailingSelector(&$params) {
      // format the params
 -    $params['offset']   = ($params['page'] - 1) * $params['rp'];
 +    $params['offset'] = ($params['page'] - 1) * $params['rp'];
      $params['rowCount'] = $params['rp'];
 -    $params['sort']     = CRM_Utils_Array::value('sortBy', $params);
 -    $params['caseId']   = NULL;
 +    $params['sort'] = CRM_Utils_Array::value('sortBy', $params);
 +    $params['caseId'] = NULL;
  
      // get contact mailings
      $mailings = CRM_Mailing_BAO_Mailing::getContactMailings($params);
          "reset=1&cid={$values['creator_id']}");
  
        //CRM-12814
 -      $contactMailings[$mailingId]['openstats'] = "Opens: ".
 -        CRM_Utils_Array::value($values['mailing_id'], $openCounts, 0).
 -        "<br />Clicks: ".
 +      $contactMailings[$mailingId]['openstats'] = "Opens: " .
 +        CRM_Utils_Array::value($values['mailing_id'], $openCounts, 0) .
 +        "<br />Clicks: " .
          CRM_Utils_Array::value($values['mailing_id'], $clickCounts, 0);
  
        $actionLinks = array(
            'url' => 'civicrm/mailing/report',
            'qs' => "mid=%%mid%%&reset=1&cid=%%cid%%&context=mailing",
            'title' => ts('View Mailing Report'),
 -        )
 +        ),
        );
  
        $mailingKey = $values['mailing_id'];
  
        $contactMailings[$mailingId]['links'] = CRM_Core_Action::formLink(
          $actionLinks,
 -        null,
 +        NULL,
          array(
            'mid' => $values['mailing_id'],
            'cid' => $params['contact_id'],
    }
  
    /**
 -   * Function to retrieve contact mailing
 +   * Retrieve contact mailing.
     *
 -   * @param array $params associated array
 +   * @param array $params
     *
 -   * @return array of mailings for a contact
 +   * @return array
 +   *   Array of mailings for a contact
     *
 -   * @static
 -   * @access public
     */
    static public function getContactMailings(&$params) {
      $params['version'] = 3;
 -    $params['offset']  = ($params['page'] - 1) * $params['rp'];
 -    $params['limit']   = $params['rp'];
 -    $params['sort']    = CRM_Utils_Array::value('sortBy', $params);
 +    $params['offset'] = ($params['page'] - 1) * $params['rp'];
 +    $params['limit'] = $params['rp'];
 +    $params['sort'] = CRM_Utils_Array::value('sortBy', $params);
  
      $result = civicrm_api('MailingContact', 'get', $params);
      return $result['values'];
    }
  
    /**
 -   * Function to retrieve contact mailing count
 +   * Retrieve contact mailing count.
     *
 -   * @param array $params associated array
 +   * @param array $params
     *
 -   * @return int count of mailings for a contact
 +   * @return int
 +   *   count of mailings for a contact
     *
 -   * @static
 -   * @access public
     */
    static public function getContactMailingsCount(&$params) {
      $params['version'] = 3;
      return civicrm_api('MailingContact', 'getcount', $params);
    }
 +
 +  /**
 +   * Get a list of permissions required for CRUD'ing each field
 +   * (when workflow is enabled).
 +   *
 +   * @return array
 +   *   Array (string $fieldName => string $permName)
 +   */
 +  public static function getWorkflowFieldPerms() {
 +    $fieldNames = array_keys(CRM_Mailing_DAO_Mailing::fields());
 +    $fieldPerms = array();
 +    foreach ($fieldNames as $fieldName) {
 +      if ($fieldName == 'id') {
 +        $fieldPerms[$fieldName] = array(
 +          array('access CiviMail', 'schedule mailings', 'approve mailings', 'create mailings'), // OR
 +        );
 +      }
 +      elseif (in_array($fieldName, array('scheduled_date', 'scheduled_id'))) {
 +        $fieldPerms[$fieldName] = array(
 +          array('access CiviMail', 'schedule mailings'), // OR
 +        );
 +      }
 +      elseif (in_array($fieldName, array('approval_date', 'approver_id', 'approval_status_id', 'approval_note'))) {
 +        $fieldPerms[$fieldName] = array(
 +          array('access CiviMail', 'approve mailings'), // OR
 +        );
 +      }
 +      else {
 +        $fieldPerms[$fieldName] = array(
 +          array('access CiviMail', 'create mailings'), // OR
 +        );
 +      }
 +    }
 +    return $fieldPerms;
 +  }
 +
  }
index ae7596a96c49c1c514e88597f0d22ff9a7220f93,b1734586cffb7d47312bbe4c02b90a04c5515ff1..3963329d6d4f5d6fb1fb98c0b62ded0114c1ee91
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
@@@ -47,21 -47,22 +47,21 @@@ class CRM_Mailing_Form_Component extend
    protected $_id;
  
    /**
 -   * The name of the BAO object for this form
 +   * The name of the BAO object for this form.
     *
     * @var string
     */
    protected $_BAOName;
  
 -  function preProcess() {
 +  public function preProcess() {
      $this->_id = $this->get('id');
      $this->_BAOName = $this->get('BAOName');
    }
  
    /**
 -   * Function to build the form
 +   * Build the form object.
     *
     * @return void
 -   * @access public
     */
    public function buildQuickForm() {
      $this->applyFilter('__ALL__', 'trim');
      $this->add('text', 'name', ts('Name'),
        CRM_Core_DAO::getAttribute('CRM_Mailing_DAO_Component', 'name'), TRUE
      );
 -    $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array('CRM_Mailing_DAO_Component', $this->_id));
 +    $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', array(
 +        'CRM_Mailing_DAO_Component',
 +        $this->_id,
 +      ));
  
      $this->add('select', 'component_type', ts('Component Type'), CRM_Core_SelectValues::mailingComponents());
  
@@@ -88,8 -86,8 +88,8 @@@
        CRM_Core_DAO::getAttribute('CRM_Mailing_DAO_Component', 'body_html')
      );
  
-     $this->add('checkbox', 'is_default', ts('Default?'));
-     $this->add('checkbox', 'is_active', ts('Enabled?'));
+     $this->addYesNo('is_default', ts('Default?'));
+     $this->addYesNo('is_active', ts('Enabled?'));
  
      $this->addFormRule(array('CRM_Mailing_Form_Component', 'dataRule'));
  
    }
  
    /**
 -   * This function sets the default values for the form.
 +   * Set default values for the form.
     *
 -   * @access public
     *
     * @return void
     */
 -  function setDefaultValues() {
 +  public function setDefaultValues() {
      $defaults = array();
      $params = array();
  
        $baoName = $this->_BAOName;
        $baoName::retrieve($params, $defaults);
      }
-     $defaults['is_active'] = 1;
+     else {
+       $defaults['is_active'] = 1;
+     }
  
      return $defaults;
    }
  
    /**
 -   * Function to process the form
 +   * Process the form submission.
     *
 -   * @access public
     *
     * @return void
     */
  
      $component = CRM_Mailing_BAO_Component::add($params);
      CRM_Core_Session::setStatus(ts('The mailing component \'%1\' has been saved.', array(
 -        1 => $component->name
 +        1 => $component->name,
        )
      ), ts('Saved'), 'success');
  
    }
 -  //end of function
  
    /**
 -   * Function for validation
 +   * Validation.
     *
 -   * @param array $params (ref.) an assoc array of name/value pairs
 +   * @param array $params
 +   *   (ref.) an assoc array of name/value pairs.
     *
     * @param $files
     * @param $options
     *
 -   * @return mixed true or array of errors
 -   * @access public
 -   * @static
 +   * @return bool|array
 +   *   mixed true or array of errors
     */
 -  static function dataRule($params, $files, $options) {
 +  public static function dataRule($params, $files, $options) {
      if ($params['component_type'] == 'Header' || $params['component_type'] == 'Footer') {
        $InvalidTokens = array();
      }
      }
      $errors = array();
      foreach (array(
 -      'text', 'html') as $type) {
 +               'text',
 +               'html',
 +             ) as $type) {
        $dataErrors = array();
        foreach ($InvalidTokens as $token => $desc) {
          if ($params['body_' . $type]) {
            if (preg_match('/' . preg_quote('{' . $token . '}') . '/', $params['body_' . $type])) {
              $dataErrors[] = '<li>' . ts('This message is having a invalid token - %1: %2', array(
 -              1 => $token, 2 => $desc)) . '</li>';
 +                1 => $token,
 +                2 => $desc,
 +              )) . '</li>';
            }
          }
        }
        if (!empty($dataErrors)) {
          $errors['body_' . $type] = ts('The following errors were detected in %1 message:', array(
 -          1 => $type)) . '<ul>' . implode('', $dataErrors) . '</ul><br /><a href="' . CRM_Utils_System::docURL2('Tokens', TRUE, NULL, NULL, NULL, "wiki") . '">' . ts('More information on tokens...') . '</a>';
 +            1 => $type,
 +          )) . '<ul>' . implode('', $dataErrors) . '</ul><br /><a href="' . CRM_Utils_System::docURL2('Tokens', TRUE, NULL, NULL, NULL, "wiki") . '">' . ts('More information on tokens...') . '</a>';
        }
      }
  
      return empty($errors) ? TRUE : $errors;
    }
 -}
  
 +}
index 60e7d43e193c1a2b89190bb3c3b4aeb339c4c873,b3f76c13c3b8a7fa50e76d09801c18c83a1ac9a7..5a0fef0788c1378a0f8053f682f4477cc5a3ec8e
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
@@@ -39,7 -39,7 +39,7 @@@
  class CRM_Mailing_Page_AJAX {
  
    /**
 -   * Function to fetch the template text/html messages
 +   * Fetch the template text/html messages
     */
    public static function template() {
      $templateId = CRM_Utils_Type::escape($_POST['tid'], 'Integer');
    }
  
    /**
 -   * Function to retrieve contact mailings
 +   * Retrieve contact mailings.
     */
    public static function getContactMailings() {
      $contactID = CRM_Utils_Type::escape($_GET['contact_id'], 'Integer');
  
      $sortMapper = array(
 -      0 => 'subject', 1 => 'creator_name', 2 => '', 3 => 'start_date', 4 => '', 5 => 'links',
 +      0 => 'subject',
 +      1 => 'creator_name',
 +      2 => '',
 +      3 => 'start_date',
 +      4 => '',
 +      5 => 'links',
      );
  
 -    $sEcho     = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 -    $offset    = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 -    $rowCount  = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 -    $sort      = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
 +    $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
 +    $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
 +    $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
 +    $sort = isset($_REQUEST['iSortCol_0']) ? CRM_Utils_Array::value(CRM_Utils_Type::escape($_REQUEST['iSortCol_0'], 'Integer'), $sortMapper) : NULL;
      $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
  
      $params = $_POST;
  
      $iFilteredTotal = $iTotal = $params['total'];
      $selectorElements = array(
 -      'subject', 'mailing_creator', 'recipients',
 -      'start_date', 'openstats', 'links',
 +      'subject',
 +      'mailing_creator',
 +      'recipients',
 +      'start_date',
 +      'openstats',
 +      'links',
      );
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encodeDataTableSelector($mailings, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
      CRM_Utils_System::civiExit();
    }
 -}
  
 +}
diff --combined CRM/Pledge/Page/AJAX.php
index 186ef74f822413bafb805d18e0141223fc252ec0,7faeff9b3c7771651eb1429a74e3a108b9f089db..33cec34871433739303ee0d8ac6f2978a4e97117
mode 100755,100644..100755
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
@@@ -23,7 -23,7 +23,7 @@@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
   *
  class CRM_Pledge_Page_AJAX {
  
    /**
 -   * Function for building Pledge Name combo box
 +   * Building Pledge Name combo box.
     */
 -  static function pledgeName() {
 +  public static function pledgeName() {
  
      $getRecords = FALSE;
      if (isset($_GET['name']) && $_GET['name']) {
 -      $name        = CRM_Utils_Type::escape($_GET['name'], 'String');
 -      $name        = str_replace('*', '%', $name);
 +      $name = CRM_Utils_Type::escape($_GET['name'], 'String');
 +      $name = str_replace('*', '%', $name);
        $whereClause = "p.creator_pledge_desc LIKE '%$name%' ";
 -      $getRecords  = TRUE;
 +      $getRecords = TRUE;
      }
  
      if (isset($_GET['id']) && is_numeric($_GET['id'])) {
 -      $pledgeId    = CRM_Utils_Type::escape($_GET['id'], 'Integer');
 +      $pledgeId = CRM_Utils_Type::escape($_GET['id'], 'Integer');
        $whereClause = "p.id = {$pledgeId} ";
 -      $getRecords  = TRUE;
 +      $getRecords = TRUE;
      }
  
      if ($getRecords) {
@@@ -78,28 -78,14 +78,29 @@@ WHERE {$whereClause
        if (!$name && isset($_GET['id'])) {
          $name = $_GET['id'];
        }
 -      $elements[] = array('name' => trim($name, '*'),
 +      $elements[] = array(
 +        'name' => trim($name, '*'),
          'value' => trim($name, '*'),
        );
      }
  
+     header('Content-Type: application/json');
      echo CRM_Utils_JSON::encode($elements, 'value');
      CRM_Utils_System::civiExit();
    }
 -}
  
 +  /**
 +   * Function to setDefaults according to Pledge Id
 +   * for batch entry pledges
 +   */
 +  public function getPledgeDefaults() {
 +    $details = array();
 +    if (!empty($_POST['pid'])) {
 +      $pledgeID = CRM_Utils_Type::escape($_POST['pid'], 'Integer');
 +      $details = CRM_Pledge_BAO_PledgePayment::getOldestPledgePayment($pledgeID);
 +    }
 +    echo json_encode($details);
 +    CRM_Utils_System::civiExit();
 +  }
 +
 +}
index a44f6fd36efc9ec8278109b2788494831d918d91,6284cdbc0cb874a73c502e011299778bb76c3238..626232974f9a55eb8aa7988e344c04b61b0d25e6
@@@ -1,7 -1,8 +1,7 @@@
  <?php
 -
  /*
   +--------------------------------------------------------------------+
 - | CiviCRM version 4.5                                                |
 + | CiviCRM version 4.6                                                |
   +--------------------------------------------------------------------+
   | Copyright CiviCRM LLC (c) 2004-2014                                |
   +--------------------------------------------------------------------+
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
 - * File for the CiviCRM APIv3 mailing_component functions
 + * This api exposes CiviCRM MailingComponent (header and footer).
   *
   * @package CiviCRM_APIv3
 - * @subpackage API_mailing_component
 - *
   */
  
  /**
 - * Save a mailing_component
 + * Save a MailingComponent.
   *
 - * Allowed @params array keys are:
 - * {@getfields mailing_component_create}
 - * @example mailing_componentCreate.php
 - *
 - * @param $params
 + * @param array $params
   *
   * @throws API_Exception
 - * @return array of newly created mailing_component property values.
 - * @access public
 + * @return array
 + *   API result array.
   */
  function civicrm_api3_mailing_component_create($params) {
    return _civicrm_api3_basic_create(_civicrm_api3_get_BAO(__FUNCTION__), $params);
  }
  
+ /**
+  * Adjust Metadata for Create action.
+  *
+  * The metadata is used for setting defaults, documentation & validation.
+  *
+  * @param array $spec
+  *   Array of parameters determined by getfields.
+  */
+ function _civicrm_api3_mailing_component_create_spec(&$spec) {
+   $spec['is_active']['api.default'] = 1;
+ }
  /**
 - * Get a mailing_component
 - *
 - * Allowed @params array keys are:
 - * {@getfields mailing_component_get}
 - * @example mailing_componentCreate.php
 + * Get a MailingComponent.
   *
 - * @param $params
 + * @param array $params
   *
 - * @return array of retrieved mailing_component property values.
 - * @access public
 + * @return array
 + *   API result array.
   */
  function civicrm_api3_mailing_component_get($params) {
    return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
  }
  
  /**
 - * Delete a mailing_component
 + * Adjust metadata for get.
   *
 - * Allowed @params array keys are:
 - * {@getfields mailing_component_delete}
 - * @example mailing_componentCreate.php
 + * @param array $params
 + */
 +function _civicrm_api3_mailing_component_get_spec(&$params) {
 +  // fetch active records by default
 +  $params['is_active']['api.default'] = 1;
 +}
 +
 +/**
 + * Delete a MailingComponent.
   *
 - * @param $params
 + * @param array $params
   *
   * @throws API_Exception
 - * @return array of deleted values.
 - * @access public
 + * @return array
 + *   API result array.
   */
  function civicrm_api3_mailing_component_delete($params) {
    return _civicrm_api3_basic_delete(_civicrm_api3_get_BAO(__FUNCTION__), $params);
index 370cb833a057f8e1af8c361d8cef03759f572f5f,07b77ba2520fcae4af7da27065308cea0d3b8ce5..a58219306ed28fc71fd4198ff860f2bcce528308
@@@ -1,4 -1,5 +1,4 @@@
  <?php
 -// $Id$
  /*
   +--------------------------------------------------------------------+
   | Project60 version 4.3                                              |
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
 -*/
 + */
  
  /**
 - * File for the CiviCRM APIv3 message_template functions
 - *
 - * @package CiviCRM_SEPA
 + * This api exposes CiviCRM message_template.
   *
 + * @package CiviCRM_APIv3
   */
  
  /**
 - * @access public
 + * Create message template.
 + *
 + * @param array $params
 + *
 + * @return array
 + * @throws \API_Exception
   */
  function civicrm_api3_message_template_create($params) {
    return _civicrm_api3_basic_create(_civicrm_api3_get_BAO(__FUNCTION__), $params);
  }
  
  /**
 - * Adjust Metadata for Create action
 + * Adjust Metadata for Create action.
 + *
 + * The metadata is used for setting defaults, documentation & validation.
   *
 - * The metadata is used for setting defaults, documentation & validation
 - * @param array $params array or parameters determined by getfields
 + * @param array $params
 + *   Array of parameters determined by getfields.
   */
  function _civicrm_api3_message_template_create_spec(&$params) {
    $params['msg_title']['api.required'] = 1;
 -  $params['is_active']['api.default'] = true;
 -/*  $params['entity_id']['api.required'] = 1;
 +  $params['is_active']['api.default'] = TRUE;
 +  /*  $params['entity_id']['api.required'] = 1;
    $params['entity_table']['api.default'] = "civicrm_contribution_recur";
    $params['type']['api.default'] = "R";
 -*/
 +   */
  }
  
  /**
 - * @param  array  $params
 + * Delete message template.
 + *
 + * @param array $params
   *
 - * @return boolean | error  true if successfull, error otherwise
 - * {@getfields message_template_delete}
 - * @access public
 + * @return bool
 + *   API result array
   */
  function civicrm_api3_message_template_delete($params) {
    return _civicrm_api3_basic_delete(_civicrm_api3_get_BAO(__FUNCTION__), $params);
  }
  
  /**
 - * @param $params
 + * Adjust metadata for message_template get action.
 + *
 + * @param array $params
   */
  function _civicrm_api3_message_template_get_spec(&$params) {
 +  // fetch active records by default
 +  $params['is_active']['api.default'] = 1;
  }
  
  /**
 - * Retrieve one or more message_template
 - *
 - * @param  array input parameters
 - *
 + * Retrieve one or more message_template.
   *
 - * @example SepaCreditorGet.php Standard Get Example
 + * @param array $params
 + *   Array of name/value pairs.
   *
 - * @param  array $params  an associative array of name/value pairs.
 - *
 - * @return  array api result array
 - * {@getfields message_template_get}
 - * @access public
 + * @return array
 + *   API result array.
   */
  function civicrm_api3_message_template_get($params) {
    return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
  
  /**
   * Sends a template.
 + *
 + * @param array $params
   */
  function civicrm_api3_message_template_send($params) {
-   CRM_Core_BAO_MessageTemplates::sendTemplate($params);
+   // Change external param names to internal ones
+   $fieldSpec = array();
+   _civicrm_api3_message_template_send_spec($fieldSpec);
+   foreach ($fieldSpec as $field => $spec) {
+     if (isset($spec['api.aliases']) && array_key_exists($field, $params)) {
+       $params[CRM_Utils_Array::first($spec['api.aliases'])] = $params[$field];
+       unset($params[$field]);
+     }
+   }
+   if (empty($params['messageTemplateID'])) {
+     if (empty($params['groupName']) || empty($params['valueName'])) {
+       // Can't use civicrm_api3_verify_mandatory for this because it would give the wrong field names
+       throw new API_Exception(
+         "Mandatory key(s) missing from params array: requires id or option_group_name + option_value_name",
+         "mandatory_missing",
+         array("fields" => array('id', 'option_group_name', 'option_value_name'))
+       );
+     }
+   }
+   CRM_Core_BAO_MessageTemplate::sendTemplate($params);
  }
  
  /**
 - * Adjust Metadata for Create action
 + * Adjust Metadata for Create action.
   *
   * The metadata is used for setting defaults, documentation &
   * validation.
   *
 - * @param array $params array or parameters determined by getfields
 + * @param array $params
 + *   Array of parameters determined by getfields.
   */
  function _civicrm_api3_message_template_send_spec(&$params) {
-   $params['messageTemplateID']['api.required'] = 1;
-   $params['messageTemplateID']['title'] = 'Message Template ID';
-   $params['contactId']['api.required'] = 1;
-   $params['contactId']['title'] = 'Contact ID';
-   $params['toEmail']['api.required'] = 1;
-   $params['toEmail']['title'] = 'To Email';
-   $params['toName']['api.required'] = 1;
-   $params['toName']['title'] = 'To Name';
+   $params['id']['description'] = 'ID of the template';
+   $params['id']['title'] = 'Message Template ID';
+   $params['id']['api.aliases'] = array('messageTemplateID', 'message_template_id');
+   $params['option_group_name']['description'] = 'option group name of the template (required if no id supplied)';
+   $params['option_group_name']['title'] = 'Option Group Name';
+   $params['option_group_name']['api.aliases'] = array('groupName');
+   $params['option_value_name']['description'] = 'option value name of the template (required if no id supplied)';
+   $params['option_value_name']['title'] = 'Option Value Name';
+   $params['option_value_name']['api.aliases'] = array('valueName');
+   $params['contact_id']['description'] = 'contact id if contact tokens are to be replaced';
+   $params['contact_id']['title'] = 'Contact ID';
+   $params['contact_id']['api.aliases'] = array('contactId');
+   $params['template_params']['description'] = 'additional template params (other than the ones already set in the template singleton)';
+   $params['template_params']['title'] = 'Template Params';
+   $params['template_params']['api.aliases'] = array('tplParams');
+   $params['from']['description'] = 'the From: header';
+   $params['from']['title'] = 'From';
+   $params['to_name']['description'] = 'the recipient’s name';
+   $params['to_name']['title'] = 'Recipient Name';
+   $params['to_name']['api.aliases'] = array('toName');
+   $params['to_email']['description'] = 'the recipient’s email - mail is sent only if set';
+   $params['to_email']['title'] = 'Recipient Email';
+   $params['to_email']['api.aliases'] = array('toEmail');
+   $params['cc']['description'] = 'the Cc: header';
+   $params['cc']['title'] = 'CC';
+   $params['bcc']['description'] = 'the Bcc: header';
+   $params['bcc']['title'] = 'BCC';
+   $params['reply_to']['description'] = 'the Reply-To: header';
+   $params['reply_to']['title'] = 'Reply To';
+   $params['reply_to']['api.aliases'] = array('replyTo');
+   $params['attachments']['description'] = 'email attachments';
+   $params['attachments']['title'] = 'Attachments';
+   $params['is_test']['description'] = 'whether this is a test email (and hence should include the test banner)';
+   $params['is_test']['title'] = 'Is Test';
+   $params['is_test']['api.aliases'] = array('isTest');
+   $params['pdf_filename']['description'] = 'filename of optional PDF version to add as attachment (do not include path)';
+   $params['pdf_filename']['title'] = 'PDF Filename';
+   $params['pdf_filename']['api.aliases'] = array('PDFFilename');
  }
index 7fa6837a4ac9c1cdc7343dad559ce5ddccf99278,c4ee0beb80324799246d21f8b9589207754a68c2..f38bf305b5a49f3c76da70fdb7c1f7d76f6e1824
@@@ -1,11 -1,25 +1,25 @@@
  // http://civicrm.org/licensing
  (function($, _) {
+   // FIXME: Much of this code is redundant with CRM.loadForm
  
    var ajaxFormParams = {
      dataType:'json',
      beforeSubmit: function(arr, $form, options) {
        $form.block();
      },
+     beforeSerialize: function(form, options) {
+       // Copied from crm.ajax.js
+       if (window.CKEDITOR && window.CKEDITOR.instances) {
+         $.each(CKEDITOR.instances, function() {
+           this.updateElement && this.updateElement();
+         });
+       }
+       if (window.tinyMCE && tinyMCE.editors) {
+         $.each(tinyMCE.editors, function() {
+           this.save();
+         });
+       }
+     },
      success: requestHandler,
      error: errorHandler
    };
@@@ -59,7 -73,7 +73,7 @@@
        o.trigger('crmFormSuccess', [response]);
        $('.crm-inline-edit-container').addClass('crm-edit-ready');
        var data = o.data('edit-params');
 -      var dependent = o.data('dependent-fields') || [];
 +      var dependent = $((o.data('dependent-fields') || []).join(','));
        // Clone the add-new link if replacing it, and queue the clone to be refreshed as a dependent block
        if (o.hasClass('add-new') && response.addressId) {
          data.aid = response.addressId;
@@@ -77,7 -91,7 +91,7 @@@
          var locNo = clData.locno++;
          cl.attr('id', cl.attr('id').replace(locNo, clData.locno)).removeClass('form');
          o.closest('.crm-summary-block').after(clone);
 -        $.merge(dependent, $('.crm-inline-edit', clone));
 +        dependent = dependent.add($('.crm-inline-edit', clone));
        }
        $('a.ui-notify-close', '#crm-notification-container').click();
        // Delete an address
        }
        else {
          // Reload this block plus all dependent blocks
 -        var update = $.merge([o], dependent);
 -        _.each(update, reloadBlock);
 +        reloadBlock(dependent.add(o));
          CRM.status(ts('Saved'));
        }
 -      // Update changelog tab and contact footer
 -      if (response.changeLog && response.changeLog.count) {
 -        CRM.tabHeader.updateCount('#tab_log', response.changeLog.count);
 -      }
 -      $("#crm-record-log").replaceWith(response.changeLog.markup);
 -      // Refresh tab contents - Simple logging
 -      if (!CRM.reloadChangeLogTab && $('#changeLog').closest('.ui-tabs-panel').data('civiCrmSnippet')) {
 -        $('#changeLog').closest('.ui-tabs-panel').crmSnippet('destroy');
 -      }
      }
      else {
        // Handle formRule error
        var errorTag = o.find('.update_oplock_ts');
        if (errorTag.length > 0) {
          $('<span>')
 -          .addClass('crm-lock-button')
 +          .addClass('crm-lock-button css_right')
            .appendTo(errorTag);
  
          var buttonContainer = o.find('.crm-lock-button');
          e.preventDefault();
        })
        // Delete an address
 -      .on('click', '.crm-inline-edit.address .delete-button', function() {
 +      .on('click', '.crm-inline-edit.address .delete-button', function(e) {
           var $block = $(this).closest('.crm-inline-edit.address');
 -         CRM.confirm(function() {
 -            CRM.api('address', 'delete', {id: $block.data('edit-params').aid}, {success:
 -              function(data) {
 -                CRM.status(ts('Address Deleted'));
 +         CRM.confirm({message: ts('Are you sure you want to delete this address?')})
 +           .on('crmConfirm:yes', function() {
 +            CRM.api3('address', 'delete', {id: $block.data('edit-params').aid}, true)
 +              .done(function(data) {
                  $('.crm-inline-edit-container').addClass('crm-edit-ready');
                  $block.remove();
 -              }
 +                reloadBlock('.crm-inline-edit.address:not(.add-new)');
 +              });
              });
 -          },
 -          {
 -          message: ts('Are you sure you want to delete this address?')
 -          }
 -        );
 -        return false;
 +        e.preventDefault();
        })
        // add more and set focus to new row
        .on('click', '.add-more-inline', function(e) {
          }
          $('#crm-contact-actions-list').hide();
        })
 +      .on('crmFormSuccess crmLoad', function(e, data) {
 +        // Update changelog tab and contact footer
 +        if (data && data.changeLog) {
 +          if (data.changeLog.count) {
 +            CRM.tabHeader.updateCount('#tab_log', data.changeLog.count);
 +          }
 +          if (data.changeLog.markup) {
 +            $("#crm-record-log").replaceWith(data.changeLog.markup);
 +          }
 +        }
 +      })
        .on('crmFormSuccess', function(e, data) {
 -        // Reload changelog whenever an inline or popup form submits
 -        CRM.reloadChangeLogTab && CRM.reloadChangeLogTab();
 +        // Refresh changeLog - advanced logging
 +        if (CRM.reloadChangeLogTab) {
 +          CRM.reloadChangeLogTab();
 +        }
 +        // Refresh changeLog - simple logging
 +        // If we didn't get a changelog count in the response, force refresh the changelog tab to populate it
 +        else {
 +          CRM.tabHeader.resetTab('#tab_log', !(data && data.changeLog && data.changeLog.count));
 +        }
          // Refresh dependent blocks
          if (data && data.reloadBlocks) {
 -          _.each(data.reloadBlocks, reloadBlock);
 +          reloadBlock(data.reloadBlocks.join(','));
          }
        });
    });