diff --git a/profiles/civicrm_starterkit/civicrm_starterkit.make b/profiles/civicrm_starterkit/civicrm_starterkit.make
index 2234788ae4a..1259072c81a 100644
--- a/profiles/civicrm_starterkit/civicrm_starterkit.make
+++ b/profiles/civicrm_starterkit/civicrm_starterkit.make
@@ -13,7 +13,7 @@ projects[drupal][version] = "7.51"
; ====== CIVICRM RELATED =========
libraries[civicrm][download][type] = get
-libraries[civicrm][download][url] = "https://download.civicrm.org/civicrm-5.3.1-drupal.tar.gz"
+libraries[civicrm][download][url] = "https://download.civicrm.org/civicrm-5.5.1-drupal.tar.gz"
libraries[civicrm][destination] = modules
libraries[civicrm][directory_name] = civicrm
@@ -22,7 +22,7 @@ libraries[civicrm][directory_name] = civicrm
; Private folders: https://civicrm.org/advisory/civi-sa-2014-001-risk-information-disclosure
; Define [civicrm.files] and [civicrm.private] paths since there is no htaccess file
; to set public/private folders.
-libraries[civicrm][patch][pantheonsettings] = ./patches/pantheon-settings-starterkit-50.patch
+libraries[civicrm][patch][pantheonsettings] = ./patches/pantheon-settings-starterkit-55.patch
libraries[civicrm][patch][publicfiledir] = ./patches/public_files_config.patch
; Set session for cron.
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CONTRIBUTORS.txt b/profiles/civicrm_starterkit/modules/civicrm/CONTRIBUTORS.txt
index 60a8f1ac4e3..c32000ea015 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CONTRIBUTORS.txt
+++ b/profiles/civicrm_starterkit/modules/civicrm/CONTRIBUTORS.txt
@@ -1,7 +1,7 @@
The following people and organizations sponsored and/or contributed new and improved features to the project.
************************************************
-Key Contributors and Sponsors for 5.x
+Code Contributors for 5.x
************************************************
CiviCRM - Coleman Watts, Tim Otten
@@ -9,17 +9,31 @@ CiviCRM - Coleman Watts, Tim Otten
AGH Strategies - Alice Frumin, Andrew Hunt, Eli Lisseck
Agileware - Alok Patel, Francis Whittle, Justin Freeman
Andrew Thompson
+applicado
Australian Greens - Seamus Lee
-CiviDesk - Yashodha Chaku
-CompuCorp - Michael Devery, Mukesh Ram, Omar Abu Hussein, René Olivo, Vinu
- Varshith Sekar
-Coop SymbioTIC - Samuel Vanhove
+Bastien Ho
+Blackfly Solutions - Alan Dixon
+Calibrate - Wannes De Roy
+Caltha - Tomasz Pietrzkowski
+CEDC - Laryn Kragt Bakker
+Chris Burgess
+CiviCoop - Jaap Jansma
+CiviDesk - Sunil Pawar, Yashodha Chaku
+CompuCorp - Camilo Rodriguez, Davi Alexandre, Debarshi Bhaumik, Michael Devery,
+ Mukesh Ram, Omar Abu Hussein, René Olivo, Vinu Varshith Sekar
+Coop SymbioTIC - Mathieu Lutfy, Samuel Vanhove
Davis Media Access - Darrick Servis
+Electronic Frontier Foundation - Mark Burdett
+eQuality Technology - Greg Rundlett
+Freeform Solutions - Herb van den Dool
Fuzion - Jitendra Purohit
Ginkgo Street Labs - Frank Gómez
+Hossein Amin
JMA Consulting - Monish Deb
+Johan Vervloet
John Kingsnorth
Joinery - Allen Shaw
+Kanzu Code - Carl Andrew Lema
Kompetenzzentrum Technik-Diversity-Chancengleichheit - Niels Heinemann
Left Join Labs - Sean Madsen
Lighthouse Design and Consulting - Brian Shaughnessy
@@ -29,12 +43,20 @@ MJW Consulting - Matthew Wire
myDropWizard - David Snopek
Naomi Rosenberg
Olivier Tétard
+OSSeed Technologies - Madhavi Malgaonkar
Oxfam Germany - Thomas Schüttler, Yuliyana Liyana
+Pradeep Nayak
Progressive Technology Project - Jamie McClelland
+Richard van Oosterhout
+Romain Thouvenin
+Squiffle Consulting - Aidan Saunders
Systopia - Björn Endres
Tadpole Collective - Kevin Cristiano
Third Sector Design - Michael McAndrew
+Tom Bloor
Wikimedia Foundation - Eileen McNaughton
+Wildsight - Lars Sanders-Green
+Will Long
************************************************
Key Contributors and Sponsors for 4.7
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/BAO/ACL.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/BAO/ACL.php
index cd9c25dfeee..15221f74565 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/BAO/ACL.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/BAO/ACL.php
@@ -877,7 +877,7 @@ public static function group(
$aclKeys = array_keys($acls);
$aclKeys = implode(',', $aclKeys);
- $cacheKey = "$tableName-$aclKeys";
+ $cacheKey = CRM_Core_BAO_Cache::cleanKey("$tableName-$aclKeys");
$cache = CRM_Utils_Cache::singleton();
$ids = $cache->get($cacheKey);
if (!$ids) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/DAO/ACL.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/DAO/ACL.php
index 97e9f1c151f..d5b37d89f3a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/DAO/ACL.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/ACL/DAO/ACL.php
@@ -168,6 +168,7 @@ public static function &fields() {
'title' => ts('Deny ACL?'),
'description' => 'Is this ACL entry Allow (0) or Deny (1) ?',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_acl',
'entity' => 'ACL',
'bao' => 'CRM_ACL_BAO_ACL',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Activity.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Activity.php
index a0a6b8e4999..e7921e83cc4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Activity.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Activity.php
@@ -920,8 +920,7 @@ public static function deprecatedGetActivities($input) {
$config = CRM_Core_Config::singleton();
- $randomNum = md5(uniqid());
- $activityTempTable = "civicrm_temp_activity_details_{$randomNum}";
+ $activityTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('actdetail')->getName();
$tableFields = array(
'activity_id' => 'int unsigned',
@@ -1012,7 +1011,7 @@ public static function deprecatedGetActivities($input) {
// step 2: Get target and assignee contacts for above activities
// create temp table for target contacts
- $activityContactTempTable = "civicrm_temp_activity_contact_{$randomNum}";
+ $activityContactTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('actcontact')->getName();
$query = "CREATE TEMPORARY TABLE {$activityContactTempTable} (
activity_id int unsigned, contact_id int unsigned, record_type_id varchar(16),
contact_name varchar(255), is_deleted int unsigned, counter int unsigned, INDEX index_activity_id( activity_id ) )
@@ -1773,20 +1772,27 @@ public static function sendSMS(
$smsProviderParams['To'] = '';
}
- $sendResult = self::sendSMSMessage(
- $contactId,
- $tokenText,
- $smsProviderParams,
- $activityID,
- $sourceContactId
- );
+ $doNotSms = CRM_Utils_Array::value('do_not_sms', $contact, 0);
- if (PEAR::isError($sendResult)) {
- // Collect all of the PEAR_Error objects
- $errMsgs[] = $sendResult;
+ if ($doNotSms) {
+ $errMsgs[] = PEAR::raiseError('Contact Does not accept SMS', NULL, PEAR_ERROR_RETURN);
}
else {
- $success++;
+ $sendResult = self::sendSMSMessage(
+ $contactId,
+ $tokenText,
+ $smsProviderParams,
+ $activityID,
+ $sourceContactId
+ );
+
+ if (PEAR::isError($sendResult)) {
+ // Collect all of the PEAR_Error objects
+ $errMsgs[] = $sendResult;
+ }
+ else {
+ $success++;
+ }
}
}
@@ -1827,9 +1833,7 @@ public static function sendSMSMessage(
$activityID,
$sourceContactID = NULL
) {
- $doNotSms = TRUE;
$toPhoneNumber = NULL;
-
if ($smsProviderParams['To']) {
// If phone number is specified use it
$toPhoneNumber = trim($smsProviderParams['To']);
@@ -1843,13 +1847,12 @@ public static function sendSMSMessage(
$toPhoneNumberDetails = reset($toPhoneNumbers);
$toPhoneNumber = CRM_Utils_Array::value('phone', $toPhoneNumberDetails);
// Contact allows to send sms
- $doNotSms = FALSE;
}
}
// make sure both phone are valid
// and that the recipient wants to receive sms
- if (empty($toPhoneNumber) or $doNotSms) {
+ if (empty($toPhoneNumber)) {
return PEAR::raiseError(
'Recipient phone number is invalid or recipient does not want to receive SMS',
NULL,
@@ -1857,7 +1860,7 @@ public static function sendSMSMessage(
);
}
- $recipient = $smsProviderParams['To'];
+ $recipient = $toPhoneNumber;
$smsProviderParams['contact_id'] = $toID;
$smsProviderParams['parent_activity_id'] = $activityID;
@@ -2529,69 +2532,70 @@ public static function isOverdue($activity) {
* @return array
* array of exportable Fields
*/
- public static function &exportableFields($name = 'Activity') {
- if (!isset(self::$_exportableFields[$name])) {
- self::$_exportableFields[$name] = array();
-
- // TODO: ideally we should retrieve all fields from xml, in this case since activity processing is done
- // my case hence we have defined fields as case_*
- if ($name == 'Activity') {
- $exportableFields = CRM_Activity_DAO_Activity::export();
- $exportableFields['source_contact_id']['title'] = ts('Source Contact ID');
- $exportableFields['source_contact'] = array(
- 'title' => ts('Source Contact'),
- 'type' => CRM_Utils_Type::T_STRING,
- );
+ public static function exportableFields($name = 'Activity') {
+ self::$_exportableFields[$name] = array();
+
+ // TODO: ideally we should retrieve all fields from xml, in this case since activity processing is done
+ // my case hence we have defined fields as case_*
+ if ($name == 'Activity') {
+ $exportableFields = CRM_Activity_DAO_Activity::export();
+ $exportableFields['source_contact_id'] = [
+ 'title' => ts('Source Contact ID'),
+ 'type' => CRM_Utils_Type::T_INT,
+ ];
+ $exportableFields['source_contact'] = array(
+ 'title' => ts('Source Contact'),
+ 'type' => CRM_Utils_Type::T_STRING,
+ );
- $Activityfields = array(
- 'activity_type' => array(
- 'title' => ts('Activity Type'),
- 'name' => 'activity_type',
- 'type' => CRM_Utils_Type::T_STRING,
- 'searchByLabel' => TRUE,
- ),
- 'activity_status' => array(
- 'title' => ts('Activity Status'),
- 'name' => 'activity_status',
- 'type' => CRM_Utils_Type::T_STRING,
- 'searchByLabel' => TRUE,
- ),
- 'activity_priority' => array(
- 'title' => ts('Activity Priority'),
- 'name' => 'activity_priority',
- 'type' => CRM_Utils_Type::T_STRING,
- 'searchByLabel' => TRUE,
- ),
- );
- $fields = array_merge($Activityfields, $exportableFields);
- }
- else {
- // Set title to activity fields.
- $fields = array(
- 'case_activity_subject' => array('title' => ts('Activity Subject'), 'type' => CRM_Utils_Type::T_STRING),
- 'case_source_contact_id' => array('title' => ts('Activity Reporter'), 'type' => CRM_Utils_Type::T_STRING),
- 'case_recent_activity_date' => array('title' => ts('Activity Actual Date'), 'type' => CRM_Utils_Type::T_DATE),
- 'case_scheduled_activity_date' => array(
- 'title' => ts('Activity Scheduled Date'),
- 'type' => CRM_Utils_Type::T_DATE,
- ),
- 'case_recent_activity_type' => array('title' => ts('Activity Type'), 'type' => CRM_Utils_Type::T_STRING),
- 'case_activity_status' => array('title' => ts('Activity Status'), 'type' => CRM_Utils_Type::T_STRING),
- 'case_activity_duration' => array('title' => ts('Activity Duration'), 'type' => CRM_Utils_Type::T_INT),
- 'case_activity_medium_id' => array('title' => ts('Activity Medium'), 'type' => CRM_Utils_Type::T_INT),
- 'case_activity_details' => array('title' => ts('Activity Details'), 'type' => CRM_Utils_Type::T_TEXT),
- 'case_activity_is_auto' => array(
- 'title' => ts('Activity Auto-generated?'),
- 'type' => CRM_Utils_Type::T_BOOLEAN,
- ),
- );
- }
+ $Activityfields = array(
+ 'activity_type' => array(
+ 'title' => ts('Activity Type'),
+ 'name' => 'activity_type',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'searchByLabel' => TRUE,
+ ),
+ 'activity_status' => array(
+ 'title' => ts('Activity Status'),
+ 'name' => 'activity_status',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'searchByLabel' => TRUE,
+ ),
+ 'activity_priority' => array(
+ 'title' => ts('Activity Priority'),
+ 'name' => 'activity_priority',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'searchByLabel' => TRUE,
+ ),
+ );
+ $fields = array_merge($Activityfields, $exportableFields);
+ }
+ else {
+ // Set title to activity fields.
+ $fields = array(
+ 'case_activity_subject' => array('title' => ts('Activity Subject'), 'type' => CRM_Utils_Type::T_STRING),
+ 'case_source_contact_id' => array('title' => ts('Activity Reporter'), 'type' => CRM_Utils_Type::T_STRING),
+ 'case_recent_activity_date' => array('title' => ts('Activity Actual Date'), 'type' => CRM_Utils_Type::T_DATE),
+ 'case_scheduled_activity_date' => array(
+ 'title' => ts('Activity Scheduled Date'),
+ 'type' => CRM_Utils_Type::T_DATE,
+ ),
+ 'case_recent_activity_type' => array('title' => ts('Activity Type'), 'type' => CRM_Utils_Type::T_STRING),
+ 'case_activity_status' => array('title' => ts('Activity Status'), 'type' => CRM_Utils_Type::T_STRING),
+ 'case_activity_duration' => array('title' => ts('Activity Duration'), 'type' => CRM_Utils_Type::T_INT),
+ 'case_activity_medium_id' => array('title' => ts('Activity Medium'), 'type' => CRM_Utils_Type::T_INT),
+ 'case_activity_details' => array('title' => ts('Activity Details'), 'type' => CRM_Utils_Type::T_TEXT),
+ 'case_activity_is_auto' => array(
+ 'title' => ts('Activity Auto-generated?'),
+ 'type' => CRM_Utils_Type::T_BOOLEAN,
+ ),
+ );
+ }
- // add custom data for case activities
- $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Activity'));
+ // add custom data for case activities
+ $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Activity'));
- self::$_exportableFields[$name] = $fields;
- }
+ self::$_exportableFields[$name] = $fields;
return self::$_exportableFields[$name];
}
@@ -2831,6 +2835,22 @@ public static function checkPermission($activityId, $action) {
return $allow;
}
+ /**
+ * Checks if user has permissions to edit inbound e-mails, either bsic info
+ * or both basic information and content.
+ *
+ * @return bool
+ */
+ public function checkEditInboundEmailsPermissions() {
+ if (CRM_Core_Permission::check('edit inbound email basic information')
+ || CRM_Core_Permission::check('edit inbound email basic information and content')
+ ) {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
/**
* Wrapper for ajax activity selector.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Query.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Query.php
index 724a30642a6..a450337ee2d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Query.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/BAO/Query.php
@@ -136,7 +136,13 @@ public static function select(&$query) {
if (!empty($query->_returnProperties['source_contact'])) {
$query->_select['source_contact'] = 'source_contact.sort_name as source_contact';
$query->_element['source_contact'] = 1;
- $query->_tables['source_contact'] = $query->_whereTables['source_contact'] = 1;
+ $query->_tables['civicrm_activity'] = $query->_tables['source_contact'] = $query->_whereTables['source_contact'] = 1;
+ }
+
+ if (!empty($query->_returnProperties['source_contact_id'])) {
+ $query->_select['source_contact_id'] = 'source_contact.id as source_contact_id';
+ $query->_element['source_contact_id'] = 1;
+ $query->_tables['civicrm_activity'] = $query->_tables['source_contact'] = $query->_whereTables['source_contact'] = 1;
}
if (!empty($query->_returnProperties['activity_result'])) {
@@ -348,6 +354,14 @@ public static function whereClauseSingle(&$values, &$query) {
$query->_qill[$grouping][] = ts('Activities which are not Followup Activities');
}
break;
+
+ case 'source_contact':
+ case 'source_contact_id':
+ $columnName = strstr($name, '_id') ? 'id' : 'sort_name';
+ $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("source_contact.{$columnName}", $op, $value, CRM_Utils_Type::typeToString($fields[$name]['type']));
+ list($op, $value) = CRM_Contact_BAO_Query::buildQillForFieldValue('CRM_Contact_DAO_Contact', $columnName, $value, $op);
+ $query->_qill[$grouping][] = ts('%1 %2 %3', array(1 => $fields[$name]['title'], 2 => $op, 3 => $value));
+ break;
}
}
@@ -399,12 +413,16 @@ public static function from($name, $mode, $side) {
break;
case 'source_contact':
- $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
- $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
+ $sourceID = CRM_Core_PseudoConstant::getKey(
+ 'CRM_Activity_BAO_ActivityContact',
+ 'record_type_id',
+ 'Activity Source'
+ );
$from = "
- LEFT JOIN civicrm_activity_contact ac
- ON ( ac.activity_id = civicrm_activity_contact.activity_id AND ac.record_type_id = {$sourceID})
- INNER JOIN civicrm_contact source_contact ON (ac.contact_id = source_contact.id)";
+ LEFT JOIN civicrm_activity_contact source_activity
+ ON (source_activity.activity_id = civicrm_activity_contact.activity_id
+ AND source_activity.record_type_id = {$sourceID})
+ LEFT JOIN civicrm_contact source_contact ON (source_activity.contact_id = source_contact.id)";
break;
case 'parent_id':
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/DAO/Activity.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/DAO/Activity.php
index c10f7d5b881..bf8a0be6140 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/DAO/Activity.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/DAO/Activity.php
@@ -475,6 +475,7 @@ public static function &fields() {
'headerPattern' => '/(is.)?test(.activity)?/i',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_activity',
'entity' => 'Activity',
'bao' => 'CRM_Activity_BAO_Activity',
@@ -505,6 +506,7 @@ public static function &fields() {
'name' => 'is_auto',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Auto'),
+ 'default' => '0',
'table_name' => 'civicrm_activity',
'entity' => 'Activity',
'bao' => 'CRM_Activity_BAO_Activity',
@@ -575,6 +577,7 @@ public static function &fields() {
'headerPattern' => '/(activity.)?(trash|deleted)/i',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_activity',
'entity' => 'Activity',
'bao' => 'CRM_Activity_BAO_Activity',
@@ -651,6 +654,7 @@ public static function &fields() {
'headerPattern' => '/(activity.)?(star|favorite)/i',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_activity',
'entity' => 'Activity',
'bao' => 'CRM_Activity_BAO_Activity',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Activity.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Activity.php
index 5f78cbd9f1b..71d6ff01956 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Activity.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Activity.php
@@ -308,6 +308,7 @@ public function preProcess() {
CRM_Activity_BAO_Activity::checkPermission($this->_activityId, CRM_Core_Action::UPDATE)
) {
$this->assign('permission', 'edit');
+ $this->assign('allow_edit_inbound_emails', CRM_Activity_BAO_Activity::checkEditInboundEmailsPermissions());
}
if (!$this->_activityTypeId && $this->_activityId) {
@@ -516,10 +517,20 @@ public function preProcess() {
$params = array('id' => $this->_activityId);
CRM_Activity_BAO_Activity::retrieve($params, $this->_values);
}
+
$this->set('values', $this->_values);
}
if ($this->_action & CRM_Core_Action::UPDATE) {
+ // We filter out alternatives, in case this is a stored e-mail, before sending to front-end
+ $this->_values['details'] = CRM_Utils_String::stripAlternatives($this->_values['details']) ?: '';
+
+ if ($this->_activityTypeName === 'Inbound Email' &&
+ !CRM_Core_Permission::check('edit inbound email basic information and content')
+ ) {
+ $this->_fields['details']['type'] = 'static';
+ }
+
CRM_Core_Form_RecurringEntity::preProcess('civicrm_activity');
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Task.php
index 254579876b0..3a052beec46 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Form/Task.php
@@ -32,37 +32,10 @@
*/
/**
- * Class for activity task actions.
+ * Class for activity form task actions.
+ * FIXME: This needs refactoring to properly inherit from CRM_Core_Form_Task and share more functions.
*/
-class CRM_Activity_Form_Task extends CRM_Core_Form {
-
- /**
- * The task being performed.
- *
- * @var int
- */
- protected $_task;
-
- /**
- * The additional clause that we restrict the search with.
- *
- * @var string
- */
- protected $_componentClause = NULL;
-
- /**
- * The array that holds all the component ids.
- *
- * @var array
- */
- protected $_componentIds;
-
- /**
- * The array that holds all the contact ids.
- *
- * @var array
- */
- public $_contactIds;
+class CRM_Activity_Form_Task extends CRM_Core_Form_Task {
/**
* The array that holds all the member ids.
@@ -82,9 +55,8 @@ public function preProcess() {
* Common pre-process function.
*
* @param CRM_Core_Form $form
- * @param bool $useTable
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_activityHolderIds = array();
$values = $form->controller->exportValues($form->get('searchFormName'));
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Page/Tab.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Page/Tab.php
index 8a4cd70d4ec..305c9dd8b6d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Page/Tab.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Page/Tab.php
@@ -131,6 +131,7 @@ public function preProcess() {
$this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse');
$this->assign('action', $this->_action);
+ $this->assign('allow_edit_inbound_emails', CRM_Activity_BAO_Activity::checkEditInboundEmailsPermissions());
// also create the form element for the activity links box
$controller = new CRM_Core_Controller_Simple(
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Selector/Activity.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Selector/Activity.php
index e7f2541bed8..8182c6409cf 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Selector/Activity.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Activity/Selector/Activity.php
@@ -181,6 +181,13 @@ public static function actionLinks(
case 'Inbound Email':
$url = 'civicrm/contact/view/activity';
$qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}";
+
+ if (CRM_Core_Permission::check('edit inbound email basic information')
+ || CRM_Core_Permission::check('edit inbound email basic information and content')
+ ) {
+ $showDelete = $showUpdate = TRUE;
+ $qsUpdate = "atype={$activityTypeId}&action=update&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}";
+ }
break;
case 'Open Case':
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Job.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Job.php
index 74776dd0d41..e319f498ca6 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Job.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Job.php
@@ -180,7 +180,7 @@ public function setDefaultValues() {
*/
public function postProcess() {
- CRM_Utils_System::flushCache('CRM_Core_DAO_Job');
+ CRM_Utils_System::flushCache();
if ($this->_action & CRM_Core_Action::DELETE) {
CRM_Core_BAO_Job::del($this->_id);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/LocationType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/LocationType.php
index 7979db2dabd..b1e1a977636 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/LocationType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/LocationType.php
@@ -86,7 +86,7 @@ public function buildQuickForm() {
* Process the form submission.
*/
public function postProcess() {
- CRM_Utils_System::flushCache('CRM_Core_DAO_LocationType');
+ CRM_Utils_System::flushCache();
if ($this->_action & CRM_Core_Action::DELETE) {
CRM_Core_BAO_LocationType::del($this->_id);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/OptionGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/OptionGroup.php
index 059a5bf8786..0b76228f1c1 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/OptionGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/OptionGroup.php
@@ -78,7 +78,7 @@ public function buildQuickForm() {
CRM_Core_DAO::getAttribute('CRM_Core_DAO_OptionGroup', 'description')
);
- $this->addSelect('data_type', array('options' => CRM_Utils_Type::dataTypes()), TRUE);
+ $this->addSelect('data_type', array('options' => CRM_Utils_Type::dataTypes()), empty($this->_values['is_reserved']));
$element = $this->add('checkbox', 'is_active', ts('Enabled?'));
if ($this->_action & CRM_Core_Action::UPDATE) {
@@ -96,8 +96,12 @@ public function buildQuickForm() {
$element->freeze();
}
}
+
+ $this->add('checkbox', 'is_reserved', ts('Reserved?'));
+ $this->freeze('is_reserved');
+
if (!empty($this->_values['is_reserved'])) {
- $this->freeze(array('name', 'is_active'));
+ $this->freeze(array('name', 'is_active', 'data_type'));
}
}
@@ -110,22 +114,25 @@ public function buildQuickForm() {
public function postProcess() {
CRM_Utils_System::flushCache();
- $params = $this->exportValues();
if ($this->_action & CRM_Core_Action::DELETE) {
CRM_Core_BAO_OptionGroup::del($this->_id);
CRM_Core_Session::setStatus(ts('Selected option group has been deleted.'), ts('Record Deleted'), 'success');
}
else {
-
- $params = $ids = array();
// store the submitted values in an array
$params = $this->exportValues();
- if ($this->_action & CRM_Core_Action::UPDATE) {
- $ids['optionGroup'] = $this->_id;
+ if ($this->_action & CRM_Core_Action::ADD) {
+ // If we are adding option group via UI it should not be marked reserved.
+ if (!isset($params['is_reserved'])) {
+ $params['is_reserved'] = 0;
+ }
+ }
+ elseif ($this->_action & CRM_Core_Action::UPDATE) {
+ $params['id'] = $this->_id;
}
- $optionGroup = CRM_Core_BAO_OptionGroup::add($params, $ids);
+ $optionGroup = CRM_Core_BAO_OptionGroup::add($params);
CRM_Core_Session::setStatus(ts('The Option Group \'%1\' has been saved.', array(1 => $optionGroup->name)), ts('Saved'), 'success');
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Options.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Options.php
index f68718d881b..fd4aa9dfa18 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Options.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Options.php
@@ -464,9 +464,9 @@ public function postProcess() {
$params['reset_default_for'] = array('filter' => "0, " . $params['filter']);
}
- //make sure we should has to have space, CRM-6977
+ //make sure we only have a single space, CRM-6977 and dev/mail/15
if ($this->_gName == 'from_email_address') {
- $params['label'] = str_replace('"<', '" <', $params['label']);
+ $params['label'] = $this->sanitizeFromEmailAddress($params['label']);
}
}
@@ -484,20 +484,7 @@ public function postProcess() {
$params['color'] = 'null';
}
- $groupParams = array('name' => ($this->_gName));
- $optionValue = CRM_Core_OptionValue::addOptionValue($params, $groupParams, $this->_action, $this->_id);
-
- // CRM-11516
- if (!empty($params['financial_account_id'])) {
- $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
- $params = array(
- 'entity_table' => 'civicrm_option_value',
- 'entity_id' => $optionValue->id,
- 'account_relationship' => $relationTypeId,
- 'financial_account_id' => $params['financial_account_id'],
- );
- CRM_Financial_BAO_FinancialTypeAccount::add($params);
- }
+ $optionValue = CRM_Core_OptionValue::addOptionValue($params, $this->_gName, $this->_action, $this->_id);
CRM_Core_Session::setStatus(ts('The %1 \'%2\' has been saved.', array(
1 => $this->_gLabel,
@@ -508,4 +495,9 @@ public function postProcess() {
}
}
+ public function sanitizeFromEmailAddress($email) {
+ preg_match("/^\"(.*)\" *<([^@>]*@[^@>]*)>$/", $email, $parts);
+ return "\"{$parts[1]}\" <$parts[2]>";
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/PaymentProcessorType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/PaymentProcessorType.php
index f8161705674..6dfdaf7647c 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/PaymentProcessorType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/PaymentProcessorType.php
@@ -203,7 +203,7 @@ public function setDefaultValues() {
* Process the form submission.
*/
public function postProcess() {
- CRM_Utils_System::flushCache('CRM_Financial_DAO_PaymentProcessorType');
+ CRM_Utils_System::flushCache();
if ($this->_action & CRM_Core_Action::DELETE) {
CRM_Financial_BAO_PaymentProcessorType::del($this->_id);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/ScheduleReminders.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/ScheduleReminders.php
index 106487c5e32..1067dad2c53 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/ScheduleReminders.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/ScheduleReminders.php
@@ -43,6 +43,22 @@ class CRM_Admin_Form_ScheduleReminders extends CRM_Admin_Form {
public $_freqUnits;
+ protected $_compId;
+
+ /**
+ * @return mixed
+ */
+ public function getComponentID() {
+ return $this->_compId;
+ }
+
+ /**
+ * @param mixed $compId
+ */
+ public function setComponentID($compId) {
+ $this->_compId = $compId;
+ }
+
/**
* Build the form object.
*/
@@ -50,57 +66,46 @@ public function buildQuickForm() {
parent::buildQuickForm();
$this->_mappingID = $mappingID = NULL;
$providersCount = CRM_SMS_BAO_Provider::activeProviderCount();
- $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
+ $this->setContext();
+ $isEvent = $this->getContext() == 'event';
- //CRM-16777: Don't provide access to administer schedule reminder page, with user that does not have 'administer CiviCRM' permission
- if (empty($this->_context) && !CRM_Core_Permission::check('administer CiviCRM')) {
- CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
- }
- //CRM-16777: When user have ACLs 'edit' permission for specific event, do not give access to add, delete & updtae
- //schedule reminder for other events.
- else {
- $this->_compId = CRM_Utils_Request::retrieve('compId', 'Integer', $this);
- if (!CRM_Event_BAO_Event::checkPermission($this->_compId, CRM_Core_Permission::EDIT)) {
- CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
+ if ($isEvent) {
+ $this->setComponentID(CRM_Utils_Request::retrieve('compId', 'Integer', $this));
+ if (!CRM_Event_BAO_Event::checkPermission($this->getComponentID(), CRM_Core_Permission::EDIT)) {
+ throw new CRM_Core_Exception(ts('You do not have permission to access this page.'));
}
}
+ elseif (!CRM_Core_Permission::check('administer CiviCRM')) {
+ throw new CRM_Core_Exception(ts('You do not have permission to access this page.'));
+ }
if ($this->_action & (CRM_Core_Action::DELETE)) {
$reminderName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionSchedule', $this->_id, 'title');
- if ($this->_context == 'event') {
- $this->_compId = CRM_Utils_Request::retrieve('compId', 'Integer', $this);
- }
$this->assign('reminderName', $reminderName);
return;
}
elseif ($this->_action & (CRM_Core_Action::UPDATE)) {
$this->_mappingID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_ActionSchedule', $this->_id, 'mapping_id');
- if ($this->_context == 'event') {
- $this->_compId = CRM_Utils_Request::retrieve('compId', 'Integer', $this);
- }
}
- elseif (!empty($this->_context)) {
- if ($this->_context == 'event') {
- $this->_compId = CRM_Utils_Request::retrieve('compId', 'Integer', $this);
- $isTemplate = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $this->_compId, 'is_template');
- $mapping = CRM_Utils_Array::first(CRM_Core_BAO_ActionSchedule::getMappings(array(
- 'id' => $isTemplate ? CRM_Event_ActionMapping::EVENT_TPL_MAPPING_ID : CRM_Event_ActionMapping::EVENT_NAME_MAPPING_ID,
- )));
- if ($mapping) {
- $this->_mappingID = $mapping->getId();
- }
- else {
- CRM_Core_Error::fatal('Could not find mapping for event scheduled reminders.');
- }
+ if ($isEvent) {
+ $isTemplate = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $this->getComponentID(), 'is_template');
+ $mapping = CRM_Utils_Array::first(CRM_Core_BAO_ActionSchedule::getMappings(array(
+ 'id' => $isTemplate ? CRM_Event_ActionMapping::EVENT_TPL_MAPPING_ID : CRM_Event_ActionMapping::EVENT_NAME_MAPPING_ID,
+ )));
+ if ($mapping) {
+ $this->_mappingID = $mapping->getId();
+ }
+ else {
+ throw new CRM_Core_Exception('Could not find mapping for event scheduled reminders.');
}
}
- if (!empty($_POST) && !empty($_POST['entity']) && empty($this->_context)) {
+ if (!empty($_POST) && !empty($_POST['entity']) && empty($this->getContext())) {
$mappingID = $_POST['entity'][0];
}
elseif ($this->_mappingID) {
$mappingID = $this->_mappingID;
- if ($this->_context == 'event') {
+ if ($isEvent) {
$this->add('hidden', 'mappingID', $mappingID);
}
}
@@ -123,7 +128,7 @@ public function buildQuickForm() {
array_combine(array_keys($entityRecipientLabels), array_keys($entityRecipientLabels))
));
- if (empty($this->_context)) {
+ if (!$this->getContext()) {
$sel = &$this->add(
'hierselect',
'entity',
@@ -158,7 +163,7 @@ public function buildQuickForm() {
$attributes = array('multiple' => 'multiple', 'class' => 'crm-select2 huge', 'placeholder' => $options[0]);
unset($options[0]);
$this->add('select', 'entity', ts('Recipient(s)'), $options, TRUE, $attributes);
- $this->assign('context', $this->_context);
+ $this->assign('context', $this->getContext());
}
//get the frequency units.
@@ -243,7 +248,7 @@ public function buildQuickForm() {
);
if (!empty($this->_submitValues['recipient_listing'])) {
- if (!empty($this->_context)) {
+ if ($this->getContext()) {
$recipientListingOptions = CRM_Core_BAO_ActionSchedule::getRecipientListing($this->_mappingID, $this->_submitValues['recipient']);
}
else {
@@ -325,7 +330,7 @@ public static function formRule($fields, $files, $self) {
$errors['html_message'] = ts('The HTML message is a required field.');
}
- if (empty($self->_context) && CRM_Utils_System::isNull(CRM_Utils_Array::value(1, $fields['entity']))) {
+ if (empty($self->getContext()) && CRM_Utils_System::isNull(CRM_Utils_Array::value(1, $fields['entity']))) {
$errors['entity'] = ts('Please select entity value');
}
@@ -384,7 +389,7 @@ public function setDefaultValues() {
$defaults = $this->_values;
$entityValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, CRM_Utils_Array::value('entity_value', $defaults));
$entityStatus = explode(CRM_Core_DAO::VALUE_SEPARATOR, CRM_Utils_Array::value('entity_status', $defaults));
- if (empty($this->_context)) {
+ if (empty($this->getContext())) {
$defaults['entity'][0] = CRM_Utils_Array::value('mapping_id', $defaults);
$defaults['entity'][1] = $entityValue;
$defaults['entity'][2] = $entityStatus;
@@ -430,9 +435,9 @@ public function postProcess() {
// delete reminder
CRM_Core_BAO_ActionSchedule::del($this->_id);
CRM_Core_Session::setStatus(ts('Selected Reminder has been deleted.'), ts('Record Deleted'), 'success');
- if ($this->_context == 'event' && $this->_compId) {
+ if ($this->getContext() == 'event' && $this->getComponentID()) {
$url = CRM_Utils_System::url('civicrm/event/manage/reminder',
- "reset=1&action=browse&id={$this->_compId}&component={$this->_context}&setTab=1"
+ "reset=1&action=browse&id=" . $this->getComponentID() . "&component=" . $this->getContext() . "&setTab=1"
);
$session = CRM_Core_Session::singleton();
$session->pushUserContext($url);
@@ -457,8 +462,8 @@ public function postProcess() {
);
}
- if ($this->_context == 'event' && $this->_compId) {
- $url = CRM_Utils_System::url('civicrm/event/manage/reminder', "reset=1&action=browse&id={$this->_compId}&component={$this->_context}&setTab=1");
+ if ($this->getContext() == 'event' && $this->getComponentID()) {
+ $url = CRM_Utils_System::url('civicrm/event/manage/reminder', "reset=1&action=browse&id=" . $this->getComponentID() . "&component=" . $this->getContext() . "&setTab=1");
$session = CRM_Core_Session::singleton();
$session->pushUserContext($url);
}
@@ -543,9 +548,9 @@ public function parseActionSchedule($values) {
$params['group_id'] = $params['recipient_manual'] = $params['recipient_listing'] = 'null';
}
- if (!empty($this->_mappingID) && !empty($this->_compId)) {
+ if (!empty($this->_mappingID) && !empty($this->getComponentID())) {
$params['mapping_id'] = $this->_mappingID;
- $params['entity_value'] = $this->_compId;
+ $params['entity_value'] = $this->getComponentID();
$params['entity_status'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, $values['entity']);
}
else {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting.php
index e19ff512865..695f6f097df 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting.php
@@ -233,6 +233,7 @@ public function commonProcess(&$params) {
}
CRM_Core_Config::clearDBCache();
+ Civi::cache('session')->clear(); // This doesn't make a lot of sense to me, but it maintains pre-existing behavior.
CRM_Utils_System::flushCache();
CRM_Core_Resources::singleton()->resetCacheCode();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/Miscellaneous.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/Miscellaneous.php
index 5f0cb2c0246..31ef53a873c 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/Miscellaneous.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/Miscellaneous.php
@@ -49,6 +49,7 @@ class CRM_Admin_Form_Setting_Miscellaneous extends CRM_Admin_Form_Setting {
'recaptchaOptions' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'recaptchaPublicKey' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'recaptchaPrivateKey' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
+ 'forceRecaptcha' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'wkhtmltopdfPath' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'recentItemsMaxCount' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'recentItemsProviders' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php
index 68711ff42aa..b5c7bb8c57b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php
@@ -65,6 +65,7 @@ public function postProcess() {
// clear all caches
CRM_Core_Config::clearDBCache();
+ Civi::cache('session')->clear();
CRM_Utils_System::flushCache();
parent::rebuildMenu();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/AJAX.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/AJAX.php
index 4854ffb9df7..1fef6d99e87 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/AJAX.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/AJAX.php
@@ -123,7 +123,7 @@ public static function getStatusMsg() {
$ret['content'] = ts('Are you sure you want to disable this CiviCRM Profile field?');
break;
- case 'CRM_Contribute_BAO_ManagePremiums':
+ case 'CRM_Contribute_BAO_Product':
$ret['content'] = ts('Are you sure you want to disable this premium? This action will remove the premium from any contribution pages that currently offer it. However it will not delete the premium record - so you can re-enable it and add it back to your contribution page(s) at a later time.');
break;
@@ -265,8 +265,8 @@ static public function mappingList() {
$recipientMapping = array_combine(array_keys($entityRecipientLabels), array_keys($entityRecipientLabels));
$output = array(
- 'sel4' => CRM_Utils_Array::toKeyValueRows($dateFieldLabels),
- 'sel5' => CRM_Utils_Array::toKeyValueRows($entityRecipientLabels),
+ 'sel4' => CRM_Utils_Array::makeNonAssociative($dateFieldLabels),
+ 'sel5' => CRM_Utils_Array::makeNonAssociative($entityRecipientLabels),
'recipientMapping' => $recipientMapping,
);
@@ -291,7 +291,7 @@ public static function recipientListing() {
));
CRM_Utils_JSON::output(array(
- 'recipients' => CRM_Utils_Array::toKeyValueRows(CRM_Core_BAO_ActionSchedule::getRecipientListing($mappingID, $recipientType)),
+ 'recipients' => CRM_Utils_Array::makeNonAssociative(CRM_Core_BAO_ActionSchedule::getRecipientListing($mappingID, $recipientType)),
));
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/Job.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/Job.php
index 92237cccda2..9d9d31699d7 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/Job.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Admin/Page/Job.php
@@ -96,6 +96,12 @@ public function &links() {
'qs' => 'action=delete&id=%%id%%',
'title' => ts('Delete Scheduled Job'),
),
+ CRM_Core_Action::COPY => array(
+ 'name' => ts('Copy'),
+ 'url' => 'civicrm/admin/job',
+ 'qs' => 'action=copy&id=%%id%%',
+ 'title' => ts('Copy Scheduled Job'),
+ ),
);
}
return self::$_links;
@@ -128,11 +134,25 @@ public function run() {
$this, FALSE, 0
);
+ // FIXME: Why are we comparing an integer with a string here?
if ($this->_action == 'export') {
$session = CRM_Core_Session::singleton();
$session->pushUserContext(CRM_Utils_System::url('civicrm/admin/job', 'reset=1'));
}
+ if (($this->_action & CRM_Core_Action::COPY) && (!empty($this->_id))) {
+ try {
+ $jobResult = civicrm_api3('Job', 'clone', array('id' => $this->_id));
+ if ($jobResult['count'] > 0) {
+ CRM_Core_Session::setStatus($jobResult['values'][$jobResult['id']]['name'], ts('Job copied successfully'), 'success');
+ }
+ CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/job', 'reset=1'));
+ }
+ catch (Exception $e) {
+ CRM_Core_Session::setStatus(ts('Failed to copy job'), 'Error');
+ }
+ }
+
return parent::run();
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Batch/BAO/Batch.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Batch/BAO/Batch.php
index ceae0731229..ee73a515f07 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Batch/BAO/Batch.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Batch/BAO/Batch.php
@@ -719,6 +719,8 @@ public static function getBatchFinancialItems($entityID, $returnValues, $notPres
'contribution_date_low',
'contribution_check_number',
'contribution_status_id',
+ 'financial_trxn_card_type_id',
+ 'financial_trxn_pan_truncation',
);
$values = array();
foreach ($searchFields as $field) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/BAO/Petition.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/BAO/Petition.php
index 43246cc66f6..f8b0500ca27 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/BAO/Petition.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/BAO/Petition.php
@@ -586,7 +586,7 @@ public static function sendEmail($params, $sendEmailMode) {
$toName = CRM_Contact_BAO_Contact::displayName($params['contactId']);
- $replyTo = "do-not-reply@$emailDomain";
+ $replyTo = CRM_Core_BAO_Domain::getNoReplyEmailAddress();
// set additional general message template params (custom tokens to use in email msg templates)
// tokens then available in msg template as {$petition.title}, etc
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/DAO/Survey.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/DAO/Survey.php
index ebb2c5275ac..935b3dda570 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/DAO/Survey.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/DAO/Survey.php
@@ -349,6 +349,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Default Survey'),
'description' => 'Is this default survey?',
+ 'default' => '0',
'table_name' => 'civicrm_survey',
'entity' => 'Survey',
'bao' => 'CRM_Campaign_BAO_Survey',
@@ -412,6 +413,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('No Email Verification'),
'description' => 'Bypass the email verification.',
+ 'default' => '0',
'table_name' => 'civicrm_survey',
'entity' => 'Survey',
'bao' => 'CRM_Campaign_BAO_Survey',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/SurveyType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/SurveyType.php
index cad02eabe6b..0cce9e4b358 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/SurveyType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/SurveyType.php
@@ -156,9 +156,8 @@ public function postProcess() {
$params['filter'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'filter', 'id');
}
- $groupParams = array('name' => ($this->_gName));
$params['component_id'] = CRM_Core_Component::getComponentID('CiviCampaign');
- $optionValue = CRM_Core_OptionValue::addOptionValue($params, $groupParams, $this->_action, $this->_id);
+ $optionValue = CRM_Core_OptionValue::addOptionValue($params, $this->_gName, $this->_action, $this->_id);
CRM_Core_Session::setStatus(ts('The Survey type \'%1\' has been saved.', array(1 => $optionValue->label)), ts('Saved'), 'success');
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/Task.php
index 5d7bbd6a9bd..5ad1593f13d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Form/Task.php
@@ -34,35 +34,7 @@
/**
* This class generates form components for relationship.
*/
-class CRM_Campaign_Form_Task extends CRM_Core_Form {
-
- /**
- * The additional clause that we restrict the search.
- *
- * @var string
- */
- protected $_componentClause = NULL;
-
- /**
- * The task being performed
- *
- * @var int
- */
- protected $_task;
-
- /**
- * The array that holds all the contact ids
- *
- * @var array
- */
- public $_contactIds;
-
- /**
- * The array that holds all the component ids
- *
- * @var array
- */
- protected $_componentIds;
+class CRM_Campaign_Form_Task extends CRM_Core_Form_Task {
/**
* The array that holds all the voter ids
@@ -93,7 +65,7 @@ public function preProcess() {
else {
$qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
$cacheKey = "civicrm search {$qfKey}";
- $allCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey, "getall");
+ $allCids = Civi::service('prevnext')->getSelection($cacheKey, "getall");
$ids = array_keys($allCids[$cacheKey]);
$this->assign('totalSelectedVoters', count($ids));
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Selector/Search.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Selector/Search.php
index 6f7d3fccab9..28c2b15b6d7 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Selector/Search.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Campaign/Selector/Search.php
@@ -271,7 +271,7 @@ public function buildPrevNextCache($sort) {
if (!$crmPID) {
$cacheKey = "civicrm search {$this->_key}";
- CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey, 'civicrm_contact');
+ Civi::service('prevnext')->deleteItem(NULL, $cacheKey, 'civicrm_contact');
$sql = $this->_query->searchQuery(0, 0, $sort,
FALSE, FALSE,
@@ -281,18 +281,19 @@ public function buildPrevNextCache($sort) {
$this->_campaignFromClause
);
list($select, $from) = explode(' FROM ', $sql);
- $insertSQL = "
-INSERT INTO civicrm_prevnext_cache ( entity_table, entity_id1, entity_id2, cacheKey, data )
-SELECT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.display_name
+ $selectSQL = "
+ SELECT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.display_name
FROM {$from}
";
- $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
- $result = CRM_Core_DAO::executeQuery($insertSQL);
- unset($errorScope);
- if (is_a($result, 'DB_Error')) {
+ try {
+ Civi::service('prevnext')->fillWithSql($cacheKey, $selectSQL);
+ }
+ catch (CRM_Core_Exception $e) {
+ // Heavy handed, no? Seems like this merits an explanation.
return;
}
+
// also record an entry in the cache key table, so we can delete it periodically
CRM_Core_BAO_Cache::setItem($cacheKey, 'CiviCRM Search PrevNextCache', $cacheKey);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/Case.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/Case.php
index 8048c8ff75b..0d5f1d10c42 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/Case.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/Case.php
@@ -274,16 +274,16 @@ public static function enableDisableCaseRelationships($caseId, $enable) {
* ID of the case.
*
* @param int $contactID
+ * @param int $startArrayAt This is to support legacy calls to Case.Get API which may rely on the first array index being set to 1
*
* @return array
*/
- public static function retrieveContactIdsByCaseId($caseId, $contactID = NULL) {
+ public static function retrieveContactIdsByCaseId($caseId, $contactID = NULL, $startArrayAt = 0) {
$caseContact = new CRM_Case_DAO_CaseContact();
$caseContact->case_id = $caseId;
$caseContact->find();
$contactArray = array();
- // FIXME: Why does this return a 1-based array?
- $count = 1;
+ $count = $startArrayAt;
while ($caseContact->fetch()) {
if ($contactID != $caseContact->contact_id) {
$contactArray[$count] = $caseContact->contact_id;
@@ -684,7 +684,7 @@ public static function getCases($allCases = TRUE, $params = array(), $context =
$casesList[$key]['activity_list'] = sprintf('',
ts('Activities'),
- CRM_Utils_System::url('civicrm/case/details', array('caseid' => $case['case_id'], 'cid' => $case['contact_id'], 'type' => $type))
+ CRM_Utils_System::url('civicrm/case/details', array('caseId' => $case['case_id'], 'cid' => $case['contact_id'], 'type' => $type))
);
$phone = empty($case['phone']) ? '' : ' {$values['description']} " . CRM_Utils_Type::escape($name, 'String');
- exit();
+ throw new CRM_Core_Exception("PayPalIPN: Could not find an entry for $name");
}
return $value;
}
/**
- * @param $input
- * @param $ids
- * @param $objects
- * @param $first
+ * @param array $input
+ * @param array $ids
+ * @param array $objects
+ * @param bool $first
+ *
+ * @return void
*
- * @return bool
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
public function recur(&$input, &$ids, &$objects, $first) {
if (!isset($input['txnType'])) {
- CRM_Core_Error::debug_log_message("Could not find txn_type in input request");
+ Civi::log()->debug('PayPalIPN: Could not find txn_type in input request');
echo "Failure: Invalid parameters ";
- return FALSE;
+ return;
}
if ($input['txnType'] == 'subscr_payment' &&
$input['paymentStatus'] != 'Completed'
) {
- CRM_Core_Error::debug_log_message("Ignore all IPN payments that are not completed");
+ Civi::log()->debug('PayPalIPN: Ignore all IPN payments that are not completed');
echo "Failure: Invalid parameters ";
- return FALSE;
+ return;
}
$recur = &$objects['contributionRecur'];
@@ -110,9 +108,9 @@ public function recur(&$input, &$ids, &$objects, $first) {
// make sure the invoice ids match
// make sure the invoice is valid and matches what we have in the contribution record
if ($recur->invoice_id != $input['invoice']) {
- CRM_Core_Error::debug_log_message("Invoice values dont match between database and IPN request");
+ Civi::log()->debug('PayPalIPN: Invoice values dont match between database and IPN request (RecurID: ' . $recur->id . ').');
echo "Failure: Invoice values dont match between database and IPN request ";
- return FALSE;
+ return;
}
$now = date('YmdHis');
@@ -127,18 +125,19 @@ public function recur(&$input, &$ids, &$objects, $first) {
}
$sendNotification = FALSE;
$subscriptionPaymentStatus = NULL;
- //set transaction type
+ // set transaction type
$txnType = $this->retrieve('txn_type', 'String');
+ $contributionStatuses = array_flip(CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'validate'));
switch ($txnType) {
case 'subscr_signup':
$recur->create_date = $now;
- //some times subscr_signup response come after the
- //subscr_payment and set to pending mode.
+ // sometimes subscr_signup response come after the subscr_payment and set to pending mode.
+
$statusID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionRecur',
$recur->id, 'contribution_status_id'
);
- if ($statusID != 5) {
- $recur->contribution_status_id = 2;
+ if ($statusID != $contributionStatuses['In Progress']) {
+ $recur->contribution_status_id = $contributionStatuses['Pending'];
}
$recur->processor_id = $this->retrieve('subscr_id', 'String');
$recur->trxn_id = $recur->processor_id;
@@ -147,8 +146,8 @@ public function recur(&$input, &$ids, &$objects, $first) {
break;
case 'subscr_eot':
- if ($recur->contribution_status_id != 3) {
- $recur->contribution_status_id = 1;
+ if ($recur->contribution_status_id != $contributionStatuses['Cancelled']) {
+ $recur->contribution_status_id = $contributionStatuses['Completed'];
}
$recur->end_date = $now;
$sendNotification = TRUE;
@@ -156,19 +155,19 @@ public function recur(&$input, &$ids, &$objects, $first) {
break;
case 'subscr_cancel':
- $recur->contribution_status_id = 3;
+ $recur->contribution_status_id = $contributionStatuses['Cancelled'];
$recur->cancel_date = $now;
break;
case 'subscr_failed':
- $recur->contribution_status_id = 4;
+ $recur->contribution_status_id = $contributionStatuses['Failed'];
$recur->modified_date = $now;
break;
case 'subscr_modify':
- CRM_Core_Error::debug_log_message("We do not handle modifications to subscriptions right now");
+ Civi::log()->debug('PayPalIPN: We do not handle modifications to subscriptions right now (RecurID: ' . $recur->id . ').');
echo "Failure: We do not handle modifications to subscriptions right now ";
- return FALSE;
+ return;
case 'subscr_payment':
if ($first) {
@@ -180,8 +179,8 @@ public function recur(&$input, &$ids, &$objects, $first) {
// make sure the contribution status is not done
// since order of ipn's is unknown
- if ($recur->contribution_status_id != 1) {
- $recur->contribution_status_id = 5;
+ if ($recur->contribution_status_id != $contributionStatuses['Completed']) {
+ $recur->contribution_status_id = $contributionStatuses['In Progress'];
}
break;
}
@@ -189,7 +188,6 @@ public function recur(&$input, &$ids, &$objects, $first) {
$recur->save();
if ($sendNotification) {
-
$autoRenewMembership = FALSE;
if ($recur->id &&
isset($ids['membership']) && $ids['membership']
@@ -211,27 +209,28 @@ public function recur(&$input, &$ids, &$objects, $first) {
}
if (!$first) {
- //check if this contribution transaction is already processed
- //if not create a contribution and then get it processed
+ // check if this contribution transaction is already processed
+ // if not create a contribution and then get it processed
$contribution = new CRM_Contribute_BAO_Contribution();
$contribution->trxn_id = $input['trxn_id'];
if ($contribution->trxn_id && $contribution->find()) {
- CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
+ Civi::log()->debug('PayPalIPN: Returning since contribution has already been handled (trxn_id: ' . $contribution->trxn_id . ')');
echo "Success: Contribution has already been handled ";
- return TRUE;
+ return;
}
- $contribution->contact_id = $ids['contact'];
- $contribution->financial_type_id = $objects['contributionType']->id;
- $contribution->contribution_page_id = $ids['contributionPage'];
- $contribution->contribution_recur_id = $ids['contributionRecur'];
- $contribution->receive_date = $now;
- $contribution->currency = $objects['contribution']->currency;
- $contribution->payment_instrument_id = $objects['contribution']->payment_instrument_id;
- $contribution->amount_level = $objects['contribution']->amount_level;
- $contribution->campaign_id = $objects['contribution']->campaign_id;
-
- $objects['contribution'] = &$contribution;
+ if ($input['paymentStatus'] != 'Completed') {
+ throw new CRM_Core_Exception("Ignore all IPN payments that are not completed");
+ }
+
+ // In future moving to create pending & then complete, but this OK for now.
+ // Also consider accepting 'Failed' like other processors.
+ $input['contribution_status_id'] = $contributionStatuses['Completed'];
+ $input['original_contribution_id'] = $ids['contribution'];
+ $input['contribution_recur_id'] = $ids['contributionRecur'];
+
+ civicrm_api3('Contribution', 'repeattransaction', $input);
+ return;
}
$this->single($input, $ids, $objects,
@@ -240,27 +239,23 @@ public function recur(&$input, &$ids, &$objects, $first) {
}
/**
- * @param $input
- * @param $ids
- * @param $objects
+ * @param array $input
+ * @param array $ids
+ * @param array $objects
* @param bool $recur
* @param bool $first
*
- * @return bool
+ * @return void
*/
- public function single(
- &$input, &$ids, &$objects,
- $recur = FALSE,
- $first = FALSE
- ) {
+ public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE) {
$contribution = &$objects['contribution'];
// make sure the invoice is valid and matches what we have in the contribution record
if ((!$recur) || ($recur && $first)) {
if ($contribution->invoice_id != $input['invoice']) {
- CRM_Core_Error::debug_log_message("Invoice values dont match between database and IPN request");
+ Civi::log()->debug('PayPalIPN: Invoice values dont match between database and IPN request. (ID: ' . $contribution->id . ').');
echo "Failure: Invoice values dont match between database and IPN request ";
- return FALSE;
+ return;
}
}
else {
@@ -269,9 +264,9 @@ public function single(
if (!$recur) {
if ($contribution->total_amount != $input['amount']) {
- CRM_Core_Error::debug_log_message("Amount values dont match between database and IPN request");
+ Civi::log()->debug('PayPalIPN: Amount values dont match between database and IPN request. (ID: ' . $contribution->id . ').');
echo "Failure: Amount values dont match between database and IPN request ";
- return FALSE;
+ return;
}
}
else {
@@ -280,9 +275,6 @@ public function single(
$transaction = new CRM_Core_Transaction();
- $participant = &$objects['participant'];
- $membership = &$objects['membership'];
-
$status = $input['paymentStatus'];
if ($status == 'Denied' || $status == 'Failed' || $status == 'Voided') {
return $this->failed($objects, $transaction);
@@ -298,11 +290,12 @@ public function single(
}
// check if contribution is already completed, if so we ignore this ipn
- if ($contribution->contribution_status_id == 1) {
+ $completedStatusId = CRM_Core_Pseudoconstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
+ if ($contribution->contribution_status_id == $completedStatusId) {
$transaction->commit();
- CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
+ Civi::log()->debug('PayPalIPN: Returning since contribution has already been handled. (ID: ' . $contribution->id . ').');
echo "Success: Contribution has already been handled ";
- return TRUE;
+ return;
}
$this->completeTransaction($input, $ids, $objects, $transaction, $recur);
@@ -311,10 +304,10 @@ public function single(
/**
* Main function.
*
- * @return bool
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
public function main() {
-
$objects = $ids = $input = array();
$component = $this->retrieve('module', 'String');
$input['component'] = $component;
@@ -337,23 +330,12 @@ public function main() {
$ids['onbehalf_dupe_alert'] = $this->retrieve('onBehalfDupeAlert', 'Integer', FALSE);
}
- $paymentProcessorID = $this->retrieve('processor_id', 'Integer', FALSE);
- if (empty($paymentProcessorID)) {
- $processorParams = array(
- 'user_name' => $this->retrieve('business', 'String', FALSE),
- 'payment_processor_type_id' => CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType', 'PayPal_Standard', 'id', 'name'),
- 'is_test' => empty($input['is_test']) ? 0 : 1,
- );
+ $paymentProcessorID = self::getPayPalPaymentProcessorID($input, $ids);
- $processorInfo = array();
- if (!CRM_Financial_BAO_PaymentProcessor::retrieve($processorParams, $processorInfo)) {
- return FALSE;
- }
- $paymentProcessorID = $processorInfo['id'];
- }
+ Civi::log()->debug('PayPalIPN: Received (ContactID: ' . $ids['contact'] . '; trxn_id: ' . $input['trxn_id'] . ').');
if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
- return FALSE;
+ return;
}
self::$_paymentProcessor = &$objects['paymentProcessor'];
@@ -361,29 +343,26 @@ public function main() {
if ($ids['contributionRecur']) {
// check if first contribution is completed, else complete first contribution
$first = TRUE;
- if ($objects['contribution']->contribution_status_id == 1) {
+ $completedStatusId = CRM_Core_Pseudoconstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
+ if ($objects['contribution']->contribution_status_id == $completedStatusId) {
$first = FALSE;
}
- return $this->recur($input, $ids, $objects, $first);
+ $this->recur($input, $ids, $objects, $first);
+ return;
}
- else {
- return $this->single($input, $ids, $objects, FALSE, FALSE);
- }
- }
- else {
- return $this->single($input, $ids, $objects, FALSE, FALSE);
}
+ $this->single($input, $ids, $objects, FALSE, FALSE);
}
/**
- * @param $input
- * @param $ids
+ * @param array $input
+ * @param array $ids
*
- * @return bool
+ * @throws \CRM_Core_Exception
*/
public function getInput(&$input, &$ids) {
if (!$this->getBillingID($ids)) {
- return FALSE;
+ return;
}
$input['txnType'] = $this->retrieve('txn_type', 'String', FALSE);
@@ -411,6 +390,64 @@ public function getInput(&$input, &$ids) {
$input['fee_amount'] = $this->retrieve('mc_fee', 'Money', FALSE);
$input['net_amount'] = $this->retrieve('settle_amount', 'Money', FALSE);
$input['trxn_id'] = $this->retrieve('txn_id', 'String', FALSE);
+
+ $paymentDate = $this->retrieve('payment_date', 'String', FALSE);
+ if (!empty($paymentDate)) {
+ $receiveDateTime = new DateTime($paymentDate);
+ $input['receive_date'] = $receiveDateTime->format('YmdHis');
+ }
+ }
+
+
+ /**
+ * Gets PaymentProcessorID for PayPal
+ *
+ * @param array $input
+ * @param array $ids
+ *
+ * @return int
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
+ */
+ public function getPayPalPaymentProcessorID($input, $ids) {
+ // First we try and retrieve from POST params
+ $paymentProcessorID = $this->retrieve('processor_id', 'Integer', FALSE);
+ if (!empty($paymentProcessorID)) {
+ return $paymentProcessorID;
+ }
+
+ // Then we try and get it from recurring contribution ID
+ if (!empty($ids['contributionRecur'])) {
+ $contributionRecur = civicrm_api3('ContributionRecur', 'getsingle', array(
+ 'id' => $ids['contributionRecur'],
+ 'return' => ['payment_processor_id'],
+ ));
+ if (!empty($contributionRecur['payment_processor_id'])) {
+ return $contributionRecur['payment_processor_id'];
+ }
+ }
+
+ // This is an unreliable method as there could be more than one instance.
+ // Recommended approach is to use the civicrm/payment/ipn/xx url where xx is the payment
+ // processor id & the handleNotification function (which should call the completetransaction api & by-pass this
+ // entirely). The only thing the IPN class should really do is extract data from the request, validate it
+ // & call completetransaction or call fail? (which may not exist yet).
+
+ Civi::log()->warning('Unreliable method used to get payment_processor_id for PayPal IPN - this will cause problems if you have more than one instance');
+ // Then we try and retrieve based on business email ID
+ $paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType', 'PayPal_Standard', 'id', 'name');
+ $processorParams = [
+ 'user_name' => $this->retrieve('business', 'String', FALSE),
+ 'payment_processor_type_id' => $paymentProcessorTypeID,
+ 'is_test' => empty($input['is_test']) ? 0 : 1,
+ 'options' => ['limit' => 1],
+ 'return' => ['id'],
+ ];
+ $paymentProcessorID = civicrm_api3('PaymentProcessor', 'getvalue', $processorParams);
+ if (empty($paymentProcessorID)) {
+ Throw new CRM_Core_Exception('PayPalIPN: Could not get Payment Processor ID');
+ }
+ return $paymentProcessorID;
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalImpl.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalImpl.php
index 3fa00668924..8ab1bbec3a7 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalImpl.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalImpl.php
@@ -412,7 +412,6 @@ public function doExpressCheckout(&$params) {
*/
public function createRecurringPayments(&$params) {
$args = array();
- // @todo this function is riddled with enotices - perhaps use $this->mapPaypalParamsToCivicrmParams($fieldMap, $result)
$this->initialize($args, 'CreateRecurringPaymentsProfile');
$start_time = strtotime(date('m/d/Y'));
@@ -424,15 +423,12 @@ public function createRecurringPayments(&$params) {
$args['currencyCode'] = $params['currencyID'];
$args['payerID'] = $params['payer_id'];
$args['invnum'] = $params['invoiceID'];
- $args['returnURL'] = $params['returnURL'];
- $args['cancelURL'] = $params['cancelURL'];
$args['profilestartdate'] = $start_date;
$args['method'] = 'CreateRecurringPaymentsProfile';
$args['billingfrequency'] = $params['frequency_interval'];
$args['billingperiod'] = ucwords($params['frequency_unit']);
$args['desc'] = $params['amount'] . " Per " . $params['frequency_interval'] . " " . $params['frequency_unit'];
- //$args['desc'] = 'Recurring Contribution';
- $args['totalbillingcycles'] = $params['installments'];
+ $args['totalbillingcycles'] = CRM_Utils_Array::value('installments', $params);
$args['version'] = '56.0';
$args['profilereference'] = "i={$params['invoiceID']}" .
"&m=" .
@@ -450,16 +446,18 @@ public function createRecurringPayments(&$params) {
return $result;
}
- /* Success */
- $params['trxn_id'] = $result['transactionid'];
- $params['gross_amount'] = $result['amt'];
- $params['fee_amount'] = $result['feeamt'];
- $params['net_amount'] = $result['settleamt'];
- if ($params['net_amount'] == 0 && $params['fee_amount'] != 0) {
- $params['net_amount'] = number_format(($params['gross_amount'] - $params['fee_amount']), 2);
- }
- $params['payment_status'] = $result['paymentstatus'];
- $params['pending_reason'] = $result['pendingreason'];
+ /* Success - result looks like"
+ * array (
+ * 'profileid' => 'I-CP1U0PLG91R2',
+ * 'profilestatus' => 'ActiveProfile',
+ * 'timestamp' => '2018-05-07T03:55:52Z',
+ * 'correlationid' => 'e717999e9bf62',
+ * 'ack' => 'Success',
+ * 'version' => '56.0',
+ * 'build' => '39949200',)
+ */
+ $params['trxn_id'] = $result['profileid'];
+ $params['payment_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
return $params;
}
@@ -721,7 +719,7 @@ public function isSuppressSubmitButtons() {
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public function cancelSubscription(&$message = '', $params = array()) {
- if ($this->isPayPalType($this::PAYPAL_PRO)) {
+ if ($this->isPayPalType($this::PAYPAL_PRO) || $this->isPayPalType($this::PAYPAL_EXPRESS)) {
$args = array();
$this->initialize($args, 'ManageRecurringPaymentsProfileStatus');
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalProIPN.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalProIPN.php
index d230762395c..abbaece1970 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalProIPN.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalProIPN.php
@@ -161,13 +161,13 @@ public function retrieve($name, $type, $location = 'POST', $abort = TRUE) {
* @param array $ids
* @param array $objects
* @param bool $first
- * @return bool
+ * @return void
*/
public function recur(&$input, &$ids, &$objects, $first) {
if (!isset($input['txnType'])) {
- CRM_Core_Error::debug_log_message("Could not find txn_type in input request");
+ Civi::log()->debug('PayPalProIPN: Could not find txn_type in input request.');
echo "Failure: Invalid parameters ";
- return FALSE;
+ return;
}
$recur = &$objects['contributionRecur'];
@@ -176,9 +176,9 @@ public function recur(&$input, &$ids, &$objects, $first) {
// make sure the invoice is valid and matches what we have in
// the contribution record
if ($recur->invoice_id != $input['invoice']) {
- CRM_Core_Error::debug_log_message("Invoice values dont match between database and IPN request recur is " . $recur->invoice_id . " input is " . $input['invoice']);
+ Civi::log()->debug('PayPalProIPN: Invoice values dont match between database and IPN request recur is ' . $recur->invoice_id . ' input is ' . $input['invoice']);
echo "Failure: Invoice values dont match between database and IPN request recur is " . $recur->invoice_id . " input is " . $input['invoice'];
- return FALSE;
+ return;
}
$now = date('YmdHis');
@@ -211,21 +211,20 @@ public function recur(&$input, &$ids, &$objects, $first) {
//set transaction type
$txnType = $this->retrieve('txn_type', 'String');
//Changes for paypal pro recurring payment
- $contributionStatuses = civicrm_api3('contribution', 'getoptions', array('field' => 'contribution_status_id'));
- $contributionStatuses = $contributionStatuses['values'];
+ $contributionStatuses = array_flip(CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'validate'));
switch ($txnType) {
case 'recurring_payment_profile_created':
if (in_array($recur->contribution_status_id, array(
- array_search('Pending', $contributionStatuses),
- array_search('In Progress', $contributionStatuses),
+ $contributionStatuses['Pending'],
+ $contributionStatuses['In Progress'],
))
&& !empty($recur->processor_id)
) {
echo "already handled";
- return FALSE;
+ return;
}
$recur->create_date = $now;
- $recur->contribution_status_id = 2;
+ $recur->contribution_status_id = $contributionStatuses['Pending'];
$recur->processor_id = $this->retrieve('recurring_payment_id', 'String');
$recur->trxn_id = $recur->processor_id;
$subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_START;
@@ -237,16 +236,16 @@ public function recur(&$input, &$ids, &$objects, $first) {
$recur->start_date = $now;
}
else {
- $input['invoice_id'] = md5(uniqid(rand(), TRUE));
- $input['original_contribution_id'] = $ids['contribution'];
- $input['contribution_recur_id'] = $ids['contributionRecur'];
-
if ($input['paymentStatus'] != 'Completed') {
throw new CRM_Core_Exception("Ignore all IPN payments that are not completed");
}
+
// In future moving to create pending & then complete, but this OK for now.
// Also consider accepting 'Failed' like other processors.
- $input['contribution_status_id'] = 1;
+ $input['contribution_status_id'] = $contributionStatuses['Completed'];
+ $input['invoice_id'] = md5(uniqid(rand(), TRUE));
+ $input['original_contribution_id'] = $ids['contribution'];
+ $input['contribution_recur_id'] = $ids['contributionRecur'];
civicrm_api3('Contribution', 'repeattransaction', $input);
return;
@@ -256,9 +255,9 @@ public function recur(&$input, &$ids, &$objects, $first) {
if ($this->retrieve('profile_status', 'String') == 'Expired') {
if (!empty($recur->end_date)) {
echo "already handled";
- return FALSE;
+ return;
}
- $recur->contribution_status_id = 1;
+ $recur->contribution_status_id = $contributionStatuses['Completed'];
$recur->end_date = $now;
$sendNotification = TRUE;
$subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_END;
@@ -266,8 +265,8 @@ public function recur(&$input, &$ids, &$objects, $first) {
// make sure the contribution status is not done
// since order of ipn's is unknown
- if ($recur->contribution_status_id != 1) {
- $recur->contribution_status_id = 5;
+ if ($recur->contribution_status_id != $contributionStatuses['Completed']) {
+ $recur->contribution_status_id = $contributionStatuses['In Progress'];
}
break;
}
@@ -291,7 +290,7 @@ public function recur(&$input, &$ids, &$objects, $first) {
}
if ($txnType != 'recurring_payment') {
- return TRUE;
+ return;
}
if (!$first) {
@@ -300,9 +299,9 @@ public function recur(&$input, &$ids, &$objects, $first) {
$contribution = new CRM_Contribute_BAO_Contribution();
$contribution->trxn_id = $input['trxn_id'];
if ($contribution->trxn_id && $contribution->find()) {
- CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
+ Civi::log()->debug('PayPalProIPN: Returning since contribution has already been handled.');
echo "Success: Contribution has already been handled ";
- return TRUE;
+ return;
}
$contribution->contact_id = $recur->contact_id;
@@ -319,19 +318,17 @@ public function recur(&$input, &$ids, &$objects, $first) {
// CRM-13737 - am not aware of any reason why payment_date would not be set - this if is a belt & braces
$objects['contribution']->receive_date = !empty($input['payment_date']) ? date('YmdHis', strtotime($input['payment_date'])) : $now;
- $this->single($input, $ids, $objects,
- TRUE, $first
- );
+ $this->single($input, $ids, $objects, TRUE, $first);
}
/**
- * @param $input
- * @param $ids
- * @param $objects
+ * @param array $input
+ * @param array $ids
+ * @param array $objects
* @param bool $recur
* @param bool $first
*
- * @return bool
+ * @return void
*/
public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE) {
$contribution = &$objects['contribution'];
@@ -339,9 +336,9 @@ public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE
// make sure the invoice is valid and matches what we have in the contribution record
if ((!$recur) || ($recur && $first)) {
if ($contribution->invoice_id != $input['invoice']) {
- CRM_Core_Error::debug_log_message("Invoice values dont match between database and IPN request");
+ Civi::log()->debug('PayPalProIPN: Invoice values dont match between database and IPN request.');
echo "Failure: Invoice values dont match between database and IPN request contribution is" . $contribution->invoice_id . " and input is " . $input['invoice'];
- return FALSE;
+ return;
}
}
else {
@@ -350,9 +347,9 @@ public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE
if (!$recur) {
if ($contribution->total_amount != $input['amount']) {
- CRM_Core_Error::debug_log_message("Amount values dont match between database and IPN request");
+ Civi::log()->debug('PayPalProIPN: Amount values dont match between database and IPN request.');
echo "Failure: Amount values dont match between database and IPN request ";
- return FALSE;
+ return;
}
}
else {
@@ -363,24 +360,29 @@ public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE
$status = $input['paymentStatus'];
if ($status == 'Denied' || $status == 'Failed' || $status == 'Voided') {
- return $this->failed($objects, $transaction);
+ $this->failed($objects, $transaction);
+ return;
}
elseif ($status == 'Pending') {
- return $this->pending($objects, $transaction);
+ $this->pending($objects, $transaction);
+ return;
}
elseif ($status == 'Refunded' || $status == 'Reversed') {
- return $this->cancelled($objects, $transaction);
+ $this->cancelled($objects, $transaction);
+ return;
}
elseif ($status != 'Completed') {
- return $this->unhandled($objects, $transaction);
+ $this->unhandled($objects, $transaction);
+ return;
}
// check if contribution is already completed, if so we ignore this ipn
- if ($contribution->contribution_status_id == 1) {
+ $completedStatusId = CRM_Core_Pseudoconstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
+ if ($contribution->contribution_status_id == $completedStatusId) {
$transaction->commit();
- CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
+ Civi::log()->debug('PayPalProIPN: Returning since contribution has already been handled.');
echo "Success: Contribution has already been handled ";
- return TRUE;
+ return;
}
$this->completeTransaction($input, $ids, $objects, $transaction, $recur);
@@ -397,6 +399,9 @@ public function getPayPalPaymentProcessorID() {
// processor id & the handleNotification function (which should call the completetransaction api & by-pass this
// entirely). The only thing the IPN class should really do is extract data from the request, validate it
// & call completetransaction or call fail? (which may not exist yet).
+
+ Civi::log()->warning('Unreliable method used to get payment_processor_id for PayPal Pro IPN - this will cause problems if you have more than one instance');
+
$paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
'PayPal', 'id', 'name'
);
@@ -414,7 +419,7 @@ public function getPayPalPaymentProcessorID() {
* (with the input parameters) & call this & all will be done
*
* @todo the references to POST throughout this class need to be removed
- * @return bool
+ * @return void
*/
public function main() {
CRM_Core_Error::debug_var('GET', $_GET, TRUE, TRUE);
@@ -464,16 +469,10 @@ public function main() {
}
}
- // This is an unreliable method as there could be more than one instance.
- // Recommended approach is to use the civicrm/payment/ipn/xx url where xx is the payment
- // processor id & the handleNotification function (which should call the completetransaction api & by-pass this
- // entirely). The only thing the IPN class should really do is extract data from the request, validate it
- // & call completetransaction or call fail? (which may not exist yet).
-
$paymentProcessorID = self::getPayPalPaymentProcessorID();
if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
- return FALSE;
+ return;
}
self::$_paymentProcessor = &$objects['paymentProcessor'];
@@ -484,31 +483,27 @@ public function main() {
if ($ids['contributionRecur']) {
// check if first contribution is completed, else complete first contribution
$first = TRUE;
- if ($objects['contribution']->contribution_status_id == 1) {
+ $completedStatusId = CRM_Core_Pseudoconstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
+ if ($objects['contribution']->contribution_status_id == $completedStatusId) {
$first = FALSE;
}
- return $this->recur($input, $ids, $objects, $first);
- }
- else {
- return $this->single($input, $ids, $objects, FALSE, FALSE);
+ $this->recur($input, $ids, $objects, $first);
+ return;
}
}
- else {
- return $this->single($input, $ids, $objects, FALSE, FALSE);
- }
+ $this->single($input, $ids, $objects, FALSE, FALSE);
}
/**
- * @param $input
- * @param $ids
+ * @param array $input
+ * @param array $ids
*
- * @return bool
+ * @return void
* @throws CRM_Core_Exception
*/
public function getInput(&$input, &$ids) {
-
if (!$this->getBillingID($ids)) {
- return FALSE;
+ return;
}
$input['txnType'] = self::retrieve('txn_type', 'String', 'POST', FALSE);
@@ -542,6 +537,7 @@ public function getInput(&$input, &$ids) {
/**
* Handle payment express IPNs.
+ *
* For one off IPNS no actual response is required
* Recurring is more difficult as we have limited confirmation material
* lets look up invoice id in recur_contribution & rely on the unique transaction id to ensure no
@@ -560,27 +556,30 @@ public function handlePaymentExpress() {
// as membership id etc can be derived by the load objects fn
$objects = $ids = $input = array();
$isFirst = FALSE;
+ $input['invoice'] = self::getValue('i', FALSE);
$input['txnType'] = $this->retrieve('txn_type', 'String');
- if ($input['txnType'] != 'recurring_payment') {
+ $contributionRecur = civicrm_api3('contribution_recur', 'getsingle', array(
+ 'return' => 'contact_id, id, payment_processor_id',
+ 'invoice_id' => $input['invoice'],
+ ));
+
+ if ($input['txnType'] !== 'recurring_payment' && $input['txnType'] !== 'recurring_payment_profile_created') {
throw new CRM_Core_Exception('Paypal IPNS not handled other than recurring_payments');
}
- $input['invoice'] = self::getValue('i', FALSE);
+
$this->getInput($input, $ids);
- if ($this->transactionExists($input['trxn_id'])) {
+ if ($input['txnType'] === 'recurring_payment' && $this->transactionExists($input['trxn_id'])) {
throw new CRM_Core_Exception('This transaction has already been processed');
}
- $contributionRecur = civicrm_api3('contribution_recur', 'getsingle', array(
- 'return' => 'contact_id, id',
- 'invoice_id' => $input['invoice'],
- ));
$ids['contact'] = $contributionRecur['contact_id'];
$ids['contributionRecur'] = $contributionRecur['id'];
- $result = civicrm_api3('contribution', 'getsingle', array('invoice_id' => $input['invoice']));
+ $result = civicrm_api3('contribution', 'getsingle', ['invoice_id' => $input['invoice'], 'contribution_test' => '']);
$ids['contribution'] = $result['id'];
- //@todo hard - coding 'pending' for now
- if ($result['contribution_status_id'] == 2) {
+ //@todo hardcoding 'pending' for now
+ $pendingStatusId = CRM_Core_Pseudoconstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
+ if ($result['contribution_status_id'] == $pendingStatusId) {
$isFirst = TRUE;
}
// arg api won't get this - fix it
@@ -595,12 +594,12 @@ public function handlePaymentExpress() {
// membership would be an easy add - but not relevant to my customer...
$this->_component = $input['component'] = 'contribute';
$input['trxn_date'] = date('Y-m-d-H-i-s', strtotime(self::retrieve('time_created', 'String')));
- $paymentProcessorID = self::getPayPalPaymentProcessorID();
+ $paymentProcessorID = $contributionRecur['payment_processor_id'];
if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
throw new CRM_Core_Exception('Data did not validate');
}
- return $this->recur($input, $ids, $objects, $isFirst);
+ $this->recur($input, $ids, $objects, $isFirst);
}
/**
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayflowPro.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayflowPro.php
index 2fcdf724084..2020b2a8cd8 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayflowPro.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayflowPro.php
@@ -567,85 +567,4 @@ public function submit_transaction($submiturl, $payflow_query) {
return $responseData;
}
- /**
- * @param int $recurringProfileID
- * @param int $processorID
- *
- * @throws Exception
- */
- public function getRecurringTransactionStatus($recurringProfileID, $processorID) {
- if (!defined('CURLOPT_SSLCERT')) {
- CRM_Core_Error::fatal(ts('Payflow Pro requires curl with SSL support'));
- }
-
- /*
- * define variables for connecting with the gateway
- */
-
- //if you have not set up a separate user account the vendor name is used as the username
- if (!$this->_paymentProcessor['subject']) {
- $user = $this->_paymentProcessor['user_name'];
- }
- else {
- $user = $this->_paymentProcessor['subject'];
- }
- //$recurringProfileID = "RT0000000001";
- // c $trythis = $this->getRecurringTransactionStatus($recurringProfileID,17);
-
- /*
- *Create the array of variables to be sent to the processor from the $params array
- * passed into this function
- *
- */
-
- $payflow_query_array = array(
- 'USER' => $user,
- 'VENDOR' => $this->_paymentProcessor['user_name'],
- 'PARTNER' => $this->_paymentProcessor['signature'],
- 'PWD' => $this->_paymentProcessor['password'],
- // C - Direct Payment using credit card
- 'TENDER' => 'C',
- // A - Authorization, S - Sale
- 'TRXTYPE' => 'R',
- 'ACTION' => 'I',
- //A for add recurring
- //(M-modify,C-cancel,R-reactivate,
- //I-inquiry,P-payment
- 'ORIGPROFILEID' => $recurringProfileID,
- 'PAYMENTHISTORY' => 'Y',
- );
-
- $payflow_query = $this->convert_to_nvp($payflow_query_array);
- echo $payflow_query;
- $submiturl = $this->_paymentProcessor['url_site'];
- //ie. url at payment processor to submit to.
- $responseData = self::submit_transaction($submiturl, $payflow_query);
- /*
- * Payment successfully sent to gateway - process the response now
- */
-
- $result = strstr($responseData, "RESULT");
- $nvpArray = array();
- while (strlen($result)) {
- // name
- $keypos = strpos($result, '=');
- $keyval = substr($result, 0, $keypos);
- // value
- $valuepos = strpos($result, '&') ? strpos($result, '&') : strlen($result);
- $valval = substr($result, $keypos + 1, $valuepos - $keypos - 1);
- // decoding the respose
- $nvpArray[$keyval] = $valval;
- $result = substr($result, $valuepos + 1, strlen($result));
- }
-
- // @TODO Function is named getRecurringTransactionStatus() which
- // suggests it returns a result. It sets a $result_code but doesn't return
- // it, printing output instead?
- $result_code = $nvpArray['RESULT'];
- print_r($responseData);
-
- //RESPMSG=Invalid Profile ID: Invalid recurring profile ID
- //RT0000000001
- }
-
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Permission.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Permission.php
index ee7b49f69d6..a532a4a2c4d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Permission.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Permission.php
@@ -761,6 +761,14 @@ public static function getCorePermissions() {
'delete activities' => array(
$prefix . ts('Delete activities'),
),
+ 'edit inbound email basic information' => array(
+ $prefix . ts('edit inbound email basic information'),
+ ts('Edit all inbound email activities (for visible contacts) basic information. Content editing not allowed.'),
+ ),
+ 'edit inbound email basic information and content' => array(
+ $prefix . ts('edit inbound email basic information and content'),
+ ts('Edit all inbound email activities (for visible contacts) basic information and content.'),
+ ),
'access CiviCRM' => array(
$prefix . ts('access CiviCRM backend and API'),
ts('Master control for access to the main CiviCRM backend and API. Give to trusted roles only.'),
@@ -1465,11 +1473,18 @@ public static function getEntityActionPermissions() {
$permissions['option_value'] = $permissions['uf_group'];
$permissions['option_group'] = $permissions['option_value'];
+ $permissions['custom_value'] = array(
+ 'gettree' => array('access CiviCRM'),
+ );
+
$permissions['message_template'] = array(
'get' => array('access CiviCRM'),
'create' => array('edit message templates', 'edit user-driven message templates', 'edit system workflow message templates'),
'update' => array('edit message templates', 'edit user-driven message templates', 'edit system workflow message templates'),
);
+
+ $permissions['report_template']['update'] = 'save Report Criteria';
+ $permissions['report_template']['create'] = 'save Report Criteria';
return $permissions;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PrevNextCache/Interface.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PrevNextCache/Interface.php
new file mode 100644
index 00000000000..c71b57ed24f
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PrevNextCache/Interface.php
@@ -0,0 +1,115 @@
+message);
+ }
+ return TRUE;
+ }
+
+ public function fillWithArray($cacheKey, $rows) {
+ if (empty($rows)) {
+ return;
+ }
+
+ $insert = CRM_Utils_SQL_Insert::into('civicrm_prevnext_cache')
+ ->columns([
+ 'entity_table',
+ 'entity_id1',
+ 'entity_id2',
+ 'cacheKey',
+ 'data'
+ ]);
+
+ foreach ($rows as &$row) {
+ $insert->row($row + ['cacheKey' => $cacheKey]);
+ }
+
+ CRM_Core_DAO::executeQuery($insert->toSQL());
+ return TRUE;
+ }
+
+ /**
+ * Save checkbox selections.
+ *
+ * @param string $cacheKey
+ * @param string $action
+ * Ex: 'select', 'unselect'.
+ * @param array|int|NULL $cIds
+ * A list of contact IDs to (un)select.
+ * To unselect all contact IDs, use NULL.
+ */
+ public function markSelection($cacheKey, $action, $cIds = NULL) {
+ $entity_table = 'civicrm_contact';
+
+ if (!$cacheKey) {
+ return;
+ }
+ $params = array();
+
+ $entity_whereClause = " AND entity_table = '{$entity_table}'";
+ if ($cIds && $cacheKey && $action) {
+ if (is_array($cIds)) {
+ $cIdFilter = "(" . implode(',', $cIds) . ")";
+ $whereClause = "
+WHERE cacheKey LIKE %1
+AND (entity_id1 IN {$cIdFilter} OR entity_id2 IN {$cIdFilter})
+";
+ }
+ else {
+ $whereClause = "
+WHERE cacheKey LIKE %1
+AND (entity_id1 = %2 OR entity_id2 = %2)
+";
+ $params[2] = array("{$cIds}", 'Integer');
+ }
+ if ($action == 'select') {
+ $whereClause .= "AND is_selected = 0";
+ $sql = "UPDATE civicrm_prevnext_cache SET is_selected = 1 {$whereClause} {$entity_whereClause}";
+ $params[1] = array("{$cacheKey}%", 'String');
+ }
+ elseif ($action == 'unselect') {
+ $whereClause .= "AND is_selected = 1";
+ $sql = "UPDATE civicrm_prevnext_cache SET is_selected = 0 {$whereClause} {$entity_whereClause}";
+ $params[1] = array("%{$cacheKey}%", 'String');
+ }
+ // default action is reseting
+ }
+ elseif (!$cIds && $cacheKey && $action == 'unselect') {
+ $sql = "
+UPDATE civicrm_prevnext_cache
+SET is_selected = 0
+WHERE cacheKey LIKE %1 AND is_selected = 1
+ {$entity_whereClause}
+";
+ $params[1] = array("{$cacheKey}%", 'String');
+ }
+ CRM_Core_DAO::executeQuery($sql, $params);
+ }
+
+ /**
+ * Get the selections.
+ *
+ * @param string $cacheKey
+ * Cache key.
+ * @param string $action
+ * One of the following:
+ * - 'get' - get only selection records
+ * - 'getall' - get all the records of the specified cache key
+ *
+ * @return array|NULL
+ */
+ public function getSelection($cacheKey, $action = 'get') {
+ $entity_table = 'civicrm_contact';
+
+ if (!$cacheKey) {
+ return NULL;
+ }
+ $params = array();
+
+ $entity_whereClause = " AND entity_table = '{$entity_table}'";
+ if ($cacheKey && ($action == 'get' || $action == 'getall')) {
+ $actionGet = ($action == "get") ? " AND is_selected = 1 " : "";
+ $sql = "
+SELECT entity_id1, entity_id2 FROM civicrm_prevnext_cache
+WHERE cacheKey LIKE %1
+ $actionGet
+ $entity_whereClause
+ORDER BY id
+";
+ $params[1] = array("{$cacheKey}%", 'String');
+
+ $contactIds = array($cacheKey => array());
+ $cIdDao = CRM_Core_DAO::executeQuery($sql, $params);
+ while ($cIdDao->fetch()) {
+ if ($cIdDao->entity_id1 == $cIdDao->entity_id2) {
+ $contactIds[$cacheKey][$cIdDao->entity_id1] = 1;
+ }
+ }
+ return $contactIds;
+ }
+ }
+
+ /**
+ * Get the previous and next keys.
+ *
+ * @param string $cacheKey
+ * @param int $id1
+ * @param int $id2
+ *
+ * NOTE: I don't really get why there are two ID columns, but we'll
+ * keep passing them through as a matter of safe-refactoring.
+ *
+ * @return array
+ */
+ public function getPositions($cacheKey, $id1, $id2) {
+ return CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, $id1, $id2);
+ }
+
+ /**
+ * Delete an item from the prevnext cache table based on the entity.
+ *
+ * @param int $id
+ * @param string $cacheKey
+ * @param string $entityTable
+ */
+ public function deleteItem($id = NULL, $cacheKey = NULL, $entityTable = 'civicrm_contact') {
+ CRM_Core_BAO_PrevNextCache::deleteItem($id, $cacheKey, $entityTable);
+ }
+
+ /**
+ * Get count of matching rows.
+ *
+ * @param string $cacheKey
+ * @return int
+ */
+ public function getCount($cacheKey) {
+ return CRM_Core_BAO_PrevNextCache::getCount($cacheKey, NULL, "entity_table = 'civicrm_contact'");
+ }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PseudoConstant.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PseudoConstant.php
index 81bdb6f232e..5cef5e081eb 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PseudoConstant.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/PseudoConstant.php
@@ -170,7 +170,7 @@ class CRM_Core_PseudoConstant {
/**
* Low-level option getter, rarely accessed directly.
* NOTE: Rather than calling this function directly use CRM_*_BAO_*::buildOptions()
- * @see http://wiki.civicrm.org/confluence/display/CRMDOC/Pseudoconstant+%28option+list%29+Reference
+ * @see https://docs.civicrm.org/dev/en/latest/framework/pseudoconstant/
*
* NOTE: If someone undertakes a refactoring of this, please consider the use-case of
* the Setting.getoptions API. There is no DAO/field, but it would be nice to use the
@@ -536,7 +536,7 @@ public static function populate(
$key = 'id',
$force = NULL
) {
- $cacheKey = "CRM_PC_{$name}_{$all}_{$key}_{$retrieve}_{$filter}_{$condition}_{$orderby}";
+ $cacheKey = CRM_Core_BAO_Cache::cleanKey("CRM_PC_{$name}_{$all}_{$key}_{$retrieve}_{$filter}_{$condition}_{$orderby}");
$cache = CRM_Utils_Cache::singleton();
$var = $cache->get($cacheKey);
if ($var && empty($force)) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/SelectValues.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/SelectValues.php
index 6f4ed3c8b41..3d429fa36e6 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/SelectValues.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/SelectValues.php
@@ -1096,4 +1096,17 @@ public static function activityTextOptions() {
);
}
+ /**
+ * Relationship permissions
+ *
+ * @return array
+ */
+ public static function getPermissionedRelationshipOptions() {
+ return array(
+ CRM_Contact_BAO_Relationship::NONE => ts('None'),
+ CRM_Contact_BAO_Relationship::VIEW => ts('View only'),
+ CRM_Contact_BAO_Relationship::EDIT => ts('View and update'),
+ );
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Session.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Session.php
index 7c1c1a42a1a..632a9e14ab9 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Session.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Session.php
@@ -286,7 +286,7 @@ public function getVars(&$vars, $prefix = '') {
$values = &$this->_session[$this->_key];
}
else {
- $values = CRM_Core_BAO_Cache::getItem('CiviCRM Session', "CiviCRM_{$prefix}");
+ $values = Civi::cache('session')->get("CiviCRM_{$prefix}");
}
if ($values) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Smarty/plugins/function.help.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Smarty/plugins/function.help.php
index c4e4836c981..f768965f61a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Smarty/plugins/function.help.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Smarty/plugins/function.help.php
@@ -92,5 +92,5 @@ function smarty_function_help($params, &$smarty) {
foreach ($params as &$param) {
$param = is_bool($param) || is_numeric($param) ? (int) $param : (string) $param;
}
- return ' ';
+ return ' ';
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Field.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Field.php
index 5326a2ff108..518bd0d7b4e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Field.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Field.php
@@ -315,24 +315,33 @@ public function buildQuickForm() {
$this->add('checkbox', 'in_selector', ts('Display in Table?'));
}
+ $optionGroupParams = [
+ 'is_reserved' => 0,
+ 'is_active' => 1,
+ 'options' => ['limit' => 0, 'sort' => "title ASC"],
+ 'return' => ['title'],
+ ];
+
if ($this->_action == CRM_Core_Action::UPDATE) {
$this->freeze('data_type');
+ if (!empty($this->_values['option_group_id'])) {
+ // Before dev/core#155 we didn't set the is_reserved flag properly, which should be handled by the upgrade script...
+ // but it is still possible that existing installs may have optiongroups linked to custom fields that are marked reserved.
+ $optionGroupParams['id'] = $this->_values['option_group_id'];
+ $optionGroupParams['options']['or'] = [["is_reserved", "id"]];
+ }
}
- $includeFieldIds = NULL;
- if ($this->_action == CRM_Core_Action::UPDATE) {
- $includeFieldIds = $this->_values['id'];
- }
- $optionGroups = CRM_Core_BAO_CustomField::customOptionGroup($includeFieldIds);
- $emptyOptGroup = FALSE;
- if (empty($optionGroups)) {
- $emptyOptGroup = TRUE;
- $optionTypes = array('1' => ts('Create a new set of options'));
- }
- else {
- $optionTypes = array(
- '1' => ts('Create a new set of options'),
- '2' => ts('Reuse an existing set'),
- );
+
+ // Retrieve optiongroups for selection list
+ $optionGroupMetadata = civicrm_api3('OptionGroup', 'get', $optionGroupParams);
+
+ // OptionGroup selection
+ $optionTypes = array('1' => ts('Create a new set of options'));
+
+ if (!empty($optionGroupMetadata['values'])) {
+ $emptyOptGroup = FALSE;
+ $optionGroups = CRM_Utils_Array::collect('title', $optionGroupMetadata['values']);
+ $optionTypes['2'] = ts('Reuse an existing set');
$this->add('select',
'option_group_id',
@@ -342,6 +351,10 @@ public function buildQuickForm() {
) + $optionGroups
);
}
+ else {
+ // No custom (non-reserved) option groups
+ $emptyOptGroup = TRUE;
+ }
$element = &$this->addRadio('option_type',
ts('Option Type'),
@@ -350,6 +363,10 @@ public function buildQuickForm() {
'onclick' => "showOptionSelect();",
), '
' . $case['phone'] . '';
@@ -725,7 +725,7 @@ public static function getCases($allCases = TRUE, $params = array(), $context =
}
if (self::checkPermission($actId, 'edit', $case['activity_type_id'], $userID)) {
$casesList[$key]['date'] .= sprintf('',
- CRM_Utils_System::url('civicrm/case/activity', array('reset' => 1, 'cid' => $case['contact_id'], 'caseid' => $case['case_id'], 'action' => 'update')),
+ CRM_Utils_System::url('civicrm/case/activity', array('reset' => 1, 'cid' => $case['contact_id'], 'caseid' => $case['case_id'], 'action' => 'update', 'id' => $actId)),
ts('Edit activity')
);
}
@@ -840,12 +840,13 @@ public static function getCasesSummary($allCases = TRUE) {
* @param int $caseID
* Case id.
* @param int $relationshipID
+ * @param bool $activeOnly
*
* @return array
* case role / relationships
*
*/
- public static function getCaseRoles($contactID, $caseID, $relationshipID = NULL) {
+ public static function getCaseRoles($contactID, $caseID, $relationshipID = NULL, $activeOnly = TRUE) {
$query = '
SELECT rel.id as civicrm_relationship_id,
con.sort_name as sort_name,
@@ -861,7 +862,11 @@ public static function getCaseRoles($contactID, $caseID, $relationshipID = NULL)
LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = con.id AND civicrm_phone.is_primary = 1)
LEFT JOIN civicrm_email ON (civicrm_email.contact_id = con.id AND civicrm_email.is_primary = 1)
WHERE (rel.contact_id_a = %1 OR rel.contact_id_b = %1) AND rel.case_id = %2
- AND rel.is_active = 1 AND con.is_deleted = 0 AND (rel.end_date IS NULL OR rel.end_date > NOW())';
+ AND con.is_deleted = 0';
+
+ if ($activeOnly) {
+ $query .= ' AND rel.is_active = 1 AND (rel.end_date IS NULL OR rel.end_date > NOW())';
+ }
$params = array(
1 => array($contactID, 'Positive'),
@@ -1085,7 +1090,6 @@ public static function getCaseActivity($caseID, &$params, $contactID, $context =
$contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", "reset=1&cid=", FALSE, NULL, FALSE);
$hasViewContact = CRM_Core_Permission::giveMeAllACLs();
- $clientIds = self::retrieveContactIdsByCaseId($caseID);
if (!$userID) {
$session = CRM_Core_Session::singleton();
@@ -1586,7 +1590,7 @@ public static function getNextScheduledActivity($cases, $type = 'upcoming') {
AND civicrm_case.id IN( {$caseID})
AND civicrm_case.is_deleted = {$cases['case_deleted']}";
- $query = self::getCaseActivityQuery($type, $userID, $condition, $cases['case_deleted']);
+ $query = self::getCaseActivityQuery($type, $userID, $condition);
$res = CRM_Core_DAO::executeQuery($query);
@@ -2741,6 +2745,12 @@ public static function checkPermission($activityId, $operation, $actTypeId = NUL
//allow edit operation.
$allowEditNames = array('Open Case');
+ if (CRM_Core_Permission::check('edit inbound email basic information') ||
+ CRM_Core_Permission::check('edit inbound email basic information and content')
+ ) {
+ $allowEditNames[] = 'Inbound Email';
+ }
+
// do not allow File on Case
$doNotFileNames = array(
'Open Case',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/CaseType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/CaseType.php
index 42cc1baedde..89baec6098e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/CaseType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/BAO/CaseType.php
@@ -242,6 +242,8 @@ public static function convertXmlToDefinition($xml) {
// set activity sets
if (isset($xml->ActivitySets)) {
$definition['activitySets'] = array();
+ $definition['timelineActivityTypes'] = array();
+
foreach ($xml->ActivitySets->ActivitySet as $activitySetXML) {
// parse basic properties
$activitySet = array();
@@ -257,7 +259,11 @@ public static function convertXmlToDefinition($xml) {
if (isset($activitySetXML->ActivityTypes)) {
$activitySet['activityTypes'] = array();
foreach ($activitySetXML->ActivityTypes->ActivityType as $activityTypeXML) {
- $activitySet['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE);
+ $activityType = json_decode(json_encode($activityTypeXML), TRUE);
+ $activitySet['activityTypes'][] = $activityType;
+ if ($activitySetXML->timeline) {
+ $definition['timelineActivityTypes'][] = $activityType;
+ }
}
}
$definition['activitySets'][] = $activitySet;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/DAO/Case.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/DAO/Case.php
index 514544ec04c..b881d040064 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/DAO/Case.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/DAO/Case.php
@@ -271,6 +271,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_case',
'entity' => 'Case',
'bao' => 'CRM_Case_BAO_Case',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Activity/ChangeCaseStatus.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Activity/ChangeCaseStatus.php
index c00901c9abc..3452a51ea79 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Activity/ChangeCaseStatus.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Activity/ChangeCaseStatus.php
@@ -194,7 +194,7 @@ public static function endPostProcess(&$form, &$params, $activity) {
// Reopen case-specific relationships (roles)
foreach ($params['target_contact_id'] as $cid) {
- $rels = CRM_Case_BAO_Case::getCaseRoles($cid, $params['case_id']);
+ $rels = CRM_Case_BAO_Case::getCaseRoles($cid, $params['case_id'], NULL, FALSE);
// FIXME: Is there an existing function?
$query = 'UPDATE civicrm_relationship SET end_date=NULL WHERE id=%1';
foreach ($rels as $relId => $relData) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/ActivityView.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/ActivityView.php
index e18b086d190..16247cda225 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/ActivityView.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/ActivityView.php
@@ -172,6 +172,38 @@ public function preProcess() {
$recentContactDisplay,
$recentOther
);
+
+ // Set breadcrumb to take the user back to the case being viewed
+ $caseTypeId = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'case_type_id');
+ $caseType = CRM_Core_PseudoConstant::getLabel('CRM_Case_BAO_Case', 'case_type_id', $caseTypeId);
+ $caseContact = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseContact', $caseID, 'contact_id', 'case_id');
+
+ CRM_Utils_System::resetBreadCrumb();
+ $breadcrumb = [
+ [
+ 'title' => ts('Home'),
+ 'url' => CRM_Utils_System::url(),
+ ],
+ [
+ 'title' => ts('CiviCRM'),
+ 'url' => CRM_Utils_System::url('civicrm', 'reset=1'),
+ ],
+ [
+ 'title' => ts('CiviCase Dashboard'),
+ 'url' => CRM_Utils_System::url('civicrm/case', 'reset=1'),
+ ],
+ [
+ 'title' => $caseType,
+ 'url' => CRM_Utils_System::url('civicrm/contact/view/case', [
+ 'reset' => 1,
+ 'id' => $caseID,
+ 'context' => 'case',
+ 'action' => 'view',
+ 'cid' => $caseContact,
+ ]),
+ ],
+ ];
+ CRM_Utils_System::appendBreadCrumb($breadcrumb);
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Task.php
index b9d05e68758..513ee62e050 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Form/Task.php
@@ -49,4 +49,13 @@ public function setContactIDs() {
);
}
+ /**
+ * Get the query mode (eg. CRM_Core_BAO_Query::MODE_CASE)
+ *
+ * @return int
+ */
+ public function getQueryMode() {
+ return CRM_Contact_BAO_Query::MODE_CASE;
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Task.php
index 956ff16662e..954786cde55 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/Task.php
@@ -67,7 +67,7 @@ public static function tasks() {
self::TASK_EXPORT => array(
'title' => ts('Export cases'),
'class' => array(
- 'CRM_Export_Form_Select',
+ 'CRM_Export_Form_Select_Case',
'CRM_Export_Form_Map',
),
'result' => FALSE,
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/XMLProcessor/Process.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/XMLProcessor/Process.php
index f125355ec93..1929c38fb72 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/XMLProcessor/Process.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Case/XMLProcessor/Process.php
@@ -31,6 +31,8 @@
* @copyright CiviCRM LLC (c) 2004-2018
*/
class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
+ protected $defaultAssigneeOptionsValues = [];
+
/**
* Run.
*
@@ -314,6 +316,7 @@ public function activityTypes($activityTypesXML, $maxInst = FALSE, $isLabel = FA
/**
* @param SimpleXMLElement $caseTypeXML
+ *
* @return array";
print "$sql;";
@@ -197,7 +200,7 @@ public function from() {
$endDateFix = "AND date_added <= '" . substr($endDate, 0, 10) . " 23:59:00'";
}
- $dateRange = "INSERT INTO dates_{$this->_tableName} ( id, date_added )
+ $dateRange = "INSERT INTO {$this->_datesTable} ( id, date_added )
SELECT
civicrm_contact.id,
min(civicrm_log.modified_date) AS date_added
@@ -249,16 +252,16 @@ public function from() {
$xGroups = 0;
}
- $sql = "DROP TEMPORARY TABLE IF EXISTS Xg_{$this->_tableName}";
+ $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_xgTable}";
CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
- $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP";
+ $sql = "CREATE TEMPORARY TABLE {$this->_xgTable} ( contact_id int primary key) ENGINE=HEAP";
CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
//used only when exclude group is selected
if ($xGroups != 0) {
- $excludeGroup = "INSERT INTO Xg_{$this->_tableName} ( contact_id )
+ $excludeGroup = "INSERT INTO {$this->_xgTable} ( contact_id )
SELECT DISTINCT civicrm_group_contact.contact_id
- FROM civicrm_group_contact, dates_{$this->_tableName} AS d
+ FROM civicrm_group_contact, {$this->_datesTable} AS d
WHERE
d.id = civicrm_group_contact.contact_id AND
civicrm_group_contact.status = 'Added' AND
@@ -277,16 +280,16 @@ public function from() {
SELECT contact_id FROM civicrm_group_contact
WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')";
- $smartGroupQuery = " INSERT IGNORE INTO Xg_{$this->_tableName}(contact_id) $smartSql";
+ $smartGroupQuery = " INSERT IGNORE INTO {$this->_xgTable}(contact_id) $smartSql";
CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray);
}
}
}
- $sql = "DROP TEMPORARY TABLE IF EXISTS Ig_{$this->_tableName}";
+ $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_igTable}";
CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
- $sql = "CREATE TEMPORARY TABLE Ig_{$this->_tableName}
+ $sql = "CREATE TEMPORARY TABLE {$this->_igTable}
( id int PRIMARY KEY AUTO_INCREMENT,
contact_id int,
group_names varchar(64)) ENGINE=HEAP";
@@ -299,9 +302,9 @@ public function from() {
CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
- $includeGroup = "INSERT INTO Ig_{$this->_tableName} (contact_id, group_names)
+ $includeGroup = "INSERT INTO {$this->_igTable} (contact_id, group_names)
SELECT d.id as contact_id, civicrm_group.name as group_name
- FROM dates_{$this->_tableName} AS d
+ FROM {$this->_datesTable} AS d
INNER JOIN civicrm_group_contact
ON civicrm_group_contact.contact_id = d.id
LEFT JOIN civicrm_group
@@ -309,8 +312,8 @@ public function from() {
//used only when exclude group is selected
if ($xGroups != 0) {
- $includeGroup .= " LEFT JOIN Xg_{$this->_tableName}
- ON d.id = Xg_{$this->_tableName}.contact_id";
+ $includeGroup .= " LEFT JOIN {$this->_xgTable}
+ ON d.id = {$this->_xgTable}.contact_id";
}
$includeGroup .= " WHERE
civicrm_group_contact.status = 'Added' AND
@@ -318,7 +321,7 @@ public function from() {
//used only when exclude group is selected
if ($xGroups != 0) {
- $includeGroup .= " AND Xg_{$this->_tableName}.contact_id IS null";
+ $includeGroup .= " AND {$this->_xgTable}.contact_id IS null";
}
if ($this->_debug > 0) {
@@ -339,7 +342,7 @@ public function from() {
$smartSql .= " AND contact_a.id IN (
SELECT id AS contact_id
- FROM dates_{$this->_tableName} )";
+ FROM {$this->_datesTable} )";
$smartSql .= " AND contact_a.id NOT IN (
SELECT contact_id FROM civicrm_group_contact
@@ -347,11 +350,11 @@ public function from() {
//used only when exclude group is selected
if ($xGroups != 0) {
- $smartSql .= " AND contact_a.id NOT IN (SELECT contact_id FROM Xg_{$this->_tableName})";
+ $smartSql .= " AND contact_a.id NOT IN (SELECT contact_id FROM {$this->_xgTable})";
}
$smartGroupQuery = " INSERT IGNORE INTO
- Ig_{$this->_tableName}(contact_id)
+ {$this->_igTable}(contact_id)
$smartSql";
CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray);
@@ -360,11 +363,11 @@ public function from() {
print "$smartGroupQuery;";
print "
";
}
- $insertGroupNameQuery = "UPDATE IGNORE Ig_{$this->_tableName}
+ $insertGroupNameQuery = "UPDATE IGNORE {$this->_igTable}
SET group_names = (SELECT title FROM civicrm_group
WHERE civicrm_group.id = $values)
- WHERE Ig_{$this->_tableName}.contact_id IS NOT NULL
- AND Ig_{$this->_tableName}.group_names IS NULL";
+ WHERE {$this->_igTable}.contact_id IS NOT NULL
+ AND {$this->_igTable}.group_names IS NULL";
CRM_Core_DAO::executeQuery($insertGroupNameQuery, CRM_Core_DAO::$_nullArray);
if ($this->_debug > 0) {
print "-- Smart group query: ";
@@ -380,12 +383,12 @@ public function from() {
/* We need to join to this again to get the date_added value */
- $from .= " INNER JOIN dates_{$this->_tableName} d ON (contact_a.id = d.id) {$this->_aclFrom}";
+ $from .= " INNER JOIN {$this->_datesTable} d ON (contact_a.id = d.id) {$this->_aclFrom}";
// Only include groups in the search query of one or more Include OR Exclude groups has been selected.
// CRM-6356
if ($this->_groups) {
- $from .= " INNER JOIN Ig_{$this->_tableName} temptable1 ON (contact_a.id = temptable1.contact_id)";
+ $from .= " INNER JOIN {$this->_igTable} temptable1 ON (contact_a.id = temptable1.contact_id)";
}
return $from;
@@ -437,13 +440,13 @@ public function count() {
public function __destruct() {
//drop the temp. tables if they exist
- if (!empty($this->_includeGroups)) {
- $sql = "DROP TEMPORARY TABLE IF EXISTS Ig_{$this->_tableName}";
+ if ($this->_igTable && !empty($this->_includeGroups)) {
+ $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_igTable}";
CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
}
- if (!empty($this->_excludeGroups)) {
- $sql = "DROP TEMPORARY TABLE IF EXISTS Xg_{$this->_tableName}";
+ if ($this->_xgTable && !empty($this->_excludeGroups)) {
+ $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_xgTable}";
CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Search/Custom/MultipleValues.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Search/Custom/MultipleValues.php
index acc1bd580f8..31b9cebbc55 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Search/Custom/MultipleValues.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Search/Custom/MultipleValues.php
@@ -246,7 +246,7 @@ public function where($includeContactIDs = FALSE) {
$this->_formValues
);
if ($contact_type != NULL) {
- $contactType = explode('__', $contact_type);
+ $contactType = explode('__', $contact_type, 2);
if (count($contactType) > 1) {
$clause[] = "contact_a.contact_type = '$contactType[0]' AND contact_a.contact_sub_type = '$contactType[1]'";
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Task.php
index 5136641e3b7..369d5945136 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Form/Task.php
@@ -34,7 +34,7 @@
/**
* This class generates form components for search-result tasks.
*/
-class CRM_Contact_Form_Task extends CRM_Core_Form {
+class CRM_Contact_Form_Task extends CRM_Core_Form_Task {
/**
* The task being performed
@@ -94,12 +94,15 @@ public function preProcess() {
* Common pre-processing function.
*
* @param CRM_Core_Form $form
- * @param bool $useTable
+ *
+ * @throws \CRM_Core_Exception
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_contactIds = array();
$form->_contactTypes = array();
+ $useTable = (CRM_Utils_System::getClassName($form->controller->getStateMachine()) == 'CRM_Export_StateMachine_Standalone');
+
$isStandAlone = in_array('task', $form->urlPath) || in_array('standalone', $form->urlPath);
if ($isStandAlone) {
list($form->_task, $title) = CRM_Contact_Task::getTaskAndTitleByClass(get_class($form));
@@ -150,7 +153,7 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
$form->assign('taskName', CRM_Utils_Array::value($form->_task, $crmContactTaskTasks));
if ($useTable) {
- $form->_componentTable = CRM_Core_DAO::createTempTableName('civicrm_task_action', TRUE, $qfKey);
+ $form->_componentTable = CRM_Utils_SQL_TempTable::build()->setCategory('tskact')->setDurable()->setId($qfKey)->getName();
$sql = " DROP TABLE IF EXISTS {$form->_componentTable}";
CRM_Core_DAO::executeQuery($sql);
@@ -169,10 +172,10 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
// rather than prevnext cache table for most of the task actions except export where we rebuild query to fetch
// final result set
if ($useTable) {
- $allCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey, "getall");
+ $allCids = Civi::service('prevnext')->getSelection($cacheKey, "getall");
}
else {
- $allCids[$cacheKey] = $form->getContactIds();
+ $allCids[$cacheKey] = self::getContactIds($form);
}
$form->_contactIds = array();
@@ -230,7 +233,7 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
}
else {
// fetching selected contact ids of passed cache key
- $selectedCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey);
+ $selectedCids = Civi::service('prevnext')->getSelection($cacheKey);
foreach ($selectedCids[$cacheKey] as $selectedCid => $ignore) {
if ($useTable) {
$insertString[] = " ( {$selectedCid} ) ";
@@ -270,7 +273,7 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
) {
$sel = CRM_Utils_Array::value('radio_ts', self::$_searchFormValues);
$form->assign('searchtype', $sel);
- $result = CRM_Core_BAO_PrevNextCache::getSelectedContacts();
+ $result = self::getSelectedContactNames();
$form->assign("value", $result);
}
@@ -283,36 +286,41 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
}
/**
- * Get the contact id for custom search.
+ * Get the contact ids for:
+ * - "Select Records: All xx records"
+ * - custom search (FIXME: does this still apply to custom search?).
+ * When we call this function we are not using the prev/next cache
+ *
+ * @param $form CRM_Core_Form
*
- * we are not using prev/next table in case of custom search
+ * @return array $contactIds
*/
- public function getContactIds() {
+ public static function getContactIds($form) {
// need to perform action on all contacts
// fire the query again and get the contact id's + display name
$sortID = NULL;
- if ($this->get(CRM_Utils_Sort::SORT_ID)) {
- $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID),
- $this->get(CRM_Utils_Sort::SORT_DIRECTION)
+ if ($form->get(CRM_Utils_Sort::SORT_ID)) {
+ $sortID = CRM_Utils_Sort::sortIDValue($form->get(CRM_Utils_Sort::SORT_ID),
+ $form->get(CRM_Utils_Sort::SORT_DIRECTION)
);
}
- $selectorName = $this->controller->selectorName();
+ $selectorName = $form->controller->selectorName();
- $fv = $this->get('formValues');
- $customClass = $this->get('customSearchClass');
+ $fv = $form->get('formValues');
+ $customClass = $form->get('customSearchClass');
$returnProperties = CRM_Core_BAO_Mapping::returnProperties(self::$_searchFormValues);
$selector = new $selectorName($customClass, $fv, NULL, $returnProperties);
- $params = $this->get('queryParams');
+ $params = $form->get('queryParams');
// fix for CRM-5165
- $sortByCharacter = $this->get('sortByCharacter');
+ $sortByCharacter = $form->get('sortByCharacter');
if ($sortByCharacter && $sortByCharacter != 1) {
$params[] = array('sortByCharacter', '=', $sortByCharacter, 0, 0);
}
- $queryOperator = $this->get('queryOperator');
+ $queryOperator = $form->get('queryOperator');
if (!$queryOperator) {
$queryOperator = 'AND';
}
@@ -469,6 +477,29 @@ public function mergeContactIdsByHousehold() {
}
}
+ /**
+ * @return array
+ * List of contact names.
+ * NOTE: These are raw values from the DB. In current data-model, that means
+ * they are pre-encoded HTML.
+ */
+ private static function getSelectedContactNames() {
+ $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String');
+ $cacheKey = "civicrm search {$qfKey}";
+
+ $cids = array();
+ // Gymanstic time!
+ foreach (Civi::service('prevnext')->getSelection($cacheKey) as $cacheKey => $values) {
+ $cids = array_unique(array_merge($cids, array_keys($values)));
+ }
+
+ $result = CRM_Utils_SQL_Select::from('civicrm_contact')
+ ->where('id IN (#cids)', ['cids' => $cids])
+ ->execute()
+ ->fetchMap('id', 'sort_name');
+ return $result;
+ }
+
/**
* Given this task's list of targets, produce a hidden group.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Import/Parser.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Import/Parser.php
index 552ec453f61..6a40dea23ff 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Import/Parser.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Import/Parser.php
@@ -275,9 +275,6 @@ public function run(
break;
}
- // clean up memory from dao's
- CRM_Core_DAO::freeResult();
-
// see if we've hit our timeout yet
/* if ( $the_thing_with_the_stuff ) {
do_something( );
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/AJAX.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/AJAX.php
index 79fa957b6c8..8270d7b753a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/AJAX.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/AJAX.php
@@ -966,19 +966,19 @@ public static function selectUnselectContacts() {
$elements[$key] = self::_convertToId($element);
}
CRM_Utils_Type::escapeAll($elements, 'Integer');
- CRM_Core_BAO_PrevNextCache::markSelection($cacheKey, $actionToPerform, $elements);
+ Civi::service('prevnext')->markSelection($cacheKey, $actionToPerform, $elements);
}
else {
- CRM_Core_BAO_PrevNextCache::markSelection($cacheKey, $actionToPerform);
+ Civi::service('prevnext')->markSelection($cacheKey, $actionToPerform);
}
}
elseif ($variableType == 'single') {
$cId = self::_convertToId($name);
CRM_Utils_Type::escape($cId, 'Integer');
$action = ($state == 'checked') ? 'select' : 'unselect';
- CRM_Core_BAO_PrevNextCache::markSelection($cacheKey, $action, $cId);
+ Civi::service('prevnext')->markSelection($cacheKey, $action, $cId);
}
- $contactIds = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey);
+ $contactIds = Civi::service('prevnext')->getSelection($cacheKey);
$countSelectionCids = count($contactIds[$cacheKey]);
$arrRet = array('getCount' => $countSelectionCids);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View.php
index aded9798511..f7e0057eefa 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View.php
@@ -117,7 +117,7 @@ public function preProcess() {
'nextPrevError' => 0,
);
if ($qfKey) {
- $pos = CRM_Core_BAO_PrevNextCache::getPositions("civicrm search $qfKey",
+ $pos = Civi::service('prevnext')->getPositions("civicrm search $qfKey",
$this->_contactId,
$this->_contactId
);
@@ -306,7 +306,7 @@ public static function checkUserPermission($page, $contactID = NULL) {
*/
public static function setTitle($contactId, $isDeleted = FALSE) {
static $contactDetails;
- $displayName = $contactImage = NULL;
+ $contactImage = NULL;
if (!isset($contactDetails[$contactId])) {
list($displayName, $contactImage) = self::getContactDetails($contactId);
$contactDetails[$contactId] = array(
@@ -327,6 +327,15 @@ public static function setTitle($contactId, $isDeleted = FALSE) {
}
if ($isDeleted) {
$title = "
{$title}";
+ $mergedTo = civicrm_api3('Contact', 'getmergedto', ['contact_id' => $contactId, 'api.Contact.get' => ['return' => 'display_name']]);
+ if ($mergedTo['count']) {
+ $mergedToContactID = $mergedTo['id'];
+ $mergedToDisplayName = $mergedTo['values'][$mergedToContactID]['api.Contact.get']['values'][0]['display_name'];
+ $title .= ' ' . ts('(This contact has been merged to %2)', [
+ 1 => CRM_Utils_System::url('civicrm/contact/view', ['reset' => 1, 'cid' => $mergedToContactID]),
+ 2 => $mergedToDisplayName,
+ ]);
+ }
}
// Inline-edit places its own title on the page
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View/UserDashBoard.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View/UserDashBoard.php
index 9ecf6863b62..2cc99577e1c 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View/UserDashBoard.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Page/View/UserDashBoard.php
@@ -72,7 +72,9 @@ public function __construct() {
$userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this);
$validUser = FALSE;
if (empty($userID) && $this->_contactId && $userChecksum) {
+ $this->assign('userChecksum', $userChecksum);
$validUser = CRM_Contact_BAO_Contact_Utils::validChecksum($this->_contactId, $userChecksum);
+ $this->_isChecksumUser = $validUser;
}
if (!$this->_contactId) {
@@ -168,7 +170,7 @@ public function buildUserDashBoard() {
$this->assign('pcpInfo', $pcpInfo);
}
- if (!empty($this->_userOptions['Assigned Activities'])) {
+ if (!empty($this->_userOptions['Assigned Activities']) && empty($this->_isChecksumUser)) {
// Assigned Activities section
$dashboardElements[] = array(
'class' => 'crm-dashboard-assignedActivities',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Selector.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Selector.php
index 731f78c69d6..066e4a4476f 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Selector.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Selector.php
@@ -579,10 +579,10 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
// note that the default action is basic
if ($rowCount) {
$cacheKey = $this->buildPrevNextCache($sort);
- $result = $this->_query->getCachedContacts($cacheKey, $offset, $rowCount, $includeContactIds);
+ $resultSet = $this->_query->getCachedContacts($cacheKey, $offset, $rowCount, $includeContactIds)->fetchGenerator();
}
else {
- $result = $this->_query->searchQuery($offset, $rowCount, $sort, FALSE, $includeContactIds);
+ $resultSet = $this->_query->searchQuery($offset, $rowCount, $sort, FALSE, $includeContactIds)->fetchGenerator();
}
// process the result of the query
@@ -671,7 +671,7 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
);
}
- while ($result->fetch()) {
+ foreach ($resultSet as $result) {
$row = array();
$this->_query->convertToPseudoNames($result);
// the columns we are interested in
@@ -881,7 +881,7 @@ public function buildPrevNextCache($sort) {
// check for current != previous to ensure cache is not reset if paging is done without changing
// sort criteria
if (!$pageNum || (!empty($currentSortID) && $currentSortID != $previousSortID)) {
- CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey, 'civicrm_contact');
+ Civi::service('prevnext')->deleteItem(NULL, $cacheKey, 'civicrm_contact');
// this means it's fresh search, so set pageNum=1
if (!$pageNum) {
$pageNum = 1;
@@ -900,7 +900,7 @@ public function buildPrevNextCache($sort) {
$sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String');
//for text field pagination selection save
- $countRow = CRM_Core_BAO_PrevNextCache::getCount($cacheKey, NULL, "entity_table = 'civicrm_contact'");
+ $countRow = Civi::service('prevnext')->getCount($cacheKey);
// $sortByCharacter triggers a refresh in the prevNext cache
if ($sortByCharacter && $sortByCharacter != 'all') {
$cacheKey .= "_alphabet";
@@ -1039,17 +1039,11 @@ public function fillupPrevNextCache($sort, $cacheKey, $start = 0, $end = self::C
// the other alternative of running the FULL query will just be incredibly inefficient
// and slow things down way too much on large data sets / complex queries
- $insertSQL = "
-INSERT INTO civicrm_prevnext_cache ( entity_table, entity_id1, entity_id2, cacheKey, data )
-SELECT DISTINCT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.sort_name
-";
+ $selectSQL = "SELECT DISTINCT 'civicrm_contact', contact_a.id, contact_a.id, '$cacheKey', contact_a.sort_name";
- $sql = str_replace(array("SELECT contact_a.id as contact_id", "SELECT contact_a.id as id"), $insertSQL, $sql);
+ $sql = str_replace(array("SELECT contact_a.id as contact_id", "SELECT contact_a.id as id"), $selectSQL, $sql);
try {
- $result = CRM_Core_DAO::executeQuery($sql, [], FALSE, NULL, FALSE, TRUE, TRUE);
- if (is_a($result, 'DB_Error')) {
- throw new CRM_Core_Exception($result->message);
- }
+ Civi::service('prevnext')->fillWithSql($cacheKey, $sql);
}
catch (CRM_Core_Exception $e) {
if ($coreSearch) {
@@ -1089,18 +1083,17 @@ public function rebuildPreNextCache($start, $end, $sort, $cacheKey) {
$dao = CRM_Core_DAO::executeQuery($sql);
// build insert query, note that currently we build cache for 500 (self::CACHE_SIZE) contact records at a time, hence below approach
- $insertValues = array();
+ $rows = [];
while ($dao->fetch()) {
- $insertValues[] = "('civicrm_contact', {$dao->contact_id}, {$dao->contact_id}, '{$cacheKey}', '" . CRM_Core_DAO::escapeString($dao->sort_name) . "')";
+ $rows[] = [
+ 'entity_table' => 'civicrm_contact',
+ 'entity_id1' => $dao->contact_id,
+ 'entity_id2' => $dao->contact_id,
+ 'data' => $dao->sort_name,
+ ];
}
- //update pre/next cache using single insert query
- if (!empty($insertValues)) {
- $sql = 'INSERT INTO civicrm_prevnext_cache ( entity_table, entity_id1, entity_id2, cacheKey, data ) VALUES
-' . implode(',', $insertValues);
-
- $result = CRM_Core_DAO::executeQuery($sql);
- }
+ Civi::service('prevnext')->fillWithArray($cacheKey, $rows);
}
/**
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Task.php
index 71cf992bdab..f314b028493 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contact/Task.php
@@ -297,18 +297,17 @@ public static function permissionedTaskTitles($permission, $params = array()) {
self::LABEL_CONTACTS => self::$_tasks[self::LABEL_CONTACTS]['title'],
);
- if (isset(self::$_tasks[self::MAP_CONTACTS]) &&
- !empty(self::$_tasks[self::MAP_CONTACTS]['title'])
- ) {
- $tasks[self::MAP_CONTACTS] = self::$_tasks[self::MAP_CONTACTS]['title'];
- }
-
- if (isset(self::$_tasks[self::CREATE_MAILING]) &&
- !empty(self::$_tasks[self::CREATE_MAILING]['title'])
- ) {
- $tasks[self::CREATE_MAILING] = self::$_tasks[self::CREATE_MAILING]['title'];
+ foreach ([
+ self::MAP_CONTACTS,
+ self::CREATE_MAILING,
+ self::TASK_SMS
+ ] as $task) {
+ if (isset(self::$_tasks[$task]) &&
+ !empty(self::$_tasks[$task]['title'])
+ ) {
+ $tasks[$task] = self::$_tasks[$task]['title'];
+ }
}
-
}
$tasks = parent::corePermissionedTaskTitles($tasks, $permission, $params);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution.php
index f58bd9f9eaa..bd1d1d452ef 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution.php
@@ -1967,7 +1967,7 @@ public static function transitionComponents($params, $processContributionObject
$membershipLog['modified_date'] = date('Ymd');
$membershipLog['membership_type_id'] = $membership->membership_type_id;
- CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray);
+ CRM_Member_BAO_MembershipLog::add($membershipLog);
//update related Memberships.
CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $formattedParams);
@@ -2441,7 +2441,7 @@ public function loadRelatedObjects(&$input, &$ids, $loadAll = FALSE) {
}
}
- $this->loadRelatedMembershipObjects($ids);
+ $ids = $this->loadRelatedMembershipObjects($ids);
if ($this->_component != 'contribute') {
// we are in event mode
@@ -3840,7 +3840,6 @@ public static function validateFinancialType($financialTypeId, $relationName = '
* @return null|object
*/
public static function recordAdditionalPayment($contributionId, $trxnsData, $paymentType = 'owed', $participantId = NULL, $updateStatus = TRUE) {
- $statusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
$getInfoOf['id'] = $contributionId;
$defaults = array();
$contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults, CRM_Core_DAO::$_nullArray);
@@ -3849,8 +3848,7 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
}
// load related memberships on basis of $contributionDAO object
- $membershipIDs = array();
- $contributionDAO->loadRelatedMembershipObjects($membershipIDs);
+ $contributionDAO->loadRelatedMembershipObjects();
// build params for recording financial trxn entry
$params['contribution'] = $contributionDAO;
@@ -3859,7 +3857,7 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
$trxnsData['trxn_date'] = !empty($trxnsData['trxn_date']) ? $trxnsData['trxn_date'] : date('YmdHis');
$arAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contributionDAO->financial_type_id, 'Accounts Receivable Account is');
- // get the paid status id
+ $completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
$paidStatus = CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_FinancialItem', 'status_id', 'Paid');
if ($paymentType == 'owed') {
@@ -3894,7 +3892,7 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
WHERE eft.entity_table = 'civicrm_contribution'
AND eft.entity_id = {$contributionId}
AND ft.to_financial_account_id != {$toFinancialAccount}
- AND ft.status_id = {$statusId}
+ AND ft.status_id = {$completedStatusId}
";
$query = CRM_Core_DAO::executeQuery($sql);
$query->fetch();
@@ -3904,7 +3902,7 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
if ($contributionDAO->total_amount == $sumOfPayments) {
// update contribution status and
// clean cancel info (if any) if prev. contribution was updated in case of 'Refunded' => 'Completed'
- $contributionDAO->contribution_status_id = $statusId;
+ $contributionDAO->contribution_status_id = $completedStatusId;
$contributionDAO->cancel_date = 'null';
$contributionDAO->cancel_reason = NULL;
$netAmount = !empty($trxnsData['net_amount']) ? NULL : $trxnsData['total_amount'];
@@ -3913,7 +3911,7 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
$contributionDAO->save();
//Change status of financial record too
- $financialTrxn->status_id = $statusId;
+ $financialTrxn->status_id = $completedStatusId;
$financialTrxn->save();
// note : not using the self::add method,
@@ -3932,15 +3930,11 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
}
}
- // update membership details
- if (!empty($contributionDAO->_relatedObjects['membership'])) {
- self::updateMembershipBasedOnCompletionOfContribution(
- $contributionDAO,
- $contributionDAO->_relatedObjects['membership'],
- $contributionId,
- $trxnsData['trxn_date']
- );
- }
+ self::updateMembershipBasedOnCompletionOfContribution(
+ $contributionDAO,
+ $contributionId,
+ $trxnsData['trxn_date']
+ );
// update financial item statuses
$baseTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contributionId);
@@ -3966,7 +3960,7 @@ public static function recordAdditionalPayment($contributionId, $trxnsData, $pay
// which in 'Pending Refund' => 'Completed' is not useful, instead specific financial record updates
// are coded below i.e. just updating financial_item status to 'Paid'
if ($updateStatus) {
- $contributionDetails = CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $statusId);
+ CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $completedStatusId);
}
// add financial item entry
$lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($contributionDAO->id);
@@ -4553,7 +4547,6 @@ public static function completeOrder(&$input, &$ids, $objects, $transaction, $re
}
$participant = CRM_Utils_Array::value('participant', $objects);
- $memberships = CRM_Utils_Array::value('membership', $objects);
$recurContrib = CRM_Utils_Array::value('contributionRecur', $objects);
$recurringContributionID = (empty($recurContrib->id)) ? NULL : $recurContrib->id;
$event = CRM_Utils_Array::value('event', $objects);
@@ -4601,10 +4594,6 @@ public static function completeOrder(&$input, &$ids, $objects, $transaction, $re
self::repeatTransaction($contribution, $input, $contributionParams, $paymentProcessorId);
$contributionParams['financial_type_id'] = $contribution->financial_type_id;
- if (is_numeric($memberships)) {
- $memberships = array($objects['membership']);
- }
-
$values = array();
if (isset($input['is_email_receipt'])) {
$values['is_email_receipt'] = $input['is_email_receipt'];
@@ -4632,13 +4621,11 @@ public static function completeOrder(&$input, &$ids, $objects, $transaction, $re
$values['is_email_receipt'] = $recurContrib->is_email_receipt;
}
- if (!empty($memberships)) {
+ if ($contributionParams['contribution_status_id'] === $completedContributionStatusID) {
self::updateMembershipBasedOnCompletionOfContribution(
$contribution,
- $memberships,
$primaryContributionID,
- $changeDate,
- CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'contribution_status_id', CRM_Utils_Array::value('contribution_status_id', $input))
+ $changeDate
);
}
}
@@ -4823,9 +4810,11 @@ public static function createCreditNoteId() {
*
* @param array $ids
*
+ * @return array $ids
+ *
* @throws Exception
*/
- public function loadRelatedMembershipObjects(&$ids) {
+ public function loadRelatedMembershipObjects($ids = []) {
$query = "
SELECT membership_id
FROM civicrm_membership_payment
@@ -4856,6 +4845,7 @@ public function loadRelatedMembershipObjects(&$ids) {
}
}
}
+ return $ids;
}
/**
@@ -4865,7 +4855,7 @@ public function loadRelatedMembershipObjects(&$ids) {
*
* @param array $params
*
- * @return object
+ * @return CRM_Financial_DAO_FinancialTrxn
*/
public static function recordPartialPayment($contribution, $params) {
$contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
@@ -5011,6 +5001,7 @@ public static function assignProportionalLineItems($trxnParams, $trxnId, $contri
public static function checkLineItems(&$params) {
$totalAmount = CRM_Utils_Array::value('total_amount', $params);
$lineItemAmount = 0;
+
foreach ($params['line_items'] as &$lineItems) {
foreach ($lineItems['line_item'] as &$item) {
if (empty($item['financial_type_id'])) {
@@ -5019,11 +5010,20 @@ public static function checkLineItems(&$params) {
$lineItemAmount += $item['line_total'];
}
}
+
if (!isset($totalAmount)) {
$params['total_amount'] = $lineItemAmount;
}
- elseif ($totalAmount != $lineItemAmount) {
- throw new API_Exception("Line item total doesn't match with total amount.");
+ else {
+ $currency = CRM_Utils_Array::value('currency', $params, '');
+
+ if (empty($currency)) {
+ $currency = CRM_Core_Config::singleton()->defaultCurrency;
+ }
+
+ if (!CRM_Utils_Money::equals($totalAmount, $lineItemAmount, $currency)) {
+ throw new CRM_Contribute_Exception_CheckLineItemsException();
+ }
}
}
@@ -5040,11 +5040,13 @@ public static function getFinancialAccountForStatusChangeTrxn($params, $default)
if (!empty($params['financial_account_id'])) {
return $params['financial_account_id'];
}
+
$contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus($params['contribution_status_id'], 'name');
$preferredAccountsRelationships = array(
'Refunded' => 'Credit/Contra Revenue Account is',
'Chargeback' => 'Chargeback Account is',
);
+
if (in_array($contributionStatus, array_keys($preferredAccountsRelationships))) {
$financialTypeID = !empty($params['financial_type_id']) ? $params['financial_type_id'] : $params['prevContribution']->financial_type_id;
return CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship(
@@ -5052,6 +5054,7 @@ public static function getFinancialAccountForStatusChangeTrxn($params, $default)
$preferredAccountsRelationships[$contributionStatus]
);
}
+
return $default;
}
@@ -5400,15 +5403,18 @@ protected static function isPaymentInstrumentChange(&$params, $pendingStatuses)
* load them in this function. Code clean up would compensate for any minor performance implication.
*
* @param \CRM_Contribute_BAO_Contribution $contribution
- * @param array $memberships
* @param int $primaryContributionID
* @param string $changeDate
- * @param string $contributionStatus
- * This shouldn't be required but historical function overload by repeattransaction probably requires it.
*
- * @todo investigate completely bypassing this function if $contributionStatus != Completed.
+ * @throws \CRM_Core_Exception
+ * @throws \CiviCRM_API3_Exception
*/
- protected static function updateMembershipBasedOnCompletionOfContribution($contribution, $memberships, $primaryContributionID, $changeDate, $contributionStatus = 'Completed') {
+ protected static function updateMembershipBasedOnCompletionOfContribution($contribution, $primaryContributionID, $changeDate) {
+ $contribution->loadRelatedMembershipObjects();
+ if (empty($contribution->_relatedObjects['membership'])) {
+ return;
+ }
+ $memberships = $contribution->_relatedObjects['membership'];
foreach ($memberships as $membershipTypeIdKey => $membership) {
if ($membership) {
$membershipParams = array(
@@ -5443,55 +5449,50 @@ protected static function updateMembershipBasedOnCompletionOfContribution($contr
}
$dao->free();
- // Unclear why this is here but this function is overloaded by repeattransaction.
- if ($contributionStatus === 'Pending') {
- $membershipParams['num_terms'] = 0;
- }
- else {
- $membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
- $membershipParams['membership_type_id'],
- $primaryContributionID
+ $membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
+ $membershipParams['membership_type_id'],
+ $primaryContributionID
+ );
+ // @todo remove all this stuff in favour of letting the api call further down handle in
+ // (it is a duplication of what the api does).
+ $dates = array_fill_keys(array(
+ 'join_date',
+ 'start_date',
+ 'end_date',
+ ), NULL);
+ if ($currentMembership) {
+ /*
+ * Fixed FOR CRM-4433
+ * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
+ * when Contribution mode is notify and membership is for renewal )
+ */
+ CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
+
+ // @todo - we should pass membership_type_id instead of null here but not
+ // adding as not sure of testing
+ $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membershipParams['id'],
+ $changeDate, NULL, $membershipParams['num_terms']
);
- // @todo remove all this stuff in favour of letting the api call further down handle in
- // (it is a duplication of what the api does).
- $dates = array_fill_keys(array(
- 'join_date',
- 'start_date',
- 'end_date',
- ), NULL);
- if ($currentMembership) {
- /*
- * Fixed FOR CRM-4433
- * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
- * when Contribution mode is notify and membership is for renewal )
- */
- CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
-
- // @todo - we should pass membership_type_id instead of null here but not
- // adding as not sure of testing
- $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membershipParams['id'],
- $changeDate, NULL, $membershipParams['num_terms']
- );
- $dates['join_date'] = $currentMembership['join_date'];
- }
+ $dates['join_date'] = $currentMembership['join_date'];
+ }
- //get the status for membership.
- $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'],
- $dates['end_date'],
- $dates['join_date'],
- 'today',
- TRUE,
- $membershipParams['membership_type_id'],
- $membershipParams
- );
+ //get the status for membership.
+ $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'],
+ $dates['end_date'],
+ $dates['join_date'],
+ 'today',
+ TRUE,
+ $membershipParams['membership_type_id'],
+ $membershipParams
+ );
+
+ unset($dates['end_date']);
+ $membershipParams['status_id'] = CRM_Utils_Array::value('id', $calcStatus, 'New');
+ //we might be renewing membership,
+ //so make status override false.
+ $membershipParams['is_override'] = FALSE;
+ $membershipParams['status_override_end_date'] = 'null';
- unset($dates['end_date']);
- $membershipParams['status_id'] = CRM_Utils_Array::value('id', $calcStatus, 'New');
- //we might be renewing membership,
- //so make status override false.
- $membershipParams['is_override'] = FALSE;
- $membershipParams['status_override_end_date'] = 'null';
- }
//CRM-17723 - reset static $relatedContactIds array()
// @todo move it to Civi Statics.
$var = TRUE;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution/Utils.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution/Utils.php
index 2b99789923a..0b2c99b898e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution/Utils.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Contribution/Utils.php
@@ -74,6 +74,8 @@ public static function processConfirm(
// add some financial type details to the params list
// if folks need to use it
+ //CRM-15297 deprecate contributionTypeID
+ $paymentParams['financial_type_id'] = $paymentParams['financialTypeID'] = $paymentParams['contributionTypeID'] = $financialType->id;
//CRM-15297 - contributionType is obsolete - pass financial type as well so people can deprecate it
$paymentParams['financialType_name'] = $paymentParams['contributionType_name'] = $form->_params['contributionType_name'] = $financialType->name;
//CRM-11456
@@ -154,8 +156,6 @@ public static function processConfirm(
}
$paymentParams['contributionID'] = $contribution->id;
- //CRM-15297 deprecate contributionTypeID
- $paymentParams['financialTypeID'] = $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
$paymentParams['contributionPageID'] = $contribution->contribution_page_id;
if (isset($paymentParams['contribution_source'])) {
$paymentParams['source'] = $paymentParams['contribution_source'];
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ContributionRecur.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ContributionRecur.php
index aa1d02b5ab2..a5c76722c43 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ContributionRecur.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ContributionRecur.php
@@ -32,6 +32,13 @@
*/
class CRM_Contribute_BAO_ContributionRecur extends CRM_Contribute_DAO_ContributionRecur {
+ /**
+ * Array with statuses that mark a recurring contribution as inactive.
+ *
+ * @var array
+ */
+ private static $inactiveStatuses = array('Cancelled', 'Chargeback', 'Refunded', 'Completed');
+
/**
* Create recurring contribution.
*
@@ -233,15 +240,12 @@ public static function deleteRecurContribution($recurId) {
*
* @param int $recurId
* Recur contribution id.
- * @param array $objects
- * An array of objects that is to be cancelled like.
- * contribution, membership, event. At least contribution object is a must.
*
* @param array $activityParams
*
* @return bool
*/
- public static function cancelRecurContribution($recurId, $objects, $activityParams = array()) {
+ public static function cancelRecurContribution($recurId, $activityParams = array()) {
if (!$recurId) {
return FALSE;
}
@@ -282,7 +286,7 @@ public static function cancelRecurContribution($recurId, $objects, $activityPara
}
$activityParams = array(
'source_contact_id' => $dao->contact_id,
- 'source_record_id' => CRM_Utils_Array::value('source_record_id', $activityParams),
+ 'source_record_id' => $dao->recur_id,
'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Cancel Recurring Contribution'),
'subject' => CRM_Utils_Array::value('subject', $activityParams, ts('Recurring contribution cancelled')),
'details' => $details,
@@ -299,16 +303,8 @@ public static function cancelRecurContribution($recurId, $objects, $activityPara
CRM_Activity_BAO_Activity::create($activityParams);
}
- // if there are associated objects, cancel them as well
- if (!$objects) {
- $transaction->commit();
- return TRUE;
- }
- else {
- // @todo - this is bad! Get the function out of the ipn.
- $baseIPN = new CRM_Core_Payment_BaseIPN();
- return $baseIPN->cancelled($objects, $transaction);
- }
+ $transaction->commit();
+ return TRUE;
}
else {
// if already cancelled, return true
@@ -938,4 +934,14 @@ public static function calculateRecurLineItems($recurId, $total_amount, $financi
return $lineSets;
}
+ /**
+ * Returns array with statuses that are considered to make a recurring
+ * contribution inacteve.
+ *
+ * @return array
+ */
+ public static function getInactiveStatuses() {
+ return self::$inactiveStatuses;
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ManagePremiums.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ManagePremiums.php
index 7b900e40446..f122fb0b887 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ManagePremiums.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/ManagePremiums.php
@@ -29,114 +29,81 @@
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2018
+ * @deprecated
*/
-class CRM_Contribute_BAO_ManagePremiums extends CRM_Contribute_DAO_Product {
-
- /**
- * Static holder for the default LT.
- */
- static $_defaultContributionType = NULL;
+class CRM_Contribute_BAO_ManagePremiums extends CRM_Contribute_BAO_Product {
/**
* Class constructor.
*/
public function __construct() {
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Contribute_BAO_Product::construct');
parent::__construct();
}
/**
* Fetch object based on array of properties.
*
+ * @deprecated
* @param array $params
* (reference ) an assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
- * @return CRM_Contribute_BAO_ManagePremium
+ * @return CRM_Contribute_BAO_Product
*/
public static function retrieve(&$params, &$defaults) {
- $premium = new CRM_Contribute_DAO_Product();
- $premium->copyValues($params);
- if ($premium->find(TRUE)) {
- $premium->product_name = $premium->name;
- CRM_Core_DAO::storeValues($premium, $defaults);
- return $premium;
- }
- return NULL;
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Contribute_BAO_Product::retrieve');
+ return parent::retrieve($params, $defaults);
}
/**
* Update the is_active flag in the db.
*
+ * @deprecated
* @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 success, null otherwise
+ * @return bool
*/
public static function setIsActive($id, $is_active) {
- if (!$is_active) {
- $dao = new CRM_Contribute_DAO_PremiumsProduct();
- $dao->product_id = $id;
- $dao->delete();
- }
- return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Product', $id, 'is_active', $is_active);
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Contribute_BAO_Product::setIsActive');
+ return parent::setIsActive($id, $is_active);
}
/**
* Add a premium product to the database, and return it.
*
+ * @deprecated
* @param array $params
* Reference array contains the values submitted by the form.
- * @param array $ids
+ * @param array $ids (deprecated)
* Reference array contains the id.
*
* @return CRM_Contribute_DAO_Product
*/
- public static function add(&$params, &$ids) {
- $params = array_merge(array(
- 'id' => CRM_Utils_Array::value('premium', $ids),
- 'image' => '',
- 'thumbnail' => '',
- 'is_active' => 0,
- 'is_deductible' => FALSE,
- 'currency' => CRM_Core_Config::singleton()->defaultCurrency,
- ), $params);
-
- // Modify the submitted values for 'image' and 'thumbnail' so that we use
- // local URLs for these images when possible.
- $params['image'] = CRM_Utils_String::simplifyURL($params['image'], TRUE);
- $params['thumbnail'] = CRM_Utils_String::simplifyURL($params['thumbnail'], TRUE);
-
- // Save and return
- $premium = new CRM_Contribute_DAO_Product();
- $premium->copyValues($params);
- $premium->save();
- return $premium;
+ public static function add(&$params, $ids) {
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Contribute_BAO_Product::create');
+ $id = CRM_Utils_Array::value('id', $params, CRM_Utils_Array::value('premium', $ids));
+ if ($id) {
+ $params['id'] = $id;
+ }
+ return parent::create($params);
}
/**
* Delete premium Types.
*
+ * @deprecated
* @param int $productID
+ *
+ * @throws \CRM_Core_Exception
*/
public static function del($productID) {
- //check dependencies
- $premiumsProduct = new CRM_Contribute_DAO_PremiumsProduct();
- $premiumsProduct->product_id = $productID;
- if ($premiumsProduct->find(TRUE)) {
- $session = CRM_Core_Session::singleton();
- $message .= ts('This Premium is being linked to Online Contribution page. Please remove it in order to delete this Premium.', array(1 => CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1')), ts('Deletion Error'), 'error');
- CRM_Core_Session::setStatus($message);
- return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/contribute/managePremiums', 'reset=1&action=browse'));
- }
-
- //delete from financial Type table
- $premium = new CRM_Contribute_DAO_Product();
- $premium->id = $productID;
- $premium->delete();
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Contribute_BAO_Product::del');
+ return parent::del($productID);
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Premium.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Premium.php
index 49b3bebe77c..a7db1d5efd4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Premium.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Premium.php
@@ -104,32 +104,33 @@ public static function del($premiumID) {
public static function buildPremiumBlock(&$form, $pageID, $formItems = FALSE, $selectedProductID = NULL, $selectedOption = NULL) {
$form->add('hidden', "selectProduct", $selectedProductID, array('id' => 'selectProduct'));
- $dao = new CRM_Contribute_DAO_Premium();
- $dao->entity_table = 'civicrm_contribution_page';
- $dao->entity_id = $pageID;
- $dao->premiums_active = 1;
- CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, CRM_Core_Action::ADD);
- $addWhere = "financial_type_id IN (0)";
- if (!empty($financialTypes)) {
- $addWhere = "financial_type_id IN (" . implode(',', array_keys($financialTypes)) . ")";
- }
+ $premiumDao = new CRM_Contribute_DAO_Premium();
+ $premiumDao->entity_table = 'civicrm_contribution_page';
+ $premiumDao->entity_id = $pageID;
+ $premiumDao->premiums_active = 1;
- if ($dao->find(TRUE)) {
- $premiumID = $dao->id;
+ if ($premiumDao->find(TRUE)) {
+ $premiumID = $premiumDao->id;
$premiumBlock = array();
- CRM_Core_DAO::storeValues($dao, $premiumBlock);
+ CRM_Core_DAO::storeValues($premiumDao, $premiumBlock);
- $dao = new CRM_Contribute_DAO_PremiumsProduct();
- $dao->premiums_id = $premiumID;
- $dao->whereAdd($addWhere);
- $dao->orderBy('weight');
- $dao->find();
+ CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, CRM_Core_Action::ADD);
+ $addWhere = "financial_type_id IN (0)";
+ if (!empty($financialTypes)) {
+ $addWhere = "financial_type_id IN (" . implode(',', array_keys($financialTypes)) . ")";
+ }
+ $addWhere = "{$addWhere} OR financial_type_id IS NULL";
+
+ $premiumsProductDao = new CRM_Contribute_DAO_PremiumsProduct();
+ $premiumsProductDao->premiums_id = $premiumID;
+ $premiumsProductDao->whereAdd($addWhere);
+ $premiumsProductDao->orderBy('weight');
+ $premiumsProductDao->find();
$products = array();
- $radio = array();
- while ($dao->fetch()) {
+ while ($premiumsProductDao->fetch()) {
$productDAO = new CRM_Contribute_DAO_Product();
- $productDAO->id = $dao->product_id;
+ $productDAO->id = $premiumsProductDao->product_id;
$productDAO->is_active = 1;
if ($productDAO->find(TRUE)) {
if ($selectedProductID != NULL) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Product.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Product.php
new file mode 100644
index 00000000000..22f1f9739d2
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/BAO/Product.php
@@ -0,0 +1,145 @@
+copyValues($params);
+ if ($premium->find(TRUE)) {
+ $premium->product_name = $premium->name;
+ CRM_Core_DAO::storeValues($premium, $defaults);
+ return $premium;
+ }
+ return NULL;
+ }
+
+ /**
+ * Update the is_active flag in the db.
+ *
+ * @param int $id
+ * Id of the database record.
+ * @param bool $is_active
+ * Value we want to set the is_active field.
+ *
+ * @return bool
+ */
+ public static function setIsActive($id, $is_active) {
+ if (!$is_active) {
+ $dao = new CRM_Contribute_DAO_PremiumsProduct();
+ $dao->product_id = $id;
+ $dao->delete();
+ }
+ return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Product', $id, 'is_active', $is_active);
+ }
+
+ /**
+ * Add a premium product to the database, and return it.
+ *
+ * @param array $params
+ * Update parameters.
+ *
+ * @return CRM_Contribute_DAO_Product
+ */
+ public static function create($params) {
+ $id = CRM_Utils_Array::value('id', $params);
+ if (empty($id)) {
+ $defaultParams = [
+ 'id' => $id,
+ 'image' => '',
+ 'thumbnail' => '',
+ 'is_active' => 0,
+ 'is_deductible' => FALSE,
+ 'currency' => CRM_Core_Config::singleton()->defaultCurrency,
+ ];
+ $params = array_merge($defaultParams, $params);
+ }
+
+ // Modify the submitted values for 'image' and 'thumbnail' so that we use
+ // local URLs for these images when possible.
+ if (isset($params['image'])) {
+ $params['image'] = CRM_Utils_String::simplifyURL($params['image'], TRUE);
+ }
+ if (isset($params['thumbnail'])) {
+ $params['thumbnail'] = CRM_Utils_String::simplifyURL($params['thumbnail'], TRUE);
+ }
+
+ // Save and return
+ $premium = new CRM_Contribute_DAO_Product();
+ $premium->copyValues($params);
+ $premium->save();
+ return $premium;
+ }
+
+ /**
+ * Delete premium Types.
+ *
+ * @param int $productID
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public static function del($productID) {
+ //check dependencies
+ $premiumsProduct = new CRM_Contribute_DAO_PremiumsProduct();
+ $premiumsProduct->product_id = $productID;
+ if ($premiumsProduct->find(TRUE)) {
+ throw new CRM_Core_Exception('Cannot delete a Premium that is linked to a Contribution page');
+ }
+ // delete product
+ $premium = new CRM_Contribute_DAO_Product();
+ $premium->id = $productID;
+ $premium->delete();
+ }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Contribution.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Contribution.php
index 527cb61eb56..d92f6f7958f 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Contribution.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Contribution.php
@@ -399,6 +399,7 @@ public static function &fields() {
'headerPattern' => '/non?.?deduct/i',
'dataPattern' => '/^\d+(\.\d{2})?$/',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_contribution',
'entity' => 'Contribution',
'bao' => 'CRM_Contribute_BAO_Contribution',
@@ -696,6 +697,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_contribution',
'entity' => 'Contribution',
'bao' => 'CRM_Contribute_BAO_Contribution',
@@ -713,6 +715,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_contribution',
'entity' => 'Contribution',
'bao' => 'CRM_Contribute_BAO_Contribution',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionPage.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionPage.php
index ab08e950890..98565ad90e4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionPage.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionPage.php
@@ -458,6 +458,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Credit Card Only?'),
'description' => 'if true - processing logic must reject transaction at confirmation stage if pay method != credit card',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -479,6 +480,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Recurring'),
'description' => 'if true - allows recurring contributions, valid only for PayPal_Standard',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -521,6 +523,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Support Recurring Intervals'),
'description' => 'if true - supports recurring intervals',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -531,6 +534,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Recurring Installments?'),
'description' => 'if true - asks user for recurring installments',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -541,6 +545,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Adjust Recurring Start Date'),
'description' => 'if true - user is able to adjust payment start date',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -551,6 +556,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Pay Later'),
'description' => 'if true - allows the user to send payment directly to the org later',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -581,6 +587,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Allow Partial Payment'),
'description' => 'is partial payment enabled for this online contribution page',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -627,6 +634,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Allow Other Amounts'),
'description' => 'if true, page will include an input text field where user can enter their own amount',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -731,6 +739,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Send email Receipt'),
'description' => 'if true, receipt is automatically emailed to contact on success',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
@@ -930,6 +939,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is billing block required'),
'description' => 'if true - billing block is required for online contribution page',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_page',
'entity' => 'ContributionPage',
'bao' => 'CRM_Contribute_BAO_ContributionPage',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionRecur.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionRecur.php
index 1f1650edad7..c27f63c0044 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionRecur.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionRecur.php
@@ -508,6 +508,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_contribution_recur',
'entity' => 'ContributionRecur',
'bao' => 'CRM_Contribute_BAO_ContributionRecur',
@@ -549,6 +550,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Number of Failures'),
'description' => 'Number of failed charge attempts since last success. Business rule could be set to deactivate on more than x failures.',
+ 'default' => '0',
'table_name' => 'civicrm_contribution_recur',
'entity' => 'ContributionRecur',
'bao' => 'CRM_Contribute_BAO_ContributionRecur',
@@ -576,6 +578,7 @@ public static function &fields() {
'title' => ts('Auto Renew'),
'description' => 'Some systems allow contributor to set a number of installments - but then auto-renew the subscription or commitment if they do not cancel.',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_contribution_recur',
'entity' => 'ContributionRecur',
'bao' => 'CRM_Contribute_BAO_ContributionRecur',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionSoft.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionSoft.php
index 977a00bea70..88c9c47f001 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionSoft.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/ContributionSoft.php
@@ -233,6 +233,7 @@ public static function &fields() {
'name' => 'pcp_display_in_roll',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Soft Contribution Display on PCP'),
+ 'default' => '0',
'table_name' => 'civicrm_contribution_soft',
'entity' => 'ContributionSoft',
'bao' => 'CRM_Contribute_BAO_ContributionSoft',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Premium.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Premium.php
index f8981352c93..9ff1e31b313 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Premium.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Premium.php
@@ -169,6 +169,7 @@ public static function &fields() {
'title' => ts('Is Premium Active?'),
'description' => 'Is the Premiums feature enabled for this page?',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_premiums',
'entity' => 'Premium',
'bao' => 'CRM_Contribute_BAO_Premium',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Product.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Product.php
index 9c1328102a7..5799fa61a55 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Product.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/DAO/Product.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contribute/Product.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:81e315b903d403508f379dc9c0fcf532)
+ * (GenCodeChecksum:a66a59f20355ce5773f427b85bd7bf0b)
*/
/**
@@ -196,7 +196,7 @@ public static function &fields() {
'required' => TRUE,
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'product_name' => [
@@ -213,7 +213,7 @@ public static function &fields() {
'dataPattern' => '',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 1,
],
'description' => [
@@ -223,7 +223,7 @@ public static function &fields() {
'description' => 'Optional description of the product/premium.',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 1,
],
'sku' => [
@@ -239,7 +239,7 @@ public static function &fields() {
'dataPattern' => '',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'options' => [
@@ -249,7 +249,7 @@ public static function &fields() {
'description' => 'Store comma-delimited list of color, size, etc. options for the product.',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 1,
],
'image' => [
@@ -261,7 +261,7 @@ public static function &fields() {
'size' => CRM_Utils_Type::HUGE,
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'thumbnail' => [
@@ -273,7 +273,7 @@ public static function &fields() {
'size' => CRM_Utils_Type::HUGE,
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'price' => [
@@ -287,7 +287,7 @@ public static function &fields() {
],
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'currency' => [
@@ -300,7 +300,7 @@ public static function &fields() {
'default' => 'NULL',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
'html' => [
'type' => 'Select',
@@ -320,7 +320,7 @@ public static function &fields() {
'default' => 'NULL',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
'FKClassName' => 'CRM_Financial_DAO_FinancialType',
'pseudoconstant' => [
@@ -340,7 +340,7 @@ public static function &fields() {
],
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'cost' => [
@@ -354,7 +354,7 @@ public static function &fields() {
],
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'is_active' => [
@@ -365,7 +365,7 @@ public static function &fields() {
'required' => TRUE,
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'period_type' => [
@@ -379,7 +379,7 @@ public static function &fields() {
'default' => 'rolling',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
'html' => [
'type' => 'Select',
@@ -396,7 +396,7 @@ public static function &fields() {
'default' => '0101',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'duration_unit' => [
@@ -408,7 +408,7 @@ public static function &fields() {
'default' => 'year',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
'html' => [
'type' => 'Select',
@@ -424,7 +424,7 @@ public static function &fields() {
'description' => 'Number of units for total duration of subscription, service, membership (e.g. 12 Months).',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
'frequency_unit' => [
@@ -437,7 +437,7 @@ public static function &fields() {
'default' => 'month',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
'html' => [
'type' => 'Select',
@@ -453,7 +453,7 @@ public static function &fields() {
'description' => 'Number of units for delivery frequency of subscription, service, membership (e.g. every 3 Months).',
'table_name' => 'civicrm_product',
'entity' => 'Product',
- 'bao' => 'CRM_Contribute_DAO_Product',
+ 'bao' => 'CRM_Contribute_BAO_Product',
'localizable' => 0,
],
];
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Exception/CheckLineItemsException.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Exception/CheckLineItemsException.php
new file mode 100644
index 00000000000..c1c0d3a9142
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Exception/CheckLineItemsException.php
@@ -0,0 +1,13 @@
+id = $id;
+ CRM_Core_Error::debug_log_message('Access to contribution page with start date in future attempted - page number ' . $id);
+ }
+
+ /**
+ * Get Contribution page ID.
+ *
+ * @return int
+ */
+ public function getID() {
+ return $this->id;
+ }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Exception/PastContributionPageException.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Exception/PastContributionPageException.php
new file mode 100644
index 00000000000..fc7c8b3182e
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Exception/PastContributionPageException.php
@@ -0,0 +1,25 @@
+id = $id;
+ CRM_Core_Error::debug_log_message('Access to contribution page with past end date attempted - page number ' . $id);
+ }
+
+ /**
+ * Get Contribution page ID.
+ *
+ * @return int
+ */
+ public function getID() {
+ return $this->id;
+ }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/AdditionalInfo.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/AdditionalInfo.php
index d279d644e10..33bf7bb1968 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/AdditionalInfo.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/AdditionalInfo.php
@@ -209,7 +209,7 @@ public static function processPremium($params, $contributionID, $premiumID = NUL
);
$productDetails = array();
- CRM_Contribute_BAO_ManagePremiums::retrieve($premiumParams, $productDetails);
+ CRM_Contribute_BAO_Product::retrieve($premiumParams, $productDetails);
$dao->financial_type_id = CRM_Utils_Array::value('financial_type_id', $productDetails);
if (!empty($options[$selectedProductID])) {
$dao->product_option = $options[$selectedProductID][$selectedProductOptionID];
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/CancelSubscription.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/CancelSubscription.php
index 06941d9035b..ec4aabd93be 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/CancelSubscription.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/CancelSubscription.php
@@ -224,7 +224,6 @@ public function postProcess() {
);
$cancelStatus = CRM_Contribute_BAO_ContributionRecur::cancelRecurContribution(
$this->_subscriptionDetails->recur_id,
- NULL,
$activityParams
);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Confirm.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Confirm.php
index 17a0bd2f92b..a8b19f13e04 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Confirm.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Confirm.php
@@ -740,21 +740,18 @@ public function postProcess() {
*
* Comments from previous refactor indicate doubt as to what was going on.
*
- * @param int $contributionTypeId
+ * @param int $financialTypeID
*
* @return null|string
*/
- public function wrangleFinancialTypeID($contributionTypeId) {
- if (isset($paymentParams['financial_type'])) {
- $contributionTypeId = $paymentParams['financial_type'];
- }
- elseif (!empty($this->_values['pledge_id'])) {
- $contributionTypeId = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_Pledge',
+ public function wrangleFinancialTypeID($financialTypeID) {
+ if (empty($financialTypeID) && !empty($this->_values['pledge_id'])) {
+ $financialTypeID = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_Pledge',
$this->_values['pledge_id'],
'financial_type_id'
);
}
- return $contributionTypeId;
+ return $financialTypeID;
}
/**
@@ -1997,6 +1994,7 @@ public static function submit($params) {
}
}
$form->set('memberPriceFieldIDS', $membershipPriceFieldIDs);
+ $form->setRecurringMembershipParams();
$form->processFormSubmission(CRM_Utils_Array::value('contact_id', $params));
}
@@ -2395,26 +2393,19 @@ protected function doMembershipProcessing($contactID, $membershipParams, $premiu
$priceFieldIds = $this->get('memberPriceFieldIDS');
if (!empty($priceFieldIds)) {
- $financialTypeID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceFieldIds['id'], 'financial_type_id');
+ $membershipParams['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceFieldIds['id'], 'financial_type_id');
unset($priceFieldIds['id']);
$membershipTypeIds = array();
$membershipTypeTerms = array();
foreach ($priceFieldIds as $priceFieldId) {
- if ($id = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $priceFieldId, 'membership_type_id')) {
- $membershipTypeIds[] = $id;
- //@todo the value for $term is immediately overwritten. It is unclear from the code whether it was intentional to
- // do this or a double = was intended (this ambiguity is the reason many IDEs complain about 'assignment in condition'
- $term = 1;
- if ($term = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $priceFieldId, 'membership_num_terms')) {
- $membershipTypeTerms[$id] = ($term > 1) ? $term : 1;
- }
- else {
- $membershipTypeTerms[$id] = 1;
- }
+ $membershipTypeId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $priceFieldId, 'membership_type_id');
+ if ($membershipTypeId) {
+ $membershipTypeIds[] = $membershipTypeId;
+ $term = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $priceFieldId, 'membership_num_terms') ?: 1;
+ $membershipTypeTerms[$membershipTypeId] = ($term > 1) ? $term : 1;
}
}
$membershipParams['selectMembership'] = $membershipTypeIds;
- $membershipParams['financial_type_id'] = $financialTypeID;
$membershipParams['types_terms'] = $membershipTypeTerms;
}
if (!empty($membershipParams['selectMembership'])) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Main.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Main.php
index 9d7ed7c59b4..4a302b82b70 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Main.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Contribution/Main.php
@@ -302,6 +302,15 @@ public function buildQuickForm() {
$this->buildComponentForm($this->_id, $this);
}
+ if (count($this->_paymentProcessors) >= 1 && !isset($this->_paymentProcessors[0]) && !$this->get_template_vars("isCaptcha") && $this->hasToAddForcefully()) {
+ if (!$this->_userID) {
+ $this->enableCaptchaOnForm();
+ }
+ else {
+ $this->displayCaptchaWarning();
+ }
+ }
+
// Build payment processor form
CRM_Core_Payment_ProcessorForm::buildQuickForm($this);
@@ -554,7 +563,7 @@ public static function buildRecur(&$form) {
$form->add('checkbox', 'is_recur', ts('I want to contribute this amount'), NULL);
if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
- $form->add('text', 'frequency_interval', ts('Every'), $attributes['frequency_interval']);
+ $form->add('text', 'frequency_interval', ts('Every'), $attributes['frequency_interval'] + ['aria-label' => ts('Every')]);
$form->addRule('frequency_interval', ts('Frequency must be a whole number (EXAMPLE: Every 3 months).'), 'integer');
}
else {
@@ -595,7 +604,7 @@ public static function buildRecur(&$form) {
}
}
}
- $frequencyUnit = &$form->add('select', 'frequency_unit', NULL, $units);
+ $frequencyUnit = &$form->addElement('select', 'frequency_unit', NULL, $units, ['aria-label' => ts('Frequency Unit')]);
}
// FIXME: Ideally we should freeze select box if there is only
@@ -1300,6 +1309,9 @@ public function assignFormVariablesByContributionID() {
if (empty($this->_ccid)) {
return;
}
+ if (!$this->getContactID()) {
+ CRM_Core_Error::statusBounce(ts("Returning since there is no contact attached to this contribution id."));
+ }
$payment = CRM_Contribute_BAO_Contribution::getPaymentInfo($this->_ccid, 'contribution');
//bounce if the contribution is not pending.
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionBase.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionBase.php
index 97a06e145ce..ec174f47baa 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionBase.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionBase.php
@@ -313,6 +313,17 @@ public function preProcess() {
throw new CRM_Contribute_Exception_InactiveContributionPageException(ts('The page you requested is currently unavailable.'), $this->_id);
}
+ $endDate = CRM_Utils_Date::processDate(CRM_Utils_Array::value('end_date', $this->_values));
+ $now = date('YmdHis');
+ if ($endDate && $endDate < $now) {
+ throw new CRM_Contribute_Exception_PastContributionPageException(ts('The page you requested has past its end date on ' . CRM_Utils_Date::customFormat($endDate)), $this->_id);
+ }
+
+ $startDate = CRM_Utils_Date::processDate(CRM_Utils_Array::value('start_date', $this->_values));
+ if ($startDate && $startDate > $now) {
+ throw new CRM_Contribute_Exception_FutureContributionPageException(ts('The page you requested will be active from ' . CRM_Utils_Date::customFormat($startDate)), $this->_id);
+ }
+
$this->assignBillingType();
// check for is_monetary status
@@ -603,11 +614,7 @@ public function assignToTemplate() {
$this->assign($paymentField, $this->_params[$paymentField]);
}
}
- $paymentFieldsetLabel = ts('%1 Information', array($paymentProcessorObject->getPaymentTypeLabel()));
- if (empty($paymentFields)) {
- $paymentFieldsetLabel = '';
- }
- $this->assign('paymentFieldsetLabel', $paymentFieldsetLabel);
+ $this->assign('paymentFieldsetLabel', CRM_Core_Payment_Form::getPaymentLabel($paymentProcessorObject));
$this->assign('paymentFields', $paymentFields);
}
@@ -770,14 +777,43 @@ public function buildCustom($id, $name, $viewOnly = FALSE, $profileContactType =
}
if ($addCaptcha && !$viewOnly) {
- $captcha = CRM_Utils_ReCAPTCHA::singleton();
- $captcha->add($this);
- $this->assign('isCaptcha', TRUE);
+ $this->enableCaptchaOnForm();
}
}
}
}
+ /**
+ * Enable ReCAPTCHA on Contribution form
+ */
+ protected function enableCaptchaOnForm() {
+ $captcha = CRM_Utils_ReCAPTCHA::singleton();
+ if ($captcha->hasSettingsAvailable()) {
+ $captcha->add($this);
+ $this->assign('isCaptcha', TRUE);
+ }
+ }
+
+ /**
+ * Display ReCAPTCHA warning on Contribution form
+ */
+ protected function displayCaptchaWarning() {
+ if (CRM_Core_Permission::check("administer CiviCRM")) {
+ $captcha = CRM_Utils_ReCAPTCHA::singleton();
+ if (!$captcha->hasSettingsAvailable()) {
+ $this->assign('displayCaptchaWarning', TRUE);
+ }
+ }
+ }
+
+ /**
+ * Check if ReCAPTCHA has to be added on Contribution form forcefully.
+ */
+ protected function hasToAddForcefully() {
+ $captcha = CRM_Utils_ReCAPTCHA::singleton();
+ return $captcha->hasToAddForcefully();
+ }
+
/**
* Add onbehalf/honoree profile fields and native module fields.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage.php
index 238353ca077..bc3f23d03ea 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage.php
@@ -332,18 +332,13 @@ public function setDefaultValues() {
if ($this->_priceSetID) {
$defaults['price_set_id'] = $this->_priceSetID;
}
-
- if (!empty($defaults['end_date'])) {
- list($defaults['end_date'], $defaults['end_date_time']) = CRM_Utils_Date::setDateDefaults($defaults['end_date']);
- }
-
- if (!empty($defaults['start_date'])) {
- list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults($defaults['start_date']);
- }
}
else {
$defaults['is_active'] = 1;
// set current date as start date
+ // @todo look to change to $defaults['start_date'] = date('Ymd His');
+ // main settings form overrides this to implement above but this is left here
+ // 'in case' another extending form uses start_date - for now
list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults();
}
@@ -353,7 +348,7 @@ public function setDefaultValues() {
), '1');
}
else {
- # CRM 10860
+ // CRM-10860
$defaults['recur_frequency_unit'] = array('month' => 1);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/AddProduct.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/AddProduct.php
index cf3b8055157..7191085d864 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/AddProduct.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/AddProduct.php
@@ -229,15 +229,12 @@ public function postProcess() {
$urlParams = 'civicrm/admin/contribute/premium';
if ($this->_action & CRM_Core_Action::PREVIEW) {
- $session = CRM_Core_Session::singleton();
$url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id);
- $single = $session->get('singleForm');
CRM_Utils_System::redirect($url);
return;
}
if ($this->_action & CRM_Core_Action::DELETE) {
- $session = CRM_Core_Session::singleton();
$url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id);
$dao = new CRM_Contribute_DAO_PremiumsProduct();
$dao->id = $this->_pid;
@@ -246,7 +243,6 @@ public function postProcess() {
CRM_Utils_System::redirect($url);
}
else {
- $session = CRM_Core_Session::singleton();
$url = CRM_Utils_System::url($urlParams, 'reset=1&action=update&id=' . $this->_id);
if ($this->_pid) {
$params['id'] = $this->_pid;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Amount.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Amount.php
index fc6486c24fd..ef174d94052 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Amount.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Amount.php
@@ -372,6 +372,11 @@ public static function formRule($fields, $files, $self) {
$errors['pay_later_receipt'] = ts('Please enter the instructions to be sent to the contributor when they choose to \'pay later\'.');
}
}
+ else {
+ if ($fields['amount_block_is_active'] && empty($fields['payment_processor'])) {
+ $errors['payment_processor'] = ts('You have listed fixed contribution options or selected a price set, but no payment option has been selected. Please select at least one payment processor and/or enable the pay later option.');
+ }
+ }
// don't allow price set w/ membership signup, CRM-5095
if ($priceSetId = CRM_Utils_Array::value('price_set_id', $fields)) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Settings.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Settings.php
index 49e595bfec0..7e94089ef4e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Settings.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Settings.php
@@ -44,6 +44,11 @@ public function preProcess() {
*/
public function setDefaultValues() {
$defaults = parent::setDefaultValues();
+ // @todo handle properly on parent.
+ if (!$this->_id) {
+ $defaults['start_date'] = date('Y-m-d H:i:s');
+ unset($defaults['start_time']);
+ }
$soft_credit_types = CRM_Core_OptionGroup::values('soft_credit_type', TRUE, FALSE, FALSE, NULL, 'name');
if ($this->_id) {
@@ -223,8 +228,8 @@ public function buildQuickForm() {
}
// add optional start and end dates
- $this->addDateTime('start_date', ts('Start Date'));
- $this->addDateTime('end_date', ts('End Date'));
+ $this->add('datepicker', 'start_date', ts('Start Date'));
+ $this->add('datepicker', 'end_date', ts('End Date'));
$this->addFormRule(array('CRM_Contribute_Form_ContributionPage_Settings', 'formRule'), $this);
@@ -334,10 +339,6 @@ public function postProcess() {
$params['is_credit_card_only'] = CRM_Utils_Array::value('is_credit_card_only', $params, FALSE);
$params['honor_block_is_active'] = CRM_Utils_Array::value('honor_block_is_active', $params, FALSE);
$params['is_for_organization'] = !empty($params['is_organization']) ? CRM_Utils_Array::value('is_for_organization', $params, FALSE) : 0;
-
- $params['start_date'] = CRM_Utils_Date::processDate($params['start_date'], $params['start_date_time'], TRUE);
- $params['end_date'] = CRM_Utils_Date::processDate($params['end_date'], $params['end_date_time'], TRUE);
-
$params['goal_amount'] = CRM_Utils_Rule::cleanMoney($params['goal_amount']);
if (!$params['honor_block_is_active']) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Widget.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Widget.php
index df8905af0af..9d8a621354b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Widget.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ContributionPage/Widget.php
@@ -85,55 +85,55 @@ public function preProcess() {
$this->_colorFields = array(
'color_title' => array(
ts('Title Text Color'),
- 'text',
+ 'color',
FALSE,
'#2786C2',
),
'color_bar' => array(
ts('Progress Bar Color'),
- 'text',
+ 'color',
FALSE,
'#2786C2',
),
'color_main_text' => array(
ts('Additional Text Color'),
- 'text',
+ 'color',
FALSE,
'#FFFFFF',
),
'color_main' => array(
ts('Background Color'),
- 'text',
+ 'color',
FALSE,
'#96C0E7',
),
'color_main_bg' => array(
ts('Background Color Top Area'),
- 'text',
+ 'color',
FALSE,
'#B7E2FF',
),
'color_bg' => array(
ts('Border Color'),
- 'text',
+ 'color',
FALSE,
'#96C0E7',
),
'color_about_link' => array(
ts('Button Text Color'),
- 'text',
+ 'color',
FALSE,
'#556C82',
),
'color_button' => array(
ts('Button Background Color'),
- 'text',
+ 'color',
FALSE,
'#FFFFFF',
),
'color_homepage_link' => array(
ts('Homepage Link Color'),
- 'text',
+ 'color',
FALSE,
'#FFFFFF',
),
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ManagePremiums.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ManagePremiums.php
index 8ac350b9c6a..37bad336abd 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ManagePremiums.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/ManagePremiums.php
@@ -50,8 +50,7 @@ public function setDefaultValues() {
$defaults = parent::setDefaultValues();
if ($this->_id) {
$params = array('id' => $this->_id);
- CRM_Contribute_BAO_ManagePremiums::retrieve($params, $tempDefaults);
- $imageUrl = (isset($tempDefaults['image'])) ? $tempDefaults['image'] : "";
+ CRM_Contribute_BAO_Product::retrieve($params, $tempDefaults);
if (isset($tempDefaults['image']) && isset($tempDefaults['thumbnail'])) {
$defaults['imageUrl'] = $tempDefaults['image'];
$defaults['thumbnailUrl'] = $tempDefaults['thumbnail'];
@@ -272,7 +271,15 @@ public function postProcess() {
// If deleting, then only delete and skip the rest of the post-processing
if ($this->_action & CRM_Core_Action::DELETE) {
- CRM_Contribute_BAO_ManagePremiums::del($this->_id);
+ try {
+ CRM_Contribute_BAO_Product::del($this->_id);
+ }
+ catch (CRM_Core_Exception $e) {
+ $message = ts("This Premium is linked to an Online Contribution page. Please remove it before deleting this Premium.", array(1 => CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1')));
+ CRM_Core_Session::setStatus($message, ts('Cannot delete Premium'), 'error');
+ CRM_Core_Session::singleton()->pushUserContext(CRM_Utils_System::url('civicrm/admin/contribute/managePremiums', 'reset=1&action=browse'));
+ return;
+ }
CRM_Core_Session::setStatus(
ts('Selected Premium Product type has been deleted.'),
ts('Deleted'), 'info');
@@ -287,15 +294,15 @@ public function postProcess() {
$params[$field] = CRM_Utils_Rule::cleanMoney($params[$field]);
}
- $ids = array();
+ // If we're updating, we need to pass in the premium product Id
if ($this->_action & CRM_Core_Action::UPDATE) {
- $ids['premium'] = $this->_id;
+ $params['id'] = $this->_id;
}
$this->_processImages($params);
- // Save to database
- $premium = CRM_Contribute_BAO_ManagePremiums::add($params, $ids);
+ // Save the premium product to database
+ $premium = CRM_Contribute_BAO_Product::create($params);
CRM_Core_Session::setStatus(
ts("The Premium '%1' has been saved.", array(1 => $premium->name)),
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Task.php
index 29640162640..f089448db49 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Form/Task.php
@@ -32,30 +32,10 @@
*/
/**
- * This class generates form components for relationship.
+ * Class for contribute form task actions.
+ * FIXME: This needs refactoring to properly inherit from CRM_Core_Form_Task and share more functions.
*/
-class CRM_Contribute_Form_Task extends CRM_Core_Form {
-
- /**
- * The task being performed.
- *
- * @var int
- */
- protected $_task;
-
- /**
- * The additional clause that we restrict the search with.
- *
- * @var string
- */
- protected $_componentClause = NULL;
-
- /**
- * The array that holds all the component ids.
- *
- * @var array
- */
- protected $_componentIds;
+class CRM_Contribute_Form_Task extends CRM_Core_Form_Task {
/**
* The array that holds all the contribution ids.
@@ -64,13 +44,6 @@ class CRM_Contribute_Form_Task extends CRM_Core_Form {
*/
protected $_contributionIds;
- /**
- * The array that holds all the contact ids.
- *
- * @var array
- */
- public $_contactIds;
-
/**
* The array that holds all the mapping contribution and contact ids.
*
@@ -94,9 +67,8 @@ public function preProcess() {
/**
* @param CRM_Core_Form $form
- * @param bool $useTable
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_contributionIds = array();
$values = $form->controller->exportValues($form->get('searchFormName'));
@@ -217,7 +189,7 @@ public function setContributionIds($contributionIds) {
*/
public function setContactIDs() {
if (!$this->_includesSoftCredits) {
- $this->_contactIds = &CRM_Core_DAO::getContactIDsFromComponent(
+ $this->_contactIds = CRM_Core_DAO::getContactIDsFromComponent(
$this->_contributionIds,
'civicrm_contribution'
);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/ManagePremiums.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/ManagePremiums.php
index d4abc4dcd01..462e8b33ebf 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/ManagePremiums.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/ManagePremiums.php
@@ -52,7 +52,7 @@ class CRM_Contribute_Page_ManagePremiums extends CRM_Core_Page_Basic {
* Classname of BAO.
*/
public function getBAOName() {
- return 'CRM_Contribute_BAO_ManagePremiums';
+ return 'CRM_Contribute_BAO_Product';
}
/**
@@ -150,10 +150,9 @@ public function browse() {
'Premium',
$dao->id
);
- //Financial Type
+ // Financial Type
if (!empty($dao->financial_type_id)) {
- require_once 'CRM/Core/DAO.php';
- $premiums[$dao->id]['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $dao->financial_type_id, 'name');
+ $premiums[$dao->id]['financial_type'] = CRM_Core_PseudoConstant::getLabel('CRM_Financial_BAO_FinancialType', 'financial_type', $dao->financial_type_id);
}
}
$this->assign('rows', $premiums);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Premium.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Premium.php
index 3a61d21ed0d..0028036acbc 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Premium.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Premium.php
@@ -130,45 +130,45 @@ public function browse() {
$pageID = CRM_Utils_Request::retrieve('id', 'Positive',
$this, FALSE, 0
);
- $dao = new CRM_Contribute_DAO_Premium();
- $dao->entity_table = 'civicrm_contribution_page';
- $dao->entity_id = $pageID;
- $dao->find(TRUE);
- $premiumID = $dao->id;
+ $premiumDao = new CRM_Contribute_DAO_Premium();
+ $premiumDao->entity_table = 'civicrm_contribution_page';
+ $premiumDao->entity_id = $pageID;
+ $premiumDao->find(TRUE);
+ $premiumID = $premiumDao->id;
$this->assign('products', FALSE);
$this->assign('id', $pageID);
if (!$premiumID) {
return;
}
- $dao = new CRM_Contribute_DAO_PremiumsProduct();
- $dao->premiums_id = $premiumID;
- $dao->orderBy('weight');
- $dao->find();
+ $premiumsProductDao = new CRM_Contribute_DAO_PremiumsProduct();
+ $premiumsProductDao->premiums_id = $premiumID;
+ $premiumsProductDao->orderBy('weight');
+ $premiumsProductDao->find();
- while ($dao->fetch()) {
+ while ($premiumsProductDao->fetch()) {
$productDAO = new CRM_Contribute_DAO_Product();
- $productDAO->id = $dao->product_id;
+ $productDAO->id = $premiumsProductDao->product_id;
$productDAO->is_active = 1;
if ($productDAO->find(TRUE)) {
$premiums[$productDAO->id] = array();
- $premiums[$productDAO->id]['weight'] = $dao->weight;
+ $premiums[$productDAO->id]['weight'] = $premiumsProductDao->weight;
CRM_Core_DAO::storeValues($productDAO, $premiums[$productDAO->id]);
$action = array_sum(array_keys($this->links()));
- $premiums[$dao->product_id]['action'] = CRM_Core_Action::formLink(self::links(), $action,
- array('id' => $pageID, 'pid' => $dao->id),
+ $premiums[$premiumsProductDao->product_id]['action'] = CRM_Core_Action::formLink(self::links(), $action,
+ array('id' => $pageID, 'pid' => $premiumsProductDao->id),
ts('more'),
FALSE,
'premium.contributionpage.row',
'Premium',
- $dao->id
+ $premiumsProductDao->id
);
- //Financial Type
- if (!empty($dao->financial_type_id)) {
- $premiums[$productDAO->id]['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $dao->financial_type_id, 'name');
+ // Financial Type
+ if (!empty($premiumsProductDao->financial_type_id)) {
+ $premiums[$productDAO->id]['financial_type'] = CRM_Core_PseudoConstant::getLabel('CRM_Financial_BAO_FinancialType', 'financial_type', $premiumsProductDao->financial_type_id);
}
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Tab.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Tab.php
index c8260fad816..fa80f7d728f 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Tab.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Contribute/Page/Tab.php
@@ -158,7 +158,9 @@ public function browse() {
if ($this->_contactId) {
$displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId);
$this->assign('displayName', $displayName);
- $this->ajaxResponse['tabCount'] = CRM_Contact_BAO_Contact::getCountComponent('contribution', $this->_contactId);
+ $tabCount = CRM_Contact_BAO_Contact::getCountComponent('contribution', $this->_contactId);
+ $this->assign('tabCount', $tabCount);
+ $this->ajaxResponse['tabCount'] = $tabCount;
}
}
@@ -166,10 +168,53 @@ public function browse() {
* Get all the recurring contribution information and assign to the template
*/
private function addRecurringContributionsBlock() {
+ list($activeContributions, $activeContributionsCount) = $this->getActiveRecurringContributions();
+ list($inactiveRecurringContributions, $inactiveContributionsCount) = $this->getInactiveRecurringContributions();
+
+ if (!empty($activeContributions) || !empty($inactiveRecurringContributions)) {
+ // assign vars to templates
+ $this->assign('action', $this->_action);
+ $this->assign('activeRecurRows', $activeContributions);
+ $this->assign('contributionRecurCount', $activeContributionsCount + $inactiveContributionsCount);
+ $this->assign('inactiveRecurRows', $inactiveRecurringContributions);
+ $this->assign('recur', TRUE);
+ }
+ }
+
+ /**
+ * Loads active recurring contributions for the current contact and formats
+ * them to be used on the form.
+ *
+ * @return array;
+ */
+ private function getActiveRecurringContributions() {
try {
$contributionRecurResult = civicrm_api3('ContributionRecur', 'get', array(
'contact_id' => $this->_contactId,
- 'options' => array('limit' => 0, 'sort' => 'start_date ASC'),
+ 'contribution_status_id' => array('NOT IN' => CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses()),
+ 'options' => ['limit' => 0, 'sort' => 'is_test, start_date DESC'],
+ ));
+ $recurContributions = CRM_Utils_Array::value('values', $contributionRecurResult);
+ }
+ catch (Exception $e) {
+ $recurContributions = array();
+ }
+
+ return $this->buildRecurringContributionsArray($recurContributions);
+ }
+
+ /**
+ * Loads inactive recurring contributions for the current contact and formats
+ * them to be used on the form.
+ *
+ * @return array;
+ */
+ private function getInactiveRecurringContributions() {
+ try {
+ $contributionRecurResult = civicrm_api3('ContributionRecur', 'get', array(
+ 'contact_id' => $this->_contactId,
+ 'contribution_status_id' => array('IN' => CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses()),
+ 'options' => ['limit' => 0, 'sort' => 'is_test, start_date DESC'],
));
$recurContributions = CRM_Utils_Array::value('values', $contributionRecurResult);
}
@@ -177,48 +222,58 @@ private function addRecurringContributionsBlock() {
$recurContributions = NULL;
}
- if (!empty($recurContributions)) {
- foreach ($recurContributions as $recurId => $recurDetail) {
- $action = array_sum(array_keys($this->recurLinks($recurId)));
- // no action allowed if it's not active
- $recurContributions[$recurId]['is_active'] = (!CRM_Contribute_BAO_Contribution::isContributionStatusNegative($recurDetail['contribution_status_id']));
+ return $this->buildRecurringContributionsArray($recurContributions);
+ }
- // Get the name of the payment processor
- if (!empty($recurDetail['payment_processor_id'])) {
- $recurContributions[$recurId]['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName($recurDetail['payment_processor_id']);
- }
- // Get the label for the contribution status
- if (!empty($recurDetail['contribution_status_id'])) {
- $recurContributions[$recurId]['contribution_status'] = CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $recurDetail['contribution_status_id']);
- }
+ /**
+ * @param $recurContributions
+ *
+ * @return mixed
+ */
+ private function buildRecurringContributionsArray($recurContributions) {
+ $liveRecurringContributionCount = 0;
+ foreach ($recurContributions as $recurId => $recurDetail) {
+ $action = array_sum(array_keys($this->recurLinks($recurId)));
+ // no action allowed if it's not active
+ $recurContributions[$recurId]['is_active'] = (!CRM_Contribute_BAO_Contribution::isContributionStatusNegative($recurDetail['contribution_status_id']));
+
+ if (empty($recurDetail['is_test'])) {
+ $liveRecurringContributionCount++;
+ }
- if ($recurContributions[$recurId]['is_active']) {
- $details = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recurContributions[$recurId]['id'], 'recur');
- $hideUpdate = $details->membership_id & $details->auto_renew;
+ // Get the name of the payment processor
+ if (!empty($recurDetail['payment_processor_id'])) {
+ $recurContributions[$recurId]['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName($recurDetail['payment_processor_id']);
+ }
+ // Get the label for the contribution status
+ if (!empty($recurDetail['contribution_status_id'])) {
+ $recurContributions[$recurId]['contribution_status'] = CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $recurDetail['contribution_status_id']);
+ }
- if ($hideUpdate) {
- $action -= CRM_Core_Action::UPDATE;
- }
+ if ($recurContributions[$recurId]['is_active']) {
+ $details = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recurContributions[$recurId]['id'], 'recur');
+ $hideUpdate = $details->membership_id & $details->auto_renew;
- $recurContributions[$recurId]['action'] = CRM_Core_Action::formLink(self::recurLinks($recurId), $action,
- array(
- 'cid' => $this->_contactId,
- 'crid' => $recurId,
- 'cxt' => 'contribution',
- ),
- ts('more'),
- FALSE,
- 'contribution.selector.recurring',
- 'Contribution',
- $recurId
- );
+ if ($hideUpdate) {
+ $action -= CRM_Core_Action::UPDATE;
}
+
+ $recurContributions[$recurId]['action'] = CRM_Core_Action::formLink(self::recurLinks($recurId), $action,
+ array(
+ 'cid' => $this->_contactId,
+ 'crid' => $recurId,
+ 'cxt' => 'contribution',
+ ),
+ ts('more'),
+ FALSE,
+ 'contribution.selector.recurring',
+ 'Contribution',
+ $recurId
+ );
}
- // assign vars to templates
- $this->assign('action', $this->_action);
- $this->assign('recurRows', $recurContributions);
- $this->assign('recur', TRUE);
}
+
+ return [$recurContributions, $liveRecurringContributionCount];
}
/**
@@ -345,8 +400,6 @@ public function setContext() {
$qfKey = NULL;
}
- $session = CRM_Core_Session::singleton();
-
switch ($context) {
case 'user':
$url = CRM_Utils_System::url('civicrm/user', 'reset=1');
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Cache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Cache.php
index 0e619143e33..d1f97f63f66 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Cache.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Cache.php
@@ -40,6 +40,13 @@
*/
class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
+ /**
+ * When store session/form state, how long should the data be retained?
+ *
+ * @var int, number of second
+ */
+ const DEFAULT_SESSION_TTL = 172800; // Two days: 2*24*60*60
+
/**
* @var array ($cacheKey => $cacheValue)
*/
@@ -66,15 +73,16 @@ public static function &getItem($group, $path, $componentID = NULL) {
$argString = "CRM_CT_{$group}_{$path}_{$componentID}";
if (!array_key_exists($argString, self::$_cache)) {
$cache = CRM_Utils_Cache::singleton();
- self::$_cache[$argString] = $cache->get($argString);
+ $cleanKey = self::cleanKey($argString);
+ self::$_cache[$argString] = $cache->get($cleanKey);
if (!self::$_cache[$argString]) {
$table = self::getTableName();
$where = self::whereCache($group, $path, $componentID);
$rawData = CRM_Core_DAO::singleValueQuery("SELECT data FROM $table WHERE $where");
- $data = $rawData ? unserialize($rawData) : NULL;
+ $data = $rawData ? self::decode($rawData) : NULL;
self::$_cache[$argString] = $data;
- $cache->set($argString, self::$_cache[$argString]);
+ $cache->set($cleanKey, self::$_cache[$argString]);
}
}
return self::$_cache[$argString];
@@ -99,7 +107,8 @@ public static function &getItems($group, $componentID = NULL) {
$argString = "CRM_CT_CI_{$group}_{$componentID}";
if (!array_key_exists($argString, self::$_cache)) {
$cache = CRM_Utils_Cache::singleton();
- self::$_cache[$argString] = $cache->get($argString);
+ $cleanKey = self::cleanKey($argString);
+ self::$_cache[$argString] = $cache->get($cleanKey);
if (!self::$_cache[$argString]) {
$table = self::getTableName();
$where = self::whereCache($group, NULL, $componentID);
@@ -107,12 +116,12 @@ public static function &getItems($group, $componentID = NULL) {
$result = array();
while ($dao->fetch()) {
- $result[$dao->path] = unserialize($dao->data);
+ $result[$dao->path] = self::decode($dao->data);
}
$dao->free();
self::$_cache[$argString] = $result;
- $cache->set($argString, self::$_cache[$argString]);
+ $cache->set($cleanKey, self::$_cache[$argString]);
}
}
@@ -148,7 +157,7 @@ public static function setItem(&$data, $group, $path, $componentID = NULL) {
$where = self::whereCache($group, $path, $componentID);
$dataExists = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM $table WHERE {$where}");
$now = date('Y-m-d H:i:s'); // FIXME - Use SQL NOW() or CRM_Utils_Time?
- $dataSerialized = serialize($data);
+ $dataSerialized = self::encode($data);
// This table has a wonky index, so we cannot use REPLACE or
// "INSERT ... ON DUPE". Instead, use SELECT+(INSERT|UPDATE).
@@ -180,13 +189,13 @@ public static function setItem(&$data, $group, $path, $componentID = NULL) {
$argString = "CRM_CT_{$group}_{$path}_{$componentID}";
$cache = CRM_Utils_Cache::singleton();
- $data = unserialize($dataSerialized);
+ $data = self::decode($dataSerialized);
self::$_cache[$argString] = $data;
- $cache->set($argString, $data);
+ $cache->set(self::cleanKey($argString), $data);
$argString = "CRM_CT_CI_{$group}_{$componentID}";
unset(self::$_cache[$argString]);
- $cache->delete($argString);
+ $cache->delete(self::cleanKey($argString));
}
/**
@@ -237,7 +246,8 @@ public static function storeSessionToCache($names, $resetSession = TRUE) {
if (!empty($_SESSION[$sessionName[0]][$sessionName[1]])) {
$value = $_SESSION[$sessionName[0]][$sessionName[1]];
}
- self::setItem($value, 'CiviCRM Session', "{$sessionName[0]}_{$sessionName[1]}");
+ $key = "{$sessionName[0]}_{$sessionName[1]}";
+ Civi::cache('session')->set($key, $value, self::pickSessionTtl($key));
if ($resetSession) {
$_SESSION[$sessionName[0]][$sessionName[1]] = NULL;
unset($_SESSION[$sessionName[0]][$sessionName[1]]);
@@ -248,7 +258,7 @@ public static function storeSessionToCache($names, $resetSession = TRUE) {
if (!empty($_SESSION[$sessionName])) {
$value = $_SESSION[$sessionName];
}
- self::setItem($value, 'CiviCRM Session', $sessionName);
+ Civi::cache('session')->set($sessionName, $value, self::pickSessionTtl($sessionName));
if ($resetSession) {
$_SESSION[$sessionName] = NULL;
unset($_SESSION[$sessionName]);
@@ -275,17 +285,13 @@ public static function storeSessionToCache($names, $resetSession = TRUE) {
public static function restoreSessionFromCache($names) {
foreach ($names as $key => $sessionName) {
if (is_array($sessionName)) {
- $value = self::getItem('CiviCRM Session',
- "{$sessionName[0]}_{$sessionName[1]}"
- );
+ $value = Civi::cache('session')->get("{$sessionName[0]}_{$sessionName[1]}");
if ($value) {
$_SESSION[$sessionName[0]][$sessionName[1]] = $value;
}
}
else {
- $value = self::getItem('CiviCRM Session',
- $sessionName
- );
+ $value = Civi::cache('session')->get($sessionName);
if ($value) {
$_SESSION[$sessionName] = $value;
}
@@ -293,6 +299,32 @@ public static function restoreSessionFromCache($names) {
}
}
+ /**
+ * Determine how long session-state should be retained.
+ *
+ * @param string $sessionKey
+ * Ex: '_CRM_Admin_Form_Preferences_Display_f1a5f232e3d850a29a7a4d4079d7c37b_4654_container'
+ * Ex: 'CiviCRM_CRM_Admin_Form_Preferences_Display_f1a5f232e3d850a29a7a4d4079d7c37b_4654'
+ * @return int
+ * Number of seconds.
+ */
+ protected static function pickSessionTtl($sessionKey) {
+ $secureSessionTimeoutMinutes = (int) Civi::settings()->get('secure_cache_timeout_minutes');
+ if ($secureSessionTimeoutMinutes) {
+ $transactionPages = array(
+ 'CRM_Contribute_Controller_Contribution',
+ 'CRM_Event_Controller_Registration',
+ );
+ foreach ($transactionPages as $transactionPage) {
+ if (strpos($sessionKey, $transactionPage) !== FALSE) {
+ return $secureSessionTimeoutMinutes * 60;
+ }
+ }
+ }
+
+ return self::DEFAULT_SESSION_TTL;
+ }
+
/**
* Do periodic cleanup of the CiviCRM session table.
*
@@ -304,33 +336,7 @@ public static function restoreSessionFromCache($names) {
* @param bool $table
* @param bool $prevNext
*/
- public static function cleanup($session = FALSE, $table = FALSE, $prevNext = FALSE) {
- // first delete all sessions more than 20 minutes old which are related to any potential transaction
- $timeIntervalMins = (int) Civi::settings()->get('secure_cache_timeout_minutes');
- if ($timeIntervalMins && $session) {
- $transactionPages = array(
- 'CRM_Contribute_Controller_Contribution',
- 'CRM_Event_Controller_Registration',
- );
-
- $params = array(
- 1 => array(
- date('Y-m-d H:i:s', time() - $timeIntervalMins * 60),
- 'String',
- ),
- );
- foreach ($transactionPages as $trPage) {
- $params[] = array("%${trPage}%", 'String');
- $where[] = 'path LIKE %' . count($params);
- }
-
- $sql = "
-DELETE FROM civicrm_cache
-WHERE group_name = 'CiviCRM Session'
-AND created_date <= %1
-AND (" . implode(' OR ', $where) . ")";
- CRM_Core_DAO::executeQuery($sql, $params);
- }
+ public static function cleanup($session = FALSE, $table = FALSE, $prevNext = FALSE, $expired = FALSE) {
// clean up the session cache every $cacheCleanUpNumber probabilistically
$cleanUpNumber = 757;
@@ -338,10 +344,10 @@ public static function cleanup($session = FALSE, $table = FALSE, $prevNext = FAL
$timeIntervalDays = 2;
if (mt_rand(1, 100000) % $cleanUpNumber == 0) {
- $session = $table = $prevNext = TRUE;
+ $expired = $session = $table = $prevNext = TRUE;
}
- if (!$session && !$table && !$prevNext) {
+ if (!$session && !$table && !$prevNext && !$expired) {
return;
}
@@ -355,13 +361,43 @@ public static function cleanup($session = FALSE, $table = FALSE, $prevNext = FAL
}
if ($session) {
+ // Session caches are just regular caches, so they expire naturally per TTL.
+ $expired = TRUE;
+ }
- $sql = "
-DELETE FROM civicrm_cache
-WHERE group_name = 'CiviCRM Session'
-AND created_date < date_sub( NOW( ), INTERVAL $timeIntervalDays DAY )
-";
- CRM_Core_DAO::executeQuery($sql);
+ if ($expired) {
+ $sql = "DELETE FROM civicrm_cache WHERE expired_date < %1";
+ $params = [
+ 1 => [date(CRM_Utils_Cache_SqlGroup::TS_FMT, CRM_Utils_Time::getTimeRaw()), 'String'],
+ ];
+ CRM_Core_DAO::executeQuery($sql, $params);
+ }
+ }
+
+ /**
+ * (Quasi-private) Encode an object/array/string/int as a string.
+ *
+ * @param $mixed
+ * @return string
+ */
+ public static function encode($mixed) {
+ return base64_encode(serialize($mixed));
+ }
+
+ /**
+ * (Quasi-private) Decode an object/array/string/int from a string.
+ *
+ * @param $string
+ * @return mixed
+ */
+ public static function decode($string) {
+ // Upgrade support -- old records (serialize) always have this punctuation,
+ // and new records (base64) never do.
+ if (strpos($string, ':') !== FALSE || strpos($string, ';') !== FALSE) {
+ return unserialize($string);
+ }
+ else {
+ return unserialize(base64_decode($string));
}
}
@@ -390,4 +426,35 @@ protected static function whereCache($group, $path, $componentID) {
return $clauses ? implode(' AND ', $clauses) : '(1)';
}
+ /**
+ * Normalize a cache key.
+ *
+ * This bridges an impedance mismatch between our traditional caching
+ * and PSR-16 -- PSR-16 accepts a narrower range of cache keys.
+ *
+ * @param string $key
+ * Ex: 'ab/cd:ef'
+ * @return string
+ * Ex: '_abcd1234abcd1234' or 'ab_xx/cd_xxef'.
+ * A similar key, but suitable for use with PSR-16-compliant cache providers.
+ */
+ public static function cleanKey($key) {
+ if (!is_string($key) && !is_int($key)) {
+ throw new \RuntimeException("Malformed cache key");
+ }
+
+ $maxLen = 64;
+ $escape = '-';
+
+ if (strlen($key) >= $maxLen) {
+ return $escape . md5($key);
+ }
+
+ $r = preg_replace_callback(';[^A-Za-z0-9_\.];', function($m) use ($escape) {
+ return $escape . dechex(ord($m[0]));
+ }, $key);
+
+ return strlen($r) >= $maxLen ? $escape . md5($key) : $r;
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/ConfigSetting.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/ConfigSetting.php
index 8cc76532861..4b5f3111e80 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/ConfigSetting.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/ConfigSetting.php
@@ -96,7 +96,7 @@ public static function retrieve(&$defaults) {
$urlVar = 'task';
}
- if ($isUpgrade && CRM_Core_DAO::checkFieldExists('civicrm_domain', 'config_backend')) {
+ if ($isUpgrade && CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_domain', 'config_backend')) {
$domain->selectAdd('config_backend');
}
else {
@@ -260,6 +260,7 @@ public static function doSiteMove($defaultValues = array()) {
// clear all caches
CRM_Core_Config::clearDBCache();
+ Civi::cache('session')->clear();
$moveStatus .= ts('Database cache tables cleared.') . '
';
$resetSessionTable = CRM_Utils_Request::retrieve('resetSessionTable',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomField.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomField.php
index 41a71643196..8dd1a491fc3 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomField.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomField.php
@@ -83,6 +83,30 @@ public static function &dataType() {
return self::$_dataType;
}
+ /**
+ * Build the map of custom field's data types and there respective Util type
+ *
+ * @return array
+ * Data data-type => CRM_Utils_Type
+ */
+ public static function dataToType() {
+ return [
+ 'String' => CRM_Utils_Type::T_STRING,
+ 'Int' => CRM_Utils_Type::T_INT,
+ 'Money' => CRM_Utils_Type::T_MONEY,
+ 'Memo' => CRM_Utils_Type::T_LONGTEXT,
+ 'Float' => CRM_Utils_Type::T_FLOAT,
+ 'Date' => CRM_Utils_Type::T_DATE,
+ 'DateTime' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
+ 'Boolean' => CRM_Utils_Type::T_BOOLEAN,
+ 'StateProvince' => CRM_Utils_Type::T_INT,
+ 'File' => CRM_Utils_Type::T_STRING,
+ 'Link' => CRM_Utils_Type::T_STRING,
+ 'ContactReference' => CRM_Utils_Type::T_INT,
+ 'Country' => CRM_Utils_Type::T_INT,
+ ];
+ }
+
/**
* Get data to html array.
*
@@ -206,6 +230,8 @@ public static function create(&$params) {
$optionGroup->name = "{$columnName}_" . date('YmdHis');
$optionGroup->title = $params['label'];
$optionGroup->is_active = 1;
+ // Don't set reserved as it's not a built-in option group and may be useful for other custom fields.
+ $optionGroup->is_reserved = 0;
$optionGroup->data_type = $dataType;
$optionGroup->save();
$params['option_group_id'] = $optionGroup->id;
@@ -376,6 +402,9 @@ public function getOptions($context = NULL) {
$this->find(TRUE);
}
+ // This will hold the list of options in format key => label
+ $options = [];
+
if (!empty($this->option_group_id)) {
$options = CRM_Core_OptionGroup::valuesByID(
$this->option_group_id,
@@ -395,9 +424,6 @@ public function getOptions($context = NULL) {
elseif ($this->data_type === 'Boolean') {
$options = $context == 'validate' ? array(0, 1) : CRM_Core_SelectValues::boolean();
}
- else {
- return FALSE;
- }
CRM_Utils_Hook::customFieldOptions($this->id, $options, FALSE);
CRM_Utils_Hook::fieldOptions($this->getEntity(), "custom_{$this->id}", $options, array('context' => $context));
return $options;
@@ -691,6 +717,7 @@ public static function getFieldsForImport(
$regexp = preg_replace('/[.,;:!?]/', '', CRM_Utils_Array::value(0, $values));
$importableFields[$key] = array(
'name' => $key,
+ 'type' => CRM_Utils_Array::value(CRM_Utils_Array::value('data_type', $values), self::dataToType()),
'title' => CRM_Utils_Array::value('label', $values),
'headerPattern' => '/' . preg_quote($regexp, '/') . '/',
'import' => 1,
@@ -2005,6 +2032,8 @@ public static function getTableColumnGroup($fieldID, $force = FALSE) {
/**
* Get custom option groups.
*
+ * @deprecated Use the API OptionGroup.get
+ *
* @param array $includeFieldIds
* Ids of custom fields for which option groups must be included.
*
@@ -2189,46 +2218,45 @@ public static function postProcess(
}
/**
+ * Get custom field ID from field/group name/title.
*
- */
-
- /**
- * Get custom field ID.
- *
- * @param string $fieldLabel
- * @param null $groupTitle
+ * @param string $fieldName Field name or label
+ * @param string|null $groupTitle (Optional) Group name or label
+ * @param bool $fullString Whether to return "custom_123" or "123"
*
- * @return int|null
+ * @return string|int|null
+ * @throws \CiviCRM_API3_Exception
*/
- public static function getCustomFieldID($fieldLabel, $groupTitle = NULL) {
- $params = array(1 => array($fieldLabel, 'String'));
- if ($groupTitle) {
- $params[2] = array($groupTitle, 'String');
- $sql = "
-SELECT f.id
-FROM civicrm_custom_field f
-INNER JOIN civicrm_custom_group g ON f.custom_group_id = g.id
-WHERE ( f.label = %1 OR f.name = %1 )
-AND ( g.title = %2 OR g.name = %2 )
-";
- }
- else {
- $sql = "
-SELECT f.id
-FROM civicrm_custom_field f
-WHERE ( f.label = %1 OR f.name = %1 )
-";
- }
+ public static function getCustomFieldID($fieldName, $groupTitle = NULL, $fullString = FALSE) {
+ if (!isset(Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName])) {
+ $customFieldParams = [
+ 'name' => $fieldName,
+ 'label' => $fieldName,
+ 'options' => ['or' => [["name", "label"]]],
+ ];
+
+ if ($groupTitle) {
+ $customFieldParams['custom_group_id.name'] = $groupTitle;
+ $customFieldParams['custom_group_id.title'] = $groupTitle;
+ $customFieldParams['options'] = ['or' => [["name", "label"], ["custom_group_id.name", "custom_group_id.title"]]];
+ }
- $dao = CRM_Core_DAO::executeQuery($sql, $params);
- if ($dao->fetch() &&
- $dao->N == 1
- ) {
- return $dao->id;
+ $field = civicrm_api3('CustomField', 'get', $customFieldParams);
+
+ if (empty($field['id'])) {
+ Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName]['id'] = NULL;
+ Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName]['string'] = NULL;
+ }
+ else {
+ Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName]['id'] = $field['id'];
+ Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName]['string'] = 'custom_' . $field['id'];
+ }
}
- else {
- return NULL;
+
+ if ($fullString) {
+ return Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName]['string'];
}
+ return Civi::$statics['CRM_Core_BAO_CustomField'][$fieldName]['id'];
}
/**
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomQuery.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomQuery.php
index bc082255a3d..b71acb1081c 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomQuery.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomQuery.php
@@ -433,7 +433,7 @@ public function where() {
break;
case 'Date':
- $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String');
+ $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Date');
list($qillOp, $qillVal) = CRM_Contact_BAO_Query::buildQillForFieldValue(NULL, $field['label'], $value, $op, array(), CRM_Utils_Type::T_DATE);
$this->_qill[$grouping][] = "{$field['label']} $qillOp '$qillVal'";
break;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValue.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValue.php
index 516eb9fe6dc..ce72448de28 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValue.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValue.php
@@ -207,13 +207,18 @@ public static function deleteCustomValue($customValueID, $customGroupID) {
// first we need to find custom value table, from custom group ID
$tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupID, 'table_name');
+ // Retrieve the $entityId so we can pass that to the hook.
+ $entityID = CRM_Core_DAO::singleValueQuery("SELECT entity_id FROM {$tableName} WHERE id = %1", array(
+ 1 => array($customValueID, 'Integer'),
+ ));
+
// delete custom value from corresponding custom value table
$sql = "DELETE FROM {$tableName} WHERE id = {$customValueID}";
CRM_Core_DAO::executeQuery($sql);
CRM_Utils_Hook::custom('delete',
$customGroupID,
- NULL,
+ $entityID,
$customValueID
);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValueTable.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValueTable.php
index 9455b06a4fa..73a431065a8 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValueTable.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/CustomValueTable.php
@@ -637,6 +637,10 @@ public static function setValues(&$params) {
'extends' => $dao->extends,
);
+ if (!empty($params['id'])) {
+ $cvParam['id'] = $params['id'];
+ }
+
if ($cvParam['type'] == 'File') {
$cvParam['file_id'] = $fieldValue['value'];
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Domain.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Domain.php
index c3a9094d6f4..58a06e16d16 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Domain.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Domain.php
@@ -319,4 +319,12 @@ public static function getDefaultReceiptFrom() {
return array($userName, $userEmail);
}
+ /**
+ * Get address to be used for system from addresses when a reply is not expected.
+ */
+ public static function getNoReplyEmailAddress() {
+ $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
+ return "do-not-reply@$emailDomain";
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/FinancialTrxn.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/FinancialTrxn.php
index ccb7d9ca0a1..393714f3b42 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/FinancialTrxn.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/FinancialTrxn.php
@@ -48,7 +48,7 @@ public function __construct() {
* @param array $params
* (reference ) an assoc array of name/value pairs.
*
- * @return CRM_Core_BAO_FinancialTrxn
+ * @return CRM_Financial_DAO_FinancialTrxn
*/
public static function create($params) {
$trxn = new CRM_Financial_DAO_FinancialTrxn();
@@ -116,7 +116,7 @@ public static function getBalanceTrxnAmt($contributionId, $contributionFinancial
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
- * @return CRM_Contribute_BAO_ContributionType
+ * @return \CRM_Financial_DAO_FinancialTrxn
*/
public static function retrieve(&$params, &$defaults) {
$financialItem = new CRM_Financial_DAO_FinancialTrxn();
@@ -350,7 +350,6 @@ public static function createPremiumTrxn($params) {
$contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
$toFinancialAccountType = !empty($params['isDeleted']) ? 'Premiums Inventory Account is' : 'Cost of Sales Account is';
$fromFinancialAccountType = !empty($params['isDeleted']) ? 'Cost of Sales Account is' : 'Premiums Inventory Account is';
- $accountRelationship = array_flip($accountRelationship);
$financialtrxn = array(
'to_financial_account_id' => CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($params['financial_type_id'], $toFinancialAccountType),
'from_financial_account_id' => CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($params['financial_type_id'], $fromFinancialAccountType),
@@ -369,7 +368,7 @@ public static function createPremiumTrxn($params) {
'id' => $params['oldPremium']['product_id'],
);
$productDetails = array();
- CRM_Contribute_BAO_ManagePremiums::retrieve($premiumParams, $productDetails);
+ CRM_Contribute_BAO_Product::retrieve($premiumParams, $productDetails);
$params = array(
'cost' => CRM_Utils_Array::value('cost', $productDetails),
'currency' => CRM_Utils_Array::value('currency', $productDetails),
@@ -387,7 +386,7 @@ public static function createPremiumTrxn($params) {
* @param array $params
* To create trxn entries.
*
- * @return bool
+ * @return bool|void
*/
public static function recordFees($params) {
$domainId = CRM_Core_Config::domainID();
@@ -482,7 +481,6 @@ public static function getPartialPaymentWithType($entityId, $entityName = 'parti
";
$ftTotalAmt = CRM_Core_DAO::singleValueQuery($sqlFtTotalAmt);
- $value = 0;
if (!$ftTotalAmt) {
$ftTotalAmt = 0;
}
@@ -507,7 +505,7 @@ public static function getPartialPaymentWithType($entityId, $entityName = 'parti
/**
* @param int $contributionId
*
- * @return array
+ * @return string
*/
public static function getTotalPayments($contributionId) {
$statusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
@@ -531,7 +529,7 @@ public static function getTotalPayments($contributionId) {
* @param array $contribution
* @param array $params
*
- * @return CRM_Core_BAO_FinancialTrxn
+ * @return \CRM_Financial_DAO_FinancialTrxn
*/
public static function getPartialPaymentTrxn($contribution, $params) {
$trxn = CRM_Contribute_BAO_Contribution::recordPartialPayment($contribution, $params);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Job.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Job.php
index fcb749a2c79..a67ffaa5b07 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Job.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Job.php
@@ -146,4 +146,25 @@ public static function cleanup($maxEntriesToKeep = 1000, $minDaysToKeep = 30) {
CRM_Core_DAO::executeQuery($query);
}
+ /**
+ * Make a copy of a Job.
+ *
+ * @param int $id The job id to copy.
+ *
+ * @return CRM_Core_DAO
+ */
+ public static function copy($id, $params = array()) {
+ $fieldsFix = array(
+ 'suffix' => array(
+ 'name' => ' - ' . ts('Copy'),
+ ),
+ 'replace' => $params,
+ );
+ $copy = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_Job', array('id' => $id), NULL, $fieldsFix);
+ $copy->save();
+ CRM_Utils_Hook::copy('Job', $copy);
+
+ return $copy;
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Navigation.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Navigation.php
index 968bd1bb6e7..9b5f50a00c5 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Navigation.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/Navigation.php
@@ -70,6 +70,7 @@ public static function add(&$params) {
if (empty($params['id'])) {
$params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
$params['has_separator'] = CRM_Utils_Array::value('has_separator', $params, FALSE);
+ $params['domain_id'] = CRM_Utils_Array::value('domain_id', $params, CRM_Core_Config::domainID());
}
if (!isset($params['id']) ||
@@ -93,8 +94,6 @@ public static function add(&$params) {
$navigation->copyValues($params);
- $navigation->domain_id = CRM_Core_Config::domainID();
-
$navigation->save();
return $navigation;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionGroup.php
index 85b2e5203de..bbabcef8bd4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionGroup.php
@@ -88,22 +88,12 @@ public static function setIsActive($id, $is_active) {
* @return object
*/
public static function add(&$params, $ids = array()) {
- if (empty($params['id'])) {
- $params['id'] = CRM_Utils_Array::value('optionGroup', $ids);
+ if (empty($params['id']) && !empty($ids['optionGroup'])) {
+ CRM_Core_Error::deprecatedFunctionWarning('no $ids array');
+ $params['id'] = $ids['optionGroup'];
}
-
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE);
-
- // action is taken depending upon the mode
$optionGroup = new CRM_Core_DAO_OptionGroup();
$optionGroup->copyValues($params);;
-
- if ($params['is_default']) {
- $query = "UPDATE civicrm_option_group SET is_default = 0";
- CRM_Core_DAO::executeQuery($query);
- }
-
$optionGroup->save();
return $optionGroup;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionValue.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionValue.php
index 2e621cf073c..98a331c6f44 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionValue.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/OptionValue.php
@@ -243,6 +243,29 @@ public static function add(&$params, $ids = array()) {
$optionValue->id = $id;
$optionValue->save();
CRM_Core_PseudoConstant::flush();
+
+ // Create relationship for payment intrument options
+ if (!empty($params['financial_account_id'])) {
+ $optionName = civicrm_api3('OptionGroup', 'getvalue', [
+ 'return' => 'name',
+ 'id' => $params['option_group_id'],
+ ]);
+ // Only create relationship for payment intrument options
+ if ($optionName == 'payment_instrument') {
+ $relationTypeId = civicrm_api3('OptionValue', 'getvalue', [
+ 'return' => 'value',
+ 'option_group_id' => 'account_relationship',
+ 'name' => 'Asset Account is',
+ ]);
+ $params = [
+ 'entity_table' => 'civicrm_option_value',
+ 'entity_id' => $optionValue->id,
+ 'account_relationship' => $relationTypeId,
+ 'financial_account_id' => $params['financial_account_id'],
+ ];
+ CRM_Financial_BAO_FinancialTypeAccount::add($params);
+ }
+ }
return $optionValue;
}
@@ -547,16 +570,23 @@ public static function getOptionValuesAssocArrayFromName($optionGroupName) {
* that an option value exists, without hitting an error if it already exists.
*
* This is sympathetic to sites who might pre-add it.
+ *
+ * @param array $params the option value attributes.
+ * @return array the option value attributes.
*/
public static function ensureOptionValueExists($params) {
- $existingValues = civicrm_api3('OptionValue', 'get', array(
+ $result = civicrm_api3('OptionValue', 'get', array(
'option_group_id' => $params['option_group_id'],
'name' => $params['name'],
- 'return' => 'id',
+ 'return' => ['id', 'value'],
+ 'sequential' => 1,
));
- if (!$existingValues['count']) {
- civicrm_api3('OptionValue', 'create', $params);
+
+ if (!$result['count']) {
+ $result = civicrm_api3('OptionValue', 'create', $params);
}
+
+ return CRM_Utils_Array::first($result['values']);
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/PrevNextCache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/PrevNextCache.php
index bf9cc0e8d47..c3078140ac4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/PrevNextCache.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/PrevNextCache.php
@@ -438,164 +438,18 @@ public static function cleanupCache() {
CRM_Core_DAO::executeQuery($sql, $params);
}
- /**
- * Save checkbox selections.
- *
- * @param $cacheKey
- * @param string $action
- * @param array $cIds
- * @param string $entity_table
- */
- public static function markSelection($cacheKey, $action = 'unselect', $cIds = NULL, $entity_table = 'civicrm_contact') {
- if (!$cacheKey) {
- return;
- }
- $params = array();
-
- $entity_whereClause = " AND entity_table = '{$entity_table}'";
- if ($cIds && $cacheKey && $action) {
- if (is_array($cIds)) {
- $cIdFilter = "(" . implode(',', $cIds) . ")";
- $whereClause = "
-WHERE cacheKey LIKE %1
-AND (entity_id1 IN {$cIdFilter} OR entity_id2 IN {$cIdFilter})
-";
- }
- else {
- $whereClause = "
-WHERE cacheKey LIKE %1
-AND (entity_id1 = %2 OR entity_id2 = %2)
-";
- $params[2] = array("{$cIds}", 'Integer');
- }
- if ($action == 'select') {
- $whereClause .= "AND is_selected = 0";
- $sql = "UPDATE civicrm_prevnext_cache SET is_selected = 1 {$whereClause} {$entity_whereClause}";
- $params[1] = array("{$cacheKey}%", 'String');
- }
- elseif ($action == 'unselect') {
- $whereClause .= "AND is_selected = 1";
- $sql = "UPDATE civicrm_prevnext_cache SET is_selected = 0 {$whereClause} {$entity_whereClause}";
- $params[1] = array("%{$cacheKey}%", 'String');
- }
- // default action is reseting
- }
- elseif (!$cIds && $cacheKey && $action == 'unselect') {
- $sql = "
-UPDATE civicrm_prevnext_cache
-SET is_selected = 0
-WHERE cacheKey LIKE %1 AND is_selected = 1
- {$entity_whereClause}
-";
- $params[1] = array("{$cacheKey}%", 'String');
- }
- CRM_Core_DAO::executeQuery($sql, $params);
- }
/**
* Get the selections.
*
- * @param string $cacheKey
- * Cache key.
- * @param string $action
- * Action.
- * $action : get - get only selection records
- * getall - get all the records of the specified cache key
- * @param string $entity_table
- * Entity table.
- *
- * @return array|NULL
- */
- public static function getSelection($cacheKey, $action = 'get', $entity_table = 'civicrm_contact') {
- if (!$cacheKey) {
- return NULL;
- }
- $params = array();
-
- $entity_whereClause = " AND entity_table = '{$entity_table}'";
- if ($cacheKey && ($action == 'get' || $action == 'getall')) {
- $actionGet = ($action == "get") ? " AND is_selected = 1 " : "";
- $sql = "
-SELECT entity_id1, entity_id2 FROM civicrm_prevnext_cache
-WHERE cacheKey LIKE %1
- $actionGet
- $entity_whereClause
-ORDER BY id
-";
- $params[1] = array("{$cacheKey}%", 'String');
-
- $contactIds = array($cacheKey => array());
- $cIdDao = CRM_Core_DAO::executeQuery($sql, $params);
- while ($cIdDao->fetch()) {
- if ($cIdDao->entity_id1 == $cIdDao->entity_id2) {
- $contactIds[$cacheKey][$cIdDao->entity_id1] = 1;
- }
- }
- return $contactIds;
- }
- }
-
- /**
- * @return array
- */
- public static function getSelectedContacts() {
- $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String');
- $cacheKey = "civicrm search {$qfKey}";
- $query = "
-SELECT *
-FROM civicrm_prevnext_cache
-WHERE cacheKey LIKE %1
- AND is_selected=1
- AND cacheKey NOT LIKE %2
-";
- $params1[1] = array("{$cacheKey}%", 'String');
- $params1[2] = array("{$cacheKey}_alphabet%", 'String');
- $dao = CRM_Core_DAO::executeQuery($query, $params1);
-
- $val = array();
- while ($dao->fetch()) {
- $val[] = $dao->data;
- }
- return $val;
- }
-
- /**
- * @param CRM_Core_Form $form
- * @param array $params
+ * NOTE: This stub has been preserved because one extension in `universe`
+ * was referencing the function.
*
- * @return mixed
+ * @deprecated
+ * @see CRM_Core_PrevNextCache_Sql::getSelection()
*/
- public static function buildSelectedContactPager(&$form, &$params) {
- $params['status'] = ts('Contacts %%StatusMessage%%');
- $params['csvString'] = NULL;
- $params['buttonTop'] = 'PagerTopButton';
- $params['buttonBottom'] = 'PagerBottomButton';
- $params['rowCount'] = $form->get(CRM_Utils_Pager::PAGE_ROWCOUNT);
-
- if (!$params['rowCount']) {
- $params['rowCount'] = CRM_Utils_Pager::ROWCOUNT;
- }
-
- $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form);
- $cacheKey = "civicrm search {$qfKey}";
-
- $query = "
-SELECT count(*)
-FROM civicrm_prevnext_cache
-WHERE cacheKey LIKE %1
- AND is_selected = 1
- AND cacheKey NOT LIKE %2
-";
- $params1[1] = array("{$cacheKey}%", 'String');
- $params1[2] = array("{$cacheKey}_alphabet%", 'String');
- $paramsTotal = CRM_Core_DAO::singleValueQuery($query, $params1);
- $params['total'] = $paramsTotal;
- $form->_pager = new CRM_Utils_Pager($params);
- $form->assign_by_ref('pager', $form->_pager);
- list($offset, $rowCount) = $form->_pager->getOffsetAndRowCount();
- $params['offset'] = $offset;
- $params['rowCount1'] = $rowCount;
- return $params;
+ public static function getSelection($cacheKey, $action = 'get') {
+ return Civi::service('prevnext')->getSelection($cacheKey, $action);
}
/**
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/RecurringEntity.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/RecurringEntity.php
index fb73a78cf2c..a5ab757b7b8 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/RecurringEntity.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/RecurringEntity.php
@@ -660,7 +660,6 @@ static public function triggerUpdate($event) {
}
$updateDAO = CRM_Core_DAO::cascadeUpdate($daoName, $obj->id, $entityID, $skipData);
- CRM_Core_DAO::freeResult();
}
else {
CRM_Core_Error::fatal("DAO Mapper missing for $entityTable.");
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/SchemaHandler.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/SchemaHandler.php
index ab58a8aa4b2..1a926044fff 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/SchemaHandler.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/SchemaHandler.php
@@ -627,18 +627,17 @@ public static function checkIfIndexExists($tableName, $indexName) {
*
* @param string $tableName
* @param string $columnName
+ * @param bool $i18nRewrite
+ * Whether to rewrite the query on multilingual setups.
*
* @return bool
*/
- public static function checkIfFieldExists($tableName, $columnName) {
- $result = CRM_Core_DAO::executeQuery(
- "SHOW COLUMNS FROM $tableName LIKE %1",
- array(1 => array($columnName, 'String'))
- );
- if ($result->fetch()) {
- return TRUE;
- }
- return FALSE;
+ public static function checkIfFieldExists($tableName, $columnName, $i18nRewrite = TRUE) {
+ $query = "SHOW COLUMNS FROM $tableName LIKE '%1'";
+ $dao = CRM_Core_DAO::executeQuery($query, [1 => [$columnName, 'Alphanumeric']], TRUE, NULL, FALSE, $i18nRewrite);
+ $result = $dao->fetch() ? TRUE : FALSE;
+ $dao->free();
+ return $result;
}
/**
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFField.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFField.php
index eaac6c3ff1a..e3ce7a46b55 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFField.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFField.php
@@ -896,7 +896,7 @@ public static function getAvailableFields($gid = NULL, $defaults = array()) {
'address_options', TRUE, NULL, TRUE
);
- if (!$addressOptions['county']) {
+ if (empty($addressOptions['county'])) {
unset($fields['Individual']['county'], $fields['Household']['county'], $fields['Organization']['county']);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFGroup.php
index 722fc4b9dfc..4434d2b4395 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/BAO/UFGroup.php
@@ -1673,12 +1673,12 @@ public static function getWeight($ufGroupId = NULL) {
public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission::VIEW, $returnFields = NULL) {
$selectFields = array('id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type');
- if (CRM_Core_DAO::checkFieldExists('civicrm_uf_group', 'description')) {
+ if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_uf_group', 'description')) {
// CRM-13555, since description field was added later (4.4), and to avoid any problems with upgrade
$selectFields[] = 'description';
}
- if (CRM_Core_DAO::checkFieldExists('civicrm_uf_group', 'frontend_title')) {
+ if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_uf_group', 'frontend_title')) {
$selectFields[] = 'frontend_title';
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config.php
index 349c672b83d..265532c67d8 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config.php
@@ -295,6 +295,7 @@ public function cleanupCaches($sessionReset = TRUE) {
// clear all caches
self::clearDBCache();
+ Civi::cache('session')->clear();
CRM_Utils_System::flushCache();
if ($sessionReset) {
@@ -356,7 +357,6 @@ public static function clearDBCache() {
'TRUNCATE TABLE civicrm_group_contact_cache',
'TRUNCATE TABLE civicrm_menu',
'UPDATE civicrm_setting SET value = NULL WHERE name="navigation" AND contact_id IS NOT NULL',
- 'DELETE FROM civicrm_setting WHERE name="modulePaths"', // CRM-10543
);
foreach ($queries as $query) {
@@ -389,11 +389,12 @@ public static function clearTempTables($timeInterval = FALSE) {
WHERE TABLE_SCHEMA = %1
AND (
TABLE_NAME LIKE 'civicrm_import_job_%'
- OR TABLE_NAME LIKE 'civicrm_export_temp%'
- OR TABLE_NAME LIKE 'civicrm_task_action_temp%'
OR TABLE_NAME LIKE 'civicrm_report_temp%'
+ OR TABLE_NAME LIKE 'civicrm_tmp_d%'
)
";
+ // NOTE: Cannot find use-cases where "civicrm_report_temp" would be durable. Could probably remove.
+
if ($timeInterval) {
$query .= " AND CREATE_TIME < DATE_SUB(NOW(), INTERVAL {$timeInterval})";
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config/MagicMerge.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config/MagicMerge.php
index e9414cb783e..63f15a8a589 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config/MagicMerge.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Config/MagicMerge.php
@@ -173,6 +173,7 @@ public static function getPropertyMap() {
'recaptchaOptions' => array('setting'),
'recaptchaPublicKey' => array('setting'),
'recaptchaPrivateKey' => array('setting'),
+ 'forceRecaptcha' => array('setting'),
'replyTo' => array('setting'),
'secondDegRelPermissions' => array('setting'),
'smartGroupCacheTimeout' => array('setting'),
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO.php
index 6df94eb19ad..c6a495b61db 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO.php
@@ -48,6 +48,13 @@
*/
class CRM_Core_DAO extends DB_DataObject {
+ /**
+ * How many times has this instance been cloned.
+ *
+ * @var int
+ */
+ protected $resultCopies = 0;
+
/**
* @var null
* @deprecated
@@ -119,6 +126,22 @@ public function __construct() {
$this->__table = $this->getTableName();
}
+ public function __clone() {
+ if (!empty($this->_DB_resultid)) {
+ $this->resultCopies++;
+ }
+ }
+
+ /**
+ * Class destructor.
+ */
+ public function __destruct() {
+ if ($this->resultCopies === 0) {
+ $this->free();
+ }
+ $this->resultCopies--;
+ }
+
/**
* Empty definition for virtual function.
*/
@@ -826,6 +849,9 @@ public static function objectExists($value, $daoName, $daoID, $fieldName = 'name
/**
* Check if there is a given column in a specific table.
*
+ * @deprecated
+ * @see CRM_Core_BAO_SchemaHandler::checkIfFieldExists
+ *
* @param string $tableName
* @param string $columnName
* @param bool $i18nRewrite
@@ -835,16 +861,7 @@ public static function objectExists($value, $daoName, $daoID, $fieldName = 'name
* true if exists, else false
*/
public static function checkFieldExists($tableName, $columnName, $i18nRewrite = TRUE) {
- $query = "
-SHOW COLUMNS
-FROM $tableName
-LIKE %1
-";
- $params = array(1 => array($columnName, 'String'));
- $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, NULL, FALSE, $i18nRewrite);
- $result = $dao->fetch() ? TRUE : FALSE;
- $dao->free();
- return $result;
+ return CRM_Core_BAO_SchemaHandler::checkIfFieldExists($tableName, $columnName, $i18nRewrite);
}
/**
@@ -1091,6 +1108,29 @@ public function fetchAll() {
return $result;
}
+ /**
+ * Return the results as PHP generator.
+ *
+ * @param string $type
+ * Whether the generator yields 'dao' objects or 'array's.
+ */
+ public function fetchGenerator($type = 'dao') {
+ while ($this->fetch()) {
+ switch ($type) {
+ case 'dao':
+ yield $this;
+ break;
+
+ case 'array':
+ yield $this->toArray();
+ break;
+
+ default:
+ throw new \RuntimeException("Invalid record type ($type)");
+ }
+ }
+ }
+
/**
* Returns a singular value.
*
@@ -1995,6 +2035,8 @@ public static function setCreateDefaults(&$params, $defaults) {
* @param null $string
*
* @return string
+ * @deprecated
+ * @see CRM_Utils_SQL_TempTable
*/
public static function createTempTableName($prefix = 'civicrm', $addRandomString = TRUE, $string = NULL) {
$tableName = $prefix . "_temp";
@@ -2243,6 +2285,54 @@ public static function getReferencesToTable($tableName) {
return $refsFound;
}
+ /**
+ * Get all references to contact table.
+ *
+ * This includes core tables, custom group tables, tables added by the merge
+ * hook and the entity_tag table.
+ *
+ * Refer to CRM-17454 for information on the danger of querying the information
+ * schema to derive this.
+ */
+ public static function getReferencesToContactTable() {
+ if (isset(\Civi::$statics[__CLASS__]) && isset(\Civi::$statics[__CLASS__]['contact_references'])) {
+ return \Civi::$statics[__CLASS__]['contact_references'];
+ }
+ $contactReferences = [];
+ $coreReferences = CRM_Core_DAO::getReferencesToTable('civicrm_contact');
+ foreach ($coreReferences as $coreReference) {
+ if (!is_a($coreReference, 'CRM_Core_Reference_Dynamic')) {
+ $contactReferences[$coreReference->getReferenceTable()][] = $coreReference->getReferenceKey();
+ }
+ }
+ self::appendCustomTablesExtendingContacts($contactReferences);
+
+ // FixME for time being adding below line statically as no Foreign key constraint defined for table 'civicrm_entity_tag'
+ $contactReferences['civicrm_entity_tag'][] = 'entity_id';
+ \Civi::$statics[__CLASS__]['contact_references'] = $contactReferences;
+ return \Civi::$statics[__CLASS__]['contact_references'];
+ }
+
+ /**
+ * Add custom tables that extend contacts to the list of contact references.
+ *
+ * CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity seems like a safe-ish
+ * function to be sure all are retrieved & we don't miss subtypes or inactive or multiples
+ * - the down side is it is not cached.
+ *
+ * Further changes should be include tests in the CRM_Core_MergerTest class
+ * to ensure that disabled, subtype, multiple etc groups are still captured.
+ *
+ * @param array $cidRefs
+ */
+ public static function appendCustomTablesExtendingContacts(&$cidRefs) {
+ $customValueTables = CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity('Contact');
+ $customValueTables->find();
+ while ($customValueTables->fetch()) {
+ $cidRefs[$customValueTables->table_name] = array('entity_id');
+ }
+ }
+
/**
* Lookup the value of a MySQL global configuration variable.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionLog.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionLog.php
index 671e1542f8c..3958e5ff22f 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionLog.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionLog.php
@@ -200,6 +200,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Error?'),
'description' => 'Was there any error sending the reminder?',
+ 'default' => '0',
'table_name' => 'civicrm_action_log',
'entity' => 'ActionLog',
'bao' => 'CRM_Core_BAO_ActionLog',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionSchedule.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionSchedule.php
index 20d7fde9d3b..c7ee8457f1a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionSchedule.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/ActionSchedule.php
@@ -407,6 +407,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Start Action Offset'),
'description' => 'Reminder Interval.',
+ 'default' => '0',
'table_name' => 'civicrm_action_schedule',
'entity' => 'ActionSchedule',
'bao' => 'CRM_Core_BAO_ActionSchedule',
@@ -458,6 +459,7 @@ public static function &fields() {
'name' => 'is_repeat',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Repeat?'),
+ 'default' => '0',
'table_name' => 'civicrm_action_schedule',
'entity' => 'ActionSchedule',
'bao' => 'CRM_Core_BAO_ActionSchedule',
@@ -486,6 +488,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Repetition Frequency Interval'),
'description' => 'Time interval for repeating the reminder.',
+ 'default' => '0',
'table_name' => 'civicrm_action_schedule',
'entity' => 'ActionSchedule',
'bao' => 'CRM_Core_BAO_ActionSchedule',
@@ -514,6 +517,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('End Frequency Interval'),
'description' => 'Time interval till repeating the reminder.',
+ 'default' => '0',
'table_name' => 'civicrm_action_schedule',
'entity' => 'ActionSchedule',
'bao' => 'CRM_Core_BAO_ActionSchedule',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Address.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Address.php
index de15258fbf2..877496a9d59 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Address.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Address.php
@@ -311,6 +311,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Address Primary?'),
'description' => 'Is this the primary address.',
+ 'default' => '0',
'table_name' => 'civicrm_address',
'entity' => 'Address',
'bao' => 'CRM_Core_BAO_Address',
@@ -324,6 +325,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Billing Address'),
'description' => 'Is this the billing address.',
+ 'default' => '0',
'table_name' => 'civicrm_address',
'entity' => 'Address',
'bao' => 'CRM_Core_BAO_Address',
@@ -706,6 +708,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is manually geocoded'),
'description' => 'Is this a manually entered geo code',
+ 'default' => '0',
'table_name' => 'civicrm_address',
'entity' => 'Address',
'bao' => 'CRM_Core_BAO_Address',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Country.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Country.php
index 5823935f092..82af44c6856 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Country.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Country.php
@@ -227,6 +227,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Abbreviate Province?'),
'description' => 'Should state/province be displayed as abbreviation for contacts from this country?',
+ 'default' => '0',
'table_name' => 'civicrm_country',
'entity' => 'Country',
'bao' => 'CRM_Core_BAO_Country',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomField.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomField.php
index 1f48b8858fb..fea2e7e4c7d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomField.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomField.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/CustomField.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:dcb494bf3990ce63b66ef13ee47a2d15)
+ * (GenCodeChecksum:7f096c92af68ef9564675e3d708fbbe1)
*/
/**
@@ -377,6 +377,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Custom Field Is Required?'),
'description' => 'Is a value required for this property.',
+ 'default' => '0',
'table_name' => 'civicrm_custom_field',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
@@ -387,6 +388,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Allow Searching on Field?'),
'description' => 'Is this property searchable.',
+ 'default' => '0',
'table_name' => 'civicrm_custom_field',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
@@ -397,6 +399,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Search as a Range'),
'description' => 'Is this property range searchable.',
+ 'default' => '0',
'table_name' => 'civicrm_custom_field',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
@@ -486,6 +489,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Field is Viewable'),
'description' => 'Is this property set by PHP Code? A code field is viewable but not editable',
+ 'default' => '0',
'table_name' => 'civicrm_custom_field',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
@@ -594,6 +598,11 @@ public static function &fields() {
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
'localizable' => 0,
+ 'pseudoconstant' => [
+ 'table' => 'civicrm_option_group',
+ 'keyColumn' => 'id',
+ 'labelColumn' => 'title',
+ ]
],
'filter' => [
'name' => 'filter',
@@ -612,6 +621,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Field Display'),
'description' => 'Should the multi-record custom field values be displayed in tab table listing',
+ 'default' => '0',
'table_name' => 'civicrm_custom_field',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomGroup.php
index 93d82140553..9e014563bc5 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/CustomGroup.php
@@ -309,6 +309,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Collapse Custom Group?'),
'description' => 'Will this group be in collapsed or expanded mode on initial display ?',
+ 'default' => '0',
'table_name' => 'civicrm_custom_group',
'entity' => 'CustomGroup',
'bao' => 'CRM_Core_BAO_CustomGroup',
@@ -384,6 +385,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Supports Multiple Records'),
'description' => 'Does this group hold multiple values?',
+ 'default' => '0',
'table_name' => 'civicrm_custom_group',
'entity' => 'CustomGroup',
'bao' => 'CRM_Core_BAO_CustomGroup',
@@ -414,6 +416,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Collapse Group Display'),
'description' => 'Will this group be in collapsed or expanded mode on advanced search display ?',
+ 'default' => '0',
'table_name' => 'civicrm_custom_group',
'entity' => 'CustomGroup',
'bao' => 'CRM_Core_BAO_CustomGroup',
@@ -445,6 +448,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Reserved Group?'),
'description' => 'Is this a reserved Custom Group?',
+ 'default' => '0',
'table_name' => 'civicrm_custom_group',
'entity' => 'CustomGroup',
'bao' => 'CRM_Core_BAO_CustomGroup',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Dashboard.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Dashboard.php
index 3974eab19e4..634e0f34124 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Dashboard.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Dashboard.php
@@ -238,6 +238,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Dashlet Active?'),
'description' => 'Is this dashlet active?',
+ 'default' => '0',
'table_name' => 'civicrm_dashboard',
'entity' => 'Dashboard',
'bao' => 'CRM_Core_BAO_Dashboard',
@@ -248,6 +249,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Dashlet Reserved?'),
'description' => 'Is this dashlet reserved?',
+ 'default' => '0',
'table_name' => 'civicrm_dashboard',
'entity' => 'Dashboard',
'bao' => 'CRM_Core_BAO_Dashboard',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Email.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Email.php
index 7abc05f434d..9d7d24eba26 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Email.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Email.php
@@ -209,6 +209,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Primary email'),
'description' => 'Is this the primary?',
+ 'default' => '0',
'table_name' => 'civicrm_email',
'entity' => 'Email',
'bao' => 'CRM_Core_BAO_Email',
@@ -219,6 +220,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Billing Email?'),
'description' => 'Is this the billing?',
+ 'default' => '0',
'table_name' => 'civicrm_email',
'entity' => 'Email',
'bao' => 'CRM_Core_BAO_Email',
@@ -234,6 +236,7 @@ public static function &fields() {
'where' => 'civicrm_email.on_hold',
'headerPattern' => '',
'dataPattern' => '',
+ 'default' => '0',
'table_name' => 'civicrm_email',
'entity' => 'Email',
'bao' => 'CRM_Core_BAO_Email',
@@ -252,6 +255,7 @@ public static function &fields() {
'where' => 'civicrm_email.is_bulkmail',
'headerPattern' => '',
'dataPattern' => '',
+ 'default' => '0',
'table_name' => 'civicrm_email',
'entity' => 'Email',
'bao' => 'CRM_Core_BAO_Email',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/IM.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/IM.php
index dcdf67f176d..35a1b01d9eb 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/IM.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/IM.php
@@ -190,6 +190,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is IM Primary?'),
'description' => 'Is this the primary IM for this contact and location.',
+ 'default' => '0',
'table_name' => 'civicrm_im',
'entity' => 'IM',
'bao' => 'CRM_Core_BAO_IM',
@@ -200,6 +201,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is IM Billing?'),
'description' => 'Is this the billing?',
+ 'default' => '0',
'table_name' => 'civicrm_im',
'entity' => 'IM',
'bao' => 'CRM_Core_BAO_IM',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/MessageTemplate.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/MessageTemplate.php
index 93d2b0ec7ec..90beadc0aac 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/MessageTemplate.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/MessageTemplate.php
@@ -224,6 +224,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Message Template is used for SMS?'),
'description' => 'Is this message template used for sms?',
+ 'default' => '0',
'table_name' => 'civicrm_msg_template',
'entity' => 'MessageTemplate',
'bao' => 'CRM_Core_BAO_MessageTemplate',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OpenID.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OpenID.php
index 90569e58f06..0033e3f37e2 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OpenID.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OpenID.php
@@ -157,6 +157,7 @@ public static function &fields() {
'title' => ts('Allowed to login?'),
'description' => 'Whether or not this user is allowed to login',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_openid',
'entity' => 'OpenID',
'bao' => 'CRM_Core_BAO_OpenID',
@@ -167,6 +168,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is OpenID Primary?'),
'description' => 'Is this the primary email for this contact and location.',
+ 'default' => '0',
'table_name' => 'civicrm_openid',
'entity' => 'OpenID',
'bao' => 'CRM_Core_BAO_OpenID',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionGroup.php
index aed6b231675..3f470ce1a5e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionGroup.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/OptionGroup.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:4f26b702ecd914e653257f0676896d87)
+ * (GenCodeChecksum:2fd99e11712c8619f29a79b062cf7612)
*/
/**
@@ -168,6 +168,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Option Group Is Reserved?'),
'description' => 'Is this a predefined system option group (i.e. it can not be deleted)?',
+ 'required' => TRUE,
'default' => '1',
'table_name' => 'civicrm_option_group',
'entity' => 'OptionGroup',
@@ -179,6 +180,8 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Option Group Is Active?'),
'description' => 'Is this option group active?',
+ 'required' => TRUE,
+ 'default' => '1',
'table_name' => 'civicrm_option_group',
'entity' => 'OptionGroup',
'bao' => 'CRM_Core_BAO_OptionGroup',
@@ -189,6 +192,8 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Option Group Is Locked'),
'description' => 'A lock to remove the ability to add new options via the UI.',
+ 'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_option_group',
'entity' => 'OptionGroup',
'bao' => 'CRM_Core_BAO_OptionGroup',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionValue.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionValue.php
index 1875c752131..dbf7059bb18 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionValue.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/OptionValue.php
@@ -286,6 +286,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Option is Default?'),
'description' => 'Is this the default option for the group?',
+ 'default' => '0',
'table_name' => 'civicrm_option_value',
'entity' => 'OptionValue',
'bao' => 'CRM_Core_BAO_OptionValue',
@@ -322,6 +323,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Option is Header?'),
'description' => 'Is this row simply a display header? Expected usage is to render these as OPTGROUP tags within a SELECT field list of options?',
+ 'default' => '0',
'table_name' => 'civicrm_option_value',
'entity' => 'OptionValue',
'bao' => 'CRM_Core_BAO_OptionValue',
@@ -332,6 +334,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Option Is Reserved?'),
'description' => 'Is this a predefined system object?',
+ 'default' => '0',
'table_name' => 'civicrm_option_value',
'entity' => 'OptionValue',
'bao' => 'CRM_Core_BAO_OptionValue',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Persistent.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Persistent.php
index b6cdf47d6d4..43954d583fa 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Persistent.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Persistent.php
@@ -132,6 +132,7 @@ public static function &fields() {
'title' => ts('Is Configuration?'),
'description' => 'Config Settings',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_persistent',
'entity' => 'Persistent',
'bao' => 'CRM_Core_BAO_Persistent',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Phone.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Phone.php
index 013b416c940..660ca3f0527 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Phone.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Phone.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/Phone.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:661faad4886dd1a40784d465b906f447)
+ * (GenCodeChecksum:22802e5d7d8dfce93626004aaf6cd2e2)
*/
/**
@@ -174,6 +174,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Phone Primary?'),
'description' => 'Is this the primary phone for this contact and location.',
+ 'default' => '0',
'table_name' => 'civicrm_phone',
'entity' => 'Phone',
'bao' => 'CRM_Core_BAO_Phone',
@@ -184,6 +185,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Billing Phone'),
'description' => 'Is this the billing?',
+ 'default' => '0',
'table_name' => 'civicrm_phone',
'entity' => 'Phone',
'bao' => 'CRM_Core_BAO_Phone',
@@ -256,6 +258,10 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Phone Type'),
'description' => 'Which type of phone does this number belongs.',
+ 'export' => TRUE,
+ 'where' => 'civicrm_phone.phone_type_id',
+ 'headerPattern' => '',
+ 'dataPattern' => '',
'table_name' => 'civicrm_phone',
'entity' => 'Phone',
'bao' => 'CRM_Core_BAO_Phone',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/PrevNextCache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/PrevNextCache.php
index 26a8d919606..bc01e75e1c9 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/PrevNextCache.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/PrevNextCache.php
@@ -160,6 +160,7 @@ public static function &fields() {
'name' => 'is_selected',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Selected'),
+ 'default' => '0',
'table_name' => 'civicrm_prevnext_cache',
'entity' => 'PrevNextCache',
'bao' => 'CRM_Core_BAO_PrevNextCache',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Tag.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Tag.php
index df103628dad..14160e2496f 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Tag.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/Tag.php
@@ -194,6 +194,7 @@ public static function &fields() {
'name' => 'is_reserved',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Reserved'),
+ 'default' => '0',
'table_name' => 'civicrm_tag',
'entity' => 'Tag',
'bao' => 'CRM_Core_BAO_Tag',
@@ -203,6 +204,7 @@ public static function &fields() {
'name' => 'is_tagset',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Tagset'),
+ 'default' => '0',
'table_name' => 'civicrm_tag',
'entity' => 'Tag',
'bao' => 'CRM_Core_BAO_Tag',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFField.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFField.php
index bd5a61dab55..b560e442ed3 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFField.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFField.php
@@ -253,6 +253,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Profile Is View Only'),
'description' => 'the field is view only and not editable in user forms.',
+ 'default' => '0',
'table_name' => 'civicrm_uf_field',
'entity' => 'UFField',
'bao' => 'CRM_Core_BAO_UFField',
@@ -263,6 +264,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Profile Field Is Required'),
'description' => 'Is this field required when included in a user or registration form?',
+ 'default' => '0',
'table_name' => 'civicrm_uf_field',
'entity' => 'UFField',
'bao' => 'CRM_Core_BAO_UFField',
@@ -324,6 +326,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Profile Field Is a Filter'),
'description' => 'Is this field included as a column in the selector table?',
+ 'default' => '0',
'table_name' => 'civicrm_uf_field',
'entity' => 'UFField',
'bao' => 'CRM_Core_BAO_UFField',
@@ -334,6 +337,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Profile Field Is Searchable'),
'description' => 'Is this field included search form of profile?',
+ 'default' => '0',
'table_name' => 'civicrm_uf_field',
'entity' => 'UFField',
'bao' => 'CRM_Core_BAO_UFField',
@@ -410,6 +414,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Profile Field Supports Multiple'),
'description' => 'Include in multi-record listing?',
+ 'default' => '0',
'table_name' => 'civicrm_uf_field',
'entity' => 'UFField',
'bao' => 'CRM_Core_BAO_UFField',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFGroup.php
index c0b5d43b477..6605de613ca 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/DAO/UFGroup.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/UFGroup.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a6776694df1be240b3f7be798792175d)
+ * (GenCodeChecksum:a48f9522d0bd2e1d485064ebfc66f9a2)
*/
/**
@@ -208,6 +208,13 @@ class CRM_Core_DAO_UFGroup extends CRM_Core_DAO {
*/
public $submit_button_text;
+ /**
+ * Should a Cancel button be included in this Profile form.
+ *
+ * @var boolean
+ */
+ public $add_cancel_button;
+
/**
* Class constructor.
*/
@@ -390,6 +397,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Show Captcha On Profile'),
'description' => 'Should a CAPTCHA widget be included this Profile form.',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -400,6 +408,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Map Profile'),
'description' => 'Do we want to map results from this profile.',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -410,6 +419,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Show Edit Link?'),
'description' => 'Should edit link display in profile selector',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -420,6 +430,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Show Link to CMS User'),
'description' => 'Should we display a link to the website profile in profile selector',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -430,6 +441,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Update on Duplicate'),
'description' => 'Should we update the contact record if we find a duplicate',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -452,6 +464,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Create CMS User?'),
'description' => 'Should we create a cms user for this profile ',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -514,6 +527,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Include Proximity Search?'),
'description' => 'Should we include proximity search feature in this profile search form?',
+ 'default' => '0',
'table_name' => 'civicrm_uf_group',
'entity' => 'UFGroup',
'bao' => 'CRM_Core_BAO_UFGroup',
@@ -545,6 +559,17 @@ public static function &fields() {
'bao' => 'CRM_Core_BAO_UFGroup',
'localizable' => 1,
],
+ 'add_cancel_button' => [
+ 'name' => 'add_cancel_button',
+ 'type' => CRM_Utils_Type::T_BOOLEAN,
+ 'title' => ts('Include Cancel Button'),
+ 'description' => 'Should a Cancel button be included in this Profile form.',
+ 'default' => '1',
+ 'table_name' => 'civicrm_uf_group',
+ 'entity' => 'UFGroup',
+ 'bao' => 'CRM_Core_BAO_UFGroup',
+ 'localizable' => 0,
+ ],
];
CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form.php
index 113411d7ff8..70e560494a7 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form.php
@@ -179,6 +179,29 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
*/
public $urlPath = array();
+ /**
+ * Context of the form being loaded.
+ *
+ * 'event' or null
+ *
+ * @var string
+ */
+ protected $context;
+
+ /**
+ * @return string
+ */
+ public function getContext() {
+ return $this->context;
+ }
+
+ /**
+ * Set context variable.
+ */
+ public function setContext() {
+ $this->context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
+ }
+
/**
* @var CRM_Core_Controller
*/
@@ -1566,6 +1589,7 @@ public function addField($name, $props = array(), $required = FALSE, $legacyDate
return $this->addEntityRef($name, $label, $props, $required);
case 'Password':
+ $props['size'] = isset($props['size']) ? $props['size'] : 60;
return $this->add('password', $name, $label, $props, $required);
// Check datatypes of fields
@@ -1845,7 +1869,7 @@ public function addCurrency(
$setDefaultCurrency = TRUE
) {
$currencies = CRM_Core_OptionGroup::values('currencies_enabled');
- if (!array_key_exists($defaultCurrency, $currencies)) {
+ if (!empty($defaultCurrency) && !array_key_exists($defaultCurrency, $currencies)) {
Civi::log()->warning('addCurrency: Currency ' . $defaultCurrency . ' is disabled but still in use!');
$currencies[$defaultCurrency] = $defaultCurrency;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/EntityFormTrait.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/EntityFormTrait.php
index 564edf6754e..f0031490f3e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/EntityFormTrait.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/EntityFormTrait.php
@@ -131,6 +131,47 @@ protected function addFormButtons() {
}
}
+ /**
+ * Get the defaults for the entity.
+ */
+ protected function getEntityDefaults() {
+ $defaults = [];
+ if ($this->_action != CRM_Core_Action::DELETE &&
+ $this->getEntityId()
+ ) {
+ $params = ['id' => $this->getEntityId()];
+ $baoName = $this->_BAOName;
+ $baoName::retrieve($params, $defaults);
+ }
+ foreach ($this->entityFields as $fieldSpec) {
+ $value = CRM_Utils_Request::retrieveValue($fieldSpec['name'], $this->getValidationTypeForField($fieldSpec['name']));
+ if ($value !== FALSE) {
+ $defaults[$fieldSpec['name']] = $value;
+ }
+ }
+ return $defaults;
+ }
+
+ /**
+ * Get the validation rule to apply to a function.
+ *
+ * Alphanumeric is designed to always be safe & for now we just return
+ * that but in future we can use tighter rules for types like int, bool etc.
+ *
+ * @param string $fieldName
+ *
+ * @return string|int|bool
+ */
+ protected function getValidationTypeForField($fieldName) {
+ switch ($this->metadata[$fieldName]['type']) {
+ case CRM_Utils_Type::T_BOOLEAN:
+ return 'Boolean';
+
+ default:
+ return 'Alphanumeric';
+ }
+ }
+
/**
* Set translated fields.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/Task.php
index 2a487ba70f1..7eea0555c59 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Form/Task.php
@@ -56,6 +56,11 @@ abstract class CRM_Core_Form_Task extends CRM_Core_Form {
*/
protected $_componentIds;
+ /**
+ * @var int
+ */
+ protected $queryMode;
+
/**
* The array that holds all the case ids
*
@@ -70,9 +75,18 @@ abstract class CRM_Core_Form_Task extends CRM_Core_Form {
*/
public $_contactIds;
- // Must be set to entity table name (eg. civicrm_participant) by child class
+ /**
+ * Must be set to entity table name (eg. civicrm_participant) by child class
+ *
+ * @var string
+ */
static $tableName = NULL;
- // Must be set to entity shortname (eg. event)
+
+ /**
+ * Must be set to entity shortname (eg. event)
+ *
+ * @var string
+ */
static $entityShortname = NULL;
/**
@@ -87,26 +101,25 @@ public function preProcess() {
/**
* Common pre-processing function.
*
- * @param CRM_Core_Form $form
- * @param bool $useTable FIXME This parameter could probably be deprecated as it's not used here
+ * @param CRM_Core_Form_Task $form
*
* @throws \CRM_Core_Exception
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_entityIds = array();
- $values = $form->controller->exportValues($form->get('searchFormName'));
+ $searchFormValues = $form->controller->exportValues($form->get('searchFormName'));
- $form->_task = $values['task'];
+ $form->_task = $searchFormValues['task'];
$className = 'CRM_' . ucfirst($form::$entityShortname) . '_Task';
$entityTasks = $className::tasks();
$form->assign('taskName', $entityTasks[$form->_task]);
- $ids = array();
- if ($values['radio_ts'] == 'ts_sel') {
- foreach ($values as $name => $value) {
+ $entityIds = array();
+ if ($searchFormValues['radio_ts'] == 'ts_sel') {
+ foreach ($searchFormValues as $name => $value) {
if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) {
- $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
+ $entityIds[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
}
}
}
@@ -117,24 +130,22 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
$sortOrder = $form->get(CRM_Utils_Sort::SORT_ORDER);
}
- $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE,
- CRM_Contact_BAO_Query::MODE_CASE
- );
+ $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE, $form->getQueryMode());
$query->_distinctComponentClause = " ( " . $form::$tableName . ".id )";
$query->_groupByComponentClause = " GROUP BY " . $form::$tableName . ".id ";
$result = $query->searchQuery(0, 0, $sortOrder);
$selector = $form::$entityShortname . '_id';
while ($result->fetch()) {
- $ids[] = $result->$selector;
+ $entityIds[] = $result->$selector;
}
}
- if (!empty($ids)) {
- $form->_componentClause = ' ' . $form::$tableName . '.id IN ( ' . implode(',', $ids) . ' ) ';
- $form->assign('totalSelected' . ucfirst($form::$entityShortname) . 's', count($ids));
+ if (!empty($entityIds)) {
+ $form->_componentClause = ' ' . $form::$tableName . '.id IN ( ' . implode(',', $entityIds) . ' ) ';
+ $form->assign('totalSelected' . ucfirst($form::$entityShortname) . 's', count($entityIds));
}
- $form->_entityIds = $form->_componentIds = $ids;
+ $form->_entityIds = $form->_componentIds = $entityIds;
// Some functions (eg. PDF letter tokens) rely on Ids being in specific fields rather than the generic $form->_entityIds
// So we set that specific field here (eg. for cases $form->_caseIds = $form->_entityIds).
@@ -197,4 +208,14 @@ public function addDefaultButtons($title, $nextType = 'next', $backType = 'back'
);
}
+ /**
+ * Get the query mode (eg. CRM_Core_BAO_Query::MODE_CASE)
+ * Should be overridden by child classes in most cases
+ *
+ * @return int
+ */
+ public function getQueryMode() {
+ return $this->queryMode ?: CRM_Contact_BAO_Query::MODE_CONTACTS;
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/I18n/Schema.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/I18n/Schema.php
index 9d72908401e..71627d76d4b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/I18n/Schema.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/I18n/Schema.php
@@ -265,7 +265,7 @@ public static function addLocale($locale, $source) {
// add new columns
foreach ($hash as $column => $type) {
// CRM-7854: skip existing columns
- if (CRM_Core_DAO::checkFieldExists($table, "{$column}_{$locale}", FALSE)) {
+ if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, "{$column}_{$locale}", FALSE)) {
continue;
}
$queries[] = "ALTER TABLE {$table} ADD {$column}_{$locale} {$type}";
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Invoke.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Invoke.php
index e5edcd82c95..eb2bef51af7 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Invoke.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Invoke.php
@@ -350,7 +350,7 @@ public static function statusCheck($template) {
return;
}
// always use cached results - they will be refreshed by the session timer
- $status = Civi::settings()->get('systemStatusCheckResult');
+ $status = Civi::cache('checks')->get('systemStatusCheckResult');
$template->assign('footer_status_severity', $status);
$template->assign('footer_status_message', CRM_Utils_Check::toStatusLabel($status));
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/JobManager.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/JobManager.php
index e7008ea6451..fccfc18b8cf 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/JobManager.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/JobManager.php
@@ -141,12 +141,15 @@ public function executeJob($job) {
$params = $job->apiParams;
}
+ CRM_Utils_Hook::preJob($job, $params);
try {
$result = civicrm_api($job->api_entity, $job->api_action, $params);
}
catch (Exception$e) {
$this->logEntry('Error while executing ' . $job->name . ': ' . $e->getMessage());
+ $result = $e;
}
+ CRM_Utils_Hook::postJob($job, $params, $result);
$this->logEntry('Finished execution of ' . $job->name . ' with result: ' . $this->_apiResultToMessage($result));
$this->currentJob = FALSE;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Menu.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Menu.php
index c7c09043550..58c9904d061 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Menu.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Menu.php
@@ -317,7 +317,7 @@ public static function store($truncate = TRUE) {
$menu->find(TRUE);
if (!CRM_Core_Config::isUpgradeMode() ||
- CRM_Core_DAO::checkFieldExists('civicrm_menu', 'module_data', FALSE)
+ CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_menu', 'module_data', FALSE)
) {
// Move unrecognized fields to $module_data.
$module_data = array();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionGroup.php
index bc1f7ad2ac8..c7e07e67d61 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionGroup.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionGroup.php
@@ -200,8 +200,8 @@ protected static function flushValues($name, $flip, $grouping, $localize, $condi
/**
* @return string
*/
- protected static function createCacheKey() {
- $cacheKey = "CRM_OG_" . serialize(func_get_args());
+ protected static function createCacheKey($id) {
+ $cacheKey = "CRM_OG_" . preg_replace('/[^a-zA-Z0-9]/', '', $id) . '_' . md5(serialize(func_get_args()));
return $cacheKey;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionValue.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionValue.php
index 27a1a756f07..4b1e5105ba2 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionValue.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/OptionValue.php
@@ -187,7 +187,7 @@ public static function getRows($groupParams, $links, $orderBy = 'weight', $skipE
*
* @param array $params
* Array containing exported values from the invoking form.
- * @param array $groupParams
+ * @param string $optionGroupName
* Array containing group fields whose option-values is to retrieved/saved.
* @param $action
* @param int $optionValueID Has the id of the optionValue being edited, disabled ..etc.
@@ -196,22 +196,17 @@ public static function getRows($groupParams, $links, $orderBy = 'weight', $skipE
* @return CRM_Core_DAO_OptionValue
*
*/
- public static function addOptionValue(&$params, &$groupParams, $action, $optionValueID) {
+ public static function addOptionValue(&$params, $optionGroupName, $action, $optionValueID) {
$params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
// checking if the group name with the given id or name (in $groupParams) exists
- if (!empty($groupParams)) {
- $config = CRM_Core_Config::singleton();
- $groupParams['is_active'] = 1;
- $optionGroup = CRM_Core_BAO_OptionGroup::retrieve($groupParams, $defaults);
- }
+ $groupParams = ['name' => $optionGroupName, 'is_active' => 1];
+ $optionGroup = CRM_Core_BAO_OptionGroup::retrieve($groupParams, $defaults);
- // if the corresponding group doesn't exist, create one, provided $groupParams has 'name' in it.
+ // if the corresponding group doesn't exist, create one.
if (!$optionGroup->id) {
- if ($groupParams['name']) {
- $newOptionGroup = CRM_Core_BAO_OptionGroup::add($groupParams, $defaults);
- $params['weight'] = 1;
- $optionGroupID = $newOptionGroup->id;
- }
+ $newOptionGroup = CRM_Core_BAO_OptionGroup::add($groupParams);
+ $params['weight'] = 1;
+ $optionGroupID = $newOptionGroup->id;
}
else {
$optionGroupID = $optionGroup->id;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment.php
index 8626cd790de..b686cd8501a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment.php
@@ -682,7 +682,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'text',
'name' => 'credit_card_number',
'title' => ts('Card Number'),
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 20,
'maxlength' => 20,
@@ -695,7 +694,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'text',
'name' => 'cvv2',
'title' => ts('Security Code'),
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 5,
'maxlength' => 10,
@@ -714,7 +712,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'date',
'name' => 'credit_card_exp_date',
'title' => ts('Expiration Date'),
- 'cc_field' => TRUE,
'attributes' => CRM_Core_SelectValues::date('creditCard'),
'is_required' => TRUE,
'rules' => array(
@@ -729,7 +726,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'select',
'name' => 'credit_card_type',
'title' => ts('Card Type'),
- 'cc_field' => TRUE,
'attributes' => $creditCardType,
'is_required' => FALSE,
),
@@ -737,7 +733,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'text',
'name' => 'account_holder',
'title' => ts('Account Holder'),
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 20,
'maxlength' => 34,
@@ -750,7 +745,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'text',
'name' => 'bank_account_number',
'title' => ts('Bank Account Number'),
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 20,
'maxlength' => 34,
@@ -770,7 +764,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'text',
'name' => 'bank_identification_number',
'title' => ts('Bank Identification Number'),
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 20,
'maxlength' => 11,
@@ -789,7 +782,6 @@ public function getPaymentFormFieldsMetadata() {
'htmlType' => 'text',
'name' => 'bank_name',
'title' => ts('Bank Name'),
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 20,
'maxlength' => 64,
@@ -803,7 +795,6 @@ public function getPaymentFormFieldsMetadata() {
'name' => 'check_number',
'title' => ts('Check Number'),
'is_required' => FALSE,
- 'cc_field' => TRUE,
'attributes' => NULL,
),
'pan_truncation' => array(
@@ -811,7 +802,6 @@ public function getPaymentFormFieldsMetadata() {
'name' => 'pan_truncation',
'title' => ts('Last 4 digits of the card'),
'is_required' => FALSE,
- 'cc_field' => TRUE,
'attributes' => array(
'size' => 4,
'maxlength' => 4,
@@ -826,6 +816,13 @@ public function getPaymentFormFieldsMetadata() {
),
),
),
+ 'payment_token' => array(
+ 'htmlType' => 'hidden',
+ 'name' => 'payment_token',
+ 'title' => ts('Authorization token'),
+ 'is_required' => FALSE,
+ 'attributes' => ['size' => 10, 'autocomplete' => 'off', 'id' => 'payment_token'],
+ ),
);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php
index 2696e2a1abb..e350195886a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php
@@ -77,7 +77,7 @@ public function main($component = 'contribute') {
// processor id & the handleNotification function (which should call the completetransaction api & by-pass this
// entirely). The only thing the IPN class should really do is extract data from the request, validate it
// & call completetransaction or call fail? (which may not exist yet).
- Civi::log()->warning('Unreliable method used for AuthNet IPN - this will cause problems if you have more than one instance');
+ Civi::log()->warning('Unreliable method used to get payment_processor_id for AuthNet IPN - this will cause problems if you have more than one instance');
$paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
'AuthNet', 'id', 'name'
);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/Form.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/Form.php
index 05de148e824..60e946d7dd0 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/Form.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/Form.php
@@ -68,8 +68,7 @@ static public function setPaymentFieldsByProcessor(&$form, $processor, $billing_
$processor['object']->setPaymentInstrumentID($paymentInstrumentID);
$paymentTypeName = self::getPaymentTypeName($processor);
$form->assign('paymentTypeName', $paymentTypeName);
- $paymentTypeLabel = self::getPaymentTypeLabel($processor);
- $form->assign('paymentTypeLabel', $paymentTypeLabel);
+ $form->assign('paymentTypeLabel', self::getPaymentLabel($processor['object']));
$form->assign('isBackOffice', $isBackOffice);
$form->_paymentFields = $form->billingFieldSets[$paymentTypeName]['fields'] = self::getPaymentFieldMetadata($processor);
$form->_paymentFields = array_merge($form->_paymentFields, self::getBillingAddressMetadata($processor, $form->_bltID));
@@ -116,24 +115,22 @@ static protected function setBillingAddressFields(&$form, $processor) {
protected static function addCommonFields(&$form, $paymentFields) {
$requiredPaymentFields = array();
foreach ($paymentFields as $name => $field) {
- // @todo - remove the cc_field check - no longer useful.
- if (!empty($field['cc_field'])) {
- if ($field['htmlType'] == 'chainSelect') {
- $form->addChainSelect($field['name'], array('required' => FALSE));
- }
- else {
- $form->add($field['htmlType'],
- $field['name'],
- $field['title'],
- $field['attributes'],
- FALSE
- );
- }
+ if ($field['htmlType'] == 'chainSelect') {
+ $form->addChainSelect($field['name'], array('required' => FALSE));
+ }
+ else {
+ $form->add($field['htmlType'],
+ $field['name'],
+ $field['title'],
+ $field['attributes'],
+ FALSE
+ );
}
// This will cause the fields to be marked as required - but it is up to the payment processor to
// validate it.
$requiredPaymentFields[$field['name']] = $field['is_required'];
}
+
$form->assign('requiredPaymentFields', $requiredPaymentFields);
}
@@ -207,7 +204,7 @@ public static function getPaymentTypeName($paymentProcessor) {
* @return string
*/
public static function getPaymentTypeLabel($paymentProcessor) {
- return ts(($paymentProcessor['object']->getPaymentTypeLabel()) . ' Information');
+ return ts('%1 Information', [$paymentProcessor->getPaymentTypeLabel()]);
}
/**
@@ -426,4 +423,25 @@ public static function getCreditCardExpirationYear($src) {
return CRM_Utils_Array::value('Y', $src['credit_card_exp_date']);
}
+ /**
+ * Get the label for the processor.
+ *
+ * We do not use a label if there are no enterable fields.
+ *
+ * @param \CRM_Core_Payment $processor
+ *
+ * @return string
+ */
+ public static function getPaymentLabel($processor) {
+ $isVisible = FALSE;
+ $paymentTypeLabel = self::getPaymentTypeLabel($processor);
+ foreach (self::getPaymentFieldMetadata(['object' => $processor]) as $paymentField) {
+ if ($paymentField['htmlType'] !== 'hidden') {
+ $isVisible = TRUE;
+ }
+ }
+ return $isVisible ? $paymentTypeLabel : '';
+
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalIPN.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalIPN.php
index 0100ca27d54..fa4f164a420 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalIPN.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Core/Payment/PayPalIPN.php
@@ -29,7 +29,6 @@
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2018
- * $Id$
*
*/
class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
@@ -52,7 +51,7 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
* @throws CRM_Core_Exception
*/
public function __construct($inputData) {
- //CRM-19676
+ // CRM-19676
$params = (!empty($inputData['custom'])) ?
array_merge($inputData, json_decode($inputData['custom'], TRUE)) :
$inputData;
@@ -62,47 +61,46 @@ public function __construct($inputData) {
/**
* @param string $name
- * @param $type
+ * @param string $type
* @param bool $abort
*
* @return mixed
+ * @throws \CRM_Core_Exception
*/
public function retrieve($name, $type, $abort = TRUE) {
- static $store = NULL;
- $value = CRM_Utils_Type::validate(
- CRM_Utils_Array::value($name, $this->_inputParameters),
- $type,
- FALSE
- );
+ $value = CRM_Utils_Type::validate(CRM_Utils_Array::value($name, $this->_inputParameters), $type, FALSE);
if ($abort && $value === NULL) {
- CRM_Core_Error::debug_log_message("Could not find an entry for $name");
+ Civi::log()->debug("PayPalIPN: Could not find an entry for $name");
echo "Failure: Missing Parameter
'
);
+ // if empty option group freeze the option type.
+ if ($emptyOptGroup) {
+ $element->freeze();
+ }
$contactGroups = CRM_Core_PseudoConstant::group();
asort($contactGroups);
@@ -370,11 +387,6 @@ public function buildQuickForm() {
$this->add('hidden', 'filter_selected', 'Group', array('id' => 'filter_selected'));
- //if empty option group freeze the option type.
- if ($emptyOptGroup) {
- $element->freeze();
- }
-
// form fields of Custom Option rows
$defaultOption = array();
$_showHide = new CRM_Core_ShowHideBlocks('', '');
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Group.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Group.php
index 90b6947adb6..6139759f17e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Group.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Group.php
@@ -115,11 +115,10 @@ public static function formRule($fields, $files, $self) {
//validate group title as well as name.
$title = $fields['title'];
$name = CRM_Utils_String::munge($title, '_', 64);
- $query = 'select count(*) from civicrm_custom_group where ( name like %1 OR title like %2 ) and id != %3';
+ $query = 'select count(*) from civicrm_custom_group where ( name like %1) and id != %2';
$grpCnt = CRM_Core_DAO::singleValueQuery($query, array(
1 => array($name, 'String'),
- 2 => array($title, 'String'),
- 3 => array((int) $self->_id, 'Integer'),
+ 2 => array((int) $self->_id, 'Integer'),
));
if ($grpCnt) {
$errors['title'] = ts('Custom group \'%1\' already exists in Database.', array(1 => $title));
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Preview.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Preview.php
index b068f147c18..5264207a103 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Preview.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Custom/Form/Preview.php
@@ -109,7 +109,7 @@ public function setDefaultValues() {
* @return void
*/
public function buildQuickForm() {
- if (is_array($this->_groupTree[$this->_groupId])) {
+ if (is_array($this->_groupTree) && !empty($this->_groupTree[$this->_groupId])) {
foreach ($this->_groupTree[$this->_groupId]['fields'] as & $field) {
//add the form elements
CRM_Core_BAO_CustomField::addQuickFormElement($this, $field['element_name'], $field['id'], CRM_Utils_Array::value('is_required', $field));
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Cxn/CiviCxnHttp.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Cxn/CiviCxnHttp.php
index f2b2c6357c8..0d6024812cc 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Cxn/CiviCxnHttp.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Cxn/CiviCxnHttp.php
@@ -54,7 +54,7 @@ public function send($verb, $url, $blob, $headers = array()) {
$lowVerb = strtolower($verb);
if ($lowVerb === 'get' && $this->cache) {
- $cachePath = 'get/' . md5($url);
+ $cachePath = 'get_' . md5($url);
$cacheLine = $this->cache->get($cachePath);
if ($cacheLine && $cacheLine['expires'] > CRM_Utils_Time::getTimeRaw()) {
return $cacheLine['data'];
@@ -66,7 +66,7 @@ public function send($verb, $url, $blob, $headers = array()) {
if ($lowVerb === 'get' && $this->cache) {
$expires = CRM_Utils_Http::parseExpiration($result[0]);
if ($expires !== NULL) {
- $cachePath = 'get/' . md5($url);
+ $cachePath = 'get_' . md5($url);
$cacheLine = array(
'url' => $url,
'expires' => $expires,
@@ -106,4 +106,11 @@ protected function createStreamOpts($verb, $url, $blob, $headers) {
return $result;
}
+ /**
+ * @return \CRM_Utils_Cache_Interface|null
+ */
+ public function getCache() {
+ return $this->cache;
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/Blog.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/Blog.php
index 23cac0abf75..3416d186601 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/Blog.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/Blog.php
@@ -73,27 +73,21 @@ public function run() {
* @return array
*/
protected function getData() {
- // Fetch data from cache
- $cache = CRM_Core_DAO::executeQuery("SELECT data, created_date FROM civicrm_cache
- WHERE group_name = 'dashboard' AND path = 'newsfeed'");
- if ($cache->fetch()) {
- $expire = time() - (60 * 60 * 24 * self::CACHE_DAYS);
- // Refresh data after CACHE_DAYS
- if (strtotime($cache->created_date) < $expire) {
- $new_data = $this->getFeeds();
- // If fetching the new rss feed was successful, return it
- // Otherwise use the old cached data - it's better than nothing
- if ($new_data) {
- return $new_data;
- }
+ $value = Civi::cache('community_messages')->get('dashboard_newsfeed');
+
+ if (!$value) {
+ $value = $this->getFeeds();
+
+ if ($value) {
+ Civi::cache('community_messages')->set('dashboard_newsfeed', $value, (60 * 60 * 24 * self::CACHE_DAYS));
}
- return unserialize($cache->data);
}
- return $this->getFeeds();
+
+ return $value;
}
/**
- * Fetch all feeds & cache results.
+ * Fetch all feeds.
*
* @return array
*/
@@ -104,7 +98,6 @@ protected function getFeeds() {
return array();
}
$feeds = $this->formatItems($newsFeed);
- CRM_Core_BAO_Cache::setItem($feeds, 'dashboard', 'newsfeed');
return $feeds;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/GettingStarted.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/GettingStarted.php
index cb77b45cff3..18e3e89d3c8 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/GettingStarted.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Dashlet/Page/GettingStarted.php
@@ -87,27 +87,21 @@ public function run() {
* @return array
*/
private function _gettingStarted() {
- // Fetch data from cache
- $cache = CRM_Core_DAO::executeQuery("SELECT data, created_date FROM civicrm_cache
- WHERE group_name = 'dashboard' AND path = 'gettingStarted'");
- if ($cache->fetch()) {
- $expire = time() - (60 * 60 * 24 * self::CACHE_DAYS);
- // Refresh data after CACHE_DAYS
- if (strtotime($cache->created_date) < $expire) {
- $new_data = $this->_getHtml($this->gettingStartedUrl());
- // If fetching the new html was successful, return it
- // Otherwise use the old cached data - it's better than nothing
- if ($new_data) {
- return $new_data;
- }
+ $value = Civi::cache('community_messages')->get('dashboard_gettingStarted');
+
+ if (!$value) {
+ $value = $this->_getHtml($this->gettingStartedUrl());
+
+ if ($value) {
+ Civi::cache('community_messages')->set('dashboard_gettingStarted', $value, (60 * 60 * 24 * self::CACHE_DAYS));
}
- return unserialize($cache->data);
}
- return $this->_getHtml($this->gettingStartedUrl());
+
+ return $value;
}
/**
- * Get html and cache results.
+ * Get html.
*
* @param $url
*
@@ -115,18 +109,15 @@ private function _gettingStarted() {
* array of gettingStarted items; or NULL if not available
*/
public function _getHtml($url) {
-
$httpClient = new CRM_Utils_HttpClient(self::CHECK_TIMEOUT);
list ($status, $html) = $httpClient->get($url);
+
if ($status !== CRM_Utils_HttpClient::STATUS_OK) {
return NULL;
}
$tokensList = CRM_Utils_Token::getTokens($html);
$this->replaceLinkToken($tokensList, $html);
- if ($html) {
- CRM_Core_BAO_Cache::setItem($html, 'dashboard', 'gettingStarted');
- }
return $html;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Dedupe/Merger.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Dedupe/Merger.php
index a2fe7e71874..afb53df5f54 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Dedupe/Merger.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Dedupe/Merger.php
@@ -203,35 +203,23 @@ public static function getActiveRelTables($cid) {
/**
* Get array tables and fields that reference civicrm_contact.id.
*
- * This includes core tables, custom group tables, tables added by the merge
- * hook and (somewhat randomly) the entity_tag table.
+ * This function calls the merge hook and only exists to wrap the DAO function to support that deprecated call.
+ * The entityTypes hook is the recommended way to add tables to this result.
*
- * Refer to CRM-17454 for information on the danger of querying the information
- * schema to derive this.
- *
- * This function calls the merge hook but the entityTypes hook is the recommended
- * way to add tables to this result.
+ * I thought about adding another hook to alter tableReferences but decided it was unclear if there
+ * are use cases not covered by entityTables and instead we should wait & see.
*/
public static function cidRefs() {
if (isset(\Civi::$statics[__CLASS__]) && isset(\Civi::$statics[__CLASS__]['contact_references'])) {
return \Civi::$statics[__CLASS__]['contact_references'];
}
- $contactReferences = array();
- $coreReferences = CRM_Core_DAO::getReferencesToTable('civicrm_contact');
- foreach ($coreReferences as $coreReference) {
- if (!is_a($coreReference, 'CRM_Core_Reference_Dynamic')) {
- $contactReferences[$coreReference->getReferenceTable()][] = $coreReference->getReferenceKey();
- }
- }
- self::addCustomTablesExtendingContactsToCidRefs($contactReferences);
- // FixME for time being adding below line statically as no Foreign key constraint defined for table 'civicrm_entity_tag'
- $contactReferences['civicrm_entity_tag'][] = 'entity_id';
+ $contactReferences = $coreReferences = CRM_Core_DAO::getReferencesToContactTable();
- // Allow hook_civicrm_merge() to adjust $cidRefs.
- // Note that if entities are registered using the entityTypes hook there
- // is no need to use this hook.
CRM_Utils_Hook::merge('cidRefs', $contactReferences);
+ if ($contactReferences !== $coreReferences) {
+ Civi::log()->warning("Deprecated hook ::merge in context of 'cidRefs. Use entityTypes instead.", array('civi.tag' => 'deprecated'));
+ }
\Civi::$statics[__CLASS__]['contact_references'] = $contactReferences;
return \Civi::$statics[__CLASS__]['contact_references'];
}
@@ -486,7 +474,8 @@ public static function moveContactBelongings($mainId, $otherId, $tables = FALSE,
// getting all custom tables
$customTables = array();
if ($customTableToCopyFrom !== NULL) {
- self::addCustomTablesExtendingContactsToCidRefs($customTables);
+ // @todo this duplicates cidRefs?
+ CRM_Core_DAO::appendCustomTablesExtendingContacts($customTables);
$customTables = array_keys($customTables);
}
@@ -1457,7 +1446,6 @@ public static function getRowsElementsAndInfo($mainId, $otherId, $checkPermissio
$otherTree = CRM_Core_BAO_CustomGroup::getTree($main['contact_type'], NULL, $otherId, -1,
CRM_Utils_Array::value('contact_sub_type', $other), NULL, TRUE, NULL, TRUE, $checkPermissions
);
- CRM_Core_DAO::freeResult();
foreach ($otherTree as $gid => $group) {
$foundField = FALSE;
@@ -1926,26 +1914,6 @@ public static function addMembershipToRealtedContacts($contactID) {
}
}
- /**
- * Add custom tables that extend contacts to the list of contact references.
- *
- * CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity seems like a safe-ish
- * function to be sure all are retrieved & we don't miss subtypes or inactive or multiples
- * - the down side is it is not cached.
- *
- * Further changes should be include tests in the CRM_Core_MergerTest class
- * to ensure that disabled, subtype, multiple etc groups are still captured.
- *
- * @param array $cidRefs
- */
- public static function addCustomTablesExtendingContactsToCidRefs(&$cidRefs) {
- $customValueTables = CRM_Core_BAO_CustomGroup::getAllCustomGroupsByBaseEntity('Contact');
- $customValueTables->find();
- while ($customValueTables->fetch()) {
- $cidRefs[$customValueTables->table_name] = array('entity_id');
- }
- }
-
/**
* Create activities tracking the merge on affected contacts.
*
@@ -2329,8 +2297,6 @@ protected static function dedupePair(&$migrationInfo, &$resultStats, &$deletedCo
// pair may have been flipped, so make sure we delete using both orders
CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString, TRUE);
}
-
- CRM_Core_DAO::freeResult();
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Cart/DAO/Cart.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Cart/DAO/Cart.php
index a5c2202e520..6bb14e6c2e9 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Cart/DAO/Cart.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Cart/DAO/Cart.php
@@ -104,6 +104,7 @@ public static function &fields() {
'name' => 'completed',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Complete?'),
+ 'default' => '0',
'table_name' => 'civicrm_event_carts',
'entity' => 'Cart',
'bao' => 'CRM_Event_Cart_BAO_Cart',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Event.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Event.php
index caa4b866f95..1f13607d0cf 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Event.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Event.php
@@ -609,6 +609,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Event Type'),
'description' => 'Event Type ID.Implicit FK to civicrm_option_value where option_group = event_type.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -626,6 +627,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Participant Listing'),
'description' => 'Should we expose the participant list? Implicit FK to civicrm_option_value where option_group = participant_listing.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -693,6 +695,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Online Registration'),
'description' => 'If true, include registration link on Event Info page.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -776,6 +779,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is this a PAID event?'),
'description' => 'If true, one or more fee amounts must be set and a Payment Processor must be configured for Online Event Registration.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -828,6 +832,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Map Enabled'),
'description' => 'Include a map block on the Event Information page when geocode info is available and a mapping provider has been specified?',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -841,6 +846,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Active'),
'description' => 'Is this Event enabled or disabled/cancelled?',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -997,6 +1003,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is confirm email'),
'description' => 'If true, confirmation is automatically emailed to contact on successful registration.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1151,6 +1158,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Pay Later Allowed'),
'description' => 'if true - allows the user to send payment directly to the org later',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1190,6 +1198,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Partial Payments Enabled'),
'description' => 'is partial payment enabled for this event',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1248,6 +1257,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Allow Multiple Registrations'),
'description' => 'if true - allows the user to register multiple participants for event',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1261,6 +1271,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Maximum number of additional participants per registration'),
'description' => 'Maximum number of additional participants that can be registered on a single booking',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1271,6 +1282,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Does Event allow multiple registrations from same email address?'),
'description' => 'if true - allows the user to register multiple registrations from same email address.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1323,6 +1335,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Allow Self-service Cancellation or Transfer'),
'description' => 'Allow self service cancellation or transfer for event?',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1336,6 +1349,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Self-service Cancellation or Transfer Time'),
'description' => 'Number of hours prior to event start date to allow self-service cancellation or transfer.',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1380,6 +1394,7 @@ public static function &fields() {
'title' => ts('Is an Event Template'),
'description' => 'whether the event has template',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
@@ -1556,6 +1571,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is billing block required'),
'description' => 'if true than billing block is required this event',
+ 'default' => '0',
'table_name' => 'civicrm_event',
'entity' => 'Event',
'bao' => 'CRM_Event_BAO_Event',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Participant.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Participant.php
index a25c71bb825..941d0eff23d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Participant.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/DAO/Participant.php
@@ -364,6 +364,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_participant',
'entity' => 'Participant',
'bao' => 'CRM_Event_BAO_Participant',
@@ -378,6 +379,7 @@ public static function &fields() {
'headerPattern' => '/(is.)?(pay(.)?later)$/i',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_participant',
'entity' => 'Participant',
'bao' => 'CRM_Event_BAO_Participant',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Fee.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Fee.php
index aea14851200..cbd038756d7 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Fee.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Fee.php
@@ -522,6 +522,11 @@ public static function formRule($values) {
$errors['pay_later_receipt'] = ts('Please enter the Pay Later instructions to be displayed to your users.');
}
}
+ else {
+ if (empty($values['payment_processor'])) {
+ $errors['payment_processor'] = ts('You have indicated that this is a paid event, but no payment option has been selected. If this is not a paid event, please select the "No" option at the top of the page. If this is a paid event, please select at least one payment processor and/or enable the pay later option.');
+ }
+ }
}
return empty($errors) ? TRUE : $errors;
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Location.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Location.php
index f7c11764dcd..d28b2187fd0 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Location.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/ManageEvent/Location.php
@@ -225,10 +225,9 @@ public function postProcess() {
CRM_Core_DAO::setFieldValue('CRM_Event_DAO_Event', $this->_id,
'loc_block_id', 'null'
);
-
- $this->_values['address'] = array();
}
+ $this->_values['address'] = array();
// if 'create new loc' optioin is selected OR selected new loc is different
// from old one, go ahead and delete the old loc provided thats not being
// used by any other event
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration.php
index 7c10574c604..e284d2daf1d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration.php
@@ -196,7 +196,7 @@ class CRM_Event_Form_Registration extends CRM_Core_Form {
*/
public function preProcess() {
$this->_eventId = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);
- $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE);
+ $this->_action = CRM_Utils_Request::retrieve('action', 'Alphanumeric', $this, FALSE, CRM_Core_Action::ADD);
//CRM-4320
$this->_participantId = CRM_Utils_Request::retrieve('participantId', 'Positive', $this);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration/Confirm.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration/Confirm.php
index da1a8ee522d..29b5c5a2795 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration/Confirm.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Registration/Confirm.php
@@ -208,7 +208,8 @@ public function buildQuickForm() {
$this->assignToTemplate();
if ($this->_values['event']['is_monetary'] &&
- ($this->_params[0]['amount'] || $this->_params[0]['amount'] == 0)
+ ($this->_params[0]['amount'] || $this->_params[0]['amount'] == 0) &&
+ !$this->_requireApproval
) {
$this->_amount = array();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Task.php
index 263a644cba8..cc7df4d31d5 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Form/Task.php
@@ -34,31 +34,10 @@
*/
/**
- * This class generates task actions for CiviEvent
- *
+ * Class for event form task actions.
+ * FIXME: This needs refactoring to properly inherit from CRM_Core_Form_Task and share more functions.
*/
-class CRM_Event_Form_Task extends CRM_Core_Form {
-
- /**
- * The task being performed.
- *
- * @var int
- */
- protected $_task;
-
- /**
- * The additional clause that we restrict the search with.
- *
- * @var string
- */
- protected $_componentClause = NULL;
-
- /**
- * The array that holds all the component ids.
- *
- * @var array
- */
- protected $_componentIds;
+class CRM_Event_Form_Task extends CRM_Core_Form_Task {
/**
* The array that holds all the participant ids.
@@ -80,9 +59,8 @@ public function preProcess() {
/**
* @param CRM_Core_Form $form
- * @param bool $useTable
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_participantIds = array();
$values = $form->controller->exportValues($form->get('searchFormName'));
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Page/EventInfo.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Page/EventInfo.php
index 7b088ea3b87..9f58bddb300 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Page/EventInfo.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Event/Page/EventInfo.php
@@ -270,8 +270,9 @@ public function run() {
);
$allowRegistration = FALSE;
+ $isEventOpenForRegistration = CRM_Event_BAO_Event::validRegistrationRequest($values['event'], $this->_id);
if (!empty($values['event']['is_online_registration'])) {
- if (CRM_Event_BAO_Event::validRegistrationRequest($values['event'], $this->_id)) {
+ if ($isEventOpenForRegistration == 1) {
// we always generate urls for the front end in joomla
$action_query = $action === CRM_Core_Action::PREVIEW ? "&action=$action" : '';
$url = CRM_Utils_System::url('civicrm/event/register',
@@ -337,8 +338,9 @@ public function run() {
$statusMessage = ts('Event is currently full, but you can register and be a part of waiting list.');
}
}
-
- CRM_Core_Session::setStatus($statusMessage);
+ if ($isEventOpenForRegistration == 1) {
+ CRM_Core_Session::setStatus($statusMessage);
+ }
}
// we do not want to display recently viewed items, so turn off
$this->assign('displayRecent', FALSE);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/Export.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/Export.php
index b86bbe8bd83..f248f51a77b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/Export.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/Export.php
@@ -42,48 +42,31 @@ class CRM_Export_BAO_Export {
const EXPORT_ROW_COUNT = 100000;
/**
- * Get Querymode based on ExportMode
+ * Key representing the head of household in the relationship array.
*
- * @param int $exportMode
- * Export mode.
+ * e.g. 8_a_b.
*
- * @return string $Querymode
- * Query Mode
+ * @var string
*/
- public static function getQueryMode($exportMode) {
- $queryMode = CRM_Contact_BAO_Query::MODE_CONTACTS;
-
- switch ($exportMode) {
- case CRM_Export_Form_Select::CONTRIBUTE_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_CONTRIBUTE;
- break;
-
- case CRM_Export_Form_Select::EVENT_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_EVENT;
- break;
+ protected static $headOfHouseholdRelationshipKey;
- case CRM_Export_Form_Select::MEMBER_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_MEMBER;
- break;
-
- case CRM_Export_Form_Select::PLEDGE_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_PLEDGE;
- break;
-
- case CRM_Export_Form_Select::CASE_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_CASE;
- break;
-
- case CRM_Export_Form_Select::GRANT_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_GRANT;
- break;
+ /**
+ * Key representing the head of household in the relationship array.
+ *
+ * e.g. 8_a_b.
+ *
+ * @var string
+ */
+ protected static $memberOfHouseholdRelationshipKey;
- case CRM_Export_Form_Select::ACTIVITY_EXPORT:
- $queryMode = CRM_Contact_BAO_Query::MODE_ACTIVITY;
- break;
- }
- return $queryMode;
- }
+ /**
+ * Key representing the head of household in the relationship array.
+ *
+ * e.g. ['8_b_a' => 'Household Member Is', '8_a_b = 'Household Member Of'.....]
+ *
+ * @var
+ */
+ protected static $relationshipTypes = [];
/**
* Get default return property for export based on mode
@@ -211,53 +194,6 @@ public static function getGroupBy($exportMode, $queryMode, $returnProperties, $q
return $groupBy;
}
- /**
- * Define extra properties for the export based on query mode
- *
- * @param string $queryMode
- * Query Mode
- * @return array $extraProperties
- * Extra Properties
- */
- public static function defineExtraProperties($queryMode) {
- switch ($queryMode) {
- case CRM_Contact_BAO_Query::MODE_EVENT:
- $paymentFields = TRUE;
- $paymentTableId = 'participant_id';
- $extraReturnProperties = array();
- break;
-
- case CRM_Contact_BAO_Query::MODE_MEMBER:
- $paymentFields = TRUE;
- $paymentTableId = 'membership_id';
- $extraReturnProperties = array();
- break;
-
- case CRM_Contact_BAO_Query::MODE_PLEDGE:
- $extraReturnProperties = CRM_Pledge_BAO_Query::extraReturnProperties($queryMode);
- $paymentFields = TRUE;
- $paymentTableId = 'pledge_payment_id';
- break;
-
- case CRM_Contact_BAO_Query::MODE_CASE:
- $extraReturnProperties = CRM_Case_BAO_Query::extraReturnProperties($queryMode);
- $paymentFields = FALSE;
- $paymentTableId = '';
- break;
-
- default:
- $paymentFields = FALSE;
- $paymentTableId = '';
- $extraReturnProperties = array();
- }
- $extraProperties = array(
- 'paymentFields' => $paymentFields,
- 'paymentTableId' => $paymentTableId,
- 'extraReturnProperties' => $extraReturnProperties,
- );
- return $extraProperties;
- }
-
/**
* Get the list the export fields.
*
@@ -308,109 +244,40 @@ public static function exportComponents(
$queryOperator = 'AND'
) {
+ $processor = new CRM_Export_BAO_ExportProcessor($exportMode, $fields, $queryOperator);
$returnProperties = array();
- $paymentFields = $selectedPaymentFields = FALSE;
$phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
// Warning - this imProviders var is used in a somewhat fragile way - don't rename it
// without manually testing the export of IM provider still works.
$imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
- $contactRelationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType(
- NULL,
- NULL,
- NULL,
- NULL,
- TRUE,
- 'name',
- FALSE
- );
+ self::$relationshipTypes = $processor->getRelationshipTypes();
+ //also merge Head of Household
+ self::$memberOfHouseholdRelationshipKey = CRM_Utils_Array::key('Household Member of', self::$relationshipTypes);
+ self::$headOfHouseholdRelationshipKey = CRM_Utils_Array::key('Head of Household for', self::$relationshipTypes);
- $queryMode = self::getQueryMode($exportMode);
+ $queryMode = $processor->getQueryMode();
if ($fields) {
- //construct return properties
- $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
- $locationTypeFields = array(
- 'street_address',
- 'supplemental_address_1',
- 'supplemental_address_2',
- 'supplemental_address_3',
- 'city',
- 'postal_code',
- 'postal_code_suffix',
- 'geo_code_1',
- 'geo_code_2',
- 'state_province',
- 'country',
- 'phone',
- 'email',
- 'im',
- );
-
foreach ($fields as $key => $value) {
- $relationField = NULL;
- $relationshipTypes = $fieldName = CRM_Utils_Array::value(1, $value);
+ $fieldName = CRM_Utils_Array::value(1, $value);
if (!$fieldName) {
continue;
}
- if (array_key_exists($relationshipTypes, $contactRelationshipTypes) && (!empty($value[2]) || !empty($value[4]))) {
- $relPhoneTypeId = $relIMProviderId = NULL;
- if (!empty($value[2])) {
- $relationField = CRM_Utils_Array::value(2, $value);
- if (trim(CRM_Utils_Array::value(3, $value))) {
- $relLocTypeId = CRM_Utils_Array::value(3, $value);
- }
- else {
- $relLocTypeId = 'Primary';
- }
-
- if ($relationField == 'phone') {
- $relPhoneTypeId = CRM_Utils_Array::value(4, $value);
- }
- elseif ($relationField == 'im') {
- $relIMProviderId = CRM_Utils_Array::value(4, $value);
- }
- }
- elseif (!empty($value[4])) {
- $relationField = CRM_Utils_Array::value(4, $value);
- $relLocTypeId = CRM_Utils_Array::value(5, $value);
- if ($relationField == 'phone') {
- $relPhoneTypeId = CRM_Utils_Array::value(6, $value);
- }
- elseif ($relationField == 'im') {
- $relIMProviderId = CRM_Utils_Array::value(6, $value);
- }
- }
- if (in_array($relationField, $locationTypeFields) && is_numeric($relLocTypeId)) {
- if ($relPhoneTypeId) {
- $returnProperties[$relationshipTypes]['location'][$locationTypes[$relLocTypeId]]['phone-' . $relPhoneTypeId] = 1;
- }
- elseif ($relIMProviderId) {
- $returnProperties[$relationshipTypes]['location'][$locationTypes[$relLocTypeId]]['im-' . $relIMProviderId] = 1;
- }
- else {
- $returnProperties[$relationshipTypes]['location'][$locationTypes[$relLocTypeId]][$relationField] = 1;
- }
- }
- else {
- $returnProperties[$relationshipTypes][$relationField] = 1;
- }
- }
-
- if ($relationField) {
- // already handled.
+ if ($processor->isRelationshipTypeKey($fieldName) && (!empty($value[2]) || !empty($value[4]))) {
+ $returnProperties[$fieldName] = $processor->setRelationshipReturnProperties($value, $fieldName);
}
elseif (is_numeric(CRM_Utils_Array::value(2, $value))) {
- $locTypeId = $value[2];
+ $locationName = CRM_Core_PseudoConstant::getName('CRM_Core_BAO_Address', 'location_type_id', $value[2]);
if ($fieldName == 'phone') {
- $returnProperties['location'][$locationTypes[$locTypeId]]['phone-' . CRM_Utils_Array::value(3, $value)] = 1;
+ $returnProperties['location'][$locationName]['phone-' . CRM_Utils_Array::value(3, $value)] = 1;
}
elseif ($fieldName == 'im') {
- $returnProperties['location'][$locationTypes[$locTypeId]]['im-' . CRM_Utils_Array::value(3, $value)] = 1;
+ $returnProperties['location'][$locationName]['im-' . CRM_Utils_Array::value(3, $value)] = 1;
}
else {
- $returnProperties['location'][$locationTypes[$locTypeId]][$fieldName] = 1;
+ $returnProperties['location'][$locationName][$fieldName] = 1;
}
}
else {
@@ -419,14 +286,6 @@ public static function exportComponents(
if ($fieldName == 'event_id') {
$returnProperties['event_id'] = 1;
}
- elseif (
- $exportMode == CRM_Export_Form_Select::EVENT_EXPORT &&
- array_key_exists($fieldName, self::componentPaymentFields())
- ) {
- $selectedPaymentFields = TRUE;
- $paymentTableId = 'participant_id';
- $returnProperties[$fieldName] = 1;
- }
else {
$returnProperties[$fieldName] = 1;
}
@@ -438,56 +297,11 @@ public static function exportComponents(
}
}
else {
- $primary = TRUE;
- $fields = CRM_Contact_BAO_Contact::exportableFields('All', TRUE, TRUE);
- foreach ($fields as $key => $var) {
- if ($key && (substr($key, 0, 6) != 'custom')) {
- //for CRM=952
- $returnProperties[$key] = 1;
- }
- }
-
- if ($primary) {
- $returnProperties['location_type'] = 1;
- $returnProperties['im_provider'] = 1;
- $returnProperties['phone_type_id'] = 1;
- $returnProperties['provider_id'] = 1;
- $returnProperties['current_employer'] = 1;
- }
-
- $extraProperties = self::defineExtraProperties($queryMode);
- $paymentFields = $extraProperties['paymentFields'];
- $extraReturnProperties = $extraProperties['extraReturnProperties'];
- $paymentTableId = $extraProperties['paymentTableId'];
-
- if ($queryMode != CRM_Contact_BAO_Query::MODE_CONTACTS) {
- $componentReturnProperties = CRM_Contact_BAO_Query::defaultReturnProperties($queryMode);
- if ($queryMode == CRM_Contact_BAO_Query::MODE_CONTRIBUTE) {
- // soft credit columns are not automatically populated, because contribution search doesn't require them by default
- $componentReturnProperties = array_merge(
- $componentReturnProperties,
- CRM_Contribute_BAO_Query::softCreditReturnProperties(TRUE));
- }
- $returnProperties = array_merge($returnProperties, $componentReturnProperties);
-
- if (!empty($extraReturnProperties)) {
- $returnProperties = array_merge($returnProperties, $extraReturnProperties);
- }
-
- // unset non exportable fields for components
- $nonExpoFields = array(
- 'groups',
- 'tags',
- 'notes',
- 'contribution_status_id',
- 'pledge_status_id',
- 'pledge_payment_status_id',
- );
- foreach ($nonExpoFields as $value) {
- unset($returnProperties[$value]);
- }
- }
+ $returnProperties = $processor->getDefaultReturnProperties();
}
+ // @todo - we are working towards this being entirely a property of the processor
+ $processor->setReturnProperties($returnProperties);
+ $paymentTableId = $processor->getPaymentTableID();
if ($mergeSameAddress) {
//make sure the addressee fields are selected
@@ -550,113 +364,27 @@ public static function exportComponents(
CRM_Contact_BAO_ProximityQuery::fixInputParams($params);
}
- $query = new CRM_Contact_BAO_Query($params, $returnProperties, NULL,
- FALSE, FALSE, $queryMode,
- FALSE, TRUE, TRUE, NULL, $queryOperator
- );
-
- //sort by state
- //CRM-15301
- $query->_sort = $order;
- list($select, $from, $where, $having) = $query->query();
+ list($query, $select, $from, $where, $having) = $processor->runQuery($params, $order, $returnProperties);
if ($mergeSameHousehold == 1) {
if (empty($returnProperties['id'])) {
$returnProperties['id'] = 1;
}
- //also merge Head of Household
- $relationKeyMOH = CRM_Utils_Array::key('Household Member of', $contactRelationshipTypes);
- $relationKeyHOH = CRM_Utils_Array::key('Head of Household for', $contactRelationshipTypes);
-
foreach ($returnProperties as $key => $value) {
- if (!array_key_exists($key, $contactRelationshipTypes)) {
- $returnProperties[$relationKeyMOH][$key] = $value;
- $returnProperties[$relationKeyHOH][$key] = $value;
+ if (!$processor->isRelationshipTypeKey($key)) {
+ $returnProperties[self::$memberOfHouseholdRelationshipKey][$key] = $value;
+ $returnProperties[self::$headOfHouseholdRelationshipKey][$key] = $value;
}
}
- unset($returnProperties[$relationKeyMOH]['location_type']);
- unset($returnProperties[$relationKeyMOH]['im_provider']);
- unset($returnProperties[$relationKeyHOH]['location_type']);
- unset($returnProperties[$relationKeyHOH]['im_provider']);
+ unset($returnProperties[self::$memberOfHouseholdRelationshipKey]['location_type']);
+ unset($returnProperties[self::$memberOfHouseholdRelationshipKey]['im_provider']);
+ unset($returnProperties[self::$headOfHouseholdRelationshipKey]['location_type']);
+ unset($returnProperties[self::$headOfHouseholdRelationshipKey]['im_provider']);
}
- $allRelContactArray = $relationQuery = array();
-
- foreach ($contactRelationshipTypes as $rel => $dnt) {
- if ($relationReturnProperties = CRM_Utils_Array::value($rel, $returnProperties)) {
- $allRelContactArray[$rel] = array();
- // build Query for each relationship
- $relationQuery[$rel] = new CRM_Contact_BAO_Query(NULL, $relationReturnProperties,
- NULL, FALSE, FALSE, $queryMode
- );
- list($relationSelect, $relationFrom, $relationWhere, $relationHaving) = $relationQuery[$rel]->query();
-
- list($id, $direction) = explode('_', $rel, 2);
- // identify the relationship direction
- $contactA = 'contact_id_a';
- $contactB = 'contact_id_b';
- if ($direction == 'b_a') {
- $contactA = 'contact_id_b';
- $contactB = 'contact_id_a';
- }
- if ($exportMode == CRM_Export_Form_Select::CONTACT_EXPORT) {
- $relIDs = $ids;
- }
- elseif ($exportMode == CRM_Export_Form_Select::ACTIVITY_EXPORT) {
- $sourceID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_ActivityContact', 'record_type_id', 'Activity Source');
- $dao = CRM_Core_DAO::executeQuery("
- SELECT contact_id FROM civicrm_activity_contact
- WHERE activity_id IN ( " . implode(',', $ids) . ") AND
- record_type_id = {$sourceID}
- ");
-
- while ($dao->fetch()) {
- $relIDs[] = $dao->contact_id;
- }
- }
- else {
- $component = self::exportComponent($exportMode);
-
- if ($exportMode == CRM_Export_Form_Select::CASE_EXPORT) {
- $relIDs = CRM_Case_BAO_Case::retrieveContactIdsByCaseId($ids);
- }
- else {
- $relIDs = CRM_Core_DAO::getContactIDsFromComponent($ids, $component);
- }
- }
-
- $relationshipJoin = $relationshipClause = '';
- if (!$selectAll && $componentTable) {
- $relationshipJoin = " INNER JOIN {$componentTable} ctTable ON ctTable.contact_id = {$contactA}";
- }
- elseif (!empty($relIDs)) {
- $relID = implode(',', $relIDs);
- $relationshipClause = " AND crel.{$contactA} IN ( {$relID} )";
- }
-
- $relationFrom = " {$relationFrom}
- INNER JOIN civicrm_relationship crel ON crel.{$contactB} = contact_a.id AND crel.relationship_type_id = {$id}
- {$relationshipJoin} ";
-
- //check for active relationship status only
- $today = date('Ymd');
- $relationActive = " AND (crel.is_active = 1 AND ( crel.end_date is NULL OR crel.end_date >= {$today} ) )";
- $relationWhere = " WHERE contact_a.is_deleted = 0 {$relationshipClause} {$relationActive}";
- $relationGroupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($relationQuery[$rel]->_select, "crel.{$contactA}");
- $relationSelect = "{$relationSelect}, {$contactA} as refContact ";
- $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving $relationGroupBy";
-
- $allRelContactDAO = CRM_Core_DAO::executeQuery($relationQueryString);
- while ($allRelContactDAO->fetch()) {
- //FIX Me: Migrate this to table rather than array
- // build the array of all related contacts
- $allRelContactArray[$rel][$allRelContactDAO->refContact] = clone($allRelContactDAO);
- }
- $allRelContactDAO->free();
- }
- }
+ list($relationQuery, $allRelContactArray) = self::buildRelatedContactArray($selectAll, $ids, $exportMode, $componentTable, $returnProperties, $queryMode);
// make sure the groups stuff is included only if specifically specified
// by the fields param (CRM-1969), else we limit the contacts outputted to only
@@ -724,14 +452,14 @@ public static function exportComponents(
$addPaymentHeader = FALSE;
$paymentDetails = array();
- if ($paymentFields || $selectedPaymentFields) {
+ if ($processor->isExportPaymentFields()) {
// get payment related in for event and members
$paymentDetails = CRM_Contribute_BAO_Contribution::getContributionDetails($exportMode, $ids);
//get all payment headers.
// If we haven't selected specific payment fields, load in all the
// payment headers.
- if (!$selectedPaymentFields) {
+ if (!$processor->isExportSpecifiedPaymentFields()) {
$paymentHeaders = self::componentPaymentFields();
if (!empty($paymentDetails)) {
$addPaymentHeader = TRUE;
@@ -759,7 +487,7 @@ public static function exportComponents(
// for CRM-3157 purposes
$i18n = CRM_Core_I18n::singleton();
- list($outputColumns, $headerRows, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $query, $contactRelationshipTypes, $relationQuery, $selectedPaymentFields);
+ list($outputColumns, $headerRows, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $processor);
$limitReached = FALSE;
while (!$limitReached) {
@@ -804,112 +532,23 @@ public static function exportComponents(
}
}
- if ($field == 'id') {
- $row[$field] = $iterationDAO->contact_id;
- // special case for calculated field
- }
- elseif ($field == 'source_contact_id') {
- $row[$field] = $iterationDAO->contact_id;
- }
- elseif ($field == 'pledge_balance_amount') {
- $row[$field] = $iterationDAO->pledge_amount - $iterationDAO->pledge_total_paid;
- // special case for calculated field
- }
- elseif ($field == 'pledge_next_pay_amount') {
- $row[$field] = $iterationDAO->pledge_next_pay_amount + $iterationDAO->pledge_outstanding_amount;
- }
- elseif (array_key_exists($field, $contactRelationshipTypes)) {
+ if ($processor->isRelationshipTypeKey($field)) {
$relDAO = CRM_Utils_Array::value($iterationDAO->contact_id, $allRelContactArray[$field]);
$relationQuery[$field]->convertToPseudoNames($relDAO);
self::fetchRelationshipDetails($relDAO, $value, $field, $row);
}
- elseif (isset($fieldValue) &&
- $fieldValue != ''
- ) {
- //check for custom data
- if ($cfID = CRM_Core_BAO_CustomField::getKeyID($field)) {
- $row[$field] = CRM_Core_BAO_CustomField::displayValue($fieldValue, $cfID);
- }
-
- elseif (in_array($field, array(
- 'email_greeting',
- 'postal_greeting',
- 'addressee',
- ))) {
- //special case for greeting replacement
- $fldValue = "{$field}_display";
- $row[$field] = $iterationDAO->$fldValue;
- }
- else {
- //normal fields with a touch of CRM-3157
- switch ($field) {
- case 'country':
- case 'world_region':
- $row[$field] = $i18n->crm_translate($fieldValue, array('context' => 'country'));
- break;
-
- case 'state_province':
- $row[$field] = $i18n->crm_translate($fieldValue, array('context' => 'province'));
- break;
-
- case 'gender':
- case 'preferred_communication_method':
- case 'preferred_mail_format':
- case 'communication_style':
- $row[$field] = $i18n->crm_translate($fieldValue);
- break;
-
- default:
- if (isset($metadata[$field])) {
- // No I don't know why we do it this way & whether we could
- // make better use of pseudoConstants.
- if (!empty($metadata[$field]['context'])) {
- $row[$field] = $i18n->crm_translate($fieldValue, $metadata[$field]);
- break;
- }
- if (!empty($metadata[$field]['pseudoconstant'])) {
- // This is not our normal syntax for pseudoconstants but I am a bit loath to
- // call an external function until sure it is not increasing php processing given this
- // may be iterated 100,000 times & we already have the $imProvider var loaded.
- // That can be next refactor...
- // Yes - definitely feeling hatred for this bit of code - I know you will beat me up over it's awfulness
- // but I have to reach a stable point....
- $varName = $metadata[$field]['pseudoconstant']['var'];
- $labels = $$varName;
- $row[$field] = $labels[$fieldValue];
- break;
- }
-
- }
- $row[$field] = $fieldValue;
- break;
- }
- }
- }
- elseif ($selectedPaymentFields && array_key_exists($field, self::componentPaymentFields())) {
- $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
- $payFieldMapper = array(
- 'componentPaymentField_total_amount' => 'total_amount',
- 'componentPaymentField_contribution_status' => 'contribution_status',
- 'componentPaymentField_payment_instrument' => 'pay_instru',
- 'componentPaymentField_transaction_id' => 'trxn_id',
- 'componentPaymentField_received_date' => 'receive_date',
- );
- $row[$field] = CRM_Utils_Array::value($payFieldMapper[$field], $paymentData, '');
- }
else {
- // if field is empty or null
- $row[$field] = '';
+ $row[$field] = self::getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor);
}
}
// add payment headers if required
- if ($addPaymentHeader && $paymentFields) {
+ if ($addPaymentHeader && $processor->isExportPaymentFields()) {
// @todo rather than do this for every single row do it before the loop starts.
// where other header definitions take place.
$headerRows = array_merge($headerRows, $paymentHeaders);
foreach (array_keys($paymentHeaders) as $paymentHdr) {
- self::sqlColumnDefn($query, $sqlColumns, $paymentHdr);
+ self::sqlColumnDefn($processor, $sqlColumns, $paymentHdr);
}
}
@@ -924,8 +563,8 @@ public static function exportComponents(
// data will already be in $row. Otherwise, add payment related
// information, if appropriate.
if ($addPaymentHeader) {
- if (!$selectedPaymentFields) {
- if ($paymentFields) {
+ if (!$processor->isExportSpecifiedPaymentFields()) {
+ if ($processor->isExportPaymentFields()) {
$paymentData = CRM_Utils_Array::value($row[$paymentTableId], $paymentDetails);
if (!is_array($paymentData) || empty($paymentData)) {
$paymentData = $nullContributionDetails;
@@ -978,8 +617,8 @@ public static function exportComponents(
// merge the records if they have corresponding households
if ($mergeSameHousehold) {
- self::mergeSameHousehold($exportTempTable, $headerRows, $sqlColumns, $relationKeyMOH);
- self::mergeSameHousehold($exportTempTable, $headerRows, $sqlColumns, $relationKeyHOH);
+ self::mergeSameHousehold($exportTempTable, $headerRows, $sqlColumns, self::$memberOfHouseholdRelationshipKey);
+ self::mergeSameHousehold($exportTempTable, $headerRows, $sqlColumns, self::$headOfHouseholdRelationshipKey);
}
// call export hook
@@ -992,7 +631,7 @@ public static function exportComponents(
}
else {
// return tableName and sqlColumns in test context
- return array($exportTempTable, $sqlColumns);
+ return array($exportTempTable, $sqlColumns, $headerRows);
}
// delete the export temp table and component table
@@ -1137,127 +776,16 @@ public static function exportCustom($customSearchClass, $formValues, $order) {
}
/**
- * @param $query
+ * @param \CRM_Export_BAO_ExportProcessor $processor
* @param $sqlColumns
* @param $field
*/
- public static function sqlColumnDefn($query, &$sqlColumns, $field) {
+ public static function sqlColumnDefn($processor, &$sqlColumns, $field) {
if (substr($field, -4) == '_a_b' || substr($field, -4) == '_b_a') {
return;
}
- $fieldName = CRM_Utils_String::munge(strtolower($field), '_', 64);
- if ($fieldName == 'id') {
- $fieldName = 'civicrm_primary_id';
- }
-
- // early exit for master_id, CRM-12100
- // in the DB it is an ID, but in the export, we retrive the display_name of the master record
- // also for current_employer, CRM-16939
- if ($fieldName == 'master_id' || $fieldName == 'current_employer') {
- $sqlColumns[$fieldName] = "$fieldName varchar(128)";
- return;
- }
-
- if (substr($fieldName, -11) == 'campaign_id') {
- // CRM-14398
- $sqlColumns[$fieldName] = "$fieldName varchar(128)";
- return;
- }
-
- $lookUp = array('prefix_id', 'suffix_id');
- // set the sql columns
- if (isset($query->_fields[$field]['type'])) {
- switch ($query->_fields[$field]['type']) {
- case CRM_Utils_Type::T_INT:
- case CRM_Utils_Type::T_BOOLEAN:
- if (in_array($field, $lookUp)) {
- $sqlColumns[$fieldName] = "$fieldName varchar(255)";
- }
- else {
- $sqlColumns[$fieldName] = "$fieldName varchar(16)";
- }
- break;
-
- case CRM_Utils_Type::T_STRING:
- if (isset($query->_fields[$field]['maxlength'])) {
- $sqlColumns[$fieldName] = "$fieldName varchar({$query->_fields[$field]['maxlength']})";
- }
- else {
- $sqlColumns[$fieldName] = "$fieldName varchar(255)";
- }
- break;
-
- case CRM_Utils_Type::T_TEXT:
- case CRM_Utils_Type::T_LONGTEXT:
- case CRM_Utils_Type::T_BLOB:
- case CRM_Utils_Type::T_MEDIUMBLOB:
- $sqlColumns[$fieldName] = "$fieldName longtext";
- break;
-
- case CRM_Utils_Type::T_FLOAT:
- case CRM_Utils_Type::T_ENUM:
- case CRM_Utils_Type::T_DATE:
- case CRM_Utils_Type::T_TIME:
- case CRM_Utils_Type::T_TIMESTAMP:
- case CRM_Utils_Type::T_MONEY:
- case CRM_Utils_Type::T_EMAIL:
- case CRM_Utils_Type::T_URL:
- case CRM_Utils_Type::T_CCNUM:
- default:
- $sqlColumns[$fieldName] = "$fieldName varchar(32)";
- break;
- }
- }
- else {
- if (substr($fieldName, -3, 3) == '_id') {
- $sqlColumns[$fieldName] = "$fieldName varchar(255)";
- }
- elseif (substr($fieldName, -5, 5) == '_note') {
- $sqlColumns[$fieldName] = "$fieldName text";
- }
- else {
- $changeFields = array(
- 'groups',
- 'tags',
- 'notes',
- );
-
- if (in_array($fieldName, $changeFields)) {
- $sqlColumns[$fieldName] = "$fieldName text";
- }
- else {
- // set the sql columns for custom data
- if (isset($query->_fields[$field]['data_type'])) {
-
- switch ($query->_fields[$field]['data_type']) {
- case 'String':
- // May be option labels, which could be up to 512 characters
- $length = max(512, CRM_Utils_Array::value('text_length', $query->_fields[$field]));
- $sqlColumns[$fieldName] = "$fieldName varchar($length)";
- break;
-
- case 'Country':
- case 'StateProvince':
- case 'Link':
- $sqlColumns[$fieldName] = "$fieldName varchar(255)";
- break;
-
- case 'Memo':
- $sqlColumns[$fieldName] = "$fieldName text";
- break;
-
- default:
- $sqlColumns[$fieldName] = "$fieldName varchar(255)";
- break;
- }
- }
- else {
- $sqlColumns[$fieldName] = "$fieldName text";
- }
- }
- }
- }
+ $sqlColumns[$processor->getMungedFieldName($field)] = $processor->getSqlColumnDefinition($field);
}
/**
@@ -1265,7 +793,7 @@ public static function sqlColumnDefn($query, &$sqlColumns, $field) {
* @param $details
* @param $sqlColumns
*/
- public static function writeDetailsToTable($tableName, &$details, &$sqlColumns) {
+ public static function writeDetailsToTable($tableName, $details, $sqlColumns) {
if (empty($details)) {
return;
}
@@ -1282,10 +810,10 @@ public static function writeDetailsToTable($tableName, &$details, &$sqlColumns)
$sqlClause = array();
- foreach ($details as $dontCare => $row) {
+ foreach ($details as $row) {
$id++;
$valueString = array($id);
- foreach ($row as $dontCare => $value) {
+ foreach ($row as $value) {
if (empty($value)) {
$valueString[] = "''";
}
@@ -1312,9 +840,9 @@ public static function writeDetailsToTable($tableName, &$details, &$sqlColumns)
*
* @return string
*/
- public static function createTempTable(&$sqlColumns) {
+ public static function createTempTable($sqlColumns) {
//creating a temporary table for the search result that need be exported
- $exportTempTable = CRM_Core_DAO::createTempTableName('civicrm_export', TRUE);
+ $exportTempTable = CRM_Utils_SQL_TempTable::build()->setDurable()->setCategory('export')->getName();
// also create the sql table
$sql = "DROP TABLE IF EXISTS {$exportTempTable}";
@@ -1780,12 +1308,11 @@ public static function writeCSVFromTable($exportTempTable, $headerRows, $sqlColu
* Manipulate header rows for relationship fields.
*
* @param $headerRows
- * @param $contactRelationshipTypes
*/
- public static function manipulateHeaderRows(&$headerRows, $contactRelationshipTypes) {
+ public static function manipulateHeaderRows(&$headerRows) {
foreach ($headerRows as & $header) {
$split = explode('-', $header);
- if ($relationTypeName = CRM_Utils_Array::value($split[0], $contactRelationshipTypes)) {
+ if ($relationTypeName = CRM_Utils_Array::value($split[0], self::$relationshipTypes)) {
$split[0] = $relationTypeName;
$header = implode('-', $split);
}
@@ -1873,41 +1400,32 @@ public static function componentPaymentFields() {
* @param array $headerRows
* @param array $sqlColumns
* Columns to go in the temp table.
- * @param CRM_Contact_BAO_Query $query
+ * @param \CRM_Export_BAO_ExportProcessor $processor
* @param array|string $value
* @param array $phoneTypes
* @param array $imProviders
- * @param array $contactRelationshipTypes
- * @param string $relationQuery
- * @param array $selectedPaymentFields
+ *
* @return array
*/
- public static function setHeaderRows($field, $headerRows, $sqlColumns, $query, $value, $phoneTypes, $imProviders, $contactRelationshipTypes, $relationQuery, $selectedPaymentFields) {
+ public static function setHeaderRows($field, $headerRows, $sqlColumns, $processor, $value, $phoneTypes, $imProviders) {
- // Split campaign into 2 fields for id and title
- if (substr($field, -14) == 'campaign_title') {
- $headerRows[] = ts('Campaign Title');
- }
- elseif (substr($field, -11) == 'campaign_id') {
+ $queryFields = $processor->getQueryFields();
+ if (substr($field, -11) == 'campaign_id') {
+ // @todo - set this correctly in the xml rather than here.
$headerRows[] = ts('Campaign ID');
}
- elseif (isset($query->_fields[$field]['title'])) {
- $headerRows[] = $query->_fields[$field]['title'];
- }
- elseif ($field == 'phone_type_id') {
- $headerRows[] = ts('Phone Type');
+ elseif (isset($queryFields[$field]['title'])) {
+ $headerRows[] = $queryFields[$field]['title'];
}
elseif ($field == 'provider_id') {
+ // @todo - set this correctly in the xml rather than here.
$headerRows[] = ts('IM Service Provider');
}
- elseif (substr($field, 0, 5) == 'case_' && $query->_fields['case'][$field]['title']) {
- $headerRows[] = $query->_fields['case'][$field]['title'];
- }
- elseif (array_key_exists($field, $contactRelationshipTypes)) {
+ elseif ($processor->isRelationshipTypeKey($field)) {
foreach ($value as $relationField => $relationValue) {
// below block is same as primary block (duplicate)
- if (isset($relationQuery[$field]->_fields[$relationField]['title'])) {
- if ($relationQuery[$field]->_fields[$relationField]['name'] == 'name') {
+ if (isset($queryFields[$relationField]['title'])) {
+ if ($queryFields[$relationField]['name'] == 'name') {
$headerName = $field . '-' . $relationField;
}
else {
@@ -1915,28 +1433,28 @@ public static function setHeaderRows($field, $headerRows, $sqlColumns, $query, $
$headerName = $field . '-' . 'current_employer';
}
else {
- $headerName = $field . '-' . $relationQuery[$field]->_fields[$relationField]['name'];
+ $headerName = $field . '-' . $queryFields[$relationField]['name'];
}
}
$headerRows[] = $headerName;
- self::sqlColumnDefn($query, $sqlColumns, $headerName);
+ self::sqlColumnDefn($processor, $sqlColumns, $headerName);
}
elseif ($relationField == 'phone_type_id') {
$headerName = $field . '-' . 'Phone Type';
$headerRows[] = $headerName;
- self::sqlColumnDefn($query, $sqlColumns, $headerName);
+ self::sqlColumnDefn($processor, $sqlColumns, $headerName);
}
elseif ($relationField == 'provider_id') {
$headerName = $field . '-' . 'Im Service Provider';
$headerRows[] = $headerName;
- self::sqlColumnDefn($query, $sqlColumns, $headerName);
+ self::sqlColumnDefn($processor, $sqlColumns, $headerName);
}
elseif ($relationField == 'state_province_id') {
$headerName = $field . '-' . 'state_province_id';
$headerRows[] = $headerName;
- self::sqlColumnDefn($query, $sqlColumns, $headerName);
+ self::sqlColumnDefn($processor, $sqlColumns, $headerName);
}
elseif (is_array($relationValue) && $relationField == 'location') {
// fix header for location type case
@@ -1944,7 +1462,7 @@ public static function setHeaderRows($field, $headerRows, $sqlColumns, $query, $
foreach (array_keys($val) as $fld) {
$type = explode('-', $fld);
- $hdr = "{$ltype}-" . $relationQuery[$field]->_fields[$type[0]]['title'];
+ $hdr = "{$ltype}-" . $queryFields[$type[0]]['title'];
if (!empty($type[1])) {
if (CRM_Utils_Array::value(0, $type) == 'phone') {
@@ -1956,21 +1474,21 @@ public static function setHeaderRows($field, $headerRows, $sqlColumns, $query, $
}
$headerName = $field . '-' . $hdr;
$headerRows[] = $headerName;
- self::sqlColumnDefn($query, $sqlColumns, $headerName);
+ self::sqlColumnDefn($processor, $sqlColumns, $headerName);
}
}
}
}
- self::manipulateHeaderRows($headerRows, $contactRelationshipTypes);
+ self::manipulateHeaderRows($headerRows);
}
- elseif ($selectedPaymentFields && array_key_exists($field, self::componentPaymentFields())) {
+ elseif ($processor->isExportPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
$headerRows[] = CRM_Utils_Array::value($field, self::componentPaymentFields());
}
else {
$headerRows[] = $field;
}
- self::sqlColumnDefn($query, $sqlColumns, $field);
+ self::sqlColumnDefn($processor, $sqlColumns, $field);
return array($headerRows, $sqlColumns);
}
@@ -1985,10 +1503,8 @@ public static function setHeaderRows($field, $headerRows, $sqlColumns, $query, $
* as a step on the refactoring path rather than how it should be.
*
* @param array $returnProperties
- * @param CRM_Contact_BAO_Contact $query
- * @param array $contactRelationshipTypes
- * @param string $relationQuery
- * @param array $selectedPaymentFields
+ * @param \CRM_Export_BAO_ExportProcessor $processor
+ *
* @return array
* - outputColumns Array of columns to be exported. The values don't matter but the key must match the
* alias for the field generated by BAO_Query object.
@@ -2005,15 +1521,16 @@ public static function setHeaderRows($field, $headerRows, $sqlColumns, $query, $
* - b) this code is old & outdated. Submit your answers to circular bin or better
* yet find a way to comment them for posterity.
*/
- public static function getExportStructureArrays($returnProperties, $query, $contactRelationshipTypes, $relationQuery, $selectedPaymentFields) {
+ public static function getExportStructureArrays($returnProperties, $processor) {
$metadata = $headerRows = $outputColumns = $sqlColumns = array();
$phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
$imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
+ $queryFields = $processor->getQueryFields();
foreach ($returnProperties as $key => $value) {
if ($key != 'location' || !is_array($value)) {
$outputColumns[$key] = $value;
- list($headerRows, $sqlColumns) = self::setHeaderRows($key, $headerRows, $sqlColumns, $query, $value, $phoneTypes, $imProviders, $contactRelationshipTypes, $relationQuery, $selectedPaymentFields);
+ list($headerRows, $sqlColumns) = self::setHeaderRows($key, $headerRows, $sqlColumns, $processor, $value, $phoneTypes, $imProviders);
}
else {
foreach ($value as $locationType => $locationFields) {
@@ -2021,7 +1538,7 @@ public static function getExportStructureArrays($returnProperties, $query, $cont
$type = explode('-', $locationFieldName);
$actualDBFieldName = $type[0];
- $outputFieldName = $locationType . '-' . $query->_fields[$actualDBFieldName]['title'];
+ $outputFieldName = $locationType . '-' . $queryFields[$actualDBFieldName]['title'];
$daoFieldName = CRM_Utils_String::munge($locationType) . '-' . $actualDBFieldName;
if (!empty($type[1])) {
@@ -2037,8 +1554,8 @@ public static function getExportStructureArrays($returnProperties, $query, $cont
// Warning: shame inducing hack.
$metadata[$daoFieldName]['pseudoconstant']['var'] = 'imProviders';
}
- self::sqlColumnDefn($query, $sqlColumns, $outputFieldName);
- list($headerRows, $sqlColumns) = self::setHeaderRows($outputFieldName, $headerRows, $sqlColumns, $query, $value, $phoneTypes, $imProviders, $contactRelationshipTypes, $relationQuery, $selectedPaymentFields);
+ self::sqlColumnDefn($processor, $sqlColumns, $outputFieldName);
+ list($headerRows, $sqlColumns) = self::setHeaderRows($outputFieldName, $headerRows, $sqlColumns, $processor, $value, $phoneTypes, $imProviders);
if ($actualDBFieldName == 'country' || $actualDBFieldName == 'world_region') {
$metadata[$daoFieldName] = array('context' => 'country');
}
@@ -2103,6 +1620,10 @@ private static function fetchRelationshipDetails($relDAO, $value, $field, &$row)
}
elseif (is_array($relationValue) && $relationField == 'location') {
foreach ($relationValue as $ltype => $val) {
+ // If the location name has a space in it the we need to handle that. This
+ // is kinda hacky but specifically covered in the ExportTest so later efforts to
+ // improve it should be secure in the knowled it will be caught.
+ $ltype = str_replace(' ', '_', $ltype);
foreach (array_keys($val) as $fld) {
$type = explode('-', $fld);
$fldValue = "{$ltype}-" . $type[0];
@@ -2167,4 +1688,211 @@ private static function fetchRelationshipDetails($relDAO, $value, $field, &$row)
}
}
+ /**
+ * Get the ids that we want to get related contact details for.
+ *
+ * @param array $ids
+ * @param int $exportMode
+ *
+ * @return array
+ */
+ protected static function getIDsForRelatedContact($ids, $exportMode) {
+ if ($exportMode == CRM_Export_Form_Select::CONTACT_EXPORT) {
+ return $ids;
+ }
+ if ($exportMode == CRM_Export_Form_Select::ACTIVITY_EXPORT) {
+ $relIDs = [];
+ $sourceID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_ActivityContact', 'record_type_id', 'Activity Source');
+ $dao = CRM_Core_DAO::executeQuery("
+ SELECT contact_id FROM civicrm_activity_contact
+ WHERE activity_id IN ( " . implode(',', $ids) . ") AND
+ record_type_id = {$sourceID}
+ ");
+
+ while ($dao->fetch()) {
+ $relIDs[] = $dao->contact_id;
+ }
+ return $relIDs;
+ }
+ $component = self::exportComponent($exportMode);
+
+ if ($exportMode == CRM_Export_Form_Select::CASE_EXPORT) {
+ return CRM_Case_BAO_Case::retrieveContactIdsByCaseId($ids);
+ }
+ else {
+ return CRM_Core_DAO::getContactIDsFromComponent($ids, $component);
+ }
+ }
+
+ /**
+ * @param $selectAll
+ * @param $ids
+ * @param $exportMode
+ * @param $componentTable
+ * @param $returnProperties
+ * @param $queryMode
+ * @return array
+ */
+ protected static function buildRelatedContactArray($selectAll, $ids, $exportMode, $componentTable, $returnProperties, $queryMode) {
+ $allRelContactArray = $relationQuery = array();
+
+ foreach (self::$relationshipTypes as $rel => $dnt) {
+ if ($relationReturnProperties = CRM_Utils_Array::value($rel, $returnProperties)) {
+ $allRelContactArray[$rel] = array();
+ // build Query for each relationship
+ $relationQuery[$rel] = new CRM_Contact_BAO_Query(NULL, $relationReturnProperties,
+ NULL, FALSE, FALSE, $queryMode
+ );
+ list($relationSelect, $relationFrom, $relationWhere, $relationHaving) = $relationQuery[$rel]->query();
+
+ list($id, $direction) = explode('_', $rel, 2);
+ // identify the relationship direction
+ $contactA = 'contact_id_a';
+ $contactB = 'contact_id_b';
+ if ($direction == 'b_a') {
+ $contactA = 'contact_id_b';
+ $contactB = 'contact_id_a';
+ }
+ $relIDs = self::getIDsForRelatedContact($ids, $exportMode);
+
+ $relationshipJoin = $relationshipClause = '';
+ if (!$selectAll && $componentTable) {
+ $relationshipJoin = " INNER JOIN {$componentTable} ctTable ON ctTable.contact_id = {$contactA}";
+ }
+ elseif (!empty($relIDs)) {
+ $relID = implode(',', $relIDs);
+ $relationshipClause = " AND crel.{$contactA} IN ( {$relID} )";
+ }
+
+ $relationFrom = " {$relationFrom}
+ INNER JOIN civicrm_relationship crel ON crel.{$contactB} = contact_a.id AND crel.relationship_type_id = {$id}
+ {$relationshipJoin} ";
+
+ //check for active relationship status only
+ $today = date('Ymd');
+ $relationActive = " AND (crel.is_active = 1 AND ( crel.end_date is NULL OR crel.end_date >= {$today} ) )";
+ $relationWhere = " WHERE contact_a.is_deleted = 0 {$relationshipClause} {$relationActive}";
+ $relationGroupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($relationQuery[$rel]->_select, "crel.{$contactA}");
+ $relationSelect = "{$relationSelect}, {$contactA} as refContact ";
+ $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving $relationGroupBy";
+
+ $allRelContactDAO = CRM_Core_DAO::executeQuery($relationQueryString);
+ while ($allRelContactDAO->fetch()) {
+ //FIX Me: Migrate this to table rather than array
+ // build the array of all related contacts
+ $allRelContactArray[$rel][$allRelContactDAO->refContact] = clone($allRelContactDAO);
+ }
+ $allRelContactDAO->free();
+ }
+ }
+ return array($relationQuery, $allRelContactArray);
+ }
+
+ /**
+ * @param $field
+ * @param $iterationDAO
+ * @param $fieldValue
+ * @param $i18n
+ * @param $metadata
+ * @param $paymentDetails
+ *
+ * @param \CRM_Export_BAO_ExportProcessor $processor
+ *
+ * @return string
+ */
+ protected static function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor) {
+
+ if ($field == 'id') {
+ return $iterationDAO->contact_id;
+ // special case for calculated field
+ }
+ elseif ($field == 'source_contact_id') {
+ return $iterationDAO->contact_id;
+ }
+ elseif ($field == 'pledge_balance_amount') {
+ return $iterationDAO->pledge_amount - $iterationDAO->pledge_total_paid;
+ // special case for calculated field
+ }
+ elseif ($field == 'pledge_next_pay_amount') {
+ return $iterationDAO->pledge_next_pay_amount + $iterationDAO->pledge_outstanding_amount;
+ }
+ elseif (isset($fieldValue) &&
+ $fieldValue != ''
+ ) {
+ //check for custom data
+ if ($cfID = CRM_Core_BAO_CustomField::getKeyID($field)) {
+ return CRM_Core_BAO_CustomField::displayValue($fieldValue, $cfID);
+ }
+
+ elseif (in_array($field, array(
+ 'email_greeting',
+ 'postal_greeting',
+ 'addressee',
+ ))) {
+ //special case for greeting replacement
+ $fldValue = "{$field}_display";
+ return $iterationDAO->$fldValue;
+ }
+ else {
+ //normal fields with a touch of CRM-3157
+ switch ($field) {
+ case 'country':
+ case 'world_region':
+ return $i18n->crm_translate($fieldValue, array('context' => 'country'));
+
+ case 'state_province':
+ return $i18n->crm_translate($fieldValue, array('context' => 'province'));
+
+ case 'gender':
+ case 'preferred_communication_method':
+ case 'preferred_mail_format':
+ case 'communication_style':
+ return $i18n->crm_translate($fieldValue);
+
+ default:
+ if (isset($metadata[$field])) {
+ // No I don't know why we do it this way & whether we could
+ // make better use of pseudoConstants.
+ if (!empty($metadata[$field]['context'])) {
+ return $i18n->crm_translate($fieldValue, $metadata[$field]);
+ }
+ if (!empty($metadata[$field]['pseudoconstant'])) {
+ // This is not our normal syntax for pseudoconstants but I am a bit loath to
+ // call an external function until sure it is not increasing php processing given this
+ // may be iterated 100,000 times & we already have the $imProvider var loaded.
+ // That can be next refactor...
+ // Yes - definitely feeling hatred for this bit of code - I know you will beat me up over it's awfulness
+ // but I have to reach a stable point....
+ $varName = $metadata[$field]['pseudoconstant']['var'];
+ if ($varName === 'imProviders') {
+ return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_IM', 'provider_id', $fieldValue);
+ }
+ if ($varName === 'phoneTypes') {
+ return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_Phone', 'phone_type_id', $fieldValue);
+ }
+ }
+
+ }
+ return $fieldValue;
+ }
+ }
+ }
+ elseif ($processor->isExportSpecifiedPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
+ $paymentTableId = $processor->getPaymentTableID();
+ $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
+ $payFieldMapper = array(
+ 'componentPaymentField_total_amount' => 'total_amount',
+ 'componentPaymentField_contribution_status' => 'contribution_status',
+ 'componentPaymentField_payment_instrument' => 'pay_instru',
+ 'componentPaymentField_transaction_id' => 'trxn_id',
+ 'componentPaymentField_received_date' => 'receive_date',
+ );
+ return CRM_Utils_Array::value($payFieldMapper[$field], $paymentData, '');
+ }
+ else {
+ // if field is empty or null
+ return '';
+ }
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/ExportProcessor.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/ExportProcessor.php
new file mode 100644
index 00000000000..57494147043
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/BAO/ExportProcessor.php
@@ -0,0 +1,633 @@
+ 'Household Member Is', '8_a_b = 'Household Member Of'.....]
+ *
+ * @var
+ */
+ protected $relationshipTypes = [];
+
+ /**
+ * Array of properties to retrieve for relationships.
+ *
+ * @var array
+ */
+ protected $relationshipReturnProperties = [];
+
+ /**
+ * @var array
+ */
+ protected $returnProperties = [];
+
+ /**
+ * CRM_Export_BAO_ExportProcessor constructor.
+ *
+ * @param int $exportMode
+ * @param array|NULL $requestedFields
+ * @param string $queryOperator
+ */
+ public function __construct($exportMode, $requestedFields, $queryOperator) {
+ $this->setExportMode($exportMode);
+ $this->setQueryMode();
+ $this->setQueryOperator($queryOperator);
+ $this->setRequestedFields($requestedFields);
+ $this->setRelationshipTypes();
+ }
+
+ /**
+ * @return array|null
+ */
+ public function getRequestedFields() {
+ return $this->requestedFields;
+ }
+
+ /**
+ * @param array|null $requestedFields
+ */
+ public function setRequestedFields($requestedFields) {
+ $this->requestedFields = $requestedFields;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getReturnProperties() {
+ return $this->returnProperties;
+ }
+
+ /**
+ * @param array $returnProperties
+ */
+ public function setReturnProperties($returnProperties) {
+ $this->returnProperties = $returnProperties;
+ }
+
+ /**
+ * @return array
+ */
+ public function getRelationshipTypes() {
+ return $this->relationshipTypes;
+ }
+
+ /**
+ */
+ public function setRelationshipTypes() {
+ $this->relationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType(
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ TRUE,
+ 'name',
+ FALSE
+ );
+ }
+
+
+ /**
+ * @param $fieldName
+ * @return bool
+ */
+ public function isRelationshipTypeKey($fieldName) {
+ return array_key_exists($fieldName, $this->relationshipTypes);
+ }
+
+ /**
+ * @return string
+ */
+ public function getQueryOperator() {
+ return $this->queryOperator;
+ }
+
+ /**
+ * @param string $queryOperator
+ */
+ public function setQueryOperator($queryOperator) {
+ $this->queryOperator = $queryOperator;
+ }
+
+ /**
+ * @return array
+ */
+ public function getQueryFields() {
+ return $this->queryFields;
+ }
+
+ /**
+ * @param array $queryFields
+ */
+ public function setQueryFields($queryFields) {
+ $this->queryFields = $queryFields;
+ }
+
+ /**
+ * @return int
+ */
+ public function getQueryMode() {
+ return $this->queryMode;
+ }
+
+ /**
+ * Set the query mode based on the export mode.
+ */
+ public function setQueryMode() {
+
+ switch ($this->getExportMode()) {
+ case CRM_Export_Form_Select::CONTRIBUTE_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_CONTRIBUTE;
+ break;
+
+ case CRM_Export_Form_Select::EVENT_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_EVENT;
+ break;
+
+ case CRM_Export_Form_Select::MEMBER_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_MEMBER;
+ break;
+
+ case CRM_Export_Form_Select::PLEDGE_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_PLEDGE;
+ break;
+
+ case CRM_Export_Form_Select::CASE_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_CASE;
+ break;
+
+ case CRM_Export_Form_Select::GRANT_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_GRANT;
+ break;
+
+ case CRM_Export_Form_Select::ACTIVITY_EXPORT:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_ACTIVITY;
+ break;
+
+ default:
+ $this->queryMode = CRM_Contact_BAO_Query::MODE_CONTACTS;
+ }
+ }
+
+ /**
+ * @return int
+ */
+ public function getExportMode() {
+ return $this->exportMode;
+ }
+
+ /**
+ * @param int $exportMode
+ */
+ public function setExportMode($exportMode) {
+ $this->exportMode = $exportMode;
+ }
+
+ /**
+ * @param $params
+ * @param $order
+ * @param $returnProperties
+ * @return array
+ */
+ public function runQuery($params, $order, $returnProperties) {
+ $query = new CRM_Contact_BAO_Query($params, $returnProperties, NULL,
+ FALSE, FALSE, $this->getQueryMode(),
+ FALSE, TRUE, TRUE, NULL, $this->getQueryOperator()
+ );
+
+ //sort by state
+ //CRM-15301
+ $query->_sort = $order;
+ list($select, $from, $where, $having) = $query->query();
+ $this->setQueryFields($query->_fields);
+ return array($query, $select, $from, $where, $having);
+ }
+
+ /**
+ * Get array of fields to return, over & above those defined in the main contact exportable fields.
+ *
+ * These include export mode specific fields & some fields apparently required as 'exportableFields'
+ * but not returned by the function of the same name.
+ *
+ * @return array
+ * Array of fields to return in the format ['field_name' => 1,...]
+ */
+ public function getAdditionalReturnProperties() {
+
+ $missing = [
+ 'location_type',
+ 'im_provider',
+ 'phone_type_id',
+ 'provider_id',
+ 'current_employer',
+ ];
+ if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_CONTACTS) {
+ $componentSpecificFields = [];
+ }
+ else {
+ $componentSpecificFields = CRM_Contact_BAO_Query::defaultReturnProperties($this->getQueryMode());
+ }
+ if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_PLEDGE) {
+ $componentSpecificFields = array_merge($componentSpecificFields, CRM_Pledge_BAO_Query::extraReturnProperties($this->getQueryMode()));
+ unset($componentSpecificFields['contribution_status_id']);
+ unset($componentSpecificFields['pledge_status_id']);
+ unset($componentSpecificFields['pledge_payment_status_id']);
+ }
+ if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_CASE) {
+ $componentSpecificFields = array_merge($componentSpecificFields, CRM_Case_BAO_Query::extraReturnProperties($this->getQueryMode()));
+ }
+ if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_CONTRIBUTE) {
+ $componentSpecificFields = array_merge($componentSpecificFields, CRM_Contribute_BAO_Query::softCreditReturnProperties(TRUE));
+ unset($componentSpecificFields['contribution_status_id']);
+ }
+ return array_merge(array_fill_keys($missing, 1), $componentSpecificFields);
+ }
+
+ /**
+ * Should payment fields be appended to the export.
+ *
+ * (This is pretty hacky so hopefully this function won't last long - notice
+ * how obviously it should be part of the above function!).
+ */
+ public function isExportPaymentFields() {
+ if ($this->getRequestedFields() === NULL
+ && in_array($this->getQueryMode(), [
+ CRM_Contact_BAO_Query::MODE_EVENT,
+ CRM_Contact_BAO_Query::MODE_MEMBER,
+ CRM_Contact_BAO_Query::MODE_PLEDGE,
+ ])) {
+ return TRUE;
+ }
+ elseif ($this->isExportSpecifiedPaymentFields()) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ /**
+ * Has specific payment fields been requested (as opposed to via all fields).
+ *
+ * If specific fields have been requested then they get added at various points.
+ *
+ * @return bool
+ */
+ public function isExportSpecifiedPaymentFields() {
+ if ($this->getRequestedFields() !== NULL && $this->hasRequestedComponentPaymentFields()) {
+ return TRUE;
+ }
+ }
+
+ /**
+ * Get the name of the id field in the table that connects contributions to the export entity.
+ */
+ public function getPaymentTableID() {
+ if ($this->getRequestedFields() === NULL) {
+ $mapping = [
+ CRM_Contact_BAO_Query::MODE_EVENT => 'participant_id',
+ CRM_Contact_BAO_Query::MODE_MEMBER => 'membership_id',
+ CRM_Contact_BAO_Query::MODE_PLEDGE => 'pledge_payment_id',
+ ];
+ return isset($mapping[$this->getQueryMode()]) ? $mapping[$this->getQueryMode()] : '';
+ }
+ elseif ($this->hasRequestedComponentPaymentFields()) {
+ return 'participant_id';
+ }
+ return FALSE;
+ }
+
+ /**
+ * Have component payment fields been requested.
+ *
+ * @return bool
+ */
+ protected function hasRequestedComponentPaymentFields() {
+ if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_EVENT) {
+ $participantPaymentFields = array_intersect_key($this->getComponentPaymentFields(), $this->getReturnProperties());
+ if (!empty($participantPaymentFields)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Get fields that indicate payment fields have been requested for a component.
+ *
+ * @return array
+ */
+ protected function getComponentPaymentFields() {
+ return [
+ 'componentPaymentField_total_amount' => ts('Total Amount'),
+ 'componentPaymentField_contribution_status' => ts('Contribution Status'),
+ 'componentPaymentField_received_date' => ts('Date Received'),
+ 'componentPaymentField_payment_instrument' => ts('Payment Method'),
+ 'componentPaymentField_transaction_id' => ts('Transaction ID'),
+ ];
+ }
+
+ /**
+ * Get the default properties when not specified.
+ *
+ * In the UI this appears as 'Primary fields only' but in practice it's
+ * most of the kitchen sink and the hallway closet thrown in.
+ *
+ * Since CRM-952 custom fields are excluded, but no other form of mercy is shown.
+ *
+ * @return array
+ */
+ public function getDefaultReturnProperties() {
+ $returnProperties = [];
+ $fields = CRM_Contact_BAO_Contact::exportableFields('All', TRUE, TRUE);
+ $skippedFields = ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_CONTACTS) ? [] : [
+ 'groups',
+ 'tags',
+ 'notes'
+ ];
+
+ foreach ($fields as $key => $var) {
+ if ($key && (substr($key, 0, 6) != 'custom') && !in_array($key, $skippedFields)) {
+ $returnProperties[$key] = 1;
+ }
+ }
+ $returnProperties = array_merge($returnProperties, $this->getAdditionalReturnProperties());
+ return $returnProperties;
+ }
+
+ /**
+ * Add the field to relationship return properties & return it.
+ *
+ * This function is doing both setting & getting which is yuck but it is an interim
+ * refactor.
+ *
+ * @param array $value
+ * @param string $relationshipKey
+ *
+ * @return array
+ */
+ public function setRelationshipReturnProperties($value, $relationshipKey) {
+ $relPhoneTypeId = $relIMProviderId = NULL;
+ if (!empty($value[2])) {
+ $relationField = CRM_Utils_Array::value(2, $value);
+ if (trim(CRM_Utils_Array::value(3, $value))) {
+ $relLocTypeId = CRM_Utils_Array::value(3, $value);
+ }
+ else {
+ $relLocTypeId = 'Primary';
+ }
+
+ if ($relationField == 'phone') {
+ $relPhoneTypeId = CRM_Utils_Array::value(4, $value);
+ }
+ elseif ($relationField == 'im') {
+ $relIMProviderId = CRM_Utils_Array::value(4, $value);
+ }
+ }
+ elseif (!empty($value[4])) {
+ $relationField = CRM_Utils_Array::value(4, $value);
+ $relLocTypeId = CRM_Utils_Array::value(5, $value);
+ if ($relationField == 'phone') {
+ $relPhoneTypeId = CRM_Utils_Array::value(6, $value);
+ }
+ elseif ($relationField == 'im') {
+ $relIMProviderId = CRM_Utils_Array::value(6, $value);
+ }
+ }
+ if (in_array($relationField, $this->getValidLocationFields()) && is_numeric($relLocTypeId)) {
+ $locationName = CRM_Core_PseudoConstant::getName('CRM_Core_BAO_Address', 'location_type_id', $relLocTypeId);
+ if ($relPhoneTypeId) {
+ $this->relationshipReturnProperties[$relationshipKey]['location'][$locationName]['phone-' . $relPhoneTypeId] = 1;
+ }
+ elseif ($relIMProviderId) {
+ $this->relationshipReturnProperties[$relationshipKey]['location'][$locationName]['im-' . $relIMProviderId] = 1;
+ }
+ else {
+ $this->relationshipReturnProperties[$relationshipKey]['location'][$locationName][$relationField] = 1;
+ }
+ }
+ else {
+ $this->relationshipReturnProperties[$relationshipKey][$relationField] = 1;
+ }
+ return $this->relationshipReturnProperties[$relationshipKey];
+ }
+
+ /**
+ * Get the default location fields to request.
+ *
+ * @return array
+ */
+ public function getValidLocationFields() {
+ return [
+ 'street_address',
+ 'supplemental_address_1',
+ 'supplemental_address_2',
+ 'supplemental_address_3',
+ 'city',
+ 'postal_code',
+ 'postal_code_suffix',
+ 'geo_code_1',
+ 'geo_code_2',
+ 'state_province',
+ 'country',
+ 'phone',
+ 'email',
+ 'im',
+ ];
+ }
+
+ /**
+ * Get the sql column definition for the given field.
+ *
+ * @param $field
+ *
+ * @return mixed
+ */
+ public function getSqlColumnDefinition($field) {
+ $fieldName = $this->getMungedFieldName($field);
+
+ // early exit for master_id, CRM-12100
+ // in the DB it is an ID, but in the export, we retrive the display_name of the master record
+ // also for current_employer, CRM-16939
+ if ($fieldName == 'master_id' || $fieldName == 'current_employer') {
+ return "$fieldName varchar(128)";
+ }
+
+ if (substr($fieldName, -11) == 'campaign_id') {
+ // CRM-14398
+ return "$fieldName varchar(128)";
+ }
+
+ $queryFields = $this->getQueryFields();
+ $lookUp = ['prefix_id', 'suffix_id'];
+ // set the sql columns
+ if (isset($queryFields[$field]['type'])) {
+ switch ($queryFields[$field]['type']) {
+ case CRM_Utils_Type::T_INT:
+ case CRM_Utils_Type::T_BOOLEAN:
+ if (in_array($field, $lookUp)) {
+ return "$fieldName varchar(255)";
+ }
+ else {
+ return "$fieldName varchar(16)";
+ }
+
+ case CRM_Utils_Type::T_STRING:
+ if (isset($queryFields[$field]['maxlength'])) {
+ return "$fieldName varchar({$queryFields[$field]['maxlength']})";
+ }
+ else {
+ return "$fieldName varchar(255)";
+ }
+
+ case CRM_Utils_Type::T_TEXT:
+ case CRM_Utils_Type::T_LONGTEXT:
+ case CRM_Utils_Type::T_BLOB:
+ case CRM_Utils_Type::T_MEDIUMBLOB:
+ return "$fieldName longtext";
+
+ case CRM_Utils_Type::T_FLOAT:
+ case CRM_Utils_Type::T_ENUM:
+ case CRM_Utils_Type::T_DATE:
+ case CRM_Utils_Type::T_TIME:
+ case CRM_Utils_Type::T_TIMESTAMP:
+ case CRM_Utils_Type::T_MONEY:
+ case CRM_Utils_Type::T_EMAIL:
+ case CRM_Utils_Type::T_URL:
+ case CRM_Utils_Type::T_CCNUM:
+ default:
+ return "$fieldName varchar(32)";
+ }
+ }
+ else {
+ if (substr($fieldName, -3, 3) == '_id') {
+ return "$fieldName varchar(255)";
+ }
+ elseif (substr($fieldName, -5, 5) == '_note') {
+ return "$fieldName text";
+ }
+ else {
+ $changeFields = [
+ 'groups',
+ 'tags',
+ 'notes',
+ ];
+
+ if (in_array($fieldName, $changeFields)) {
+ return "$fieldName text";
+ }
+ else {
+ // set the sql columns for custom data
+ if (isset($queryFields[$field]['data_type'])) {
+
+ switch ($queryFields[$field]['data_type']) {
+ case 'String':
+ // May be option labels, which could be up to 512 characters
+ $length = max(512, CRM_Utils_Array::value('text_length', $queryFields[$field]));
+ return "$fieldName varchar($length)";
+
+ case 'Country':
+ case 'StateProvince':
+ case 'Link':
+ return "$fieldName varchar(255)";
+
+ case 'Memo':
+ return "$fieldName text";
+
+ default:
+ return "$fieldName varchar(255)";
+ }
+ }
+ else {
+ return "$fieldName text";
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the munged field name.
+ *
+ * @param string $field
+ * @return string
+ */
+ public function getMungedFieldName($field) {
+ $fieldName = CRM_Utils_String::munge(strtolower($field), '_', 64);
+ if ($fieldName == 'id') {
+ $fieldName = 'civicrm_primary_id';
+ }
+ return $fieldName;
+ }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select.php
index 3e36b238ca9..af478d4adfa 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select.php
@@ -36,7 +36,7 @@
/**
* This class gets the name of the file to upload
*/
-class CRM_Export_Form_Select extends CRM_Core_Form {
+class CRM_Export_Form_Select extends CRM_Core_Form_Task {
/**
* Various Contact types.
@@ -70,20 +70,6 @@ class CRM_Export_Form_Select extends CRM_Core_Form {
public $_componentTable;
- /**
- * Must be set to entity table name (eg. civicrm_participant) by child class
- *
- * @var string
- */
- static $tableName = NULL;
-
- /**
- * Must be set to entity shortname (eg. event)
- *
- * @var string
- */
- static $entityShortname = NULL;
-
/**
* Build all the data structures needed to build the form.
*
@@ -108,23 +94,14 @@ public function preProcess() {
$this->_componentIds = array();
$this->_componentClause = NULL;
- $stateMachine = $this->controller->getStateMachine();
- $formName = CRM_Utils_System::getClassName($stateMachine);
- $isStandalone = $formName == 'CRM_Export_StateMachine_Standalone';
-
// we need to determine component export
- $componentName = explode('_', $formName);
$components = array('Contact', 'Contribute', 'Member', 'Event', 'Pledge', 'Case', 'Grant', 'Activity');
- if ($isStandalone) {
- $componentName = array('CRM', $this->controller->get('entity'));
- }
-
- $componentMode = $this->controller->get('component_mode');
// FIXME: This should use a modified version of CRM_Contact_Form_Search::getModeValue but it doesn't have all the contexts
- switch ($componentMode) {
+ switch ($this->getQueryMode()) {
case CRM_Contact_BAO_Query::MODE_CONTRIBUTE:
$entityShortname = 'Contribute';
+ $entityDAOName = $entityShortname;
break;
case CRM_Contact_BAO_Query::MODE_MEMBER:
@@ -134,33 +111,41 @@ public function preProcess() {
case CRM_Contact_BAO_Query::MODE_EVENT:
$entityShortname = 'Event';
+ $entityDAOName = $entityShortname;
break;
case CRM_Contact_BAO_Query::MODE_PLEDGE:
$entityShortname = 'Pledge';
+ $entityDAOName = $entityShortname;
break;
case CRM_Contact_BAO_Query::MODE_CASE:
$entityShortname = 'Case';
+ $entityDAOName = $entityShortname;
break;
case CRM_Contact_BAO_Query::MODE_GRANT:
$entityShortname = 'Grant';
+ $entityDAOName = $entityShortname;
break;
case CRM_Contact_BAO_Query::MODE_ACTIVITY:
$entityShortname = 'Activity';
+ $entityDAOName = $entityShortname;
break;
default:
+ // FIXME: Code cleanup, we may not need to do this $componentName code here.
+ $formName = CRM_Utils_System::getClassName($this->controller->getStateMachine());
+ $componentName = explode('_', $formName);
+ if ($formName == 'CRM_Export_StateMachine_Standalone') {
+ $componentName = array('CRM', $this->controller->get('entity'));
+ }
$entityShortname = $componentName[1]; // Contact
+ $entityDAOName = $entityShortname;
break;
}
- if (empty($entityDAOName)) {
- $entityDAOName = $entityShortname;
- }
-
if (in_array($entityShortname, $components)) {
$this->_exportMode = constant('CRM_Export_Form_Select::' . strtoupper($entityShortname) . '_EXPORT');
$formTaskClassName = "CRM_{$entityShortname}_Form_Task";
@@ -210,7 +195,7 @@ public function preProcess() {
}
}
- $formTaskClassName::preProcessCommon($this, !$isStandalone);
+ $formTaskClassName::preProcessCommon($this);
// $component is used on CRM/Export/Form/Select.tpl to display extra information for contact export
($this->_exportMode == self::CONTACT_EXPORT) ? $component = FALSE : $component = TRUE;
@@ -358,7 +343,7 @@ public function buildQuickForm() {
* @return bool|array
* mixed true or array of errors
*/
- static public function formRule($params, $files, $self) {
+ public static function formRule($params, $files, $self) {
$errors = array();
if (CRM_Utils_Array::value('mergeOption', $params) == self::EXPORT_MERGE_SAME_ADDRESS &&
@@ -386,7 +371,7 @@ static public function formRule($params, $files, $self) {
/**
* Process the uploaded file.
*
- * @return void
+ * @throws \CRM_Core_Exception
*/
public function postProcess() {
$params = $this->controller->exportValues($this->_name);
@@ -535,4 +520,13 @@ public static function getGreetingOptions() {
return $options;
}
+ /**
+ * Get the query mode (eg. CRM_Core_BAO_Query::MODE_CASE)
+ *
+ * @return int
+ */
+ public function getQueryMode() {
+ return (int) ($this->queryMode ?: $this->controller->get('component_mode'));
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select/Case.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select/Case.php
new file mode 100644
index 00000000000..c95aba984ae
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Export/Form/Select/Case.php
@@ -0,0 +1,53 @@
+cache && !$fresh) {
- $moduleExtensions = $this->cache->get($this->cacheKey . '/moduleFiles');
+ $moduleExtensions = $this->cache->get($this->cacheKey . '_moduleFiles');
}
if ($fresh == 'NOCACHE') {
@@ -319,7 +319,7 @@ public function getActiveModuleFiles($fresh = FALSE) {
}
if ($this->cache) {
- $this->cache->set($this->cacheKey . '/moduleFiles', $moduleExtensions);
+ $this->cache->set($this->cacheKey . '_moduleFiles', $moduleExtensions);
}
}
return $moduleExtensions;
@@ -465,7 +465,7 @@ public function refresh() {
$this->infos = array();
$this->moduleExtensions = NULL;
if ($this->cache) {
- $this->cache->delete($this->cacheKey . '/moduleFiles');
+ $this->cache->delete($this->cacheKey . '_moduleFiles');
}
// FIXME: How can code so code wrong be so right?
CRM_Extension_System::singleton()->getClassLoader()->refresh();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialAccount.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialAccount.php
index 062eef27e1e..e171ee9a48b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialAccount.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialAccount.php
@@ -32,11 +32,6 @@
*/
class CRM_Financial_BAO_FinancialAccount extends CRM_Financial_DAO_FinancialAccount {
- /**
- * Static holder for the default LT.
- */
- static $_defaultContributionType = NULL;
-
/**
* Class constructor.
*/
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialItem.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialItem.php
index 63eee63f636..35e6b448d98 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialItem.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialItem.php
@@ -47,7 +47,7 @@ public function __construct() {
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
- * @return CRM_Financial_BAO_FinancialItem
+ * @return CRM_Financial_DAO_FinancialItem
*/
public static function retrieve(&$params, &$defaults) {
$financialItem = new CRM_Financial_DAO_FinancialItem();
@@ -189,9 +189,9 @@ public static function create(&$params, $ids = NULL, $trxnIds = NULL) {
* Takes an associative array and creates a entity financial transaction object.
*
* @param array $params
- * (reference ) an assoc array of name/value pairs.
+ * an assoc array of name/value pairs.
*
- * @return CRM_Core_BAO_FinancialTrxn
+ * @return CRM_Financial_DAO_EntityFinancialTrxn
*/
public static function createEntityTrxn($params) {
$entity_trxn = new CRM_Financial_DAO_EntityFinancialTrxn();
@@ -204,9 +204,9 @@ public static function createEntityTrxn($params) {
* Retrive entity financial trxn details.
*
* @param array $params
- * (reference ) an assoc array of name/value pairs.
+ * an assoc array of name/value pairs.
* @param bool $maxId
- * To retrive max id.
+ * To retrieve max id.
*
* @return array
*/
@@ -247,7 +247,7 @@ public static function retrieveEntityFinancialTrxn($params, $maxId = FALSE) {
* @param array $error
* Error to display.
*
- * @return array
+ * @return array|bool
*/
public static function checkContactPresent($contactIds, &$error) {
if (empty($contactIds)) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialType.php
index 3f5f5efe8d7..901e7888ee4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/BAO/FinancialType.php
@@ -32,10 +32,6 @@
*/
class CRM_Financial_BAO_FinancialType extends CRM_Financial_DAO_FinancialType {
- /**
- * Static holder for the default LT.
- */
- static $_defaultContributionType = NULL;
/**
* Static cache holder of available financial types for this session
*/
@@ -60,7 +56,7 @@ public function __construct() {
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
- * @return CRM_Contribute_BAO_ContributionType
+ * @return CRM_Financial_DAO_FinancialType
*/
public static function retrieve(&$params, &$defaults) {
$financialType = new CRM_Financial_DAO_FinancialType();
@@ -80,8 +76,7 @@ public static function retrieve(&$params, &$defaults) {
* @param bool $is_active
* Value we want to set the is_active field.
*
- * @return Object
- * DAO object on success, null otherwise
+ * @return bool
*/
public static function setIsActive($id, $is_active) {
return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_FinancialType', $id, 'is_active', $is_active);
@@ -139,7 +134,7 @@ public static function del($financialTypeId) {
$financialType = new CRM_Financial_DAO_FinancialType();
$financialType->id = $financialTypeId;
$financialType->find(TRUE);
- // tables to ingore checks for financial_type_id
+ // tables to ignore checks for financial_type_id
$ignoreTables = array('CRM_Financial_DAO_EntityFinancialAccount');
// TODO: if (!$financialType->find(true)) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialAccount.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialAccount.php
index 4d7f073092b..f2ab3fff119 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialAccount.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialAccount.php
@@ -279,6 +279,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Header Financial Account?'),
'description' => 'Is this a header account which does not allow transactions to be posted against it directly, but only to its sub-accounts?',
+ 'default' => '0',
'table_name' => 'civicrm_financial_account',
'entity' => 'FinancialAccount',
'bao' => 'CRM_Financial_BAO_FinancialAccount',
@@ -300,6 +301,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Tax Financial Account?'),
'description' => 'Is this account for taxes?',
+ 'default' => '0',
'table_name' => 'civicrm_financial_account',
'entity' => 'FinancialAccount',
'bao' => 'CRM_Financial_BAO_FinancialAccount',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialItem.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialItem.php
index 480b78afdca..7cfd9b651eb 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialItem.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialItem.php
@@ -207,6 +207,7 @@ public static function &fields() {
20,
2
],
+ 'default' => '0',
'table_name' => 'civicrm_financial_item',
'entity' => 'FinancialItem',
'bao' => 'CRM_Financial_BAO_FinancialItem',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialTrxn.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialTrxn.php
index 6ac9060720c..bf194318976 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialTrxn.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialTrxn.php
@@ -321,6 +321,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_financial_trxn',
'entity' => 'FinancialTrxn',
'bao' => 'CRM_Financial_DAO_FinancialTrxn',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialType.php
index 7ee17ac490c..8f805cb8c3d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/DAO/FinancialType.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Financial/FinancialType.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:9d787931917508983d68631821eea721)
+ * (GenCodeChecksum:6d85bc0675253407de19ac9226ba4478)
*/
/**
@@ -114,6 +114,15 @@ public static function &fields() {
'entity' => 'FinancialType',
'bao' => 'CRM_Financial_BAO_FinancialType',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'Text',
+ 'label' => ts("Name"),
+ ],
+ 'pseudoconstant' => [
+ 'table' => 'civicrm_financial_type',
+ 'keyColumn' => 'id',
+ 'labelColumn' => 'name',
+ ]
],
'description' => [
'name' => 'description',
@@ -126,6 +135,10 @@ public static function &fields() {
'entity' => 'FinancialType',
'bao' => 'CRM_Financial_BAO_FinancialType',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'TextArea',
+ 'label' => ts("Description"),
+ ],
],
'is_deductible' => [
'name' => 'is_deductible',
@@ -137,6 +150,10 @@ public static function &fields() {
'entity' => 'FinancialType',
'bao' => 'CRM_Financial_BAO_FinancialType',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'CheckBox',
+ 'label' => ts("Tax-Deductible?"),
+ ],
],
'is_reserved' => [
'name' => 'is_reserved',
@@ -147,6 +164,10 @@ public static function &fields() {
'entity' => 'FinancialType',
'bao' => 'CRM_Financial_BAO_FinancialType',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'CheckBox',
+ 'label' => ts("Reserved?"),
+ ],
],
'is_active' => [
'name' => 'is_active',
@@ -157,6 +178,10 @@ public static function &fields() {
'entity' => 'FinancialType',
'bao' => 'CRM_Financial_BAO_FinancialType',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'CheckBox',
+ 'label' => ts("Enabled?"),
+ ],
],
];
CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialAccount.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialAccount.php
index 5b9b8f49c31..1b1eb9e3acf 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialAccount.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialAccount.php
@@ -200,7 +200,14 @@ public function postProcess() {
if ($this->_action & CRM_Core_Action::UPDATE) {
$params['id'] = $this->_id;
}
-
+ foreach ([
+ 'is_active',
+ 'is_deductible',
+ 'is_tax',
+ 'is_default',
+ ] as $field) {
+ $params[$field] = CRM_Utils_Array::value($field, $params, FALSE);
+ }
$financialAccount = CRM_Financial_BAO_FinancialAccount::add($params);
CRM_Core_Session::setStatus(ts('The Financial Account \'%1\' has been saved.', array(1 => $financialAccount->name)), ts('Saved'), 'success');
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialType.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialType.php
index 10a30c7f248..3600ef65473 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialType.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Form/FinancialType.php
@@ -36,6 +36,22 @@
*/
class CRM_Financial_Form_FinancialType extends CRM_Contribute_Form {
+ use CRM_Core_Form_EntityFormTrait;
+
+ /**
+ * Fields for the entity to be assigned to the template.
+ *
+ * @var array
+ */
+ protected $entityFields = [];
+
+ /**
+ * Deletion message to be assigned to the form.
+ *
+ * @var string
+ */
+ protected $deleteMessage;
+
/**
* Set variables up before form is built.
*/
@@ -46,40 +62,67 @@ public function preProcess() {
) {
CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
}
+ $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
parent::preProcess();
+ $this->setPageTitle(ts('Financial Type'));
+ if ($this->_id) {
+ $this->_title = CRM_Core_PseudoConstant::getLabel(
+ 'CRM_Financial_BAO_FinancialType',
+ 'financial_type',
+ $this->_id
+ );
+ $this->assign('aid', $this->_id);
+ }
+ }
+
+ /**
+ * Set entity fields to be assigned to the form.
+ */
+ protected function setEntityFields() {
+ $this->entityFields = [
+ 'name' => [
+ 'name' => 'name',
+ 'required' => TRUE,
+ ],
+ 'description' => ['name' => 'description'],
+ 'is_deductible' => [
+ 'name' => 'is_deductible',
+ 'description' => ts('Are contributions of this type tax-deductible?'),
+ ],
+ 'is_reserved' => ['name' => 'is_reserved'],
+ 'is_active' => ['name' => 'is_active'],
+ ];
+ }
+
+ /**
+ * Explicitly declare the entity api name.
+ */
+ public function getDefaultEntity() {
+ return 'FinancialType';
+ }
+
+ /**
+ * Set the delete message.
+ *
+ * We do this from the constructor in order to do a translation.
+ */
+ public function setDeleteMessage() {
+ $this->deleteMessage = ts('WARNING: You cannot delete a financial type if it is currently used by any Contributions, Contribution Pages or Membership Types. Consider disabling this option instead.') . ts('Deleting a financial type cannot be undone.') . ts('Do you want to continue?');
}
/**
* Build the form object.
*/
public function buildQuickForm() {
- parent::buildQuickForm();
- $this->setPageTitle(ts('Financial Type'));
-
- $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
- if ($this->_id) {
- $this->_title = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $this->_id, 'name');
- }
+ self::buildQuickEntityForm();
if ($this->_action & CRM_Core_Action::DELETE) {
return;
}
- $this->applyFilter('__ALL__', 'trim');
- $this->add('text', 'name', ts('Name'), CRM_Core_DAO::getAttribute('CRM_Financial_DAO_FinancialType', 'name'), TRUE);
-
- $this->add('text', 'description', ts('Description'), CRM_Core_DAO::getAttribute('CRM_Financial_DAO_FinancialType', 'description'));
-
- $this->add('checkbox', 'is_deductible', ts('Tax-Deductible?'), CRM_Core_DAO::getAttribute('CRM_Financial_DAO_FinancialType', 'is_deductible'));
- $this->add('checkbox', 'is_active', ts('Enabled?'), CRM_Core_DAO::getAttribute('CRM_Financial_DAO_FinancialType', 'is_active'));
- $this->add('checkbox', 'is_reserved', ts('Reserved?'), CRM_Core_DAO::getAttribute('CRM_Financial_DAO_FinancialType', 'is_reserved'));
- if ($this->_action == CRM_Core_Action::UPDATE) {
- $this->assign('aid', $this->_id);
- }
- if ($this->_action == CRM_Core_Action::UPDATE && CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $this->_id, 'is_reserved', 'vid')) {
- $this->freeze(array('is_active'));
+ if ($this->_action == CRM_Core_Action::UPDATE && CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $this->_id, 'is_reserved')) {
+ $this->freeze(['is_active']);
}
-
$this->addRule('name', ts('A financial type with this name already exists. Please select another name.'), 'objectExists',
- array('CRM_Financial_DAO_FinancialType', $this->_id)
+ ['CRM_Financial_DAO_FinancialType', $this->_id]
);
}
@@ -95,35 +138,46 @@ public function postProcess() {
CRM_Core_Session::setStatus(ts('Selected financial type has been deleted.'), ts('Record Deleted'), 'success');
}
else {
- $params = $ids = array();
// store the submitted values in an array
$params = $this->exportValues();
-
- if ($this->_action & CRM_Core_Action::UPDATE) {
- $ids['financialType'] = $this->_id;
+ if ($this->_id) {
+ $params['id'] = $this->_id;
}
-
- $financialType = CRM_Financial_BAO_FinancialType::add($params, $ids);
+ foreach ([
+ 'is_active',
+ 'is_reserved',
+ 'is_deductible',
+ ] as $field) {
+ $params[$field] = CRM_Utils_Array::value($field, $params, FALSE);
+ }
+ $financialType = civicrm_api3('FinancialType', 'create', $params);
if ($this->_action & CRM_Core_Action::UPDATE) {
$url = CRM_Utils_System::url('civicrm/admin/financial/financialType', 'reset=1&action=browse');
- CRM_Core_Session::setStatus(ts('The financial type "%1" has been updated.', array(1 => $financialType->name)), ts('Saved'), 'success');
+ CRM_Core_Session::setStatus(ts('The financial type "%1" has been updated.', [1 => $params['name']]), ts('Saved'), 'success');
}
else {
- $url = CRM_Utils_System::url('civicrm/admin/financial/financialType/accounts', 'reset=1&action=browse&aid=' . $financialType->id);
- $statusArray = array(
- 1 => $financialType->name,
- 2 => $financialType->name,
- 3 => CRM_Utils_Array::value(0, $financialType->titles),
- 4 => CRM_Utils_Array::value(1, $financialType->titles),
- 5 => CRM_Utils_Array::value(2, $financialType->titles),
- );
- if (empty($financialType->titles)) {
- $text = ts('Your Financial "%1" Type has been created and assigned to an existing financial account with the same title. You should review the assigned account and determine whether additional account relationships are needed.', $statusArray);
+ $url = CRM_Utils_System::url('civicrm/admin/financial/financialType/accounts', 'reset=1&action=browse&aid=' . $financialType['id']);
+
+ $statusArray = [
+ 1 => $params['name'],
+ ];
+ $financialAccounts = civicrm_api3('EntityFinancialAccount', 'get', [
+ 'return' => ["financial_account_id.name"],
+ 'entity_table' => "civicrm_financial_type",
+ 'entity_id' => $financialType['id'],
+ 'options' => ['sort' => "id"],
+ 'account_relationship' => ['!=' => "Income Account is"],
+ ]);
+ if (!empty($financialAccounts['values'])) {
+ foreach ($financialAccounts['values'] as $financialAccount) {
+ $statusArray[] = $financialAccount['financial_account_id.name'];
+ }
+ $text = ts('Your Financial "%1" Type has been created, along with a corresponding income account "%1". That income account, along with standard financial accounts "%2", "%3" and "%4" have been linked to the financial type. You may edit or replace those relationships here.', $statusArray);
}
else {
- $text = ts('Your Financial "%1" Type has been created, along with a corresponding income account "%2". That income account, along with standard financial accounts "%3", "%4" and "%5" have been linked to the financial type. You may edit or replace those relationships here.', $statusArray);
+ $text = ts('Your Financial "%1" Type has been created and assigned to an existing financial account with the same title. You should review the assigned account and determine whether additional account relationships are needed.', $statusArray);
}
- CRM_Core_Session::setStatus($text, ts('Saved'), 'success', array('expires' => 0));
+ CRM_Core_Session::setStatus($text, ts('Saved'), 'success', ['expires' => 0]);
}
$session = CRM_Core_Session::singleton();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Page/AJAX.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Page/AJAX.php
index 1c3a9bc2663..c5a51b5f993 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Page/AJAX.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Financial/Page/AJAX.php
@@ -293,6 +293,8 @@ public static function getFinancialTransactionsList() {
'civicrm_financial_trxn.currency as currency',
'civicrm_financial_trxn.status_id as status',
'civicrm_financial_trxn.check_number as check_number',
+ 'civicrm_financial_trxn.card_type_id',
+ 'civicrm_financial_trxn.pan_truncation',
);
$columnHeader = array(
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/BAO/Friend.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/BAO/Friend.php
index 2d650fd8d7e..38455411ff9 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/BAO/Friend.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/BAO/Friend.php
@@ -29,15 +29,22 @@
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2018
- * $Id$
*
*/
/**
- * This class contains the funtions for Friend
+ * This class contains the functions for Friend
*
*/
class CRM_Friend_BAO_Friend extends CRM_Friend_DAO_Friend {
+
+ /**
+ * Tell a friend id in db.
+ *
+ * @var int
+ */
+ public $_friendId;
+
/**
*/
public function __construct() {
@@ -74,13 +81,9 @@ public static function add(&$params) {
*/
public static function retrieve(&$params, &$values) {
$friend = new CRM_Friend_DAO_Friend();
-
$friend->copyValues($params);
-
$friend->find(TRUE);
-
CRM_Core_DAO::storeValues($friend, $values);
-
return $values;
}
@@ -88,15 +91,17 @@ public static function retrieve(&$params, &$values) {
* Takes an associative array and creates a friend object.
*
* @param array $params
- * (reference ) an assoc array of name/value pairs.
+ * (reference) an assoc array of name/value pairs.
*
- * @return void
+ * @throws \CRM_Core_Exception
*/
public static function create(&$params) {
$transaction = new CRM_Core_Transaction();
$mailParams = array();
- //create contact corresponding to each friend
+ $contactParams = array();
+
+ // create contact corresponding to each friend
foreach ($params['friend'] as $key => $details) {
if ($details["first_name"]) {
$contactParams[$key] = array(
@@ -111,14 +116,15 @@ public static function create(&$params) {
}
}
- $frndParams = array();
- $frndParams['entity_id'] = $params['entity_id'];
- $frndParams['entity_table'] = $params['entity_table'];
- self::getValues($frndParams);
+ $friendParams = [
+ 'entity_id' => $params['entity_id'],
+ 'entity_table' => $params['entity_table'],
+ ];
+ self::getValues($friendParams);
$activityTypeId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', 'Tell a Friend', 'value', 'name');
- //create activity
+ // create activity
$activityParams = array(
'source_contact_id' => $params['source_contact_id'],
'source_record_id' => NULL,
@@ -127,20 +133,19 @@ public static function create(&$params) {
'activity_date_time' => date("YmdHis"),
'subject' => ts('Tell a Friend') . ": {$params['title']}",
'details' => $params['suggested_message'],
- 'status_id' => 2,
+ 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed'),
'is_test' => $params['is_test'],
'campaign_id' => CRM_Utils_Array::value('campaign_id', $params),
);
- //activity creation
+ // activity creation
$activity = CRM_Activity_BAO_Activity::create($activityParams);
$activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
- //friend contacts creation
+ // friend contacts creation
foreach ($contactParams as $key => $value) {
-
- //create contact only if it does not exits in db
+ // create contact only if it does not exits in db
$value['email'] = $value['email-Primary'];
$contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($value, 'Individual', 'Supervised', array(), FALSE);
@@ -167,28 +172,27 @@ public static function create(&$params) {
$transaction->commit();
- //process sending of mails
+ // Process sending of mails
$mailParams['title'] = CRM_Utils_Array::value('title', $params);
- $mailParams['general_link'] = CRM_Utils_Array::value('general_link', $frndParams);
+ $mailParams['general_link'] = CRM_Utils_Array::value('general_link', $friendParams);
$mailParams['message'] = CRM_Utils_Array::value('suggested_message', $params);
- // get domain
- $domainDetails = CRM_Core_BAO_Domain::getNameAndEmail();
- list($username, $mailParams['domain']) = explode('@', $domainDetails[1]);
+ // Default "from email address" is default domain address.
+ list($_, $mailParams['email_from']) = CRM_Core_BAO_Domain::getNameAndEmail();
+ list($username, $mailParams['domain']) = explode('@', $mailParams['email_from']);
$default = array();
$findProperties = array('id' => $params['entity_id']);
if ($params['entity_table'] == 'civicrm_contribution_page') {
-
$returnProperties = array('receipt_from_email', 'is_email_receipt');
CRM_Core_DAO::commonRetrieve('CRM_Contribute_DAO_ContributionPage',
$findProperties,
$default,
$returnProperties
);
- //if is_email_receipt is set then take receipt_from_email
- //as from_email
+
+ // if is_email_receipt is set then take receipt_from_email as from_email
if (!empty($default['is_email_receipt']) && !empty($default['receipt_from_email'])) {
$mailParams['email_from'] = $default['receipt_from_email'];
}
@@ -197,7 +201,6 @@ public static function create(&$params) {
$mailParams['module'] = 'contribute';
}
elseif ($params['entity_table'] == 'civicrm_event') {
-
$returnProperties = array('confirm_from_email', 'is_email_confirm');
CRM_Core_DAO::commonRetrieve('CRM_Event_DAO_Event',
$findProperties,
@@ -205,10 +208,7 @@ public static function create(&$params) {
$returnProperties
);
- $mailParams['email_from'] = $domainDetails['1'];
-
- //if is_email_confirm is set then take confirm_from_email
- //as from_email
+ // if is_email_confirm is set then take confirm_from_email as from_email
if (!empty($default['is_email_confirm']) && !empty($default['confirm_from_email'])) {
$mailParams['email_from'] = $default['confirm_from_email'];
}
@@ -217,23 +217,25 @@ public static function create(&$params) {
$mailParams['module'] = 'event';
}
elseif ($params['entity_table'] == 'civicrm_pcp') {
- $mailParams['email_from'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Email', $params['source_contact_id'],
- 'email', 'contact_id'
- );
+ if (Civi::settings()->get('allow_mail_from_logged_in_contact')) {
+ $mailParams['email_from'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Email', $params['source_contact_id'],
+ 'email', 'contact_id'
+ );
+ }
$urlPath = 'civicrm/pcp/info';
$mailParams['module'] = 'contribute';
}
$mailParams['page_url'] = CRM_Utils_System::url($urlPath, "reset=1&id={$params['entity_id']}", TRUE, NULL, FALSE, TRUE);
- //send mail
+ // Send the email
self::sendMail($params['source_contact_id'], $mailParams);
}
/**
* Build the form object.
*
- * @param CRM_Core_Form $form
+ * @param CRM_Friend_Form $form
* Form object.
*
* @return void
@@ -263,12 +265,12 @@ public static function buildFriendForm($form) {
}
/**
- * The function sets the deafult values of the form.
+ * The function sets the default values of the form.
*
* @param array $defaults
* (reference) the default values.
*
- * @return booelan
+ * @return bool
* whether anything was found
*/
public static function getValues(&$defaults) {
@@ -283,7 +285,7 @@ public static function getValues(&$defaults) {
}
/**
- * Process that send tell a friend e-mails
+ * Process that sends tell a friend e-mails
*
* @param int $contactID
* @param array $values
@@ -297,33 +299,41 @@ public static function sendMail($contactID, &$values) {
$fromName = $email;
}
- // use contact email, CRM-4963
+ if (Civi::settings()->get('allow_mail_from_logged_in_contact')) {
+ // use contact email, CRM-4963
+ if (empty($values['email_from'])) {
+ $values['email_from'] = $email;
+ }
+ }
+
+ // If we have no "email_from" when we get to here, explicitly set it to the default domain email.
if (empty($values['email_from'])) {
- $values['email_from'] = $email;
+ list($domainFromName, $domainEmail) = CRM_Core_BAO_Domain::getNameAndEmail();
+ $values['email_from'] = $domainEmail;
+ $values['domain'] = $domainFromName;
}
+ $templateParams = array(
+ 'groupName' => 'msg_tpl_workflow_friend',
+ 'valueName' => 'friend',
+ 'contactId' => $contactID,
+ 'tplParams' => array(
+ $values['module'] => $values['module'],
+ 'senderContactName' => $fromName,
+ 'title' => $values['title'],
+ 'generalLink' => $values['general_link'],
+ 'pageURL' => $values['page_url'],
+ 'senderMessage' => $values['message'],
+ ),
+ 'from' => "$fromName (via {$values['domain']}) <{$values['email_from']}>",
+ 'replyTo' => $email,
+ );
+
foreach ($values['email'] as $displayName => $emailTo) {
if ($emailTo) {
- // FIXME: factor the below out of the foreach loop
- CRM_Core_BAO_MessageTemplate::sendTemplate(
- array(
- 'groupName' => 'msg_tpl_workflow_friend',
- 'valueName' => 'friend',
- 'contactId' => $contactID,
- 'tplParams' => array(
- $values['module'] => $values['module'],
- 'senderContactName' => $fromName,
- 'title' => $values['title'],
- 'generalLink' => $values['general_link'],
- 'pageURL' => $values['page_url'],
- 'senderMessage' => $values['message'],
- ),
- 'from' => "$fromName (via {$values['domain']}) <{$values['email_from']}>",
- 'toName' => $displayName,
- 'toEmail' => $emailTo,
- 'replyTo' => $email,
- )
- );
+ $templateParams['toName'] = $displayName;
+ $templateParams['toEmail'] = $emailTo;
+ CRM_Core_BAO_MessageTemplate::sendTemplate($templateParams);
}
}
}
@@ -336,16 +346,14 @@ public static function sendMail($contactID, &$values) {
* pairs
*
* @param array $params
- * (reference ) an assoc array of name/value pairs.
+ * (reference) an assoc array of name/value pairs.
*
- * @return CRM_Friend_BAO_Friend
+ * @return CRM_Friend_DAO_Friend
*/
public static function addTellAFriend(&$params) {
$friendDAO = new CRM_Friend_DAO_Friend();
-
$friendDAO->copyValues($params);
$friendDAO->is_active = CRM_Utils_Array::value('is_active', $params, FALSE);
-
$friendDAO->save();
return $friendDAO;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/Form.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/Form.php
index 7f0329ac49a..9b2a9c9f765 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/Form.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Friend/Form.php
@@ -45,14 +45,21 @@ class CRM_Friend_Form extends CRM_Core_Form {
const NUM_OPTION = 3;
/**
- * The id of the entity that we are proceessing.
+ * The id of the entity that we are processing.
*
* @var int
*/
protected $_entityId;
/**
- * The table name of the entity that we are proceessing.
+ * Tell a friend id in db.
+ *
+ * @var int
+ */
+ public $_friendId;
+
+ /**
+ * The table name of the entity that we are processing.
*
* @var string
*/
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Grant/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Grant/Form/Task.php
index 51f505428ee..58fd8f9acff 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Grant/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Grant/Form/Task.php
@@ -34,31 +34,10 @@
*/
/**
- * This class generates task actions for CiviEvent
- *
+ * Class for grant form task actions.
+ * FIXME: This needs refactoring to properly inherit from CRM_Core_Form_Task and share more functions.
*/
-class CRM_Grant_Form_Task extends CRM_Core_Form {
-
- /**
- * The task being performed.
- *
- * @var int
- */
- protected $_task;
-
- /**
- * The additional clause that we restrict the search with.
- *
- * @var string
- */
- protected $_componentClause = NULL;
-
- /**
- * The array that holds all the component ids.
- *
- * @var array
- */
- protected $_componentIds;
+class CRM_Grant_Form_Task extends CRM_Core_Form_Task {
/**
* The array that holds all the grant ids.
@@ -80,9 +59,8 @@ public function preProcess() {
/**
* @param CRM_Core_Form $form
- * @param bool $useTable
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_grantIds = array();
$values = $form->controller->exportValues('Search');
@@ -127,7 +105,7 @@ public static function preProcessCommon(&$form, $useTable = FALSE) {
$form->_grantIds = $form->_componentIds = $ids;
//set the context for redirection for any task actions
- $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
+ $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form);
$urlParams = 'force=1';
if (CRM_Utils_Rule::qfKey($qfKey)) {
$urlParams .= "&qfKey=$qfKey";
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Edit.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Edit.php
index a4d944e18f7..810ca19d1b8 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Edit.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Edit.php
@@ -364,7 +364,7 @@ public static function formRule($fields, $fileParams, $options) {
* Process the form when submitted.
*/
public function postProcess() {
- CRM_Utils_System::flushCache('CRM_Core_DAO_Group');
+ CRM_Utils_System::flushCache();
$updateNestingCache = FALSE;
if ($this->_action & CRM_Core_Action::DELETE) {
@@ -458,7 +458,7 @@ public static function buildParentGroups(&$form) {
$potentialParentGroupIds = array_keys($groupNames);
}
- $parentGroupSelectValues = array('' => '- ' . ts('select group') . ' -');
+ $parentGroupSelectValues = array();
foreach ($potentialParentGroupIds as $potentialParentGroupId) {
if (array_key_exists($potentialParentGroupId, $groupNames)) {
$parentGroupSelectValues[$potentialParentGroupId] = $groupNames[$potentialParentGroupId];
@@ -472,7 +472,7 @@ public static function buildParentGroups(&$form) {
else {
$required = FALSE;
}
- $form->add('select', 'parents', ts('Add Parent'), $parentGroupSelectValues, $required, array('class' => 'crm-select2'));
+ $form->add('select', 'parents', ts('Add Parent'), $parentGroupSelectValues, $required, array('class' => 'crm-select2', 'multiple' => TRUE));
}
return $parentGroups;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Search.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Search.php
index f05dfdcb830..a8edc042fde 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Search.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Form/Search.php
@@ -81,6 +81,17 @@ public function buildQuickForm() {
NULL, NULL, NULL, NULL, ' '
);
+ $componentModes = CRM_Contact_Form_Search::getModeSelect();
+ if (count($componentModes) > 1) {
+ $this->add('select',
+ 'component_mode',
+ ts('View Results As'),
+ $componentModes,
+ FALSE,
+ array('class' => 'crm-select2')
+ );
+ }
+
$this->addButtons(array(
array(
'type' => 'refresh',
@@ -97,7 +108,7 @@ public function postProcess() {
$params = $this->controller->exportValues($this->_name);
$parent = $this->controller->getParent();
if (!empty($params)) {
- $fields = array('title', 'created_by', 'group_type', 'visibility', 'active_status', 'inactive_status');
+ $fields = array('title', 'created_by', 'group_type', 'visibility', 'active_status', 'inactive_status', 'component_mode');
foreach ($fields as $field) {
if (isset($params[$field]) &&
!CRM_Utils_System::isNull($params[$field])
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Page/AJAX.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Page/AJAX.php
index a1d9211f9f0..da2e8f1ea65 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Page/AJAX.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Group/Page/AJAX.php
@@ -54,6 +54,7 @@ public static function getGroupList() {
'created_by' => 'String',
'group_type' => 'String',
'visibility' => 'String',
+ 'component_mode' => 'String',
'status' => 'Integer',
'parentsOnly' => 'Integer',
'showOrgInfo' => 'Boolean',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Logging/Schema.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Logging/Schema.php
index 996653ce6cd..a24906ef91b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Logging/Schema.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Logging/Schema.php
@@ -945,7 +945,7 @@ public static function disableLoggingForThisConnection() {
* but this is the only entity currently available...
*/
public function getLogTablesForContact() {
- $tables = array_keys(CRM_Dedupe_Merger::cidRefs());
+ $tables = array_keys(CRM_Core_DAO::getReferencesToContactTable());
return array_intersect($tables, $this->tables);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Mailing.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Mailing.php
index 8e34d917e12..212284f00ee 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Mailing.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Mailing.php
@@ -228,35 +228,39 @@ public static function getRecipients($mailingID) {
);
if ($isSMSmode) {
- $includeFilters = array(
- "mg.group_type = 'Include'",
- 'mg.search_id IS NULL',
- "$contact.is_opt_out = 0",
- "$contact.is_deceased <> 1",
- "$entityTable.phone_type_id = " . CRM_Core_PseudoConstant::getKey('CRM_Core_DAO_Phone', 'phone_type_id', 'Mobile'),
- "$entityTable.phone IS NOT NULL",
- "$entityTable.phone != ''",
- "$entityTable.is_primary = 1",
- "mg.mailing_id = #mailingID",
- 'temp.contact_id IS null',
+ $criteria = array(
+ 'is_opt_out' => CRM_Utils_SQL_Select::fragment()->where("$contact.is_opt_out = 0"),
+ 'is_deceased' => CRM_Utils_SQL_Select::fragment()->where("$contact.is_deceased <> 1"),
+ 'do_not_sms' => CRM_Utils_SQL_Select::fragment()->where("$contact.do_not_sms = 0"),
+ 'location_filter' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.phone_type_id = " . CRM_Core_PseudoConstant::getKey('CRM_Core_DAO_Phone', 'phone_type_id', 'Mobile')),
+ 'phone_not_null' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.phone IS NOT NULL"),
+ 'phone_not_empty' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.phone != ''"),
+ 'is_primary' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.is_primary = 1"),
+ 'mailing_id' => CRM_Utils_SQL_Select::fragment()->where("mg.mailing_id = #mailingID"),
+ 'temp_contact_null' => CRM_Utils_SQL_Select::fragment()->where('temp.contact_id IS null'),
+ 'order_by' => CRM_Utils_SQL_Select::fragment()->orderBy("$entityTable.is_primary = 1"),
);
- $order_by = array("$entityTable.is_primary = 1");
}
else {
// Criterias to filter recipients that need to be included
- $includeFilters = array(
- "$contact.do_not_email = 0",
- "$contact.is_opt_out = 0",
- "$contact.is_deceased <> 1",
- $location_filter,
- "$entityTable.email IS NOT NULL",
- "$entityTable.email != ''",
- "$entityTable.on_hold = 0",
- "mg.mailing_id = #mailingID",
- 'temp.contact_id IS NULL',
+ $criteria = array(
+ 'do_not_email' => CRM_Utils_SQL_Select::fragment()->where("$contact.do_not_email = 0"),
+ 'is_opt_out' => CRM_Utils_SQL_Select::fragment()->where("$contact.is_opt_out = 0"),
+ 'is_deceased' => CRM_Utils_SQL_Select::fragment()->where("$contact.is_deceased <> 1"),
+ 'location_filter' => CRM_Utils_SQL_Select::fragment()->where($location_filter),
+ 'email_not_null' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.email IS NOT NULL"),
+ 'email_not_empty' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.email != ''"),
+ 'email_not_on_hold' => CRM_Utils_SQL_Select::fragment()->where("$entityTable.on_hold = 0"),
+ 'mailing_id' => CRM_Utils_SQL_Select::fragment()->where("mg.mailing_id = #mailingID"),
+ 'temp_contact_null' => CRM_Utils_SQL_Select::fragment()->where('temp.contact_id IS NULL'),
+ 'order_by' => CRM_Utils_SQL_Select::fragment()->orderBy($order_by),
);
}
+ // Allow user to alter query responsible to fetch mailing recipients before build,
+ // by changing the mail filters identified $params
+ CRM_Utils_Hook::alterMailingRecipients($mailingObj, $criteria, 'pre');
+
// Get the group contacts, but only those which are not in the
// exclusion temp table.
if (!empty($recipientsGroup['Include'])) {
@@ -267,7 +271,7 @@ public static function getRecipients($mailingID) {
->join('mg', " INNER JOIN civicrm_mailing_group mg ON gc.group_id = mg.entity_id AND mg.search_id IS NULL ")
->join('temp', " LEFT JOIN $excludeTempTablename temp ON $contact.id = temp.contact_id ")
->where('gc.group_id IN (#groups) AND gc.status = "Added"')
- ->where($includeFilters)
+ ->merge($criteria)
->groupBy(array("$contact.id", "$entityTable.id"))
->replaceInto($includedTempTablename, array('contact_id', $entityColumn))
->param('#groups', $recipientsGroup['Include'])
@@ -293,8 +297,7 @@ public static function getRecipients($mailingID) {
->join('mg', " INNER JOIN civicrm_mailing_group mg ON gc.group_id = mg.entity_id AND mg.search_id IS NULL ")
->join('temp', " LEFT JOIN $excludeTempTablename temp ON $contact.id = temp.contact_id ")
->where('gc.group_id IN (#groups)')
- ->where($includeFilters)
- ->orderBy($order_by)
+ ->merge($criteria)
->replaceInto($includedTempTablename, array('contact_id', $entityColumn))
->param('#groups', $includeSmartGroupIDs)
->param('#mailingID', $mailingID)
@@ -370,6 +373,8 @@ public static function getRecipients($mailingID) {
$mailingGroup->reset();
$mailingGroup->query(" DROP TEMPORARY TABLE $excludeTempTablename ");
$mailingGroup->query(" DROP TEMPORARY TABLE $includedTempTablename ");
+
+ CRM_Utils_Hook::alterMailingRecipients($mailingObj, $criteria, 'post');
}
/**
@@ -1453,7 +1458,7 @@ public static function add(&$params, $ids = array()) {
}
$mailing->domain_id = CRM_Utils_Array::value('domain_id', $params, CRM_Core_Config::domainID());
- if (!isset($params['replyto_email']) &&
+ if (((!$id && empty($params['replyto_email'])) || !isset($params['replyto_email'])) &&
isset($params['from_email'])
) {
$params['replyto_email'] = $params['from_email'];
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/MailingJob.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/MailingJob.php
index 9b2a80b2079..12379bcc8e6 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/MailingJob.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/MailingJob.php
@@ -598,6 +598,7 @@ public function deliverGroup(&$fields, &$mailing, &$mailer, &$job_date, &$attach
$returnProperties = $mailing->getReturnProperties();
$params = $targetParams = $deliveredParams = array();
$count = 0;
+ $retryGroup = FALSE;
// CRM-15702: Sending bulk sms to contacts without e-mail address fails.
// Solution is to skip checking for on hold
@@ -675,18 +676,17 @@ public function deliverGroup(&$fields, &$mailing, &$mailer, &$job_date, &$attach
if (is_a($result, 'PEAR_Error') && !$mailing->sms_provider_id) {
// CRM-9191
$message = $result->getMessage();
- if (
- strpos($message, 'Failed to write to socket') !== FALSE ||
- strpos($message, 'Failed to set sender') !== FALSE
- ) {
+ if ($this->isTemporaryError($message)) {
// lets log this message and code
$code = $result->getCode();
CRM_Core_Error::debug_log_message("SMTP Socket Error or failed to set sender error. Message: $message, Code: $code");
// these are socket write errors which most likely means smtp connection errors
- // lets skip them
+ // lets skip them and reconnect.
$smtpConnectionErrors++;
if ($smtpConnectionErrors <= 5) {
+ $mailer->disconnect();
+ $retryGroup = TRUE;
continue;
}
@@ -776,9 +776,50 @@ public function deliverGroup(&$fields, &$mailing, &$mailer, &$job_date, &$attach
$job_date
);
+ if ($retryGroup) {
+ return FALSE;
+ }
+
return $result;
}
+ /**
+ * Determine if an SMTP error is temporary or permanent.
+ *
+ * @param string $message
+ * PEAR error message.
+ * @return bool
+ * TRUE - Temporary/retriable error
+ * FALSE - Permanent/non-retriable error
+ */
+ protected function isTemporaryError($message) {
+ // SMTP response code is buried in the message.
+ $code = preg_match('/ \(code: (.+), response: /', $message, $matches) ? $matches[1] : '';
+
+ if (strpos($message, 'Failed to write to socket') !== FALSE) {
+ return TRUE;
+ }
+
+ // Register 5xx SMTP response code (permanent failure) as bounce.
+ if (isset($code{0}) && $code{0} === '5') {
+ return FALSE;
+ }
+
+ if (strpos($message, 'Failed to set sender') !== FALSE) {
+ return TRUE;
+ }
+
+ if (strpos($message, 'Failed to add recipient') !== FALSE) {
+ return TRUE;
+ }
+
+ if (strpos($message, 'Failed to send data') !== FALSE) {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
/**
* Cancel a mailing.
*
@@ -817,11 +858,54 @@ public static function cancel($mailingId) {
2 => array(date('YmdHis'), 'Timestamp'),
);
CRM_Core_DAO::executeQuery($sql, $params);
-
- CRM_Core_Session::setStatus(ts('The mailing has been canceled.'), ts('Canceled'), 'success');
}
}
+ /**
+ * Pause a mailing
+ *
+ * @param int $mailingID
+ * The id of the mailing to be paused.
+ */
+ public static function pause($mailingID) {
+ $sql = "
+ UPDATE civicrm_mailing_job
+ SET status = 'Paused'
+ WHERE mailing_id = %1
+ AND is_test = 0
+ AND status IN ('Scheduled', 'Running')
+ ";
+ CRM_Core_DAO::executeQuery($sql, array(1 => array($mailingID, 'Integer')));
+ }
+
+ /**
+ * Resume a mailing
+ *
+ * @param int $mailingID
+ * The id of the mailing to be resumed.
+ */
+ public static function resume($mailingID) {
+ $sql = "
+ UPDATE civicrm_mailing_job
+ SET status = 'Scheduled'
+ WHERE mailing_id = %1
+ AND is_test = 0
+ AND start_date IS NULL
+ AND status = 'Paused'
+ ";
+ CRM_Core_DAO::executeQuery($sql, array(1 => array($mailingID, 'Integer')));
+
+ $sql = "
+ UPDATE civicrm_mailing_job
+ SET status = 'Running'
+ WHERE mailing_id = %1
+ AND is_test = 0
+ AND start_date IS NOT NULL
+ AND status = 'Paused'
+ ";
+ CRM_Core_DAO::executeQuery($sql, array(1 => array($mailingID, 'Integer')));
+ }
+
/**
* Return a translated status enum string.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Recipients.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Recipients.php
index 4ca5be9cde4..5dfeb1e58af 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Recipients.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/Recipients.php
@@ -102,7 +102,7 @@ public static function updateRandomRecipients($sourceMailingId, $newMailingID, $
CRM_Core_DAO::executeQuery("DROP TEMPORARY TABLE IF EXISTS srcMailing_$sourceMailingId");
$sql = "
CREATE TEMPORARY TABLE srcMailing_$sourceMailingId
- (mailing_recipient_id int, id int PRIMARY KEY AUTO_INCREMENT, INDEX(mailing_recipient_id))
+ (mailing_recipient_id int unsigned, id int PRIMARY KEY AUTO_INCREMENT, INDEX(mailing_recipient_id))
ENGINE=HEAP";
CRM_Core_DAO::executeQuery($sql);
$sql = "
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/TrackableURL.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/TrackableURL.php
index 6d563f3ee24..b1e40d7009a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/TrackableURL.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/BAO/TrackableURL.php
@@ -97,7 +97,7 @@ public static function getTrackerURL($url, $mailing_id, $queue_id) {
$returnUrl = "{$urlCache[$mailing_id . $url]}&qid={$queue_id}";
if ($hrefExists) {
- $returnUrl = "href='{$returnUrl}'";
+ $returnUrl = "href='{$returnUrl}' rel='nofollow'";
}
return $returnUrl;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Component.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Component.php
index d0c861594b6..38aef9f12ae 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Component.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Component.php
@@ -182,6 +182,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Mailing Component is Default?'),
'description' => 'Is this the default component for this component_type?',
+ 'default' => '0',
'table_name' => 'civicrm_mailing_component',
'entity' => 'Component',
'bao' => 'CRM_Mailing_BAO_Component',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Mailing.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Mailing.php
index aafeb0090d3..286256a503b 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Mailing.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/Mailing.php
@@ -674,6 +674,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Override Verp'),
'description' => 'Should we overrite VERP address in Reply-To',
+ 'default' => '0',
'table_name' => 'civicrm_mailing',
'entity' => 'Mailing',
'bao' => 'CRM_Mailing_BAO_Mailing',
@@ -814,6 +815,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Mailing Archived?'),
'description' => 'Is this mailing archived?',
+ 'default' => '0',
'table_name' => 'civicrm_mailing',
'entity' => 'Mailing',
'bao' => 'CRM_Mailing_BAO_Mailing',
@@ -865,6 +867,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('No Duplicate emails?'),
'description' => 'Remove duplicate emails?',
+ 'default' => '0',
'table_name' => 'civicrm_mailing',
'entity' => 'Mailing',
'bao' => 'CRM_Mailing_BAO_Mailing',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/MailingJob.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/MailingJob.php
index 93cd6819486..931685895fd 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/MailingJob.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/DAO/MailingJob.php
@@ -216,6 +216,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Mailing Job Is Test?'),
'description' => 'Is this job for a test mail?',
+ 'default' => '0',
'table_name' => 'civicrm_mailing_job',
'entity' => 'MailingJob',
'bao' => 'CRM_Mailing_BAO_MailingJob',
@@ -250,6 +251,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Mailing Job Offset'),
'description' => 'Offset of the child job',
+ 'default' => '0',
'table_name' => 'civicrm_mailing_job',
'entity' => 'MailingJob',
'bao' => 'CRM_Mailing_BAO_MailingJob',
@@ -260,6 +262,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Mailing Job Limit'),
'description' => 'Queue size limit for each child job',
+ 'default' => '0',
'table_name' => 'civicrm_mailing_job',
'entity' => 'MailingJob',
'bao' => 'CRM_Mailing_BAO_MailingJob',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/Event/BAO/Confirm.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/Event/BAO/Confirm.php
index f01e188d8ab..1d3c2d4d18d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/Event/BAO/Confirm.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Mailing/Event/BAO/Confirm.php
@@ -118,8 +118,6 @@ public static function confirm($contact_id, $subscribe_id, $hash) {
$component->find(TRUE);
- $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
-
$html = $component->body_html;
if ($component->body_text) {
@@ -143,11 +141,11 @@ public static function confirm($contact_id, $subscribe_id, $hash) {
$mailParams = array(
'groupName' => 'Mailing Event ' . $component->component_type,
'subject' => $component->subject,
- 'from' => "\"$domainEmailName\"
')
);
- $form->addElement('text', 'pledge_installments', ts('Installments'), array('size' => 3));
+ $form->addElement('text', 'pledge_installments', ts('Installments'), ['size' => 3, 'aria-label' => ts('Installments')]);
if (!empty($pledgeBlock['is_pledge_interval'])) {
$form->assign('is_pledge_interval', CRM_Utils_Array::value('is_pledge_interval', $pledgeBlock));
- $form->addElement('text', 'pledge_frequency_interval', NULL, array('size' => 3));
+ $form->addElement('text', 'pledge_frequency_interval', NULL, ['size' => 3, 'aria-label' => ts('Frequency Intervals')]);
}
else {
$form->add('hidden', 'pledge_frequency_interval', 1);
@@ -299,7 +299,7 @@ public static function buildPledgeBlock($form) {
$freqUnits[$val] = !empty($pledgeBlock['is_pledge_interval']) ? "{$frequencyUnits[$val]}(s)" : $frequencyUnits[$val];
}
}
- $form->addElement('select', 'pledge_frequency_unit', NULL, $freqUnits);
+ $form->addElement('select', 'pledge_frequency_unit', NULL, $freqUnits, ['aria-label' => ts('Frequency Units')]);
// CRM-18854
if (CRM_Utils_Array::value('is_pledge_start_date_visible', $pledgeBlock)) {
if (CRM_Utils_Array::value('pledge_start_date', $pledgeBlock)) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/Pledge.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/Pledge.php
index 21d857a3d9f..bfe1c096128 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/Pledge.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/Pledge.php
@@ -575,6 +575,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_pledge',
'entity' => 'Pledge',
'bao' => 'CRM_Pledge_BAO_Pledge',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgeBlock.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgeBlock.php
index 19ee593688d..1efdbf69aca 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgeBlock.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgeBlock.php
@@ -188,6 +188,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Expose Frequency Interval?'),
'description' => 'Is frequency interval exposed on the contribution form.',
+ 'default' => '0',
'table_name' => 'civicrm_pledge_block',
'entity' => 'PledgeBlock',
'bao' => 'CRM_Pledge_BAO_PledgeBlock',
@@ -244,6 +245,7 @@ public static function &fields() {
'title' => ts('Show Recurring Donation Start Date?'),
'description' => 'If true - recurring start date is shown.',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_pledge_block',
'entity' => 'PledgeBlock',
'bao' => 'CRM_Pledge_BAO_PledgeBlock',
@@ -255,6 +257,7 @@ public static function &fields() {
'title' => ts('Allow Edits to Recurring Donation Start Date?'),
'description' => 'If true - recurring start date is editable.',
'required' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_pledge_block',
'entity' => 'PledgeBlock',
'bao' => 'CRM_Pledge_BAO_PledgeBlock',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgePayment.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgePayment.php
index d3f05e4656b..3a996ff0ed4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgePayment.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/DAO/PledgePayment.php
@@ -266,6 +266,7 @@ public static function &fields() {
'headerPattern' => '',
'dataPattern' => '',
'export' => TRUE,
+ 'default' => '0',
'table_name' => 'civicrm_pledge_payment',
'entity' => 'PledgePayment',
'bao' => 'CRM_Pledge_BAO_PledgePayment',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/Form/Task.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/Form/Task.php
index 092fece3a3e..4a8b8556144 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/Form/Task.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Pledge/Form/Task.php
@@ -32,30 +32,10 @@
*/
/**
- * This class generates task actions for CiviEvent.
+ * Class for pledge form task actions.
+ * FIXME: This needs refactoring to properly inherit from CRM_Core_Form_Task and share more functions.
*/
-class CRM_Pledge_Form_Task extends CRM_Core_Form {
-
- /**
- * The task being performed.
- *
- * @var int
- */
- protected $_task;
-
- /**
- * The additional clause that we restrict the search with.
- *
- * @var string
- */
- protected $_componentClause = NULL;
-
- /**
- * The array that holds all the component ids.
- *
- * @var array
- */
- protected $_componentIds;
+class CRM_Pledge_Form_Task extends CRM_Core_Form_Task {
/**
* The array that holds all the pledge ids.
@@ -75,9 +55,8 @@ public function preProcess() {
* Common pre-processing.
*
* @param CRM_Core_Form $form
- * @param bool $useTable
*/
- public static function preProcessCommon(&$form, $useTable = FALSE) {
+ public static function preProcessCommon(&$form) {
$form->_pledgeIds = array();
$values = $form->controller->exportValues('Search');
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/BAO/PriceField.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/BAO/PriceField.php
index d7dc9614344..0dd12fd66c5 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/BAO/PriceField.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/BAO/PriceField.php
@@ -413,10 +413,10 @@ public static function addQuickFormElement(
if ($field->is_display_amounts) {
$opt['label'] = !empty($opt['label']) ? $opt['label'] . ' - ' : '';
$preHelpText = $postHelpText = '';
- if (isset($opt['help_pre'])) {
+ if (!empty($opt['help_pre'])) {
$preHelpText = '' . $opt['help_pre'] . ': ';
}
- if (isset($opt['help_post'])) {
+ if (!empty($opt['help_post'])) {
$postHelpText = ': ' . $opt['help_post'] . '';
}
if (isset($taxAmount) && $invoicing) {
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceField.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceField.php
index 9cfe9768066..aeaf386e72e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceField.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceField.php
@@ -254,6 +254,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Price Field Quantity Required?'),
'description' => 'Enter a quantity for this field?',
+ 'default' => '0',
'table_name' => 'civicrm_price_field',
'entity' => 'PriceField',
'bao' => 'CRM_Price_BAO_PriceField',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceFieldValue.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceFieldValue.php
index e656e0ed28e..f07a16e344e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceFieldValue.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceFieldValue.php
@@ -382,6 +382,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Default Price Field Option?'),
'description' => 'Is this default price field option',
+ 'default' => '0',
'table_name' => 'civicrm_price_field_value',
'entity' => 'PriceFieldValue',
'bao' => 'CRM_Price_BAO_PriceFieldValue',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceSet.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceSet.php
index 3abf87d17f2..cd26b23f777 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceSet.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Price/DAO/PriceSet.php
@@ -318,6 +318,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Is Price Set Quick Config?'),
'description' => 'Is set if edited on Contribution or Event Page rather than through Manage Price Sets',
+ 'default' => '0',
'table_name' => 'civicrm_price_set',
'entity' => 'PriceSet',
'bao' => 'CRM_Price_BAO_PriceSet',
@@ -331,6 +332,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Price Set Is Reserved'),
'description' => 'Is this a predefined system price set (i.e. it can not be deleted, edited)?',
+ 'default' => '0',
'table_name' => 'civicrm_price_set',
'entity' => 'PriceSet',
'bao' => 'CRM_Price_BAO_PriceSet',
@@ -344,6 +346,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Minimum Amount'),
'description' => 'Minimum Amount required for this set.',
+ 'default' => '0',
'table_name' => 'civicrm_price_set',
'entity' => 'PriceSet',
'bao' => 'CRM_Price_BAO_PriceSet',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Form/Edit.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Form/Edit.php
index 601283c1e6f..ada0354e0ad 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Form/Edit.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Form/Edit.php
@@ -222,6 +222,7 @@ public function buildQuickForm() {
$cancelButtonValue = !empty($this->_ufGroup['cancel_button_text']) ? $this->_ufGroup['cancel_button_text'] : ts('Cancel');
$this->assign('cancelButtonText', $cancelButtonValue);
+ $this->assign('includeCancelButton', CRM_Utils_Array::value('add_cancel_button', $this->_ufGroup));
if (($this->_multiRecord & CRM_Core_Action::DELETE) && $this->_recordExists) {
$this->_deleteButtonName = $this->getButtonName('upload', 'delete');
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Page/MultipleRecordFieldsListing.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Page/MultipleRecordFieldsListing.php
index 9bff1a8a159..e8ab497e072 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Page/MultipleRecordFieldsListing.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Profile/Page/MultipleRecordFieldsListing.php
@@ -341,7 +341,7 @@ public function browse() {
// TODO: Not all widget types and validation rules are supported by crmEditable so some fields will not be in-place editable
$fieldAttributes = array('class' => "crmf-custom_{$fieldId}_$recId");
$editable = FALSE;
- if (!$options[$fieldId]['attributes']['is_view'] && $linkAction & CRM_Core_Action::UPDATE) {
+ if (!$options[$fieldId]['attributes']['is_view'] && $this->_pageViewType == 'customDataView' && $linkAction & CRM_Core_Action::UPDATE) {
$spec = $options[$fieldId]['attributes'];
switch ($spec['html_type']) {
case 'Text':
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/BAO/ReportInstance.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/BAO/ReportInstance.php
index 0b254ee73cb..a7dc5733cb4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/BAO/ReportInstance.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/BAO/ReportInstance.php
@@ -364,24 +364,35 @@ public static function doFormDelete($instanceId, $bounceTo = 'civicrm/report/lis
* - general script-add.
*/
public static function getActionMetadata() {
- $actions = array(
- 'report_instance.save' => array('title' => ts('Save')),
- 'report_instance.copy' => array(
+ $actions = array();
+ if (CRM_Core_Permission::check('save Report Criteria')) {
+ $actions['report_instance.save'] = array('title' => ts('Save'));
+ $actions['report_instance.copy'] = array(
'title' => ts('Save a Copy'),
'data' => array(
'is_confirm' => TRUE,
'confirm_title' => ts('Save a copy...'),
'confirm_refresh_fields' => json_encode(array(
- 'title' => array('selector' => '.crm-report-instanceForm-form-block-title', 'prepend' => ts('(Copy) ')),
- 'description' => array('selector' => '.crm-report-instanceForm-form-block-description', 'prepend' => ''),
- 'parent_id' => array('selector' => '.crm-report-instanceForm-form-block-parent_id', 'prepend' => ''),
+ 'title' => array(
+ 'selector' => '.crm-report-instanceForm-form-block-title',
+ 'prepend' => ts('(Copy) '),
+ ),
+ 'description' => array(
+ 'selector' => '.crm-report-instanceForm-form-block-description',
+ 'prepend' => '',
+ ),
+ 'parent_id' => array(
+ 'selector' => '.crm-report-instanceForm-form-block-parent_id',
+ 'prepend' => '',
+ ),
)),
),
- ),
- 'report_instance.print' => array('title' => ts('Print Report')),
- 'report_instance.pdf' => array('title' => ts('Print to PDF')),
- 'report_instance.csv' => array('title' => ts('Export as CSV')),
- );
+ );
+ }
+ $actions['report_instance.print'] = array('title' => ts('Print Report'));
+ $actions['report_instance.pdf'] = array('title' => ts('Print to PDF'));
+ $actions['report_instance.csv'] = array('title' => ts('Export as CSV'));
+
if (CRM_Core_Permission::check('administer Reports')) {
$actions['report_instance.delete'] = array(
'title' => ts('Delete report'),
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/DAO/ReportInstance.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/DAO/ReportInstance.php
index 4effadcc03d..141e6f6312c 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/DAO/ReportInstance.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/DAO/ReportInstance.php
@@ -500,6 +500,7 @@ public static function &fields() {
'name' => 'is_reserved',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Instance is Reserved'),
+ 'default' => '0',
'table_name' => 'civicrm_report_instance',
'entity' => 'ReportInstance',
'bao' => 'CRM_Report_BAO_ReportInstance',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form.php
index 97f2e78d0f3..722c35f3236 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form.php
@@ -488,6 +488,14 @@ class CRM_Report_Form extends CRM_Core_Form {
protected $sqlArray;
+ /**
+ * Tables created for the report that need removal afterwards.
+ *
+ * ['civicrm_temp_report_x' => ['temporary' => TRUE, 'name' => 'civicrm_temp_report_x']
+ * @var array
+ */
+ protected $temporaryTables = [];
+
/**
* Can this report use the sql mode ONLY_FULL_GROUP_BY.
* @var bool
@@ -1060,6 +1068,15 @@ public function setParams($params) {
$this->_params = $params;
}
+ /**
+ * Getter for $_params.
+ *
+ * @return void|array $params
+ */
+ public function getParams() {
+ return $this->_params;
+ }
+
/**
* Setter for $_id.
*
@@ -1114,6 +1131,36 @@ public function getDefaultValues() {
return $this->_defaults;
}
+ /**
+ * Remove any temporary tables.
+ */
+ public function cleanUpTemporaryTables() {
+ foreach ($this->temporaryTables as $temporaryTable) {
+ CRM_Core_DAO::executeQuery('DROP ' . ($temporaryTable['temporary'] ? 'TEMPORARY' : '') . ' TABLE IF EXISTS ' . $temporaryTable['name']);
+ }
+ }
+
+ /**
+ * Create a temporary table.
+ *
+ * This function creates a table AND adds the details to the developer tab & $this->>temporary tables.
+ *
+ * @todo improve presentation on the developer tab since CREATE TEMPORARY is removed.
+ *
+ * @param string $identifier
+ * @param $sql
+ * @param bool $isTrueTemporary
+ * Is this a mysql temporary table or temporary in a less technical sense.
+ *
+ * @return string
+ */
+ public function createTemporaryTable($identifier, $sql, $isTrueTemporary = TRUE) {
+ $this->addToDeveloperTab($sql);
+ $name = CRM_Utils_SQL_TempTable::build()->setUtf8(TRUE)->setDurable($isTrueTemporary)->createWithQuery($sql)->getName();
+ $this->temporaryTables[$identifier] = ['temporary' => $isTrueTemporary, 'name' => $name];
+ return $name;
+ }
+
/**
* Add columns to report.
*/
@@ -3672,7 +3719,7 @@ public function buildGroupTempTable() {
WHERE smartgroup_contact.group_id IN ({$smartGroups}) ";
}
- $this->groupTempTable = 'civicrm_report_temp_group_' . date('Ymd_') . uniqid();
+ $this->groupTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('rptgrp')->setId(date('Ymd_') . uniqid())->getName();
$this->executeReportQuery("
CREATE TEMPORARY TABLE $this->groupTempTable $this->_databaseAttributes
$query
@@ -4383,70 +4430,51 @@ public function addAddressFields($groupBy = TRUE, $orderBy = FALSE, $filters = T
/**
* Do AlterDisplay processing on Address Fields.
+ * If there are multiple address field values then
+ * on basis of provided separator the code values are translated into respective labels
*
* @param array $row
* @param array $rows
* @param int $rowNum
* @param string $baseUrl
* @param string $linkText
+ * @param string $separator
*
* @return bool
*/
- public function alterDisplayAddressFields(&$row, &$rows, &$rowNum, $baseUrl, $linkText) {
+ public function alterDisplayAddressFields(&$row, &$rows, &$rowNum, $baseUrl, $linkText, $separator = ',') {
$criteriaQueryParams = CRM_Report_Utils_Report::getPreviewCriteriaQueryParams($this->_defaults, $this->_params);
$entryFound = FALSE;
- // handle country
- if (array_key_exists('civicrm_address_country_id', $row)) {
- if ($value = $row['civicrm_address_country_id']) {
- $rows[$rowNum]['civicrm_address_country_id'] = CRM_Core_PseudoConstant::country($value, FALSE);
- if ($baseUrl) {
- $url = CRM_Report_Utils_Report::getNextUrl($baseUrl,
- "reset=1&force=1&{$criteriaQueryParams}&" .
- "country_id_op=in&country_id_value={$value}",
- $this->_absoluteUrl, $this->_id
- );
- $rows[$rowNum]['civicrm_address_country_id_link'] = $url;
- $rows[$rowNum]['civicrm_address_country_id_hover'] = ts("%1 for this country.",
- array(1 => $linkText)
- );
- }
- }
-
- $entryFound = TRUE;
- }
- if (array_key_exists('civicrm_address_county_id', $row)) {
- if ($value = $row['civicrm_address_county_id']) {
- $rows[$rowNum]['civicrm_address_county_id'] = CRM_Core_PseudoConstant::county($value, FALSE);
- if ($baseUrl) {
- $url = CRM_Report_Utils_Report::getNextUrl($baseUrl,
- "reset=1&force=1&{$criteriaQueryParams}&" .
- "county_id_op=in&county_id_value={$value}",
- $this->_absoluteUrl, $this->_id
- );
- $rows[$rowNum]['civicrm_address_county_id_link'] = $url;
- $rows[$rowNum]['civicrm_address_county_id_hover'] = ts("%1 for this county.",
- array(1 => $linkText)
- );
- }
- }
- $entryFound = TRUE;
- }
- // handle state province
- if (array_key_exists('civicrm_address_state_province_id', $row)) {
- if ($value = $row['civicrm_address_state_province_id']) {
- $rows[$rowNum]['civicrm_address_state_province_id'] = CRM_Core_PseudoConstant::stateProvince($value, FALSE);
- if ($baseUrl) {
- $url = CRM_Report_Utils_Report::getNextUrl($baseUrl,
- "reset=1&force=1&{$criteriaQueryParams}&state_province_id_op=in&state_province_id_value={$value}",
- $this->_absoluteUrl, $this->_id
- );
- $rows[$rowNum]['civicrm_address_state_province_id_link'] = $url;
- $rows[$rowNum]['civicrm_address_state_province_id_hover'] = ts("%1 for this state.",
- array(1 => $linkText)
- );
+ $columnMap = array(
+ 'civicrm_address_country_id' => 'country',
+ 'civicrm_address_county_id' => 'county',
+ 'civicrm_address_state_province_id' => 'stateProvince',
+ );
+ foreach ($columnMap as $fieldName => $fnName) {
+ if (array_key_exists($fieldName, $row)) {
+ if ($values = $row[$fieldName]) {
+ $values = (array) explode($separator, $values);
+ $rows[$rowNum][$fieldName] = [];
+ $addressField = $fnName == 'stateProvince' ? 'state' : $fnName;
+ foreach ($values as $value) {
+ $rows[$rowNum][$fieldName][] = CRM_Core_PseudoConstant::$fnName($value);
+ }
+ $rows[$rowNum][$fieldName] = implode($separator, $rows[$rowNum][$fieldName]);
+ if ($baseUrl) {
+ $url = CRM_Report_Utils_Report::getNextUrl($baseUrl,
+ sprintf("reset=1&force=1&%s&%s_op=in&%s_value=%s",
+ $criteriaQueryParams,
+ str_replace('civicrm_address_', '', $fieldName),
+ str_replace('civicrm_address_', '', $fieldName),
+ implode(',', $values)
+ ), $this->_absoluteUrl, $this->_id
+ );
+ $rows[$rowNum]["{$fieldName}_link"] = $url;
+ $rows[$rowNum]["{$fieldName}_hover"] = ts("%1 for this %2.", array(1 => $linkText, 2 => $addressField));
+ }
+ $entryFound = TRUE;
}
}
- $entryFound = TRUE;
}
return $entryFound;
@@ -5357,12 +5385,27 @@ protected function getContactColumns($options = array()) {
'title' => $options['prefix_label'] . ts('Nick Name'),
'is_fields' => TRUE,
),
+ $options['prefix'] . 'prefix_id' => array(
+ 'name' => 'prefix_id',
+ 'title' => $options['prefix_label'] . ts('Prefix'),
+ 'options' => CRM_Contact_BAO_Contact::buildOptions('prefix_id'),
+ 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
+ 'is_fields' => TRUE,
+ 'is_filters' => TRUE,
+ ),
+ $options['prefix'] . 'suffix_id' => array(
+ 'name' => 'suffix_id',
+ 'title' => $options['prefix_label'] . ts('Suffix'),
+ 'options' => CRM_Contact_BAO_Contact::buildOptions('suffix_id'),
+ 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
+ 'is_fields' => TRUE,
+ 'is_filters' => TRUE,
+ ),
$options['prefix'] . 'gender_id' => array(
'name' => 'gender_id',
'title' => $options['prefix_label'] . ts('Gender'),
'options' => CRM_Contact_BAO_Contact::buildOptions('gender_id'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
- 'alter_display' => 'alterGenderID',
'is_fields' => TRUE,
'is_filters' => TRUE,
),
@@ -5375,7 +5418,7 @@ protected function getContactColumns($options = array()) {
),
'age' => array(
'title' => $options['prefix_label'] . ts('Age'),
- 'dbAlias' => 'TIMESTAMPDIFF(YEAR, ' . $tableAlias . '.birth_date, CURDATE())',
+ 'dbAlias' => 'TIMESTAMPDIFF(YEAR, ' . $tableAlias . '_civireport.birth_date, CURDATE())',
'type' => CRM_Utils_Type::T_INT,
'is_fields' => TRUE,
),
@@ -5448,6 +5491,16 @@ protected function getAddressColumns($options = array()) {
'type' => 1,
'is_fields' => TRUE,
),
+ $options['prefix'] . 'odd_street_number' => array(
+ 'title' => ts('Odd / Even Street Number'),
+ 'name' => 'odd_street_number',
+ 'type' => CRM_Utils_Type::T_INT,
+ 'no_display' => TRUE,
+ 'required' => TRUE,
+ 'dbAlias' => '(address_civireport.street_number % 2)',
+ 'is_fields' => TRUE,
+ 'is_order_bys' => TRUE,
+ ),
$options['prefix'] . 'street_name' => array(
'name' => 'street_name',
'title' => ts($options['prefix_label'] . 'Street Name'),
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Activity.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Activity.php
index b38b95d24d3..9b55f415fa9 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Activity.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Activity.php
@@ -91,6 +91,9 @@ public function __construct() {
$condition = " AND ( v.component_id IS NULL {$include} )";
$this->activityTypes = CRM_Core_OptionGroup::values('activity_type', FALSE, FALSE, FALSE, $condition);
asort($this->activityTypes);
+
+ // @todo split the 3 different contact tables into their own array items.
+ // this will massively simplify the needs of this report.
$this->_columns = array(
'civicrm_contact' => array(
'dao' => 'CRM_Contact_DAO_Contact',
@@ -394,7 +397,12 @@ public function addressFields($orderBy = FALSE) {
/**
* Build select clause.
*
- * @param null $recordType
+ * @todo get rid of $recordType param. It's only because 3 separate contact tables
+ * are mis-declared as one that we need it.
+ *
+ * @param null $recordType deprecated
+ * Parameter to hack around the bad decision made in construct to misrepresent
+ * different tables as the same table.
*/
public function select($recordType = 'target') {
if (!array_key_exists("contact_{$recordType}", $this->_params['fields']) &&
@@ -416,6 +424,7 @@ public function select($recordType = 'target') {
$removeKeys = array();
if ($recordType == 'target') {
+ // @todo - fix up the way the tables are declared in construct & remove this.
foreach ($this->_selectClauses as $key => $clause) {
if (strstr($clause, 'civicrm_contact_assignee.') ||
strstr($clause, 'civicrm_contact_source.') ||
@@ -430,13 +439,15 @@ public function select($recordType = 'target') {
}
}
elseif ($recordType == 'assignee') {
+ // @todo - fix up the way the tables are declared in construct & remove this.
foreach ($this->_selectClauses as $key => $clause) {
if (strstr($clause, 'civicrm_contact_target.') ||
strstr($clause, 'civicrm_contact_source.') ||
strstr($clause, 'civicrm_email_target.') ||
strstr($clause, 'civicrm_email_source.') ||
strstr($clause, 'civicrm_phone_target.') ||
- strstr($clause, 'civicrm_phone_source.')
+ strstr($clause, 'civicrm_phone_source.') ||
+ strstr($clause, 'civicrm_address_')
) {
$removeKeys[] = $key;
unset($this->_selectClauses[$key]);
@@ -444,13 +455,15 @@ public function select($recordType = 'target') {
}
}
elseif ($recordType == 'source') {
+ // @todo - fix up the way the tables are declared in construct & remove this.
foreach ($this->_selectClauses as $key => $clause) {
if (strstr($clause, 'civicrm_contact_target.') ||
strstr($clause, 'civicrm_contact_assignee.') ||
strstr($clause, 'civicrm_email_target.') ||
strstr($clause, 'civicrm_email_assignee.') ||
strstr($clause, 'civicrm_phone_target.') ||
- strstr($clause, 'civicrm_phone_assignee.')
+ strstr($clause, 'civicrm_phone_assignee.') ||
+ strstr($clause, 'civicrm_address_')
) {
$removeKeys[] = $key;
unset($this->_selectClauses[$key]);
@@ -460,6 +473,7 @@ public function select($recordType = 'target') {
elseif ($recordType == 'final') {
$this->_selectClauses = $this->_selectAliasesTotal;
foreach ($this->_selectClauses as $key => $clause) {
+ // @todo - fix up the way the tables are declared in construct & remove this.
if (strstr($clause, 'civicrm_contact_contact_target') ||
strstr($clause, 'civicrm_contact_contact_assignee') ||
strstr($clause, 'civicrm_contact_contact_source') ||
@@ -468,9 +482,10 @@ public function select($recordType = 'target') {
strstr($clause, 'civicrm_email_contact_source_email') ||
strstr($clause, 'civicrm_email_contact_assignee_email') ||
strstr($clause, 'civicrm_email_contact_target_email') ||
- strstr($clause, 'civicrm_phone_contact_target_phone')
+ strstr($clause, 'civicrm_phone_contact_target_phone') ||
+ strstr($clause, 'civicrm_address_')
) {
- $this->_selectClauses[$key] = "GROUP_CONCAT($clause SEPARATOR ';') as $clause";
+ $this->_selectClauses[$key] = "GROUP_CONCAT(DISTINCT $clause SEPARATOR ';') as $clause";
}
}
}
@@ -480,7 +495,7 @@ public function select($recordType = 'target') {
unset($this->_selectAliases[$key]);
}
- if ($recordType != 'final') {
+ if ($recordType == 'target') {
foreach ($this->_columns['civicrm_address']['order_bys'] as $fieldName => $field) {
$orderByFld = $this->_columns['civicrm_address']['order_bys'][$fieldName];
$fldInfo = $this->_columns['civicrm_address']['fields'][$fieldName];
@@ -496,91 +511,35 @@ public function select($recordType = 'target') {
/**
* Build from clause.
- *
- * @param string $recordType
+ * @todo remove this function & declare the 3 contact tables separately
*/
- public function from($recordType = 'target') {
+ public function from() {
$activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
- $activityTypeId = CRM_Core_DAO::getFieldValue("CRM_Core_DAO_OptionGroup", 'activity_type', 'id', 'name');
- $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
- $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
-
- if ($recordType == 'target') {
- $this->_from = "
- FROM civicrm_activity {$this->_aliases['civicrm_activity']}
- INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']}
- ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_contact']}.activity_id AND
- {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$targetID}
- INNER JOIN civicrm_contact civicrm_contact_target
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_contact_target.id
- {$this->_aclFrom}";
-
- if ($this->isTableSelected('civicrm_email')) {
- $this->_from .= "
- LEFT JOIN civicrm_email civicrm_email_target
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_email_target.contact_id AND
- civicrm_email_target.is_primary = 1";
- }
-
- if ($this->isTableSelected('civicrm_phone')) {
- $this->_from .= "
- LEFT JOIN civicrm_phone civicrm_phone_target
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_phone_target.contact_id AND
- civicrm_phone_target.is_primary = 1 ";
- }
- $this->_aliases['civicrm_contact'] = 'civicrm_contact_target';
- }
-
- if ($recordType == 'assignee') {
- $this->_from = "
- FROM civicrm_activity {$this->_aliases['civicrm_activity']}
- INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']}
- ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_contact']}.activity_id AND
- {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$assigneeID}
- INNER JOIN civicrm_contact civicrm_contact_assignee
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_contact_assignee.id
- {$this->_aclFrom}";
- if ($this->isTableSelected('civicrm_email')) {
- $this->_from .= "
- LEFT JOIN civicrm_email civicrm_email_assignee
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_email_assignee.contact_id AND
- civicrm_email_assignee.is_primary = 1";
- }
- if ($this->isTableSelected('civicrm_phone')) {
- $this->_from .= "
- LEFT JOIN civicrm_phone civicrm_phone_assignee
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_phone_assignee.contact_id AND
- civicrm_phone_assignee.is_primary = 1 ";
- }
- $this->_aliases['civicrm_contact'] = 'civicrm_contact_assignee';
+ $this->_from = "
+ FROM civicrm_activity {$this->_aliases['civicrm_activity']}
+ INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']}
+ ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_contact']}.activity_id AND
+ {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$targetID}
+ INNER JOIN civicrm_contact civicrm_contact_target
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_contact_target.id
+ {$this->_aclFrom}";
+
+ if ($this->isTableSelected('civicrm_email')) {
+ $this->_from .= "
+ LEFT JOIN civicrm_email civicrm_email_target
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_email_target.contact_id AND
+ civicrm_email_target.is_primary = 1";
}
- if ($recordType == 'source') {
- $this->_from = "
- FROM civicrm_activity {$this->_aliases['civicrm_activity']}
- INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']}
- ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_contact']}.activity_id AND
- {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$sourceID}
- INNER JOIN civicrm_contact civicrm_contact_source
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_contact_source.id
- {$this->_aclFrom}";
-
- if ($this->isTableSelected('civicrm_email')) {
- $this->_from .= "
- LEFT JOIN civicrm_email civicrm_email_source
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_email_source.contact_id AND
- civicrm_email_source.is_primary = 1";
- }
- if ($this->isTableSelected('civicrm_phone')) {
- $this->_from .= "
- LEFT JOIN civicrm_phone civicrm_phone_source
- ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_phone_source.contact_id AND
- civicrm_phone_source.is_primary = 1 ";
- }
- $this->_aliases['civicrm_contact'] = 'civicrm_contact_source';
+ if ($this->isTableSelected('civicrm_phone')) {
+ $this->_from .= "
+ LEFT JOIN civicrm_phone civicrm_phone_target
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_phone_target.contact_id AND
+ civicrm_phone_target.is_primary = 1 ";
}
+ $this->_aliases['civicrm_contact'] = 'civicrm_contact_target';
$this->joinAddressFromContact();
}
@@ -588,6 +547,9 @@ public function from($recordType = 'target') {
/**
* Build where clause.
*
+ * @todo get rid of $recordType param. It's only because 3 separate contact tables
+ * are mis-declared as one that we need it.
+ *
* @param string $recordType
*/
public function where($recordType = NULL) {
@@ -731,7 +693,7 @@ public function add2group($groupID) {
$new_having = ' addtogroup_contact_id';
$having = str_ireplace(' civicrm_contact_contact_target_id', $new_having, $this->_having);
$query = "$select
-FROM civireport_activity_temp_target tar
+FROM {$this->temporaryTables['activity_temp_table']} tar
GROUP BY civicrm_activity_id $having {$this->_orderBy}";
$select = 'AS addtogroup_contact_id';
$query = str_ireplace('AS civicrm_contact_contact_target_id', $select, $query);
@@ -805,21 +767,21 @@ public function buildQuery($applyLimit = TRUE) {
}
}
+ // @todo - all this temp table stuff is here because pre 4.4 the activity contact
+ // form did not exist.
+ // Fixing the way the construct method declares them will make all this redundant.
// 1. fill temp table with target results
$this->buildACLClause(array('civicrm_contact_target'));
$this->select('target');
- $this->from('target');
+ $this->from();
$this->customDataFrom();
$this->where('target');
- $insertCols = implode(',', $this->_selectAliases);
- $tempQuery = "CREATE TEMPORARY TABLE civireport_activity_temp_target {$this->_databaseAttributes} AS
-{$this->_select} {$this->_from} {$this->_where} ";
- $this->executeReportQuery($tempQuery);
+ $tempTableName = $this->createTemporaryTable('activity_temp_table', "{$this->_select} {$this->_from} {$this->_where}");
// 2. add new columns to hold assignee and source results
// fixme: add when required
$tempQuery = "
- ALTER TABLE civireport_activity_temp_target
+ ALTER TABLE $tempTableName
MODIFY COLUMN civicrm_contact_contact_target_id VARCHAR(128),
ADD COLUMN civicrm_contact_contact_assignee VARCHAR(128),
ADD COLUMN civicrm_contact_contact_source VARCHAR(128),
@@ -834,11 +796,12 @@ public function buildQuery($applyLimit = TRUE) {
// 3. fill temp table with assignee results
$this->buildACLClause(array('civicrm_contact_assignee'));
$this->select('assignee');
- $this->from('assignee');
+ $this->buildAssigneeFrom();
+
$this->customDataFrom();
$this->where('assignee');
$insertCols = implode(',', $this->_selectAliases);
- $tempQuery = "INSERT INTO civireport_activity_temp_target ({$insertCols})
+ $tempQuery = "INSERT INTO $tempTableName ({$insertCols})
{$this->_select}
{$this->_from} {$this->_where}";
$this->executeReportQuery($tempQuery);
@@ -846,11 +809,11 @@ public function buildQuery($applyLimit = TRUE) {
// 4. fill temp table with source results
$this->buildACLClause(array('civicrm_contact_source'));
$this->select('source');
- $this->from('source');
+ $this->buildSourceFrom();
$this->customDataFrom();
$this->where('source');
$insertCols = implode(',', $this->_selectAliases);
- $tempQuery = "INSERT INTO civireport_activity_temp_target ({$insertCols})
+ $tempQuery = "INSERT INTO $tempTableName ({$insertCols})
{$this->_select}
{$this->_from} {$this->_where}";
$this->executeReportQuery($tempQuery);
@@ -865,7 +828,7 @@ public function buildQuery($applyLimit = TRUE) {
$this->orderBy();
foreach ($this->_sections as $alias => $section) {
if (!empty($section) && $section['name'] == 'activity_date_time') {
- $this->alterSectionHeaderForDateTime('civireport_activity_temp_target', $section['tplField']);
+ $this->alterSectionHeaderForDateTime($tempTableName, $section['tplField']);
}
}
@@ -882,7 +845,7 @@ public function buildQuery($applyLimit = TRUE) {
}
$sql = "{$this->_select}
- FROM civireport_activity_temp_target tar
+ FROM $tempTableName tar
INNER JOIN civicrm_activity {$this->_aliases['civicrm_activity']} ON {$this->_aliases['civicrm_activity']}.id = tar.civicrm_activity_id
INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']} ON {$this->_aliases['civicrm_activity_contact']}.activity_id = {$this->_aliases['civicrm_activity']}.id
AND {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$sourceID}
@@ -930,7 +893,10 @@ public function alterDisplay(&$rows) {
$activityStatus = CRM_Core_PseudoConstant::activityStatus();
$priority = CRM_Core_PseudoConstant::get('CRM_Activity_DAO_Activity', 'priority_id');
$viewLinks = FALSE;
- $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this, FALSE, 'report');
+
+ // Would we ever want to retrieve from the form controller??
+ $form = $this->noController ? NULL : $this;
+ $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $form, FALSE, 'report');
$actUrl = '';
if (CRM_Core_Permission::check('access CiviCRM')) {
@@ -1088,7 +1054,7 @@ public function alterDisplay(&$rows) {
}
}
- $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, 'activity', 'List all activities for this ') ? TRUE : $entryFound;
+ $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, 'activity', 'List all activities for this', ';') ? TRUE : $entryFound;
if (!$entryFound) {
break;
@@ -1114,7 +1080,7 @@ public function sectionTotals() {
$this->_select = CRM_Contact_BAO_Query::appendAnyValueToSelect($ifnulls, $sectionAliases);
$query = $this->_select .
- ", count(DISTINCT civicrm_activity_id) as ct from civireport_activity_temp_target group by " .
+ ", count(DISTINCT civicrm_activity_id) as ct from {$this->temporaryTables['activity_temp_table']} group by " .
implode(", ", $sectionAliases);
// initialize array of total counts
@@ -1147,4 +1113,72 @@ public function sectionTotals() {
}
}
+ /**
+ * @todo remove this function & declare the 3 contact tables separately
+ *
+ * (Currently the construct method incorrectly melds them - this is an interim
+ * refactor in order to get this under ReportTemplateTests)
+ */
+ protected function buildAssigneeFrom() {
+ $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
+ $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
+ $this->_from = "
+ FROM civicrm_activity {$this->_aliases['civicrm_activity']}
+ INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']}
+ ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_contact']}.activity_id AND
+ {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$assigneeID}
+ INNER JOIN civicrm_contact civicrm_contact_assignee
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_contact_assignee.id
+ {$this->_aclFrom}";
+
+ if ($this->isTableSelected('civicrm_email')) {
+ $this->_from .= "
+ LEFT JOIN civicrm_email civicrm_email_assignee
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_email_assignee.contact_id AND
+ civicrm_email_assignee.is_primary = 1";
+ }
+ if ($this->isTableSelected('civicrm_phone')) {
+ $this->_from .= "
+ LEFT JOIN civicrm_phone civicrm_phone_assignee
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_phone_assignee.contact_id AND
+ civicrm_phone_assignee.is_primary = 1 ";
+ }
+ $this->_aliases['civicrm_contact'] = 'civicrm_contact_assignee';
+ $this->joinAddressFromContact();
+ }
+
+ /**
+ * @todo remove this function & declare the 3 contact tables separately
+ *
+ * (Currently the construct method incorrectly melds them - this is an interim
+ * refactor in order to get this under ReportTemplateTests)
+ */
+ protected function buildSourceFrom() {
+ $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
+ $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
+ $this->_from = "
+ FROM civicrm_activity {$this->_aliases['civicrm_activity']}
+ INNER JOIN civicrm_activity_contact {$this->_aliases['civicrm_activity_contact']}
+ ON {$this->_aliases['civicrm_activity']}.id = {$this->_aliases['civicrm_activity_contact']}.activity_id AND
+ {$this->_aliases['civicrm_activity_contact']}.record_type_id = {$sourceID}
+ INNER JOIN civicrm_contact civicrm_contact_source
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_contact_source.id
+ {$this->_aclFrom}";
+
+ if ($this->isTableSelected('civicrm_email')) {
+ $this->_from .= "
+ LEFT JOIN civicrm_email civicrm_email_source
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_email_source.contact_id AND
+ civicrm_email_source.is_primary = 1";
+ }
+ if ($this->isTableSelected('civicrm_phone')) {
+ $this->_from .= "
+ LEFT JOIN civicrm_phone civicrm_phone_source
+ ON {$this->_aliases['civicrm_activity_contact']}.contact_id = civicrm_phone_source.contact_id AND
+ civicrm_phone_source.is_primary = 1 ";
+ }
+ $this->_aliases['civicrm_contact'] = 'civicrm_contact_source';
+ $this->joinAddressFromContact();
+ }
+
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contact/Relationship.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contact/Relationship.php
index dd20fba0ea8..0e34078cdfb 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contact/Relationship.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contact/Relationship.php
@@ -256,10 +256,10 @@ public function __construct() {
'title' => ts('Relationship End Date'),
),
'is_permission_a_b' => array(
- 'title' => ts('Is permission A over B?'),
+ 'title' => ts('Permission A has to access B'),
),
'is_permission_b_a' => array(
- 'title' => ts('Is permission B over A?'),
+ 'title' => ts('Permission B has to access A'),
),
'description' => array(
'title' => ts('Description'),
@@ -310,22 +310,14 @@ public function __construct() {
),
'is_permission_a_b' => array(
'title' => ts('Does contact A have permission over contact B?'),
- 'operatorType' => CRM_Report_Form::OP_SELECT,
- 'options' => array(
- '' => ts('- Any -'),
- 1 => ts('Yes'),
- 0 => ts('No'),
- ),
+ 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
+ 'options' => CRM_Contact_BAO_Relationship::buildOptions('is_permission_a_b'),
'type' => CRM_Utils_Type::T_INT,
),
'is_permission_b_a' => array(
'title' => ts('Does contact B have permission over contact A?'),
- 'operatorType' => CRM_Report_Form::OP_SELECT,
- 'options' => array(
- '' => ts('- Any -'),
- 1 => ts('Yes'),
- 0 => ts('No'),
- ),
+ 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
+ 'options' => CRM_Contact_BAO_Relationship::buildOptions('is_permission_b_a'),
'type' => CRM_Utils_Type::T_INT,
),
),
@@ -792,6 +784,19 @@ public function alterDisplay(&$rows) {
$entryFound = TRUE;
}
+ // Handle permissioned relationships
+ if (array_key_exists('civicrm_relationship_is_permission_a_b', $row)) {
+ $rows[$rowNum]['civicrm_relationship_is_permission_a_b']
+ = ts(self::permissionedRelationship($row['civicrm_relationship_is_permission_a_b']));
+ $entryFound = TRUE;
+ }
+
+ if (array_key_exists('civicrm_relationship_is_permission_b_a', $row)) {
+ $rows[$rowNum]['civicrm_relationship_is_permission_b_a']
+ = ts(self::permissionedRelationship($row['civicrm_relationship_is_permission_b_a']));
+ $entryFound = TRUE;
+ }
+
// skip looking further in rows, if first row itself doesn't
// have the column we need
if (!$entryFound) {
@@ -800,6 +805,19 @@ public function alterDisplay(&$rows) {
}
}
+ /**
+ * Convert values to permissioned relationship descriptions
+ * @param [int] $key
+ * @return [string]
+ */
+ public static function permissionedRelationship($key) {
+ static $lookup;
+ if (!$lookup) {
+ $lookup = CRM_Contact_BAO_Relationship::buildOptions("is_permission_a_b");
+ };
+ return CRM_Utils_Array::value($key, $lookup);
+ }
+
/**
* @param $valid bool - set to 1 if we are looking for a valid relationship, 0 if not
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Bookkeeping.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Bookkeeping.php
index 088e2d730e8..8e4c25d1e3d 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Bookkeeping.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Bookkeeping.php
@@ -301,6 +301,10 @@ public function __construct() {
'title' => ts('Contribution Status'),
'default' => TRUE,
),
+ 'contribution_source' => array(
+ 'title' => ts('Source'),
+ 'name' => 'source',
+ ),
'id' => array(
'title' => ts('Contribution ID'),
'default' => TRUE,
@@ -314,6 +318,11 @@ public function __construct() {
'type' => CRM_Utils_Type::T_INT,
),
'receive_date' => array('operatorType' => CRM_Report_Form::OP_DATE),
+ 'contribution_source' => array(
+ 'title' => ts('Source'),
+ 'name' => 'source',
+ 'type' => CRM_Utils_Type::T_STRING,
+ ),
'contribution_status_id' => array(
'title' => ts('Contribution Status'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Detail.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Detail.php
index 7910fa1453c..2369127d1ae 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Detail.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Detail.php
@@ -46,6 +46,32 @@ class CRM_Report_Form_Contribute_Detail extends CRM_Report_Form {
protected $groupConcatTested = TRUE;
+ protected $isTempTableBuilt = FALSE;
+
+ /**
+ * Query mode.
+ *
+ * This can be 'Main' or 'SoftCredit' to denote which query we are building.
+ *
+ * @var string
+ */
+ protected $queryMode = 'Main';
+
+ /**
+ * Is this report being run on contributions as the base entity.
+ *
+ * The report structure is generally designed around a base entity but
+ * depending on input it can be run in a sort of hybrid way that causes a lot
+ * of complexity.
+ *
+ * If it is in isContributionsOnlyMode we can simplify.
+ *
+ * (arguably there should be 2 separate report templates, not one doing double duty.)
+ *
+ * @var bool
+ */
+ protected $isContributionBaseMode = FALSE;
+
/**
* This report has been optimised for group filtering.
*
@@ -465,34 +491,59 @@ public function statistics(&$rows) {
}
/**
- * This function appears to have been overrriden for the purposes of facilitating soft credits in the report.
- *
- * The report appears to have 2 different functions:
- * 1) contribution report
- * 2) soft credit report - showing a row per 'payment engagement' (payment or soft credit). There is a separate
- * soft credit report as well.
+ * Build the report query.
*
- * Somewhat confusingly this report returns multiple rows per contribution when soft credits are included. It feels
- * like there is a case to split it into 2 separate reports.
+ * @param bool $applyLimit
*
- * Soft credit functionality is not currently unit tested for this report.
+ * @return string
*/
- public function postProcess() {
- // @todo in order to make this report testable we need to remove this function override in favour of the
- // functions called by the reportTemplate.getrows api - this requires a bit of tidy up!
- // get the acl clauses built before we assemble the query
- $this->buildACLClause($this->_aliases['civicrm_contact']);
+ public function buildQuery($applyLimit = TRUE) {
+ if ($this->isTempTableBuilt) {
+ return "SELECT * FROM civireport_contribution_detail_temp3 $this->_orderBy";
+ }
+ return parent::buildQuery($applyLimit);
+ }
- $this->beginPostProcess();
+ /**
+ * Shared function for preliminary processing.
+ *
+ * This is called by the api / unit tests and the form layer and is
+ * the right place to do 'initial analysis of input'.
+ */
+ public function beginPostProcessCommon() {
+ // CRM-18312 - display soft_credits and soft_credits_for column
+ // when 'Contribution or Soft Credit?' column is not selected
+ if (empty($this->_params['fields']['contribution_or_soft'])) {
+ $this->_params['fields']['contribution_or_soft'] = 1;
+ $this->noDisplayContributionOrSoftColumn = TRUE;
+ }
+ if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) == 'contributions_only') {
+ $this->isContributionBaseMode = TRUE;
+ }
+ if ($this->isContributionBaseMode &&
+ (!empty($this->_params['fields']['soft_credit_type_id'])
+ || !empty($this->_params['soft_credit_type_id_value']))
+ ) {
+ unset($this->_params['fields']['soft_credit_type_id']);
+ if (!empty($this->_params['soft_credit_type_id_value'])) {
+ $this->_params['soft_credit_type_id_value'] = array();
+ CRM_Core_Session::setStatus(ts('Is it not possible to filter on soft contribution type when not including soft credits.'));
+ }
+ }
// 1. use main contribution query to build temp table 1
$sql = $this->buildQuery();
$tempQuery = "CREATE TEMPORARY TABLE civireport_contribution_detail_temp1 {$this->_databaseAttributes} AS {$sql}";
- $this->addToDeveloperTab($tempQuery);
- CRM_Core_DAO::executeQuery($tempQuery);
+ $this->temporaryTables['civireport_contribution_detail_temp1'] = ['name' => 'civireport_contribution_detail_temp1', 'temporary' => TRUE];
+ $this->executeReportQuery($tempQuery);
$this->setPager();
// 2. customize main contribution query for soft credit, and build temp table 2 with soft credit contributions only
+ $this->queryMode = 'SoftCredit';
+ // Rebuild select with no groupby. Do not let column headers change.
+ $headers = $this->_columnHeaders;
+ $this->select();
+ $this->_columnHeaders = $headers;
$this->softCreditFrom();
// also include custom group from if included
// since this might be included in select
@@ -504,11 +555,13 @@ public function postProcess() {
if (!empty($this->_groupBy) && !$this->noDisplayContributionOrSoftColumn) {
$this->_groupBy .= ', contribution_soft_civireport.amount';
}
- // we inner join with temp1 to restrict soft contributions to those in temp1 table
- $sql = "{$select} {$this->_from} {$this->_where} {$this->_groupBy}";
+ // we inner join with temp1 to restrict soft contributions to those in temp1 table.
+ // no group by here as we want to display as many soft credit rows as actually exist.
+ $sql = "{$select} {$this->_from} {$this->_where}";
$tempQuery = "CREATE TEMPORARY TABLE civireport_contribution_detail_temp2 {$this->_databaseAttributes} AS {$sql}";
- $this->addToDeveloperTab($tempQuery);
- CRM_Core_DAO::executeQuery($tempQuery);
+ $this->executeReportQuery($tempQuery);
+ $this->temporaryTables['civireport_contribution_detail_temp2'] = ['name' => 'civireport_contribution_detail_temp2', 'temporary' => TRUE];
+
if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
'soft_credits_only'
) {
@@ -527,66 +580,41 @@ public function postProcess() {
$this->customDataFrom();
// 3. Decide where to populate temp3 table from
- if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
- 'contributions_only'
+ if ($this->isContributionBaseMode
) {
- $tempQuery = "(SELECT * FROM civireport_contribution_detail_temp1)";
+ $this->executeReportQuery(
+ "CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes} AS (SELECT * FROM civireport_contribution_detail_temp1)"
+ );
}
elseif (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
'soft_credits_only'
) {
- $tempQuery = "(SELECT * FROM civireport_contribution_detail_temp2)";
+ $this->executeReportQuery(
+ "CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes} AS (SELECT * FROM civireport_contribution_detail_temp2)"
+ );
}
else {
- $tempQuery = "
+ $this->executeReportQuery("CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes}
(SELECT * FROM civireport_contribution_detail_temp1)
UNION ALL
-(SELECT * FROM civireport_contribution_detail_temp2)";
+(SELECT * FROM civireport_contribution_detail_temp2)");
}
-
- // 4. build temp table 3
- $sql = "CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes} AS {$tempQuery}";
- $this->addToDeveloperTab($sql);
- CRM_Core_DAO::executeQuery($sql);
-
- // 6. show result set from temp table 3
- $rows = array();
- $sql = "SELECT * FROM civireport_contribution_detail_temp3 $this->_orderBy";
- $this->buildRows($sql, $rows);
-
- // format result set.
- $this->formatDisplay($rows, FALSE);
-
- // assign variables to templates
- $this->doTemplateAssignment($rows);
- // do print / pdf / instance stuff if needed
- $this->endPostProcess($rows);
+ $this->temporaryTables['civireport_contribution_detail_temp3'] = ['name' => 'civireport_contribution_detail_temp3', 'temporary' => TRUE];
+ $this->isTempTableBuilt = TRUE;
}
/**
- * Shared function for preliminary processing.
+ * Store group bys into array - so we can check elsewhere what is grouped.
*
- * This is called by the api / unit tests and the form layer and is
- * the right place to do 'initial analysis of input'.
+ * If we are generating a table of soft credits we do not want to be using
+ * group by.
*/
- public function beginPostProcessCommon() {
- // CRM-18312 - display soft_credits and soft_credits_for column
- // when 'Contribution or Soft Credit?' column is not selected
- if (empty($this->_params['fields']['contribution_or_soft'])) {
- $this->_params['fields']['contribution_or_soft'] = 1;
- $this->noDisplayContributionOrSoftColumn = TRUE;
+ protected function storeGroupByArray() {
+ if ($this->queryMode === 'SoftCredit') {
+ $this->_groupByArray = [];
}
-
- if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
- 'contributions_only' &&
- (!empty($this->_params['fields']['soft_credit_type_id'])
- || !empty($this->_params['soft_credit_type_id_value']))
- ) {
- unset($this->_params['fields']['soft_credit_type_id']);
- if (!empty($this->_params['soft_credit_type_id_value'])) {
- $this->_params['soft_credit_type_id_value'] = array();
- CRM_Core_Session::setStatus(ts('Is it not possible to filter on soft contribution type when not including soft credits.'));
- }
+ else {
+ parent::storeGroupByArray();
}
}
@@ -600,7 +628,6 @@ public function beginPostProcessCommon() {
* Rows generated by SQL, with an array for each row.
*/
public function alterDisplay(&$rows) {
- $checkList = array();
$entryFound = FALSE;
$display_flag = $prev_cid = $cid = 0;
$contributionTypes = CRM_Contribute_PseudoConstant::financialType();
@@ -717,7 +744,7 @@ public function alterDisplay(&$rows) {
array_key_exists('civicrm_contribution_contribution_id', $row)
) {
$query = "
-SELECT civicrm_contact_id, civicrm_contact_sort_name, civicrm_contribution_total_amount_sum, civicrm_contribution_currency
+SELECT civicrm_contact_id, civicrm_contact_sort_name, civicrm_contribution_total_amount, civicrm_contribution_currency
FROM civireport_contribution_detail_temp2
WHERE civicrm_contribution_contribution_id={$row['civicrm_contribution_contribution_id']}";
$this->addToDeveloperTab($query);
@@ -729,7 +756,7 @@ public function alterDisplay(&$rows) {
$dao->civicrm_contact_id);
$string = $string . ($string ? $separator : '') .
"{$dao->civicrm_contact_sort_name} " .
- CRM_Utils_Money::format($dao->civicrm_contribution_total_amount_sum, $dao->civicrm_contribution_currency);
+ CRM_Utils_Money::format($dao->civicrm_contribution_total_amount, $dao->civicrm_contribution_currency);
}
$rows[$rowNum]['civicrm_contribution_soft_credits'] = $string;
}
@@ -796,6 +823,12 @@ public function sectionTotals() {
// pull section aliases out of $this->_sections
$sectionAliases = array_keys($this->_sections);
+ // hack alert - but it's tested so go forth & make pretty, or whack the new mole that popped up with gay abandon.
+ if (in_array('civicrm_contribution_total_amount', $this->_selectAliases)) {
+ $keyToHack = array_search('civicrm_contribution_total_amount', $this->_selectAliases);
+ $this->_selectAliases[$keyToHack] = 'civicrm_contribution_total_amount_sum';
+ }
+
$ifnulls = array();
foreach (array_merge($sectionAliases, $this->_selectAliases) as $alias) {
$ifnulls[] = "ifnull($alias, '') as $alias";
@@ -810,10 +843,10 @@ public function sectionTotals() {
$addtotals = '';
- if (array_search("civicrm_contribution_total_amount", $this->_selectAliases) !==
+ if (array_search("civicrm_contribution_total_amount_sum", $this->_selectAliases) !==
FALSE
) {
- $addtotals = ", sum(civicrm_contribution_total_amount) as sumcontribs";
+ $addtotals = ", sum(civicrm_contribution_total_amount_sum) as sumcontribs";
$showsumcontribs = TRUE;
}
@@ -899,6 +932,10 @@ public function softCreditFrom() {
{$this->_aclFrom}
";
+ //Join temp table if report is filtered by group. This is specific to 'notin' operator and covered in unit test(ref dev/core#212)
+ if (!empty($this->_params['gid_op']) && $this->_params['gid_op'] == 'notin') {
+ $this->joinGroupTempTable('civicrm_contact', 'id', $this->_aliases['civicrm_contact']);
+ }
$this->appendAdditionalFromJoins();
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/History.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/History.php
index 117ece48366..ac23fd4bfd4 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/History.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/History.php
@@ -867,6 +867,8 @@ public function alterDisplay(&$rows) {
$entryFound = TRUE;
}
+ $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, NULL, NULL) ? TRUE : $entryFound;
+
}
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Lybunt.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Lybunt.php
index 0fb7f093a5d..e5aeb0fcba2 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Lybunt.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Lybunt.php
@@ -567,7 +567,7 @@ public function beginPostProcessCommon() {
// @todo this acl has no test coverage and is very hard to test manually so could be fragile.
$this->resetFormSqlAndWhereHavingClauses();
- $this->contactTempTable = 'civicrm_report_temp_lybunt_c_' . date('Ymd_') . uniqid();
+ $this->contactTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('rptlybunt')->setId(date('Ymd_') . uniqid())->getName();
$this->limit();
$getContacts = "
CREATE TEMPORARY TABLE $this->contactTempTable {$this->_databaseAttributes}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Repeat.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Repeat.php
index 6b87d4ebfdb..471b076dab1 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Repeat.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Contribute/Repeat.php
@@ -400,6 +400,11 @@ public function from() {
.{$this->contributionJoinTableColumn}
LEFT JOIN $this->tempTableRepeat2 {$this->_aliases['civicrm_contribution']}2
ON {$this->groupByTableAlias}.$fromCol = {$this->_aliases['civicrm_contribution']}2.{$this->contributionJoinTableColumn}";
+
+ //Join temp table if report is filtered by group. This is specific to 'notin' operator and covered in unit test(ref dev/core#212)
+ if (!empty($this->_params['gid_op']) && $this->_params['gid_op'] == 'notin') {
+ $this->joinGroupTempTable('civicrm_contact', 'id', $this->_aliases['civicrm_contact']);
+ }
}
/**
@@ -825,6 +830,7 @@ public function statistics(&$rows) {
public function postProcess() {
$this->beginPostProcess();
+ $this->buildGroupTempTable();
$this->select();
$this->from();
$this->where();
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Register.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Register.php
index 094520df38e..4f7bd460289 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Register.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Register.php
@@ -191,8 +191,7 @@ public function postProcess() {
// get the submitted form values.
$params = $this->controller->exportValues($this->_name);
- $groupParams = array('name' => ('report_template'));
- $optionValue = CRM_Core_OptionValue::addOptionValue($params, $groupParams, $this->_action, $this->_id);
+ $optionValue = CRM_Core_OptionValue::addOptionValue($params, 'report_template', $this->_action, $this->_id);
CRM_Core_Session::setStatus(ts('The %1 \'%2\' has been saved.', array(
1 => 'Report Template',
2 => $optionValue->label,
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Walklist/Walklist.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Walklist/Walklist.php
index 04644112776..5727e3b5ec5 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Walklist/Walklist.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Form/Walklist/Walklist.php
@@ -76,55 +76,6 @@ public function __construct() {
),
),
),
- 'civicrm_address' => array(
- 'dao' => 'CRM_Core_DAO_Address',
- 'fields' => array(
- 'street_number' => array(
- 'title' => ts('Street Number'),
- 'type' => 1,
- ),
- 'street_address' => NULL,
- 'city' => NULL,
- 'postal_code' => NULL,
- 'state_province_id' => array(
- 'title' => ts('State/Province'),
- 'default' => TRUE,
- 'type' => CRM_Utils_Type::T_INT,
- ),
- 'country_id' => array(
- 'title' => ts('Country'),
- ),
- 'odd_street_number' => array(
- 'title' => ts('Odd/Even Street Number'),
- 'type' => CRM_Utils_Type::T_INT,
- 'no_display' => TRUE,
- 'required' => TRUE,
- 'dbAlias' => '(address_civireport.street_number % 2)',
- ),
- ),
- 'filters' => array(
- 'street_number' => array(
- 'title' => ts('Street Number'),
- 'type' => 1,
- 'name' => 'street_number',
- ),
- 'street_address' => NULL,
- 'city' => NULL,
- ),
- 'order_bys' => array(
- 'street_name' => array(
- 'title' => ts('Street Name'),
- ),
- 'street_number' => array(
- 'title' => ts('Street Number'),
- ),
- 'odd_street_number' => array(
- 'title' => ts('Odd/Even Street Number'),
- 'dbAlias' => 'civicrm_address_odd_street_number',
- ),
- ),
- 'grouping' => 'location-fields',
- ),
'civicrm_email' => array(
'dao' => 'CRM_Core_DAO_Email',
'fields' => array('email' => array('default' => TRUE)),
@@ -135,7 +86,7 @@ public function __construct() {
'fields' => array('phone' => NULL),
'grouping' => 'location-fields',
),
- );
+ ) + $this->getAddressColumns(array('group_bys' => FALSE));
parent::__construct();
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Info.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Info.php
index 83cc3bbbe5d..8d8c429a5de 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Info.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Report/Info.php
@@ -87,6 +87,10 @@ public function getPermissions($getAllUnconditionally = FALSE, $descriptions = F
ts('access Report Criteria'),
ts('Change report search criteria'),
),
+ 'save Report Criteria' => array(
+ ts('save Report Criteria'),
+ ts('Save report search criteria'),
+ ),
'administer private reports' => array(
ts('administer private reports'),
ts('Edit all private reports'),
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/DAO/Provider.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/DAO/Provider.php
index 990f58c84ea..fc295eef0d5 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/DAO/Provider.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/DAO/Provider.php
@@ -237,6 +237,7 @@ public static function &fields() {
'name' => 'is_default',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('SMS Provider is Default?'),
+ 'default' => '0',
'table_name' => 'civicrm_sms_provider',
'entity' => 'Provider',
'bao' => 'CRM_SMS_BAO_Provider',
@@ -249,6 +250,7 @@ public static function &fields() {
'name' => 'is_active',
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('SMS Provider is Active?'),
+ 'default' => '0',
'table_name' => 'civicrm_sms_provider',
'entity' => 'Provider',
'bao' => 'CRM_SMS_BAO_Provider',
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/Form/Provider.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/Form/Provider.php
index c5496c2b571..f6aace80402 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/Form/Provider.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/SMS/Form/Provider.php
@@ -159,7 +159,7 @@ public function setDefaultValues() {
*/
public function postProcess() {
- CRM_Utils_System::flushCache('CRM_SMS_DAO_Provider');
+ CRM_Utils_System::flushCache();
if ($this->_action & CRM_Core_Action::DELETE) {
CRM_SMS_BAO_Provider::del($this->_id);
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Tag/Form/Tag.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Tag/Form/Tag.php
index ed75c7017c3..765c71eb774 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Tag/Form/Tag.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Tag/Form/Tag.php
@@ -113,7 +113,7 @@ public function buildQuickForm() {
* @return void
*/
public function postProcess() {
- CRM_Utils_System::flushCache('CRM_Core_DAO_Tag');
+ CRM_Utils_System::flushCache();
// array contains the posted values
// exportvalues is not used because its give value 1 of the checkbox which were checked by default,
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/AdvanceSetting.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/AdvanceSetting.php
index 617940127f9..01db60e8b9e 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/AdvanceSetting.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/AdvanceSetting.php
@@ -50,6 +50,8 @@ public static function buildAdvanceSetting(&$form) {
$form->addGroup($options, 'is_update_dupe', ts('What to do upon duplicate match'));
// we do not have any url checks to allow relative urls
$form->addElement('text', 'post_URL', ts('Redirect URL'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'post_URL'));
+
+ $form->add('advcheckbox', 'add_cancel_button', ts('Include Cancel Button?'));
$form->addElement('text', 'cancel_URL', ts('Cancel Redirect URL'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'cancel_URL'));
$form->addElement('text', 'cancel_button_text', ts('Cancel Button Text'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'cancel_button_text'));
$form->addElement('text', 'submit_button_text', ts('Submit Button Text'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_UFGroup', 'submit_button_text'));
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/Group.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/Group.php
index 9adc2485035..9fcb8341766 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/Group.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/UF/Form/Group.php
@@ -270,6 +270,7 @@ public function setDefaultValues() {
}
}
else {
+ $defaults['add_cancel_button'] = 1;
$defaults['is_active'] = 1;
$defaults['is_map'] = 0;
$defaults['is_update_dupe'] = 0;
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Form.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Form.php
index b2b09f08f2a..7a6ad203c86 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Form.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Form.php
@@ -769,6 +769,7 @@ public function setPreUpgradeMessage(&$preUpgradeMessage, $currentVer, $latestVe
foreach ($revisions as $rev) {
if (version_compare($currentVer, $rev) < 0) {
$versionObject = $this->incrementalPhpObject($rev);
+ CRM_Upgrade_Incremental_General::updateMessageTemplate($preUpgradeMessage, $rev);
if (is_callable(array($versionObject, 'setPreUpgradeMessage'))) {
$versionObject->setPreUpgradeMessage($preUpgradeMessage, $rev, $currentVer);
}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/Base.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/Base.php
index 1cbf1cc3f57..b180904d70a 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/Base.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/Base.php
@@ -183,6 +183,18 @@ public static function addColumn($ctx, $table, $column, $properties, $localizabl
return TRUE;
}
+ /**
+ * Do any relevant message template updates.
+ *
+ * @param CRM_Queue_TaskContext $ctx
+ * @param string $version
+ */
+ public static function updateMessageTemplates($ctx, $version) {
+ $messageTemplateObject = new CRM_Upgrade_Incremental_MessageTemplates($version);
+ $messageTemplateObject->updateTemplates();
+
+ }
+
/**
* Drop a column from a table if it exist.
*
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/General.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/General.php
index 9f0ebe39c92..5737fbd5e47 100644
--- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/General.php
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/General.php
@@ -117,13 +117,41 @@ public static function setPreUpgradeMessage(&$preUpgradeMessage, $currentVer, $l
}
}
+ /**
+ * Perform any message template updates. 5.0+.
+ * @param $message
+ * @param $version
+ */
+ public static function updateMessageTemplate(&$message, $version) {
+ if (version_compare($version, 5.0, '<')) {
+ return;
+ }
+ $messageObj = new CRM_Upgrade_Incremental_MessageTemplates($version);
+ $messages = $messageObj->getUpgradeMessages();
+ if (empty($messages)) {
+ return;
+ }
+ $messagesHtml = array_map(function($k, $v) {
+ return sprintf("
' . ts("The default copies of the message templates listed below will be updated to handle new features or correct a problem. Your installation has customized versions of these message templates, and you will need to apply the updates manually after running this upgrade. Click here for detailed instructions. %2", array(
+ 1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Message+Templates#MessageTemplates-UpgradesandCustomizedSystemWorkflowTemplates',
+ 2 => '' . implode('', $messagesHtml) . '
',
+ ));
+
+ $messageObj->updateTemplates();
+ }
+
/**
* @param $message
* @param $latestVer
* @param $currentVer
*/
public static function checkMessageTemplate(&$message, $latestVer, $currentVer) {
-
+ if (version_compare($currentVer, 5.0, '>')) {
+ return;
+ }
$sql = "SELECT orig.workflow_id as workflow_id,
orig.msg_title as title
FROM civicrm_msg_template diverted JOIN civicrm_msg_template orig ON (
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/MessageTemplates.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/MessageTemplates.php
new file mode 100644
index 00000000000..7b11e199df9
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/MessageTemplates.php
@@ -0,0 +1,155 @@
+upgradeVersion;
+ }
+
+ /**
+ * @param string $upgradeVersion
+ */
+ public function setUpgradeVersion($upgradeVersion) {
+ $this->upgradeVersion = $upgradeVersion;
+ }
+
+ /**
+ * CRM_Upgrade_Incremental_MessageTemplates constructor.
+ *
+ * @param string $upgradeVersion
+ */
+ public function __construct($upgradeVersion) {
+ $this->setUpgradeVersion($upgradeVersion);
+ }
+
+ /**
+ * Get any templates that have been updated.
+ *
+ * @return array
+ */
+ protected function getTemplateUpdates() {
+ return [
+ [
+ 'version' => '5.4.alpha1',
+ 'upgrade_descriptor' => ts('Use email greeting at top where available'),
+ 'templates' => [
+ ['name' => 'membership_online_receipt', 'type' => 'text'],
+ ['name' => 'membership_online_receipt', 'type' => 'html'],
+ ['name' => 'contribution_online_receipt', 'type' => 'text'],
+ ['name' => 'contribution_online_receipt', 'type' => 'html'],
+ ['name' => 'event_online_receipt', 'type' => 'text'],
+ ['name' => 'event_online_receipt', 'type' => 'html'],
+ ['name' => 'event_online_receipt', 'type' => 'subject'],
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * Get any required template updates.
+ *
+ * @return array
+ */
+ public function getTemplatesToUpdate() {
+ $templates = $this->getTemplateUpdates();
+ $return = [];
+ foreach ($templates as $templateArray) {
+ if ($templateArray['version'] === $this->getUpgradeVersion()) {
+ foreach ($templateArray['templates'] as $template) {
+ $return[$template['name'] . '_' . $template['type']] = array_merge($template, $templateArray);
+ }
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * Get the upgrade messages.
+ */
+ public function getUpgradeMessages() {
+ $updates = $this->getTemplatesToUpdate();
+ $messages = [];
+ foreach ($updates as $key => $value) {
+ $templateLabel = civicrm_api3('OptionValue', 'getvalue', [
+ 'return' => 'label',
+ 'name' => $value['name'],
+ 'options' => ['limit' => 1],
+ ]);
+ $messages[$templateLabel] = $value['upgrade_descriptor'];
+ }
+ return $messages;
+ }
+
+ /**
+ * Update message templates.
+ */
+ public function updateTemplates() {
+ $templates = $this->getTemplatesToUpdate();
+ foreach ($templates as $template) {
+ $workFlowID = CRM_Core_DAO::singleValueQuery("SELECT MAX(id) as id FROM civicrm_option_value WHERE name = %1", [
+ 1 => [$template['name'], 'String'],
+ ]);
+ $content = file_get_contents(\Civi::paths()->getPath('[civicrm.root]/xml/templates/message_templates/' . $template['name'] . '_' . $template['type'] . '.tpl'));
+ $templatesToUpdate = [];
+ $templatesToUpdate[] = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_msg_template WHERE workflow_id = $workFlowID AND is_reserved = 1");
+ $defaultTemplateID = CRM_Core_DAO::singleValueQuery("
+ SELECT default_template.id FROM civicrm_msg_template reserved
+ LEFT JOIN civicrm_msg_template default_template
+ ON reserved.workflow_id = default_template.workflow_id
+ WHERE reserved.workflow_id = $workFlowID
+ AND reserved.is_reserved = 1 AND default_template.is_default = 1 AND reserved.id <> default_template.id
+ AND reserved.msg_{$template['type']} = default_template.msg_{$template['type']}
+ ");
+ if ($defaultTemplateID) {
+ $templatesToUpdate[] = $defaultTemplateID;
+ }
+
+ CRM_Core_DAO::executeQuery("
+ UPDATE civicrm_msg_template SET msg_{$template['type']} = %1 WHERE id IN (" . implode(',', $templatesToUpdate) . ")", [
+ 1 => [$content, 'String']
+ ]
+ );
+ }
+ }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveFive.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveFive.php
new file mode 100644
index 00000000000..c1d96128a19
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveFive.php
@@ -0,0 +1,87 @@
+' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '
' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
+ // }
+ }
+
+ /*
+ * Important! All upgrade functions MUST add a 'runSql' task.
+ * Uncomment and use the following template for a new upgrade version
+ * (change the x in the function name):
+ */
+
+ // /**
+ // * Upgrade function.
+ // *
+ // * @param string $rev
+ // */
+ // public function upgrade_5_0_x($rev) {
+ // $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+ // $this->addTask('Do the foo change', 'taskFoo', ...);
+ // // Additional tasks here...
+ // // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
+ // // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
+ // }
+
+ // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
+ // return TRUE;
+ // }
+
+}
diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveFour.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveFour.php
new file mode 100644
index 00000000000..ff9091a1f41
--- /dev/null
+++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveFour.php
@@ -0,0 +1,139 @@
+' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '
' . ts('A new permission, "%1", has been added. It is not granted by default. If your users create reports, you may wish to review their permissions.', array(1 => ts('save Report Criteria'))) . '
'; + } + // Example: Generate a post-upgrade message. + // if ($rev == '5.12.34') { + // $postUpgradeMessage .= '' . ts('A new permission has been added called %1 This Permission is now used to control access to the Manage Tags screen', array(1 => 'manage tags')) . '
'; + // $preUpgradeMessage .= '' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '
'; // } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveThree.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveThree.php index f4b75d32db4..5eebd3bc64b 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveThree.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveThree.php @@ -50,7 +50,7 @@ public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NU } // Example: Generate a pre-upgrade message. // if ($rev == '5.12.34') { - // $preUpgradeMessage .= '' . ts('A new permission has been added called %1 This Permission is now used to control access to the Manage Tags screen', array(1 => 'manage tags')) . '
'; + // $preUpgradeMessage .= '' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '
'; // } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveZero.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveZero.php index 30551dd604b..e77abab3318 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveZero.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FiveZero.php @@ -43,7 +43,7 @@ class CRM_Upgrade_Incremental_php_FiveZero extends CRM_Upgrade_Incremental_Base public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) { // Example: Generate a pre-upgrade message. //if ($rev == '5.12.34') { - // $preUpgradeMessage .= '' . ts('A new permission has been added called %1 This Permission is now used to control access to the Manage Tags screen', array(1 => 'manage tags')) . '
'; + // $preUpgradeMessage .= '' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '
'; //} } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourSeven.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourSeven.php index 0f667a7c919..2fa54ff1d45 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourSeven.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourSeven.php @@ -1140,7 +1140,7 @@ public static function alterIndexAndTypeForImageURL() { * @return bool */ public static function addMailingTemplateType() { - if (!CRM_Core_DAO::checkFieldExists('civicrm_mailing', 'template_type', FALSE)) { + if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_mailing', 'template_type', FALSE)) { CRM_Core_DAO::executeQuery(' ALTER TABLE civicrm_mailing ADD COLUMN `template_type` varchar(64) NOT NULL DEFAULT \'traditional\' COMMENT \'The language/processing system used for email templates.\', diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourThree.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourThree.php index e224cac48a7..f1030b54617 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourThree.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/FourThree.php @@ -277,7 +277,7 @@ public function upgrade_4_3_alpha1($rev) { */ public function upgrade_4_3_alpha2($rev) { //CRM-11847 - $isColumnPresent = CRM_Core_DAO::checkFieldExists('civicrm_dedupe_rule_group', 'is_default'); + $isColumnPresent = CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_dedupe_rule_group', 'is_default'); if ($isColumnPresent) { CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dedupe_rule_group DROP COLUMN is_default'); } @@ -300,7 +300,7 @@ public function upgrade_4_3_beta2($rev) { // CRM-12002 if ( CRM_Core_DAO::checkTableExists('log_civicrm_line_item') && - CRM_Core_DAO::checkFieldExists('log_civicrm_line_item', 'label') + CRM_Core_BAO_SchemaHandler::checkIfFieldExists('log_civicrm_line_item', 'label') ) { CRM_Core_DAO::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL'); } @@ -335,7 +335,7 @@ public function upgrade_4_3_beta5($rev) { // CRM-12205 if ( CRM_Core_DAO::checkTableExists('log_civicrm_financial_trxn') && - CRM_Core_DAO::checkFieldExists('log_civicrm_financial_trxn', 'trxn_id') + CRM_Core_BAO_SchemaHandler::checkIfFieldExists('log_civicrm_financial_trxn', 'trxn_id') ) { CRM_Core_DAO::executeQuery('ALTER TABLE `log_civicrm_financial_trxn` CHANGE `trxn_id` `trxn_id` VARCHAR(255) NULL DEFAULT NULL'); } @@ -343,7 +343,7 @@ public function upgrade_4_3_beta5($rev) { // CRM-12367 - add this column to single lingual sites only $upgrade = new CRM_Upgrade_Form(); if (!$upgrade->multilingual && - !CRM_Core_DAO::checkFieldExists('civicrm_premiums', 'premiums_nothankyou_label') + !CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_premiums', 'premiums_nothankyou_label') ) { $query = " ALTER TABLE civicrm_premiums @@ -925,7 +925,7 @@ public function task_4_3_alpha1_checkDBConstraints() { } } // check if column contact_id is present or not in civicrm_financial_account - $fieldExists = CRM_Core_DAO::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE); + $fieldExists = CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_financial_account', 'contact_id', FALSE); if (!$fieldExists) { $query = " ALTER TABLE civicrm_financial_account diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/Template.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/Template.php index 7fe34e90de7..5c15aa15755 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/Template.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/php/Template.php @@ -48,7 +48,7 @@ class CRM_Upgrade_Incremental_php_ extends CRM_Upgrad public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) { // Example: Generate a pre-upgrade message. // if ($rev == '5.12.34') { - // $preUpgradeMessage .= '' . ts('A new permission has been added called %1 This Permission is now used to control access to the Manage Tags screen', array(1 => 'manage tags')) . '
'; + // $preUpgradeMessage .= '' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '
'; // } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.0.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.0.mysql.tpl deleted file mode 100644 index b557c2542ba..00000000000 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.0.mysql.tpl +++ /dev/null @@ -1,18 +0,0 @@ -{* file to handle db changes in 5.3.0 during upgrade *} -ALTER TABLE civicrm_custom_group ALTER column is_multiple SET DEFAULT 0; -UPDATE civicrm_custom_group SET is_multiple = 0 WHERE is_multiple IS NULL; -ALTER TABLE civicrm_custom_group ALTER column is_active SET DEFAULT 1; -ALTER TABLE civicrm_custom_field ALTER column is_view SET DEFAULT 0; -UPDATE civicrm_custom_field SET is_view = 0 WHERE is_view IS NULL; -ALTER TABLE civicrm_custom_field ALTER column is_required SET DEFAULT 0; -UPDATE civicrm_custom_field SET is_required = 0 WHERE is_required IS NULL; -ALTER TABLE civicrm_custom_field ALTER column is_searchable SET DEFAULT 0; -UPDATE civicrm_custom_field SET is_searchable = 0 WHERE is_required IS NULL; -ALTER TABLE civicrm_custom_field ALTER column is_active SET DEFAULT 1; - -SET @UKCountryId = (SELECT id FROM civicrm_country cc WHERE cc.name = 'United Kingdom'); -INSERT INTO civicrm_state_province (country_id, abbreviation, name) -VALUES (@UKCountryId, 'MON', 'Monmouthshire'); - -{* dev/core/#152 *} -UPDATE `civicrm_custom_field` set `html_type` = "Multi-Select" WHERE `html_type` = "AdvMulti-Select"; diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.1.mysql.tpl deleted file mode 100644 index 2e2057d6dd9..00000000000 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.1.mysql.tpl +++ /dev/null @@ -1,19 +0,0 @@ -{* file to handle db changes in 5.3.1 during upgrade *} -{* Re run upgrades from 5.3.0 Just in case they were missed somehow due to dodgy tarball *} -ALTER TABLE civicrm_custom_group ALTER column is_multiple SET DEFAULT 0; -UPDATE civicrm_custom_group SET is_multiple = 0 WHERE is_multiple IS NULL; -ALTER TABLE civicrm_custom_group ALTER column is_active SET DEFAULT 1; -ALTER TABLE civicrm_custom_field ALTER column is_view SET DEFAULT 0; -UPDATE civicrm_custom_field SET is_view = 0 WHERE is_view IS NULL; -ALTER TABLE civicrm_custom_field ALTER column is_required SET DEFAULT 0; -UPDATE civicrm_custom_field SET is_required = 0 WHERE is_required IS NULL; -ALTER TABLE civicrm_custom_field ALTER column is_searchable SET DEFAULT 0; -UPDATE civicrm_custom_field SET is_searchable = 0 WHERE is_required IS NULL; -ALTER TABLE civicrm_custom_field ALTER column is_active SET DEFAULT 1; - -SET @UKCountryId = (SELECT id FROM civicrm_country cc WHERE cc.name = 'United Kingdom'); -INSERT IGNORE INTO civicrm_state_province (country_id, abbreviation, name) -VALUES (@UKCountryId, 'MON', 'Monmouthshire'); - -{* dev/core/#152 *} -UPDATE `civicrm_custom_field` set `html_type` = "Multi-Select" WHERE `html_type` = "AdvMulti-Select"; diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.alpha1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.alpha1.mysql.tpl index 8a3d52ecc1e..7c05f9ecaac 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.alpha1.mysql.tpl +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.3.alpha1.mysql.tpl @@ -1 +1,18 @@ {* file to handle db changes in 5.3.alpha1 during upgrade *} +ALTER TABLE civicrm_custom_group ALTER column is_multiple SET DEFAULT 0; +UPDATE civicrm_custom_group SET is_multiple = 0 WHERE is_multiple IS NULL; +ALTER TABLE civicrm_custom_group ALTER column is_active SET DEFAULT 1; +ALTER TABLE civicrm_custom_field ALTER column is_view SET DEFAULT 0; +UPDATE civicrm_custom_field SET is_view = 0 WHERE is_view IS NULL; +ALTER TABLE civicrm_custom_field ALTER column is_required SET DEFAULT 0; +UPDATE civicrm_custom_field SET is_required = 0 WHERE is_required IS NULL; +ALTER TABLE civicrm_custom_field ALTER column is_searchable SET DEFAULT 0; +UPDATE civicrm_custom_field SET is_searchable = 0 WHERE is_required IS NULL; +ALTER TABLE civicrm_custom_field ALTER column is_active SET DEFAULT 1; + +SET @UKCountryId = (SELECT id FROM civicrm_country cc WHERE cc.name = 'United Kingdom'); +INSERT IGNORE INTO civicrm_state_province (country_id, abbreviation, name) +VALUES (@UKCountryId, 'MON', 'Monmouthshire'); + +{* dev/core/#152 *} +UPDATE `civicrm_custom_field` set `html_type` = "Multi-Select" WHERE `html_type` = "AdvMulti-Select"; diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.4.alpha1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.4.alpha1.mysql.tpl new file mode 100644 index 00000000000..e47d96cf832 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.4.alpha1.mysql.tpl @@ -0,0 +1,13 @@ +{* file to handle db changes in 5.4.alpha1 during upgrade *} + +{* +v4.7.20 updated these colums so that new installs would default to TIMESTAMP instead of DATETIME. +Status-checks and DoctorWhen have been encouraging a transition, but it wasn't mandated, and there +was little urgency... because `expired_date` was ignored, and adhoc TTLs on `created_date` had +generally long windows. Now that we're using `expired_date` in more important ways for 5.4, +we want to ensure that these values are handled precisely and consistently. +*} + +ALTER TABLE civicrm_cache + CHANGE created_date created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'When was the cache item created', + CHANGE expired_date expired_date TIMESTAMP NULL DEFAULT NULL COMMENT 'When should the cache item expire'; diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.4.beta1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.4.beta1.mysql.tpl new file mode 100644 index 00000000000..b486eda69d1 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.4.beta1.mysql.tpl @@ -0,0 +1 @@ +{* file to handle db changes in 5.4.beta1 during upgrade *} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.0.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.0.mysql.tpl new file mode 100644 index 00000000000..b27009b9dc6 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.0.mysql.tpl @@ -0,0 +1 @@ +{* file to handle db changes in 5.5.0 during upgrade *} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.1.mysql.tpl new file mode 100644 index 00000000000..dd195d7382e --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.1.mysql.tpl @@ -0,0 +1 @@ +{* file to handle db changes in 5.5.1 during upgrade *} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.alpha1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.alpha1.mysql.tpl new file mode 100644 index 00000000000..504659d4374 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.alpha1.mysql.tpl @@ -0,0 +1,18 @@ +{* file to handle db changes in 5.5.alpha1 during upgrade *} +#https://lab.civicrm.org/dev/core/issues/228 +UPDATE civicrm_option_group SET is_active = 0 WHERE is_active IS NULL; +ALTER TABLE civicrm_option_group MODIFY COLUMN is_active TINYINT(4) NOT NULL DEFAULT 1 COMMENT 'Is this option group active?'; +UPDATE civicrm_option_group SET is_locked = 0 WHERE is_locked IS NULL; +ALTER TABLE civicrm_option_group MODIFY COLUMN is_locked TINYINT(4) NOT NULL DEFAULT 1 COMMENT 'A lock to remove the ability to add new options via the UI.'; +#is_reserved already has a default so is effectively required but let's be explicit. +UPDATE civicrm_option_group SET `is_reserved` = 0 WHERE `is_reserved` IS NULL; +ALTER TABLE civicrm_option_group MODIFY COLUMN `is_reserved` tinyint(4) NOT NULL DEFAULT 1 COMMENT 'Is this a predefined system option group (i.e. it can not be deleted)?'; + +#https://lab.civicrm.org/dev/core/issues/155 +{* Fix is_reserved flag on civicrm_option_group table *} +UPDATE civicrm_option_group AS cog INNER JOIN civicrm_custom_field AS ccf +ON cog.id = ccf.option_group_id +SET cog.is_reserved = 0 WHERE cog.is_active = 1 AND ccf.is_active = 1; +UPDATE civicrm_option_group SET is_reserved = 1 WHERE name='environment'; + +UPDATE civicrm_navigation SET url = 'civicrm/admin/options?action=browse&reset=1' WHERE name = 'Dropdown Options' AND domain_id = {$domainID}; diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.beta1.mysql.tpl b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.beta1.mysql.tpl new file mode 100644 index 00000000000..e2172c7ed06 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Upgrade/Incremental/sql/5.5.beta1.mysql.tpl @@ -0,0 +1,6 @@ +{* file to handle db changes in 5.5.beta1 during upgrade *} + +UPDATE civicrm_action_schedule SET start_action_date = 'start_date' WHERE start_action_date = 'event_start_date'; +UPDATE civicrm_action_schedule SET start_action_date = 'end_date' WHERE start_action_date = 'event_end_date'; +UPDATE civicrm_action_schedule SET start_action_date = 'join_date' WHERE start_action_date = 'membership_join_date'; +UPDATE civicrm_action_schedule SET start_action_date = 'end_date' WHERE start_action_date = 'membership_end_date'; diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Array.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Array.php index a9d6cdd07ef..73b4dab45a2 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Array.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Array.php @@ -866,9 +866,13 @@ public static function subset($array, $keys) { * This is necessary to preserve sort order when sending an array through json_encode. * * @param array $associative + * Ex: ['foo' => 'bar']. * @param string $keyName + * Ex: 'key'. * @param string $valueName + * Ex: 'value'. * @return array + * Ex: [0 => ['key' => 'foo', 'value' => 'bar']]. */ public static function makeNonAssociative($associative, $keyName = 'key', $valueName = 'value') { $output = array(); @@ -965,38 +969,58 @@ public static function extend(&$array, $other) { } /** - * Get a single value from an array-tre. + * Get a single value from an array-tree. * - * @param array $arr - * Ex: array('foo'=>array('bar'=>123)). - * @param array $pathParts - * Ex: array('foo',bar'). - * @return mixed|NULL + * @param array $values + * Ex: ['foo' => ['bar' => 123]]. + * @param array $path + * Ex: ['foo', 'bar']. + * @param mixed $default + * @return mixed * Ex 123. */ - public static function pathGet($arr, $pathParts) { - $r = $arr; - foreach ($pathParts as $part) { - if (!isset($r[$part])) { - return NULL; + public static function pathGet($values, $path, $default = NULL) { + foreach ($path as $key) { + if (!is_array($values) || !isset($values[$key])) { + return $default; + } + $values = $values[$key]; + } + return $values; + } + + /** + * Check if a key isset which may be several layers deep. + * + * This is a helper for when the calling function does not know how many layers deep + * the path array is so cannot easily check. + * + * @param array $values + * @param array $path + * @return bool + */ + public static function pathIsset($values, $path) { + foreach ($path as $key) { + if (!is_array($values) || !isset($values[$key])) { + return FALSE; } - $r = $r[$part]; + $values = $values[$key]; } - return $r; + return TRUE; } /** * Set a single value in an array tree. * - * @param array $arr - * Ex: array('foo'=>array('bar'=>123)). + * @param array $values + * Ex: ['foo' => ['bar' => 123]]. * @param array $pathParts - * Ex: array('foo',bar'). + * Ex: ['foo', 'bar']. * @param $value * Ex: 456. */ - public static function pathSet(&$arr, $pathParts, $value) { - $r = &$arr; + public static function pathSet(&$values, $pathParts, $value) { + $r = &$values; $last = array_pop($pathParts); foreach ($pathParts as $part) { if (!isset($r[$part])) { @@ -1017,19 +1041,10 @@ public static function pathSet(&$arr, $pathParts, $value) { * @param string $valueField * Ex: 'value'. * @return array - * Ex: array( - * 0 => array('key' => 'foo', 'value' => 'bar') - * ). + * @deprecated */ public static function toKeyValueRows($array, $keyField = 'key', $valueField = 'value') { - $result = array(); - foreach ($array as $key => $value) { - $result[] = array( - $keyField => $key, - $valueField => $value, - ); - } - return $result; + return self::makeNonAssociative($array, $keyField, $valueField); } /** @@ -1152,77 +1167,4 @@ public static function findInTree($search, $tree, $field = 'id') { return NULL; } - /** - * Check if a key isset which may be several layers deep. - * - * This is a helper for when the calling function does not know how many layers deep the - * path array is so cannot easily check. - * - * @param array $array - * @param array $path - * @return bool - * @throws \CRM_Core_Exception - */ - public static function recursiveIsset($array, $path) { - foreach ($path as $key) { - if (!is_array($array) || !isset($array[$key])) { - return FALSE; - } - $array = $array[$key]; - } - return TRUE; - } - - /** - * Check if a key isset which may be several layers deep. - * - * This is a helper for when the calling function does not know how many layers deep the - * path array is so cannot easily check. - * - * @param array $array - * @param array $path - * An array of keys - e.g [0, 'bob', 8] where we want to check if $array[0]['bob'][8] - * @param mixed $default - * Value to return if not found. - * @return bool - * @throws \CRM_Core_Exception - */ - public static function recursiveValue($array, $path, $default = NULL) { - foreach ($path as $key) { - if (!is_array($array) || !isset($array[$key])) { - return $default; - } - $array = $array[$key]; - } - return $array; - } - - /** - * Append the value to the array using the key provided. - * - * e.g if value is 'llama' & path is [0, 'email', 'location'] result will be - * [0 => ['email' => ['location' => 'llama']] - * - * @param $path - * @param $value - * @param array $source - * - * @return array - */ - public static function recursiveBuild($path, $value, $source = []) { - $arrayKey = array_shift($path); - // Recurse through array keys - if ($path) { - if (!isset($source[$arrayKey])) { - $source[$arrayKey] = []; - } - $source[$arrayKey] = self::recursiveBuild($path, $value, $source[$arrayKey]); - } - // Final iteration - else { - $source[$arrayKey] = $value; - } - return $source; - } - } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache.php index 00a92888fc8..0ce1128c83b 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache.php @@ -35,6 +35,9 @@ * Cache is an empty base object, we'll modify the scheme when we have different caching schemes */ class CRM_Utils_Cache { + + const DELIMITER = '/'; + /** * (Quasi-Private) Treat this as private. It is marked public to facilitate testing. * @@ -64,25 +67,11 @@ public function __construct(&$config) { */ public static function &singleton() { if (self::$_singleton === NULL) { - $className = 'ArrayCache'; // default to ArrayCache for now - - // Maintain backward compatibility for now. - // Setting CIVICRM_USE_MEMCACHE or CIVICRM_USE_ARRAYCACHE will - // override the CIVICRM_DB_CACHE_CLASS setting. - // Going forward, CIVICRM_USE_xxxCACHE should be deprecated. - if (defined('CIVICRM_USE_MEMCACHE') && CIVICRM_USE_MEMCACHE) { - $className = 'Memcache'; - } - elseif (defined('CIVICRM_USE_ARRAYCACHE') && CIVICRM_USE_ARRAYCACHE) { - $className = 'ArrayCache'; - } - elseif (defined('CIVICRM_DB_CACHE_CLASS') && CIVICRM_DB_CACHE_CLASS) { - $className = CIVICRM_DB_CACHE_CLASS; - } - + $className = self::getCacheDriver(); // a generic method for utilizing any of the available db caches. $dbCacheClass = 'CRM_Utils_Cache_' . $className; $settings = self::getCacheSettings($className); + $settings['prefix'] = CRM_Utils_Array::value('prefix', $settings, '') . self::DELIMITER . 'default' . self::DELIMITER; self::$_singleton = new $dbCacheClass($settings); } return self::$_singleton; @@ -171,6 +160,9 @@ public static function getCacheSettings($cachePlugin) { * @param array $params * Array with keys: * - name: string, unique symbolic name. + * For a naming convention, use `snake_case` or `CamelCase` to maximize + * portability/cleanliness. Any other punctuation or whitespace + * should function correctly, but it can be harder to inspect/debug. * - type: array|string, list of acceptable cache types, in order of preference. * - prefetch: bool, whether to prefetch all data in cache (if possible). * @return CRM_Utils_Cache_Interface @@ -180,13 +172,17 @@ public static function getCacheSettings($cachePlugin) { public static function create($params = array()) { $types = (array) $params['type']; + if (!empty($params['name'])) { + $params['name'] = CRM_Core_BAO_Cache::cleanKey($params['name']); + } + foreach ($types as $type) { switch ($type) { case '*memory*': if (defined('CIVICRM_DB_CACHE_CLASS') && in_array(CIVICRM_DB_CACHE_CLASS, array('Memcache', 'Memcached', 'Redis'))) { $dbCacheClass = 'CRM_Utils_Cache_' . CIVICRM_DB_CACHE_CLASS; $settings = self::getCacheSettings(CIVICRM_DB_CACHE_CLASS); - $settings['prefix'] = $settings['prefix'] . '_' . $params['name']; + $settings['prefix'] = CRM_Utils_Array::value('prefix', $settings, '') . self::DELIMITER . $params['name'] . self::DELIMITER; return new $dbCacheClass($settings); } break; @@ -210,4 +206,56 @@ public static function create($params = array()) { throw new CRM_Core_Exception("Failed to instantiate cache. No supported cache type found. " . print_r($params, 1)); } + /** + * Assert that a key is well-formed. + * + * @param string $key + * @return string + * Same $key, if it's valid. + * @throws \CRM_Utils_Cache_InvalidArgumentException + */ + public static function assertValidKey($key) { + $strict = CRM_Utils_Constant::value('CIVICRM_PSR16_STRICT', FALSE) || defined('CIVICRM_TEST'); + + if (!is_string($key)) { + throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache key: Not a string"); + } + + if ($strict && !preg_match(';^[A-Za-z0-9_\-\. ]+$;', $key)) { + throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache key: Illegal characters"); + } + + if ($strict && strlen($key) > 255) { + throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache key: Too long"); + } + + return $key; + } + + /** + * @return string + * Ex: 'ArrayCache', 'Memcache', 'Redis'. + */ + public static function getCacheDriver() { + $className = 'ArrayCache'; // default to ArrayCache for now + + // Maintain backward compatibility for now. + // Setting CIVICRM_USE_MEMCACHE or CIVICRM_USE_ARRAYCACHE will + // override the CIVICRM_DB_CACHE_CLASS setting. + // Going forward, CIVICRM_USE_xxxCACHE should be deprecated. + if (defined('CIVICRM_USE_MEMCACHE') && CIVICRM_USE_MEMCACHE) { + $className = 'Memcache'; + return $className; + } + elseif (defined('CIVICRM_USE_ARRAYCACHE') && CIVICRM_USE_ARRAYCACHE) { + $className = 'ArrayCache'; + return $className; + } + elseif (defined('CIVICRM_DB_CACHE_CLASS') && CIVICRM_DB_CACHE_CLASS) { + $className = CIVICRM_DB_CACHE_CLASS; + return $className; + } + return $className; + } + } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/APCcache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/APCcache.php index e696aa19c3d..26fa86b2416 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/APCcache.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/APCcache.php @@ -31,6 +31,10 @@ * @copyright CiviCRM LLC (c) 2004-2018 */ class CRM_Utils_Cache_APCcache implements CRM_Utils_Cache_Interface { + + use CRM_Utils_Cache_NaiveMultipleTrait; // TODO Consider native implementation. + use CRM_Utils_Cache_NaiveHasTrait; // TODO Native implementation + const DEFAULT_TIMEOUT = 3600; const DEFAULT_PREFIX = ''; @@ -72,11 +76,19 @@ public function __construct(&$config) { /** * @param $key * @param $value + * @param null|int|\DateInterval $ttl * * @return bool */ - public function set($key, &$value) { - if (!apc_store($this->_prefix . $key, $value, $this->_timeout)) { + public function set($key, $value, $ttl = NULL) { + CRM_Utils_Cache::assertValidKey($key); + if (is_int($ttl) && $ttl <= 0) { + return $this->delete($key); + } + + $ttl = CRM_Utils_Date::convertCacheTtl($ttl, $this->_timeout); + $expires = time() + $ttl; + if (!apc_store($this->_prefix . $key, ['e' => $expires, 'v' => $value], $ttl)) { return FALSE; } return TRUE; @@ -84,11 +96,17 @@ public function set($key, &$value) { /** * @param $key + * @param mixed $default * * @return mixed */ - public function get($key) { - return apc_fetch($this->_prefix . $key); + public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); + $result = apc_fetch($this->_prefix . $key, $success); + if ($success && isset($result['e']) && $result['e'] > time()) { + return $this->reobjectify($result['v']); + } + return $default; } /** @@ -97,22 +115,33 @@ public function get($key) { * @return bool|string[] */ public function delete($key) { - return apc_delete($this->_prefix . $key); + CRM_Utils_Cache::assertValidKey($key); + apc_delete($this->_prefix . $key); + return TRUE; } public function flush() { $allinfo = apc_cache_info('user'); $keys = $allinfo['cache_list']; - $prefix = $this->_prefix . "CRM_"; // Our keys follows this pattern: ([A-Za-z0-9_]+)?CRM_[A-Za-z0-9_]+ + $prefix = $this->_prefix; // Our keys follows this pattern: ([A-Za-z0-9_]+)?CRM_[A-Za-z0-9_]+ $lp = strlen($prefix); // Get prefix length foreach ($keys as $key) { $name = $key['info']; if ($prefix == substr($name, 0, $lp)) { // Ours? - apc_delete($this->_prefix . $name); + apc_delete($name); } } + return TRUE; + } + + public function clear() { + return $this->flush(); + } + + private function reobjectify($value) { + return is_object($value) ? unserialize(serialize($value)) : $value; } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/ArrayCache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/ArrayCache.php index b2272fa1eb6..287c6a3e5ce 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/ArrayCache.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/ArrayCache.php @@ -36,11 +36,18 @@ */ class CRM_Utils_Cache_Arraycache implements CRM_Utils_Cache_Interface { + use CRM_Utils_Cache_NaiveMultipleTrait; + use CRM_Utils_Cache_NaiveHasTrait; // TODO Native implementation + + const DEFAULT_TIMEOUT = 3600; + /** * The cache storage container, an in memory array by default */ protected $_cache; + protected $_expires; + /** * Constructor. * @@ -51,35 +58,67 @@ class CRM_Utils_Cache_Arraycache implements CRM_Utils_Cache_Interface { */ public function __construct($config) { $this->_cache = array(); + $this->_expires = array(); } /** * @param string $key * @param mixed $value + * @param null|int|\DateInterval $ttl + * @return bool + * @throws \Psr\SimpleCache\InvalidArgumentException */ - public function set($key, &$value) { - $this->_cache[$key] = $value; + public function set($key, $value, $ttl = NULL) { + CRM_Utils_Cache::assertValidKey($key); + $this->_cache[$key] = $this->reobjectify($value); + $this->_expires[$key] = CRM_Utils_Date::convertCacheTtlToExpires($ttl, self::DEFAULT_TIMEOUT); + return TRUE; } /** * @param string $key + * @param mixed $default * * @return mixed + * @throws \Psr\SimpleCache\InvalidArgumentException */ - public function get($key) { - return CRM_Utils_Array::value($key, $this->_cache); + public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); + if (isset($this->_expires[$key]) && is_numeric($this->_expires[$key]) && $this->_expires[$key] <= time()) { + return $default; + } + if (array_key_exists($key, $this->_cache)) { + return $this->reobjectify($this->_cache[$key]); + } + return $default; } /** * @param string $key + * @return bool + * @throws \Psr\SimpleCache\InvalidArgumentException */ public function delete($key) { + CRM_Utils_Cache::assertValidKey($key); + unset($this->_cache[$key]); + unset($this->_expires[$key]); + return TRUE; } public function flush() { unset($this->_cache); + unset($this->_expires); $this->_cache = array(); + return TRUE; + } + + public function clear() { + return $this->flush(); + } + + private function reobjectify($value) { + return is_object($value) ? unserialize(serialize($value)) : $value; } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/CacheException.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/CacheException.php new file mode 100644 index 00000000000..cdb0821da2f --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/CacheException.php @@ -0,0 +1,36 @@ + mixed $value - * - * and PSR-6 defines: - * - * function getItem($key) => ItemInterface $item - * - * These are different styles (e.g. "weak item" vs "strong item"), - * but the two methods do not *conflict*. They can coexist, - * and you can trivially write adapters between the two. - * - * @see https://github.com/php-fig/fig-standards/blob/master/proposed/cache.md + * @see https://www.php-fig.org/psr/psr-16/ */ -interface CRM_Utils_Cache_Interface { +interface CRM_Utils_Cache_Interface extends \Psr\SimpleCache\CacheInterface { /** * Set the value in the cache. * * @param string $key * @param mixed $value + * @param null|int|\DateInterval $ttl + * @return bool */ - public function set($key, &$value); + public function set($key, $value, $ttl = NULL); /** * Get a value from the cache. * * @param string $key + * @param mixed $default * @return mixed - * NULL if $key has not been previously set + * The previously set value value, or $default (NULL). */ - public function get($key); + public function get($key, $default = NULL); /** * Delete a value from the cache. * * @param string $key + * @return bool */ public function delete($key); /** * Delete all values from the cache. + * + * NOTE: flush() and clear() should be aliases. flush() is specified by + * Civi's traditional interface, and clear() is specified by PSR-16. + * + * @return bool + * @see clear + * @deprecated */ public function flush(); + /** + * Delete all values from the cache. + * + * NOTE: flush() and clear() should be aliases. flush() is specified by + * Civi's traditional interface, and clear() is specified by PSR-16. + * + * @return bool + * @see flush + */ + public function clear(); + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + */ + public function has($key); + } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/InvalidArgumentException.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/InvalidArgumentException.php new file mode 100644 index 00000000000..5d9747d9164 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/InvalidArgumentException.php @@ -0,0 +1,36 @@ +_cache->set($this->_prefix . $key, $value, FALSE, $this->_timeout)) { - return FALSE; + public function set($key, $value, $ttl = NULL) { + CRM_Utils_Cache::assertValidKey($key); + if (is_int($ttl) && $ttl <= 0) { + return $this->delete($key); } - return TRUE; + $expires = CRM_Utils_Date::convertCacheTtlToExpires($ttl, $this->_timeout); + return $this->_cache->set($this->getTruePrefix() . $key, serialize($value), FALSE, $expires); } /** * @param $key + * @param mixed $default * * @return mixed */ - public function &get($key) { - $result = $this->_cache->get($this->_prefix . $key); - return $result; + public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); + $result = $this->_cache->get($this->getTruePrefix() . $key); + return ($result === FALSE) ? $default : unserialize($result); } + /** + * @param string $key + * + * @return bool + * @throws \Psr\SimpleCache\CacheException + */ + public function has($key) { + CRM_Utils_Cache::assertValidKey($key); + $result = $this->_cache->get($this->getTruePrefix() . $key); + return ($result !== FALSE); + } + + /** * @param $key * - * @return mixed + * @return bool */ public function delete($key) { - return $this->_cache->delete($this->_prefix . $key); + CRM_Utils_Cache::assertValidKey($key); + $this->_cache->delete($this->getTruePrefix() . $key); + return TRUE; } /** - * @return mixed + * @return bool */ public function flush() { - return $this->_cache->flush(); + $this->_truePrefix = NULL; + $this->_cache->delete($this->_prefix); + return TRUE; + } + + public function clear() { + return $this->flush(); + } + + protected function getTruePrefix() { + if ($this->_truePrefix === NULL || $this->_truePrefix['expires'] < time()) { + $key = $this->_prefix; + $value = $this->_cache->get($key); + if ($value === FALSE) { + $value = uniqid(); + $this->_cache->set($key, $value, FALSE, 0); // Indefinite. + } + $this->_truePrefix = [ + 'value' => $value, + 'expires' => time() + self::NS_LOCAL_TTL, + ]; + } + return $this->_prefix . $this->_truePrefix['value'] . '/'; } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Memcached.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Memcached.php index e80b1af4b35..546c5b933b9 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Memcached.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Memcached.php @@ -31,11 +31,19 @@ * @copyright CiviCRM LLC (c) 2004-2018 */ class CRM_Utils_Cache_Memcached implements CRM_Utils_Cache_Interface { + + use CRM_Utils_Cache_NaiveMultipleTrait; // TODO Consider native implementation. + const DEFAULT_HOST = 'localhost'; const DEFAULT_PORT = 11211; const DEFAULT_TIMEOUT = 3600; const DEFAULT_PREFIX = ''; - const MAX_KEY_LEN = 62; + const MAX_KEY_LEN = 200; + + /** + * If another process clears namespace, we'll find out in ~5 sec. + */ + const NS_LOCAL_TTL = 5; /** * The host name of the memcached server @@ -76,6 +84,15 @@ class CRM_Utils_Cache_Memcached implements CRM_Utils_Cache_Interface { */ protected $_cache; + /** + * @var NULL|array + * + * This is the effective prefix. It may be bumped up whenever the dataset is flushed. + * + * @see https://github.com/memcached/memcached/wiki/ProgrammingTricks#deleting-by-namespace + */ + protected $_truePrefix = NULL; + /** * Constructor. * @@ -110,29 +127,79 @@ public function __construct($config) { /** * @param $key * @param $value + * @param null|int|\DateInterval $ttl * * @return bool * @throws Exception */ - public function set($key, &$value) { + public function set($key, $value, $ttl = NULL) { + CRM_Utils_Cache::assertValidKey($key); + if (is_int($ttl) && $ttl <= 0) { + return $this->delete($key); + } + $expires = CRM_Utils_Date::convertCacheTtlToExpires($ttl, $this->_timeout); + $key = $this->cleanKey($key); - if (!$this->_cache->set($key, $value, $this->_timeout)) { - CRM_Core_Error::debug('Result Code: ', $this->_cache->getResultMessage()); - CRM_Core_Error::fatal("memcached set failed, wondering why?, $key", $value); + if (!$this->_cache->set($key, serialize($value), $expires)) { + if (PHP_SAPI === 'cli' || (Civi\Core\Container::isContainerBooted() && CRM_Core_Permission::check('view debug output'))) { + throw new CRM_Utils_Cache_CacheException("Memcached::set($key) failed: " . $this->_cache->getResultMessage()); + } + else { + Civi::log()->error("Memcached::set($key) failed: " . $this->_cache->getResultMessage()); + throw new CRM_Utils_Cache_CacheException("Memcached::set($key) failed"); + } return FALSE; + } return TRUE; } /** * @param $key + * @param mixed $default * * @return mixed */ - public function &get($key) { + public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); $key = $this->cleanKey($key); $result = $this->_cache->get($key); - return $result; + switch ($this->_cache->getResultCode()) { + case Memcached::RES_SUCCESS: + return unserialize($result); + + case Memcached::RES_NOTFOUND: + return $default; + + default: + Civi::log()->error("Memcached::get($key) failed: " . $this->_cache->getResultMessage()); + throw new CRM_Utils_Cache_CacheException("Memcached set ($key) failed"); + } + } + + /** + * @param string $key + * + * @return bool + * @throws \Psr\SimpleCache\CacheException + */ + public function has($key) { + CRM_Utils_Cache::assertValidKey($key); + $key = $this->cleanKey($key); + if ($this->_cache->get($key) !== FALSE) { + return TRUE; + } + switch ($this->_cache->getResultCode()) { + case Memcached::RES_NOTFOUND: + return FALSE; + + case Memcached::RES_SUCCESS: + return TRUE; + + default: + Civi::log()->error("Memcached::has($key) failed: " . $this->_cache->getResultMessage()); + throw new CRM_Utils_Cache_CacheException("Memcached set ($key) failed"); + } } /** @@ -141,8 +208,13 @@ public function &get($key) { * @return mixed */ public function delete($key) { + CRM_Utils_Cache::assertValidKey($key); $key = $this->cleanKey($key); - return $this->_cache->delete($key); + if ($this->_cache->delete($key)) { + return TRUE; + } + $code = $this->_cache->getResultCode(); + return ($code == Memcached::RES_DELETED || $code == Memcached::RES_NOTFOUND); } /** @@ -151,20 +223,47 @@ public function delete($key) { * @return mixed|string */ public function cleanKey($key) { - $key = preg_replace('/\s+|\W+/', '_', $this->_prefix . $key); - if (strlen($key) > self::MAX_KEY_LEN) { + $truePrefix = $this->getTruePrefix(); + $maxLen = self::MAX_KEY_LEN - strlen($truePrefix); + $key = preg_replace('/\s+|\W+/', '_', $key); + if (strlen($key) > $maxLen) { $md5Key = md5($key); // this should be 32 characters in length - $subKeyLen = self::MAX_KEY_LEN - 1 - strlen($md5Key); + $subKeyLen = $maxLen - 1 - strlen($md5Key); $key = substr($key, 0, $subKeyLen) . "_" . $md5Key; } - return $key; + return $truePrefix . $key; } /** - * @return mixed + * @return bool */ public function flush() { - return $this->_cache->flush(); + $this->_truePrefix = NULL; + if ($this->_cache->delete($this->_prefix)) { + return TRUE; + } + $code = $this->_cache->getResultCode(); + return ($code == Memcached::RES_DELETED || $code == Memcached::RES_NOTFOUND); + } + + public function clear() { + return $this->flush(); + } + + protected function getTruePrefix() { + if ($this->_truePrefix === NULL || $this->_truePrefix['expires'] < time()) { + $key = $this->_prefix; + $value = $this->_cache->get($key); + if ($this->_cache->getResultCode() === Memcached::RES_NOTFOUND) { + $value = uniqid(); + $this->_cache->add($key, $value, 0); // Indefinite. + } + $this->_truePrefix = [ + 'value' => $value, + 'expires' => time() + self::NS_LOCAL_TTL, + ]; + } + return $this->_prefix . $this->_truePrefix['value'] . '/'; } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NaiveHasTrait.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NaiveHasTrait.php new file mode 100644 index 00000000000..78ecc678876 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NaiveHasTrait.php @@ -0,0 +1,49 @@ +get($key, NULL) === NULL); + $hasDefaultB = ($this->get($key, 123) === 123); + return !($hasDefaultA && $hasDefaultB); + } + +} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NaiveMultipleTrait.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NaiveMultipleTrait.php new file mode 100644 index 00000000000..d7ead9fc94b --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NaiveMultipleTrait.php @@ -0,0 +1,121 @@ + value pairs. Cache keys that do not exist or are stale will have $default as value. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function getMultiple($keys, $default = NULL) { + $this->assertIterable('getMultiple', $keys); + + $result = []; + foreach ($keys as $key) { + $result[$key] = $this->get($key, $default); + } + return $result; + } + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + */ + public function setMultiple($values, $ttl = NULL) { + $this->assertIterable('setMultiple', $values); + + $result = TRUE; + foreach ($values as $key => $value) { + if (is_int($key)) { + $key = (string) $key; + } + $result = $this->set($key, $value, $ttl) || $result; + } + return $result; + } + + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function deleteMultiple($keys) { + $this->assertIterable('deleteMultiple', $keys); + + $result = TRUE; + foreach ($keys as $key) { + $result = $this->delete($key) || $result; + } + return $result; + } + + /** + * @param $keys + * @throws \CRM_Utils_Cache_InvalidArgumentException + */ + private function assertIterable($func, $keys) { + if (!is_array($keys) && !($keys instanceof Traversable)) { + throw new CRM_Utils_Cache_InvalidArgumentException("$func expects iterable input"); + } + } + +} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NoCache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NoCache.php index 66c6b74cff4..3c1d9b94452 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NoCache.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/NoCache.php @@ -32,6 +32,9 @@ */ class CRM_Utils_Cache_NoCache implements CRM_Utils_Cache_Interface { + use CRM_Utils_Cache_NaiveMultipleTrait; // TODO Consider native implementation. + use CRM_Utils_Cache_NaiveHasTrait; // TODO Native implementation + /** * We only need one instance of this object. So we use the singleton * pattern and cache the instance in this variable @@ -54,20 +57,22 @@ public function __construct($config) { /** * @param string $key * @param mixed $value + * @param null|int|\DateInterval $ttl * * @return bool */ - public function set($key, &$value) { + public function set($key, $value, $ttl = NULL) { return FALSE; } /** * @param string $key + * @param mixed $default * * @return null */ - public function get($key) { - return NULL; + public function get($key, $default = NULL) { + return $default; } /** @@ -86,4 +91,8 @@ public function flush() { return FALSE; } + public function clear() { + return $this->flush(); + } + } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Redis.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Redis.php index 07279d530de..ad1d07cd3a3 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Redis.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/Redis.php @@ -33,25 +33,15 @@ * */ class CRM_Utils_Cache_Redis implements CRM_Utils_Cache_Interface { + + use CRM_Utils_Cache_NaiveMultipleTrait; // TODO Consider native implementation. + use CRM_Utils_Cache_NaiveHasTrait; // TODO Native implementation + const DEFAULT_HOST = 'localhost'; const DEFAULT_PORT = 6379; const DEFAULT_TIMEOUT = 3600; const DEFAULT_PREFIX = ''; - /** - * The host name of the redisd server - * - * @var string - */ - protected $_host = self::DEFAULT_HOST; - - /** - * The port on which to connect on - * - * @var int - */ - protected $_port = self::DEFAULT_PORT; - /** * The default timeout to use * @@ -77,6 +67,34 @@ class CRM_Utils_Cache_Redis implements CRM_Utils_Cache_Interface { */ protected $_cache; + /** + * Create a connection. If a connection already exists, re-use it. + * + * @param array $config + * @return Redis + */ + public static function connect($config) { + $host = isset($config['host']) ? $config['host'] : self::DEFAULT_HOST; + $port = isset($config['port']) ? $config['port'] : self::DEFAULT_PORT; + $pass = CRM_Utils_Constant::value('CIVICRM_DB_CACHE_PASSWORD'); // Ugh. + $id = implode(':', ['connect', $host, $port /* $pass is constant */]); + if (!isset(Civi::$statics[__CLASS__][$id])) { + // Ideally, we'd track the connection in the service-container, but the + // cache connection is boot-critical. + $redis = new Redis(); + if (!$redis->connect($host, $port)) { + // dont use fatal here since we can go in an infinite loop + echo 'Could not connect to redisd server'; + CRM_Utils_System::civiExit(); + } + if ($pass) { + $redis->auth($pass); + } + Civi::$statics[__CLASS__][$id] = $redis; + } + return Civi::$statics[__CLASS__][$id]; + } + /** * Constructor * @@ -86,12 +104,6 @@ class CRM_Utils_Cache_Redis implements CRM_Utils_Cache_Interface { * @return \CRM_Utils_Cache_Redis */ public function __construct($config) { - if (isset($config['host'])) { - $this->_host = $config['host']; - } - if (isset($config['port'])) { - $this->_port = $config['port']; - } if (isset($config['timeout'])) { $this->_timeout = $config['timeout']; } @@ -99,25 +111,31 @@ public function __construct($config) { $this->_prefix = $config['prefix']; } - $this->_cache = new Redis(); - if (!$this->_cache->connect($this->_host, $this->_port)) { - // dont use fatal here since we can go in an infinite loop - echo 'Could not connect to redisd server'; - CRM_Utils_System::civiExit(); - } - $this->_cache->auth(CIVICRM_DB_CACHE_PASSWORD); + $this->_cache = self::connect($config); } /** * @param $key * @param $value + * @param null|int|\DateInterval $ttl * * @return bool * @throws Exception */ - public function set($key, &$value) { - if (!$this->_cache->set($this->_prefix . $key, serialize($value), $this->_timeout)) { - CRM_Core_Error::fatal("Redis set failed, wondering why?, $key", $value); + public function set($key, $value, $ttl = NULL) { + CRM_Utils_Cache::assertValidKey($key); + if (is_int($ttl) && $ttl <= 0) { + return $this->delete($key); + } + $ttl = CRM_Utils_Date::convertCacheTtl($ttl, self::DEFAULT_TIMEOUT); + if (!$this->_cache->setex($this->_prefix . $key, $ttl, serialize($value))) { + if (PHP_SAPI === 'cli' || (Civi\Core\Container::isContainerBooted() && CRM_Core_Permission::check('view debug output'))) { + throw new CRM_Utils_Cache_CacheException("Redis set ($key) failed: " . $this->_cache->getLastError()); + } + else { + Civi::log()->error("Redis set ($key) failed: " . $this->_cache->getLastError()); + throw new CRM_Utils_Cache_CacheException("Redis set ($key) failed"); + } return FALSE; } return TRUE; @@ -125,28 +143,42 @@ public function set($key, &$value) { /** * @param $key + * @param mixed $default * * @return mixed */ - public function get($key) { + public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); $result = $this->_cache->get($this->_prefix . $key); - return unserialize($result); + return ($result === FALSE) ? $default : unserialize($result); } /** * @param $key * - * @return mixed + * @return bool */ public function delete($key) { - return $this->_cache->delete($this->_prefix . $key); + CRM_Utils_Cache::assertValidKey($key); + $this->_cache->delete($this->_prefix . $key); + return TRUE; } /** - * @return mixed + * @return bool */ public function flush() { - return $this->_cache->flushDB(); + // FIXME: Ideally, we'd map each prefix to a different 'hash' object in Redis, + // and this would be simpler. However, that needs to go in tandem with a + // more general rethink of cache expiration/TTL. + + $keys = $this->_cache->keys($this->_prefix . '*'); + $this->_cache->del($keys); + return TRUE; + } + + public function clear() { + return $this->flush(); } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SerializeCache.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SerializeCache.php index 6164694c3e5..fdf0eb6d47b 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SerializeCache.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SerializeCache.php @@ -36,6 +36,9 @@ */ class CRM_Utils_Cache_SerializeCache implements CRM_Utils_Cache_Interface { + use CRM_Utils_Cache_NaiveMultipleTrait; + use CRM_Utils_Cache_NaiveHasTrait; // TODO Native implementation + /** * The cache storage container, an array by default, stored in a file under templates */ @@ -67,10 +70,15 @@ public function fileName($key) { /** * @param string $key + * @param mixed $default * * @return mixed */ - public function get($key) { + public function get($key, $default = NULL) { + if ($default !== NULL) { + throw new \RuntimeException("FIXME: " . __CLASS__ . "::get() only supports NULL default"); + } + if (array_key_exists($key, $this->_cache)) { return $this->_cache[$key]; } @@ -85,32 +93,41 @@ public function get($key) { /** * @param string $key * @param mixed $value + * @param null|int|\DateInterval $ttl + * @return bool */ - public function set($key, &$value) { + public function set($key, $value, $ttl = NULL) { + if ($ttl !== NULL) { + throw new \RuntimeException("FIXME: " . __CLASS__ . "::set() should support non-NULL TTL"); + } if (file_exists($this->fileName($key))) { - return; + return FALSE; // WTF, write-once cache?! } $this->_cache[$key] = $value; - file_put_contents($this->fileName($key), "fileName($key), "fileName($key))) { unlink($this->fileName($key)); } unset($this->_cache[$key]); + return TRUE; } /** * @param null $key + * @return bool */ public function flush($key = NULL) { $prefix = "CRM_"; if (!$handle = opendir(CIVICRM_TEMPLATE_COMPILEDIR)) { - return; // die? Error? + return FALSE; // die? Error? } while (FALSE !== ($entry = readdir($handle))) { if (substr($entry, 0, 4) == $prefix) { @@ -120,6 +137,11 @@ public function flush($key = NULL) { closedir($handle); unset($this->_cache); $this->_cache = array(); + return TRUE; + } + + public function clear() { + return $this->flush(); } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SqlGroup.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SqlGroup.php index 6f3f45f7927..beaf5fd1ddb 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SqlGroup.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Cache/SqlGroup.php @@ -38,6 +38,12 @@ */ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface { + // 6*60*60 + const DEFAULT_TTL = 21600; + + const TS_FMT = 'Y-m-d H:i:s'; + use CRM_Utils_Cache_NaiveMultipleTrait; // TODO Consider native implementation. + /** * The host name of the memcached server. * @@ -53,7 +59,18 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface { /** * @var array in-memory cache to optimize redundant get()s */ - protected $frontCache; + protected $valueCache; + + /** + * @var array in-memory cache to optimize redundant get()s + * Note: expiresCache[$key]===NULL means cache-miss + */ + protected $expiresCache; + + /** + * @var string + */ + protected $table; /** * Constructor. @@ -68,6 +85,7 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface { * @return \CRM_Utils_Cache_SqlGroup */ public function __construct($config) { + $this->table = CRM_Core_DAO_Cache::getTableName(); if (isset($config['group'])) { $this->group = $config['group']; } @@ -80,7 +98,7 @@ public function __construct($config) { else { $this->componentID = NULL; } - $this->frontCache = array(); + $this->valueCache = array(); if (CRM_Utils_Array::value('prefetch', $config, TRUE)) { $this->prefetch(); } @@ -89,22 +107,80 @@ public function __construct($config) { /** * @param string $key * @param mixed $value + * @param null|int|\DateInterval $ttl + * @return bool */ - public function set($key, &$value) { - CRM_Core_BAO_Cache::setItem($value, $this->group, $key, $this->componentID); - $this->frontCache[$key] = $value; + public function set($key, $value, $ttl = NULL) { + CRM_Utils_Cache::assertValidKey($key); + + $lock = Civi::lockManager()->acquire("cache.{$this->group}_{$key}._null"); + if (!$lock->isAcquired()) { + throw new \CRM_Utils_Cache_CacheException("SqlGroup: Failed to acquire lock on cache key."); + } + + if (is_int($ttl) && $ttl <= 0) { + return $this->delete($key); + } + + $dataExists = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM {$this->table} WHERE {$this->where($key)}"); + $expires = round(microtime(1)) + CRM_Utils_Date::convertCacheTtl($ttl, self::DEFAULT_TTL); + + $dataSerialized = CRM_Core_BAO_Cache::encode($value); + + // This table has a wonky index, so we cannot use REPLACE or + // "INSERT ... ON DUPE". Instead, use SELECT+(INSERT|UPDATE). + if ($dataExists) { + $sql = "UPDATE {$this->table} SET data = %1, created_date = FROM_UNIXTIME(%2), expired_date = FROM_UNIXTIME(%3) WHERE {$this->where($key)}"; + $args = array( + 1 => array($dataSerialized, 'String'), + 2 => array(time(), 'Positive'), + 3 => array($expires, 'Positive'), + ); + $dao = CRM_Core_DAO::executeQuery($sql, $args, FALSE, NULL, FALSE, FALSE); + } + else { + $sql = "INSERT INTO {$this->table} (group_name,path,data,created_date,expired_date) VALUES (%1,%2,%3,FROM_UNIXTIME(%4),FROM_UNIXTIME(%5))"; + $args = array( + 1 => [$this->group, 'String'], + 2 => [$key, 'String'], + 3 => [$dataSerialized, 'String'], + 4 => [time(), 'Positive'], + 5 => [$expires, 'Positive'], + ); + $dao = CRM_Core_DAO::executeQuery($sql, $args, FALSE, NULL, FALSE, FALSE); + } + + $lock->release(); + + $dao->free(); + + $this->valueCache[$key] = CRM_Core_BAO_Cache::decode($dataSerialized); + $this->expiresCache[$key] = $expires; + return TRUE; } /** * @param string $key + * @param mixed $default * * @return mixed */ - public function get($key) { - if (!array_key_exists($key, $this->frontCache)) { - $this->frontCache[$key] = CRM_Core_BAO_Cache::getItem($this->group, $key, $this->componentID); + public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); + if (!isset($this->expiresCache[$key]) || time() >= $this->expiresCache[$key]) { + $sql = "SELECT path, data, UNIX_TIMESTAMP(expired_date) as expires FROM {$this->table} WHERE " . $this->where($key); + $dao = CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $this->expiresCache[$key] = $dao->expires; + $this->valueCache[$key] = CRM_Core_BAO_Cache::decode($dao->data); + } + $dao->free(); } - return $this->frontCache[$key]; + return (isset($this->expiresCache[$key]) && time() < $this->expiresCache[$key]) ? $this->reobjectify($this->valueCache[$key]) : $default; + } + + private function reobjectify($value) { + return is_object($value) ? unserialize(serialize($value)) : $value; } /** @@ -114,24 +190,60 @@ public function get($key) { * @return mixed */ public function getFromFrontCache($key, $default = NULL) { - return CRM_Utils_Array::value($key, $this->frontCache, $default); + if (isset($this->expiresCache[$key]) && time() < $this->expiresCache[$key] && $this->valueCache[$key]) { + return $this->reobjectify($this->valueCache[$key]); + } + else { + return $default; + } + } + + public function has($key) { + $this->get($key); + return isset($this->expiresCache[$key]) && time() < $this->expiresCache[$key]; } /** * @param string $key + * @return bool */ public function delete($key) { - CRM_Core_BAO_Cache::deleteGroup($this->group, $key); - unset($this->frontCache[$key]); + CRM_Utils_Cache::assertValidKey($key); + CRM_Core_DAO::executeQuery("DELETE FROM {$this->table} WHERE {$this->where($key)}"); + unset($this->valueCache[$key]); + unset($this->expiresCache[$key]); + return TRUE; } public function flush() { - CRM_Core_BAO_Cache::deleteGroup($this->group); - $this->frontCache = array(); + CRM_Core_DAO::executeQuery("DELETE FROM {$this->table} WHERE {$this->where()}"); + $this->valueCache = array(); + $this->expiresCache = array(); + return TRUE; + } + + public function clear() { + return $this->flush(); } public function prefetch() { - $this->frontCache = CRM_Core_BAO_Cache::getItems($this->group, $this->componentID); + $dao = CRM_Core_DAO::executeQuery("SELECT path, data, UNIX_TIMESTAMP(expired_date) AS expires FROM {$this->table} WHERE " . $this->where(NULL)); + $this->valueCache = array(); + $this->expiresCache = array(); + while ($dao->fetch()) { + $this->valueCache[$dao->path] = CRM_Core_BAO_Cache::decode($dao->data); + $this->expiresCache[$dao->path] = $dao->expires; + } + $dao->free(); + } + + protected function where($path = NULL) { + $clauses = array(); + $clauses[] = ('group_name = "' . CRM_Core_DAO::escapeString($this->group) . '"'); + if ($path) { + $clauses[] = ('path = "' . CRM_Core_DAO::escapeString($path) . '"'); + } + return $clauses ? implode(' AND ', $clauses) : '(1)'; } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check.php index 24fd07062a1..57d15a741ff 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check.php @@ -223,7 +223,7 @@ public static function checkAll($max = FALSE) { break; } - Civi::settings()->set('systemStatusCheckResult', $maxSeverity); + Civi::cache('checks')->set('systemStatusCheckResult', $maxSeverity); return ($max) ? $maxSeverity : $messages; } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check/Component/Env.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check/Component/Env.php index df866185edc..a253716e42f 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check/Component/Env.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Check/Component/Env.php @@ -910,7 +910,7 @@ public function checkResourceUrl() { $arrowUrl = CRM_Core_Config::singleton()->userFrameworkResourceURL . 'packages/jquery/css/images/arrow.png'; $headers = get_headers($arrowUrl); $fileExists = stripos($headers[0], "200 OK") ? 1 : 0; - if (!$fileExists) { + if ($fileExists === FALSE) { $messages[] = new CRM_Utils_Check_Message( __FUNCTION__, ts('The Resource URL is not set correctly. Please set the CiviCRM Resource URL.', diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Date.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Date.php index 3d4570d7e19..74aa2e35cae 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Date.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Date.php @@ -695,6 +695,58 @@ public static function isDate(&$date) { return TRUE; } + /** + * Translate a TTL to a concrete expiration time. + * + * @param NULL|int|DateInterval $ttl + * @param int $default + * The value to use if $ttl is not specified (NULL). + * @return int + * Timestamp (seconds since epoch). + * @throws \CRM_Utils_Cache_InvalidArgumentException + */ + public static function convertCacheTtlToExpires($ttl, $default) { + if ($ttl === NULL) { + $ttl = $default; + } + + if (is_int($ttl)) { + return time() + $ttl; + } + elseif ($ttl instanceof DateInterval) { + return date_add(new DateTime(), $ttl)->getTimestamp(); + } + else { + throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache TTL"); + } + } + + /** + * Normalize a TTL. + * + * @param NULL|int|DateInterval $ttl + * @param int $default + * The value to use if $ttl is not specified (NULL). + * @return int + * Seconds until expiration. + * @throws \CRM_Utils_Cache_InvalidArgumentException + */ + public static function convertCacheTtl($ttl, $default) { + if ($ttl === NULL) { + return $default; + } + elseif (is_int($ttl)) { + return $ttl; + } + elseif ($ttl instanceof DateInterval) { + return date_add(new DateTime(), $ttl)->getTimestamp() - time(); + } + else { + throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache TTL"); + } + } + + /** * @param null $timeStamp * diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/DeprecatedUtils.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/DeprecatedUtils.php index 00afe4332eb..7c726a3ee08 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/DeprecatedUtils.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/DeprecatedUtils.php @@ -1268,7 +1268,7 @@ function _civicrm_api3_deprecated_contact_check_params( // @todo switch to using api version // $dupes = civicrm_api3('Contact', 'duplicatecheck', (array('match' => $params, 'dedupe_rule_id' => $dedupeRuleGroupID))); // $ids = $dupes['count'] ? implode(',', array_keys($dupes['values'])) : NULL; - $ids = CRM_Contact_BAO_Contact::getDuplicateContacts($params, $params['contact_type'], 'Unsupervised', array(), CRM_Utils_Array::value('check_permissions', $params, $dedupeRuleGroupID)); + $ids = CRM_Contact_BAO_Contact::getDuplicateContacts($params, $params['contact_type'], 'Unsupervised', array(), CRM_Utils_Array::value('check_permissions', $params), $dedupeRuleGroupID); if ($ids != NULL) { $error = CRM_Core_Error::createError("Found matching contacts: " . implode(',', $ids), CRM_Core_Error::DUPLICATE_CONTACT, diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/GeocodeProvider.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/GeocodeProvider.php index f87c8eac115..e11a2eb67ad 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/GeocodeProvider.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/GeocodeProvider.php @@ -84,7 +84,7 @@ public static function getUsableClassName() { // or extend a base class. While we identify and implement a geocoding // abstraction library (rather than continue to roll our own), we settle for // this check. - if (!method_exists($provider, 'format')) { + if (!method_exists($provider, 'format') && $provider !== FALSE) { Civi::log()->error('Configured geocoder is invalid, must provide a format method', ['geocode_class' => $provider]); $provider = FALSE; } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Hook.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Hook.php index 612a26c67a6..da50eb035d7 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Hook.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Hook.php @@ -2418,4 +2418,57 @@ public static function alterEntityRefParams(&$params, $formName) { ); } + /** + * This hook is called before a scheduled job is executed + * + * @param CRM_Core_DAO_Job $job + * The job to be executed + * @param array $params + * The arguments to be given to the job + */ + public static function preJob($job, $params) { + return self::singleton()->invoke(array('job', 'params'), $job, $params, + self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, + 'civicrm_preJob' + ); + } + + /** + * This hook is called after a scheduled job is executed + * + * @param CRM_Core_DAO_Job $job + * The job that was executed + * @param array $params + * The arguments given to the job + * @param array $result + * The result of the API call, or the thrown exception if any + */ + public static function postJob($job, $params, $result) { + return self::singleton()->invoke(array('job', 'params', 'result'), $job, $params, $result, + self::$_nullObject, self::$_nullObject, self::$_nullObject, + 'civicrm_postJob' + ); + } + + /** + * This hook is called before and after constructing mail recipients. + * Allows user to alter filter and/or search query to fetch mail recipients + * + * @param CRM_Mailing_DAO_Mailing $mailingObject + * @param array $criteria + * A list of SQL criteria; you can add/remove/replace/modify criteria. + * Array(string $name => CRM_Utils_SQL_Select $criterion). + * Ex: array('do_not_email' => CRM_Utils_SQL_Select::fragment()->where("$contact.do_not_email = 0")). + * @param string $context + * Ex: 'pre', 'post' + * @return mixed + */ + public static function alterMailingRecipients(&$mailingObject, &$criteria, $context) { + return self::singleton()->invoke(array('mailingObject', 'params', 'context'), + $mailingObject, $criteria, $context, + self::$_nullObject, self::$_nullObject, self::$_nullObject, + 'civicrm_alterMailingRecipients' + ); + } + } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Migrate/Import.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Migrate/Import.php index 1736130bf0a..dc9e24419ae 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Migrate/Import.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Migrate/Import.php @@ -242,6 +242,15 @@ public function customGroups(&$xml, &$idMap) { elseif (in_array($customGroup->extends, array('Individual', 'Organization', 'Household'))) { $valueIDs = $optionValues; } + elseif (in_array($customGroup->extends, array('Contribution', 'ContributionRecur'))) { + $sql = "SELECT id + FROM civicrm_financial_type + WHERE name IN ('{$optValues}')"; + $dao = &CRM_Core_DAO::executeQuery($sql); + while ($dao->fetch()) { + $valueIDs[] = $dao->id; + } + } else { $sql = " SELECT v.value diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Money.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Money.php index 28ecf6aafe9..59168cb606a 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Money.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Money.php @@ -154,4 +154,36 @@ public static function subtractCurrencies($leftOp, $rightOp, $currency) { } } + /** + * Tests if two currency values are equal, taking into account the currency's + * precision, so that if the difference between the two values is less than + * one more order of magnitude for the precision, then the values are + * considered as equal. So, if the currency has precision of 2 decimal + * points, a difference of more than 0.001 will cause the values to be + * considered as different. Anything less than 0.001 will be considered as + * equal. + * + * Eg. + * + * 1.2312 == 1.2319 with a currency precision of 2 decimal points + * 1.2310 != 1.2320 with a currency precision of 2 decimal points + * 1.3000 != 1.2000 with a currency precision of 2 decimal points + * + * @param $value1 + * @param $value2 + * @param $currency + * + * @return bool + */ + public static function equals($value1, $value2, $currency) { + $precision = 1 / pow(10, self::getCurrencyPrecision($currency) + 1); + $difference = self::subtractCurrencies($value1, $value2, $currency); + + if (abs($difference) > $precision) { + return FALSE; + } + + return TRUE; + } + } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/ReCAPTCHA.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/ReCAPTCHA.php index de4021bb1f9..80861599309 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/ReCAPTCHA.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/ReCAPTCHA.php @@ -62,6 +62,29 @@ public static function &singleton() { return self::$_singleton; } + + /** + * Check if reCaptcha settings is avilable to add on form. + */ + public static function hasSettingsAvailable() { + $config = CRM_Core_Config::singleton(); + if ($config->recaptchaPublicKey == NULL || $config->recaptchaPublicKey == "") { + return FALSE; + } + return TRUE; + } + + /** + * Check if reCaptcha has to be added on form forcefully. + */ + public static function hasToAddForcefully() { + $config = CRM_Core_Config::singleton(); + if (!$config->forceRecaptcha) { + return FALSE; + } + return TRUE; + } + /** * Add element to form. * diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Rule.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Rule.php index 61a467451fd..2bc78c243e2 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Rule.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/Rule.php @@ -157,7 +157,7 @@ public static function mysqlOrderBy($str) { // at all, so we split and loop over. $parts = explode(',', $str); foreach ($parts as $part) { - if (!preg_match('/^((`[\w-]{1,64}`|[\w-]{1,64})\.)?(`[\w-]{1,64}`|[\w-]{1,64})( (asc|desc))?$/i', trim($part))) { + if (!preg_match('/^((`[\w-]{1,64}`|[\w-]{1,64})\.)*(`[\w-]{1,64}`|[\w-]{1,64})( (asc|desc))?$/i', trim($part))) { return FALSE; } } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/BaseParamQuery.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/BaseParamQuery.php new file mode 100644 index 00000000000..82fb91cfc36 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/BaseParamQuery.php @@ -0,0 +1,232 @@ +strict = $strict; + return $this; + } + + /** + * Given a string like "field_name = @value", replace "@value" with an escaped SQL string + * + * @param string $expr SQL expression + * @param null|array $args a list of values to insert into the SQL expression; keys are prefix-coded: + * prefix '@' => escape SQL + * prefix '#' => literal number, skip escaping but do validation + * prefix '!' => literal, skip escaping and validation + * if a value is an array, then it will be imploded + * + * PHP NULL's will be treated as SQL NULL's. The PHP string "null" will be treated as a string. + * + * @param string $activeMode + * + * @return string + */ + public function interpolate($expr, $args, $activeMode = self::INTERPOLATE_INPUT) { + if ($args === NULL) { + return $expr; + } + else { + if ($this->mode === self::INTERPOLATE_AUTO) { + $this->mode = $activeMode; + } + elseif ($activeMode !== $this->mode) { + throw new RuntimeException("Cannot mix interpolation modes."); + } + + $select = $this; + return preg_replace_callback('/([#!@])([a-zA-Z0-9_]+)/', function($m) use ($select, $args) { + if (isset($args[$m[2]])) { + $values = $args[$m[2]]; + } + elseif (isset($args[$m[1] . $m[2]])) { + // Backward compat. Keys in $args look like "#myNumber" or "@myString". + $values = $args[$m[1] . $m[2]]; + } + elseif ($select->strict) { + throw new CRM_Core_Exception('Cannot build query. Variable "' . $m[1] . $m[2] . '" is unknown.'); + } + else { + // Unrecognized variables are ignored. Mitigate risk of accidents. + return $m[0]; + } + $values = is_array($values) ? $values : array($values); + switch ($m[1]) { + case '@': + $parts = array_map(array($select, 'escapeString'), $values); + return implode(', ', $parts); + + // TODO: ensure all uses of this un-escaped literal are safe + case '!': + return implode(', ', $values); + + case '#': + foreach ($values as $valueKey => $value) { + if ($value === NULL) { + $values[$valueKey] = 'NULL'; + } + elseif (!is_numeric($value)) { + //throw new API_Exception("Failed encoding non-numeric value" . var_export(array($m[0] => $values), TRUE)); + throw new CRM_Core_Exception("Failed encoding non-numeric value (" . $m[0] . ")"); + } + } + return implode(', ', $values); + + default: + throw new CRM_Core_Exception("Unrecognized prefix"); + } + }, $expr); + } + } + + /** + * @param string|NULL $value + * @return string + * SQL expression, e.g. "it\'s great" (with-quotes) or NULL (without-quotes) + */ + public function escapeString($value) { + return $value === NULL ? 'NULL' : '"' . CRM_Core_DAO::escapeString($value) . '"'; + } + + /** + * Set one (or multiple) parameters to interpolate into the query. + * + * @param array|string $keys + * Key name, or an array of key-value pairs. + * @param null|mixed $value + * The new value of the parameter. + * Values may be strings, ints, or arrays thereof -- provided that the + * SQL query uses appropriate prefix (e.g. "@", "!", "#"). + * @return $this + */ + public function param($keys, $value = NULL) { + if ($this->mode === self::INTERPOLATE_AUTO) { + $this->mode = self::INTERPOLATE_OUTPUT; + } + elseif ($this->mode !== self::INTERPOLATE_OUTPUT) { + throw new RuntimeException("Select::param() only makes sense when interpolating on output."); + } + + if (is_array($keys)) { + foreach ($keys as $k => $v) { + $this->params[$k] = $v; + } + } + else { + $this->params[$keys] = $value; + } + return $this; + } + + /** + * Has an offset been set. + * + * @param string $offset + * + * @return bool + */ + public function offsetExists($offset) { + return isset($this->params[$offset]); + } + + /** + * Get the value of a SQL parameter. + * + * @code + * $select['cid'] = 123; + * $select->where('contact.id = #cid'); + * echo $select['cid']; + * @endCode + * + * @param string $offset + * @return mixed + * @see param() + * @see ArrayAccess::offsetGet + */ + public function offsetGet($offset) { + return $this->params[$offset]; + } + + /** + * Set the value of a SQL parameter. + * + * @code + * $select['cid'] = 123; + * $select->where('contact.id = #cid'); + * echo $select['cid']; + * @endCode + * + * @param string $offset + * @param mixed $value + * The new value of the parameter. + * Values may be strings, ints, or arrays thereof -- provided that the + * SQL query uses appropriate prefix (e.g. "@", "!", "#"). + * @see param() + * @see ArrayAccess::offsetSet + */ + public function offsetSet($offset, $value) { + $this->param($offset, $value); + } + + /** + * Unset the value of a SQL parameter. + * + * @param string $offset + * @see param() + * @see ArrayAccess::offsetUnset + */ + public function offsetUnset($offset) { + unset($this->params[$offset]); + } + +} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Delete.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Delete.php new file mode 100644 index 00000000000..b646d3b3e20 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Delete.php @@ -0,0 +1,269 @@ +where('activity_type_id = #type', array('type' => 234)) + * ->where('status_id IN (#statuses)', array('statuses' => array(1,2,3)) + * ->where('subject like @subj', array('subj' => '%hello%')) + * ->where('!dynamicColumn = 1', array('dynamicColumn' => 'coalesce(is_active,0)')) + * ->where('!column = @value', array( + * 'column' => $customField->column_name, + * 'value' => $form['foo'] + * )) + * echo $del->toSQL(); + * @endcode + * + * Design principles: + * - Portable + * - No knowledge of the underlying SQL API (except for escaping -- CRM_Core_DAO::escapeString) + * - No knowledge of the underlying data model + * - SQL clauses correspond to PHP functions ($select->where("foo_id=123")) + * - Variable escaping is concise and controllable based on prefixes, eg + * - similar to Drupal's t() + * - use "@varname" to insert the escaped value + * - use "!varname" to insert raw (unescaped) values + * - use "#varname" to insert a numerical value (these are validated but not escaped) + * - to disable any preprocessing, simply omit the variable list + * - control characters (@!#) are mandatory in expressions but optional in arg-keys + * - Variables may be individual values or arrays; arrays are imploded with commas + * - Conditionals are AND'd; if you need OR's, do it yourself + * - Use classes/functions with documentation (rather than undocumented array-trees) + * - For any given string, interpolation is only performed once. After an interpolation, + * a string may never again be subjected to interpolation. + * + * The "interpolate-once" principle can be enforced by either interpolating on input + * xor output. The notations for input and output interpolation are a bit different, + * and they may not be mixed. + * + * @code + * // Interpolate on input. Set params when using them. + * $select->where('activity_type_id = #type', array( + * 'type' => 234, + * )); + * + * // Interpolate on output. Set params independently. + * $select + * ->where('activity_type_id = #type') + * ->param('type', 234), + * @endcode + * + * @package CRM + * @copyright CiviCRM LLC (c) 2004-2018 + */ +class CRM_Utils_SQL_Delete extends CRM_Utils_SQL_BaseParamQuery { + + private $from; + private $wheres = array(); + + /** + * Create a new DELETE query. + * + * @param string $from + * Table-name and optional alias. + * @param array $options + * @return CRM_Utils_SQL_Delete + */ + public static function from($from, $options = array()) { + return new self($from, $options); + } + + /** + * Create a new DELETE query. + * + * @param string $from + * Table-name and optional alias. + * @param array $options + */ + public function __construct($from, $options = array()) { + $this->from = $from; + $this->mode = isset($options['mode']) ? $options['mode'] : self::INTERPOLATE_AUTO; + } + + /** + * Make a new copy of this query. + * + * @return CRM_Utils_SQL_Delete + */ + public function copy() { + return clone $this; + } + + /** + * Merge something or other. + * + * @param CRM_Utils_SQL_Delete $other + * @param array|NULL $parts + * ex: 'wheres' + * @return CRM_Utils_SQL_Delete + */ + public function merge($other, $parts = NULL) { + if ($other === NULL) { + return $this; + } + + if ($this->mode === self::INTERPOLATE_AUTO) { + $this->mode = $other->mode; + } + elseif ($other->mode === self::INTERPOLATE_AUTO) { + // Noop. + } + elseif ($this->mode !== $other->mode) { + // Mixing modes will lead to someone getting an expected substitution. + throw new RuntimeException("Cannot merge queries that use different interpolation modes ({$this->mode} vs {$other->mode})."); + } + + $arrayFields = array('wheres', 'params'); + foreach ($arrayFields as $f) { + if ($parts === NULL || in_array($f, $parts)) { + $this->{$f} = array_merge($this->{$f}, $other->{$f}); + } + } + + $flatFields = array('from'); + foreach ($flatFields as $f) { + if ($parts === NULL || in_array($f, $parts)) { + if ($other->{$f} !== NULL) { + $this->{$f} = $other->{$f}; + } + } + } + + return $this; + } + + /** + * Limit results by adding extra condition(s) to the WHERE clause + * + * @param string|array $exprs list of SQL expressions + * @param null|array $args use NULL to disable interpolation; use an array of variables to enable + * @return CRM_Utils_SQL_Delete + */ + public function where($exprs, $args = NULL) { + $exprs = (array) $exprs; + foreach ($exprs as $expr) { + $evaluatedExpr = $this->interpolate($expr, $args); + $this->wheres[$evaluatedExpr] = $evaluatedExpr; + } + return $this; + } + + /** + * Set one (or multiple) parameters to interpolate into the query. + * + * @param array|string $keys + * Key name, or an array of key-value pairs. + * @param null|mixed $value + * The new value of the parameter. + * Values may be strings, ints, or arrays thereof -- provided that the + * SQL query uses appropriate prefix (e.g. "@", "!", "#"). + * @return \CRM_Utils_SQL_Delete + */ + public function param($keys, $value = NULL) { + // Why bother with an override? To provide better type-hinting in `@return`. + return parent::param($keys, $value); + } + + /** + * @param array|NULL $parts + * List of fields to check (e.g. 'wheres'). + * Defaults to all. + * @return bool + */ + public function isEmpty($parts = NULL) { + $empty = TRUE; + $fields = array( + 'from', + 'wheres', + ); + if ($parts !== NULL) { + $fields = array_intersect($fields, $parts); + } + foreach ($fields as $field) { + if (!empty($this->{$field})) { + $empty = FALSE; + } + } + return $empty; + } + + /** + * @return string + * SQL statement + */ + public function toSQL() { + $sql = 'DELETE '; + + if ($this->from !== NULL) { + $sql .= 'FROM ' . $this->from . "\n"; + } + if ($this->wheres) { + $sql .= 'WHERE (' . implode(') AND (', $this->wheres) . ")\n"; + } + if ($this->mode === self::INTERPOLATE_OUTPUT) { + $sql = $this->interpolate($sql, $this->params, self::INTERPOLATE_OUTPUT); + } + return $sql; + } + + /** + * Execute the query. + * + * To examine the results, use a function like `fetch()`, `fetchAll()`, + * `fetchValue()`, or `fetchMap()`. + * + * @param string|NULL $daoName + * The return object should be an instance of this class. + * Ex: 'CRM_Contact_BAO_Contact'. + * @param bool $i18nRewrite + * If the system has multilingual features, should the field/table + * names be rewritten? + * @return CRM_Core_DAO + * @see CRM_Core_DAO::executeQuery + * @see CRM_Core_I18n_Schema::rewriteQuery + */ + public function execute($daoName = NULL, $i18nRewrite = TRUE) { + // Don't pass through $params. toSQL() handles interpolation. + $params = array(); + + // Don't pass through $abort, $trapException. Just use straight-up exceptions. + $abort = TRUE; + $trapException = FALSE; + $errorScope = CRM_Core_TemporaryErrorScope::useException(); + + // Don't pass through freeDAO. You can do it yourself. + $freeDAO = FALSE; + + return CRM_Core_DAO::executeQuery($this->toSQL(), $params, $abort, $daoName, + $freeDAO, $i18nRewrite, $trapException); + } + +} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Select.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Select.php index 23adc513d4b..e53df900418 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Select.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/Select.php @@ -47,7 +47,6 @@ * - Portable * - No knowledge of the underlying SQL API (except for escaping -- CRM_Core_DAO::escapeString) * - No knowledge of the underlying data model - * - Single file * - SQL clauses correspond to PHP functions ($select->where("foo_id=123")) * - Variable escaping is concise and controllable based on prefixes, eg * - similar to Drupal's t() @@ -81,38 +80,8 @@ * @package CRM * @copyright CiviCRM LLC (c) 2004-2018 */ -class CRM_Utils_SQL_Select implements ArrayAccess { +class CRM_Utils_SQL_Select extends CRM_Utils_SQL_BaseParamQuery { - /** - * Interpolate values as soon as they are passed in (where(), join(), etc). - * - * Default. - * - * Pro: Every clause has its own unique namespace for parameters. - * Con: Probably slower. - * Advice: Use this when aggregating SQL fragments from agents who - * maintained by different parties. - */ - const INTERPOLATE_INPUT = 'in'; - - /** - * Interpolate values when rendering SQL output (toSQL()). - * - * Pro: Probably faster. - * Con: Must maintain an aggregated list of all parameters. - * Advice: Use this when you have control over the entire query. - */ - const INTERPOLATE_OUTPUT = 'out'; - - /** - * Determine mode automatically. When the first attempt is made - * to use input-interpolation (eg `where(..., array(...))`) or - * output-interpolation (eg `param(...)`), the mode will be - * set. Subsequent calls will be validated using the same mode. - */ - const INTERPOLATE_AUTO = 'auto'; - - private $mode = NULL; private $insertInto = NULL; private $insertVerb = 'INSERT INTO '; private $insertIntoFields = array(); @@ -125,12 +94,8 @@ class CRM_Utils_SQL_Select implements ArrayAccess { private $orderBys = array(); private $limit = NULL; private $offset = NULL; - private $params = array(); private $distinct = NULL; - // Public to work-around PHP 5.3 limit. - public $strict = NULL; - /** * Create a new SELECT query. * @@ -177,7 +142,7 @@ public function copy() { /** * Merge something or other. * - * @param CRM_Utils_SQL_Select $other + * @param array|CRM_Utils_SQL_Select $other * @param array|NULL $parts * ex: 'joins', 'wheres' * @return CRM_Utils_SQL_Select @@ -187,6 +152,13 @@ public function merge($other, $parts = NULL) { return $this; } + if (is_array($other)) { + foreach ($other as $fragment) { + $this->merge($fragment, $parts); + } + return $this; + } + if ($this->mode === self::INTERPOLATE_AUTO) { $this->mode = $other->mode; } @@ -349,22 +321,8 @@ public function orderBy($exprs, $args = NULL, $weight = 0) { * @return \CRM_Utils_SQL_Select */ public function param($keys, $value = NULL) { - if ($this->mode === self::INTERPOLATE_AUTO) { - $this->mode = self::INTERPOLATE_OUTPUT; - } - elseif ($this->mode !== self::INTERPOLATE_OUTPUT) { - throw new RuntimeException("Select::param() only makes sense when interpolating on output."); - } - - if (is_array($keys)) { - foreach ($keys as $k => $v) { - $this->params[$k] = $v; - } - } - else { - $this->params[$keys] = $value; - } - return $this; + // Why bother with an override? To provide bett er type-hinting in `@return`. + return parent::param($keys, $value); } /** @@ -477,101 +435,6 @@ public function isEmpty($parts = NULL) { return $empty; } - /** - * Enable (or disable) strict mode. - * - * In strict mode, unknown variables will generate exceptions. - * - * @param bool $strict - * @return CRM_Utils_SQL_Select - */ - public function strict($strict = TRUE) { - $this->strict = $strict; - return $this; - } - - /** - * Given a string like "field_name = @value", replace "@value" with an escaped SQL string - * - * @param string $expr SQL expression - * @param null|array $args a list of values to insert into the SQL expression; keys are prefix-coded: - * prefix '@' => escape SQL - * prefix '#' => literal number, skip escaping but do validation - * prefix '!' => literal, skip escaping and validation - * if a value is an array, then it will be imploded - * - * PHP NULL's will be treated as SQL NULL's. The PHP string "null" will be treated as a string. - * - * @param string $activeMode - * - * @return string - */ - public function interpolate($expr, $args, $activeMode = self::INTERPOLATE_INPUT) { - if ($args === NULL) { - return $expr; - } - else { - if ($this->mode === self::INTERPOLATE_AUTO) { - $this->mode = $activeMode; - } - elseif ($activeMode !== $this->mode) { - throw new RuntimeException("Cannot mix interpolation modes."); - } - - $select = $this; - return preg_replace_callback('/([#!@])([a-zA-Z0-9_]+)/', function($m) use ($select, $args) { - if (isset($args[$m[2]])) { - $values = $args[$m[2]]; - } - elseif (isset($args[$m[1] . $m[2]])) { - // Backward compat. Keys in $args look like "#myNumber" or "@myString". - $values = $args[$m[1] . $m[2]]; - } - elseif ($select->strict) { - throw new CRM_Core_Exception('Cannot build query. Variable "' . $m[1] . $m[2] . '" is unknown.'); - } - else { - // Unrecognized variables are ignored. Mitigate risk of accidents. - return $m[0]; - } - $values = is_array($values) ? $values : array($values); - switch ($m[1]) { - case '@': - $parts = array_map(array($select, 'escapeString'), $values); - return implode(', ', $parts); - - // TODO: ensure all uses of this un-escaped literal are safe - case '!': - return implode(', ', $values); - - case '#': - foreach ($values as $valueKey => $value) { - if ($value === NULL) { - $values[$valueKey] = 'NULL'; - } - elseif (!is_numeric($value)) { - //throw new API_Exception("Failed encoding non-numeric value" . var_export(array($m[0] => $values), TRUE)); - throw new CRM_Core_Exception("Failed encoding non-numeric value (" . $m[0] . ")"); - } - } - return implode(', ', $values); - - default: - throw new CRM_Core_Exception("Unrecognized prefix"); - } - }, $expr); - } - } - - /** - * @param string|NULL $value - * @return string - * SQL expression, e.g. "it\'s great" (with-quotes) or NULL (without-quotes) - */ - public function escapeString($value) { - return $value === NULL ? 'NULL' : '"' . CRM_Core_DAO::escapeString($value) . '"'; - } - /** * @return string * SQL statement @@ -655,65 +518,4 @@ public function execute($daoName = NULL, $i18nRewrite = TRUE) { $freeDAO, $i18nRewrite, $trapException); } - /** - * Has an offset been set. - * - * @param string $offset - * - * @return bool - */ - public function offsetExists($offset) { - return isset($this->params[$offset]); - } - - /** - * Get the value of a SQL parameter. - * - * @code - * $select['cid'] = 123; - * $select->where('contact.id = #cid'); - * echo $select['cid']; - * @endCode - * - * @param string $offset - * @return mixed - * @see param() - * @see ArrayAccess::offsetGet - */ - public function offsetGet($offset) { - return $this->params[$offset]; - } - - /** - * Set the value of a SQL parameter. - * - * @code - * $select['cid'] = 123; - * $select->where('contact.id = #cid'); - * echo $select['cid']; - * @endCode - * - * @param string $offset - * @param mixed $value - * The new value of the parameter. - * Values may be strings, ints, or arrays thereof -- provided that the - * SQL query uses appropriate prefix (e.g. "@", "!", "#"). - * @see param() - * @see ArrayAccess::offsetSet - */ - public function offsetSet($offset, $value) { - $this->param($offset, $value); - } - - /** - * Unset the value of a SQL parameter. - * - * @param string $offset - * @see param() - * @see ArrayAccess::offsetUnset - */ - public function offsetUnset($offset) { - unset($this->params[$offset]); - } - } diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/TempTable.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/TempTable.php new file mode 100644 index 00000000000..cedc46c8162 --- /dev/null +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/SQL/TempTable.php @@ -0,0 +1,272 @@ +getName(); + * $name = CRM_Utils_SQL_TempTable::build()->setDurable()->getName(); + * $name = CRM_Utils_SQL_TempTable::build()->setCategory('contactstats')->setId($contact['id'])->getName(); + * + * Example 2: Create a temp table using the results of a SELECT query. + * + * $tmpTbl = CRM_Utils_SQL_TempTable::build()->createWithQuery('SELECT id, display_name FROM civicrm_contact'); + * $tmpTbl = CRM_Utils_SQL_TempTable::build()->createWithQuery(CRM_Utils_SQL_Select::from('civicrm_contact')->select('display_name')); + * + * Example 3: Create an empty temp table with list of columns. + * + * $tmpTbl = CRM_Utils_SQL_TempTable::build()->setDurable()->setUtf8()->createWithColumns('id int(10, name varchar(64)'); + * + * Example 4: Drop a table that you previously created. + * + * $tmpTbl->drop(); + * + * Example 5: Auto-drop a temp table when $tmpTbl falls out of scope + * + * $tmpTbl->setAutodrop(); + * + */ +class CRM_Utils_SQL_TempTable { + + const UTF8 = 'DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci'; + const CATEGORY_LENGTH = 12; + const CATEGORY_REGEXP = ';^[a-zA-Z0-9]+$;'; + const ID_LENGTH = 37; // MAX{64} - CATEGORY_LENGTH{12} - CONST_LENGHTH{15} = 37 + const ID_REGEXP = ';^[a-zA-Z0-9_]+$;'; + + /** + * @var bool + */ + protected $durable, $utf8; + + protected $category; + + protected $id; + + protected $autodrop; + + /** + * @return CRM_Utils_SQL_TempTable + */ + public static function build() { + $t = new CRM_Utils_SQL_TempTable(); + $t->category = NULL; + $t->id = md5(uniqid('', TRUE)); + // The constant CIVICRM_TEMP_FORCE_DURABLE is for local debugging. + $t->durable = CRM_Utils_Constant::value('CIVICRM_TEMP_FORCE_DURABLE', FALSE); + // I suspect it would be better to just say utf8=true, but a lot of existing queries don't do the utf8 bit. + $t->utf8 = CRM_Utils_Constant::value('CIVICRM_TEMP_FORCE_UTF8', FALSE); + $t->autodrop = FALSE; + return $t; + } + + public function __destruct() { + if ($this->autodrop) { + $this->drop(); + } + } + + /** + * Determine the full table name. + * + * @return string + * Ex: 'civicrm_tmp_d_foo_abcd1234abcd1234' + */ + public function getName() { + $parts = ['civicrm', 'tmp']; + $parts[] = ($this->durable ? 'd' : 'e'); + $parts[] = $this->category ? $this->category : 'dflt'; + $parts[] = $this->id ? $this->id : 'dflt'; + return implode('_', $parts); + } + + /** + * Create the table using results from a SELECT query. + * + * @param string|CRM_Utils_SQL_Select $selectQuery + * @return CRM_Utils_SQL_TempTable + */ + public function createWithQuery($selectQuery) { + $sql = sprintf('%s %s AS %s', + $this->toSQL('CREATE'), + $this->utf8 ? self::UTF8 : '', + ($selectQuery instanceof CRM_Utils_SQL_Select ? $selectQuery->toSQL() : $selectQuery) + ); + CRM_Core_DAO::executeQuery($sql, array(), TRUE, NULL, TRUE, FALSE); + return $this; + } + + /** + * Create the empty table. + * + * @parma string $columns + * SQL column listing. + * Ex: 'id int(10), name varchar(64)'. + * @return CRM_Utils_SQL_TempTable + */ + public function createWithColumns($columns) { + $sql = sprintf('%s (%s) %s', + $this->toSQL('CREATE'), + $columns, + $this->utf8 ? self::UTF8 : '' + ); + CRM_Core_DAO::executeQuery($sql, array(), TRUE, NULL, TRUE, FALSE); + return $this; + } + + /** + * Drop the table. + * + * @return CRM_Utils_SQL_TempTable + */ + public function drop() { + $sql = $this->toSQL('DROP', 'IF EXISTS'); + CRM_Core_DAO::executeQuery($sql, array(), TRUE, NULL, TRUE, FALSE); + return $this; + } + + /** + * @param string $action + * Ex: 'CREATE', 'DROP' + * @param string|NULL $ifne + * Ex: 'IF EXISTS', 'IF NOT EXISTS'. + * @return string + * Ex: 'CREATE TEMPORARY TABLE `civicrm_tmp_e_foo_abcd1234`' + * Ex: 'CREATE TABLE IF NOT EXISTS `civicrm_tmp_d_foo_abcd1234`' + */ + private function toSQL($action, $ifne = NULL) { + $parts = []; + $parts[] = $action; + if (!$this->durable) { + $parts[] = 'TEMPORARY'; + } + $parts[] = 'TABLE'; + if ($ifne) { + $parts[] = $ifne; + } + $parts[] = '`' . $this->getName() . '`'; + return implode(' ', $parts); + } + + /** + * @return string|NULL + */ + public function getCategory() { + return $this->category; + } + + /** + * @return string|NULL + */ + public function getId() { + return $this->id; + } + + /** + * @return bool + */ + public function isAutodrop() { + return $this->autodrop; + } + + /** + * @return bool + */ + public function isDurable() { + return $this->durable; + } + + /** + * @return bool + */ + public function isUtf8() { + return $this->utf8; + } + + /** + * @param bool $autodrop + * @return CRM_Utils_SQL_TempTable + */ + public function setAutodrop($autodrop = TRUE) { + $this->autodrop = $autodrop; + return $this; + } + + /** + * @param string|NULL $category + * @return CRM_Utils_SQL_TempTable + */ + public function setCategory($category) { + if ($category && !preg_match(self::CATEGORY_REGEXP, $category) || strlen($category) > self::CATEGORY_LENGTH) { + throw new \RuntimeException("Malformed temp table category"); + } + $this->category = $category; + return $this; + } + + /** + * @parma bool $value + * @return CRM_Utils_SQL_TempTable + */ + public function setDurable($durable = TRUE) { + $this->durable = $durable; + return $this; + } + + /** + * @param mixed $id + * @return CRM_Utils_SQL_TempTable + */ + public function setId($id) { + if ($id && !preg_match(self::ID_REGEXP, $id) || strlen($id) > self::ID_LENGTH) { + throw new \RuntimeException("Malformed temp table id"); + } + $this->id = $id; + return $this; + } + + public function setUtf8($value = TRUE) { + $this->utf8 = $value; + return $this; + } + +} diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System.php index e2d72f53032..fb5bb879ea4 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System.php @@ -1416,8 +1416,21 @@ public static function civiExit($status = 0) { public static function flushCache() { // flush out all cache entries so we can reload new data // a bit aggressive, but livable for now - $cache = CRM_Utils_Cache::singleton(); - $cache->flush(); + CRM_Utils_Cache::singleton()->flush(); + + // Traditionally, systems running on memory-backed caches were quite + // zealous about destroying *all* memory-backed caches during a flush(). + // These flushes simulate that legacy behavior. However, they should probably + // be removed at some point. + $localDrivers = ['CRM_Utils_Cache_Arraycache', 'CRM_Utils_Cache_NoCache']; + if (Civi\Core\Container::isContainerBooted() + && !in_array(get_class(CRM_Utils_Cache::singleton()), $localDrivers)) { + Civi::cache('settings')->flush(); + Civi::cache('js_strings')->flush(); + Civi::cache('community_messages')->flush(); + CRM_Extension_System::singleton()->getCache()->flush(); + CRM_Cxn_CiviCxnHttp::singleton()->getCache()->flush(); + } // also reset the various static memory caches diff --git a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System/Drupal8.php b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System/Drupal8.php index 499a1431a87..1413f2bd7b9 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System/Drupal8.php +++ b/profiles/civicrm_starterkit/modules/civicrm/CRM/Utils/System/Drupal8.php @@ -422,7 +422,7 @@ public function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = chdir($root); // Create a mock $request object - $autoloader = require_once $root . '/vendor/autoload.php'; + $autoloader = require_once $root . '/autoload.php'; if ($autoloader === TRUE) { $autoloader = ComposerAutoloaderInitDrupal8::getLoader(); } diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi.php b/profiles/civicrm_starterkit/modules/civicrm/Civi.php index ae5dc6f4b1d..8acfdba7686 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi.php @@ -26,20 +26,15 @@ class Civi { public static $statics = array(); /** - * EXPERIMENTAL. Retrieve a named cache instance. - * - * This interface is flagged as experimental due to political - * ambiguity in PHP community -- PHP-FIG has an open but - * somewhat controversial draft standard for caching. Based on - * the current draft, it's expected that this function could - * simultaneously support both CRM_Utils_Cache_Interface and - * PSR-6, but that depends on whether PSR-6 changes any more. + * Retrieve a named cache instance. * * @param string $name * The name of the cache. The 'default' cache is biased toward * high-performance caches (eg memcache/redis/apc) when * available and falls back to single-request (static) caching. * @return CRM_Utils_Cache_Interface + * NOTE: Beginning in CiviCRM v5.4, the cache instance complies with + * PSR-16 (\Psr\SimpleCache\CacheInterface). */ public static function cache($name = 'default') { return \Civi\Core\Container::singleton()->get('cache.' . $name); diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Angular/Manager.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Angular/Manager.php index 62d896e2f8f..61f36af0eeb 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Angular/Manager.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Angular/Manager.php @@ -246,7 +246,7 @@ public function getRawPartials($name) { * Invalid partials configuration. */ public function getPartials($name) { - $cacheKey = "angular-partials::$name"; + $cacheKey = "angular-partials_$name"; $cacheValue = $this->cache->get($cacheKey); if ($cacheValue === NULL) { $cacheValue = ChangeSet::applyResourceFilters($this->getChangeSets(), 'partials', $this->getRawPartials($name)); diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/Container.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/Container.php index ffe1bfbe3bc..6eb4a4d66a9 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/Container.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/Container.php @@ -65,7 +65,7 @@ public function loadContainer() { // services. Consequently, we assume a minimal service available -- the classloader // has been setup, and civicrm.settings.php is loaded, but nothing else works. - $cacheMode = defined('CIVICRM_CONTAINER_CACHE') ? CIVICRM_CONTAINER_CACHE : 'always'; + $cacheMode = defined('CIVICRM_CONTAINER_CACHE') ? CIVICRM_CONTAINER_CACHE : 'auto'; // In pre-installation environments, don't bother with caching. if (!defined('CIVICRM_TEMPLATE_COMPILEDIR') || !defined('CIVICRM_DSN') || $cacheMode === 'never' || \CRM_Utils_System::isInUpgradeMode()) { @@ -160,12 +160,18 @@ public function createContainer() { $container->setDefinition('psr_log', new Definition('CRM_Core_Error_Log', array())); - foreach (array('js_strings', 'community_messages') as $cacheName) { - $container->setDefinition("cache.{$cacheName}", new Definition( + $basicCaches = array( + 'js_strings' => 'js_strings', + 'community_messages' => 'community_messages', + 'checks' => 'checks', + 'session' => 'CiviCRM Session', + ); + foreach ($basicCaches as $cacheSvc => $cacheGrp) { + $container->setDefinition("cache.{$cacheSvc}", new Definition( 'CRM_Utils_Cache_Interface', array( array( - 'name' => $cacheName, + 'name' => $cacheGrp, 'type' => array('*memory*', 'SqlGroup', 'ArrayCache'), ), ) @@ -208,6 +214,16 @@ public function createContainer() { ->setFactory(array($class, 'singleton')); } + $container->setDefinition('prevnext', new Definition( + 'CRM_Core_PrevNextCache_Interface', + [new Reference('service_container')] + ))->setFactory(array(new Reference(self::SELF), 'createPrevNextCache')); + + $container->setDefinition('prevnext.driver.sql', new Definition( + 'CRM_Core_PrevNextCache_Sql', + [] + )); + $container->setDefinition('civi.mailing.triggers', new Definition( 'Civi\Core\SqlTrigger\TimestampTriggers', array('civicrm_mailing', 'Mailing') @@ -393,6 +409,18 @@ public function createApiKernel($dispatcher, $magicFunctionProvider) { return $kernel; } + /** + * @param ContainerInterface $container + * @return \CRM_Core_PrevNextCache_Interface + */ + public static function createPrevNextCache($container) { + $cacheDriver = \CRM_Utils_Cache::getCacheDriver(); + $service = 'prevnext.driver.' . strtolower($cacheDriver); + return $container->has($service) + ? $container->get($service) + : $container->get('prevnext.driver.sql'); + } + /** * Get a list of boot services. * diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsBag.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsBag.php index e3fcd7adb82..167be544c39 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsBag.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsBag.php @@ -139,7 +139,7 @@ public function loadValues() { $isUpgradeMode = \CRM_Core_Config::isUpgradeMode(); - if ($isUpgradeMode && empty($this->contactId) && \CRM_Core_DAO::checkFieldExists('civicrm_domain', 'config_backend', FALSE)) { + if ($isUpgradeMode && empty($this->contactId) && \CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_domain', 'config_backend', FALSE)) { $config_backend = \CRM_Core_DAO::singleValueQuery('SELECT config_backend FROM civicrm_domain WHERE id = %1', array(1 => array($this->domainId, 'Positive'))); $oldSettings = \CRM_Upgrade_Incremental_php_FourSeven::convertBackendToSettings($this->domainId, $config_backend); @@ -373,7 +373,7 @@ protected function setDb($name, $value) { if (!isset(\Civi::$statics[__CLASS__]['upgradeMode'])) { \Civi::$statics[__CLASS__]['upgradeMode'] = \CRM_Core_Config::isUpgradeMode(); } - if (\Civi::$statics[__CLASS__]['upgradeMode'] && \CRM_Core_DAO::checkFieldExists('civicrm_setting', 'group_name')) { + if (\Civi::$statics[__CLASS__]['upgradeMode'] && \CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_setting', 'group_name')) { $dao->group_name = 'placeholder'; } diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsManager.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsManager.php index 8147afca982..e56d723b2fb 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsManager.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SettingsManager.php @@ -205,7 +205,7 @@ protected function getDefaults($entity) { return self::getSystemDefaults($entity); } - $cacheKey = 'defaults:' . $entity; + $cacheKey = 'defaults_' . $entity; $defaults = $this->cache->get($cacheKey); if (!is_array($defaults)) { $specs = SettingsMetadata::getMetadata(array( diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/StaticTriggers.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/StaticTriggers.php index 40cd3a57ba5..30a02a8fa13 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/StaticTriggers.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/StaticTriggers.php @@ -89,7 +89,7 @@ public function alterTriggerInfo(&$info, $tableFilter = NULL) { if (\CRM_Core_Config::isUpgradeMode() && isset($trigger['upgrade_check'])) { $uc = $trigger['upgrade_check']; - if (!\CRM_Core_DAO::checkFieldExists($uc['table'], $uc['column']) + if (!\CRM_Core_BAO_SchemaHandler::checkIfFieldExists($uc['table'], $uc['column']) ) { continue; } diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/TimestampTriggers.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/TimestampTriggers.php index c7e1127322b..dcce0e39307 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/TimestampTriggers.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Core/SqlTrigger/TimestampTriggers.php @@ -145,7 +145,7 @@ public function alterTriggerInfo(&$info, $tableFilter = NULL) { // In the past, this was a version-based check, but checkFieldExists() // seems more robust. if (\CRM_Core_Config::isUpgradeMode()) { - if (!\CRM_Core_DAO::checkFieldExists($this->getTableName(), + if (!\CRM_Core_BAO_SchemaHandler::checkIfFieldExists($this->getTableName(), $this->getCreatedDate()) ) { return; diff --git a/profiles/civicrm_starterkit/modules/civicrm/Civi/Test/Api3TestTrait.php b/profiles/civicrm_starterkit/modules/civicrm/Civi/Test/Api3TestTrait.php index 1efcd13ce69..2a10abf7e73 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/Civi/Test/Api3TestTrait.php +++ b/profiles/civicrm_starterkit/modules/civicrm/Civi/Test/Api3TestTrait.php @@ -235,6 +235,9 @@ public function callAPISuccessGetValue($entity, $params, $type = NULL) { 'debug' => 1, ); $result = $this->civicrm_api($entity, 'getvalue', $params); + if (is_array($result) && (!empty($result['is_error']) || isset($result['values']))) { + throw new \Exception('Invalid getvalue result' . print_r($result, TRUE)); + } if ($type) { if ($type == 'integer') { // api seems to return integers as strings diff --git a/profiles/civicrm_starterkit/modules/civicrm/PATCHES.txt b/profiles/civicrm_starterkit/modules/civicrm/PATCHES.txt index 5a8f44a89cd..1f36fb46aad 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/PATCHES.txt +++ b/profiles/civicrm_starterkit/modules/civicrm/PATCHES.txt @@ -1,5 +1,5 @@ The following patches have been applied to this project: -- pantheon-settings-starterkit-50.patch +- pantheon-settings-starterkit-55.patch - public_files_config.patch - cron.patch - extern-cms-bootstrap.patch diff --git a/profiles/civicrm_starterkit/modules/civicrm/README.md b/profiles/civicrm_starterkit/modules/civicrm/README.md index cf7462f47db..69835a0b75c 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/README.md +++ b/profiles/civicrm_starterkit/modules/civicrm/README.md @@ -46,5 +46,5 @@ questions and ideas in the [Developer Discussion room](https://chat.civicrm.org/ Installing the latest developmental code requires some [special steps](http://wiki.civicrm.org/confluence/display/CRMDOC/Contributing+to+CiviCRM+using+GitHub). -Report all issues to CiviCRM via JIRA: -https://issues.civicrm.org +Report all issues to CiviCRM via GitLab: +https://lab.civicrm.org diff --git a/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType.js b/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType.js index ee9efb96030..12500df6154 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType.js +++ b/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType.js @@ -67,6 +67,13 @@ limit: 0 } }]; + reqs.defaultAssigneeTypes = ['OptionValue', 'get', { + option_group_id: 'activity_default_assignee', + sequential: 1, + options: { + limit: 0 + } + }]; reqs.relTypes = ['RelationshipType', 'get', { sequential: 1, options: { @@ -230,41 +237,101 @@ }); crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls) { - // CRM_Case_XMLProcessor::REL_TYPE_CNAME - var REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME, + var REL_TYPE_CNAME, defaultAssigneeDefaultValue, ts; + + (function init () { + // CRM_Case_XMLProcessor::REL_TYPE_CNAME + REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME; + + ts = $scope.ts = CRM.ts(null); + $scope.locks = { caseTypeName: true, activitySetName: true }; + $scope.workflows = { timeline: 'Timeline', sequence: 'Sequence' }; + defaultAssigneeDefaultValue = _.find(apiCalls.defaultAssigneeTypes.values, { is_default: '1' }) || {}; + + storeApiCallsResults(); + initCaseType(); + initCaseTypeDefinition(); + initSelectedStatuses(); + })(); + + /// Stores the api calls results in the $scope object + function storeApiCallsResults() { + $scope.activityStatuses = apiCalls.actStatuses.values; + $scope.caseStatuses = _.indexBy(apiCalls.caseStatuses.values, 'name'); + $scope.activityTypes = _.indexBy(apiCalls.actTypes.values, 'name'); + $scope.activityTypeOptions = _.map(apiCalls.actTypes.values, formatActivityTypeOption); + $scope.defaultAssigneeTypes = apiCalls.defaultAssigneeTypes.values; + $scope.relationshipTypeOptions = _.map(apiCalls.relTypes.values, function(type) { + return {id: type[REL_TYPE_CNAME], text: type.label_b_a}; + }); + $scope.defaultRelationshipTypeOptions = getDefaultRelationshipTypeOptions(); + // stores the default assignee values indexed by their option name: + $scope.defaultAssigneeTypeValues = _.chain($scope.defaultAssigneeTypes) + .indexBy('name').mapValues('value').value(); + } - ts = $scope.ts = CRM.ts(null); + /// Returns the default relationship type options. If the relationship is + /// bidirectional (Ex: Spouse of) it adds a single option otherwise it adds + /// two options representing the relationship type directions + /// (Ex: Employee of, Employer is) + function getDefaultRelationshipTypeOptions() { + return _.transform(apiCalls.relTypes.values, function(result, relType) { + var isBidirectionalRelationship = relType.label_a_b === relType.label_b_a; + + result.push({ + label: relType.label_b_a, + value: relType.id + '_b_a' + }); - $scope.activityStatuses = apiCalls.actStatuses.values; - $scope.caseStatuses = _.indexBy(apiCalls.caseStatuses.values, 'name'); - $scope.activityTypes = _.indexBy(apiCalls.actTypes.values, 'name'); - $scope.activityTypeOptions = _.map(apiCalls.actTypes.values, formatActivityTypeOption); - $scope.relationshipTypeOptions = _.map(apiCalls.relTypes.values, function(type) { - return {id: type[REL_TYPE_CNAME], text: type.label_b_a}; - }); - $scope.locks = {caseTypeName: true, activitySetName: true}; + if (!isBidirectionalRelationship) { + result.push({ + label: relType.label_a_b, + value: relType.id + '_a_b' + }); + } + }, []); + } - $scope.workflows = { - 'timeline': 'Timeline', - 'sequence': 'Sequence' - }; + /// initializes the case type object + function initCaseType() { + var isNewCaseType = !apiCalls.caseType; + + if (isNewCaseType) { + $scope.caseType = _.cloneDeep(newCaseTypeTemplate); + } else { + $scope.caseType = apiCalls.caseType; + } + } - $scope.caseType = apiCalls.caseType ? apiCalls.caseType : _.cloneDeep(newCaseTypeTemplate); - $scope.caseType.definition = $scope.caseType.definition || []; - $scope.caseType.definition.activityTypes = $scope.caseType.definition.activityTypes || []; - $scope.caseType.definition.activitySets = $scope.caseType.definition.activitySets || []; - _.each($scope.caseType.definition.activitySets, function (set) { - _.each(set.activityTypes, function (type, name) { - type.label = $scope.activityTypes[type.name].label; + /// initializes the case type definition object + function initCaseTypeDefinition() { + $scope.caseType.definition = $scope.caseType.definition || []; + $scope.caseType.definition.activityTypes = $scope.caseType.definition.activityTypes || []; + $scope.caseType.definition.activitySets = $scope.caseType.definition.activitySets || []; + $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || []; + $scope.caseType.definition.statuses = $scope.caseType.definition.statuses || []; + $scope.caseType.definition.timelineActivityTypes = $scope.caseType.definition.timelineActivityTypes || []; + + _.each($scope.caseType.definition.activitySets, function (set) { + _.each(set.activityTypes, function (type, name) { + var isDefaultAssigneeTypeUndefined = _.isUndefined(type.default_assignee_type); + type.label = $scope.activityTypes[type.name].label; + + if (isDefaultAssigneeTypeUndefined) { + type.default_assignee_type = defaultAssigneeDefaultValue.value; + } + }); }); - }); - $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || []; - $scope.caseType.definition.statuses = $scope.caseType.definition.statuses || []; + } - $scope.selectedStatuses = {}; - _.each(apiCalls.caseStatuses.values, function (status) { - $scope.selectedStatuses[status.name] = !$scope.caseType.definition.statuses.length || $scope.caseType.definition.statuses.indexOf(status.name) > -1; - }); + /// initializes the selected statuses + function initSelectedStatuses() { + $scope.selectedStatuses = {}; + + _.each(apiCalls.caseStatuses.values, function (status) { + $scope.selectedStatuses[status.name] = !$scope.caseType.definition.statuses.length || $scope.caseType.definition.statuses.indexOf(status.name) > -1; + }); + } $scope.addActivitySet = function(workflow) { var activitySet = {}; @@ -288,14 +355,28 @@ } function addActivityToSet(activitySet, activityTypeName) { - activitySet.activityTypes.push({ - name: activityTypeName, - label: $scope.activityTypes[activityTypeName].label, - status: 'Scheduled', - reference_activity: 'Open Case', - reference_offset: '1', - reference_select: 'newest' - }); + var activity = { + name: activityTypeName, + label: $scope.activityTypes[activityTypeName].label, + status: 'Scheduled', + reference_activity: 'Open Case', + reference_offset: '1', + reference_select: 'newest', + default_assignee_type: $scope.defaultAssigneeTypeValues.NONE + }; + activitySet.activityTypes.push(activity); + if(typeof activitySet.timeline !== "undefined" && activitySet.timeline == "1") { + $scope.caseType.definition.timelineActivityTypes.push(activity); + } + } + + function resetTimelineActivityTypes() { + $scope.caseType.definition.timelineActivityTypes = []; + angular.forEach($scope.caseType.definition.activitySets, function(activitySet) { + angular.forEach(activitySet.activityTypes, function(activityType) { + $scope.caseType.definition.timelineActivityTypes.push(activityType); + }); + }); } function createActivity(name, callback) { @@ -334,6 +415,12 @@ } }; + /// Clears the activity's default assignee values for relationship and contact + $scope.clearActivityDefaultAssigneeValues = function(activity) { + activity.default_assignee_relationship = null; + activity.default_assignee_contact = null; + }; + /// Add a new role $scope.addRole = function(roles, roleName) { var names = _.pluck($scope.caseType.definition.caseRoles, 'name'); @@ -363,6 +450,7 @@ var idx = _.indexOf(array, item); if (idx != -1) { array.splice(idx, 1); + resetTimelineActivityTypes(); } }; @@ -462,6 +550,7 @@ if (!$scope.isForkable()) { CRM.alert(ts('The CiviCase XML file for this case-type prohibits editing the definition.')); } + }); crmCaseType.controller('CaseTypeListCtrl', function($scope, crmApi, caseTypes) { diff --git a/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType/list.html b/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType/list.html index 52d1a3d0a6f..a9caecc34a2 100644 --- a/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType/list.html +++ b/profiles/civicrm_starterkit/modules/civicrm/ang/crmCaseType/list.html @@ -35,7 +35,7 @@