diff --git a/.gitignore b/.gitignore
index 20ab4f93a8de..231ab1469771 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@
!/ext/civi_pledge
!/ext/civi_report
!/ext/scheduled_communications
+!/ext/user_dashboard
backdrop/
bower_components
CRM/Case/xml/configuration
diff --git a/CRM/ACL/BAO/ACL.php b/CRM/ACL/BAO/ACL.php
index dd39cce67904..944faaf3de8b 100644
--- a/CRM/ACL/BAO/ACL.php
+++ b/CRM/ACL/BAO/ACL.php
@@ -513,7 +513,7 @@ private static function getGroupClause(array $groupIDs, string $operation): stri
";
$dao = CRM_Core_DAO::executeQuery($query);
$foundGroupIDs = [];
- $groupContactCacheClause = FALSE;
+ $groupContactCacheClause = '';
while ($dao->fetch()) {
$foundGroupIDs[] = $dao->id;
if (($dao->saved_search_id || $dao->children || $dao->parents)) {
@@ -524,7 +524,7 @@ private static function getGroupClause(array $groupIDs, string $operation): stri
}
}
- if ($groupIDs) {
+ if ($foundGroupIDs) {
return "(
`contact_a`.id $operation (
SELECT contact_id FROM civicrm_group_contact WHERE group_id IN (" . implode(', ', $foundGroupIDs) . ") AND status = 'Added'
@@ -532,7 +532,12 @@ private static function getGroupClause(array $groupIDs, string $operation): stri
)
)";
}
- return '';
+ else {
+ // Edge case avoiding SQL syntax error if no $foundGroupIDs
+ return "(
+ `contact_a`.id $operation (0)
+ )";
+ }
}
public static function getObjectTableOptions(): array {
diff --git a/CRM/ACL/DAO/ACL.php b/CRM/ACL/DAO/ACL.php
index 0a9b48d46869..b9b28c82b0ac 100644
--- a/CRM/ACL/DAO/ACL.php
+++ b/CRM/ACL/DAO/ACL.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/ACL/ACL.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:56266204b43a487af7bf9963d23e0556)
+ * (GenCodeChecksum:d49159426e04e1bab16768e2f7ed9551)
*/
/**
@@ -135,7 +135,7 @@ class CRM_ACL_DAO_ACL extends CRM_Core_DAO {
/**
* Is this property active?
*
- * @var bool|string|null
+ * @var bool|string
* (SQL type: tinyint)
* Note that values will be retrieved from the database as a string.
*/
@@ -425,6 +425,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('ACL Is Active?'),
'description' => ts('Is this property active?'),
+ 'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
@@ -432,6 +433,7 @@ public static function &fields() {
'token' => FALSE,
],
'where' => 'civicrm_acl.is_active',
+ 'default' => '1',
'table_name' => 'civicrm_acl',
'entity' => 'ACL',
'bao' => 'CRM_ACL_BAO_ACL',
diff --git a/CRM/ACL/Form/ACL.php b/CRM/ACL/Form/ACL.php
index b4f52a7c746a..5f5c5b88a5e2 100644
--- a/CRM/ACL/Form/ACL.php
+++ b/CRM/ACL/Form/ACL.php
@@ -256,7 +256,7 @@ public function postProcess() {
}
else {
$params = $this->controller->exportValues($this->_name);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
$params['entity_table'] = 'civicrm_acl_role';
// Figure out which type of object we're permissioning on and set object_table and object_id.
diff --git a/CRM/Activity/BAO/Activity.php b/CRM/Activity/BAO/Activity.php
index 5d74041ed6fe..8405e21c4bfe 100644
--- a/CRM/Activity/BAO/Activity.php
+++ b/CRM/Activity/BAO/Activity.php
@@ -2335,8 +2335,8 @@ public static function getContactActivitySelector(&$params) {
$params['rowCount'] = $params['rp'];
$params['sort'] = $params['sortBy'] ?? NULL;
$params['caseId'] = NULL;
- $context = $params['context'] ?? NULL;
- $showContactOverlay = !CRM_Utils_String::startsWith($context, "dashlet");
+ $context = $params['context'] ?? '';
+ $showContactOverlay = !str_starts_with($context, "dashlet");
$activityTypeInfo = civicrm_api3('OptionValue', 'get', [
'option_group_id' => "activity_type",
'options' => ['limit' => 0],
diff --git a/CRM/Activity/Form/Activity.php b/CRM/Activity/Form/Activity.php
index 001ea75742a9..cefbe57ae377 100644
--- a/CRM/Activity/Form/Activity.php
+++ b/CRM/Activity/Form/Activity.php
@@ -550,12 +550,8 @@ public function setDefaultValues() {
if (isset($this->_activityId)) {
if ($this->_context !== 'standalone') {
- $this->assign('target_contact_value',
- CRM_Utils_Array::value('target_contact_value', $defaults)
- );
- $this->assign('assignee_contact_value',
- CRM_Utils_Array::value('assignee_contact_value', $defaults)
- );
+ $this->assign('target_contact_value', $defaults['target_contact_value'] ?? NULL);
+ $this->assign('assignee_contact_value', $defaults['assignee_contact_value'] ?? NULL);
}
// Fixme: why are we getting the wrong keys from upstream?
@@ -596,7 +592,7 @@ public function setDefaultValues() {
}
if ($this->_action & (CRM_Core_Action::DELETE | CRM_Core_Action::RENEW)) {
- $this->assign('delName', CRM_Utils_Array::value('subject', $defaults));
+ $this->assign('delName', $defaults['subject'] ?? NULL);
}
if ($this->_activityTypeFile) {
@@ -679,13 +675,13 @@ public function buildQuickForm() {
$this->addEntityRef($field, $values['label'], $attribute, $required);
}
else {
- $this->add($values['type'], $field, $values['label'], $attribute, $required, CRM_Utils_Array::value('extra', $values));
+ $this->add($values['type'], $field, $values['label'], $attribute, $required, $values['extra'] ?? NULL);
}
}
}
// CRM-7362 --add campaigns.
- CRM_Campaign_BAO_Campaign::addCampaign($this, CRM_Utils_Array::value('campaign_id', $this->_values));
+ CRM_Campaign_BAO_Campaign::addCampaign($this, $this->_values['campaign_id'] ?? NULL);
// Add engagement level CRM-7775
$buildEngagementLevel = FALSE;
diff --git a/CRM/Activity/Selector/Activity.php b/CRM/Activity/Selector/Activity.php
index f8682ae5a7ba..d6a2af75e694 100644
--- a/CRM/Activity/Selector/Activity.php
+++ b/CRM/Activity/Selector/Activity.php
@@ -417,11 +417,11 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL, $ca
$row['engagement_level'] = CRM_Utils_Array::value($engagementLevel, $engagementLevels, $engagementLevel);
}
- $actionLinks = $this->actionLinks(CRM_Utils_Array::value('activity_type_id', $row),
- CRM_Utils_Array::value('source_record_id', $row),
+ $actionLinks = $this->actionLinks($row['activity_type_id'],
+ $row['source_record_id'] ?? NULL,
// CRM-3553
!empty($row['mailingId']),
- CRM_Utils_Array::value('activity_id', $row),
+ $row['activity_id'] ?? NULL,
$this->_key
);
diff --git a/CRM/Admin/Form/MailSettings.php b/CRM/Admin/Form/MailSettings.php
index acdc5744da43..833c0de13753 100644
--- a/CRM/Admin/Form/MailSettings.php
+++ b/CRM/Admin/Form/MailSettings.php
@@ -211,7 +211,7 @@ public function postProcess() {
'is_contact_creation_disabled_if_no_match',
'is_active',
])) {
- $params[$f] = CRM_Utils_Array::value($f, $formValues, FALSE);
+ $params[$f] = $formValues[$f] ?? FALSE;
}
else {
$params[$f] = $formValues[$f] ?? NULL;
diff --git a/CRM/Admin/Form/ParticipantStatusType.php b/CRM/Admin/Form/ParticipantStatusType.php
index a3097c7de7e9..7eb952356895 100644
--- a/CRM/Admin/Form/ParticipantStatusType.php
+++ b/CRM/Admin/Form/ParticipantStatusType.php
@@ -119,7 +119,7 @@ public function postProcess() {
}
$params['weight'] = CRM_Utils_Weight::updateOtherWeights('CRM_Event_DAO_ParticipantStatusType', $oldWeight, $params['weight']);
- $participantStatus = CRM_Event_BAO_ParticipantStatusType::create($params);
+ $participantStatus = CRM_Event_BAO_ParticipantStatusType::writeRecord($params);
if ($participantStatus->id) {
if ($this->_action & CRM_Core_Action::UPDATE) {
diff --git a/CRM/Admin/Form/PaymentProcessorType.php b/CRM/Admin/Form/PaymentProcessorType.php
index 2259920ef8a3..8543723e85a9 100644
--- a/CRM/Admin/Form/PaymentProcessorType.php
+++ b/CRM/Admin/Form/PaymentProcessorType.php
@@ -146,7 +146,7 @@ public function buildQuickForm($check = FALSE) {
$attributes = CRM_Core_DAO::getAttribute('CRM_Financial_DAO_PaymentProcessorType');
foreach ($this->_fields as $field) {
- $required = CRM_Utils_Array::value('required', $field, FALSE);
+ $required = $field['required'] ?? FALSE;
$this->add('text', $field['name'],
$field['label'], $attributes['name'], $required
);
@@ -210,9 +210,9 @@ public function postProcess() {
$dao = new CRM_Financial_DAO_PaymentProcessorType();
$dao->id = $this->_id;
- $dao->is_default = CRM_Utils_Array::value('is_default', $values, 0);
- $dao->is_active = CRM_Utils_Array::value('is_active', $values, 0);
- $dao->is_recur = CRM_Utils_Array::value('is_recur', $values, 0);
+ $dao->is_default = $values['is_default'] ?? 0;
+ $dao->is_active = $values['is_active'] ?? 0;
+ $dao->is_recur = $values['is_recur'] ?? 0;
$dao->name = $values['name'];
$dao->description = $values['description'];
diff --git a/CRM/Admin/Form/Preferences/Contribute.php b/CRM/Admin/Form/Preferences/Contribute.php
index 7729a1f170ed..e6182123ee51 100644
--- a/CRM/Admin/Form/Preferences/Contribute.php
+++ b/CRM/Admin/Form/Preferences/Contribute.php
@@ -167,7 +167,7 @@ public function postProcess() {
// too. This means that saving from api will not have the desired core effect.
// but we should fix that elsewhere - ie. stop abusing the settings
// and fix the code repetition associated with invoicing
- $invoiceParams['invoicing'] = CRM_Utils_Array::value('invoicing', $params, 0);
+ $invoiceParams['invoicing'] = $params['invoicing'] ?? 0;
Civi::settings()->set('contribution_invoice_settings', $invoiceParams);
parent::postProcess();
}
diff --git a/CRM/Admin/Form/RelationshipType.php b/CRM/Admin/Form/RelationshipType.php
index ce4320617155..c3c07573ddc3 100644
--- a/CRM/Admin/Form/RelationshipType.php
+++ b/CRM/Admin/Form/RelationshipType.php
@@ -141,7 +141,7 @@ public function postProcess() {
else {
// store the submitted values in an array
$params = $this->exportValues();
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
if ($this->_action & CRM_Core_Action::UPDATE) {
$params['id'] = $this->_id;
diff --git a/CRM/Admin/Form/ScheduleReminders.php b/CRM/Admin/Form/ScheduleReminders.php
index 6b76ffa22c0e..eee74938962d 100644
--- a/CRM/Admin/Form/ScheduleReminders.php
+++ b/CRM/Admin/Form/ScheduleReminders.php
@@ -22,6 +22,8 @@
*/
class CRM_Admin_Form_ScheduleReminders extends CRM_Admin_Form {
+ protected $retrieveMethod = 'api4';
+
/**
* @return string
*/
diff --git a/CRM/Admin/Form/Setting/Miscellaneous.php b/CRM/Admin/Form/Setting/Miscellaneous.php
index 6a5a443dfe76..cf0753506856 100644
--- a/CRM/Admin/Form/Setting/Miscellaneous.php
+++ b/CRM/Admin/Form/Setting/Miscellaneous.php
@@ -62,7 +62,6 @@ public function preProcess() {
'recentItemsMaxCount',
'recentItemsProviders',
'dedupe_default_limit',
- 'esm_loader',
'prevNextBackend',
'import_batch_size',
]);
diff --git a/CRM/Admin/Page/AJAX.php b/CRM/Admin/Page/AJAX.php
index 0cc9bbbb8ced..c82be9ba8dba 100644
--- a/CRM/Admin/Page/AJAX.php
+++ b/CRM/Admin/Page/AJAX.php
@@ -290,7 +290,7 @@ public static function getTagTree() {
$result = [];
$whereClauses = ['is_tagset <> 1'];
- $orderColumn = 'name';
+ $orderColumn = 'label';
// fetch all child tags in Array('parent_tag' => array('child_tag_1', 'child_tag_2', ...)) format
$childTagIDs = CRM_Core_BAO_Tag::getChildTags($substring);
@@ -300,7 +300,7 @@ public static function getTagTree() {
$whereClauses[] = "parent_id = $parent";
}
elseif ($substring) {
- $whereClauses['substring'] = " name LIKE '%$substring%' ";
+ $whereClauses['substring'] = " label LIKE '%$substring%' ";
if (!empty($parentIDs)) {
$whereClauses['substring'] = sprintf(" %s OR id IN (%s) ", $whereClauses['substring'], implode(',', $parentIDs));
}
@@ -328,7 +328,7 @@ public static function getTagTree() {
$usedFor = (array) explode(',', $dao->used_for);
$tag = [
'id' => $dao->id,
- 'text' => $dao->name,
+ 'text' => $dao->label,
'a_attr' => [
'class' => 'crm-tag-item',
],
diff --git a/CRM/Api4/Page/AJAX.php b/CRM/Api4/Page/AJAX.php
index dee72c6f70ed..bea9ec482240 100644
--- a/CRM/Api4/Page/AJAX.php
+++ b/CRM/Api4/Page/AJAX.php
@@ -137,7 +137,7 @@ private function execute(string $entity, string $action, array $params = [], $in
$status = $statusMap[get_class($e)] ?? 500;
// Send error code (but don't overwrite success code if there are multiple calls and one was successful)
$this->httpResponseCode = $this->httpResponseCode ?: $status;
- if (CRM_Core_Permission::check('view debug output')) {
+ if (CRM_Core_Permission::check('view debug output') || ($e->getErrorData()['show_detailed_error'] ?? FALSE)) {
$response['error_code'] = $e->getCode();
$response['error_message'] = $e->getMessage();
if (!empty($params['debug'])) {
diff --git a/CRM/Badge/BAO/Layout.php b/CRM/Badge/BAO/Layout.php
index c146c3a49c18..e7443c3ef43f 100644
--- a/CRM/Badge/BAO/Layout.php
+++ b/CRM/Badge/BAO/Layout.php
@@ -50,9 +50,9 @@ public static function setIsActive($id, $is_active) {
* @return object
*/
public static function create(&$params) {
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE);
- $params['is_reserved'] = CRM_Utils_Array::value('is_reserved', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
+ $params['is_default'] = $params['is_default'] ?? FALSE;
+ $params['is_reserved'] = $params['is_reserved'] ?? FALSE;
$params['label_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Core_DAO_PrintLabel', 'label_type_id', 'Event Badge');
diff --git a/CRM/Badge/Form/Layout.php b/CRM/Badge/Form/Layout.php
index 661fb70ac3b5..6f5b9a41892a 100644
--- a/CRM/Badge/Form/Layout.php
+++ b/CRM/Badge/Form/Layout.php
@@ -9,6 +9,8 @@
+--------------------------------------------------------------------+
*/
+use Civi\Token\TokenProcessor;
+
/**
*
* @package CRM
@@ -49,21 +51,13 @@ public function buildQuickForm(): void {
$this->add('text', 'description', ts('Description'),
CRM_Core_DAO::getAttribute('CRM_Core_DAO_PrintLabel', 'title'));
- // get the tokens - at the point of rendering the token processor is used so
- // the only reason for this cut-down set of tokens is UI on this
- // screen and / or historical.
- $contactTokens = CRM_Core_SelectValues::contactTokens();
- $eventTokens = [
- '{event.event_id}' => ts('Event ID'),
- '{event.title}' => ts('Event Title'),
- // This layout selection is day + month eg October 27th
- // obviously someone felt year was not logical for dates.
- '{event.start_date|crmDate:"%B %E%f"}' => ts('Event Start Date'),
- '{event.end_date|crmDate:"%B %E%f"}' => ts('Event End Date'),
- ];
- $participantTokens = CRM_Core_SelectValues::participantTokens();
-
- $tokens = array_merge($contactTokens, $eventTokens, $participantTokens);
+ $tokenProcessor = new TokenProcessor(Civi::dispatcher(), ['schema' => ['participantId', 'contactId', 'eventId']]);
+ $tokens = $tokenProcessor->listTokens();
+ // This layout selection is day + month eg October 27th
+ // obviously someone felt year was not logical for dates.
+ $tokens['{event.start_date|crmDate:"%B %E%f"}'] = ts('Event Start Date - Day & Month');
+ $tokens[] = ts('Event End Date - Day & Month');
+
asort($tokens);
$tokens = array_merge(['spacer' => ts('- spacer -')] + $tokens);
diff --git a/CRM/Campaign/BAO/Campaign.php b/CRM/Campaign/BAO/Campaign.php
index b8d6b1c4c6a1..b613455438fa 100644
--- a/CRM/Campaign/BAO/Campaign.php
+++ b/CRM/Campaign/BAO/Campaign.php
@@ -278,160 +278,6 @@ public static function isCampaignEnable(): bool {
return self::isComponentEnabled();
}
- /**
- * Retrieve campaigns for dashboard.
- *
- * @param array $params
- * @param bool $onlyCount
- *
- * @return array|int
- */
- public static function getCampaignSummary($params = [], $onlyCount = FALSE) {
- $campaigns = [];
-
- //build the limit and order clause.
- $limitClause = $orderByClause = $lookupTableJoins = NULL;
- if (!$onlyCount) {
- $sortParams = [
- 'sort' => 'start_date',
- 'offset' => 0,
- 'rowCount' => 10,
- 'sortOrder' => 'desc',
- ];
- foreach ($sortParams as $name => $default) {
- if (!empty($params[$name])) {
- $sortParams[$name] = $params[$name];
- }
- }
-
- //need to lookup tables.
- $orderOnCampaignTable = TRUE;
- if ($sortParams['sort'] === 'status') {
- $orderOnCampaignTable = FALSE;
- $lookupTableJoins = "
- LEFT JOIN civicrm_option_value status ON ( status.value = campaign.status_id OR campaign.status_id IS NULL )
-INNER JOIN civicrm_option_group grp ON ( status.option_group_id = grp.id AND grp.name = 'campaign_status' )";
- $orderByClause = "ORDER BY status.label {$sortParams['sortOrder']}";
- }
- elseif ($sortParams['sort'] === 'campaign_type') {
- $orderOnCampaignTable = FALSE;
- $lookupTableJoins = "
- LEFT JOIN civicrm_option_value campaign_type ON ( campaign_type.value = campaign.campaign_type_id
- OR campaign.campaign_type_id IS NULL )
-INNER JOIN civicrm_option_group grp ON ( campaign_type.option_group_id = grp.id AND grp.name = 'campaign_type' )";
- $orderByClause = "ORDER BY campaign_type.label {$sortParams['sortOrder']}";
- }
- elseif ($sortParams['sort'] === 'isActive') {
- $sortParams['sort'] = 'is_active';
- }
- if ($orderOnCampaignTable) {
- $orderByClause = "ORDER BY campaign.{$sortParams['sort']} {$sortParams['sortOrder']}";
- }
- $orderByClause = ($orderByClause) ? $orderByClause . ", campaign.id {$sortParams['sortOrder']}" : $orderByClause;
- $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}";
- }
-
- //build the where clause.
- $queryParams = $where = [];
- if (!empty($params['id'])) {
- $where[] = "( campaign.id = %1 )";
- $queryParams[1] = [$params['id'], 'Positive'];
- }
- if (!empty($params['name'])) {
- $where[] = "( campaign.name LIKE %2 )";
- $queryParams[2] = ['%' . trim($params['name']) . '%', 'String'];
- }
- if (!empty($params['title'])) {
- $where[] = "( campaign.title LIKE %3 )";
- $queryParams[3] = ['%' . trim($params['title']) . '%', 'String'];
- }
- if (!empty($params['start_date'])) {
- $startDate = CRM_Utils_Date::processDate($params['start_date']);
- $where[] = "( campaign.start_date >= %4 OR campaign.start_date IS NULL )";
- $queryParams[4] = [$startDate, 'String'];
- }
- if (!empty($params['end_date'])) {
- $endDate = CRM_Utils_Date::processDate($params['end_date'], '235959');
- $where[] = "( campaign.end_date <= %5 OR campaign.end_date IS NULL )";
- $queryParams[5] = [$endDate, 'String'];
- }
- if (!empty($params['description'])) {
- $where[] = "( campaign.description LIKE %6 )";
- $queryParams[6] = ['%' . trim($params['description']) . '%', 'String'];
- }
- if (!empty($params['campaign_type_id'])) {
- $where[] = "( campaign.campaign_type_id IN ( %7 ) )";
- $queryParams[7] = [implode(',', (array) $params['campaign_type_id']), 'CommaSeparatedIntegers'];
- }
- if (!empty($params['status_id'])) {
- $where[] = "( campaign.status_id IN ( %8 ) )";
- $queryParams[8] = [implode(',', (array) $params['status_id']), 'CommaSeparatedIntegers'];
- }
- if (array_key_exists('is_active', $params)) {
- $active = "( campaign.is_active = 1 )";
- if (!empty($params['is_active'])) {
- $active = "campaign.is_active = 0";
- }
- $where[] = $active;
- }
- $whereClause = NULL;
- if (!empty($where)) {
- $whereClause = ' WHERE ' . implode(" \nAND ", $where);
- }
-
- $properties = [
- 'id',
- 'name',
- 'title',
- 'start_date',
- 'end_date',
- 'status_id',
- 'is_active',
- 'description',
- 'campaign_type_id',
- ];
-
- $selectClause = '
-SELECT campaign.id as id,
- campaign.name as name,
- campaign.title as title,
- campaign.is_active as is_active,
- campaign.status_id as status_id,
- campaign.end_date as end_date,
- campaign.start_date as start_date,
- campaign.description as description,
- campaign.campaign_type_id as campaign_type_id';
- if ($onlyCount) {
- $selectClause = 'SELECT COUNT(*)';
- }
- $fromClause = 'FROM civicrm_campaign campaign';
-
- $query = "{$selectClause} {$fromClause} {$lookupTableJoins} {$whereClause} {$orderByClause} {$limitClause}";
-
- //in case of only count.
- if ($onlyCount) {
- return (int) CRM_Core_DAO::singleValueQuery($query, $queryParams);
- }
-
- $campaign = CRM_Core_DAO::executeQuery($query, $queryParams);
- while ($campaign->fetch()) {
- foreach ($properties as $property) {
- $campaigns[$campaign->id][$property] = $campaign->$property;
- }
- }
-
- return $campaigns;
- }
-
- /**
- * Get the campaign count.
- *
- * @return int
- */
- public static function getCampaignCount(): int {
- return (int) CRM_Core_DAO::singleValueQuery('SELECT COUNT(*) FROM civicrm_campaign');
- }
-
/**
* Get Campaigns groups.
*
diff --git a/CRM/Campaign/BAO/Petition.php b/CRM/Campaign/BAO/Petition.php
index d75e2b612f09..887370953fa3 100644
--- a/CRM/Campaign/BAO/Petition.php
+++ b/CRM/Campaign/BAO/Petition.php
@@ -34,136 +34,6 @@ public function __construct() {
$this->cookieExpire = (1 * 60 * 60 * 24);
}
- /**
- * Get Petition Details for dashboard.
- *
- * @param array $params
- * @param bool $onlyCount
- *
- * @return array|int
- */
- public static function getPetitionSummary($params = [], $onlyCount = FALSE) {
- //build the limit and order clause.
- $limitClause = $orderByClause = $lookupTableJoins = NULL;
- if (!$onlyCount) {
- $sortParams = [
- 'sort' => 'created_date',
- 'offset' => 0,
- 'rowCount' => 10,
- 'sortOrder' => 'desc',
- ];
- foreach ($sortParams as $name => $default) {
- if (!empty($params[$name])) {
- $sortParams[$name] = $params[$name];
- }
- }
-
- //need to lookup tables.
- $orderOnPetitionTable = TRUE;
- if ($sortParams['sort'] == 'campaign') {
- $orderOnPetitionTable = FALSE;
- $lookupTableJoins = '
- LEFT JOIN civicrm_campaign campaign ON ( campaign.id = petition.campaign_id )';
- $orderByClause = "ORDER BY campaign.title {$sortParams['sortOrder']}";
- }
- elseif ($sortParams['sort'] == 'activity_type') {
- $orderOnPetitionTable = FALSE;
- $lookupTableJoins = "
- LEFT JOIN civicrm_option_value activity_type ON ( activity_type.value = petition.activity_type_id
- OR petition.activity_type_id IS NULL )
-INNER JOIN civicrm_option_group grp ON ( activity_type.option_group_id = grp.id AND grp.name = 'activity_type' )";
- $orderByClause = "ORDER BY activity_type.label {$sortParams['sortOrder']}";
- }
- elseif ($sortParams['sort'] == 'isActive') {
- $sortParams['sort'] = 'is_active';
- }
- if ($orderOnPetitionTable) {
- $orderByClause = "ORDER BY petition.{$sortParams['sort']} {$sortParams['sortOrder']}";
- }
- $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}";
- }
-
- //build the where clause.
- $queryParams = $where = [];
-
- //we only have activity type as a
- //difference between survey and petition.
- $petitionTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Petition');
- if ($petitionTypeID) {
- $where[] = "( petition.activity_type_id = %1 )";
- $queryParams[1] = [$petitionTypeID, 'Positive'];
- }
- if (!empty($params['title'])) {
- $where[] = "( petition.title LIKE %2 )";
- $queryParams[2] = ['%' . trim($params['title']) . '%', 'String'];
- }
- if (!empty($params['campaign_id'])) {
- $where[] = '( petition.campaign_id = %3 )';
- $queryParams[3] = [$params['campaign_id'], 'Positive'];
- }
- $whereClause = NULL;
- if (!empty($where)) {
- $whereClause = ' WHERE ' . implode(" \nAND ", $where);
- }
-
- $selectClause = '
-SELECT petition.id as id,
- petition.title as title,
- petition.is_active as is_active,
- petition.result_id as result_id,
- petition.is_default as is_default,
- petition.campaign_id as campaign_id,
- petition.activity_type_id as activity_type_id';
-
- if ($onlyCount) {
- $selectClause = 'SELECT COUNT(*)';
- }
- $fromClause = 'FROM civicrm_survey petition';
-
- $query = "{$selectClause} {$fromClause} {$whereClause} {$orderByClause} {$limitClause}";
-
- if ($onlyCount) {
- return (int) CRM_Core_DAO::singleValueQuery($query, $queryParams);
- }
-
- $petitions = [];
- $properties = [
- 'id',
- 'title',
- 'campaign_id',
- 'is_active',
- 'is_default',
- 'result_id',
- 'activity_type_id',
- ];
-
- $petition = CRM_Core_DAO::executeQuery($query, $queryParams);
- while ($petition->fetch()) {
- foreach ($properties as $property) {
- $petitions[$petition->id][$property] = $petition->$property;
- }
- }
-
- return $petitions;
- }
-
- /**
- * Get the petition count.
- *
- */
- public static function getPetitionCount() {
- $whereClause = 'WHERE ( 1 )';
- $queryParams = [];
- $petitionTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Petition');
- if ($petitionTypeID) {
- $whereClause = "WHERE ( petition.activity_type_id = %1 )";
- $queryParams[1] = [$petitionTypeID, 'Positive'];
- }
- $query = "SELECT COUNT(*) FROM civicrm_survey petition {$whereClause}";
-
- return (int) CRM_Core_DAO::singleValueQuery($query, $queryParams);
- }
-
/**
* Takes an associative array and creates a petition signature activity.
*
diff --git a/CRM/Campaign/BAO/Survey.php b/CRM/Campaign/BAO/Survey.php
index 5f9ee274931a..f0220a12b2b6 100644
--- a/CRM/Campaign/BAO/Survey.php
+++ b/CRM/Campaign/BAO/Survey.php
@@ -63,141 +63,6 @@ public static function create(&$params) {
return $dao;
}
- /**
- * Retrieve surveys for dashboard.
- *
- * @param array $params
- * @param bool $onlyCount
- *
- * @return array|int
- */
- public static function getSurveySummary($params = [], $onlyCount = FALSE) {
- //build the limit and order clause.
- $limitClause = $orderByClause = $lookupTableJoins = NULL;
- if (!$onlyCount) {
- $sortParams = [
- 'sort' => 'created_date',
- 'offset' => 0,
- 'rowCount' => 10,
- 'sortOrder' => 'desc',
- ];
- foreach ($sortParams as $name => $default) {
- if (!empty($params[$name])) {
- $sortParams[$name] = $params[$name];
- }
- }
-
- //need to lookup tables.
- $orderOnSurveyTable = TRUE;
- if ($sortParams['sort'] == 'campaign') {
- $orderOnSurveyTable = FALSE;
- $lookupTableJoins = '
- LEFT JOIN civicrm_campaign campaign ON ( campaign.id = survey.campaign_id )';
- $orderByClause = "ORDER BY campaign.title {$sortParams['sortOrder']}";
- }
- elseif ($sortParams['sort'] == 'activity_type') {
- $orderOnSurveyTable = FALSE;
- $lookupTableJoins = "
- LEFT JOIN civicrm_option_value activity_type ON ( activity_type.value = survey.activity_type_id
- OR survey.activity_type_id IS NULL )
-INNER JOIN civicrm_option_group grp ON ( activity_type.option_group_id = grp.id AND grp.name = 'activity_type' )";
- $orderByClause = "ORDER BY activity_type.label {$sortParams['sortOrder']}";
- }
- elseif ($sortParams['sort'] == 'isActive') {
- $sortParams['sort'] = 'is_active';
- }
- if ($orderOnSurveyTable) {
- $orderByClause = "ORDER BY survey.{$sortParams['sort']} {$sortParams['sortOrder']}";
- }
- $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}";
- }
-
- //build the where clause.
- $queryParams = $where = [];
-
- //we only have activity type as a
- //difference between survey and petition.
- $petitionTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Petition');
- if ($petitionTypeID) {
- $where[] = "( survey.activity_type_id != %1 )";
- $queryParams[1] = [$petitionTypeID, 'Positive'];
- }
-
- if (!empty($params['title'])) {
- $where[] = "( survey.title LIKE %2 )";
- $queryParams[2] = ['%' . trim($params['title']) . '%', 'String'];
- }
- if (!empty($params['campaign_id'])) {
- $where[] = '( survey.campaign_id = %3 )';
- $queryParams[3] = [$params['campaign_id'], 'Positive'];
- }
- if (!empty($params['activity_type_id'])) {
- $typeId = $params['activity_type_id'];
- if (is_array($params['activity_type_id'])) {
- $typeId = implode(' , ', $params['activity_type_id']);
- }
- $where[] = "( survey.activity_type_id IN ( {$typeId} ) )";
- }
- $whereClause = NULL;
- if (!empty($where)) {
- $whereClause = ' WHERE ' . implode(" \nAND ", $where);
- }
-
- $selectClause = '
-SELECT survey.id as id,
- survey.title as title,
- survey.is_active as is_active,
- survey.result_id as result_id,
- survey.is_default as is_default,
- survey.campaign_id as campaign_id,
- survey.activity_type_id as activity_type_id,
- survey.release_frequency as release_frequency,
- survey.max_number_of_contacts as max_number_of_contacts,
- survey.default_number_of_contacts as default_number_of_contacts';
- if ($onlyCount) {
- $selectClause = 'SELECT COUNT(*)';
- }
- $fromClause = 'FROM civicrm_survey survey';
-
- $query = "{$selectClause} {$fromClause} {$lookupTableJoins} {$whereClause} {$orderByClause} {$limitClause}";
-
- //return only count.
- if ($onlyCount) {
- return (int) CRM_Core_DAO::singleValueQuery($query, $queryParams);
- }
-
- $surveys = [];
- $properties = [
- 'id',
- 'title',
- 'campaign_id',
- 'is_active',
- 'is_default',
- 'result_id',
- 'activity_type_id',
- 'release_frequency',
- 'max_number_of_contacts',
- 'default_number_of_contacts',
- ];
-
- $survey = CRM_Core_DAO::executeQuery($query, $queryParams);
- while ($survey->fetch()) {
- foreach ($properties as $property) {
- $surveys[$survey->id][$property] = $survey->$property;
- }
- }
-
- return $surveys;
- }
-
- /**
- * Get the survey count.
- *
- */
- public static function getSurveyCount() {
- return (int) CRM_Core_DAO::singleValueQuery('SELECT COUNT(*) FROM civicrm_survey');
- }
-
/**
* Get Surveys.
*
@@ -809,7 +674,7 @@ public static function buildPermissionLinks($surveyId, $enclosedInUL = FALSE, $e
);
$menuLinks[] = sprintf('%s ',
$urlPath,
- CRM_Utils_Array::value('title', $link),
+ $link['title'] ?? NULL,
$link['title']
);
}
diff --git a/CRM/Campaign/DAO/Survey.php b/CRM/Campaign/DAO/Survey.php
index cbf590c94370..8343227f3855 100644
--- a/CRM/Campaign/DAO/Survey.php
+++ b/CRM/Campaign/DAO/Survey.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Campaign/Survey.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:754f9a2e62e86ff340afea563b561dec)
+ * (GenCodeChecksum:b517a686715877b8cde6af69122dcc0d)
*/
/**
@@ -45,6 +45,17 @@ class CRM_Campaign_DAO_Survey extends CRM_Core_DAO {
*/
public static $_log = FALSE;
+ /**
+ * Paths for accessing this entity in the UI.
+ *
+ * @var string[]
+ */
+ protected static $_paths = [
+ 'add' => 'civicrm/survey/add?reset=1',
+ 'update' => 'civicrm/survey/configure/main?reset=1&action=update&id=[id]',
+ 'delete' => 'civicrm/survey/delete?reset=1&id=[id]',
+ ];
+
/**
* Survey id.
*
diff --git a/CRM/Campaign/Form/Campaign.php b/CRM/Campaign/Form/Campaign.php
index 6a3931a1e994..f5a1c523bb41 100644
--- a/CRM/Campaign/Form/Campaign.php
+++ b/CRM/Campaign/Form/Campaign.php
@@ -235,14 +235,6 @@ public function buildQuickForm() {
'isDefault' => TRUE,
],
];
- // Skip this button when adding a new campaign from an entityRef
- if (empty($_GET['snippet']) || empty($_GET['returnExtra'])) {
- $buttons[] = [
- 'type' => 'upload',
- 'name' => ts('Save and New'),
- 'subName' => 'new',
- ];
- }
$buttons[] = [
'type' => 'cancel',
'name' => ts('Cancel'),
@@ -299,7 +291,7 @@ public function postProcess() {
$params['created_date'] = date('YmdHis');
}
// format params
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
$params['last_modified_id'] = $session->get('userID');
$params['last_modified_date'] = date('YmdHis');
$result = self::submit($params, $this);
diff --git a/CRM/Campaign/Form/Petition.php b/CRM/Campaign/Form/Petition.php
index 1cbd72d69bd1..55a7377984fa 100644
--- a/CRM/Campaign/Form/Petition.php
+++ b/CRM/Campaign/Form/Petition.php
@@ -291,7 +291,7 @@ public function postProcess() {
$params['last_modified_id'] = $session->get('userID');
$params['last_modified_date'] = date('YmdHis');
- $params['is_share'] = CRM_Utils_Array::value('is_share', $params, FALSE);
+ $params['is_share'] = $params['is_share'] ?? FALSE;
if ($this->_surveyId) {
@@ -309,9 +309,9 @@ public function postProcess() {
$params['created_date'] = date('YmdHis');
}
- $params['bypass_confirm'] = CRM_Utils_Array::value('bypass_confirm', $params, 0);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, 0);
- $params['is_default'] = CRM_Utils_Array::value('is_default', $params, 0);
+ $params['bypass_confirm'] = $params['bypass_confirm'] ?? 0;
+ $params['is_active'] = $params['is_active'] ?? 0;
+ $params['is_default'] = $params['is_default'] ?? 0;
$params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, $this->getEntityId(), $this->getDefaultEntity());
diff --git a/CRM/Campaign/Form/Search/Campaign.php b/CRM/Campaign/Form/Search/Campaign.php
deleted file mode 100644
index 3778ccea929b..000000000000
--- a/CRM/Campaign/Form/Search/Campaign.php
+++ /dev/null
@@ -1,119 +0,0 @@
-_search = $_GET['search'] ?? NULL;
- $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE, FALSE);
- $this->_searchTab = CRM_Utils_Request::retrieve('type', 'String', $this, FALSE, 'campaign');
-
- //when we do load tab, lets load the default objects.
- $this->assign('force', $this->_force || $this->_searchTab);
- $this->assign('searchParams', json_encode($this->get('searchParams')));
- $this->assign('buildSelector', $this->_search);
- $this->assign('searchFor', $this->_searchTab);
- $this->assign('campaignTypes', json_encode($this->get('campaignTypes')));
- $this->assign('campaignStatus', json_encode($this->get('campaignStatus')));
- $this->assign('suppressForm', TRUE);
-
- //set the form title.
- $this->setTitle(ts('Find Campaigns'));
- }
-
- /**
- * Build the form object.
- */
- public function buildQuickForm() {
- if ($this->_search) {
- return;
- }
-
- $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Campaign');
- $this->add('text', 'campaign_title', ts('Title'), $attributes['title']);
-
- //campaign description.
- $this->add('text', 'description', ts('Description'), $attributes['description']);
-
- $this->add('datepicker', 'start_date', ts('Campaign Start Date'), [], FALSE, ['time' => FALSE]);
- $this->add('datepicker', 'end_date', ts('Campaign End Date'), [], FALSE, ['time' => FALSE]);
-
- //campaign type.
- $campaignTypes = CRM_Campaign_PseudoConstant::campaignType();
- $this->add('select', 'campaign_type_id', ts('Campaign Type'),
- [
- '' => ts('- select -'),
- ] + $campaignTypes
- );
-
- $this->set('campaignTypes', $campaignTypes);
- $this->assign('campaignTypes', json_encode($campaignTypes));
-
- //campaign status
- $campaignStatus = CRM_Campaign_PseudoConstant::campaignStatus();
- $this->addElement('select', 'status_id', ts('Campaign Status'),
- [
- '' => ts('- select -'),
- ] + $campaignStatus
- );
- $this->set('campaignStatus', $campaignStatus);
- $this->assign('campaignStatus', json_encode($campaignStatus));
-
- //active campaigns
- $this->addElement('select', 'is_active', ts('Is Active?'), [
- '' => ts('- select -'),
- '0' => ts('Yes'),
- '1' => ts('No'),
- ]);
-
- //build the array of all search params.
- $this->_searchParams = [];
- foreach ($this->_elements as $element) {
- $name = $element->_attributes['name'];
- $label = $element->_label;
- if ($name == 'qfKey') {
- continue;
- }
- $this->_searchParams[$name] = ($label) ? $label : $name;
- }
- $this->set('searchParams', $this->_searchParams);
- $this->assign('searchParams', json_encode($this->_searchParams));
- }
-
-}
diff --git a/CRM/Campaign/Form/Search/Petition.php b/CRM/Campaign/Form/Search/Petition.php
deleted file mode 100644
index 49b94a12265f..000000000000
--- a/CRM/Campaign/Form/Search/Petition.php
+++ /dev/null
@@ -1,81 +0,0 @@
-_search = $_GET['search'] ?? NULL;
- $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE, FALSE);
- $this->_searchTab = CRM_Utils_Request::retrieve('type', 'String', $this, FALSE, 'petition');
-
- //when we do load tab, lets load the default objects.
- $this->assign('force', $this->_force || $this->_searchTab);
- $this->assign('searchParams', json_encode($this->get('searchParams')));
- $this->assign('buildSelector', $this->_search);
- $this->assign('searchFor', $this->_searchTab);
- $this->assign('petitionCampaigns', json_encode($this->get('petitionCampaigns')));
- $this->assign('suppressForm', TRUE);
-
- //set the form title.
- $this->setTitle(ts('Find Petition'));
- }
-
- /**
- * Build the form object.
- */
- public function buildQuickForm() {
- if ($this->_search) {
- return;
- }
-
- $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey');
- $this->add('text', 'petition_title', ts('Title'), $attributes['title']);
-
- //campaigns
- $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
- $this->add('select', 'petition_campaign_id', ts('Campaign'), ['' => ts('- select -')] + $campaigns);
- $this->set('petitionCampaigns', $campaigns);
- $this->assign('petitionCampaigns', json_encode($campaigns));
-
- //build the array of all search params.
- $this->_searchParams = [];
- foreach ($this->_elements as $element) {
- $name = $element->_attributes['name'];
- $label = $element->_label;
- if ($name == 'qfKey') {
- continue;
- }
- $this->_searchParams[$name] = ($label) ? $label : $name;
- }
- $this->set('searchParams', $this->_searchParams);
- $this->assign('searchParams', json_encode($this->_searchParams));
- }
-
-}
diff --git a/CRM/Campaign/Form/Search/Survey.php b/CRM/Campaign/Form/Search/Survey.php
deleted file mode 100644
index 6ad51606c772..000000000000
--- a/CRM/Campaign/Form/Search/Survey.php
+++ /dev/null
@@ -1,92 +0,0 @@
-_search = $_GET['search'] ?? NULL;
- $this->_force = CRM_Utils_Request::retrieve('force', 'Boolean', $this, FALSE, FALSE);
- $this->_searchTab = CRM_Utils_Request::retrieve('type', 'String', $this, FALSE, 'survey');
-
- //when we do load tab, lets load the default objects.
- $this->assign('force', $this->_force || $this->_searchTab);
- $this->assign('searchParams', json_encode($this->get('searchParams')));
- $this->assign('buildSelector', $this->_search);
- $this->assign('searchFor', $this->_searchTab);
- $this->assign('surveyTypes', json_encode($this->get('surveyTypes')));
- $this->assign('surveyCampaigns', json_encode($this->get('surveyCampaigns')));
- $this->assign('suppressForm', TRUE);
-
- //set the form title.
- $this->setTitle(ts('Find Survey'));
- }
-
- /**
- * Build the form object.
- */
- public function buildQuickForm() {
- if ($this->_search) {
- return;
- }
-
- $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Survey');
- $this->add('text', 'survey_title', ts('Title'), $attributes['title']);
-
- //activity Type id
- $surveyTypes = CRM_Campaign_BAO_Survey::getSurveyActivityType();
- $this->add('select', 'activity_type_id',
- ts('Activity Type'), [
- '' => ts('- select -'),
- ] + $surveyTypes
- );
- $this->set('surveyTypes', $surveyTypes);
- $this->assign('surveyTypes', json_encode($surveyTypes));
-
- //campaigns
- $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
- $this->add('select', 'survey_campaign_id', ts('Campaign'), ['' => ts('- select -')] + $campaigns);
- $this->set('surveyCampaigns', $campaigns);
- $this->assign('surveyCampaigns', json_encode($campaigns));
-
- //build the array of all search params.
- $this->_searchParams = [];
- foreach ($this->_elements as $element) {
- $name = $element->_attributes['name'];
- $label = $element->_label;
- if ($name == 'qfKey') {
- continue;
- }
- $this->_searchParams[$name] = ($label) ? $label : $name;
- }
- $this->set('searchParams', $this->_searchParams);
- $this->assign('searchParams', json_encode($this->_searchParams));
- }
-
-}
diff --git a/CRM/Campaign/Form/Survey.php b/CRM/Campaign/Form/Survey.php
index e06367831d00..74d1563dad45 100644
--- a/CRM/Campaign/Form/Survey.php
+++ b/CRM/Campaign/Form/Survey.php
@@ -58,6 +58,9 @@ public function getEntityId() {
}
public function preProcess() {
+ // Multistep form doesn't play well with popups
+ $this->preventAjaxSubmit();
+
if (!CRM_Campaign_BAO_Campaign::accessCampaign()) {
CRM_Utils_System::permissionDenied();
}
@@ -83,6 +86,7 @@ public function preProcess() {
// CRM-11480, CRM-11682
// Preload libraries required by the "Questions" tab
+ $this->assign('perm', (bool) CRM_Core_Permission::check('administer CiviCRM'));
CRM_UF_Page_ProfileEditor::registerProfileScripts();
CRM_UF_Page_ProfileEditor::registerSchemas(['IndividualModel', 'ActivityModel']);
@@ -101,17 +105,6 @@ public function buildQuickForm() {
'name' => ts('Save'),
'isDefault' => TRUE,
],
- [
- 'type' => 'upload',
- 'name' => ts('Save and Done'),
- 'subName' => 'done',
- ],
- [
- 'type' => 'upload',
- 'name' => ts('Save and Next'),
- 'spacing' => ' ',
- 'subName' => 'next',
- ],
];
}
else {
diff --git a/CRM/Campaign/Form/Survey/Main.php b/CRM/Campaign/Form/Survey/Main.php
index 2aca9a250b68..e23617951bf2 100644
--- a/CRM/Campaign/Form/Survey/Main.php
+++ b/CRM/Campaign/Form/Survey/Main.php
@@ -155,8 +155,8 @@ public function postProcess() {
$params['created_date'] = date('YmdHis');
}
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, 0);
- $params['is_default'] = CRM_Utils_Array::value('is_default', $params, 0);
+ $params['is_active'] = $params['is_active'] ?? 0;
+ $params['is_default'] = $params['is_default'] ?? 0;
$params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, $this->getEntityId(), $this->getDefaultEntity());
diff --git a/CRM/Campaign/Page/AJAX.php b/CRM/Campaign/Page/AJAX.php
index f5e857c2d358..69e15a5585c2 100644
--- a/CRM/Campaign/Page/AJAX.php
+++ b/CRM/Campaign/Page/AJAX.php
@@ -254,9 +254,9 @@ public static function voterList() {
TRUE, FALSE,
FALSE, FALSE,
FALSE,
- CRM_Utils_Array::value('whereClause', $voterClause),
+ $voterClause['whereClause'] ?? NULL,
NULL,
- CRM_Utils_Array::value('fromClause', $voterClause)
+ $voterClause['fromClause'] ?? NULL
);
$iTotal = $searchCount;
@@ -287,9 +287,9 @@ public static function voterList() {
FALSE, FALSE,
FALSE, FALSE,
FALSE,
- CRM_Utils_Array::value('whereClause', $voterClause),
+ $voterClause['whereClause'] ?? NULL,
$sortOrder,
- CRM_Utils_Array::value('fromClause', $voterClause)
+ $voterClause['fromClause'] ?? NULL
);
while ($result->fetch()) {
$contactID = $result->contact_id;
@@ -501,312 +501,4 @@ public static function campaignGroups() {
CRM_Utils_JSON::output($results);
}
- /**
- * This function uses the deprecated v1 datatable api and needs updating. See CRM-16353.
- * @deprecated
- */
- public static function campaignList() {
- //get the search criteria params.
- $searchCriteria = CRM_Utils_Request::retrieve('searchCriteria', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'POST');
- $searchParams = explode(',', $searchCriteria);
-
- $params = $searchRows = [];
- foreach ($searchParams as $param) {
- if (isset($_POST[$param])) {
- $params[$param] = $_POST[$param];
- }
- }
-
- //this is sequence columns on datatable.
- $selectorCols = [
- 'id',
- 'name',
- 'title',
- 'description',
- 'start_date',
- 'end_date',
- 'campaign_type_id',
- 'campaign_type',
- 'status_id',
- 'status',
- 'is_active',
- 'isActive',
- 'action',
- ];
-
- // get the data table params.
- $dataTableParams = [
- 'sEcho' => [
- 'name' => 'sEcho',
- 'type' => 'Integer',
- 'default' => 0,
- ],
- 'offset' => [
- 'name' => 'iDisplayStart',
- 'type' => 'Integer',
- 'default' => 0,
- ],
- 'rowCount' => [
- 'name' => 'iDisplayLength',
- 'type' => 'Integer',
- 'default' => 25,
- ],
- 'sort' => [
- 'name' => 'iSortCol_0',
- 'type' => 'Integer',
- 'default' => 'start_date',
- ],
- 'sortOrder' => [
- 'name' => 'sSortDir_0',
- 'type' => 'String',
- 'default' => 'desc',
- ],
- ];
- foreach ($dataTableParams as $pName => $pValues) {
- $$pName = $pValues['default'];
- if (!empty($_POST[$pValues['name']])) {
- $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']);
- if ($pName == 'sort') {
- $$pName = $selectorCols[$$pName];
- }
- }
- }
- foreach ([
- 'sort',
- 'offset',
- 'rowCount',
- 'sortOrder',
- ] as $sortParam) {
- $params[$sortParam] = $$sortParam;
- }
-
- $searchCount = CRM_Campaign_BAO_Campaign::getCampaignSummary($params, TRUE);
- $campaigns = CRM_Campaign_Page_DashBoard::getCampaignSummary($params);
- $iTotal = $searchCount;
-
- if ($searchCount > 0) {
- if ($searchCount < $offset) {
- $offset = 0;
- }
- foreach ($campaigns as $campaignID => $values) {
- foreach ($selectorCols as $col) {
- $searchRows[$campaignID][$col] = $values[$col] ?? NULL;
- }
- }
- }
-
- $selectorElements = $selectorCols;
-
- $iFilteredTotal = $iTotal;
-
- CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
- echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
- CRM_Utils_System::civiExit();
- }
-
- /**
- * This function uses the deprecated v1 datatable api and needs updating. See CRM-16353.
- * @deprecated
- */
- public static function surveyList() {
- //get the search criteria params.
- $searchCriteria = CRM_Utils_Request::retrieve('searchCriteria', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'POST');
- $searchParams = explode(',', $searchCriteria);
-
- $params = $searchRows = [];
- foreach ($searchParams as $param) {
- if (!empty($_POST[$param])) {
- $params[$param] = $_POST[$param];
- }
- }
-
- //this is sequence columns on datatable.
- $selectorCols = [
- 'id',
- 'title',
- 'campaign_id',
- 'campaign',
- 'activity_type_id',
- 'activity_type',
- 'release_frequency',
- 'default_number_of_contacts',
- 'max_number_of_contacts',
- 'is_default',
- 'is_active',
- 'isActive',
- 'result_id',
- 'action',
- 'voterLinks',
- ];
-
- // get the data table params.
- $dataTableParams = [
- 'sEcho' => [
- 'name' => 'sEcho',
- 'type' => 'Integer',
- 'default' => 0,
- ],
- 'offset' => [
- 'name' => 'iDisplayStart',
- 'type' => 'Integer',
- 'default' => 0,
- ],
- 'rowCount' => [
- 'name' => 'iDisplayLength',
- 'type' => 'Integer',
- 'default' => 25,
- ],
- 'sort' => [
- 'name' => 'iSortCol_0',
- 'type' => 'Integer',
- 'default' => 'created_date',
- ],
- 'sortOrder' => [
- 'name' => 'sSortDir_0',
- 'type' => 'String',
- 'default' => 'desc',
- ],
- ];
- foreach ($dataTableParams as $pName => $pValues) {
- $$pName = $pValues['default'];
- if (!empty($_POST[$pValues['name']])) {
- $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']);
- if ($pName == 'sort') {
- $$pName = $selectorCols[$$pName];
- }
- }
- }
- foreach ([
- 'sort',
- 'offset',
- 'rowCount',
- 'sortOrder',
- ] as $sortParam) {
- $params[$sortParam] = $$sortParam;
- }
-
- $surveys = CRM_Campaign_Page_DashBoard::getSurveySummary($params);
- $searchCount = CRM_Campaign_BAO_Survey::getSurveySummary($params, TRUE);
- $iTotal = $searchCount;
-
- if ($searchCount > 0) {
- if ($searchCount < $offset) {
- $offset = 0;
- }
- foreach ($surveys as $surveyID => $values) {
- foreach ($selectorCols as $col) {
- $searchRows[$surveyID][$col] = $values[$col] ?? NULL;
- }
- }
- }
-
- $selectorElements = $selectorCols;
-
- $iFilteredTotal = $iTotal;
-
- CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
- echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
- CRM_Utils_System::civiExit();
- }
-
- /**
- * This function uses the deprecated v1 datatable api and needs updating. See CRM-16353.
- * @deprecated
- */
- public static function petitionList() {
- //get the search criteria params.
- $searchCriteria = CRM_Utils_Request::retrieve('searchCriteria', 'String', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'POST');
- $searchParams = explode(',', $searchCriteria);
-
- $params = $searchRows = [];
- foreach ($searchParams as $param) {
- if (!empty($_POST[$param])) {
- $params[$param] = $_POST[$param];
- }
- }
-
- //this is sequence columns on datatable.
- $selectorCols = [
- 'id',
- 'title',
- 'campaign_id',
- 'campaign',
- 'activity_type_id',
- 'activity_type',
- 'is_default',
- 'is_active',
- 'isActive',
- 'action',
- ];
-
- // get the data table params.
- $dataTableParams = [
- 'sEcho' => [
- 'name' => 'sEcho',
- 'type' => 'Integer',
- 'default' => 0,
- ],
- 'offset' => [
- 'name' => 'iDisplayStart',
- 'type' => 'Integer',
- 'default' => 0,
- ],
- 'rowCount' => [
- 'name' => 'iDisplayLength',
- 'type' => 'Integer',
- 'default' => 25,
- ],
- 'sort' => [
- 'name' => 'iSortCol_0',
- 'type' => 'Integer',
- 'default' => 'created_date',
- ],
- 'sortOrder' => [
- 'name' => 'sSortDir_0',
- 'type' => 'String',
- 'default' => 'desc',
- ],
- ];
- foreach ($dataTableParams as $pName => $pValues) {
- $$pName = $pValues['default'];
- if (!empty($_POST[$pValues['name']])) {
- $$pName = CRM_Utils_Type::escape($_POST[$pValues['name']], $pValues['type']);
- if ($pName == 'sort') {
- $$pName = $selectorCols[$$pName];
- }
- }
- }
- foreach ([
- 'sort',
- 'offset',
- 'rowCount',
- 'sortOrder',
- ] as $sortParam) {
- $params[$sortParam] = $$sortParam;
- }
-
- $petitions = CRM_Campaign_Page_DashBoard::getPetitionSummary($params);
- $searchCount = CRM_Campaign_BAO_Petition::getPetitionSummary($params, TRUE);
- $iTotal = $searchCount;
-
- if ($searchCount > 0) {
- if ($searchCount < $offset) {
- $offset = 0;
- }
- foreach ($petitions as $petitionID => $values) {
- foreach ($selectorCols as $col) {
- $searchRows[$petitionID][$col] = $values[$col] ?? NULL;
- }
- }
- }
-
- $selectorElements = $selectorCols;
-
- $iFilteredTotal = $iTotal;
-
- CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
- echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
- CRM_Utils_System::civiExit();
- }
-
}
diff --git a/CRM/Campaign/Page/DashBoard.php b/CRM/Campaign/Page/DashBoard.php
deleted file mode 100644
index 013ebcec4da8..000000000000
--- a/CRM/Campaign/Page/DashBoard.php
+++ /dev/null
@@ -1,499 +0,0 @@
- [
- 'name' => ts('Edit'),
- 'url' => 'civicrm/campaign/add',
- 'qs' => 'reset=1&action=update&id=%%id%%',
- 'title' => ts('Update Campaign'),
- ],
- CRM_Core_Action::DISABLE => [
- 'name' => ts('Disable'),
- 'title' => ts('Disable Campaign'),
- 'ref' => 'crm-enable-disable',
- ],
- CRM_Core_Action::ENABLE => [
- 'name' => ts('Enable'),
- 'title' => ts('Enable Campaign'),
- 'ref' => 'crm-enable-disable',
- ],
- CRM_Core_Action::DELETE => [
- 'name' => ts('Delete'),
- 'url' => 'civicrm/campaign/add',
- 'qs' => 'action=delete&reset=1&id=%%id%%',
- 'title' => ts('Delete Campaign'),
- ],
- ];
- }
-
- return self::$_campaignActionLinks;
- }
-
- /**
- * @return array
- */
- public static function surveyActionLinks() {
- // check if variable _actionsLinks is populated
- if (!isset(self::$_surveyActionLinks)) {
- self::$_surveyActionLinks = [
- CRM_Core_Action::UPDATE => [
- 'name' => ts('Edit'),
- 'url' => 'civicrm/survey/configure/main',
- 'qs' => 'action=update&id=%%id%%&reset=1',
- 'title' => ts('Update Survey'),
- ],
- CRM_Core_Action::DISABLE => [
- 'name' => ts('Disable'),
- 'ref' => 'crm-enable-disable',
- 'title' => ts('Disable Survey'),
- ],
- CRM_Core_Action::ENABLE => [
- 'name' => ts('Enable'),
- 'ref' => 'crm-enable-disable',
- 'title' => ts('Enable Survey'),
- ],
- CRM_Core_Action::DELETE => [
- 'name' => ts('Delete'),
- 'url' => 'civicrm/survey/delete',
- 'qs' => 'id=%%id%%&reset=1',
- 'title' => ts('Delete Survey'),
- ],
- ];
- }
-
- return self::$_surveyActionLinks;
- }
-
- /**
- * @return array
- */
- public static function petitionActionLinks() {
- if (!isset(self::$_petitionActionLinks)) {
- self::$_petitionActionLinks = self::surveyActionLinks();
- self::$_petitionActionLinks[CRM_Core_Action::UPDATE] = [
- 'name' => ts('Edit'),
- 'url' => 'civicrm/petition/add',
- 'qs' => 'action=update&id=%%id%%&reset=1',
- 'title' => ts('Update Petition'),
- ];
- self::$_petitionActionLinks[CRM_Core_Action::DISABLE] = [
- 'name' => ts('Disable'),
- 'ref' => 'crm-enable-disable',
- 'title' => ts('Disable Petition'),
- ];
- self::$_petitionActionLinks[CRM_Core_Action::ENABLE] = [
- 'name' => ts('Enable'),
- 'ref' => 'crm-enable-disable',
- 'title' => ts('Enable Petition'),
- ];
- self::$_petitionActionLinks[CRM_Core_Action::DELETE] = [
- 'name' => ts('Delete'),
- 'url' => 'civicrm/petition/add',
- 'qs' => 'action=delete&id=%%id%%&reset=1',
- 'title' => ts('Delete Petition'),
- ];
- self::$_petitionActionLinks[CRM_Core_Action::PROFILE] = [
- 'name' => ts('Sign'),
- 'url' => 'civicrm/petition/sign',
- 'qs' => 'sid=%%id%%&reset=1',
- 'title' => ts('Sign Petition'),
- 'fe' => TRUE,
- //CRM_Core_Action::PROFILE is used because there isn't a specific action for sign
- ];
- self::$_petitionActionLinks[CRM_Core_Action::BROWSE] = [
- 'name' => ts('Signatures'),
- 'url' => 'civicrm/activity/search',
- 'qs' => 'survey=%%id%%&force=1',
- 'title' => ts('List the signatures'),
- //CRM_Core_Action::PROFILE is used because there isn't a specific action for sign
- ];
- }
-
- return self::$_petitionActionLinks;
- }
-
- /**
- * @return mixed
- */
- public function browseCampaign() {
- // ensure valid javascript (these must have a value set)
- $this->assign('searchParams', json_encode(NULL));
- $this->assign('campaignTypes', json_encode(NULL));
- $this->assign('campaignStatus', json_encode(NULL));
-
- $this->assign('addCampaignUrl', CRM_Utils_System::url('civicrm/campaign/add', 'reset=1&action=add'));
- $campaignCount = CRM_Campaign_BAO_Campaign::getCampaignCount();
- //don't load find interface when no campaigns in db.
- if (!$campaignCount) {
- $this->assign('hasCampaigns', FALSE);
- return;
- }
- $this->assign('hasCampaigns', TRUE);
-
- //build the ajaxify campaign search and selector.
- $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Search_Campaign', ts('Search Campaigns'));
- $controller->set('searchTab', 'campaign');
- $controller->setEmbedded(TRUE);
- $controller->process();
- return $controller->run();
- }
-
- /**
- * @param array $params
- *
- * @return array
- */
- public static function getCampaignSummary($params = []) {
- $campaignsData = [];
-
- //get the campaigns.
- $campaigns = CRM_Campaign_BAO_Campaign::getCampaignSummary($params);
- if (!empty($campaigns)) {
- $config = CRM_Core_Config::singleton();
- $campaignType = CRM_Campaign_PseudoConstant::campaignType();
- $campaignStatus = CRM_Campaign_PseudoConstant::campaignStatus();
- $properties = [
- 'id',
- 'name',
- 'title',
- 'status_id',
- 'description',
- 'campaign_type_id',
- 'is_active',
- 'start_date',
- 'end_date',
- ];
- foreach ($campaigns as $cmpid => $campaign) {
- foreach ($properties as $prop) {
- $campaignsData[$cmpid][$prop] = $campaign[$prop] ?? NULL;
- }
- $statusId = $campaign['status_id'] ?? NULL;
- $campaignsData[$cmpid]['status'] = $campaignStatus[$statusId] ?? NULL;
- $campaignsData[$cmpid]['campaign_id'] = $campaign['id'];
- $campaignsData[$cmpid]['campaign_type'] = $campaignType[$campaign['campaign_type_id']];
-
- $action = array_sum(array_keys(self::campaignActionLinks()));
- if ($campaign['is_active']) {
- $action -= CRM_Core_Action::ENABLE;
- }
- else {
- $action -= CRM_Core_Action::DISABLE;
- }
-
- $isActive = ts('No');
- if ($campaignsData[$cmpid]['is_active']) {
- $isActive = ts('Yes');
- }
- $campaignsData[$cmpid]['isActive'] = $isActive;
-
- if (!empty($campaignsData[$cmpid]['start_date'])) {
- $campaignsData[$cmpid]['start_date'] = CRM_Utils_Date::customFormat($campaignsData[$cmpid]['start_date'],
- $config->dateformatFull
- );
- }
- if (!empty($campaignsData[$cmpid]['end_date'])) {
- $campaignsData[$cmpid]['end_date'] = CRM_Utils_Date::customFormat($campaignsData[$cmpid]['end_date'],
- $config->dateformatFull
- );
- }
- $campaignsData[$cmpid]['action'] = CRM_Core_Action::formLink(self::campaignActionLinks(),
- $action,
- ['id' => $campaign['id']],
- ts('more'),
- FALSE,
- 'campaign.dashboard.row',
- 'Campaign',
- $campaign['id']
- );
- }
- }
-
- return $campaignsData;
- }
-
- /**
- * @return mixed
- */
- public function browseSurvey() {
- // ensure valid javascript - this must have a value set
- $this->assign('searchParams', json_encode(NULL));
- $this->assign('surveyTypes', json_encode(NULL));
- $this->assign('surveyCampaigns', json_encode(NULL));
-
- $this->assign('addSurveyUrl', CRM_Utils_System::url('civicrm/survey/add', 'reset=1&action=add'));
-
- $surveyCount = CRM_Campaign_BAO_Survey::getSurveyCount();
- //don't load find interface when no survey in db.
- if (!$surveyCount) {
- $this->assign('hasSurveys', FALSE);
- return;
- }
- $this->assign('hasSurveys', TRUE);
-
- //build the ajaxify survey search and selector.
- $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Search_Survey', ts('Search Survey'));
- $controller->set('searchTab', 'survey');
- $controller->setEmbedded(TRUE);
- $controller->process();
- return $controller->run();
- }
-
- /**
- * @param array $params
- *
- * @return array
- */
- public static function getSurveySummary($params = []) {
- $surveysData = [];
-
- //get the survey.
- $config = CRM_Core_Config::singleton();
- $surveys = CRM_Campaign_BAO_Survey::getSurveySummary($params);
- if (!empty($surveys)) {
- $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
- $surveyType = CRM_Campaign_BAO_Survey::getSurveyActivityType();
- foreach ($surveys as $sid => $survey) {
- $surveysData[$sid] = $survey;
- $campaignId = $survey['campaign_id'] ?? NULL;
- $surveysData[$sid]['campaign'] = $campaigns[$campaignId] ?? NULL;
- $surveysData[$sid]['activity_type'] = $surveyType[$survey['activity_type_id']];
- if (!empty($survey['release_frequency'])) {
- $surveysData[$sid]['release_frequency'] = ts('1 Day', ['plural' => '%count Days', 'count' => $survey['release_frequency']]);
- }
-
- $action = array_sum(array_keys(self::surveyActionLinks($surveysData[$sid]['activity_type'])));
- if ($survey['is_active']) {
- $action -= CRM_Core_Action::ENABLE;
- }
- else {
- $action -= CRM_Core_Action::DISABLE;
- }
-
- $isActive = ts('No');
- if ($surveysData[$sid]['is_active']) {
- $isActive = ts('Yes');
- }
- $surveysData[$sid]['isActive'] = $isActive;
-
- // For some reason, 'is_default' is coming as a string.
- $surveysData[$sid]['is_default'] = boolval($surveysData[$sid]['is_default']);
-
- if ($surveysData[$sid]['result_id']) {
- $resultSet = '' . ts('Result Set') . ' ';
- $surveysData[$sid]['result_id'] = $resultSet;
- }
- else {
- $resultUrl = CRM_Utils_System::url("civicrm/survey/configure/results", "action=update&id={$sid}&reset=1");
- $surveysData[$sid]['result_id'] = "(" . ts('Incomplete. Click to configure result set.') . ') ';
- }
- $surveysData[$sid]['action'] = CRM_Core_Action::formLink(self::surveyActionLinks($surveysData[$sid]['activity_type']),
- $action,
- ['id' => $sid],
- ts('more'),
- FALSE,
- 'survey.dashboard.row',
- 'Survey',
- $sid
- );
-
- if (($surveysData[$sid]['activity_type'] ?? NULL) != 'Petition') {
- $surveysData[$sid]['voterLinks'] = CRM_Campaign_BAO_Survey::buildPermissionLinks($sid,
- TRUE,
- ts('more')
- );
- }
-
- if ($reportID = CRM_Campaign_BAO_Survey::getReportID($sid)) {
- $url = CRM_Utils_System::url("civicrm/report/instance/{$reportID}", 'reset=1');
- $surveysData[$sid]['title'] = "{$surveysData[$sid]['title']} ";
- }
- }
- }
-
- return $surveysData;
- }
-
- /**
- * Browse petitions.
- *
- * @return mixed|null
- */
- public function browsePetition() {
- // Ensure valid javascript - this must have a value set
- $this->assign('searchParams', json_encode(NULL));
- $this->assign('petitionCampaigns', json_encode(NULL));
-
- $this->assign('addPetitionUrl', CRM_Utils_System::url('civicrm/petition/add', 'reset=1&action=add'));
-
- $petitionCount = CRM_Campaign_BAO_Petition::getPetitionCount();
- //don't load find interface when no petition in db.
- if (!$petitionCount) {
- $this->assign('hasPetitions', FALSE);
- return NULL;
- }
- $this->assign('hasPetitions', TRUE);
-
- // Build the ajax petition search and selector.
- $controller = new CRM_Core_Controller_Simple('CRM_Campaign_Form_Search_Petition', ts('Search Petition'));
- $controller->set('searchTab', 'petition');
- $controller->setEmbedded(TRUE);
- $controller->process();
- return $controller->run();
- }
-
- /**
- * @param array $params
- *
- * @return array
- */
- public static function getPetitionSummary($params = []) {
- $config = CRM_Core_Config::singleton();
- $petitionsData = [];
-
- //get the petitions.
- $petitions = CRM_Campaign_BAO_Petition::getPetitionSummary($params);
- if (!empty($petitions)) {
- $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
- $petitionType = CRM_Campaign_BAO_Survey::getSurveyActivityType('label', TRUE);
- foreach ($petitions as $pid => $petition) {
- $petitionsData[$pid] = $petition;
- $camapignId = $petition['campaign_id'] ?? NULL;
- $petitionsData[$pid]['campaign'] = $campaigns[$camapignId] ?? NULL;
- $petitionsData[$pid]['activity_type'] = $petitionType[$petition['activity_type_id']];
-
- $action = array_sum(array_keys(self::petitionActionLinks()));
-
- if ($petition['is_active']) {
- $action -= CRM_Core_Action::ENABLE;
- }
- else {
- $action -= CRM_Core_Action::DISABLE;
- }
-
- $isActive = ts('No');
- if ($petitionsData[$pid]['is_active']) {
- $isActive = ts('Yes');
- }
- $petitionsData[$pid]['isActive'] = $isActive;
-
- // For some reason, 'is_default' is coming as a string.
- $petitionsData[$pid]['is_default'] = boolval($petitionsData[$pid]['is_default']);
-
- $petitionsData[$pid]['action'] = CRM_Core_Action::formLink(self::petitionActionLinks(),
- $action,
- ['id' => $pid],
- ts('more'),
- FALSE,
- 'petition.dashboard.row',
- 'Petition',
- $pid
- );
- }
- }
-
- return $petitionsData;
- }
-
- public function browse() {
- $this->_tabs = [
- 'campaign' => ts('Campaigns'),
- 'survey' => ts('Surveys'),
- 'petition' => ts('Petitions'),
- ];
-
- $subPageType = CRM_Utils_Request::retrieve('type', 'String', $this);
- // Load the data for a specific tab
- if ($subPageType) {
- if (!isset($this->_tabs[$subPageType])) {
- CRM_Utils_System::permissionDenied();
- }
- //load the data in tabs.
- $this->{'browse' . ucfirst($subPageType)}();
- }
- // Initialize tabs
- else {
- $this->buildTabs();
- }
- $this->assign('subPageType', ucfirst($subPageType));
- }
-
- /**
- * @return string
- */
- public function run() {
- if (!CRM_Campaign_BAO_Campaign::accessCampaign()) {
- CRM_Utils_System::permissionDenied();
- }
-
- $this->browse();
-
- return parent::run();
- }
-
- public function buildTabs() {
- $allTabs = [];
- foreach ($this->_tabs as $name => $title) {
- $allTabs[$name] = [
- 'title' => $title,
- 'valid' => TRUE,
- 'active' => TRUE,
- 'link' => CRM_Utils_System::url('civicrm/campaign', "reset=1&type=$name"),
- 'extra' => NULL,
- 'template' => NULL,
- 'count' => NULL,
- 'icon' => NULL,
- 'class' => NULL,
- ];
- }
- $allTabs['campaign']['class'] = 'livePage';
- $this->assign('tabHeader', $allTabs);
- CRM_Core_Resources::singleton()
- ->addScriptFile('civicrm', 'templates/CRM/common/TabHeader.js', 1, 'html-header')
- ->addSetting([
- 'tabSettings' => [
- // Tabs should use selectedChild, but Campaign has many legacy links
- 'active' => strtolower($_GET['subPage'] ?? $_GET['selectedChild'] ?? 'campaign'),
- ],
- ]);
- }
-
-}
diff --git a/CRM/Campaign/Page/SurveyType.php b/CRM/Campaign/Page/SurveyType.php
index d1e972df52a7..b72daac2d8f5 100644
--- a/CRM/Campaign/Page/SurveyType.php
+++ b/CRM/Campaign/Page/SurveyType.php
@@ -92,22 +92,26 @@ public function &links() {
'url' => 'civicrm/admin/campaign/surveyType',
'qs' => 'action=update&id=%%id%%&reset=1',
'title' => ts('Edit %1', [1 => $this->_gName]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
CRM_Core_Action::DISABLE => [
'name' => ts('Disable'),
'ref' => 'crm-enable-disable',
'title' => ts('Disable %1', [1 => $this->_gName]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE),
],
CRM_Core_Action::ENABLE => [
'name' => ts('Enable'),
'ref' => 'crm-enable-disable',
'title' => ts('Enable %1', [1 => $this->_gName]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE),
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
'url' => 'civicrm/admin/campaign/surveyType',
'qs' => 'action=delete&id=%%id%%',
'title' => ts('Delete %1 Type', [1 => $this->_gName]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
];
}
diff --git a/CRM/Campaign/xml/Menu/Campaign.xml b/CRM/Campaign/xml/Menu/Campaign.xml
index 5d051df2493b..9e4be74c218b 100644
--- a/CRM/Campaign/xml/Menu/Campaign.xml
+++ b/CRM/Campaign/xml/Menu/Campaign.xml
@@ -1,13 +1,6 @@
- -
-
civicrm/campaign
- Campaign Dashboard
- CRM_Campaign_Page_DashBoard
- administer CiviCampaign;manage campaign
- CiviCampaign
-
-
civicrm/campaign/add
New Campaign
diff --git a/CRM/Case/BAO/Case.php b/CRM/Case/BAO/Case.php
index d8aa69d2e82b..d6d3c55cd9d4 100644
--- a/CRM/Case/BAO/Case.php
+++ b/CRM/Case/BAO/Case.php
@@ -3019,33 +3019,47 @@ public static function buildOptions($fieldName, $context = NULL, $props = []) {
* @inheritDoc
*/
public function addSelectWhereClause(string $entityName = NULL, int $userId = NULL, array $conditions = []): array {
+ $administerCases = CRM_Core_Permission::check('administer CiviCase', $userId);
+ $viewMyCases = CRM_Core_Permission::check('access my cases and activities', $userId);
+ $viewAllCases = CRM_Core_Permission::check('access all cases and activities', $userId);
+
// We always return an array with these keys, even if they are empty,
// because this tells the query builder that we have considered these fields for acls
$clauses = [
'id' => [],
// Only case admins can view deleted cases
- 'is_deleted' => CRM_Core_Permission::check('administer CiviCase') ? [] : ["= 0"],
+ 'is_deleted' => $administerCases ? [] : ['= 0'],
];
- // Ensure the user has permission to view the case client
- $contactClause = CRM_Utils_SQL::mergeSubquery('Contact');
- if ($contactClause) {
- $contactClause = implode(' AND contact_id ', $contactClause);
- $clauses['id'][] = "IN (SELECT case_id FROM civicrm_case_contact WHERE contact_id $contactClause)";
- }
- // The api gatekeeper ensures the user has at least "access my cases and activities"
- // so if they do not have permission to see all cases we'll assume they can only access their own
- if (!CRM_Core_Permission::check('access all cases and activities')) {
- $user = (int) CRM_Core_Session::getLoggedInContactID();
- $clauses['id'][] = "IN (
- SELECT r.case_id FROM civicrm_relationship r, civicrm_case_contact cc WHERE r.is_active = 1 AND cc.case_id = r.case_id AND (
- (r.contact_id_a = cc.contact_id AND r.contact_id_b = $user) OR (r.contact_id_b = cc.contact_id AND r.contact_id_a = $user)
- )
- )";
+
+ // No CiviCase access
+ if (!$viewAllCases && !$viewMyCases) {
+ $clauses['id'][] = 'IS NULL';
+ }
+ else {
+ // Enforce permission to view the case client
+ $contactClause = CRM_Utils_SQL::mergeSubquery('Contact');
+ if ($contactClause) {
+ $contactClause = implode(' AND contact_id ', $contactClause);
+ $clauses['id'][] = "IN (SELECT case_id FROM civicrm_case_contact WHERE contact_id $contactClause)";
+ }
+ // User can only access their own cases
+ if (!$viewAllCases) {
+ $clauses['id'][] = self::getAccessMyCasesClause($userId);
+ }
}
CRM_Utils_Hook::selectWhereClause($this, $clauses, $userId, $conditions);
return $clauses;
}
+ private static function getAccessMyCasesClause(int $userId = NULL): string {
+ $user = $userId ?? (int) CRM_Core_Session::getLoggedInContactID();
+ return "IN (
+ SELECT r.case_id FROM civicrm_relationship r, civicrm_case_contact cc WHERE r.is_active = 1 AND cc.case_id = r.case_id AND (
+ (r.contact_id_a = cc.contact_id AND r.contact_id_b = $user) OR (r.contact_id_b = cc.contact_id AND r.contact_id_a = $user)
+ )
+ )";
+ }
+
/**
* CRM-20308: Method to get the contact id to use as from contact for email copy
* 1. Activity Added by Contact's email address
diff --git a/CRM/Case/DAO/Case.php b/CRM/Case/DAO/Case.php
index 08d048818b67..cc6544671c1e 100644
--- a/CRM/Case/DAO/Case.php
+++ b/CRM/Case/DAO/Case.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Case/Case.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:83be6db09d4f5220f74ccc72149dcab6)
+ * (GenCodeChecksum:b5dbbb96b15e9ff288890017d324b984)
*/
/**
@@ -45,6 +45,15 @@ class CRM_Case_DAO_Case extends CRM_Core_DAO {
*/
public static $_log = TRUE;
+ /**
+ * Paths for accessing this entity in the UI.
+ *
+ * @var string[]
+ */
+ protected static $_paths = [
+ 'view' => 'civicrm/contact/view/case?action=view&reset=1&id=[id]',
+ ];
+
/**
* Unique Case ID
*
diff --git a/CRM/Case/Form/Activity.php b/CRM/Case/Form/Activity.php
index e959a9423291..6a82870900c9 100644
--- a/CRM/Case/Form/Activity.php
+++ b/CRM/Case/Form/Activity.php
@@ -203,10 +203,7 @@ public function setDefaultValues() {
}
$this->assign('targetContactValues', empty($targetContactValues) ? FALSE : $targetContactValues);
- if (isset($this->_encounterMedium)) {
- $this->_defaults['medium_id'] = $this->_encounterMedium;
- }
- elseif (empty($this->_defaults['medium_id'])) {
+ if (empty($this->_defaults['medium_id'])) {
// set default encounter medium CRM-4816
$medium = CRM_Core_OptionGroup::values('encounter_medium', FALSE, FALSE, FALSE, 'AND is_default = 1');
if (count($medium) == 1) {
@@ -266,22 +263,13 @@ public function buildQuickForm() {
$this->assign('urlPath', 'civicrm/case/activity');
- $encounterMediums = CRM_Case_PseudoConstant::encounterMedium();
-
if ($this->_activityTypeFile == 'OpenCase' && $this->_action == CRM_Core_Action::UPDATE) {
$this->getElement('activity_date_time')->freeze();
-
- if ($this->_activityId) {
- // Fixme: what's the justification for this? It seems like it is just re-adding an option in case it is the default and disabled.
- // Is that really a big problem?
- $this->_encounterMedium = CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $this->_activityId, 'medium_id');
- if (!array_key_exists($this->_encounterMedium, $encounterMediums)) {
- $encounterMediums[$this->_encounterMedium] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'medium_id', $this->_encounterMedium);
- }
- }
}
- $this->add('select', 'medium_id', ts('Medium'), $encounterMediums, TRUE);
+ $this->addSelect('medium_id');
+
+ // Related contacts
$i = 0;
foreach ($this->_caseId as $key => $val) {
$this->_relatedContacts[] = $rgc = CRM_Case_BAO_Case::getRelatedAndGlobalContacts($val);
@@ -394,7 +382,7 @@ public function postProcess($params = NULL) {
// store the submitted values in an array
// Explanation for why we only check the is_unittest element: Prior to adding that check, there was no check and so any $params passed in would have been overwritten. Just in case somebody is passing in some non-null params and that broken code would have inadvertently been working, we can maintain backwards compatibility by only checking for the is_unittest parameter, and so that broken code will still work. At the same time this allows unit tests to pass in a $params without it getting overwritten. See also PR #2077 for some discussion of when the $params parameter was added as a passed in variable.
if (empty($params['is_unittest'])) {
- $params = $this->controller->exportValues($this->_name);
+ $params = $this->getSubmittedValues();
}
//set parent id if its edit mode
diff --git a/CRM/Case/Form/CaseView.php b/CRM/Case/Form/CaseView.php
index 24c0f4552c7a..6ef33b6d899c 100644
--- a/CRM/Case/Form/CaseView.php
+++ b/CRM/Case/Form/CaseView.php
@@ -49,6 +49,8 @@ class CRM_Case_Form_CaseView extends CRM_Core_Form {
*/
public $_contactID;
+ private $_caseClients;
+
/**
* ID of case being viewed
*
@@ -100,9 +102,21 @@ public function preProcess() {
$this->_hasAccessToAllCases = CRM_Core_Permission::check('access all cases and activities');
$this->assign('hasAccessToAllCases', $this->_hasAccessToAllCases);
- $this->assign('contactID', $this->_contactID = (int) $this->get('cid'));
$this->assign('caseID', $this->_caseID = (int) $this->get('id'));
+ $this->_caseClients = CRM_Case_BAO_Case::getContactNames($this->_caseID);
+
+ $cid = $this->get('cid');
+
+ // If no cid supplied, use first case client
+ if (!$cid) {
+ $cid = array_keys($this->_caseClients)[0];
+ }
+ elseif (!isset($this->_caseClients[$cid])) {
+ CRM_Core_Error::statusBounce("Contact $cid not a client of case " . $this->_caseID);
+ }
+ $this->assign('contactID', $this->_contactID = (int) $cid);
+
// Access check.
if (!CRM_Case_BAO_Case::accessCase($this->_caseID, FALSE)) {
CRM_Core_Error::statusBounce(ts('You do not have permission to access this case.'));
@@ -147,7 +161,7 @@ public function preProcess() {
"action=view&reset=1&id={$this->_caseID}&cid={$this->_contactID}&context=home"
);
- $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactID);
+ $displayName = $this->_caseClients[$this->_contactID]['display_name'];
$this->assign('displayName', $displayName);
$this->setTitle($displayName . ' - ' . $caseType);
@@ -366,7 +380,7 @@ public function buildQuickForm() {
$this->assign('caseRelationships', $caseRelationships);
//also add client as role. CRM-4438
- $caseRoles['client'] = CRM_Case_BAO_Case::getContactNames($this->_caseID);
+ $caseRoles['client'] = $this->_caseClients;
$this->assign('caseRoles', $caseRoles);
@@ -443,16 +457,16 @@ public function buildQuickForm() {
'entity_table' => 'civicrm_case',
'tag_id.parent_id.is_tagset' => 1,
'options' => ['limit' => 0],
- 'return' => ["tag_id.parent_id", "tag_id.parent_id.name", "tag_id.name"],
+ 'return' => ["tag_id.parent_id", "tag_id.parent_id.label", "tag_id.label"],
]);
foreach ($tagSetItems['values'] as $tag) {
$tagSetTags += [
$tag['tag_id.parent_id'] => [
- 'name' => $tag['tag_id.parent_id.name'],
+ 'label' => $tag['tag_id.parent_id.label'],
'items' => [],
],
];
- $tagSetTags[$tag['tag_id.parent_id']]['items'][] = $tag['tag_id.name'];
+ $tagSetTags[$tag['tag_id.parent_id']]['items'][] = $tag['tag_id.label'];
}
}
$this->assign('tagSetTags', $tagSetTags);
diff --git a/CRM/Case/Page/Tab.php b/CRM/Case/Page/Tab.php
index 8c91b6ffb5ea..3dc37a7e6bb6 100644
--- a/CRM/Case/Page/Tab.php
+++ b/CRM/Case/Page/Tab.php
@@ -61,11 +61,6 @@ public function preProcess() {
CRM_Contact_Page_View::checkUserPermission($this);
}
}
- else {
- if ($this->_action & CRM_Core_Action::VIEW) {
- CRM_Core_Error::statusBounce(ts('Contact Id is required for view action.'));
- }
- }
$activityTypes = CRM_Case_PseudoConstant::caseActivityType();
diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php
index b9b83e95d819..fc3435e30f4f 100644
--- a/CRM/Contact/BAO/Contact.php
+++ b/CRM/Contact/BAO/Contact.php
@@ -119,7 +119,10 @@ public static function add(&$params) {
// CRM-7925
throw new CRM_Core_Exception(ts('The Contact Sub Type does not match the Contact type for this record'));
}
- $params['contact_sub_type'] = CRM_Utils_Array::implodePadded($params['contact_sub_type']);
+ // Ensure value is an array so it can be handled properly by `copyValues()`
+ if (is_string($params['contact_sub_type'])) {
+ $params['contact_sub_type'] = CRM_Core_DAO::unSerializeField($params['contact_sub_type'], self::fields()['contact_sub_type']['serialize']);
+ }
}
}
@@ -2925,8 +2928,8 @@ public static function contextMenu($contactId = NULL) {
'key' => 'note',
'tab' => 'note',
'class' => 'medium-popup',
- 'href' => CRM_Utils_System::url('civicrm/contact/view/note',
- 'reset=1&action=add'
+ 'href' => CRM_Utils_System::url('civicrm/note',
+ 'reset=1&action=add&entity_table=civicrm_contact&entity_id=' . $contactId
),
'permissions' => ['edit all contacts'],
],
@@ -3581,6 +3584,7 @@ public static function getEntityRefCreateLinks($appendProfiles = []) {
public static function getEntityRefFilters() {
return [
['key' => 'contact_type', 'value' => ts('Contact Type')],
+ ['key' => 'email', 'value' => ts('Email'), 'entity' => 'Email', 'type' => 'text'],
['key' => 'group', 'value' => ts('Group'), 'entity' => 'GroupContact'],
['key' => 'tag', 'value' => ts('Tag'), 'entity' => 'EntityTag'],
['key' => 'city', 'value' => ts('City'), 'type' => 'text', 'entity' => 'Address'],
diff --git a/CRM/Contact/BAO/ContactType.php b/CRM/Contact/BAO/ContactType.php
index 477bb09d06f8..de18235c9644 100644
--- a/CRM/Contact/BAO/ContactType.php
+++ b/CRM/Contact/BAO/ContactType.php
@@ -69,7 +69,7 @@ public static function basicTypeInfo($includeInactive = FALSE) {
* @throws \CRM_Core_Exception
* @throws \Civi\API\Exception\UnauthorizedException
*/
- public static function basicTypes($all = FALSE) {
+ public static function basicTypes($all = FALSE): array {
return array_keys(self::basicTypeInfo($all));
}
@@ -849,15 +849,26 @@ public static function getAllContactTypes() {
$contactTypes[$name]['parent_label'] = $contactType['parent_id'] ? $parents[$contactType['parent_id']]['label'] : NULL;
// Cast int/bool types.
$contactTypes[$name]['id'] = (int) $contactType['id'];
- $contactTypes[$name]['parent_id'] = $contactType['parent_id'] ? (int) $contactType['parent_id'] : NULL;
+ $contactTypes[$name]['parent_id'] = ((int) $contactType['parent_id']) ?: NULL;
$contactTypes[$name]['is_active'] = (bool) $contactType['is_active'];
$contactTypes[$name]['is_reserved'] = (bool) $contactType['is_reserved'];
+ $contactTypes[$name]['icon'] = $contactType['icon'] ?? $parents[$contactType['parent_id']]['icon'] ?? NULL;
}
$cache->set($cacheKey, $contactTypes);
}
return $contactTypes;
}
+ /**
+ * Get contact type by name
+ *
+ * @param string $name
+ * @return array|null
+ */
+ public static function getContactType(string $name): ?array {
+ return self::getAllContactTypes()[$name] ?? NULL;
+ }
+
/**
* @param string $entityName
* @param string $action
diff --git a/CRM/Contact/BAO/Group.php b/CRM/Contact/BAO/Group.php
index 3a5b8b7b8196..7c777557d7c5 100644
--- a/CRM/Contact/BAO/Group.php
+++ b/CRM/Contact/BAO/Group.php
@@ -344,9 +344,11 @@ public static function create(&$params) {
'parents' => NULL,
];
+ // Fill title and frontend_title if not supplied
+ if (empty($params['id']) && empty($params['title'])) {
+ $params['title'] = $params['frontend_title'] ?? $params['name'];
+ }
if (empty($params['id']) && empty($params['frontend_title'])) {
- // If we were calling writeRecord it would handle this, but we need
- // to migrate the other bits of magic.
$params['frontend_title'] = $params['title'];
}
$hook = empty($params['id']) ? 'create' : 'edit';
@@ -388,6 +390,8 @@ public static function create(&$params) {
// form the name only if missing: CRM-627
$nameParam = $params['name'] ?? NULL;
+ // If we were calling writeRecord it would handle this, but we need
+ // to migrate the other bits of magic.
if (!$nameParam && empty($params['id'])) {
$params['name'] = CRM_Utils_String::titleToVar($params['title']);
}
diff --git a/CRM/Contact/BAO/GroupNesting.php b/CRM/Contact/BAO/GroupNesting.php
index f480e44566e5..4e3f17cee7fa 100644
--- a/CRM/Contact/BAO/GroupNesting.php
+++ b/CRM/Contact/BAO/GroupNesting.php
@@ -27,7 +27,7 @@ class CRM_Contact_BAO_GroupNesting extends CRM_Contact_DAO_GroupNesting {
*/
public static function create($params) {
$hook = empty($params['id']) ? 'create' : 'edit';
- CRM_Utils_Hook::pre($hook, 'GroupNesting', CRM_Utils_Array::value('id', $params), $params);
+ CRM_Utils_Hook::pre($hook, 'GroupNesting', $params['id'] ?? NULL, $params);
$dao = new CRM_Contact_BAO_GroupNesting();
$dao->copyValues($params);
if (empty($params['id'])) {
diff --git a/CRM/Contact/BAO/Individual.php b/CRM/Contact/BAO/Individual.php
index 7d4ea9875a47..200c7b54d780 100644
--- a/CRM/Contact/BAO/Individual.php
+++ b/CRM/Contact/BAO/Individual.php
@@ -31,12 +31,12 @@ public function __construct() {
*
* @param array $params
* (reference ) an assoc array of name/value pairs.
- * @param CRM_Contact_BAO_Contact $contact
+ * @param CRM_Contact_DAO_Contact $contact
* Contact object.
*
- * @return CRM_Contact_BAO_Contact
+ * @return CRM_Contact_DAO_Contact
*/
- public static function format(&$params, &$contact) {
+ public static function format(&$params, $contact) {
if (!self::dataExists($params)) {
return NULL;
}
@@ -59,13 +59,8 @@ public static function format(&$params, &$contact) {
$formalTitle = CRM_Utils_Array::value('formal_title', $params, '');
// get prefix and suffix names
- $prefix = $suffix = NULL;
- if ($prefix_id) {
- $params['individual_prefix'] = $prefix = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'prefix_id', $prefix_id);
- }
- if ($suffix_id) {
- $params['individual_suffix'] = $suffix = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'suffix_id', $suffix_id);
- }
+ $params['prefix_id:label'] = $prefix = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'prefix_id', $prefix_id);
+ $params['suffix_id:label'] = $suffix = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', 'suffix_id', $suffix_id);
$individual = NULL;
if ($contact->id) {
@@ -87,12 +82,12 @@ public static function format(&$params, &$contact) {
}
}
- foreach (['prefix', 'suffix'] as $name) {
- $dbName = "{$name}_id";
- $value = $individual->$dbName;
- if ($value && !empty($params['preserveDBName'])) {
- $useDBNames[] = $name;
- }
+ if ($individual->suffix_id && !empty($params['preserveDBName'])) {
+ $useDBNames[] = 'suffix_id';
+ }
+
+ if ($individual->prefix_id && !empty($params['preserveDBName'])) {
+ $useDBNames[] = 'prefix_id';
}
if ($individual->formal_title && !empty($params['preserveDBName'])) {
@@ -168,8 +163,8 @@ public static function format(&$params, &$contact) {
'middle_name' => $middleName,
'last_name' => $lastName,
'nick_name' => $nickName,
- 'individual_suffix' => $suffix,
- 'individual_prefix' => $prefix,
+ 'suffix_id:label' => $suffix,
+ 'prefix_id:label' => $prefix,
'prefix_id' => $prefix_id,
'suffix_id' => $suffix_id,
'formal_title' => $formalTitle,
diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php
index 23499c9219b4..6fb4936ad15f 100644
--- a/CRM/Contact/BAO/Query.php
+++ b/CRM/Contact/BAO/Query.php
@@ -583,10 +583,10 @@ public function initialize($apiEntity = NULL) {
// Unit test coverage in api_v3_FinancialTypeACLTest::testGetACLContribution.
$clauses = [];
if ($component === 'contribution') {
- $clauses = CRM_Contribute_BAO_Contribution::getSelectWhereClause();
+ $clauses = array_filter(CRM_Contribute_BAO_Contribution::getSelectWhereClause());
}
if ($component === 'membership') {
- $clauses = CRM_Member_BAO_Membership::getSelectWhereClause();
+ $clauses = array_filter(CRM_Member_BAO_Membership::getSelectWhereClause());
}
if ($clauses) {
$this->_whereClause .= ' AND ' . implode(' AND ', $clauses);
@@ -4247,7 +4247,7 @@ public function relationship(&$values) {
if (!empty($relQill)) {
$relQill .= ' OR ';
}
- $relQill .= CRM_Utils_Array::value($rel, $allRelationshipType);
+ $relQill .= $allRelationshipType[$rel] ?? '';
}
$this->_qill[$grouping][] = 'Relationship Type(s) ' . $relQill . " ( " . implode(", ", $qillNames) . " )";
}
@@ -5077,27 +5077,12 @@ public function generatePermissionClause($onlyDeleted = FALSE, $count = FALSE) {
}
}
+ // Add ACL permission clause generated by the BAO. This is the same clause used by API::get.
+ // TODO: Why only activities?
if (isset($this->_tables['civicrm_activity'])) {
- $bao = new CRM_Activity_BAO_Activity();
- $clauses = $subclauses = [];
- foreach ($bao->addSelectWhereClause() as $field => $vals) {
- if ($vals && $field !== 'id') {
- foreach ($vals as $val) {
- $clauses[] = $bao->tableName() . ".$field " . $val;
- }
- }
- elseif ($vals) {
- $subclauses[] = "$field " . implode(" AND $field ", (array) $vals);
- }
- }
- if ($subclauses) {
- $clauses[] = $bao->tableName() . '.`id` IN (SELECT `id` FROM `' . $bao->tableName() . '` WHERE ' . implode(' AND ', $subclauses) . ')';
- }
- if (!empty($clauses) && $this->_permissionWhereClause) {
- $this->_permissionWhereClause .= ' AND (' . implode(' AND ', $clauses) . ')';
- }
- elseif (!empty($clauses)) {
- $this->_permissionWhereClause .= '(' . implode(' AND ', $clauses) . ')';
+ $clauses = array_filter(CRM_Activity_BAO_Activity::getSelectWhereClause());
+ if ($clauses) {
+ $this->_permissionWhereClause .= ($this->_permissionWhereClause ? ' AND ' : '') . '(' . implode(' AND ', $clauses) . ')';
}
}
}
@@ -6217,7 +6202,7 @@ public static function buildQillForFieldValue(
$pseudoOptions = CRM_Core_PseudoConstant::worldRegion();
}
elseif ($daoName == 'CRM_Event_DAO_Event' && $fieldName == 'id') {
- $checkPermission = CRM_Utils_Array::value('check_permission', $pseudoExtraParam, TRUE);
+ $checkPermission = $pseudoExtraParam['check_permission'] ?? TRUE;
$pseudoOptions = CRM_Event_BAO_Event::getEvents(0, $fieldValue, TRUE, $checkPermission, TRUE);
}
elseif ($fieldName == 'contribution_product_id') {
@@ -6452,7 +6437,7 @@ protected function prepareOrderBy($sort, $sortOrder) {
// is not declared for them.
// @todo so far only integer fields are being handled. If we add string fields we need to look at
// escaping.
- $pseudoConstantMetadata = CRM_Utils_Array::value('pseudoconstant', $fieldSpec, FALSE);
+ $pseudoConstantMetadata = $fieldSpec['pseudoconstant'] ?? FALSE;
if (!empty($pseudoConstantMetadata)
) {
if (!empty($pseudoConstantMetadata['optionGroupName'])
diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php
index 6405520474f7..9d231e0fe40e 100644
--- a/CRM/Contact/BAO/Relationship.php
+++ b/CRM/Contact/BAO/Relationship.php
@@ -1807,14 +1807,9 @@ public static function membershipTypeToRelationshipTypes(&$params, $direction =
}
/**
- * Wrapper for contact relationship selector.
+ * @deprecated since 5.68. Will be removed around 5.74.
*
- * @param array $params
- * Associated array for params record id.
- *
- * @return array
- * associated array of contact relationships
- * @throws \Exception
+ * Only-used-by-user-dashboard.
*/
public static function getContactRelationshipSelector(&$params) {
// format the params
@@ -1957,7 +1952,9 @@ public static function getContactRelationshipSelector(&$params) {
}
/**
- * @return array
+ * @deprecated since 5.68. Will be removed around 5.74.
+ *
+ * Only-used-by-user-dashboard.
*/
public static function getColumnHeaders() {
return [
diff --git a/CRM/Contact/DAO/Contact.php b/CRM/Contact/DAO/Contact.php
index edae63298bea..af30aab877b0 100644
--- a/CRM/Contact/DAO/Contact.php
+++ b/CRM/Contact/DAO/Contact.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contact/Contact.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:4066902548c1bc5ba4358b9e0195a3fa)
+ * (GenCodeChecksum:0470d0df786c3ac33a435555a3d026fb)
*/
/**
@@ -604,7 +604,6 @@ public static function &fields() {
],
'where' => 'civicrm_contact.contact_type',
'export' => TRUE,
- 'contactType' => NULL,
'table_name' => 'civicrm_contact',
'entity' => 'Contact',
'bao' => 'CRM_Contact_BAO_Contact',
diff --git a/CRM/Contact/DAO/DashboardContact.php b/CRM/Contact/DAO/DashboardContact.php
index 3e298084bb58..aff797b875d6 100644
--- a/CRM/Contact/DAO/DashboardContact.php
+++ b/CRM/Contact/DAO/DashboardContact.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contact/DashboardContact.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:73ab6a9a4f5d372c85b888aae2abe826)
+ * (GenCodeChecksum:2b31333980964ba3394f0c71cc764a9d)
*/
/**
@@ -67,7 +67,7 @@ class CRM_Contact_DAO_DashboardContact extends CRM_Core_DAO {
/**
* Is this widget active?
*
- * @var bool|string|null
+ * @var bool|string
* (SQL type: tinyint)
* Note that values will be retrieved from the database as a string.
*/
@@ -219,6 +219,7 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_BOOLEAN,
'title' => ts('Dashlet is Active?'),
'description' => ts('Is this widget active?'),
+ 'required' => TRUE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
diff --git a/CRM/Contact/DAO/Relationship.php b/CRM/Contact/DAO/Relationship.php
index 32b8f3e61be2..ea5624a36f46 100644
--- a/CRM/Contact/DAO/Relationship.php
+++ b/CRM/Contact/DAO/Relationship.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contact/Relationship.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:053ca157abcac8e7f4c8ab55425df5ff)
+ * (GenCodeChecksum:e6e709da33773d09d7e788d21c64437b)
*/
/**
@@ -423,6 +423,11 @@ public static function &fields() {
],
'pseudoconstant' => [
'callback' => 'CRM_Core_SelectValues::getPermissionedRelationshipOptions',
+ 'suffixes' => [
+ 'name',
+ 'label',
+ 'icon',
+ ],
],
'add' => '2.1',
],
@@ -449,6 +454,11 @@ public static function &fields() {
],
'pseudoconstant' => [
'callback' => 'CRM_Core_SelectValues::getPermissionedRelationshipOptions',
+ 'suffixes' => [
+ 'name',
+ 'label',
+ 'icon',
+ ],
],
'add' => '2.1',
],
diff --git a/CRM/Contact/DAO/RelationshipCache.php b/CRM/Contact/DAO/RelationshipCache.php
index 060f18063798..5486d1c3b90f 100644
--- a/CRM/Contact/DAO/RelationshipCache.php
+++ b/CRM/Contact/DAO/RelationshipCache.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contact/RelationshipCache.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:422520600ff998c1a9203004ae958e8c)
+ * (GenCodeChecksum:9170513963860f5b9cadce190a68b8bf)
*/
/**
@@ -43,6 +43,7 @@ class CRM_Contact_DAO_RelationshipCache extends CRM_Core_DAO {
* @var string[]
*/
protected static $_paths = [
+ 'add' => 'civicrm/contact/view/rel?cid=[near_contact_id]&action=add&reset=1',
'view' => 'civicrm/contact/view/rel?action=view&reset=1&cid=[near_contact_id]&id=[relationship_id]',
'update' => 'civicrm/contact/view/rel?action=update&reset=1&cid=[near_contact_id]&id=[relationship_id]&rtype=[orientation]',
'delete' => 'civicrm/contact/view/rel?action=delete&reset=1&cid=[near_contact_id]&id=[relationship_id]',
diff --git a/CRM/Contact/Form/Contact.php b/CRM/Contact/Form/Contact.php
index b1395a93c85c..0b0aec7ab16f 100644
--- a/CRM/Contact/Form/Contact.php
+++ b/CRM/Contact/Form/Contact.php
@@ -501,10 +501,7 @@ public function blockSetDefaults(&$defaults) {
// make we require one primary block, CRM-5505
if ($updateMode) {
if (!$hasPrimary) {
- $hasPrimary = CRM_Utils_Array::value(
- 'is_primary',
- CRM_Utils_Array::value($instance, $defaults[$name])
- );
+ $hasPrimary = !empty($defaults[$name][$instance]['is_primary']);
}
continue;
}
@@ -892,7 +889,7 @@ public function buildQuickForm() {
'isDefault' => TRUE,
],
];
- if (CRM_Core_Permission::check('add contacts')) {
+ if (!$this->_contactId && CRM_Core_Permission::check('add contacts')) {
$buttons[] = [
'type' => 'upload',
'name' => ts('Save and New'),
@@ -987,7 +984,7 @@ public function postProcess() {
}
//get the submitted values in an array
- $params = $this->controller->exportValues($this->_name);
+ $params = $this->getSubmittedValues();
if (!isset($params['preferred_communication_method'])) {
// If this field is empty QF will trim it so we have to add it in.
$params['preferred_communication_method'] = 'null';
@@ -1060,7 +1057,7 @@ public function postProcess() {
if (array_key_exists('CommunicationPreferences', $this->_editOptions)) {
// this is a chekbox, so mark false if we dont get a POST value
- $params['is_opt_out'] = CRM_Utils_Array::value('is_opt_out', $params, FALSE);
+ $params['is_opt_out'] = $params['is_opt_out'] ?? FALSE;
CRM_Utils_Array::formatArrayKeys($params['preferred_communication_method']);
}
@@ -1294,15 +1291,15 @@ public static function checkDuplicateContacts(&$fields, &$errors, $contactID, $c
for ($i = 0; $i < count($contactLinks['rows']); $i++) {
$row .= ' ';
$row .= ' ';
- $row .= CRM_Utils_Array::value('display_name', $contactLinks['rows'][$i]);
+ $row .= $contactLinks['rows'][$i]['display_name'] ?? '';
$row .= ' ';
$row .= ' ';
- $row .= CRM_Utils_Array::value('primary_email', $contactLinks['rows'][$i]);
+ $row .= $contactLinks['rows'][$i]['primary_email'] ?? '';
$row .= ' ';
$row .= ' ';
- $row .= CRM_Utils_Array::value('view', $contactLinks['rows'][$i]);
- $row .= CRM_Utils_Array::value('edit', $contactLinks['rows'][$i]);
- $row .= CRM_Utils_Array::value('merge', $contactLinks['rows'][$i]);
+ $row .= $contactLinks['rows'][$i]['view'] ?? '';
+ $row .= $contactLinks['rows'][$i]['edit'] ?? '';
+ $row .= $contactLinks['rows'][$i]['merge'] ?? '';
$row .= ' ';
$row .= ' ';
}
@@ -1413,7 +1410,7 @@ public static function parseAddress(&$params) {
$streetAddress .= ' ';
}
}
- $streetAddress .= CRM_Utils_Array::value($fld, $address);
+ $streetAddress .= $address[$fld] ?? '';
}
$address['street_address'] = trim($streetAddress);
$parseSuccess[$instance] = TRUE;
diff --git a/CRM/Contact/Form/Edit/Address.php b/CRM/Contact/Form/Edit/Address.php
index 8b88bb49c286..4c82a7ff5134 100644
--- a/CRM/Contact/Form/Edit/Address.php
+++ b/CRM/Contact/Form/Edit/Address.php
@@ -296,7 +296,7 @@ public static function setDefaultValues(&$defaults, &$form) {
$streetAddress .= ' ';
}
}
- $streetAddress .= CRM_Utils_Array::value($fld, $address);
+ $streetAddress .= $address[$fld] ?? '';
}
$streetAddress = trim($streetAddress);
if (!empty($streetAddress)) {
diff --git a/CRM/Contact/Form/Inline/CommunicationPreferences.php b/CRM/Contact/Form/Inline/CommunicationPreferences.php
index 6452b0b02e47..f65942b56ffe 100644
--- a/CRM/Contact/Form/Inline/CommunicationPreferences.php
+++ b/CRM/Contact/Form/Inline/CommunicationPreferences.php
@@ -65,7 +65,7 @@ public function postProcess() {
// Process / save communication preferences
// this is a chekbox, so mark false if we dont get a POST value
- $params['is_opt_out'] = CRM_Utils_Array::value('is_opt_out', $params, FALSE);
+ $params['is_opt_out'] = $params['is_opt_out'] ?? FALSE;
$params['contact_type'] = $this->_contactType;
$params['contact_id'] = $this->_contactId;
diff --git a/CRM/Contact/Form/Inline/CustomData.php b/CRM/Contact/Form/Inline/CustomData.php
index d8e92f86bbfb..96247fa48459 100644
--- a/CRM/Contact/Form/Inline/CustomData.php
+++ b/CRM/Contact/Form/Inline/CustomData.php
@@ -72,7 +72,7 @@ public function setDefaultValues() {
public function postProcess() {
// Process / save custom data
// Get the form values and groupTree
- $params = $this->controller->exportValues($this->_name);
+ $params = $this->getSubmittedValues();
CRM_Core_BAO_CustomValueTable::postProcess($params,
'civicrm_contact',
$this->_contactId,
diff --git a/CRM/Contact/Form/Relationship.php b/CRM/Contact/Form/Relationship.php
index 47116d7d1759..7001592c6bc0 100644
--- a/CRM/Contact/Form/Relationship.php
+++ b/CRM/Contact/Form/Relationship.php
@@ -403,10 +403,6 @@ public function postProcess() {
// Refresh contact tabs which might have been affected
$this->ajaxResponse = [
'reloadBlocks' => ['#crm-contactinfo-content'],
- 'updateTabs' => [
- '#tab_member' => CRM_Contact_BAO_Contact::getCountComponent('membership', $this->_contactId),
- '#tab_contribute' => CRM_Contact_BAO_Contact::getCountComponent('contribution', $this->_contactId),
- ],
];
}
@@ -493,7 +489,7 @@ public static function getRelationshipTypeMetadata($relationshipList) {
$jsData[$id] = array_filter(array_intersect_key($allRelationshipNames[$id], $whatWeWant));
// Add user-friendly placeholder
foreach (['a', 'b'] as $x) {
- $type = !empty($jsData[$id]["contact_sub_type_$x"]) ? $jsData[$id]["contact_sub_type_$x"] : CRM_Utils_Array::value("contact_type_$x", $jsData[$id]);
+ $type = !empty($jsData[$id]["contact_sub_type_$x"]) ? $jsData[$id]["contact_sub_type_$x"] : (CRM_Utils_Array::value("contact_type_$x", $jsData[$id]));
$jsData[$id]["placeholder_$x"] = $type ? ts('- select %1 -', [strtolower($contactTypes[$type]['label'])]) : ts('- select contact -');
}
}
@@ -579,8 +575,8 @@ private function preparePostProcessParameters($values) {
}
// If this is a b_a relationship these form elements are flipped
- $params['is_permission_a_b'] = CRM_Utils_Array::value("is_permission_{$a}_{$b}", $values, 0);
- $params['is_permission_b_a'] = CRM_Utils_Array::value("is_permission_{$b}_{$a}", $values, 0);
+ $params['is_permission_a_b'] = $values["is_permission_{$a}_{$b}"] ?? 0;
+ $params['is_permission_b_a'] = $values["is_permission_{$b}_{$a}"] ?? 0;
return [$params, $a];
}
diff --git a/CRM/Contact/Form/Search.php b/CRM/Contact/Form/Search.php
index 575b3d38c25e..ac69d0ce9b15 100644
--- a/CRM/Contact/Form/Search.php
+++ b/CRM/Contact/Form/Search.php
@@ -530,7 +530,7 @@ public function preProcess() {
$this->_amtgID = CRM_Utils_Request::retrieve('amtgID', 'Positive', $this);
$this->_ssID = CRM_Utils_Request::retrieve('ssID', 'Positive', $this);
$this->_sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String', $this);
- $this->_ufGroupID = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+ $ufGroupID = CRM_Utils_Request::retrieve('uf_group_id', 'Positive', $this);
$this->_componentMode = CRM_Utils_Request::retrieve('component_mode', 'Positive', $this, FALSE, CRM_Contact_BAO_Query::MODE_CONTACTS, $_REQUEST);
$this->_operator = CRM_Utils_Request::retrieve('operator', 'String', $this, FALSE, CRM_Contact_BAO_Query::SEARCH_OPERATOR_AND, 'REQUEST');
@@ -547,10 +547,10 @@ public function preProcess() {
// if we dont get this from the url, use default if one exsts
$config = CRM_Core_Config::singleton();
- if ($this->_ufGroupID == NULL &&
+ if ($ufGroupID == NULL &&
$config->defaultSearchProfileID != NULL
) {
- $this->_ufGroupID = $config->defaultSearchProfileID;
+ $ufGroupID = $config->defaultSearchProfileID;
}
// assign context to drive the template display, make sure context is valid
@@ -579,9 +579,9 @@ public function preProcess() {
$this->_returnProperties = &$this->returnProperties();
// also get the uf group id directly from the post value
- $this->_ufGroupID = CRM_Utils_Array::value('uf_group_id', $_POST, $this->_ufGroupID);
- $this->_formValues['uf_group_id'] = $this->_ufGroupID;
- $this->set('id', $this->_ufGroupID);
+ $ufGroupID = $_POST['uf_group_id'] ?? $ufGroupID;
+ $this->_formValues['uf_group_id'] = $ufGroupID;
+ $this->set('uf_group_id', $ufGroupID);
// also get the object mode directly from the post value
$this->_componentMode = CRM_Utils_Array::value('component_mode', $_POST, $this->_componentMode);
@@ -595,8 +595,8 @@ public function preProcess() {
$this->_formValues = $this->get('formValues');
$this->_params = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields);
$this->_returnProperties = &$this->returnProperties();
- if (!empty($this->_ufGroupID)) {
- $this->set('id', $this->_ufGroupID);
+ if ($ufGroupID) {
+ $this->set('uf_group_id', $ufGroupID);
}
}
@@ -623,9 +623,9 @@ public function preProcess() {
$this->_returnProperties = &$this->returnProperties();
}
else {
- if (isset($this->_ufGroupID)) {
+ if ($ufGroupID) {
// also set the uf group id if not already present
- $this->_formValues['uf_group_id'] = $this->_ufGroupID;
+ $this->_formValues['uf_group_id'] = $ufGroupID;
}
if (isset($this->_componentMode)) {
$this->_formValues['component_mode'] = $this->_componentMode;
@@ -667,9 +667,7 @@ public function preProcess() {
}
}
}
- $this->assign('id',
- CRM_Utils_Array::value('uf_group_id', $this->_formValues)
- );
+ $this->assign('id', $ufGroupID);
$operator = CRM_Utils_Array::value('operator', $this->_formValues, CRM_Contact_BAO_Query::SEARCH_OPERATOR_AND);
$this->set('queryOperator', $operator);
if ($operator == CRM_Contact_BAO_Query::SEARCH_OPERATOR_OR) {
@@ -768,10 +766,7 @@ public function postProcess() {
//get the button name
$buttonName = $this->controller->getButtonName();
-
- if (isset($this->_ufGroupID) && empty($this->_formValues['uf_group_id'])) {
- $this->_formValues['uf_group_id'] = $this->_ufGroupID;
- }
+ $this->_formValues['uf_group_id'] = $this->_formValues['uf_group_id'] ?? $this->get('uf_group_id');
if (isset($this->_componentMode) && empty($this->_formValues['component_mode'])) {
$this->_formValues['component_mode'] = $this->_componentMode;
diff --git a/CRM/Contact/Form/Search/Advanced.php b/CRM/Contact/Form/Search/Advanced.php
index fb00ab8809a9..7b9d471ef349 100644
--- a/CRM/Contact/Form/Search/Advanced.php
+++ b/CRM/Contact/Form/Search/Advanced.php
@@ -226,6 +226,10 @@ public function postProcess() {
$this->set('isAdvanced', '1');
$this->setFormValues();
+ if (is_numeric($_POST['id'] ?? NULL)) {
+ $this->_formValues['contact_id'] = (int) $_POST['id'];
+ }
+ $this->set('formValues', $this->_formValues);
// get user submitted values
// get it from controller only if form has been submitted, else preProcess has set this
if (!empty($_POST)) {
@@ -238,13 +242,7 @@ public function postProcess() {
}
}
- // set the group if group is submitted
- if (!empty($this->_formValues['uf_group_id'])) {
- $this->set('id', $this->_formValues['uf_group_id']);
- }
- else {
- $this->set('id', '');
- }
+ $this->set('uf_group_id', $this->_formValues['uf_group_id'] ?? '');
}
// retrieve ssID values only if formValues is null, i.e. form has never been posted
diff --git a/CRM/Contact/Form/Search/Builder.php b/CRM/Contact/Form/Search/Builder.php
index c65dc87d0c73..a0a1e70f0f73 100644
--- a/CRM/Contact/Form/Search/Builder.php
+++ b/CRM/Contact/Form/Search/Builder.php
@@ -365,14 +365,7 @@ public function postProcess() {
// get it from controller only if form has been submitted, else preProcess has set this
if (!empty($_POST)) {
$this->_formValues = $this->controller->exportValues($this->_name);
-
- // set the group if group is submitted
- if (!empty($this->_formValues['uf_group_id'])) {
- $this->set('id', $this->_formValues['uf_group_id']);
- }
- else {
- $this->set('id', '');
- }
+ $this->set('uf_group_id', $this->_formValues['uf_group_id'] ?? '');
}
// we dont want to store the sortByCharacter in the formValue, it is more like
diff --git a/CRM/Contact/Form/Search/Criteria.php b/CRM/Contact/Form/Search/Criteria.php
index ac6b93820377..0a96629033ab 100644
--- a/CRM/Contact/Form/Search/Criteria.php
+++ b/CRM/Contact/Form/Search/Criteria.php
@@ -98,8 +98,8 @@ public static function basic(&$form) {
$form->addElement('text', 'job_title', ts('Job Title'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'job_title'));
//added internal ID
- $form->add('number', 'contact_id', ts('Contact ID'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'id') + ['min' => 1]);
- $form->addRule('contact_id', ts('Please enter valid Contact ID'), 'positiveInteger');
+ $form->add('number', 'id', ts('Contact ID'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'id') + ['min' => 1]);
+ $form->addRule('id', ts('Please enter valid Contact ID'), 'positiveInteger');
//added external ID
$form->addElement('text', 'external_identifier', ts('External ID'), CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'external_identifier'));
@@ -461,7 +461,7 @@ public static function location(&$form) {
}
if ($addressOptions['postal_code']) {
- $attr = ['class' => 'six'] + (array) CRM_Utils_Array::value('postal_code', $attributes);
+ $attr = ['class' => 'six'] + ($attributes['postal_code'] ?? []);
$form->addElement('text', 'postal_code_low', NULL, $attr + ['placeholder' => ts('From')]);
$form->addElement('text', 'postal_code_high', NULL, $attr + ['placeholder' => ts('To')]);
}
diff --git a/CRM/Contact/Form/Task.php b/CRM/Contact/Form/Task.php
index 6d21f77a261e..f7eb5479687b 100644
--- a/CRM/Contact/Form/Task.php
+++ b/CRM/Contact/Form/Task.php
@@ -262,7 +262,7 @@ protected static function legacyGetContactIds($form) {
$queryOperator = 'AND';
}
$dao = $selector->contactIDQuery($params, $sortID,
- CRM_Utils_Array::value('display_relationship_type', $fv),
+ $fv['display_relationship_type'] ?? NULL,
$queryOperator
);
diff --git a/CRM/Contact/Form/Task/EmailTrait.php b/CRM/Contact/Form/Task/EmailTrait.php
index 1755bbc2327f..3a97596024e4 100644
--- a/CRM/Contact/Form/Task/EmailTrait.php
+++ b/CRM/Contact/Form/Task/EmailTrait.php
@@ -384,7 +384,7 @@ public function submit($formValues): void {
$cc,
$bcc,
$additionalDetails,
- CRM_Utils_Array::value('campaign_id', $formValues),
+ $formValues['campaign_id'] ?? NULL,
$this->getCaseID()
);
diff --git a/CRM/Contact/Form/Task/Label.php b/CRM/Contact/Form/Task/Label.php
index e303d62dd13f..0b8455968456 100644
--- a/CRM/Contact/Form/Task/Label.php
+++ b/CRM/Contact/Form/Task/Label.php
@@ -250,7 +250,7 @@ public function postProcess($params = NULL) {
if (!empty($fv['location_type_id'])) {
foreach ($valuesothers as $vals) {
if (($vals['location_type_id'] ?? NULL) ==
- CRM_Utils_Array::value('location_type_id', $fv)
+ ($fv['location_type_id'] ?? NULL)
) {
foreach ($vals as $k => $v) {
if (in_array($k, [
diff --git a/CRM/Contact/Form/Task/PDFTrait.php b/CRM/Contact/Form/Task/PDFTrait.php
index 521e02664f08..9e8219c27d7a 100644
--- a/CRM/Contact/Form/Task/PDFTrait.php
+++ b/CRM/Contact/Form/Task/PDFTrait.php
@@ -151,7 +151,6 @@ public function addPDFElementsToForm(): void {
$form->assign('totalSelectedContacts', !is_null($form->_contactIds) ? count($form->_contactIds) : 0);
$form->add('select', 'document_type', ts('Document Type'), CRM_Core_SelectValues::documentFormat());
-
$documentTypes = implode(',', CRM_Core_SelectValues::documentApplicationType());
$form->addElement('file', "document_file", 'Upload Document', 'size=30 maxlength=255 accept="' . $documentTypes . '"');
$form->addUploadElement("document_file");
diff --git a/CRM/Contact/Page/AJAX.php b/CRM/Contact/Page/AJAX.php
index 99181e9276a9..9cacb36776d2 100644
--- a/CRM/Contact/Page/AJAX.php
+++ b/CRM/Contact/Page/AJAX.php
@@ -951,7 +951,7 @@ public static function getAddressDisplay() {
public static function toggleDedupeSelect() {
$pnid = $_REQUEST['pnid'];
$isSelected = CRM_Utils_Type::escape($_REQUEST['is_selected'], 'Boolean');
- $cacheKeyString = CRM_Utils_Request::retrieve('cacheKey', 'Alphanumeric', $null, FALSE);
+ $cacheKeyString = CRM_Utils_Request::retrieve('cacheKey', 'Alphanumeric', NULL, FALSE);
$params = [
1 => [$isSelected, 'Boolean'],
@@ -979,7 +979,9 @@ public static function toggleDedupeSelect() {
}
/**
- * Retrieve contact relationships.
+ * @deprecated since 5.68. Will be removed around 5.74.
+ *
+ * Only-used-by-user-dashboard.
*/
public static function getContactRelationships() {
$contactID = CRM_Utils_Type::escape($_GET['cid'], 'Integer');
diff --git a/CRM/Contact/Page/DedupeMerge.php b/CRM/Contact/Page/DedupeMerge.php
index 559ab66764ae..70a7bd91aaab 100644
--- a/CRM/Contact/Page/DedupeMerge.php
+++ b/CRM/Contact/Page/DedupeMerge.php
@@ -42,7 +42,7 @@ public static function getRunner() {
$limit = CRM_Utils_Request::retrieveValue('limit', 'Positive');
$action = CRM_Utils_Request::retrieveValue('action', 'String');
$mode = CRM_Utils_Request::retrieveValue('mode', 'String', 'safe');
- $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $null, FALSE, '{}');
+ $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', NULL, FALSE, '{}');
$urlQry = [
'reset' => 1,
diff --git a/CRM/Contact/Page/DedupeRules.php b/CRM/Contact/Page/DedupeRules.php
index 84461909a3c2..d0a345fde389 100644
--- a/CRM/Contact/Page/DedupeRules.php
+++ b/CRM/Contact/Page/DedupeRules.php
@@ -52,6 +52,7 @@ public function &links() {
'url' => 'civicrm/contact/dedupefind',
'qs' => 'reset=1&rgid=%%id%%&action=preview',
'title' => ts('Use DedupeRule'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::VIEW),
];
}
if (CRM_Core_Permission::check('administer dedupe rules')) {
@@ -60,6 +61,7 @@ public function &links() {
'url' => 'civicrm/contact/deduperules',
'qs' => 'action=update&id=%%id%%',
'title' => ts('Edit DedupeRule'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
];
$links[CRM_Core_Action::DELETE] = [
'name' => ts('Delete'),
@@ -67,6 +69,7 @@ public function &links() {
'qs' => 'action=delete&id=%%id%%',
'extra' => 'onclick = "return confirm(\'' . $deleteExtra . '\');"',
'title' => ts('Delete DedupeRule'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
];
}
@@ -129,7 +132,7 @@ public function browse() {
// form all action links
$action = array_sum(array_keys($this->links()));
- $links = self::links();
+ $links = $this->links();
if ($dao->is_reserved) {
unset($links[CRM_Core_Action::DELETE]);
diff --git a/CRM/Contact/Page/View/Note.php b/CRM/Contact/Page/View/Note.php
deleted file mode 100644
index 8375a2760601..000000000000
--- a/CRM/Contact/Page/View/Note.php
+++ /dev/null
@@ -1,311 +0,0 @@
-addSelect('*', 'privacy:label')
- ->addWhere('id', '=', $this->_id)
- ->execute()
- ->single();
- $note['privacy'] = $note['privacy:label'];
- $this->assign('note', $note);
-
- $comments = CRM_Core_BAO_Note::getNoteTree($this->_id, 1);
- $this->assign('comments', $comments);
-
- // add attachments part
- $currentAttachmentInfo = CRM_Core_BAO_File::getEntityFile('civicrm_note', $this->_id);
- $this->assign('currentAttachmentInfo', $currentAttachmentInfo);
-
- }
-
- /**
- * called when action is browse.
- */
- public function browse(): void {
- $note = new CRM_Core_DAO_Note();
- $note->entity_table = 'civicrm_contact';
- $note->entity_id = $this->getContactID();
-
- $note->orderBy('modified_date desc');
-
- //CRM-4418, handling edit and delete separately.
- $permissions = [$this->_permission];
- if ($this->_permission == CRM_Core_Permission::EDIT) {
- //previously delete was subset of edit
- //so for consistency lets grant delete also.
- $permissions[] = CRM_Core_Permission::DELETE;
- }
- $mask = CRM_Core_Action::mask($permissions);
-
- $this->assign('canAddNotes', CRM_Core_Permission::check('add contact notes'));
-
- $links = self::links();
- $action = array_sum(array_keys($links)) & $mask;
-
- $note->find();
- while ($note->fetch()) {
- if (!CRM_Core_BAO_Note::getNotePrivacyHidden($note)) {
- CRM_Core_DAO::storeValues($note, $this->values[$note->id]);
-
- $this->values[$note->id]['action'] = CRM_Core_Action::formLink($links,
- $action,
- [
- 'id' => $note->id,
- 'cid' => $this->getContactID(),
- ],
- ts('more'),
- FALSE,
- 'note.selector.row',
- 'Note',
- $note->id
- );
- if (!empty($note->contact_id)) {
- $contact = new CRM_Contact_DAO_Contact();
- $contact->id = $note->contact_id;
- $contact->find();
- $contact->fetch();
- $this->values[$note->id]['createdBy'] = $contact->display_name;
- }
- $this->values[$note->id]['comment_count'] = CRM_Core_BAO_Note::getChildCount($note->id);
-
- // paper icon view for attachments part
- $paperIconAttachmentInfo = CRM_Core_BAO_File::paperIconAttachment('civicrm_note', $note->id);
- $this->values[$note->id]['attachment'] = $paperIconAttachmentInfo;
- }
- }
- $this->assign('notes', $this->values);
-
- $commentLinks = self::commentLinks();
-
- $action = array_sum(array_keys($commentLinks)) & $mask;
-
- $commentAction = CRM_Core_Action::formLink($commentLinks,
- $action,
- [
- 'id' => $note->id,
- 'pid' => $note->entity_id,
- 'cid' => $note->entity_id,
- ],
- ts('more'),
- FALSE,
- 'note.comment.action',
- 'Note',
- $note->id
- );
- $this->assign('commentAction', $commentAction);
-
- $this->ajaxResponse['tabCount'] = CRM_Contact_BAO_Contact::getCountComponent('note', $this->getContactID());
- }
-
- /**
- * called when action is update or new.
- */
- public function edit() {
- $controller = new CRM_Core_Controller_Simple('CRM_Note_Form_Note', ts('Contact Notes'), $this->_action);
- $controller->setEmbedded(TRUE);
-
- // set the userContext stack
- $session = CRM_Core_Session::singleton();
- $contactID = $this->getContactID();
- $url = CRM_Utils_System::url('civicrm/contact/view',
- 'action=browse&selectedChild=note&cid=' . $contactID
- );
- $session->pushUserContext($url);
-
- if (CRM_Utils_Request::retrieve('confirmed', 'Boolean')) {
- $this->delete();
- CRM_Utils_System::redirect($url);
- }
-
- $controller->reset();
- $controller->set('entityTable', 'civicrm_contact');
- $controller->set('entityId', $this->_contactId);
- $controller->set('id', $this->_id);
-
- $controller->process();
- $controller->run();
- }
-
- public function preProcess() {
- $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
-
- if ($this->_id && CRM_Core_BAO_Note::getNotePrivacyHidden($this->_id)) {
- CRM_Core_Error::statusBounce(ts('You do not have access to this note.'));
- }
-
- $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
- $this->assign('contactId', $this->_contactId);
-
- // check logged in url permission
- CRM_Contact_Page_View::checkUserPermission($this);
-
- $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId);
- CRM_Utils_System::setTitle(ts('Notes for') . ' ' . $displayName);
-
- $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse');
- $this->assign('action', $this->_action);
- }
-
- /**
- * the main function that is called when the page loads,
- * it decides the which action has to be taken for the page.
- *
- * @return null
- */
- public function run() {
- $this->preProcess();
-
- if ($this->_action & CRM_Core_Action::VIEW) {
- $this->view();
- }
- elseif ($this->_action & CRM_Core_Action::ADD) {
- if (
- $this->_permission != CRM_Core_Permission::EDIT &&
- !CRM_Core_Permission::check('add contact notes')
- ) {
- CRM_Core_Error::statusBounce(ts('You do not have access to add notes.'));
- }
-
- $this->edit();
- }
- elseif ($this->_action & CRM_Core_Action::UPDATE) {
- if ($this->_permission != CRM_Core_Permission::EDIT) {
- CRM_Core_Error::statusBounce(ts('You do not have access to edit this note.'));
- }
-
- $this->edit();
- }
- elseif ($this->_action & CRM_Core_Action::DELETE) {
- if ($this->_permission != CRM_Core_Permission::EDIT) {
- CRM_Core_Error::statusBounce(ts('You do not have access to delete this note.'));
- }
- // we use the edit screen the confirm the delete
- $this->edit();
- }
-
- $this->browse();
- return parent::run();
- }
-
- /**
- * Delete the note object from the db and set a status msg.
- */
- public function delete() {
- CRM_Core_BAO_Note::deleteRecord(['id' => $this->_id]);
- $status = ts('Selected Note has been deleted successfully.');
- CRM_Core_Session::setStatus($status, ts('Deleted'), 'success');
- }
-
- /**
- * Get action links.
- *
- * @return array[]
- */
- public static function links() {
- return [
- CRM_Core_Action::VIEW => [
- 'name' => ts('View'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=view&reset=1&cid=%%cid%%&id=%%id%%&selectedChild=note',
- 'title' => ts('View Note'),
- 'weight' => -20,
- ],
- CRM_Core_Action::UPDATE => [
- 'name' => ts('Edit'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=update&reset=1&cid=%%cid%%&id=%%id%%&selectedChild=note',
- 'title' => ts('Edit Note'),
- 'weight' => -10,
- ],
- CRM_Core_Action::ADD => [
- 'name' => ts('Comment'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=add&reset=1&cid=%%cid%%&parentId=%%id%%&selectedChild=note',
- 'title' => ts('Add Comment'),
- 'weight' => -5,
- ],
- CRM_Core_Action::DELETE => [
- 'name' => ts('Delete'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=delete&reset=1&cid=%%cid%%&id=%%id%%&selectedChild=note',
- 'title' => ts('Delete Note'),
- 'weight' => 100,
- ],
- ];
- }
-
- /**
- * Get action links for comments.
- *
- * @return array[]
- */
- public static function commentLinks(): array {
- return [
- CRM_Core_Action::VIEW => [
- 'name' => ts('View'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=view&reset=1&cid=%%cid%%&id={id}&selectedChild=note',
- 'title' => ts('View Comment'),
- 'weight' => -20,
- ],
- CRM_Core_Action::UPDATE => [
- 'name' => ts('Edit'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=update&reset=1&cid=%%cid%%&id={id}&parentId=%%pid%%&selectedChild=note',
- 'title' => ts('Edit Comment'),
- 'weight' => -10,
- ],
- CRM_Core_Action::DELETE => [
- 'name' => ts('Delete'),
- 'url' => 'civicrm/contact/view/note',
- 'qs' => 'action=delete&reset=1&cid=%%cid%%&id={id}&selectedChild=note',
- 'title' => ts('Delete Comment'),
- 'weight' => 100,
- ],
- ];
- }
-
- /**
- * Get the relevant contact ID.
- *
- * @api supported to be accessed from outside of core.
- *
- * @return int
- *
- * @noinspection PhpUnhandledExceptionInspection
- * @noinspection PhpDocMissingThrowsInspection
- */
- public function getContactID(): int {
- return (int) CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
- }
-
-}
diff --git a/CRM/Contact/Page/View/Relationship.php b/CRM/Contact/Page/View/Relationship.php
index f0d6e4d804f3..ec6ad2f88de7 100644
--- a/CRM/Contact/Page/View/Relationship.php
+++ b/CRM/Contact/Page/View/Relationship.php
@@ -139,19 +139,6 @@ public function view() {
);
}
- /**
- * called when action is browse.
- *
- */
- public function browse() {
- // do nothing :) we are using datatable for rendering relationship selectors
- $columnHeaders = CRM_Contact_BAO_Relationship::getColumnHeaders();
- $selector = NULL;
- $contactRelationships = [];
- CRM_Utils_Hook::searchColumns('relationship.columns', $columnHeaders, $contactRelationships, $selector);
- $this->assign('columnHeaders', $columnHeaders);
- }
-
/**
* called when action is update or new.
*
@@ -215,11 +202,6 @@ public function run() {
$this->edit();
}
- // if this is called from case view, suppress browse relationships form
- else {
- $this->browse();
- }
-
return parent::run();
}
@@ -245,7 +227,9 @@ public function delete() {
}
/**
- * Get action links.
+ * @deprecated since 5.68. Will be removed around 5.74.
+ *
+ * Only-used-by-user-dashboard.
*
* @return array
* (reference) of action links
diff --git a/CRM/Contact/Page/View/Summary.php b/CRM/Contact/Page/View/Summary.php
index 585bf193fcb8..f1387457232c 100644
--- a/CRM/Contact/Page/View/Summary.php
+++ b/CRM/Contact/Page/View/Summary.php
@@ -304,13 +304,6 @@ public static function basicTabs() {
'weight' => 70,
'icon' => 'crm-i fa-tasks',
],
- [
- 'id' => 'rel',
- 'title' => ts('Relationships'),
- 'class' => 'livePage',
- 'weight' => 80,
- 'icon' => 'crm-i fa-handshake-o',
- ],
[
'id' => 'group',
'title' => ts('Groups'),
@@ -318,13 +311,6 @@ public static function basicTabs() {
'weight' => 90,
'icon' => 'crm-i fa-users',
],
- [
- 'id' => 'note',
- 'title' => ts('Notes'),
- 'class' => 'livePage',
- 'weight' => 100,
- 'icon' => 'crm-i fa-sticky-note-o',
- ],
[
'id' => 'tag',
'title' => ts('Tags'),
diff --git a/CRM/Contact/Page/View/UserDashBoard.php b/CRM/Contact/Page/View/UserDashBoard.php
index c93b161213f3..5eee298b7536 100644
--- a/CRM/Contact/Page/View/UserDashBoard.php
+++ b/CRM/Contact/Page/View/UserDashBoard.php
@@ -126,7 +126,10 @@ public function buildUserDashBoard() {
}
}
- // CRM-16512 - Hide related contact table if user lacks permission to view self
+ // Relationship section
+ // FIXME - this used to share code with the contact summary "Relationships" tab
+ // now that tab has been switched to use SearchKit, and this ought to be switched as well;
+ // then remove all code commented with "only-used-by-user-dashboard"
if (!empty($dashboardOptions['Permissioned Orgs']) && CRM_Core_Permission::check('view my contact')) {
$columnHeaders = CRM_Contact_BAO_Relationship::getColumnHeaders();
$contactRelationships = $selector = NULL;
diff --git a/CRM/Contact/Page/View/Vcard.php b/CRM/Contact/Page/View/Vcard.php
index 9d98552cf35c..29ff266df677 100644
--- a/CRM/Contact/Page/View/Vcard.php
+++ b/CRM/Contact/Page/View/Vcard.php
@@ -45,10 +45,10 @@ public function run() {
if ($defaults['contact_type'] == 'Individual') {
$vcard->setName(CRM_Utils_Array::value('last_name', $defaults),
- CRM_Utils_Array::value('first_name', $defaults),
- CRM_Utils_Array::value('middle_name', $defaults),
- CRM_Utils_Array::value('prefix', $defaults),
- CRM_Utils_Array::value('suffix', $defaults)
+ $defaults['first_name'] ?? NULL,
+ $defaults['middle_name'] ?? NULL,
+ $defaults['prefix'] ?? NULL,
+ $defaults['suffix'] ?? NULL
);
$organizationName = $defaults['organization_name'] ?? NULL;
if ($organizationName !== NULL) {
diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php
index 2a9eaccc6e7d..a04da212f21c 100644
--- a/CRM/Contribute/BAO/Contribution.php
+++ b/CRM/Contribute/BAO/Contribution.php
@@ -409,6 +409,8 @@ protected static function getBillingAddressParams($params, $billingLocationTypeI
$billingFirstName = $params['billing_first_name'] ?? NULL;
$billingMiddleName = $params['billing_middle_name'] ?? NULL;
$billingLastName = $params['billing_last_name'] ?? NULL;
+ // Note this is NOT used when creating a billing address. It is probably passed
+ // the the payment processor - which is horrible & could maybe change.
$addressParams['address_name'] = "{$billingFirstName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingMiddleName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingLastName}";
foreach ($billingFields as $value) {
@@ -1029,6 +1031,7 @@ protected static function getContributionTransactionInformation($contributionId,
'class' => 'medium-popup',
'qs' => "reset=1&id=%%id%%&contribution_id=%%contribution_id%%",
'title' => ts('Edit Payment'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
];
$paymentEditLink = CRM_Core_Action::formLink(
@@ -1655,16 +1658,21 @@ public static function getContributionDetails($exportMode, $componentIds) {
* thought).
*
* @param array $params
- * @param int $billingLocationTypeID
*
* @return int
* address id
*/
- public static function createAddress($params, $billingLocationTypeID) {
+ public static function createAddress($params) {
+ $billingLocationTypeID = CRM_Core_BAO_LocationType::getBilling();
[$hasBillingField, $addressParams] = self::getBillingAddressParams($params, $billingLocationTypeID);
if ($hasBillingField) {
- $address = CRM_Core_BAO_Address::writeRecord($addressParams);
- return $address->id;
+ $nameFields = [
+ $params['billing_first_name'] ?? NULL,
+ $params['billing_middle_name'] ?? NULL,
+ $params['billing_last_name'] ?? NULL,
+ ];
+ $addressParams['name'] = implode(' ', array_filter($nameFields));
+ return (int) CRM_Core_BAO_Address::writeRecord($addressParams)->id;
}
return NULL;
@@ -1714,35 +1722,18 @@ public static function deleteAddress($contributionId = NULL, $contactId = NULL)
* Online Event Registration or Online Membership signup.
*
* @param int $componentId
- * Participant/membership id.
- * @param string $componentName
- * Event/Membership.
+ * Participant id.
*
* @return int
* pending contribution id.
*/
- public static function checkOnlinePendingContribution($componentId, $componentName) {
+ public static function checkOnlinePendingContribution($componentId) {
$contributionId = NULL;
- if (!$componentId ||
- !in_array($componentName, ['Event', 'Membership'])
- ) {
- return $contributionId;
- }
-
- if ($componentName === 'Event') {
- $idName = 'participant_id';
- $componentTable = 'civicrm_participant';
- $paymentTable = 'civicrm_participant_payment';
- $source = ts('Online Event Registration');
- }
-
- if ($componentName === 'Membership') {
- $idName = 'membership_id';
- $componentTable = 'civicrm_membership';
- $paymentTable = 'civicrm_membership_payment';
- $source = ts('Online Contribution');
- }
+ $idName = 'participant_id';
+ $componentTable = 'civicrm_participant';
+ $paymentTable = 'civicrm_participant_payment';
+ $source = ts('Online Event Registration');
$pendingStatusId = array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'));
$query = "
@@ -3375,7 +3366,7 @@ public static function recordFinancialAccounts(&$params, CRM_Contribute_DAO_Cont
}
// record line items and financial items
if (empty($params['skipLineItem'])) {
- CRM_Price_BAO_LineItem::processPriceSet($entityId, CRM_Utils_Array::value('line_item', $params), $params['contribution'], $entityTable, $isUpdate);
+ CRM_Price_BAO_LineItem::processPriceSet($entityId, $params['line_item'] ?? NULL, $params['contribution'], $entityTable, $isUpdate);
}
// create batch entry if batch_id is passed and
@@ -3499,7 +3490,7 @@ public static function buildOptions($fieldName, $context = NULL, $props = []) {
'version' => 3,
'id' => ($props['contribution_page_id']),
]);
- $types = (array) CRM_Utils_Array::value('payment_processor', $page, 0);
+ $types = (array) $page['payment_processor'] ?? 0;
$params['condition'] = 'id IN (' . implode(',', $types) . ')';
}
break;
@@ -3963,7 +3954,7 @@ public static function generateFromEmailAndName($input, $contribution) {
// if we are still empty see if we can use anything from a contribution page.
if (!empty($pageValues['receipt_from_email'])) {
return [
- CRM_Utils_Array::value('receipt_from_name', $pageValues),
+ $pageValues['receipt_from_name'] ?? NULL,
$pageValues['receipt_from_email'],
];
}
@@ -4308,6 +4299,7 @@ public static function getContributionPaymentLinks(int $id, string $contribution
'is_refund' => 0,
],
'extra' => '',
+ 'weight' => 0,
];
if (CRM_Core_Config::isEnabledBackOfficeCreditCardPayments()) {
@@ -4325,6 +4317,7 @@ public static function getContributionPaymentLinks(int $id, string $contribution
'mode' => 'live',
],
'extra' => '',
+ 'weight' => 0,
];
}
if ($contributionStatus !== 'Pending') {
@@ -4341,6 +4334,7 @@ public static function getContributionPaymentLinks(int $id, string $contribution
'is_refund' => 1,
],
'extra' => '',
+ 'weight' => 0,
];
}
diff --git a/CRM/Contribute/BAO/ContributionPage.php b/CRM/Contribute/BAO/ContributionPage.php
index 72fec24e8437..a2a5ce289d62 100644
--- a/CRM/Contribute/BAO/ContributionPage.php
+++ b/CRM/Contribute/BAO/ContributionPage.php
@@ -261,7 +261,7 @@ public static function sendMail($contactID, $values, $isTest = FALSE, $returnMes
if ($gId) {
$email = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gId, 'notify');
if ($email) {
- $val = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($gId, $contactID, CRM_Utils_Array::value($key, $params), TRUE);
+ $val = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($gId, $contactID, $params[$key] ?? NULL, TRUE);
CRM_Core_BAO_UFGroup::commonSendMail($contactID, $val);
}
}
diff --git a/CRM/Contribute/BAO/ContributionSoft.php b/CRM/Contribute/BAO/ContributionSoft.php
index 797d3dce9bf5..2a2885c95f34 100644
--- a/CRM/Contribute/BAO/ContributionSoft.php
+++ b/CRM/Contribute/BAO/ContributionSoft.php
@@ -30,7 +30,7 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio
*/
public static function add(&$params) {
$hook = empty($params['id']) ? 'create' : 'edit';
- CRM_Utils_Hook::pre($hook, 'ContributionSoft', CRM_Utils_Array::value('id', $params), $params);
+ CRM_Utils_Hook::pre($hook, 'ContributionSoft', $params['id'] ?? NULL, $params);
$contributionSoft = new CRM_Contribute_DAO_ContributionSoft();
$contributionSoft->copyValues($params);
diff --git a/CRM/Contribute/BAO/FinancialProcessor.php b/CRM/Contribute/BAO/FinancialProcessor.php
index 475caa8165cc..73056b55dafe 100644
--- a/CRM/Contribute/BAO/FinancialProcessor.php
+++ b/CRM/Contribute/BAO/FinancialProcessor.php
@@ -81,7 +81,7 @@ private static function createFinancialItemsForLine($params, $context, $fields,
if ($params['contribution']->currency) {
$currency = $params['contribution']->currency;
}
- $previousLineItemTotal = CRM_Utils_Array::value('line_total', CRM_Utils_Array::value($fieldValueId, $previousLineItems), 0);
+ $previousLineItemTotal = CRM_Utils_Array::value('line_total', $previousLineItems[$fieldValueId] ?? NULL, 0);
$itemParams = [
'transaction_date' => $receiveDate,
'contact_id' => $params['prevContribution']->contact_id,
@@ -101,10 +101,10 @@ private static function createFinancialItemsForLine($params, $context, $fields,
$taxAmount = (float) $lineItemDetails['tax_amount'];
if ($context === 'changeFinancialType' && $lineItemDetails['tax_amount'] === 'null') {
// reverse the Sale Tax amount if there is no tax rate associated with new Financial Type
- $taxAmount = CRM_Utils_Array::value('tax_amount', CRM_Utils_Array::value($fieldValueId, $previousLineItems), 0);
+ $taxAmount = CRM_Utils_Array::value('tax_amount', $previousLineItems[$fieldValueId] ?? NULL, 0);
}
elseif ($previousLineItemTotal != $lineItemDetails['line_total']) {
- $taxAmount -= CRM_Utils_Array::value('tax_amount', CRM_Utils_Array::value($fieldValueId, $previousLineItems), 0);
+ $taxAmount -= CRM_Utils_Array::value('tax_amount', $previousLineItems[$fieldValueId] ?? NULL, 0);
}
if ($taxAmount != 0) {
$itemParams['amount'] = CRM_Contribute_BAO_FinancialProcessor::getMultiplier($params['contribution']->contribution_status_id, $context) * $taxAmount;
diff --git a/CRM/Contribute/BAO/Premium.php b/CRM/Contribute/BAO/Premium.php
index 2f648474de4b..f79715f40a2f 100644
--- a/CRM/Contribute/BAO/Premium.php
+++ b/CRM/Contribute/BAO/Premium.php
@@ -114,6 +114,7 @@ public static function buildPremiumBlock(&$form, $pageID, $formItems = FALSE, $s
else {
CRM_Core_DAO::storeValues($productDAO, $products[$productDAO->id]);
}
+ $products[$productDAO->id] += ['thumbnail' => '', 'image' => ''];
}
$options = $temp = [];
$temp = explode(',', $productDAO->options);
@@ -127,10 +128,10 @@ public static function buildPremiumBlock(&$form, $pageID, $formItems = FALSE, $s
if (count($products)) {
$form->assign('showPremium', $formItems);
$form->assign('showSelectOptions', $formItems);
- $form->assign('products', $products);
$form->assign('premiumBlock', $premiumBlock);
}
}
+ $form->assign('products', $products ?? NULL);
}
/**
diff --git a/CRM/Contribute/Form/AbstractEditPayment.php b/CRM/Contribute/Form/AbstractEditPayment.php
index 68e86322e4a1..6b9b5472ef3c 100644
--- a/CRM/Contribute/Form/AbstractEditPayment.php
+++ b/CRM/Contribute/Form/AbstractEditPayment.php
@@ -529,7 +529,7 @@ public static function formatCreditCardDetails(&$params) {
}
$tplParams['credit_card_exp_date'] = isset($params['credit_card_exp_date']) ? CRM_Utils_Date::mysqlToIso(CRM_Utils_Date::format($params['credit_card_exp_date'])) : NULL;
- $tplParams['credit_card_type'] = CRM_Utils_Array::value('credit_card_type', $params);
+ $tplParams['credit_card_type'] = $params['credit_card_type'] ?? NULL;
$tplParams['credit_card_number'] = CRM_Utils_System::mungeCreditCard(CRM_Utils_Array::value('credit_card_number', $params));
return $tplParams;
}
diff --git a/CRM/Contribute/Form/AdditionalInfo.php b/CRM/Contribute/Form/AdditionalInfo.php
index 86b0e9457265..7f1d5e393fd0 100644
--- a/CRM/Contribute/Form/AdditionalInfo.php
+++ b/CRM/Contribute/Form/AdditionalInfo.php
@@ -147,9 +147,11 @@ public static function buildAdditionalDetail(&$form) {
*
* Build the form object for PaymentReminders Information.
*
+ * @deprecated since 5.68 will be removed around 5.78.
* @param CRM_Core_Form $form
*/
public static function buildPaymentReminders(&$form) {
+ CRM_Core_Error::deprecatedFunctionWarning('no alternative, will be removed around 5.78');
//PaymentReminders section
$form->add('hidden', 'hidden_PaymentReminders', 1);
$form->add('text', 'initial_reminder_day', ts('Send Initial Reminder'), ['size' => 3]);
diff --git a/CRM/Contribute/Form/ContributeFormTrait.php b/CRM/Contribute/Form/ContributeFormTrait.php
new file mode 100644
index 000000000000..b5f23429e9fe
--- /dev/null
+++ b/CRM/Contribute/Form/ContributeFormTrait.php
@@ -0,0 +1,91 @@
+isDefined('Contribution')) {
+ return $this->lookup('Contribution', $fieldName);
+ }
+ $id = $this->getContributionID();
+ if ($id) {
+ $this->define('Contribution', 'Contribution', ['id' => $id]);
+ return $this->lookup('Contribution', $fieldName);
+ }
+ return NULL;
+ }
+
+ /**
+ * Get the selected Contribution ID.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getContributionID(): ?int {
+ throw new CRM_Core_Exception('`getContributionID` must be implemented');
+ }
+
+ /**
+ * Get id of contribution page being acted on.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getContributionPageID(): ?int {
+ throw new CRM_Core_Exception('`ContributionPageID` must be implemented');
+ }
+
+ /**
+ * Get a value from the contribution being acted on.
+ *
+ * All values returned in apiv4 format. Escaping may be required.
+ *
+ * @param string $fieldName
+ *
+ * @return mixed
+ * @noinspection PhpUnhandledExceptionInspection
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ */
+ public function getContributionPageValue(string $fieldName) {
+ if ($this->isDefined('ContributionPage')) {
+ return $this->lookup('ContributionPage', $fieldName);
+ }
+ $id = $this->getContributionPageID();
+ if ($id) {
+ $this->define('ContributionPage', 'ContributionPage', ['id' => $id]);
+ return $this->lookup('ContributionPage', $fieldName);
+ }
+ return NULL;
+ }
+
+}
diff --git a/CRM/Contribute/Form/Contribution.php b/CRM/Contribute/Form/Contribution.php
index bfad7aa6ae19..8227fb63af04 100644
--- a/CRM/Contribute/Form/Contribution.php
+++ b/CRM/Contribute/Form/Contribution.php
@@ -18,6 +18,7 @@
*/
class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditPayment {
use CRM_Contact_Form_ContactFormTrait;
+ use CRM_Contribute_Form_ContributeFormTrait;
/**
* The id of the contribution that we are processing.
@@ -208,6 +209,11 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
*/
public $payment_instrument_id;
+ /**
+ * @var bool
+ */
+ private $_payNow;
+
/**
* Explicitly declare the form context.
*/
@@ -215,6 +221,14 @@ public function getDefaultContext() {
return 'create';
}
+ public function __get($name) {
+ if ($name === '_contributionID') {
+ CRM_Core_Error::deprecatedWarning('_contributionID is not a form property - use getContributionID()');
+ return $this->getContributionID();
+ }
+ return NULL;
+ }
+
/**
* Set variables up before form is built.
*
@@ -240,8 +254,7 @@ public function preProcess(): void {
$this->assign('action', $this->_action);
// Get the contribution id if update
- $this->_id = CRM_Utils_Request::retrieve('id', 'Positive');
- $this->assign('isUsePaymentBlock', !empty($this->_id));
+ $this->assign('isUsePaymentBlock', (bool) $this->getContributionID());
if (!empty($this->_id)) {
$this->assignPaymentInfoBlock();
$this->assign('contribID', $this->_id);
@@ -306,7 +319,6 @@ public function preProcess(): void {
// Set title
if ($this->_mode && $this->_id) {
$this->_payNow = TRUE;
- $this->assign('payNow', $this->_payNow);
$this->setTitle(ts('Pay with Credit Card'));
}
elseif ($this->_values['is_template']) {
@@ -318,6 +330,7 @@ public function preProcess(): void {
else {
$this->setPageTitle($this->_ppID ? ts('Pledge Payment') : ts('Contribution'));
}
+ $this->assign('payNow', $this->_payNow);
}
private function preProcessPledge(): void {
@@ -605,8 +618,7 @@ public function buildQuickForm() {
$getOnlyPriceSetElements = FALSE;
}
- $this->set('priceSetId', $this->_priceSetId);
- CRM_Price_BAO_PriceSet::buildPriceSet($this, 'contribution', FALSE);
+ $this->buildPriceSet();
// get only price set form elements.
if ($getOnlyPriceSetElements) {
@@ -670,7 +682,7 @@ public function buildQuickForm() {
}
}
if ($buildRecurBlock) {
- CRM_Contribute_Form_Contribution_Main::buildRecur($this);
+ $this->buildRecur();
$this->setDefaults(['is_recur' => 0]);
$this->assign('buildRecurBlock', TRUE);
}
@@ -872,24 +884,27 @@ public function buildQuickForm() {
$mailingInfo = Civi::settings()->get('mailing_backend');
$this->assign('outBound_option', $mailingInfo['outBound_option']);
- $this->addButtons([
+ $buttons = [
[
'type' => 'upload',
'name' => ts('Save'),
'js' => $js,
'isDefault' => TRUE,
],
- [
+ ];
+ if (!$this->_id) {
+ $buttons[] = [
'type' => 'upload',
'name' => ts('Save and New'),
'js' => $js,
'subName' => 'new',
- ],
- [
- 'type' => 'cancel',
- 'name' => ts('Cancel'),
- ],
- ]);
+ ];
+ }
+ $buttons[] = [
+ 'type' => 'cancel',
+ 'name' => ts('Cancel'),
+ ];
+ $this->addButtons($buttons);
// if contribution is related to membership or participant freeze Financial Type, Amount
if ($this->_id) {
@@ -922,6 +937,49 @@ public function buildQuickForm() {
}
}
+ /**
+ * Build the price set form.
+ */
+ private function buildPriceSet(): void {
+ $priceSetId = $this->getPriceSetID();
+ $form = $this;
+ $component = 'contribution';
+ $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($priceSetId, TRUE, FALSE);
+ $form->_priceSet = $priceSet[$priceSetId] ?? NULL;
+ $validPriceFieldIds = array_keys($form->_priceSet['fields']);
+
+ $form->_priceSet['id'] = $form->_priceSet['id'] ?? $priceSetId;
+ $form->assign('priceSet', $form->_priceSet);
+
+ $feeBlock = &$form->_priceSet['fields'];
+
+ // Call the buildAmount hook.
+ CRM_Utils_Hook::buildAmount($component ?? 'contribution', $form, $feeBlock);
+
+ $hideAdminValues = !CRM_Core_Permission::check('edit contributions');
+ // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
+ $adminFieldVisible = CRM_Core_Permission::check('administer CiviCRM');
+ $checklifetime = FALSE;
+ foreach ($feeBlock as $id => $field) {
+ $options = $field['options'] ?? NULL;
+
+ if (!is_array($options) || !in_array($id, $validPriceFieldIds)) {
+ continue;
+ }
+
+ if (!empty($options)) {
+ CRM_Price_BAO_PriceField::addQuickFormElement($form,
+ 'price_' . $field['id'],
+ $field['id'],
+ FALSE,
+ $field['is_required'] ?? FALSE,
+ NULL,
+ $options
+ );
+ }
+ }
+ }
+
/**
* Global form rule.
*
@@ -1028,7 +1086,7 @@ public function postProcess() {
return;
}
// Get the submitted form values.
- $submittedValues = $this->controller->exportValues($this->_name);
+ $submittedValues = $this->getSubmittedValues();
if ($this->_values['is_template']) {
// If we are a template contribution we don't allow the contribution_status_id to be set
// on the form but we need it for the submit function.
@@ -1207,7 +1265,7 @@ protected function processCreditCard($submittedValues, $lineItem, $contactID) {
$contributionParams,
$financialType,
$this->_bltID,
- CRM_Utils_Array::value('is_recur', $this->_params)
+ $this->_params['is_recur'] ?? NULL
);
$paymentParams['contributionID'] = $contribution->id;
@@ -1332,7 +1390,7 @@ private function processFormContribution(
// add these values for the recurringContrib function ,CRM-10188
$params['financial_type_id'] = $financialType->id;
- $contributionParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $billingLocationID);
+ $contributionParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params);
//@todo - this is being set from the form to resolve CRM-10188 - an
// eNotice caused by it not being set @ the front end
@@ -1346,7 +1404,7 @@ private function processFormContribution(
// We may no longer need to set params['is_recur'] - it used to be used in processRecurringContribution
$params['is_recur'] = $isRecur;
$params['payment_instrument_id'] = $contributionParams['payment_instrument_id'] ?? NULL;
- $recurringContributionID = !$isRecur ? NULL : CRM_Contribute_Form_Contribution_Confirm::processRecurringContribution($form, $params, [
+ $recurringContributionID = !$isRecur ? NULL : $this->processRecurringContribution($form, $params, [
'contact_id' => $contactID,
'financial_type_id' => $financialType->id,
]);
@@ -1391,9 +1449,6 @@ private function processFormContribution(
$smarty->assign('dataArray', $dataArray);
$smarty->assign('totalTaxAmount', $params['tax_amount'] ?? NULL);
}
-
- // lets store it in the form variable so postProcess hook can get to this and use it
- $form->_contributionID = $contribution->id;
}
// process soft credit / pcp params first
@@ -1429,6 +1484,51 @@ private function processFormContribution(
return $contribution;
}
+ /**
+ * Create the recurring contribution record.
+ *
+ * @param self $form
+ * @param array $params
+ * @param array $recurParams
+ *
+ * @return int|null
+ */
+ private function processRecurringContribution($form, $params, $recurParams) {
+ // @todo - previously shared code - many items may be irrelevant.
+ $recurParams['amount'] = $params['amount'] ?? NULL;
+ $recurParams['auto_renew'] = $params['auto_renew'] ?? NULL;
+ $recurParams['frequency_unit'] = $params['frequency_unit'] ?? NULL;
+ $recurParams['frequency_interval'] = $params['frequency_interval'] ?? NULL;
+ $recurParams['installments'] = $params['installments'] ?? NULL;
+ $recurParams['currency'] = $params['currency'] ?? NULL;
+ $recurParams['payment_instrument_id'] = $params['payment_instrument_id'];
+
+ $recurParams['is_test'] = 0;
+ if (($form->_action & CRM_Core_Action::PREVIEW) ||
+ (isset($form->_mode) && ($form->_mode == 'test'))
+ ) {
+ $recurParams['is_test'] = 1;
+ }
+
+ $recurParams['start_date'] = $recurParams['create_date'] = $recurParams['modified_date'] = date('YmdHis');
+ if (!empty($params['receive_date'])) {
+ $recurParams['start_date'] = date('YmdHis', strtotime($params['receive_date']));
+ }
+ $recurParams['invoice_id'] = $params['invoiceID'] ?? NULL;
+ $recurParams['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', 'Pending');
+ $recurParams['payment_processor_id'] = $params['payment_processor_id'] ?? NULL;
+ $recurParams['is_email_receipt'] = (bool) ($params['is_email_receipt'] ?? FALSE);
+ // We set trxn_id=invoiceID specifically for paypal IPN. It is reset this when paypal sends us the real trxn id, CRM-2991
+ $recurParams['processor_id'] = $recurParams['trxn_id'] = ($params['trxn_id'] ?? $params['invoiceID']);
+
+ $campaignId = $params['campaign_id'] ?? $form->_values['campaign_id'] ?? NULL;
+ $recurParams['campaign_id'] = $campaignId;
+ $recurring = CRM_Contribute_BAO_ContributionRecur::add($recurParams);
+ $form->_params['contributionRecurID'] = $recurring->id;
+
+ return $recurring->id;
+ }
+
/**
* Generate the data to construct a snippet based pane.
*
@@ -1481,8 +1581,20 @@ protected function generatePane($type, $defaults) {
*
* @throws \CRM_Core_Exception
* @throws \Civi\Payment\Exception\PaymentProcessorException
+ *
+ * @deprecated since 5.68 will be removed around 5.80.
+ *
+ * Try something like
+ * use use \Civi\Test\FormTrait;
+ * $form = $this->getTestForm('CRM_Contribute_Form_Contribution', $submittedValues, [
+ * 'id' => 4;
+ * 'action' => 'update',
+ * ]);
+ * $form->processForm();
*/
public function testSubmit($params, $action, $creditCardMode = NULL) {
+ // Note that this is really used from tests - so adding noisy deprecations would make them
+ // fail straight away.
$defaults = [
'soft_credit_contact_id' => [],
'receive_date' => date('Y-m-d H:i:s'),
@@ -1528,7 +1640,6 @@ public function testSubmit($params, $action, $creditCardMode = NULL) {
$this->_fields = [];
return $this->submit(array_merge($defaults, $params), $action, CRM_Utils_Array::value('pledge_payment_id', $params));
-
}
/**
@@ -1555,7 +1666,7 @@ protected function submit($submittedValues, $action, $pledgePaymentID) {
if ($this->getPriceSetID() && $action & CRM_Core_Action::UPDATE) {
$line = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution');
$lineID = key($line);
- $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', CRM_Utils_Array::value('price_field_id', $line[$lineID]), 'price_set_id');
+ $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $line[$lineID]['price_field_id'] ?? NULL, 'price_set_id');
$quickConfig = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceSetId, 'is_quick_config');
// Why do we do this? Seems like a like a wrapper for old functionality - but single line price sets & quick
// config should be treated the same.
@@ -1658,7 +1769,7 @@ protected function submit($submittedValues, $action, $pledgePaymentID) {
$componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id);
if (empty($componentDetails['membership']) && empty($componentDetails['participant'])) {
if (!($this->_action & CRM_Core_Action::UPDATE && (($this->_defaults['contribution_status_id'] != $submittedValues['contribution_status_id'])))) {
- $lineItems[$itemId]['unit_price'] = $lineItems[$itemId]['line_total'] = CRM_Utils_Rule::cleanMoney(CRM_Utils_Array::value('total_amount', $submittedValues));
+ $lineItems[$itemId]['unit_price'] = $lineItems[$itemId]['line_total'] = $this->getSubmittedValue('total_amount');
}
}
@@ -1704,7 +1815,7 @@ protected function submit($submittedValues, $action, $pledgePaymentID) {
$submittedValues['total_amount'] = $this->_values['total_amount'] ?? NULL;
// Avoid tax amount deduction on edit form and keep it original, because this will lead to error described in CRM-20676
if (!$this->_id) {
- $submittedValues['total_amount'] -= CRM_Utils_Array::value('tax_amount', $this->_values, 0);
+ $submittedValues['total_amount'] -= $this->_values['tax_amount'] ?? 0;
}
}
$this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE);
@@ -1892,9 +2003,9 @@ protected function submit($submittedValues, $action, $pledgePaymentID) {
$contribution->id,
($formValues['option_type'] ?? 0) == 2,
$formValues['total_amount'],
- CRM_Utils_Array::value('total_amount', $this->_defaults),
+ $this->_defaults['total_amount'] ?? NULL,
$formValues['contribution_status_id'],
- CRM_Utils_Array::value('contribution_status_id', $this->_defaults)
+ $this->_defaults['contribution_status_id'] ?? NULL
);
return $contribution;
}
@@ -1916,7 +2027,7 @@ protected function invoicingPostProcessHook($submittedValues, $action, $lineItem
foreach ($lineItem as $key => $value) {
foreach ($value as $v) {
if (isset($taxRate[(string) CRM_Utils_Array::value('tax_rate', $v)])) {
- $taxRate[(string) $v['tax_rate']] = $taxRate[(string) $v['tax_rate']] + CRM_Utils_Array::value('tax_amount', $v);
+ $taxRate[(string) $v['tax_rate']] = $taxRate[(string) $v['tax_rate']] + ($v['tax_amount'] ?? 0);
}
else {
if (isset($v['tax_rate'])) {
@@ -2055,12 +2166,32 @@ public function setUserContext(): void {
}
/**
- * Get the contribution ID.
+ * Get the selected Contribution ID.
*
- * @return int|null
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
*/
- protected function getContributionID(): ?int {
- return $this->_id;
+ public function getContributionID(): ?int {
+ if (!$this->_id) {
+ $this->_id = CRM_Utils_Request::retrieve('id', 'Positive');
+ }
+ return $this->_id ? (int) $this->_id : NULL;
+ }
+
+ /**
+ * Get id of contribution page being acted on.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getContributionPageID(): ?int {
+ return $this->getContributionID() ? $this->getContributionValue('contribution_page_id') : NULL;
}
/**
@@ -2220,4 +2351,91 @@ public function getPledgePaymentID(): ?int {
return $this->_ppID ? (int) $this->_ppID : NULL;
}
+ /**
+ * Build elements to collect information for recurring contributions.
+ *
+ * Previously shared function.
+ */
+ private function buildRecur(): void {
+ $form = $this;
+ $attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionRecur');
+ $className = 'CRM_Contribute_Form_Contribution';
+
+ $form->assign('is_recur_interval', $form->_values['is_recur_interval'] ?? NULL);
+ $form->assign('is_recur_installments', $form->_values['is_recur_installments'] ?? NULL);
+ $paymentObject = $form->getVar('_paymentObject');
+ if ($paymentObject) {
+ $form->assign('recurringHelpText', $paymentObject->getText('contributionPageRecurringHelp', [
+ 'is_recur_installments' => !empty($form->_values['is_recur_installments']),
+ 'is_email_receipt' => !empty($form->_values['is_email_receipt']),
+ ]));
+ }
+
+ $frUnits = $form->_values['recur_frequency_unit'] ?? NULL;
+ $frequencyUnits = CRM_Core_OptionGroup::values('recur_frequency_units', FALSE, FALSE, TRUE);
+ if (empty($frUnits) &&
+ $className == 'CRM_Contribute_Form_Contribution'
+ ) {
+ $frUnits = implode(CRM_Core_DAO::VALUE_SEPARATOR,
+ CRM_Core_OptionGroup::values('recur_frequency_units', FALSE, FALSE, FALSE, NULL, 'value')
+ );
+ }
+
+ $unitVals = explode(CRM_Core_DAO::VALUE_SEPARATOR, $frUnits);
+
+ // FIXME: Ideally we should freeze select box if there is only
+ // one option but looks there is some problem /w QF freeze.
+ //if ( count( $units ) == 1 ) {
+ //$frequencyUnit->freeze( );
+ //}
+
+ $form->add('text', 'installments', ts('installments'),
+ $attributes['installments'] + ['class' => 'two']
+ );
+ $form->addRule('installments', ts('Number of installments must be a whole number.'), 'integer');
+
+ $is_recur_label = ts('I want to contribute this amount every');
+
+ // CRM 10860, display text instead of a dropdown if there's only 1 frequency unit
+ if (count($unitVals) == 1) {
+ $form->assign('one_frequency_unit', TRUE);
+ $form->add('hidden', 'frequency_unit', $unitVals[0]);
+ if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
+ $unit = CRM_Contribute_BAO_Contribution::getUnitLabelWithPlural($unitVals[0]);
+ $form->assign('frequency_unit', $unit);
+ }
+ else {
+ $is_recur_label = ts('I want to contribute this amount every %1',
+ [1 => $frequencyUnits[$unitVals[0]]]
+ );
+ $form->assign('all_text_recur', TRUE);
+ }
+ }
+ else {
+ $form->assign('one_frequency_unit', FALSE);
+ $units = [];
+ foreach ($unitVals as $key => $val) {
+ if (array_key_exists($val, $frequencyUnits)) {
+ $units[$val] = $frequencyUnits[$val];
+ if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
+ $units[$val] = CRM_Contribute_BAO_Contribution::getUnitLabelWithPlural($val);
+ $unit = ts('Every');
+ }
+ }
+ }
+ $frequencyUnit = &$form->add('select', 'frequency_unit', NULL, $units, FALSE, ['aria-label' => ts('Frequency Unit'), 'class' => 'crm-select2 eight']);
+ }
+
+ if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
+ $form->add('text', 'frequency_interval', $unit, $attributes['frequency_interval'] + ['aria-label' => ts('Every'), 'class' => 'two']);
+ $form->addRule('frequency_interval', ts('Frequency must be a whole number (EXAMPLE: Every 3 months).'), 'integer');
+ }
+ else {
+ // make sure frequency_interval is submitted as 1 if given no choice to user.
+ $form->add('hidden', 'frequency_interval', 1);
+ }
+
+ $form->add('checkbox', 'is_recur', $is_recur_label, NULL);
+ }
+
}
diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php
index e43d107f1c7f..daf64aa0f6c7 100644
--- a/CRM/Contribute/Form/Contribution/Confirm.php
+++ b/CRM/Contribute/Form/Contribution/Confirm.php
@@ -328,7 +328,7 @@ public function preProcess() {
[$field, $locType] = explode('-', $loc);
}
- if (in_array($field, $addressBlocks)) {
+ if (in_array($field, $addressBlocks) && !empty($value)) {
if ($locType === 'Primary') {
$defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
$locType = $defaultLocationType->id;
@@ -565,20 +565,11 @@ public function buildQuickForm() {
$this->assign('is_separate_payment', $this->isSeparateMembershipPayment());
$this->assign('priceSetID', $this->_priceSetId);
-
- // The concept of contributeMode is deprecated.
- if ($this->_contributeMode === 'notify' ||
- $this->_amount <= 0.0 || $this->_params['is_pay_later']
- ) {
- $contribButton = ts('Continue');
- }
- elseif (!empty($this->_ccid)) {
- $contribButton = ts('Make Payment');
- }
- else {
- $contribButton = ts('Make Contribution');
- }
- $this->assign('button', $contribButton);
+ $contributionButtonText = $this->getPaymentProcessorObject()->getText('contributionPageButtonText', [
+ 'is_payment_to_existing' => !empty($this->_ccid),
+ 'amount' => $this->_amount,
+ ]);
+ $this->assign('button', $contributionButtonText);
$this->assign('continueText',
$this->getPaymentProcessorObject()->getText('contributionPageContinueText', [
@@ -586,11 +577,17 @@ public function buildQuickForm() {
'amount' => $this->_amount,
])
);
+ $this->assign('confirmText',
+ $this->getPaymentProcessorObject()->getText('contributionPageConfirmText', [
+ 'is_payment_to_existing' => !empty($this->_ccid),
+ 'amount' => $this->_amount,
+ ])
+ );
$this->addButtons([
[
'type' => 'next',
- 'name' => $contribButton,
+ 'name' => $contributionButtonText,
'spacing' => ' ',
'isDefault' => TRUE,
],
@@ -802,22 +799,6 @@ private function buildMembershipBlock($cid, $selectedMembershipTypeID = NULL, $i
return $separateMembershipPayment;
}
- /**
- * Overwrite action.
- *
- * Since we are only showing elements in frozen mode no help display needed.
- *
- * @return int
- */
- public function getAction() {
- if ($this->_action & CRM_Core_Action::PREVIEW) {
- return CRM_Core_Action::VIEW | CRM_Core_Action::PREVIEW;
- }
- else {
- return CRM_Core_Action::VIEW;
- }
- }
-
/**
* Set default values for the form.
*
@@ -1047,7 +1028,7 @@ protected function processFormContribution(
// add these values for the recurringContrib function ,CRM-10188
$params['financial_type_id'] = $financialType->id;
- $contributionParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $billingLocationID);
+ $contributionParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params);
//@todo - this is being set from the form to resolve CRM-10188 - an
// eNotice caused by it not being set @ the front end
@@ -1061,7 +1042,7 @@ protected function processFormContribution(
// We may no longer need to set params['is_recur'] - it used to be used in processRecurringContribution
$params['is_recur'] = $isRecur;
$params['payment_instrument_id'] = $contributionParams['payment_instrument_id'] ?? NULL;
- $recurringContributionID = !$isRecur ? NULL : self::processRecurringContribution($form, $params, [
+ $recurringContributionID = !$isRecur ? NULL : $this->processRecurringContribution($params, [
'contact_id' => $contactID,
'financial_type_id' => $financialType->id,
]);
@@ -1167,13 +1148,12 @@ protected function processFormContribution(
/**
* Create the recurring contribution record.
*
- * @param CRM_Core_Form $form
* @param array $params
* @param array $recurParams
*
* @return int|null
*/
- public static function processRecurringContribution($form, $params, $recurParams) {
+ private function processRecurringContribution(array $params, array $recurParams) {
$recurParams['amount'] = $params['amount'] ?? NULL;
$recurParams['auto_renew'] = $params['auto_renew'] ?? NULL;
@@ -1185,20 +1165,20 @@ public static function processRecurringContribution($form, $params, $recurParams
// CRM-14354: For an auto-renewing membership with an additional contribution,
// if separate payments is not enabled, make sure only the membership fee recurs
- if (!empty($form->_membershipBlock)
- && $form->_membershipBlock['is_separate_payment'] === '0'
+ if (!empty($this->_membershipBlock)
+ && $this->_membershipBlock['is_separate_payment'] === '0'
&& isset($params['selectMembership'])
- && $form->_values['is_allow_other_amount'] == '1'
+ && $this->_values['is_allow_other_amount'] == '1'
// CRM-16331
- && !empty($form->_membershipTypeValues)
- && !empty($form->_membershipTypeValues[$params['selectMembership']]['minimum_fee'])
+ && !empty($this->_membershipTypeValues)
+ && !empty($this->_membershipTypeValues[$params['selectMembership']]['minimum_fee'])
) {
- $recurParams['amount'] = $form->_membershipTypeValues[$params['selectMembership']]['minimum_fee'];
+ $recurParams['amount'] = $this->_membershipTypeValues[$params['selectMembership']]['minimum_fee'];
}
$recurParams['is_test'] = 0;
- if (($form->_action & CRM_Core_Action::PREVIEW) ||
- (isset($form->_mode) && ($form->_mode == 'test'))
+ if (($this->_action & CRM_Core_Action::PREVIEW) ||
+ (isset($this->_mode) && ($this->_mode === 'test'))
) {
$recurParams['is_test'] = 1;
}
@@ -1208,29 +1188,16 @@ public static function processRecurringContribution($form, $params, $recurParams
$recurParams['start_date'] = date('YmdHis', strtotime($params['receive_date']));
}
$recurParams['invoice_id'] = $params['invoiceID'] ?? NULL;
- $recurParams['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
+ $recurParams['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', 'Pending');
$recurParams['payment_processor_id'] = $params['payment_processor_id'] ?? NULL;
$recurParams['is_email_receipt'] = (bool) ($params['is_email_receipt'] ?? FALSE);
// We set trxn_id=invoiceID specifically for paypal IPN. It is reset this when paypal sends us the real trxn id, CRM-2991
$recurParams['processor_id'] = $recurParams['trxn_id'] = ($params['trxn_id'] ?? $params['invoiceID']);
- $campaignId = $params['campaign_id'] ?? $form->_values['campaign_id'] ?? NULL;
+ $campaignId = $params['campaign_id'] ?? $this->_values['campaign_id'] ?? NULL;
$recurParams['campaign_id'] = $campaignId;
$recurring = CRM_Contribute_BAO_ContributionRecur::add($recurParams);
- if (is_a($recurring, 'CRM_Core_Error')) {
- CRM_Core_Error::displaySessionError($recurring);
- $urlString = 'civicrm/contribute/transact';
- $urlParams = '_qf_Main_display=true';
- if (get_class($form) == 'CRM_Contribute_Form_Contribution') {
- $urlString = 'civicrm/contact/view/contribution';
- $urlParams = "action=add&cid={$form->_contactID}";
- if ($form->_mode) {
- $urlParams .= "&mode={$form->_mode}";
- }
- }
- CRM_Utils_System::redirect(CRM_Utils_System::url($urlString, $urlParams));
- }
- $form->_params['contributionRecurID'] = $recurring->id;
+ $this->_params['contributionRecurID'] = $recurring->id;
return $recurring->id;
}
@@ -1471,13 +1438,11 @@ protected function postProcessMembership(
$membershipParams, $contactID, $premiumParams,
$customFieldsFormatted, $membershipDetails, $membershipTypeIDs, $isPaidMembership, $membershipID,
$isProcessSeparateMembershipTransaction, $financialTypeID, $unprocessedLineItems) {
- // Assign $this to $form while we eliminate it.
- $form = $this;
$membershipContribution = NULL;
$isTest = $membershipParams['is_test'] ?? FALSE;
$errors = $paymentResults = [];
- $form->_values['isMembership'] = TRUE;
- $isRecurForFirstTransaction = $form->_params['is_recur'] ?? $membershipParams['is_recur'] ?? NULL;
+ $this->_values['isMembership'] = TRUE;
+ $isRecurForFirstTransaction = $this->_params['is_recur'] ?? $membershipParams['is_recur'] ?? NULL;
$totalAmount = $membershipParams['amount'];
@@ -1515,14 +1480,14 @@ protected function postProcessMembership(
$membershipContribution = $paymentResult['contribution'];
// Save the contribution ID so that I can be used in email receipts
// For example, if you need to generate a tax receipt for the donation only.
- $form->_values['contribution_other_id'] = $membershipContribution->id;
+ $this->_values['contribution_other_id'] = $membershipContribution->id;
}
}
if ($isProcessSeparateMembershipTransaction) {
try {
- $form->_lineItem = $unprocessedLineItems;
- if (empty($form->_params['auto_renew']) && !empty($membershipParams['is_recur'])) {
+ $this->_lineItem = $unprocessedLineItems;
+ if (empty($this->_params['auto_renew']) && !empty($membershipParams['is_recur'])) {
unset($membershipParams['is_recur']);
}
[$membershipContribution, $secondPaymentResult] = $this->processSecondaryFinancialTransaction($contactID, array_merge($membershipParams, ['skipLineItem' => 1]),
@@ -1543,7 +1508,7 @@ protected function postProcessMembership(
//@todo - why is this nested so deep? it seems like it could be just set on the calling function on the form layer
if (isset($membershipParams['onbehalf']) && !empty($membershipParams['onbehalf']['member_campaign_id'])) {
- $form->_params['campaign_id'] = $membershipParams['onbehalf']['member_campaign_id'];
+ $this->_params['campaign_id'] = $membershipParams['onbehalf']['member_campaign_id'];
}
//@todo it should no longer be possible for it to get to this point & membership to not be an array
if (is_array($membershipTypeIDs) && !empty($membershipContributionID)) {
@@ -1559,7 +1524,7 @@ protected function postProcessMembership(
}
$i = 1;
- $form->_params['createdMembershipIDs'] = [];
+ $this->_params['createdMembershipIDs'] = [];
foreach ($membershipTypeIDs as $memType) {
$membershipLineItems = [];
if ($i < count($membershipTypeIDs)) {
@@ -1571,22 +1536,22 @@ protected function postProcessMembership(
}
$i++;
$numTerms = $typesTerms[$memType] ?? 1;
- $contributionRecurID = $form->_params['contributionRecurID'] ?? NULL;
+ $contributionRecurID = $this->_params['contributionRecurID'] ?? NULL;
$membershipSource = NULL;
- if (!empty($form->_params['membership_source'])) {
- $membershipSource = $form->_params['membership_source'];
+ if (!empty($this->_params['membership_source'])) {
+ $membershipSource = $this->_params['membership_source'];
}
- elseif ((isset($form->_values['title']) && !empty($form->_values['title'])) || (isset($form->_values['frontend_title']) && !empty($form->_values['frontend_title']))) {
- $title = $form->_values['frontend_title'];
+ elseif ((isset($this->_values['title']) && !empty($this->_values['title'])) || (isset($this->_values['frontend_title']) && !empty($this->_values['frontend_title']))) {
+ $title = $this->_values['frontend_title'];
$membershipSource = ts('Online Contribution:') . ' ' . $title;
}
$isPayLater = NULL;
- if (isset($form->_params)) {
- $isPayLater = $form->_params['is_pay_later'] ?? NULL;
+ if (isset($this->_params)) {
+ $isPayLater = $this->_params['is_pay_later'] ?? NULL;
}
$memParams = [
- 'campaign_id' => $form->_params['campaign_id'] ?? ($form->_values['campaign_id'] ?? NULL),
+ 'campaign_id' => $this->_params['campaign_id'] ?? ($this->_values['campaign_id'] ?? NULL),
];
// @todo Move this into CRM_Member_BAO_Membership::processMembership
@@ -1594,15 +1559,6 @@ protected function postProcessMembership(
$pending = $membershipContribution->contribution_status_id == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
}
else {
- // The concept of contributeMode is deprecated.
- // the is_monetary concept probably should be too as it can be calculated from
- // the existence of 'amount' & seems fragile.
- if (((isset($this->_contributeMode)) || !empty($this->_params['is_pay_later'])
- ) &&
- (($this->_values['is_monetary'] && $this->_amount > 0.0))
- ) {
- $pending = TRUE;
- }
$pending = FALSE;
}
@@ -1615,10 +1571,10 @@ protected function postProcessMembership(
$membershipLineItems
);
- $form->set('renewal_mode', $renewalMode);
+ $this->set('renewal_mode', $renewalMode);
if (!empty($dates)) {
- $form->assign('mem_start_date', CRM_Utils_Date::customFormat($dates['start_date'], '%Y%m%d'));
- $form->assign('mem_end_date', CRM_Utils_Date::customFormat($dates['end_date'], '%Y%m%d'));
+ $this->assign('mem_start_date', CRM_Utils_Date::customFormat($dates['start_date'], '%Y%m%d'));
+ $this->assign('mem_end_date', CRM_Utils_Date::customFormat($dates['end_date'], '%Y%m%d'));
}
if (!empty($membershipContribution)) {
@@ -1631,17 +1587,17 @@ protected function postProcessMembership(
civicrm_api3('MembershipPayment', 'create', $membershipPaymentParams);
}
if ($membership) {
- CRM_Core_BAO_CustomValueTable::postProcess($form->_params, 'civicrm_membership', $membership->id, 'Membership');
- $form->_params['createdMembershipIDs'][] = $membership->id;
- $form->_params['membershipID'] = $membership->id;
+ CRM_Core_BAO_CustomValueTable::postProcess($this->_params, 'civicrm_membership', $membership->id, 'Membership');
+ $this->_params['createdMembershipIDs'][] = $membership->id;
+ $this->_params['membershipID'] = $membership->id;
//CRM-15232: Check if membership is created and on the basis of it use
//membership receipt template to send payment receipt
- $form->_values['isMembership'] = TRUE;
+ $this->_values['isMembership'] = TRUE;
}
}
- if ($form->_priceSetId && !empty($form->_useForMember) && !empty($form->_lineItem)) {
- foreach ($form->_lineItem[$form->_priceSetId] as & $priceFieldOp) {
+ if ($this->_priceSetId && !empty($this->_useForMember) && !empty($this->_lineItem)) {
+ foreach ($this->_lineItem[$this->_priceSetId] as & $priceFieldOp) {
if (!empty($priceFieldOp['membership_type_id']) && $membership->membership_type_id == $priceFieldOp['membership_type_id']) {
$membershipOb = $membership;
$priceFieldOp['start_date'] = $membershipOb->start_date ? CRM_Utils_Date::formatDateOnlyLong($membershipOb->start_date) : '-';
@@ -1651,8 +1607,8 @@ protected function postProcessMembership(
$priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
}
}
- $form->_values['lineItem'] = $form->_lineItem;
- $form->assign('lineItem', $form->_lineItem);
+ $this->_values['lineItem'] = $this->_lineItem;
+ $this->assign('lineItem', $this->_lineItem);
}
}
@@ -1662,25 +1618,25 @@ protected function postProcessMembership(
}
if (isset($membershipContributionID)) {
- $form->_values['contribution_id'] = $membershipContributionID;
+ $this->_values['contribution_id'] = $membershipContributionID;
}
- if (empty($form->_params['is_pay_later']) && $form->_paymentProcessor) {
+ if (empty($this->_params['is_pay_later']) && $this->_paymentProcessor) {
// the is_monetary concept probably should be deprecated as it can be calculated from
// the existence of 'amount' & seems fragile.
- if ($form->_values['is_monetary'] && $form->_amount > 0.0 && !$form->_params['is_pay_later']) {
+ if ($this->_values['is_monetary'] && $this->_amount > 0.0 && !$this->_params['is_pay_later']) {
// call postProcess hook before leaving
- $form->postProcessHook();
+ $this->postProcessHook();
}
- $payment = Civi\Payment\System::singleton()->getByProcessor($form->_paymentProcessor);
+ $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
// The contribution_other_id is effectively the ID for the only contribution or the non-membership contribution.
// Since we have called the membership contribution (in a 2 contribution scenario) this is out
// primary-contribution compared to that - but let's face it - it's all just too hard & confusing at the moment!
- $paymentParams = array_merge($form->_params, ['contributionID' => $form->_values['contribution_other_id']]);
+ $paymentParams = array_merge($this->_params, ['contributionID' => $this->_values['contribution_other_id']]);
// CRM-19792 : set necessary fields for payment processor
- CRM_Core_Payment_Form::mapParams($form->_bltID, $paymentParams, $paymentParams, TRUE);
+ CRM_Core_Payment_Form::mapParams($this->_bltID, $paymentParams, $paymentParams, TRUE);
// If this is a single membership-related contribution, it won't have
// be performed yet, so do it now.
@@ -1718,9 +1674,9 @@ protected function postProcessMembership(
return;
}
- $emailValues = array_merge($membershipParams, $form->_values);
+ $emailValues = array_merge($membershipParams, $this->_values);
$emailValues['membership_assign'] = 1;
- $emailValues['useForMember'] = !empty($form->_useForMember);
+ $emailValues['useForMember'] = !empty($this->_useForMember);
// Finally send an email receipt for pay-later scenario (although it might sometimes be caught above!)
if ($totalAmount == 0) {
@@ -1732,7 +1688,7 @@ protected function postProcessMembership(
// also it reset any payment processor selection result into pending free membership
// so its a kind of hack to complete free membership at this point since there is no $form->_paymentProcessor info
if (!empty($membershipContribution) && !is_a($membershipContribution, 'CRM_Core_Error')) {
- if (empty($form->_paymentProcessor)) {
+ if (empty($this->_paymentProcessor)) {
// @todo this can maybe go now we are setting payment_processor_id = 0 more reliably.
$paymentProcessorIDs = explode(CRM_Core_DAO::VALUE_SEPARATOR, $this->_values['payment_processor'] ?? NULL);
$this->_paymentProcessor['id'] = $paymentProcessorIDs[0];
diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php
index 0c4c36bef11e..5f7d9aa04ab0 100644
--- a/CRM/Contribute/Form/Contribution/Main.php
+++ b/CRM/Contribute/Form/Contribution/Main.php
@@ -126,14 +126,14 @@ public function setDefaultValues() {
// remove component related fields
foreach ($this->_fields as $name => $fieldInfo) {
//don't set custom data Used for Contribution (CRM-1344)
- if (substr($name, 0, 7) == 'custom_') {
+ if (substr($name, 0, 7) === 'custom_') {
$id = substr($name, 7);
if (!CRM_Core_BAO_CustomGroup::checkCustomField($id, ['Contribution', 'Membership'])) {
continue;
}
// ignore component fields
}
- elseif (array_key_exists($name, $contribFields) || (substr($name, 0, 11) == 'membership_') || (substr($name, 0, 13) == 'contribution_')) {
+ elseif (array_key_exists($name, $contribFields) || (substr($name, 0, 11) === 'membership_') || (substr($name, 0, 13) == 'contribution_')) {
continue;
}
$fields[$name] = $fieldInfo;
@@ -146,8 +146,9 @@ public function setDefaultValues() {
$billingDefaults = $this->getProfileDefaults('Billing', $contactID);
$this->_defaults = array_merge($this->_defaults, $billingDefaults);
}
- if (!empty($this->_ccid) && !empty($this->_pendingAmount)) {
- $this->_defaults['total_amount'] = CRM_Utils_Money::formatLocaleNumericRoundedForDefaultCurrency($this->_pendingAmount);
+ $balance = $this->getContributionBalance();
+ if ($balance) {
+ $this->_defaults['total_amount'] = CRM_Utils_Money::formatLocaleNumericRoundedForDefaultCurrency($balance);
}
/*
@@ -254,7 +255,11 @@ public function setDefaultValues() {
//set custom field defaults
foreach ($this->_fields as $name => $field) {
if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
- if (!isset($this->_defaults[$name])) {
+ // check if the custom field is on a membership, we only want to load
+ // defaults for membership custom fields here, not contact fields
+ if (!isset($this->_defaults[$name])
+ && !CRM_Core_BAO_CustomGroup::checkCustomField($customFieldID, ['Membership'])
+ ) {
CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, $name, $this->_defaults,
$entityId, CRM_Profile_Form::MODE_REGISTER
);
@@ -287,7 +292,7 @@ public function buildQuickForm() {
// CRM-18399: used by template to pass pre profile id as a url arg
$this->assign('custom_pre_id', $this->_values['custom_pre_id']);
- $this->buildComponentForm($this->_id, $this);
+ $this->buildComponentForm();
}
// Build payment processor form
@@ -345,12 +350,12 @@ public function buildQuickForm() {
// build price set form.
$this->set('priceSetId', $this->_priceSetId);
if (empty($this->_ccid)) {
- CRM_Price_BAO_PriceSet::buildPriceSet($this, $this->getFormContext());
+ $this->buildPriceSet($this, $this->getFormContext());
}
if ($this->_values['is_monetary'] &&
$this->_values['is_recur'] && empty($this->_values['pledge_id'])
) {
- self::buildRecur($this);
+ $this->buildRecur();
}
}
@@ -362,7 +367,7 @@ public function buildQuickForm() {
//don't build pledge block when mid is passed
if (!$this->getRenewalMembershipID() && empty($this->_ccid)) {
if (CRM_Core_Component::isEnabled('CiviPledge') && !empty($this->_values['pledge_block_id'])) {
- CRM_Pledge_BAO_PledgeBlock::buildPledgeBlock($this);
+ $this->buildPledgeBlock();
}
}
@@ -397,10 +402,9 @@ public function buildQuickForm() {
CRM_Core_BAO_CMSUser::buildForm($this, $profileID, TRUE);
}
}
- if ($this->_pcpId && empty($this->_ccid)) {
+ if ($this->getPcpID() && empty($this->_ccid)) {
if (CRM_PCP_BAO_PCP::displayName($this->_pcpId)) {
$pcp_supporter_text = CRM_PCP_BAO_PCP::getPcpSupporterText($this->_pcpId, $this->_id, 'contribute');
- $this->assign('pcpSupporterText', $pcp_supporter_text);
}
$prms = ['id' => $this->_pcpId];
CRM_Core_DAO::commonRetrieve('CRM_PCP_DAO_PCP', $prms, $pcpInfo);
@@ -416,6 +420,7 @@ public function buildQuickForm() {
$this->addField('pcp_personal_note', ['entity' => 'ContributionSoft', 'context' => 'create', 'style' => 'height: 3em; width: 40em;']);
}
}
+ $this->assign('pcpSupporterText', $pcp_supporter_text ?? NULL);
if (empty($this->_values['fee']) && empty($this->_ccid)) {
throw new CRM_Core_Exception(ts('This page does not have any price fields configured or you may not have permission for them. Please contact the site administrator for more details.'));
}
@@ -464,6 +469,122 @@ public function buildQuickForm() {
$this->addFormRule(['CRM_Contribute_Form_Contribution_Main', 'formRule'], $this);
}
+ /**
+ * Build the price set form.
+ *
+ * @param CRM_Core_Form $form
+ * @param string|null $component
+ *
+ * @return void
+ * @throws \CRM_Core_Exception
+ */
+ private function buildPriceSet(&$form, $component = NULL) {
+ $validPriceFieldIds = array_keys($this->getPriceFieldMetaData());
+ $form->assign('priceSet', $form->_priceSet);
+
+ // @todo - this hook wrangling can be done earlier if we set the form on $this->>order.
+ $feeBlock = &$form->_values['fee'];
+ // Call the buildAmount hook.
+ CRM_Utils_Hook::buildAmount($component ?? 'contribution', $form, $feeBlock);
+
+ // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
+ $adminFieldVisible = CRM_Core_Permission::check('administer CiviCRM');
+ $checklifetime = FALSE;
+ foreach ($this->getPriceFieldMetaData() as $id => $field) {
+ if ($field['visibility_id:name'] === 'public' ||
+ ($field['visibility_id:name'] === 'admin' && $adminFieldVisible)
+ ) {
+ $options = $field['options'] ?? NULL;
+ if ($this->_membershipContactID && $options) {
+ $contactsLifetimeMemberships = CRM_Member_BAO_Membership::getAllContactMembership($this->_membershipContactID, FALSE, TRUE);
+ $contactsLifetimeMembershipTypes = array_column($contactsLifetimeMemberships, 'membership_type_id');
+ $memTypeIdsInPriceField = array_column($options, 'membership_type_id');
+ $isCurrentMember = (bool) array_intersect($memTypeIdsInPriceField, $contactsLifetimeMembershipTypes);
+ $checklifetime = $checklifetime ?: $isCurrentMember;
+ }
+
+ if (!is_array($options) || !in_array($id, $validPriceFieldIds)) {
+ continue;
+ }
+ if (!CRM_Core_Permission::check('edit contributions')) {
+ foreach ($options as $key => $currentOption) {
+ if ($currentOption['visibility_id:name'] === 'admin') {
+ unset($options[$key]);
+ }
+ }
+ }
+ if (!empty($options)) {
+ $label = (!empty($this->_membershipBlock) && $field['name'] === 'contribution_amount') ? ts('Additional Contribution') : $field['label'];
+ $extra = [];
+ $fieldID = (int) $field['id'];
+ if ($fieldID === $this->getPriceFieldOtherID()) {
+ $extra = [
+ 'onclick' => 'useAmountOther("price_' . $this->getPriceFieldMainID() . '");',
+ 'autocomplete' => 'off',
+ ];
+ }
+ if ($fieldID === $this->getPriceFieldMainID()) {
+ $extra = [
+ 'onclick' => 'clearAmountOther("price_' . $this->getPriceFieldOtherID() . '");',
+ ];
+ }
+
+ CRM_Price_BAO_PriceField::addQuickFormElement($form,
+ 'price_' . $fieldID,
+ $field['id'],
+ FALSE,
+ $field['is_required'] ?? FALSE,
+ $label,
+ $options,
+ [],
+ $extra
+ );
+ }
+ }
+ }
+ $form->assign('hasExistingLifetimeMembership', $checklifetime);
+ }
+
+ /**
+ * Get the idea of the other amount field if the form is configured to offer it.
+ *
+ * The other amount field is an alternative to the configured radio options,
+ * specific to this form.
+ *
+ * @return int|null
+ */
+ private function getPriceFieldOtherID(): ?int {
+ if (!$this->isQuickConfig()) {
+ return NULL;
+ }
+ foreach ($this->order->getPriceFieldsMetadata() as $field) {
+ if ($field['name'] === 'other_amount') {
+ return (int) $field['id'];
+ }
+ }
+ return NULL;
+ }
+
+ /**
+ * Get the idea of the other amount field if the form is configured to offer an other amount.
+ *
+ * The other amount field is an alternative to the configured radio options,
+ * specific to this form.
+ *
+ * @return int|null
+ */
+ private function getPriceFieldMainID(): ?int {
+ if (!$this->isQuickConfig() || !$this->getPriceFieldOtherID()) {
+ return NULL;
+ }
+ foreach ($this->order->getPriceFieldsMetadata() as $field) {
+ if ($field['name'] !== 'other_amount') {
+ return (int) $field['id'];
+ }
+ }
+ return NULL;
+ }
+
/**
* Build Membership Block in Contribution Pages.
* @todo this was shared on CRM_Contribute_Form_ContributionBase but we are refactoring and simplifying for each
@@ -476,7 +597,7 @@ public function buildQuickForm() {
*/
private function buildMembershipBlock() {
$cid = $this->_membershipContactID;
- $isTest = (bool) ($this->_action & CRM_Core_Action::PREVIEW);
+ $isTest = (bool) ($this->getAction() & CRM_Core_Action::PREVIEW);
$separateMembershipPayment = FALSE;
$this->addOptionalQuickFormElement('auto_renew');
if ($this->_membershipBlock) {
@@ -491,7 +612,7 @@ private function buildMembershipBlock() {
$separateMembershipPayment = $this->_membershipBlock['is_separate_payment'] ?? NULL;
- foreach ($this->_priceSet['fields'] as $pField) {
+ foreach ($this->getPriceFieldMetaData() as $pField) {
if (empty($pField['options'])) {
continue;
}
@@ -567,7 +688,7 @@ private function buildMembershipBlock() {
if ($membership["membership_type_id.duration_unit:name"] === 'lifetime') {
unset($radio[$memType['id']]);
unset($radioOptAttrs[$memType['id']]);
- $this->assign('islifetime', TRUE);
+ $this->assign('hasExistingLifetimeMembership', TRUE);
continue;
}
$this->assign('renewal_mode', TRUE);
@@ -618,15 +739,14 @@ private function buildMembershipBlock() {
/**
* Build elements to collect information for recurring contributions.
*
- *
- * @param CRM_Core_Form $form
+ * Previously shared function.
*/
- public static function buildRecur(&$form) {
+ private function buildRecur(): void {
+ $form = $this;
$attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_ContributionRecur');
- $className = get_class($form);
- $form->assign('is_recur_interval', CRM_Utils_Array::value('is_recur_interval', $form->_values));
- $form->assign('is_recur_installments', CRM_Utils_Array::value('is_recur_installments', $form->_values));
+ $form->assign('is_recur_interval', $this->getContributionPageValue('is_recur_interval'));
+ $form->assign('is_recur_installments', $this->getContributionPageValue('is_recur_installments'));
$paymentObject = $form->getVar('_paymentObject');
if ($paymentObject) {
$form->assign('recurringHelpText', $paymentObject->getText('contributionPageRecurringHelp', [
@@ -637,13 +757,6 @@ public static function buildRecur(&$form) {
$frUnits = $form->_values['recur_frequency_unit'] ?? NULL;
$frequencyUnits = CRM_Core_OptionGroup::values('recur_frequency_units', FALSE, FALSE, TRUE);
- if (empty($frUnits) &&
- $className == 'CRM_Contribute_Form_Contribution'
- ) {
- $frUnits = implode(CRM_Core_DAO::VALUE_SEPARATOR,
- CRM_Core_OptionGroup::values('recur_frequency_units', FALSE, FALSE, FALSE, NULL, 'value')
- );
- }
$unitVals = explode(CRM_Core_DAO::VALUE_SEPARATOR, $frUnits);
@@ -664,7 +777,7 @@ public static function buildRecur(&$form) {
if (count($unitVals) == 1) {
$form->assign('one_frequency_unit', TRUE);
$form->add('hidden', 'frequency_unit', $unitVals[0]);
- if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
+ if (!empty($form->_values['is_recur_interval'])) {
$unit = CRM_Contribute_BAO_Contribution::getUnitLabelWithPlural($unitVals[0]);
$form->assign('frequency_unit', $unit);
}
@@ -681,7 +794,7 @@ public static function buildRecur(&$form) {
foreach ($unitVals as $key => $val) {
if (array_key_exists($val, $frequencyUnits)) {
$units[$val] = $frequencyUnits[$val];
- if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
+ if (!empty($form->_values['is_recur_interval'])) {
$units[$val] = CRM_Contribute_BAO_Contribution::getUnitLabelWithPlural($val);
$unit = ts('Every');
}
@@ -690,7 +803,7 @@ public static function buildRecur(&$form) {
$frequencyUnit = &$form->add('select', 'frequency_unit', NULL, $units, FALSE, ['aria-label' => ts('Frequency Unit'), 'class' => 'crm-select2 eight']);
}
- if (!empty($form->_values['is_recur_interval']) || $className == 'CRM_Contribute_Form_Contribution') {
+ if (!empty($form->_values['is_recur_interval'])) {
$form->add('text', 'frequency_interval', $unit, $attributes['frequency_interval'] + ['aria-label' => ts('Every'), 'class' => 'two']);
$form->addRule('frequency_interval', ts('Frequency must be a whole number (EXAMPLE: Every 3 months).'), 'integer');
}
@@ -716,7 +829,7 @@ public static function buildRecur(&$form) {
*/
public static function formRule($fields, $files, $self) {
$errors = [];
- $amount = self::computeAmount($fields, $self->_values);
+ $amount = $self->computeAmount($fields, $self->_values);
if (!empty($fields['auto_renew']) && empty($fields['payment_processor_id'])) {
$errors['auto_renew'] = ts('You cannot have auto-renewal on if you are paying later.');
}
@@ -908,7 +1021,7 @@ public static function formRule($fields, $files, $self) {
}
if (isset($fields['selectProduct']) &&
- $fields['selectProduct'] != 'no_thanks'
+ $fields['selectProduct'] !== 'no_thanks'
) {
$productDAO = new CRM_Contribute_DAO_Product();
$productDAO->id = $fields['selectProduct'];
@@ -1028,7 +1141,7 @@ public static function formRule($fields, $files, $self) {
*
* @return int|mixed|null|string
*/
- public static function computeAmount($params, $formValues) {
+ private function computeAmount($params, $formValues) {
$amount = 0;
// First clean up the other amount field if present.
if (isset($params['amount_other'])) {
@@ -1131,13 +1244,13 @@ public function submit($params) {
}
}
}
-
- if (!empty($this->_ccid) && !empty($this->_pendingAmount)) {
- $params['amount'] = $this->_pendingAmount;
+ $balance = $this->getContributionBalance();
+ if ($balance) {
+ $params['amount'] = $balance;
}
else {
// from here on down, $params['amount'] holds a monetary value (or null) rather than an option ID
- $params['amount'] = self::computeAmount($params, $this->_values);
+ $params['amount'] = $this->computeAmount($params, $this->_values);
}
$params['separate_amount'] = $params['amount'];
@@ -1177,11 +1290,11 @@ public function submit($params) {
$this->set('amount_level', CRM_Utils_Array::value('amount_level', $params));
}
- $priceSetId = $params['priceSetId'] ?? NULL;
+ $priceSetID = $this->getPriceSetID();
if (!empty($this->_ccid)) {
$this->set('lineItem', [$this->getPriceSetID() => $this->getExistingContributionLineItems()]);
}
- elseif ($priceSetId) {
+ elseif ($priceSetID) {
$lineItem = [];
if ($this->isQuickConfig()) {
foreach ($this->_values['fee'] as $key => & $val) {
@@ -1201,17 +1314,17 @@ public function submit($params) {
}
if ($this->_membershipBlock) {
- $this->processAmountAndGetAutoRenew($this->_values['fee'], $params, $lineItem[$priceSetId], $priceSetId);
+ $this->processAmountAndGetAutoRenew($this->_values['fee'], $params, $lineItem[$priceSetID]);
}
else {
- CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem[$priceSetId], $priceSetId);
+ CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem[$priceSetID], $priceSetID);
}
if ($proceFieldAmount) {
- $lineItem[$params['priceSetId']][$fieldOption]['unit_price'] = $proceFieldAmount;
- $lineItem[$params['priceSetId']][$fieldOption]['line_total'] = $proceFieldAmount;
- if (isset($lineItem[$params['priceSetId']][$fieldOption]['tax_amount'])) {
- $proceFieldAmount += $lineItem[$params['priceSetId']][$fieldOption]['tax_amount'];
+ $lineItem[$priceSetID][$fieldOption]['unit_price'] = $proceFieldAmount;
+ $lineItem[$priceSetID][$fieldOption]['line_total'] = $proceFieldAmount;
+ if (isset($lineItem[$priceSetID][$fieldOption]['tax_amount'])) {
+ $proceFieldAmount += $lineItem[$priceSetID][$fieldOption]['tax_amount'];
}
if (!$this->_membershipBlock['is_separate_payment']) {
//require when separate membership not used
@@ -1333,24 +1446,11 @@ public function assignFormVariablesByContributionID(): void {
}
}
$this->assign('dummyTitle', $dummyTitle);
-
+ $this->assign('pendingAmount', $this->getContributionBalance());
if (empty($this->getExistingContributionID())) {
return;
}
- if (!$this->getContactID()) {
- CRM_Core_Error::statusBounce(ts("Returning since there is no contact attached to this contribution id."));
- }
-
- $paymentBalance = CRM_Contribute_BAO_Contribution::getContributionBalance($this->_ccid);
- //bounce if the contribution is not pending.
- if ((float) $paymentBalance <= 0) {
- CRM_Core_Error::statusBounce(ts("Returning since contribution has already been handled."));
- }
- if (!empty($paymentBalance)) {
- $this->_pendingAmount = $paymentBalance;
- $this->assign('pendingAmount', $this->_pendingAmount);
- }
-
+ // @todo - all this stuff is likely obsolete.
if ($taxAmount = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->_ccid, 'tax_amount')) {
$this->assign('taxAmount', $taxAmount);
}
@@ -1361,6 +1461,29 @@ public function assignFormVariablesByContributionID(): void {
$this->assign('priceSetID', $this->getPriceSetID());
}
+ /**
+ * Get the balance amount if an existing contribution is being paid.
+ *
+ * @return float|null
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function getContributionBalance(): ?float {
+ if (empty($this->getExistingContributionID())) {
+ return NULL;
+ }
+ if (!$this->getContactID()) {
+ CRM_Core_Error::statusBounce(ts('Returning since there is no contact attached to this contribution id.'));
+ }
+
+ $paymentBalance = CRM_Contribute_BAO_Contribution::getContributionBalance($this->_ccid);
+ //bounce if the contribution is not pending.
+ if ((float) $paymentBalance <= 0) {
+ CRM_Core_Error::statusBounce(ts('Returning since contribution has already been handled.'));
+ }
+ return $paymentBalance;
+ }
+
/**
* Function for unit tests on the postProcess function.
*
@@ -1382,7 +1505,7 @@ public function testSubmit($params) {
*
* @param array $params
*
- * @return mixed
+ * @return bool
* @throws \CRM_Core_Exception
*/
protected function hasSeparateMembershipPaymentAmount($params) {
@@ -1407,4 +1530,354 @@ protected function getCurrentPaymentProcessor(): ?int {
return NULL;
}
+ /**
+ * Add onbehalf/honoree profile fields and native module fields.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function buildComponentForm(): void {
+
+ foreach (['soft_credit', 'on_behalf'] as $module) {
+ if ($module === 'soft_credit') {
+ $this->addSoftCreditFields();
+ }
+ else {
+ $this->addOnBehalfFields();
+ }
+ }
+
+ }
+
+ /**
+ * Add soft credit fields.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function addSoftCreditFields(): void {
+ if (!empty($this->_values['honoree_profile_id'])) {
+ if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_values['honoree_profile_id'], 'is_active')) {
+ CRM_Core_Error::statusBounce(ts('This contribution page has been configured for contribution on behalf of honoree and the selected honoree profile is either disabled or not found.'));
+ }
+
+ $profileContactType = CRM_Core_BAO_UFGroup::getContactType($this->_values['honoree_profile_id']);
+ $requiredProfileFields = [
+ 'Individual' => ['first_name', 'last_name'],
+ 'Organization' => ['organization_name', 'email'],
+ 'Household' => ['household_name', 'email'],
+ ];
+ $validProfile = CRM_Core_BAO_UFGroup::checkValidProfile($this->_values['honoree_profile_id'], $requiredProfileFields[$profileContactType]);
+ if (!$validProfile) {
+ CRM_Core_Error::statusBounce(ts('This contribution page has been configured for contribution on behalf of honoree and the required fields of the selected honoree profile are disabled or doesn\'t exist.'));
+ }
+
+ $softCreditTypes = CRM_Core_OptionGroup::values("soft_credit_type", FALSE);
+
+ // radio button for Honor Type
+ foreach ($this->_values['soft_credit_types'] as $value) {
+ $honorTypes[$value] = $softCreditTypes[$value];
+ }
+ $this->addRadio('soft_credit_type_id', NULL, $honorTypes, ['allowClear' => TRUE]);
+
+ $honoreeProfileFields = CRM_Core_BAO_UFGroup::getFields(
+ $this->_values['honoree_profile_id'], FALSE,
+ NULL, NULL,
+ NULL, FALSE,
+ NULL, TRUE,
+ NULL, CRM_Core_Permission::CREATE
+ );
+
+ // add the form elements
+ foreach ($honoreeProfileFields as $name => $field) {
+ // If soft credit type is not chosen then make omit requiredness from honoree profile fields
+ if (count($this->_submitValues) &&
+ empty($this->_submitValues['soft_credit_type_id']) &&
+ !empty($field['is_required'])
+ ) {
+ $field['is_required'] = FALSE;
+ }
+ CRM_Core_BAO_UFGroup::buildProfile($this, $field, CRM_Profile_Form::MODE_CREATE, NULL, FALSE, FALSE, NULL, 'honor');
+ }
+ }
+ $this->assign('honoreeProfileFields', $honoreeProfileFields ?? NULL);
+ $this->assign('honor_block_title', $this->_values['honor_block_title'] ?? NULL);
+ $this->assign('honor_block_text', $this->_values['honor_block_text'] ?? NULL);
+ }
+
+ /**
+ * Add the on behalf fields.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function addOnBehalfFields(): void {
+ $contactID = $this->getContactID();
+ if (!empty($this->_values['onbehalf_profile_id'])) {
+
+ if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $this->_values['onbehalf_profile_id'], 'is_active')) {
+ CRM_Core_Error::statusBounce(ts('This contribution page has been configured for contribution on behalf of an organization and the selected onbehalf profile is either disabled or not found.'));
+ }
+
+ $member = CRM_Member_BAO_Membership::getMembershipBlock($this->getContributionPageID());
+ if (empty($member['is_active'])) {
+ $msg = ts('Mixed profile not allowed for on behalf of registration/sign up.');
+ $onBehalfProfile = CRM_Core_BAO_UFGroup::profileGroups($this->_values['onbehalf_profile_id']);
+ foreach (
+ [
+ 'Individual',
+ 'Organization',
+ 'Household',
+ ] as $contactType
+ ) {
+ if (in_array($contactType, $onBehalfProfile) &&
+ (in_array('Membership', $onBehalfProfile) ||
+ in_array('Contribution', $onBehalfProfile)
+ )
+ ) {
+ CRM_Core_Error::statusBounce($msg);
+ }
+ }
+ }
+
+ if ($contactID) {
+ // retrieve all permissioned organizations of contact $contactID
+ $organizations = CRM_Contact_BAO_Relationship::getPermissionedContacts($contactID, NULL, NULL, 'Organization');
+
+ if (count($organizations)) {
+ // Related org url - pass checksum if needed
+ $args = [
+ 'ufID' => $this->_values['onbehalf_profile_id'],
+ 'cid' => '',
+ ];
+ if (!empty($_GET['cs'])) {
+ $args = [
+ 'ufID' => $this->_values['onbehalf_profile_id'],
+ 'uid' => $this->_contactID,
+ 'cs' => $_GET['cs'],
+ 'cid' => '',
+ ];
+ }
+ $locDataURL = CRM_Utils_System::url('civicrm/ajax/permlocation', $args, FALSE, NULL, FALSE);
+ }
+ if (count($organizations) > 0) {
+ $this->add('select', 'onbehalfof_id', '', CRM_Utils_Array::collect('name', $organizations));
+
+ $orgOptions = [
+ 0 => ts('Select an existing organization'),
+ 1 => ts('Enter a new organization'),
+ ];
+ $this->addRadio('org_option', ts('options'), $orgOptions);
+ $this->setDefaults(['org_option' => 0]);
+ }
+ }
+
+ if (!empty($this->_values['is_for_organization'])) {
+ if ((int) $this->_values['is_for_organization'] !== 2) {
+ $this->addElement('checkbox', 'is_for_organization',
+ $this->_values['for_organization'],
+ NULL
+ );
+ }
+ }
+
+ $profileFields = CRM_Core_BAO_UFGroup::getFields(
+ $this->_values['onbehalf_profile_id'],
+ FALSE, CRM_Core_Action::VIEW, NULL,
+ NULL, FALSE, NULL, FALSE, NULL,
+ CRM_Core_Permission::CREATE, NULL
+ );
+
+ $fieldTypes = ['Contact', 'Organization'];
+ if (!empty($this->_membershipBlock)) {
+ $fieldTypes = array_merge($fieldTypes, ['Membership']);
+ }
+ $contactSubType = CRM_Contact_BAO_ContactType::subTypes('Organization');
+ $fieldTypes = array_merge($fieldTypes, $contactSubType);
+
+ foreach ($profileFields as $name => $field) {
+ if (in_array($field['field_type'], $fieldTypes)) {
+ [$prefixName, $index] = CRM_Utils_System::explode('-', $name, 2);
+ if (in_array($prefixName, ['organization_name', 'email']) && empty($field['is_required'])) {
+ $field['is_required'] = 1;
+ }
+ if (count($this->_submitValues) &&
+ empty($this->_submitValues['is_for_organization']) &&
+ $this->_values['is_for_organization'] == 1 &&
+ !empty($field['is_required'])
+ ) {
+ $field['is_required'] = FALSE;
+ }
+ CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, NULL, FALSE, 'onbehalf', NULL, 'onbehalf');
+ }
+ }
+ }
+ $this->assign('onBehalfRequired', (int) ($this->_values['is_for_organization'] ?? 0) === 2);
+ $this->assign('locDataURL', $locDataURL ?? NULL);
+ $this->assign('onBehalfOfFields', $profileFields ?? NULL);
+ $this->assign('fieldSetTitle', empty($this->_values['onbehalf_profile_id']) ? NULL : CRM_Core_BAO_UFGroup::getFrontEndTitle($this->_values['onbehalf_profile_id']));
+ // @todo - this is horrible - we are accessing a value in the POST rather than via QF. _submitValues is 'raw'
+ $this->assign('submittedOnBehalf', $this->_submitValues['onbehalfof_id'] ?? NULL);
+ $this->assign('submittedOnBehalfInfo', empty($this->_submitValues['onbehalf']) ? NULL : json_encode(str_replace('"', '\"', $this->_submitValues['onbehalf']), JSON_HEX_APOS));
+ }
+
+ /**
+ * Build Pledge Block in Contribution Pages.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function buildPledgeBlock() {
+ //build pledge payment fields.
+ if (!empty($this->_values['pledge_id'])) {
+ //get all payments required details.
+ $allPayments = [];
+ $returnProperties = [
+ 'status_id',
+ 'scheduled_date',
+ 'scheduled_amount',
+ 'currency',
+ ];
+ CRM_Core_DAO::commonRetrieveAll('CRM_Pledge_DAO_PledgePayment', 'pledge_id',
+ $this->_values['pledge_id'], $allPayments, $returnProperties
+ );
+ // get all status
+ $allStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
+
+ $nextPayment = [];
+ $isNextPayment = FALSE;
+ $overduePayments = [];
+ foreach ($allPayments as $payID => $value) {
+ if ($allStatus[$value['status_id']] == 'Overdue') {
+ $overduePayments[$payID] = [
+ 'id' => $payID,
+ 'scheduled_amount' => CRM_Utils_Rule::cleanMoney($value['scheduled_amount']),
+ 'scheduled_amount_currency' => $value['currency'],
+ 'scheduled_date' => CRM_Utils_Date::customFormat($value['scheduled_date'],
+ '%B %d'
+ ),
+ ];
+ }
+ elseif (!$isNextPayment &&
+ $allStatus[$value['status_id']] == 'Pending'
+ ) {
+ // get the next payment.
+ $nextPayment = [
+ 'id' => $payID,
+ 'scheduled_amount' => CRM_Utils_Rule::cleanMoney($value['scheduled_amount']),
+ 'scheduled_amount_currency' => $value['currency'],
+ 'scheduled_date' => CRM_Utils_Date::customFormat($value['scheduled_date'],
+ '%B %d'
+ ),
+ ];
+ $isNextPayment = TRUE;
+ }
+ }
+
+ // build check box array for payments.
+ $payments = [];
+ if (!empty($overduePayments)) {
+ foreach ($overduePayments as $id => $payment) {
+ $label = ts("%1 - due on %2 (overdue)", [
+ 1 => CRM_Utils_Money::format(CRM_Utils_Array::value('scheduled_amount', $payment), CRM_Utils_Array::value('scheduled_amount_currency', $payment)),
+ 2 => $payment['scheduled_date'] ?? NULL,
+ ]);
+ $paymentID = $payment['id'] ?? NULL;
+ $payments[] = $this->createElement('checkbox', $paymentID, NULL, $label, ['amount' => CRM_Utils_Array::value('scheduled_amount', $payment)]);
+ }
+ }
+
+ if (!empty($nextPayment)) {
+ $label = ts("%1 - due on %2", [
+ 1 => CRM_Utils_Money::format(CRM_Utils_Array::value('scheduled_amount', $nextPayment), CRM_Utils_Array::value('scheduled_amount_currency', $nextPayment)),
+ 2 => $nextPayment['scheduled_date'] ?? NULL,
+ ]);
+ $paymentID = $nextPayment['id'] ?? NULL;
+ $payments[] = $this->createElement('checkbox', $paymentID, NULL, $label, ['amount' => CRM_Utils_Array::value('scheduled_amount', $nextPayment)]);
+ }
+ // give error if empty or build form for payment.
+ if (empty($payments)) {
+ throw new CRM_Core_Exception(ts('Oops. It looks like there is no valid payment status for online payment.'));
+ }
+ $this->addGroup($payments, 'pledge_amount', ts('Make Pledge Payment(s):'), ' ');
+ }
+ else {
+ $pledgeBlock = [];
+
+ $dao = new CRM_Pledge_DAO_PledgeBlock();
+ $dao->entity_table = 'civicrm_contribution_page';
+ $dao->entity_id = $pageID;
+ if ($dao->find(TRUE)) {
+ CRM_Core_DAO::storeValues($dao, $pledgeBlock);
+ }
+ // build form for pledge creation.
+ $pledgeOptions = [
+ '0' => ts('I want to make a one-time contribution'),
+ '1' => ts('I pledge to contribute this amount every'),
+ ];
+ $this->addRadio('is_pledge', ts('Pledge Frequency Interval'), $pledgeOptions,
+ NULL, [' ']
+ );
+ $this->addElement('text', 'pledge_installments', ts('Installments'), ['size' => 3, 'aria-label' => ts('Installments')]);
+
+ if (!empty($pledgeBlock['is_pledge_interval'])) {
+ $this->addElement('text', 'pledge_frequency_interval', NULL, ['size' => 3, 'aria-label' => ts('Frequency Intervals')]);
+ }
+ else {
+ $this->add('hidden', 'pledge_frequency_interval', 1);
+ }
+ // Frequency unit drop-down label suffixes switch from *ly to *(s)
+ $freqUnitVals = explode(CRM_Core_DAO::VALUE_SEPARATOR, $pledgeBlock['pledge_frequency_unit']);
+ $freqUnits = [];
+ $frequencyUnits = CRM_Core_OptionGroup::values('recur_frequency_units');
+ foreach ($freqUnitVals as $key => $val) {
+ if (array_key_exists($val, $frequencyUnits)) {
+ $freqUnits[$val] = !empty($pledgeBlock['is_pledge_interval']) ? "{$frequencyUnits[$val]}(s)" : $frequencyUnits[$val];
+ }
+ }
+ $this->addElement('select', 'pledge_frequency_unit', NULL, $freqUnits, ['aria-label' => ts('Frequency Units')]);
+ // CRM-18854
+ if (!empty($pledgeBlock['is_pledge_start_date_visible'])) {
+ if (!empty($pledgeBlock['pledge_start_date'])) {
+ $defaults = [];
+ $date = (array) json_decode($pledgeBlock['pledge_start_date']);
+ foreach ($date as $field => $value) {
+ switch ($field) {
+ case 'contribution_date':
+ $this->add('datepicker', 'start_date', ts('First installment payment'), [], FALSE, ['time' => FALSE]);
+ $paymentDate = $value = date('Y-m-d');
+ $defaults['start_date'] = $value;
+ $this->assign('is_date', TRUE);
+ break;
+
+ case 'calendar_date':
+ $this->add('datepicker', 'start_date', ts('First installment payment'), [], FALSE, ['time' => FALSE]);
+ $defaults['start_date'] = $value;
+ $this->assign('is_date', TRUE);
+ $paymentDate = $value;
+ break;
+
+ case 'calendar_month':
+ $month = CRM_Utils_Date::getCalendarDayOfMonth();
+ $this->add('select', 'start_date', ts('Day of month installments paid'), $month);
+ $paymentDate = CRM_Pledge_BAO_Pledge::getPaymentDate($value);
+ $defaults['start_date'] = $paymentDate;
+ break;
+
+ default:
+ break;
+
+ }
+ $this->setDefaults($defaults);
+ $this->assign('start_date_display', $paymentDate);
+ $this->assign('start_date_editable', FALSE);
+ if (!empty($pledgeBlock['is_pledge_start_date_editable'])) {
+ $this->assign('start_date_editable', TRUE);
+ if ($field == 'calendar_month') {
+ $this->assign('is_date', FALSE);
+ $this->setDefaults(['start_date' => $value]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/CRM/Contribute/Form/ContributionBase.php b/CRM/Contribute/Form/ContributionBase.php
index ac9a967edbc3..46fb52bf9d64 100644
--- a/CRM/Contribute/Form/ContributionBase.php
+++ b/CRM/Contribute/Form/ContributionBase.php
@@ -15,11 +15,14 @@
* @copyright CiviCRM LLC https://civicrm.org/licensing
*/
+use Civi\Api4\PriceSet;
+
/**
* This class generates form components for processing a contribution.
*/
class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
use CRM_Financial_Form_FrontEndPaymentFormTrait;
+ use CRM_Contribute_Form_ContributeFormTrait;
/**
* The id of the contribution page that we are processing.
@@ -114,6 +117,8 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
* Pcp id
*
* @var int
+ *
+ * @internal use getPcpID().
*/
public $_pcpId;
@@ -268,11 +273,41 @@ public function getPriceSetID(): ?int {
else {
$this->_priceSetId = CRM_Price_BAO_PriceSet::getFor('civicrm_contribution_page', $this->_id);
}
+ if (!$this->_priceSetId) {
+ if ($this->isShowMembershipBlock()) {
+ $this->_priceSetId = PriceSet::get(FALSE)
+ ->addWhere('name', '=', 'default_membership_type_amount')
+ ->execute()
+ ->first()['id'];
+ }
+ }
$this->set('priceSetId', $this->_priceSetId);
}
return $this->_priceSetId ?: NULL;
}
+ /**
+ * Get id of contribution page being acted on.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @return int
+ */
+ public function getContributionPageID(): int {
+ if (!$this->_id) {
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+ if (!$this->_id) {
+ // seems like the session is corrupted and/or we lost the id trail
+ // lets just bump this to a regular session error and redirect user to main page
+ $this->controller->invalidKeyRedirect();
+ }
+ }
+ return $this->_id;
+ }
+
/**
* Set variables up before form is built.
*
@@ -282,13 +317,8 @@ public function getPriceSetID(): ?int {
public function preProcess() {
// current contribution page id
- $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+ $this->getContributionPageID();
$this->_ccid = CRM_Utils_Request::retrieve('ccid', 'Positive', $this);
- if (!$this->_id) {
- // seems like the session is corrupted and/or we lost the id trail
- // lets just bump this to a regular session error and redirect user to main page
- $this->controller->invalidKeyRedirect();
- }
$this->_emailExists = $this->get('emailExists');
$this->_contactID = $this->_membershipContactID = $this->getContactID();
@@ -354,6 +384,7 @@ public function preProcess() {
if ($this->getPriceSetID()) {
$this->order = new CRM_Financial_BAO_Order();
$this->order->setPriceSetID($this->getPriceSetID());
+ $this->order->setIsExcludeExpiredFields(TRUE);
}
else {
CRM_Core_Error::deprecatedFunctionWarning('forms require a price set ID');
@@ -366,11 +397,6 @@ public function preProcess() {
$this->_fields = [];
CRM_Contribute_BAO_ContributionPage::setValues($this->_id, $this->_values);
- if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()
- && !CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($this->_values['financial_type_id']))
- ) {
- CRM_Core_Error::statusBounce(ts('You do not have permission to access this page.'));
- }
if (empty($this->_values['is_active'])) {
throw new CRM_Contribute_Exception_InactiveContributionPageException(ts('The page you requested is currently unavailable.'), $this->_id);
}
@@ -455,10 +481,9 @@ public function preProcess() {
$this->set('membershipBlock', $this->getMembershipBlock());
// Handle PCP
- $pcpId = CRM_Utils_Request::retrieve('pcpId', 'Positive', $this);
- if ($pcpId) {
+ $pcpId = $this->getPcpID();
+ if ($this->getPcpID()) {
$pcp = CRM_PCP_BAO_PCP::handlePcp($pcpId, 'contribute', $this->_values);
- $this->_pcpId = $pcp['pcpId'];
$this->_pcpBlock = $pcp['pcpBlock'];
$this->_pcpInfo = $pcp['pcpInfo'];
}
@@ -473,10 +498,7 @@ public function preProcess() {
$this->assign('linkText', $linkText);
}
- //set pledge block if block id is set
- if (!empty($this->_values['pledge_block_id'])) {
- $this->assign('pledgeBlock', TRUE);
- }
+ $this->assign('pledgeBlock', !empty($this->_values['pledge_block_id']));
// @todo - move this check to `getMembershipBlock`
if (!$this->isFormSupportsNonMembershipContributions() &&
@@ -490,7 +512,6 @@ public function preProcess() {
$this->set('amount_block_is_active', $this->isFormSupportsNonMembershipContributions());
$this->_contributeMode = $this->get('contributeMode');
- $this->assign('contributeMode', $this->_contributeMode);
//assigning is_monetary and is_email_receipt to template
$this->assign('is_monetary', $this->_values['is_monetary']);
@@ -499,7 +520,7 @@ public function preProcess() {
//assign cancelSubscription URL to templates
$this->assign('cancelSubscriptionUrl',
- CRM_Utils_Array::value('cancelSubscriptionUrl', $this->_values)
+ $this->_values['cancelSubscriptionUrl'] ?? NULL
);
$title = $this->_values['frontend_title'];
@@ -543,19 +564,45 @@ private function initSet($form) {
if ($priceSetId) {
if ($form->_action & CRM_Core_Action::UPDATE) {
$form->_values['line_items'] = CRM_Price_BAO_LineItem::getLineItems($form->_id, 'contribution');
- $required = FALSE;
- }
- else {
- $required = TRUE;
}
-
- $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($priceSetId, $required);
- $form->_priceSet = $priceSet[$priceSetId] ?? NULL;
- $form->_values['fee'] = $form->_priceSet['fields'] ?? NULL;
+ $form->_priceSet = $this->order->getPriceSetMetadata();
+ $this->setPriceFieldMetaData($this->order->getPriceFieldsMetadata());
$form->set('priceSet', $form->_priceSet);
}
}
+ /**
+ * Set price field metadata.
+ *
+ * @param array $metadata
+ */
+ public function setPriceFieldMetaData(array $metadata): void {
+ $this->_values['fee'] = $this->_priceSet['fields'] = $metadata;
+ }
+
+ /**
+ * Get price field metadata.
+ *
+ * The returned value is an array of arrays where each array
+ * is an id-keyed price field and an 'options' key has been added to that
+ * arry for any options.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @return array
+ */
+ public function getPriceFieldMetaData(): array {
+ if (!empty($this->_values['fee'])) {
+ return $this->_values['fee'];
+ }
+ if (!empty($this->_priceSet['fields'])) {
+ return $this->_priceSet['fields'];
+ }
+ return $this->order->getPriceFieldsMetadata();
+ }
+
/**
* Set the default values.
*/
@@ -791,8 +838,6 @@ public function buildCustom($id, $name, $viewOnly = FALSE, $profileContactType =
}
}
- $this->assign($name, $fields);
-
if ($profileContactType && count($viewOnlyFileValues[$profileContactType])) {
$this->assign('viewOnlyPrefixFileValues', $viewOnlyFileValues);
}
@@ -801,6 +846,7 @@ public function buildCustom($id, $name, $viewOnly = FALSE, $profileContactType =
}
}
}
+ $this->assign($name, $fields ?? NULL);
}
/**
@@ -860,195 +906,6 @@ public function assignPaymentFields() {
}
}
- /**
- * Add onbehalf/honoree profile fields and native module fields.
- *
- * @param int $id
- * @param CRM_Core_Form $form
- *
- * @throws \CRM_Core_Exception
- */
- public function buildComponentForm($id, $form): void {
- if (empty($id)) {
- return;
- }
-
- $contactID = $this->getContactID();
-
- foreach (['soft_credit', 'on_behalf'] as $module) {
- if ($module === 'soft_credit') {
- if (empty($form->_values['honoree_profile_id'])) {
- continue;
- }
-
- if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $form->_values['honoree_profile_id'], 'is_active')) {
- CRM_Core_Error::statusBounce(ts('This contribution page has been configured for contribution on behalf of honoree and the selected honoree profile is either disabled or not found.'));
- }
-
- $profileContactType = CRM_Core_BAO_UFGroup::getContactType($form->_values['honoree_profile_id']);
- $requiredProfileFields = [
- 'Individual' => ['first_name', 'last_name'],
- 'Organization' => ['organization_name', 'email'],
- 'Household' => ['household_name', 'email'],
- ];
- $validProfile = CRM_Core_BAO_UFGroup::checkValidProfile($form->_values['honoree_profile_id'], $requiredProfileFields[$profileContactType]);
- if (!$validProfile) {
- CRM_Core_Error::statusBounce(ts('This contribution page has been configured for contribution on behalf of honoree and the required fields of the selected honoree profile are disabled or doesn\'t exist.'));
- }
-
- foreach (['honor_block_title', 'honor_block_text'] as $name) {
- $form->assign($name, $form->_values[$name]);
- }
-
- $softCreditTypes = CRM_Core_OptionGroup::values("soft_credit_type", FALSE);
-
- // radio button for Honor Type
- foreach ($form->_values['soft_credit_types'] as $value) {
- $honorTypes[$value] = $softCreditTypes[$value];
- }
- $form->addRadio('soft_credit_type_id', NULL, $honorTypes, ['allowClear' => TRUE]);
-
- $honoreeProfileFields = CRM_Core_BAO_UFGroup::getFields(
- $this->_values['honoree_profile_id'], FALSE,
- NULL, NULL,
- NULL, FALSE,
- NULL, TRUE,
- NULL, CRM_Core_Permission::CREATE
- );
- $form->assign('honoreeProfileFields', $honoreeProfileFields);
-
- // add the form elements
- foreach ($honoreeProfileFields as $name => $field) {
- // If soft credit type is not chosen then make omit requiredness from honoree profile fields
- if (count($form->_submitValues) &&
- empty($form->_submitValues['soft_credit_type_id']) &&
- !empty($field['is_required'])
- ) {
- $field['is_required'] = FALSE;
- }
- CRM_Core_BAO_UFGroup::buildProfile($form, $field, CRM_Profile_Form::MODE_CREATE, NULL, FALSE, FALSE, NULL, 'honor');
- }
- }
- else {
- if (empty($form->_values['onbehalf_profile_id'])) {
- continue;
- }
-
- if (!CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $form->_values['onbehalf_profile_id'], 'is_active')) {
- CRM_Core_Error::statusBounce(ts('This contribution page has been configured for contribution on behalf of an organization and the selected onbehalf profile is either disabled or not found.'));
- }
-
- $member = CRM_Member_BAO_Membership::getMembershipBlock($form->_id);
- if (empty($member['is_active'])) {
- $msg = ts('Mixed profile not allowed for on behalf of registration/sign up.');
- $onBehalfProfile = CRM_Core_BAO_UFGroup::profileGroups($form->_values['onbehalf_profile_id']);
- foreach (
- [
- 'Individual',
- 'Organization',
- 'Household',
- ] as $contactType
- ) {
- if (in_array($contactType, $onBehalfProfile) &&
- (in_array('Membership', $onBehalfProfile) ||
- in_array('Contribution', $onBehalfProfile)
- )
- ) {
- CRM_Core_Error::statusBounce($msg);
- }
- }
- }
-
- if ($contactID) {
- // retrieve all permissioned organizations of contact $contactID
- $organizations = CRM_Contact_BAO_Relationship::getPermissionedContacts($contactID, NULL, NULL, 'Organization');
-
- if (count($organizations)) {
- // Related org url - pass checksum if needed
- $args = [
- 'ufID' => $form->_values['onbehalf_profile_id'],
- 'cid' => '',
- ];
- if (!empty($_GET['cs'])) {
- $args = [
- 'ufID' => $form->_values['onbehalf_profile_id'],
- 'uid' => $this->_contactID,
- 'cs' => $_GET['cs'],
- 'cid' => '',
- ];
- }
- $locDataURL = CRM_Utils_System::url('civicrm/ajax/permlocation', $args, FALSE, NULL, FALSE);
- $form->assign('locDataURL', $locDataURL);
- }
- if (count($organizations) > 0) {
- $form->add('select', 'onbehalfof_id', '', CRM_Utils_Array::collect('name', $organizations));
-
- $orgOptions = [
- 0 => ts('Select an existing organization'),
- 1 => ts('Enter a new organization'),
- ];
- $form->addRadio('org_option', ts('options'), $orgOptions);
- $form->setDefaults(['org_option' => 0]);
- }
- }
-
- $form->assign('fieldSetTitle', CRM_Core_BAO_UFGroup::getFrontEndTitle($form->_values['onbehalf_profile_id']));
-
- if (!empty($form->_values['is_for_organization'])) {
- if ($form->_values['is_for_organization'] == 2) {
- $form->assign('onBehalfRequired', TRUE);
- }
- else {
- $form->addElement('checkbox', 'is_for_organization',
- $form->_values['for_organization'],
- NULL
- );
- }
- }
-
- $profileFields = CRM_Core_BAO_UFGroup::getFields(
- $form->_values['onbehalf_profile_id'],
- FALSE, CRM_Core_Action::VIEW, NULL,
- NULL, FALSE, NULL, FALSE, NULL,
- CRM_Core_Permission::CREATE, NULL
- );
-
- $form->assign('onBehalfOfFields', $profileFields);
- if (!empty($form->_submitValues['onbehalf'])) {
- if (!empty($form->_submitValues['onbehalfof_id'])) {
- $form->assign('submittedOnBehalf', $form->_submitValues['onbehalfof_id']);
- }
- $form->assign('submittedOnBehalfInfo', json_encode(str_replace('"', '\"', $form->_submitValues['onbehalf']), JSON_HEX_APOS));
- }
-
- $fieldTypes = ['Contact', 'Organization'];
- if (!empty($form->_membershipBlock)) {
- $fieldTypes = array_merge($fieldTypes, ['Membership']);
- }
- $contactSubType = CRM_Contact_BAO_ContactType::subTypes('Organization');
- $fieldTypes = array_merge($fieldTypes, $contactSubType);
-
- foreach ($profileFields as $name => $field) {
- if (in_array($field['field_type'], $fieldTypes)) {
- [$prefixName, $index] = CRM_Utils_System::explode('-', $name, 2);
- if (in_array($prefixName, ['organization_name', 'email']) && empty($field['is_required'])) {
- $field['is_required'] = 1;
- }
- if (count($form->_submitValues) &&
- empty($form->_submitValues['is_for_organization']) &&
- $form->_values['is_for_organization'] == 1 &&
- !empty($field['is_required'])
- ) {
- $field['is_required'] = FALSE;
- }
- CRM_Core_BAO_UFGroup::buildProfile($form, $field, NULL, NULL, FALSE, 'onbehalf', NULL, 'onbehalf');
- }
- }
- }
- }
-
- }
-
/**
* Check template file exists.
*
@@ -1245,10 +1102,9 @@ protected function getMainContributionAmount($params) {
* Params reflecting form input e.g with fields 'price_5' => 7, 'price_8' => array(7, 8)
* @param $lineItems
* Line item array to be altered.
- * @param int $priceSetID
*/
- public function processAmountAndGetAutoRenew($fields, &$params, &$lineItems, $priceSetID = NULL) {
- CRM_Price_BAO_PriceSet::processAmount($fields, $params, $lineItems, $priceSetID);
+ public function processAmountAndGetAutoRenew($fields, &$params, &$lineItems) {
+ CRM_Price_BAO_PriceSet::processAmount($fields, $params, $lineItems, $this->getPriceSetID());
$autoRenew = [];
$autoRenew[0] = $autoRenew[1] = $autoRenew[2] = 0;
foreach ($lineItems as $lineItem) {
@@ -1397,4 +1253,37 @@ protected function getExistingContributionLineItems(): array {
return $lineItems;
}
+ /**
+ * Get the PCP ID being contributed to.
+ *
+ * @return int|null
+ */
+ protected function getPcpID(): ?int {
+ if ($this->_pcpId === NULL) {
+ $this->_pcpId = CRM_Utils_Request::retrieve('pcpId', 'Positive', $this);
+ }
+ return $this->_pcpId ? (int) $this->_pcpId : NULL;
+ }
+
+ /**
+ * Get the selected Contribution ID.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getContributionID(): ?int {
+ if ($this->getExistingContributionID()) {
+ return $this->getExistingContributionID();
+ }
+ if (property_exists($this, '_contributionID')) {
+ // Available on Confirm form (which is tested), so this avoids
+ // accessing that directly & will work for ThankYou in time.
+ return $this->_contributionID;
+ }
+ return NULL;
+ }
+
}
diff --git a/CRM/Contribute/Form/ContributionCharts.php b/CRM/Contribute/Form/ContributionCharts.php
index 5b2005f74641..666546e0ca81 100644
--- a/CRM/Contribute/Form/ContributionCharts.php
+++ b/CRM/Contribute/Form/ContributionCharts.php
@@ -97,7 +97,7 @@ public function postProcess() {
$abbrMonthNames = CRM_Utils_Date::getAbbrMonthNames();
foreach ($abbrMonthNames as $monthKey => $monthName) {
- $val = CRM_Utils_Array::value($monthKey, $chartInfoMonthly['By Month'], 0);
+ $val = $chartInfoMonthly['By Month'][$monthKey] ?? 0;
// don't include zero value month.
if (!$val && ($chartType != 'bvg')) {
diff --git a/CRM/Contribute/Form/ContributionPage.php b/CRM/Contribute/Form/ContributionPage.php
index f09086dfd020..3b8f5a1d6fc0 100644
--- a/CRM/Contribute/Form/ContributionPage.php
+++ b/CRM/Contribute/Form/ContributionPage.php
@@ -34,13 +34,6 @@ class CRM_Contribute_Form_ContributionPage extends CRM_Core_Form {
*/
protected $_pledgeBlockID;
- /**
- * Are we in single form mode or wizard mode?
- *
- * @var bool
- */
- protected $_single;
-
/**
* Is this the first page?
*
@@ -48,19 +41,12 @@ class CRM_Contribute_Form_ContributionPage extends CRM_Core_Form {
*/
protected $_first = FALSE;
- /**
- * Is this the last page?
- *
- * @var bool
- */
- protected $_last = FALSE;
-
/**
* Store price set id.
*
* @var int
*/
- protected $_priceSetID = NULL;
+ protected $_priceSetID;
protected $_values;
@@ -82,11 +68,7 @@ public function getDefaultContext() {
* Set variables up before form is built.
*/
public function preProcess() {
- // current contribution page id
- $this->_id = CRM_Utils_Request::retrieve('id', 'Positive',
- $this, FALSE, NULL, 'REQUEST'
- );
- $this->assign('contributionPageID', $this->_id);
+ $this->assign('contributionPageID', $this->getContributionPageID());
// get the requested action
$this->_action = CRM_Utils_Request::retrieve('action', 'String',
@@ -97,16 +79,9 @@ public function preProcess() {
// setting title and 3rd level breadcrumb for html page if contrib page exists
if ($this->_id) {
$title = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $this->_id, 'title');
-
- if ($this->_action == CRM_Core_Action::UPDATE) {
- $this->_single = TRUE;
- }
}
- // CRM-16776 - show edit/copy/create buttons on Profiles Tab if user has required permission.
- if (CRM_Core_Permission::check('administer CiviCRM')) {
- $this->assign('perm', TRUE);
- }
+ $this->assign('perm', (bool) CRM_Core_Permission::check('administer CiviCRM'));
// set up tabs
CRM_Contribute_Form_ContributionPage_TabHeader::build($this);
@@ -166,57 +141,18 @@ public function buildQuickForm() {
$this->addElement('hidden', 'cancelURL', $this->_cancelURL);
}
- if ($this->_single) {
- $buttons = [
- [
- 'type' => 'next',
- 'name' => ts('Save'),
- 'spacing' => ' ',
- 'isDefault' => TRUE,
- ],
- [
- 'type' => 'upload',
- 'name' => ts('Save and Done'),
- 'spacing' => ' ',
- 'subName' => 'done',
- ],
- ];
- if (!$this->_last) {
- $buttons[] = [
- 'type' => 'submit',
- 'name' => ts('Save and Next'),
- 'spacing' => ' ',
- 'subName' => 'savenext',
- ];
- }
- $buttons[] = [
- 'type' => 'cancel',
- 'name' => ts('Cancel'),
- ];
- $this->addButtons($buttons);
- }
- else {
- $buttons = [];
- if (!$this->_first) {
- $buttons[] = [
- 'type' => 'back',
- 'name' => ts('Previous'),
- 'spacing' => ' ',
- ];
- }
- $buttons[] = [
+ $buttons = [
+ [
'type' => 'next',
- 'name' => ts('Continue'),
- 'spacing' => ' ',
+ 'name' => ts('Save'),
'isDefault' => TRUE,
- ];
- $buttons[] = [
+ ],
+ [
'type' => 'cancel',
'name' => ts('Cancel'),
- ];
-
- $this->addButtons($buttons);
- }
+ ],
+ ];
+ $this->addButtons($buttons);
$session->replaceUserContext($this->_cancelURL);
@@ -315,10 +251,8 @@ public function setDefaultValues() {
// get price set of type contributions
//this is the value for stored in db if price set extends contribution
- $usedFor = 2;
- $this->_priceSetID = CRM_Price_BAO_PriceSet::getFor('civicrm_contribution_page', $this->_id, $usedFor, 1);
- if ($this->_priceSetID) {
- $defaults['price_set_id'] = $this->_priceSetID;
+ if ($this->getPriceSetID()) {
+ $defaults['price_set_id'] = $this->getPriceSetID();
}
}
else {
@@ -463,4 +397,36 @@ public function getTemplateFileName() {
}
}
+ /**
+ * Get the price set ID for the event.
+ *
+ * @return int|null
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ */
+ public function getContributionPageID(): ?int {
+ if (!$this->_id) {
+ $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+ }
+ return $this->_id ? (int) $this->_id : NULL;
+ }
+
+ /**
+ * Get the price set ID for the contribution page.
+ *
+ * @return int|null
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ */
+ public function getPriceSetID(): ?int {
+ if (!$this->_priceSetID && $this->getContributionPageID()) {
+ $this->_priceSetID = CRM_Price_BAO_PriceSet::getFor('civicrm_contribution_page', $this->getContributionPageID());
+ }
+ return $this->_priceSetID ? (int) $this->_priceSetID : NULL;
+ }
+
}
diff --git a/CRM/Contribute/Form/ContributionPage/Amount.php b/CRM/Contribute/Form/ContributionPage/Amount.php
index 910d57e1a9e0..03df84064ade 100644
--- a/CRM/Contribute/Form/ContributionPage/Amount.php
+++ b/CRM/Contribute/Form/ContributionPage/Amount.php
@@ -98,9 +98,7 @@ public function buildQuickForm() {
if (count($recurringPaymentProcessor)) {
$this->assign('recurringPaymentProcessor', $recurringPaymentProcessor);
}
- if (count($futurePaymentProcessor)) {
- $this->assign('futurePaymentProcessor', $futurePaymentProcessor);
- }
+ $this->assign('futurePaymentProcessor', json_encode($futurePaymentProcessor ?? [], TRUE));
if (count($paymentProcessor)) {
$this->assign('paymentProcessor', $paymentProcessor);
}
@@ -144,7 +142,7 @@ public function buildQuickForm() {
else {
$this->assign('price', TRUE);
}
-
+ $this->assign('isQuick', $this->isQuickConfig());
$this->addSelect('price_set_id', [
'entity' => 'PriceSet',
'option_url' => 'civicrm/admin/price',
@@ -208,12 +206,10 @@ public function setDefaultValues() {
if (empty($defaults['pay_later_text'])) {
$defaults['pay_later_text'] = ts('I will send payment by check');
}
-
if (!empty($defaults['amount_block_is_active'])) {
if ($priceSetId = CRM_Price_BAO_PriceSet::getFor('civicrm_contribution_page', $this->_id, NULL)) {
- if ($isQuick = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceSetId, 'is_quick_config')) {
- $this->assign('isQuick', $isQuick);
+ if ($this->isQuickConfig()) {
//$priceField = CRM_Core_DAO::getFieldValue( 'CRM_Price_DAO_PriceField', $priceSetId, 'id', 'price_set_id' );
$options = $pFIDs = [];
$priceFieldParams = ['price_set_id' => $priceSetId];
@@ -447,7 +443,7 @@ public function postProcess() {
if (array_key_exists(CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessor', 'AuthNet',
'id', 'payment_processor_type_id'
),
- CRM_Utils_Array::value('payment_processor', $params)
+ ($params['payment_processor'] ?? NULL)
)) {
CRM_Core_Session::setStatus(ts(' Please note that the Authorize.net payment processor only allows recurring contributions and auto-renew memberships with payment intervals from 7-365 days or 1-12 months (i.e. not greater than 1 year).'), '', 'alert');
}
@@ -501,8 +497,8 @@ public function postProcess() {
$params['recur_frequency_unit'] = implode(CRM_Core_DAO::VALUE_SEPARATOR,
array_keys($params['recur_frequency_unit'])
);
- $params['is_recur_interval'] = CRM_Utils_Array::value('is_recur_interval', $params, FALSE);
- $params['is_recur_installments'] = CRM_Utils_Array::value('is_recur_installments', $params, FALSE);
+ $params['is_recur_interval'] = $params['is_recur_interval'] ?? FALSE;
+ $params['is_recur_installments'] = $params['is_recur_installments'] ?? FALSE;
}
if (!empty($params['adjust_recur_start_date'])) {
@@ -818,7 +814,7 @@ public function postProcess() {
}
if ($deleteAmountBlk) {
- $priceField = !empty($params['price_field_id']) ? $params['price_field_id'] : CRM_Utils_Array::value('price_field_other', $params);
+ $priceField = !empty($params['price_field_id']) ? $params['price_field_id'] : $params['price_field_other'] ?? NULL;
if ($priceField) {
$priceSetID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $priceField, 'price_set_id');
CRM_Price_BAO_PriceSet::setIsQuickConfig($priceSetID, 0);
@@ -828,6 +824,15 @@ public function postProcess() {
parent::endPostProcess();
}
+ /**
+ * Is the price set quick config.
+ *
+ * @return bool
+ */
+ private function isQuickConfig(): bool {
+ return $this->getPriceSetID() && CRM_Price_BAO_PriceSet::isQuickConfig($this->getPriceSetID());
+ }
+
/**
* Return a descriptive name for the page, used in wizard header
*
diff --git a/CRM/Contribute/Form/ContributionPage/Premium.php b/CRM/Contribute/Form/ContributionPage/Premium.php
index 7683f3d90015..258c4e1cbafe 100644
--- a/CRM/Contribute/Form/ContributionPage/Premium.php
+++ b/CRM/Contribute/Form/ContributionPage/Premium.php
@@ -127,8 +127,8 @@ public function postProcess() {
$params['id'] = $premiumID;
}
- $params['premiums_active'] = CRM_Utils_Array::value('premiums_active', $params, FALSE);
- $params['premiums_display_min_contribution'] = CRM_Utils_Array::value('premiums_display_min_contribution', $params, FALSE);
+ $params['premiums_active'] = $params['premiums_active'] ?? FALSE;
+ $params['premiums_display_min_contribution'] = $params['premiums_display_min_contribution'] ?? FALSE;
$params['entity_table'] = 'civicrm_contribution_page';
$params['entity_id'] = $this->_id;
diff --git a/CRM/Contribute/Form/ContributionPage/Settings.php b/CRM/Contribute/Form/ContributionPage/Settings.php
index ebf7b9cc7828..a91499ab6a5f 100644
--- a/CRM/Contribute/Form/ContributionPage/Settings.php
+++ b/CRM/Contribute/Form/ContributionPage/Settings.php
@@ -69,8 +69,8 @@ public function setDefaultValues() {
$defaults['honoree_profile'] = $ufGroupDAO->id;
}
$defaults['soft_credit_types'] = [
- CRM_Utils_Array::value('in_honor_of', $soft_credit_types),
- CRM_Utils_Array::value('in_memory_of', $soft_credit_types),
+ $soft_credit_types['in_honor_of'] ?? NULL,
+ $soft_credit_types['in_memory_of'] ?? NULL,
];
}
else {
@@ -92,8 +92,8 @@ public function setDefaultValues() {
$defaults['honoree_profile'] = $ufGroupDAO->id;
}
$defaults['soft_credit_types'] = [
- CRM_Utils_Array::value('in_honor_of', $soft_credit_types),
- CRM_Utils_Array::value('in_memory_of', $soft_credit_types),
+ $soft_credit_types['in_honor_of'] ?? NULL,
+ $soft_credit_types['in_memory_of'] ?? NULL,
];
}
@@ -311,11 +311,11 @@ public function postProcess() {
$params['currency'] = $config->defaultCurrency;
}
- $params['is_confirm_enabled'] = CRM_Utils_Array::value('is_confirm_enabled', $params, FALSE);
- $params['is_share'] = CRM_Utils_Array::value('is_share', $params, FALSE);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $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_confirm_enabled'] = $params['is_confirm_enabled'] ?? FALSE;
+ $params['is_share'] = $params['is_share'] ?? FALSE;
+ $params['is_active'] = $params['is_active'] ?? FALSE;
+ $params['is_credit_card_only'] = $params['is_credit_card_only'] ?? FALSE;
+ $params['honor_block_is_active'] = $params['honor_block_is_active'] ?? FALSE;
$params['is_for_organization'] = !empty($params['is_organization']) ? CRM_Utils_Array::value('is_for_organization', $params, FALSE) : 0;
$params['goal_amount'] = CRM_Utils_Rule::cleanMoney($params['goal_amount']);
@@ -389,15 +389,6 @@ public function postProcess() {
if ($this->_action & CRM_Core_Action::ADD) {
$url = 'civicrm/admin/contribute/amount';
$urlParams = "action=update&reset=1&id={$dao->id}";
- // special case for 'Save and Done' consistency.
- if ($this->controller->getButtonName('submit') == '_qf_Amount_upload_done') {
- $url = 'civicrm/admin/contribute';
- $urlParams = 'reset=1';
- CRM_Core_Session::setStatus(ts("'%1' information has been saved.",
- [1 => $this->getTitle()]
- ), ts('Saved'), 'success');
- }
-
CRM_Utils_System::redirect(CRM_Utils_System::url($url, $urlParams));
}
parent::endPostProcess();
diff --git a/CRM/Contribute/Form/ContributionPage/ThankYou.php b/CRM/Contribute/Form/ContributionPage/ThankYou.php
index f8cc668f0701..2b325bc60b61 100644
--- a/CRM/Contribute/Form/ContributionPage/ThankYou.php
+++ b/CRM/Contribute/Form/ContributionPage/ThankYou.php
@@ -100,7 +100,7 @@ public function postProcess() {
$params = $this->controller->exportValues($this->_name);
$params['id'] = $this->_id;
- $params['is_email_receipt'] = CRM_Utils_Array::value('is_email_receipt', $params, FALSE);
+ $params['is_email_receipt'] = $params['is_email_receipt'] ?? FALSE;
if (!$params['is_email_receipt']) {
$params['receipt_from_name'] = NULL;
$params['receipt_from_email'] = NULL;
diff --git a/CRM/Contribute/Form/ContributionPage/Widget.php b/CRM/Contribute/Form/ContributionPage/Widget.php
index 937d7457c35a..a8b838cbb4bc 100644
--- a/CRM/Contribute/Form/ContributionPage/Widget.php
+++ b/CRM/Contribute/Form/ContributionPage/Widget.php
@@ -241,7 +241,7 @@ public function postProcess() {
$params['id'] = $this->_widget->id;
}
$params['contribution_page_id'] = $this->_id;
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
$params['url_homepage'] = 'null';
$widget = new CRM_Contribute_DAO_Widget();
diff --git a/CRM/Contribute/Form/ContributionView.php b/CRM/Contribute/Form/ContributionView.php
index e3fa74ea259d..d68c4d30876d 100644
--- a/CRM/Contribute/Form/ContributionView.php
+++ b/CRM/Contribute/Form/ContributionView.php
@@ -21,6 +21,7 @@
* This class generates form components for Payment-Instrument.
*/
class CRM_Contribute_Form_ContributionView extends CRM_Core_Form {
+ use CRM_Contribute_Form_ContributeFormTrait;
/**
* Set variables up before form is built.
@@ -28,7 +29,7 @@ class CRM_Contribute_Form_ContributionView extends CRM_Core_Form {
* @throws \CRM_Core_Exception
*/
public function preProcess() {
- $id = $this->getID();
+ $id = $this->getContributionID();
// Check permission for action.
$actionMapping = [
@@ -82,11 +83,11 @@ public function preProcess() {
$values['contribution_page_title'] = '';
if (!empty($values['contribution_page_id'])) {
$contribPages = CRM_Contribute_PseudoConstant::contributionPage(NULL, TRUE);
- $values['contribution_page_title'] = CRM_Utils_Array::value(CRM_Utils_Array::value('contribution_page_id', $values), $contribPages);
+ $values['contribution_page_title'] = $contribPages[$values['contribution_page_id']] ?? '';
}
// get received into i.e to_financial_account_id from last trxn
- $financialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($this->getID(), 'DESC');
+ $financialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($this->getContributionID(), 'DESC');
$values['to_financial_account'] = '';
$values['payment_processor_name'] = '';
if (!empty($financialTrxnId['financialTrxnId'])) {
@@ -176,7 +177,7 @@ public function preProcess() {
}
//assign soft credit record if exists.
- $SCRecords = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($this->getID(), TRUE);
+ $SCRecords = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($this->getContributionID(), TRUE);
$this->assign('softContributions', empty($SCRecords['soft_credit']) ? NULL : $SCRecords['soft_credit']);
// unset doesn't complain if array member missing
unset($SCRecords['soft_credit']);
@@ -266,7 +267,7 @@ public function preProcess() {
$urlParams = "reset=1&id={$id}&cid={$values['contact_id']}&action=update&context={$context}&key={$searchKey}";
}
if (!$contribution['is_template']) {
- foreach (CRM_Contribute_BAO_Contribution::getContributionPaymentLinks($this->getID(), $contributionStatus) as $paymentButton) {
+ foreach (CRM_Contribute_BAO_Contribution::getContributionPaymentLinks($this->getContributionID(), $contributionStatus) as $paymentButton) {
$paymentButton['icon'] = 'fa-plus-circle';
$linkButtons[] = $paymentButton;
}
@@ -378,7 +379,7 @@ private function isHasAccess(string $action): bool {
try {
return Contribution::checkAccess()
->setAction($action)
- ->addValue('id', $this->getID())
+ ->addValue('id', $this->getContributionID())
->execute()->first()['access'];
}
catch (CRM_Core_Exception $e) {
@@ -387,16 +388,33 @@ private function isHasAccess(string $action): bool {
}
/**
- * Get the contribution ID.
+ * Get the selected Contribution ID.
*
- * @return int
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
*/
- private function getID(): int {
+ public function getContributionID(): ?int {
$id = $this->get('id');
- if (empty($id)) {
- CRM_Core_Error::statusBounce('Contribution ID is required');
+ if (!$id) {
+ $id = CRM_Utils_Request::retrieve('id', 'Positive');
}
- return $id;
+ return (int) $id;
+ }
+
+ /**
+ * Get id of contribution page being acted on.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getContributionPageID(): ?int {
+ return $this->getContributionID() ? $this->getContributionValue('contribution_page_id') : NULL;
}
}
diff --git a/CRM/Contribute/Form/Task/Invoice.php b/CRM/Contribute/Form/Task/Invoice.php
index c43a24be99b1..f8b885edcbb6 100644
--- a/CRM/Contribute/Form/Task/Invoice.php
+++ b/CRM/Contribute/Form/Task/Invoice.php
@@ -287,12 +287,12 @@ public static function printPDF($contribIDs, &$params, $contactIds) {
$lineItem = CRM_Price_BAO_LineItem::getLineItemsByContributionID($contributionID);
foreach ($lineItem as $taxRate) {
if (isset($dataArray[(string) $taxRate['tax_rate']])) {
- $dataArray[(string) $taxRate['tax_rate']] = $dataArray[(string) $taxRate['tax_rate']] + CRM_Utils_Array::value('tax_amount', $taxRate);
+ $dataArray[(string) $taxRate['tax_rate']] = $dataArray[(string) $taxRate['tax_rate']] + ($taxRate['tax_amount'] ?? 0);
}
else {
$dataArray[(string) $taxRate['tax_rate']] = $taxRate['tax_amount'] ?? NULL;
}
- $subTotal += CRM_Utils_Array::value('subTotal', $taxRate);
+ $subTotal += $taxRate['subTotal'] ?? 0;
}
// to email the invoice
diff --git a/CRM/Contribute/Form/Task/PDFLetter.php b/CRM/Contribute/Form/Task/PDFLetter.php
index 833bc44be9a4..1718cca1a701 100644
--- a/CRM/Contribute/Form/Task/PDFLetter.php
+++ b/CRM/Contribute/Form/Task/PDFLetter.php
@@ -241,7 +241,7 @@ public function postProcess() {
$contactIds = array_keys($contacts);
// CRM-16725 Skip creation of activities if user is previewing their PDF letter(s)
if ($this->isLiveMode()) {
- $this->createActivities($html_message, $contactIds, CRM_Utils_Array::value('subject', $formValues, ts('Thank you letter')), CRM_Utils_Array::value('campaign_id', $formValues), $contactHtml);
+ $this->createActivities($html_message, $contactIds, CRM_Utils_Array::value('subject', $formValues, ts('Thank you letter')), $formValues['campaign_id'] ?? NULL, $contactHtml);
}
$html = array_diff_key($html, $emailedHtml);
diff --git a/CRM/Contribute/Page/ContributionRecur.php b/CRM/Contribute/Page/ContributionRecur.php
index 644c4144b976..4236ae3a582a 100644
--- a/CRM/Contribute/Page/ContributionRecur.php
+++ b/CRM/Contribute/Page/ContributionRecur.php
@@ -51,7 +51,7 @@ public function view() {
}
$contributionRecur['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName(
- CRM_Utils_Array::value('payment_processor_id', $contributionRecur)
+ $contributionRecur['payment_processor_id'] ?? NULL
);
$idFields = ['contribution_status_id', 'campaign_id', 'financial_type_id'];
foreach ($idFields as $idField) {
diff --git a/CRM/Contribute/Page/DashBoard.php b/CRM/Contribute/Page/DashBoard.php
index b7df27e2f79d..aa8cdbbc413d 100644
--- a/CRM/Contribute/Page/DashBoard.php
+++ b/CRM/Contribute/Page/DashBoard.php
@@ -68,7 +68,7 @@ public function preProcess() {
}
//for contribution tabular View
- $buildTabularView = CRM_Utils_Array::value('showtable', $_GET, FALSE);
+ $buildTabularView = $_GET['showtable'] ?? FALSE;
$this->assign('buildTabularView', $buildTabularView);
if ($buildTabularView) {
return;
diff --git a/CRM/Contribute/Page/ManagePremiums.php b/CRM/Contribute/Page/ManagePremiums.php
index f1b2b7c86ae6..0c08a37687d2 100644
--- a/CRM/Contribute/Page/ManagePremiums.php
+++ b/CRM/Contribute/Page/ManagePremiums.php
@@ -53,28 +53,33 @@ public function &links() {
'url' => 'civicrm/admin/contribute/managePremiums',
'qs' => 'action=update&id=%%id%%&reset=1',
'title' => ts('Edit Premium'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
CRM_Core_Action::PREVIEW => [
'name' => ts('Preview'),
'url' => 'civicrm/admin/contribute/managePremiums',
'qs' => 'action=preview&id=%%id%%',
'title' => ts('Preview Premium'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::PREVIEW),
],
CRM_Core_Action::DISABLE => [
'name' => ts('Disable'),
'ref' => 'crm-enable-disable',
'title' => ts('Disable Premium'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE),
],
CRM_Core_Action::ENABLE => [
'name' => ts('Enable'),
'ref' => 'crm-enable-disable',
'title' => ts('Enable Premium'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE),
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
'url' => 'civicrm/admin/contribute/managePremiums',
'qs' => 'action=delete&id=%%id%%',
'title' => ts('Delete Premium'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
];
}
@@ -125,7 +130,7 @@ public function browse() {
$action -= CRM_Core_Action::DISABLE;
}
- $premiums[$dao->id]['action'] = CRM_Core_Action::formLink(self::links(),
+ $premiums[$dao->id]['action'] = CRM_Core_Action::formLink($this->links(),
$action,
['id' => $dao->id],
ts('more'),
diff --git a/CRM/Contribute/Page/Tab.php b/CRM/Contribute/Page/Tab.php
index 641bb6ee4f01..b9ed69a9ba76 100644
--- a/CRM/Contribute/Page/Tab.php
+++ b/CRM/Contribute/Page/Tab.php
@@ -428,7 +428,7 @@ public function preProcess() {
$this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse');
$this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
- if ($context == 'standalone') {
+ if ($context === 'standalone') {
$this->_action = CRM_Core_Action::ADD;
}
else {
@@ -439,11 +439,11 @@ public function preProcess() {
'return' => 'contact_id',
]);
}
- $this->assign('contactId', $this->_contactId);
// check logged in url permission
CRM_Contact_Page_View::checkUserPermission($this);
}
+ $this->assign('contactId', $this->_contactId);
$this->assign('action', $this->_action);
if ($this->_permission == CRM_Core_Permission::EDIT && !CRM_Core_Permission::check('edit contributions')) {
diff --git a/CRM/Contribute/Page/UserDashboard.php b/CRM/Contribute/Page/UserDashboard.php
index 96b94a18d73b..cdb2745468a7 100644
--- a/CRM/Contribute/Page/UserDashboard.php
+++ b/CRM/Contribute/Page/UserDashboard.php
@@ -32,7 +32,9 @@ public function listContribution(): void {
// which the tpl can iterate through - this should allow us to cope with competing attempts to add new buttons
// and allow extensions to assign new ones through the pageRun hook
// We could check for balance_amount > 0 here? It feels more correct but this seems to be working.
- if (in_array($row['contribution_status_id:name'], ['Pending', 'Partially paid'], TRUE)) {
+ if (in_array($row['contribution_status_id:name'], ['Pending', 'Partially paid'], TRUE)
+ && Civi::settings()->get('default_invoice_page')
+ ) {
$row['buttons']['pay'] = [
'class' => 'button',
'label' => ts('Pay Now'),
diff --git a/CRM/Contribute/Tokens.php b/CRM/Contribute/Tokens.php
index 5af208998fcd..625496528f87 100644
--- a/CRM/Contribute/Tokens.php
+++ b/CRM/Contribute/Tokens.php
@@ -10,8 +10,8 @@
+--------------------------------------------------------------------+
*/
-use Civi\Api4\ContributionPage;
-use Civi\Api4\ContributionRecur;
+use Civi\Api4\Address;
+use Civi\Token\TokenRow;
/**
* Class CRM_Contribute_Tokens
@@ -61,35 +61,61 @@ protected function getRelatedTokens(): array {
if (!array_key_exists('Contribution', \Civi::service('action_object_provider')->getEntities())) {
return $tokens;
}
+ $tokens += $this->getRelatedTokensForEntity('Address', 'address_id', ['name', 'id']);
+
+ $tokens['address_id.name']['title'] = ts('Billing Address Name');
+ $tokens['address_id.display'] = [
+ 'title' => ts('Billing Address'),
+ 'name' => 'address_id.display',
+ 'type' => 'mapped',
+ 'input_type' => 'Text',
+ 'audience' => 'user',
+ 'data_type' => 'String',
+ ];
+
// Ideally we would derive this from 'usage' - but it looks like adding the usage data
// was quite a bit of work & didn't leave the energy to implement - esp expose for
// where clauses (also, it feels like 'hidden+token' would be a good usage.
- $tokenList = ['frontend_title', 'pay_later_text', 'pay_later_receipt', 'is_share', 'receipt_text'];
- $contributionPageTokens = ContributionPage::getFields(FALSE)->addWhere('name', 'IN', $tokenList)->execute();
- foreach ($contributionPageTokens as $contributionPageToken) {
- $tokens['contribution_page_id.' . $contributionPageToken['name']] = [
- 'title' => $contributionPageToken['title'],
- 'name' => 'contribution_page_id.' . $contributionPageToken['name'],
- 'type' => 'mapped',
- 'data_type' => $contributionPageToken['data_type'],
- 'input_type' => $contributionPageToken['input_type'],
- 'audience' => $contributionPageToken['name'] === 'is_share' ? 'hidden' : 'user',
- ];
- }
+ $contributionPageTokens = ['frontend_title', 'pay_later_text', 'pay_later_receipt', 'is_share', 'receipt_text'];
+ $tokens += $this->getRelatedTokensForEntity('ContributionPage', 'contribution_page_id', $contributionPageTokens, ['is_share']);
+
$hiddenTokens = ['modified_date', 'create_date', 'trxn_id', 'invoice_id', 'is_test', 'payment_token_id', 'payment_processor_id', 'payment_instrument_id', 'cycle_day', 'installments', 'processor_id', 'next_sched_contribution_date', 'failure_count', 'failure_retry_date', 'auto_renew', 'is_email_receipt', 'contribution_status_id'];
- $contributionRecurFields = ContributionRecur::getFields(FALSE)->setLoadOptions(TRUE)->execute();
- foreach ($contributionRecurFields as $contributionRecurField) {
- $tokens['contribution_recur_id.' . $contributionRecurField['name']] = [
- 'title' => $contributionRecurField['title'],
- 'name' => 'contribution_recur_id.' . $contributionRecurField['name'],
- 'type' => 'mapped',
- 'options' => $contributionRecurField['options'] ?? NULL,
- 'data_type' => $contributionRecurField['data_type'],
- 'input_type' => $contributionRecurField['input_type'],
- 'audience' => in_array($contributionRecurField['name'], $hiddenTokens) ? 'hidden' : 'user',
- ];
- }
+ $tokens += $this->getRelatedTokensForEntity('ContributionRecur', 'contribution_recur_id', ['*'], $hiddenTokens);
return $tokens;
}
+ /**
+ * @param \Civi\Token\TokenRow $row
+ * @param string $field
+ * @return string|int
+ */
+ protected function getFieldValue(TokenRow $row, string $field) {
+ $entityName = $this->getEntityName();
+ if (isset($row->context[$entityName][$field])) {
+ return $row->context[$entityName][$field];
+ }
+ if ($field === 'address_id.display') {
+ $addressID = $this->getFieldValue($row, 'address_id.id');
+ // We possibly could figure out how to load in a cleverer way
+ // or as part of apiv4 but this is tested so that can easily happen later...
+ $address = Address::get(FALSE)
+ ->addWhere('id', '=', $addressID)
+ ->addSelect('*', 'state_province_id:label', 'country_id:label')
+ ->execute()->first();
+ // We have name in the address_id.name token.
+ unset($address['name']);
+ return \CRM_Utils_Address::format($address);
+ }
+ return parent::getFieldValue($row, $field);
+ }
+
+ /**
+ * Get fields which need to be returned to render another token.
+ *
+ * @return array
+ */
+ public function getDependencies(): array {
+ return ['address_id.display' => 'address_id.id'];
+ }
+
}
diff --git a/CRM/Contribute/WorkflowMessage/Contribution/BasicContribution.php b/CRM/Contribute/WorkflowMessage/Contribution/BasicContribution.php
index d3477bb3da10..4c5bdc364fca 100644
--- a/CRM/Contribute/WorkflowMessage/Contribution/BasicContribution.php
+++ b/CRM/Contribute/WorkflowMessage/Contribution/BasicContribution.php
@@ -143,6 +143,10 @@ private function addExampleData(GenericWorkflowMessage $messageTemplate, $exampl
$this->setLineItem($mockOrder, $priceField, $priceFieldValue, $index);
}
+ $contribution['address_id.name'] = 'Barbara Johnson';
+ $contribution['address_id.display'] = '790L Lincoln St S
+Baltimore, New York 10545
+United States';
$contribution['total_amount'] = $mockOrder->getTotalAmount();
$contribution['tax_amount'] = $mockOrder->getTotalTaxAmount() ? round($mockOrder->getTotalTaxAmount(), 2) : 0;
$messageTemplate->setContribution($contribution);
diff --git a/CRM/Contribute/WorkflowMessage/ContributionTrait.php b/CRM/Contribute/WorkflowMessage/ContributionTrait.php
index 81e32f49b423..b7baed4edb37 100644
--- a/CRM/Contribute/WorkflowMessage/ContributionTrait.php
+++ b/CRM/Contribute/WorkflowMessage/ContributionTrait.php
@@ -30,6 +30,18 @@ trait CRM_Contribute_WorkflowMessage_ContributionTrait {
*/
public $isShowTax;
+ /**
+ * Is it a good idea to show the line item subtotal.
+ *
+ * This would be true if at least one line has a quantity > 1.
+ * Otherwise it is very repetitive.
+ *
+ * @var bool
+ *
+ * @scope tplParams
+ */
+ public $isShowLineSubtotal;
+
/**
* Line items associated with the contribution.
*
@@ -109,6 +121,25 @@ public function getIsShowLineItems(): bool {
return FALSE;
}
return !$this->order->getPriceSetMetadata()['is_quick_config'];
+ return $this->isShowLineItems;
+ }
+
+ /**
+ * Is it a good idea to show the line item subtotal.
+ *
+ * This would be true if at least one line has a quantity > 1.
+ * Otherwise it is very repetitive.
+ *
+ * @return bool
+ * @throws \CRM_Core_Exception
+ */
+ public function getIsShowLineSubtotal(): bool {
+ foreach ($this->getLineItems() as $lineItem) {
+ if ((int) $lineItem['qty'] > 1) {
+ return TRUE;
+ }
+ }
+ return FALSE;
}
/**
diff --git a/CRM/Core/BAO/Address.php b/CRM/Core/BAO/Address.php
index d7391167e735..139f0ea6a958 100644
--- a/CRM/Core/BAO/Address.php
+++ b/CRM/Core/BAO/Address.php
@@ -1283,8 +1283,13 @@ public static function addGeocoderData(&$params) {
catch (CRM_Core_Exception $e) {
$providerExists = FALSE;
}
- if ($providerExists) {
- $provider::format($params);
+ try {
+ if ($providerExists) {
+ $provider::format($params);
+ }
+ }
+ catch (CRM_Core_Exception $e) {
+ \Civi::log()->error('Geocoding error:' . $e->getMessage(), ['geocoder' => get_class($provider), 'input' => $params]);
}
// dev/core#2379 - Limit geocode length to 14 characters to avoid validation error on save in UI.
foreach (['geo_code_1', 'geo_code_2'] as $geocode) {
@@ -1312,7 +1317,7 @@ public static function legacyCreate(array $params, bool $fixAddress) {
}
CRM_Core_BAO_Block::sortPrimaryFirst($params['address']);
- $updateBlankLocInfo = CRM_Utils_Array::value('updateBlankLocInfo', $params, FALSE);
+ $updateBlankLocInfo = $params['updateBlankLocInfo'] ?? FALSE;
$contactId = $params['contact_id'];
//get all the addresses for this contact
$addresses = self::allAddress($contactId);
diff --git a/CRM/Core/BAO/Block.php b/CRM/Core/BAO/Block.php
index bd80441e142d..fe5df456d309 100644
--- a/CRM/Core/BAO/Block.php
+++ b/CRM/Core/BAO/Block.php
@@ -208,8 +208,8 @@ public static function create($blockName, $params) {
$contactId = $params['contact_id'];
- $updateBlankLocInfo = CRM_Utils_Array::value('updateBlankLocInfo', $params, FALSE);
- $isIdSet = CRM_Utils_Array::value('isIdSet', $params[$blockName], FALSE);
+ $updateBlankLocInfo = $params['updateBlankLocInfo'] ?? FALSE;
+ $isIdSet = $params[$blockName]['isIdSet'] ?? FALSE;
//get existing block ids.
$blockIds = self::getBlockIds($blockName, $contactId, $entityElements);
diff --git a/CRM/Core/BAO/CMSUser.php b/CRM/Core/BAO/CMSUser.php
index e43a7b499876..c5f01e496a56 100644
--- a/CRM/Core/BAO/CMSUser.php
+++ b/CRM/Core/BAO/CMSUser.php
@@ -40,9 +40,12 @@ public static function create(&$params, $mailParam) {
$ufID = $config->userSystem->createUser($params, $mailParam);
- //if contact doesn't already exist create UF Match
- if ($ufID !== FALSE &&
- isset($params['contactID'])
+ // Create UF Match if we have contactID unless we're Standalone
+ // since in Standalone uf_match is the same table as User.
+ if (
+ CIVICRM_UF !== 'Standalone'
+ && $ufID !== FALSE
+ && isset($params['contactID'])
) {
// create the UF Match record
$ufmatch['uf_id'] = $ufID;
diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php
index 79ef2f16f7d3..e6f4b68d31b0 100644
--- a/CRM/Core/BAO/CustomField.php
+++ b/CRM/Core/BAO/CustomField.php
@@ -856,11 +856,12 @@ public static function getViewableCustomFields(string $extends, array $extendsEn
&& $field['custom_group_id.is_public']
&& (
!empty($entityValueMatches)
+ || empty($entityFilters)
|| empty($field['custom_group_id.extends_entity_column_id'])
)
&& (
$field['custom_group_id.extends'] === $extends
- || ($field['extends'] === 'Contact' && in_array($extends, ['Individual', 'Organization', 'Household']))
+ || ($field['custom_group_id.extends'] === 'Contact' && in_array($extends, ['Individual', 'Organization', 'Household']))
)
) {
\Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey][(int) $field['id']] = $field;
@@ -1132,6 +1133,10 @@ public static function addQuickFormElement(
$qf->assign('customUrls', $customUrls);
break;
+
+ case 'Hidden':
+ $element = $qf->add('hidden', $elementName);
+ break;
}
switch ($field->data_type) {
@@ -1148,21 +1153,21 @@ public static function addQuickFormElement(
case 'Float':
if ($field->is_search_range && $search) {
- $qf->addRule($elementName . '_from', ts('%1 From must be a number (with or without decimal point).', [1 => $label]), 'numeric');
- $qf->addRule($elementName . '_to', ts('%1 To must be a number (with or without decimal point).', [1 => $label]), 'numeric');
+ $qf->addRule($elementName . '_from', ts('%1 From must be a number (with or without decimals).', [1 => $label]), 'money');
+ $qf->addRule($elementName . '_to', ts('%1 To must be a number (with or without decimals).', [1 => $label]), 'money');
}
elseif ($widget == 'Text') {
- $qf->addRule($elementName, ts('%1 must be a number (with or without decimal point).', [1 => $label]), 'numeric');
+ $qf->addRule($elementName, ts('%1 must be a number (with or without decimals).', [1 => $label]), 'money');
}
break;
case 'Money':
if ($field->is_search_range && $search) {
- $qf->addRule($elementName . '_from', ts('%1 From must in proper money format. (decimal point/comma/space is allowed).', [1 => $label]), 'money');
- $qf->addRule($elementName . '_to', ts('%1 To must in proper money format. (decimal point/comma/space is allowed).', [1 => $label]), 'money');
+ $qf->addRule($elementName . '_from', ts('%1 From must in money format (a number with or without decimals, ex: %2).', [1 => $label, 2 => Civi::format()->number(123.98)]), 'money');
+ $qf->addRule($elementName . '_to', ts('%1 To must in money format (a number with or without decimals, ex: %2).', [1 => $label, 2 => Civi::format()->number(123.98)]), 'money');
}
elseif ($widget == 'Text') {
- $qf->addRule($elementName, ts('%1 must be in proper money format. (decimal point/comma/space is allowed).', [1 => $label]), 'money');
+ $qf->addRule($elementName, ts('%1 must be in money format (a number with or without decimals, ex: %2).', [1 => $label, 2 => Civi::format()->number(123.98)]), 'money');
}
break;
@@ -1321,7 +1326,7 @@ private static function formatDisplayValue($value, $field, $entityId = NULL) {
// In such cases we could just get intval($value) and fetch matching
// option again, but this would not work if key is float like 5.6.
// So we need to truncate trailing zeros to make it work as expected.
- if ($display === '' && strpos(($value ?? ''), '.') !== FALSE) {
+ if ($display === '' && is_numeric($value) && strpos(($value ?? ''), '.') !== FALSE) {
// Use round() to truncate trailing zeros, e.g:
// 10.00 -> 10, 10.60 -> 10.6, 10.69 -> 10.69.
$value = (string) round($value, 5);
@@ -2221,7 +2226,7 @@ protected static function prepareCreate($params) {
// create any option group & values if required
$allowedOptionTypes = ['String', 'Int', 'Float', 'Money'];
- if ($htmlType !== 'Text' && in_array($dataType, $allowedOptionTypes, TRUE)) {
+ if (!in_array($htmlType, ['Text', 'Hidden'], TRUE) && in_array($dataType, $allowedOptionTypes, TRUE)) {
//CRM-16659: if option_value then create an option group for this custom field.
// An option_type of 2 would be a 'message' from the form layer not to handle
// the option_values key. If not set then it is not ignored.
@@ -2749,30 +2754,22 @@ public static function validateCustomData($params) {
switch ($dataType) {
case 'Int':
$ruleName = 'integer';
- $errorMsg = ts('%1 must be an integer (whole number).',
- [1 => $fieldTitle]
- );
+ $errorMsg = ts('%1 must be an integer (whole number).', [1 => $fieldTitle]);
break;
case 'Money':
$ruleName = 'money';
- $errorMsg = ts('%1 must in proper money format. (decimal point/comma/space is allowed).',
- [1 => $fieldTitle]
- );
+ $errorMsg = ts('%1 must be in money format (a number with or without decimals, ex: %2).', [1 => $fieldTitle, 2 => Civi::format()->number(123.98)]);
break;
case 'Float':
$ruleName = 'numeric';
- $errorMsg = ts('%1 must be a number (with or without decimal point).',
- [1 => $fieldTitle]
- );
+ $errorMsg = ts('%1 must be a number (with or without decimals).', [1 => $fieldTitle]);
break;
case 'Link':
$ruleName = 'wikiURL';
- $errorMsg = ts('%1 must be valid Website.',
- [1 => $fieldTitle]
- );
+ $errorMsg = ts('%1 must be valid Website.', [1 => $fieldTitle]);
break;
}
diff --git a/CRM/Core/BAO/CustomGroup.php b/CRM/Core/BAO/CustomGroup.php
index e7b561a07c8d..69acff737844 100644
--- a/CRM/Core/BAO/CustomGroup.php
+++ b/CRM/Core/BAO/CustomGroup.php
@@ -550,6 +550,7 @@ public static function getTree(
$cacheString .= "_Inline";
}
+ $multipleFieldGroups = [];
$cacheKey = "CRM_Core_DAO_CustomGroup_Query " . md5($cacheString);
$multipleFieldGroupCacheKey = "CRM_Core_DAO_CustomGroup_QueryMultipleFields " . md5($cacheString);
$cache = CRM_Utils_Cache::singleton();
@@ -837,6 +838,7 @@ public static function buildCustomFieldData($dao, &$groupTree, $table, $groupID,
'qs' => 'reset=1&id=%%id%%&eid=%%eid%%&fid=%%fid%%&action=delete&fcs=%%fcs%%',
'extra' => 'onclick = "if (confirm( \'' . $deleteExtra
. '\' ) ) this.href+=\'&confirmed=1\'; else return false;"',
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
];
$customValue['deleteURL'] = CRM_Core_Action::formLink($deleteURL,
@@ -2061,7 +2063,7 @@ public static function getExtendedObjectTypes(&$types = []) {
* @param array $params
* @return array
*/
- public static function getExtendsEntityColumnValueOptions($context, $params) {
+ public static function getExtendsEntityColumnValueOptions($context, $params): array {
$props = $params['values'] ?? [];
// Requesting this option list only makes sense if the value of 'extends' is known or can be looked up
if (!empty($props['id']) || !empty($props['name']) || !empty($props['extends']) || !empty($props['extends_entity_column_id'])) {
@@ -2397,18 +2399,51 @@ public static function checkGroupAccess($groupId, $operation = CRM_Core_Permissi
return in_array($groupId, $allowedGroups);
}
+ /**
+ * Given the name of a custom group, gets the name of the API entity the group extends.
+ *
+ * Sort of the inverse of this function:
+ * @see \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends
+ *
+ * @param string $groupName
+ * @return string
+ * @throws \CRM_Core_Exception
+ */
+ public static function getEntityForGroup(string $groupName): string {
+ $extends = \CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'extends', 'name');
+ if (!$extends) {
+ throw new \CRM_Core_Exception("Custom group $groupName not found");
+ }
+ return self::getEntityFromExtends($extends);
+ }
+
+ /**
+ * Translate CustomGroup.extends to entity name.
+ *
+ * CustomGroup.extends pretty much maps 1-1 with entity names, except for Individual, Organization & Household.
+ * @param string $extends
+ * @return string
+ * @see self::getCustomGroupExtendsOptions
+ */
+ public static function getEntityFromExtends(string $extends): string {
+ if ($extends === 'Contact' || in_array($extends, \CRM_Contact_BAO_ContactType::basicTypes(TRUE))) {
+ return 'Contact';
+ }
+ return $extends;
+ }
+
/**
* List all possible values for `CustomGroup.extends`.
*
- * This includes the fake entities "Individual", "Organization", "Household"
- * but not the extra options from `custom_data_type` used on the form ("ParticipantStatus", etc).
+ * This includes the pseudo-entities "Individual", "Organization", "Household".
*
* Returns a mix of hard-coded array and `cg_extend_objects` OptionValues.
- * The 'id' return key maps to the 'value' in `cg_extend_objects`.
- * The 'grouping' key refers to the entity field used to select a sub-type.
- * The 'table_name' key is for internal use (is not returned by getFields.loadOptions), and
- * maps to the 'name' in `cg_extend_objects`. We don't return it as the 'name' in getFields because
- * it is not always unique (since contact types are pseudo-entities in this list).
+ * - 'id' return key (maps to `cg_extend_objects.value`).
+ * - 'grouping' key refers to the entity field used to select a sub-type.
+ * - 'is_multiple' (@internal, not returned by getFields.loadOptions) (maps to `cg_extend_objects.filter`)
+ * controls whether the entity supports multi-record custom groups.
+ * - 'table_name' (@internal, not returned by getFields.loadOptions) (maps to `cg_extend_objects.name`).
+ * We don't return it as the 'name' in getFields because it is not always unique (since contact types are pseudo-entities).
*
* @return array{id: string, label: string, grouping: string, table_name: string}[]
*/
@@ -2419,81 +2454,100 @@ public static function getCustomGroupExtendsOptions() {
'label' => ts('Activities'),
'grouping' => 'activity_type_id',
'table_name' => 'civicrm_activity',
+ 'is_multiple' => FALSE,
],
[
'id' => 'Relationship',
'label' => ts('Relationships'),
'grouping' => 'relationship_type_id',
'table_name' => 'civicrm_relationship',
+ 'is_multiple' => FALSE,
],
+ // TODO: Move to civi_contribute extension (example: OptionValue_cg_extends_objects_grant.mgd.php)
[
'id' => 'Contribution',
'label' => ts('Contributions'),
'grouping' => 'financial_type_id',
'table_name' => 'civicrm_contribution',
+ 'is_multiple' => FALSE,
],
[
'id' => 'ContributionRecur',
'label' => ts('Recurring Contributions'),
'grouping' => NULL,
'table_name' => 'civicrm_contribution_recur',
+ 'is_multiple' => FALSE,
],
[
'id' => 'Group',
'label' => ts('Groups'),
'grouping' => NULL,
'table_name' => 'civicrm_group',
+ 'is_multiple' => FALSE,
],
+ // TODO: Move to civi_member extension (example: OptionValue_cg_extends_objects_grant.mgd.php)
[
'id' => 'Membership',
'label' => ts('Memberships'),
'grouping' => 'membership_type_id',
'table_name' => 'civicrm_membership',
+ 'is_multiple' => FALSE,
],
+ // TODO: Move to civi_event extension (example: OptionValue_cg_extends_objects_grant.mgd.php)
[
'id' => 'Event',
'label' => ts('Events'),
'grouping' => 'event_type_id',
'table_name' => 'civicrm_event',
+ 'is_multiple' => FALSE,
],
[
'id' => 'Participant',
'label' => ts('Participants'),
'grouping' => NULL,
'table_name' => 'civicrm_participant',
+ 'is_multiple' => FALSE,
],
+ // TODO: Move to civi_pledge extension (example: OptionValue_cg_extends_objects_grant.mgd.php)
[
'id' => 'Pledge',
'label' => ts('Pledges'),
'grouping' => NULL,
'table_name' => 'civicrm_pledge',
+ 'is_multiple' => FALSE,
],
[
'id' => 'Address',
'label' => ts('Addresses'),
'grouping' => NULL,
'table_name' => 'civicrm_address',
+ 'is_multiple' => FALSE,
],
+ // TODO: Move to civi_campaign extension (example: OptionValue_cg_extends_objects_grant.mgd.php)
[
'id' => 'Campaign',
'label' => ts('Campaigns'),
'grouping' => 'campaign_type_id',
'table_name' => 'civicrm_campaign',
+ 'is_multiple' => FALSE,
],
[
'id' => 'Contact',
'label' => ts('Contacts'),
'grouping' => NULL,
'table_name' => 'civicrm_contact',
+ 'is_multiple' => TRUE,
],
];
// `CustomGroup.extends` stores contact type as if it were an entity.
- foreach (CRM_Contact_BAO_ContactType::basicTypePairs(TRUE) as $contactType => $contactTypeLabel) {
+ foreach (CRM_Contact_BAO_ContactType::basicTypeInfo(TRUE) as $contactType => $contactInfo) {
$options[] = [
'id' => $contactType,
- 'label' => $contactTypeLabel,
+ 'label' => $contactInfo['label'],
'grouping' => 'contact_sub_type',
'table_name' => 'civicrm_contact',
+ 'is_multiple' => TRUE,
+ 'icon' => $contactInfo['icon'],
];
}
$ogId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'cg_extend_objects', 'id', 'name');
@@ -2504,8 +2558,12 @@ public static function getCustomGroupExtendsOptions() {
'label' => $ogValue['label'],
'grouping' => $ogValue['grouping'] ?? NULL,
'table_name' => $ogValue['name'],
+ 'is_multiple' => !empty($ogValue['filter']),
];
}
+ foreach ($options as &$option) {
+ $option['icon'] = $option['icon'] ?? \Civi\Api4\Utils\CoreUtil::getInfoItem($option['id'], 'icon');
+ }
return $options;
}
diff --git a/CRM/Core/BAO/CustomValue.php b/CRM/Core/BAO/CustomValue.php
index f801e1296fb8..485b231cc4ba 100644
--- a/CRM/Core/BAO/CustomValue.php
+++ b/CRM/Core/BAO/CustomValue.php
@@ -211,18 +211,19 @@ public static function deleteCustomValue($customValueID, $customGroupID) {
}
/**
- * ACL clause for an APIv4 custom pseudo-entity (aka multi-record custom group extending Contact).
+ * ACL clause for an APIv4 custom pseudo-entity (aka multi-record custom group).
* @param string|null $entityName
* @param int|null $userId
* @param array $conditions
* @return array
*/
public function addSelectWhereClause(string $entityName = NULL, int $userId = NULL, array $conditions = []): array {
- // To-date, custom-value-based entities are only supported for contacts.
- // If this changes, $entityName variable contains the name of this custom group,
- // and could be used to lookup the type of entity this custom group joins to.
+ // Some legacy code omits $entityName, in which case fall-back on 'Contact' which until 2023
+ // was the only type of entity that could be extended by multi-record custom groups.
+ $groupName = \Civi\Api4\Utils\CoreUtil::getCustomGroupName((string) $entityName);
+ $joinEntity = $groupName ? CRM_Core_BAO_CustomGroup::getEntityForGroup($groupName) : 'Contact';
$clauses = [
- 'entity_id' => CRM_Utils_SQL::mergeSubquery('Contact'),
+ 'entity_id' => CRM_Utils_SQL::mergeSubquery($joinEntity),
];
CRM_Utils_Hook::selectWhereClause($entityName ?? $this, $clauses);
return $clauses;
@@ -232,7 +233,7 @@ public function addSelectWhereClause(string $entityName = NULL, int $userId = NU
* Special checkAccess function for multi-record custom pseudo-entities
*
* @param string $entityName
- * Ex: 'Contact' or 'Custom_Foobar'
+ * APIv4-style entity name e.g. 'Custom_Foobar'
* @param string $action
* @param array $record
* @param int $userID
@@ -243,8 +244,9 @@ public function addSelectWhereClause(string $entityName = NULL, int $userId = NU
public static function _checkAccess(string $entityName, string $action, array $record, int $userID): ?bool {
// This check implements two rules: you must have access to the specific custom-data-group - and to the underlying record (e.g. Contact).
- $groupName = substr($entityName, 0, 7) === 'Custom_' ? substr($entityName, 7) : NULL;
- $extends = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'extends', 'name');
+ // Expecting APIv4-style entity name
+ $groupName = \Civi\Api4\Utils\CoreUtil::getCustomGroupName($entityName);
+ $extends = \CRM_Core_BAO_CustomGroup::getEntityForGroup($groupName);
$id = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'id', 'name');
if (!$groupName) {
// $groupName is required but the function signature has to match the parent.
@@ -267,17 +269,8 @@ public static function _checkAccess(string $entityName, string $action, array $r
}
// Do we have access to the target record?
- if ($extends === 'Contact' || in_array($extends, CRM_Contact_BAO_ContactType::basicTypes(TRUE), TRUE)) {
- return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated('Contact', 'update', ['id' => $eid], $userID);
- }
- elseif (\Civi\Api4\Utils\CoreUtil::getApiClass($extends)) {
- // For most entities (Activity, Relationship, Contribution, ad nauseum), we acn just use an eponymous API.
- return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated($extends, 'update', ['id' => $eid], $userID);
- }
- else {
- // Do you need to add a special case for some oddball custom-group type?
- throw new CRM_Core_Exception("Cannot assess delegated permissions for group {$groupName}.");
- }
+ $delegatedAction = $action === 'get' ? 'get' : 'update';
+ return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated($extends, $delegatedAction, ['id' => $eid], $userID);
}
}
diff --git a/CRM/Core/BAO/Domain.php b/CRM/Core/BAO/Domain.php
index 548baffdc68a..6e4049562fae 100644
--- a/CRM/Core/BAO/Domain.php
+++ b/CRM/Core/BAO/Domain.php
@@ -164,9 +164,11 @@ public static function create($params) {
}
/**
+ * @deprecated
* @return bool
*/
public static function multipleDomains() {
+ CRM_Core_Error::deprecatedFunctionWarning('API');
$session = CRM_Core_Session::singleton();
$numberDomains = $session->get('numberDomains');
@@ -231,12 +233,12 @@ public static function getFromEmail(): string {
/**
* @param int $contactID
- *
- * @return bool|null|object|string
- *
+ * @return bool|int
+ * @deprecated
* @throws \CRM_Core_Exception
*/
public static function addContactToDomainGroup($contactID) {
+ CRM_Core_Error::deprecatedFunctionWarning('CRM_Contact_BAO_GroupContact::addContactsToGroup');
$groupID = self::getGroupId();
if ($groupID) {
diff --git a/CRM/Core/BAO/EntityTag.php b/CRM/Core/BAO/EntityTag.php
index c48246775db4..97c94866d95d 100644
--- a/CRM/Core/BAO/EntityTag.php
+++ b/CRM/Core/BAO/EntityTag.php
@@ -301,7 +301,7 @@ public static function create(&$params, $entityTable, $entityID) {
public static function getContactTags($contactID, $count = FALSE) {
$contactTags = [];
if (!$count) {
- $select = "SELECT ct.id, ct.name ";
+ $select = "SELECT ct.id, ct.label ";
}
else {
$select = "SELECT count(*) as cnt";
@@ -322,7 +322,7 @@ public static function getContactTags($contactID, $count = FALSE) {
}
while ($dao->fetch()) {
- $contactTags[$dao->id] = $dao->name;
+ $contactTags[$dao->id] = $dao->label;
}
return $contactTags;
diff --git a/CRM/Core/BAO/MailSettings.php b/CRM/Core/BAO/MailSettings.php
index 1519394d031b..2d8b6b85ef6d 100644
--- a/CRM/Core/BAO/MailSettings.php
+++ b/CRM/Core/BAO/MailSettings.php
@@ -19,7 +19,7 @@ class CRM_Core_BAO_MailSettings extends CRM_Core_DAO_MailSettings {
/**
* Get a list of setup-actions.
*
- * @return array
+ * @return array{array{title:string, callback: mixed, url: string}}
* List of available actions. See description in the hook-docs.
* @see CRM_Utils_Hook::mailSetupActions()
*/
@@ -31,6 +31,13 @@ public static function getSetupActions() {
];
CRM_Utils_Hook::mailSetupActions($setupActions);
+
+ foreach ($setupActions as $key => &$setupAction) {
+ if (!isset($setupAction['url'])) {
+ $setupAction['url'] = (string) Civi::url('//civicrm/ajax/setupMailAccount')->addQuery(['type' => $key]);
+ }
+ }
+
return $setupActions;
}
@@ -129,8 +136,8 @@ public static function add(&$params) {
}
if (empty($params['id'])) {
- $params['is_ssl'] = CRM_Utils_Array::value('is_ssl', $params, FALSE);
- $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE);
+ $params['is_ssl'] = $params['is_ssl'] ?? FALSE;
+ $params['is_default'] = $params['is_default'] ?? FALSE;
}
//handle is_default.
diff --git a/CRM/Core/BAO/Managed.php b/CRM/Core/BAO/Managed.php
index 420435010538..38fc061a7ca7 100644
--- a/CRM/Core/BAO/Managed.php
+++ b/CRM/Core/BAO/Managed.php
@@ -50,11 +50,14 @@ public static function on_hook_civicrm_managed(\Civi\Core\Event\GenericHookEvent
* @param \Civi\Core\Event\PostEvent $event
*/
public static function on_hook_civicrm_post(\Civi\Core\Event\PostEvent $event) {
- // When an entity is deleted, delete the corresponding Managed record
+ // When an entity is deleted by the user, nullify 'entity_id' from corresponding Managed record
+ // This tells the ManagedEntity system that the entity was manually deleted,
+ // and should be recreated at the discretion of the `update` policy.
if ($event->action === 'delete' && $event->id && self::isApi4ManagedType($event->entity)) {
- \Civi\Api4\Managed::delete(FALSE)
+ \Civi\Api4\Managed::update(FALSE)
->addWhere('entity_type', '=', $event->entity)
->addWhere('entity_id', '=', $event->id)
+ ->addValue('entity_id', NULL)
->execute();
}
// When an entity is updated, update the timestamp in corresponding Managed record
diff --git a/CRM/Core/BAO/Navigation.php b/CRM/Core/BAO/Navigation.php
index 5357b6f7d4a9..9a5bb862a260 100644
--- a/CRM/Core/BAO/Navigation.php
+++ b/CRM/Core/BAO/Navigation.php
@@ -74,10 +74,9 @@ public static function setIsActive($id, $is_active) {
* @return CRM_Core_DAO_Navigation
*/
public static function add(&$params) {
- $navigation = new CRM_Core_DAO_Navigation();
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['is_active'] = $params['is_active'] ?? FALSE;
+ $params['has_separator'] = $params['has_separator'] ?? FALSE;
$params['domain_id'] = CRM_Utils_Array::value('domain_id', $params, CRM_Core_Config::domainID());
}
@@ -98,14 +97,7 @@ public static function add(&$params) {
$params['weight'] = self::calculateWeight(CRM_Utils_Array::value('parent_id', $params));
}
- if (array_key_exists('permission', $params) && is_array($params['permission'])) {
- $params['permission'] = implode(',', $params['permission']);
- }
-
- $navigation->copyValues($params);
-
- $navigation->save();
- return $navigation;
+ return self::writeRecord($params);
}
/**
@@ -513,11 +505,11 @@ public static function processNavigation(&$params) {
break;
case "rename":
- self::processRename($nodeID, $label);
+ self::writeRecord(['id' => $nodeID, 'label' => $label]);
break;
case "delete":
- self::processDelete($nodeID);
+ self::deleteRecord(['id' => $nodeID]);
break;
}
@@ -578,8 +570,6 @@ public static function processMove($nodeID, $referenceID, $position) {
$incrementOtherNodes = FALSE;
}
- $transaction = new CRM_Core_Transaction();
-
// now update the existing nodes to weight + 1, if required.
if ($incrementOtherNodes) {
$query = "UPDATE civicrm_navigation SET weight = weight + 1
@@ -588,11 +578,8 @@ public static function processMove($nodeID, $referenceID, $position) {
CRM_Core_DAO::executeQuery($query);
}
- // finally set the weight of current node
- $query = "UPDATE civicrm_navigation SET weight = {$newWeight}, parent_id = {$newParentID} WHERE id = {$nodeID}";
- CRM_Core_DAO::executeQuery($query);
-
- $transaction->commit();
+ // finally set the weight and parent of current node
+ self::writeRecord(['id' => $nodeID, 'weight' => $newWeight, 'parent_id' => $newParentID]);
}
/**
@@ -600,19 +587,22 @@ public static function processMove($nodeID, $referenceID, $position) {
*
* @param int $nodeID
* @param $label
+ * @deprecated - use API
*/
public static function processRename($nodeID, $label) {
- CRM_Core_DAO::setFieldValue('CRM_Core_DAO_Navigation', $nodeID, 'label', $label);
+ CRM_Core_Error::deprecatedFunctionWarning('writeRecord');
+ self::writeRecord(['id' => $nodeID, 'label' => $label]);
}
/**
* Process delete action for tree.
*
* @param int $nodeID
+ * @deprecated - use API
*/
public static function processDelete($nodeID) {
- $query = "DELETE FROM civicrm_navigation WHERE id = {$nodeID}";
- CRM_Core_DAO::executeQuery($query);
+ CRM_Core_Error::deprecatedFunctionWarning('writeRecord');
+ self::deleteRecord(['id' => $nodeID]);
}
/**
diff --git a/CRM/Core/BAO/Note.php b/CRM/Core/BAO/Note.php
index 46e7a9052c6f..f1e54f06f7ba 100644
--- a/CRM/Core/BAO/Note.php
+++ b/CRM/Core/BAO/Note.php
@@ -171,19 +171,19 @@ public static function add(&$params, $ids = []) {
$recentOther = [];
if ($noteActions) {
$recentOther = [
- 'editUrl' => CRM_Utils_System::url('civicrm/contact/view/note',
- "reset=1&action=update&cid={$note->entity_id}&id={$note->id}&context=home"
+ 'editUrl' => CRM_Utils_System::url('civicrm/note',
+ "reset=1&action=update&id={$note->id}&context=home"
),
- 'deleteUrl' => CRM_Utils_System::url('civicrm/contact/view/note',
- "reset=1&action=delete&cid={$note->entity_id}&id={$note->id}&context=home"
+ 'deleteUrl' => CRM_Utils_System::url('civicrm/note',
+ "reset=1&action=delete&id={$note->id}&context=home"
),
];
}
// add the recently created Note
CRM_Utils_Recent::add($displayName . ' - ' . $note->subject,
- CRM_Utils_System::url('civicrm/contact/view/note',
- "reset=1&action=view&cid={$note->entity_id}&id={$note->id}&context=home"
+ CRM_Utils_System::url('civicrm/note',
+ "reset=1&action=view&id={$note->id}&context=home"
),
$note->id,
'Note',
@@ -376,7 +376,7 @@ public static function getContactNoteCount($contactID) {
*
* @return array
* Nested associative array beginning with direct children of given note.
- *
+ * @deprecated only called by deprecated APIv3
*/
public static function getNoteTree($parentId, $maxDepth = 0, $snippet = FALSE) {
return self::buildNoteTree($parentId, $maxDepth, $snippet);
@@ -422,6 +422,7 @@ public static function getChildCount($id) {
*
* @return array
* Nested associative array beginning with direct children of given note.
+ * @deprecated only called by deprecated APIv3
*/
private static function buildNoteTree($parentId, $maxDepth = 0, $snippet = FALSE, &$tree = [], $depth = 0) {
if ($maxDepth && $depth > $maxDepth) {
diff --git a/CRM/Core/BAO/RecurringEntity.php b/CRM/Core/BAO/RecurringEntity.php
index 9a8aa744927a..cc1d7c1f8eca 100644
--- a/CRM/Core/BAO/RecurringEntity.php
+++ b/CRM/Core/BAO/RecurringEntity.php
@@ -39,24 +39,8 @@ class CRM_Core_BAO_RecurringEntity extends CRM_Core_DAO_RecurringEntity implemen
protected $recursion = NULL;
protected $recursion_start_date = NULL;
- public static $_entitiesToBeDeleted = [];
-
public static $status = NULL;
- public static $_recurringEntityHelper
- = [
- 'civicrm_event' => [
- 'helper_class' => 'CRM_Event_DAO_Event',
- 'delete_func' => 'delete',
- 'pre_delete_func' => 'CRM_Event_Form_ManageEvent_Repeat::checkRegistrationForEvents',
- ],
- 'civicrm_activity' => [
- 'helper_class' => 'CRM_Activity_DAO_Activity',
- 'delete_func' => 'delete',
- 'pre_delete_func' => '',
- ],
- ];
-
public static $_dateColumns
= [
'civicrm_event' => [
diff --git a/CRM/Core/BAO/Tag.php b/CRM/Core/BAO/Tag.php
index cd2a0522e05e..a86f4b1785ce 100644
--- a/CRM/Core/BAO/Tag.php
+++ b/CRM/Core/BAO/Tag.php
@@ -311,7 +311,7 @@ public static function getColorTags($usedFor = NULL, $allowSelectingNonSelectabl
'sort' => "name ASC",
],
'is_tagset' => 0,
- 'return' => ['name', 'description', 'parent_id', 'color', 'is_selectable', 'used_for'],
+ 'return' => ['label', 'description', 'parent_id', 'color', 'is_selectable', 'used_for'],
];
if ($usedFor) {
$params['used_for'] = ['LIKE' => "%$usedFor%"];
@@ -322,7 +322,7 @@ public static function getColorTags($usedFor = NULL, $allowSelectingNonSelectabl
$allTags = [];
foreach (CRM_Utils_Array::value('values', civicrm_api3('Tag', 'get', $params)) as $id => $tag) {
$allTags[$id] = [
- 'text' => $tag['name'],
+ 'text' => $tag['label'],
'id' => $id,
'description' => $tag['description'] ?? NULL,
'parent_id' => $tag['parent_id'] ?? NULL,
@@ -366,8 +366,16 @@ public static function del($id) {
*/
public static function add(&$params, $ids = []) {
$id = $params['id'] ?? $ids['tag'] ?? NULL;
- if (!$id && !self::dataExists($params)) {
- return NULL;
+ if (!$id) {
+ // Make label from name if missing.
+ if (CRM_Utils_System::isNull($params['label'] ?? NULL)) {
+ // If name is also missing, cannot create object.
+ if (CRM_Utils_System::isNull($params['name'] ?? NULL)) {
+ // FIXME: Throw exception
+ return NULL;
+ }
+ $params['label'] = $params['name'];
+ }
}
// Check permission to create or modify reserved tag
@@ -401,7 +409,6 @@ public static function add(&$params, $ids = []) {
// save creator id and time
if (!$id) {
$params['created_id'] = $params['created_id'] ?? CRM_Core_Session::getLoggedInContactID();
- $params['created_date'] = $params['created_date'] ?? date('YmdHis');
}
$tag = self::writeRecord($params);
@@ -422,23 +429,6 @@ public static function add(&$params, $ids = []) {
return $tag;
}
- /**
- * Check if there is data to create the object.
- *
- * @param array $params
- *
- * @return bool
- */
- public static function dataExists($params) {
- // Disallow empty values except for the number zero.
- // TODO: create a utility for this since it's needed in many places
- if (!empty($params['name']) || (string) $params['name'] === '0') {
- return TRUE;
- }
-
- return FALSE;
- }
-
/**
* Get the tag sets for a entity object.
*
@@ -450,7 +440,7 @@ public static function dataExists($params) {
*/
public static function getTagSet($entityTable) {
$tagSets = [];
- $query = "SELECT name, id FROM civicrm_tag
+ $query = "SELECT label, id FROM civicrm_tag
WHERE is_tagset=1 AND parent_id IS NULL and used_for LIKE %1";
$dao = CRM_Core_DAO::executeQuery($query, [
1 => [
@@ -459,7 +449,7 @@ public static function getTagSet($entityTable) {
],
], TRUE, NULL, FALSE, FALSE);
while ($dao->fetch()) {
- $tagSets[$dao->id] = $dao->name;
+ $tagSets[$dao->id] = $dao->label;
}
return $tagSets;
}
diff --git a/CRM/Core/BAO/UFField.php b/CRM/Core/BAO/UFField.php
index 88ef83cfe107..0212831e838d 100644
--- a/CRM/Core/BAO/UFField.php
+++ b/CRM/Core/BAO/UFField.php
@@ -248,7 +248,7 @@ public static function autoWeight($params) {
$oldWeight = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFField', !empty($params['id']) ? $params['id'] : $params['field_id'], 'weight', 'id');
}
$fieldValues = ['uf_group_id' => !empty($params['uf_group_id']) ? $params['uf_group_id'] : $params['group_id']];
- return CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_UFField', $oldWeight, CRM_Utils_Array::value('weight', $params, 0), $fieldValues);
+ return CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_UFField', $oldWeight, $params['weight'] ?? 0, $fieldValues);
}
/**
diff --git a/CRM/Core/BAO/UFGroup.php b/CRM/Core/BAO/UFGroup.php
index 645dfcb6d3cd..fae355c2e705 100644
--- a/CRM/Core/BAO/UFGroup.php
+++ b/CRM/Core/BAO/UFGroup.php
@@ -1808,7 +1808,7 @@ public static function buildProfile(
$view = $field['is_view'];
$required = ($mode == CRM_Profile_Form::MODE_SEARCH) ? FALSE : $field['is_required'];
$search = $mode == CRM_Profile_Form::MODE_SEARCH;
- $isShared = CRM_Utils_Array::value('is_shared', $field, 0);
+ $isShared = $field['is_shared'] ?? 0;
// do not display view fields in drupal registration form
// CRM-4632
@@ -1958,7 +1958,7 @@ public static function buildProfile(
], $required);
}
elseif ($fieldName === 'contact_sub_type') {
- $gId = $form->get('gid') ? $form->get('gid') : CRM_Utils_Array::value('group_id', $field);
+ $gId = $form->get('gid') ?: $field['group_id'] ?? NULL;
if ($usedFor == 'onbehalf') {
$profileType = 'Organization';
}
@@ -1992,7 +1992,7 @@ public static function buildProfile(
}
elseif (in_array($fieldName, CRM_Contact_BAO_Contact::$_greetingTypes)) {
// Get contact type for greeting selector
- $gId = $form->get('gid') ?: CRM_Utils_Array::value('group_id', $field);
+ $gId = $form->get('gid') ?: $field['group_id'] ?? NULL;
$profileType = CRM_Core_BAO_UFField::getProfileType($gId, TRUE, FALSE, TRUE);
if (!$profileType || in_array($profileType, ['Contact', 'Contribution', 'Participant', 'Membership'])) {
diff --git a/CRM/Core/BAO/UFMatch.php b/CRM/Core/BAO/UFMatch.php
index 5a2406b5c173..6290430fd0d7 100644
--- a/CRM/Core/BAO/UFMatch.php
+++ b/CRM/Core/BAO/UFMatch.php
@@ -539,8 +539,7 @@ public static function getAllowedToLogin($openId) {
}
/**
- * Get the next unused uf_id value, since the standalone UF doesn't
- * have id's (it uses OpenIDs, which go in a different field).
+ * Get the next unused uf_id value
*
* @deprecated
* @return int
diff --git a/CRM/Core/CodeGen/Util/MessageTemplates.php b/CRM/Core/CodeGen/Util/MessageTemplates.php
new file mode 100644
index 000000000000..2df31656427e
--- /dev/null
+++ b/CRM/Core/CodeGen/Util/MessageTemplates.php
@@ -0,0 +1,82 @@
+ ts('Message Template Workflow for Cases', ['escape' => 'sql']),
+ 'contribution' => ts('Message Template Workflow for Contributions', ['escape' => 'sql']),
+ 'event' => ts('Message Template Workflow for Events', ['escape' => 'sql']),
+ 'friend' => ts('Message Template Workflow for Tell-a-Friend', ['escape' => 'sql']),
+ 'membership' => ts('Message Template Workflow for Memberships', ['escape' => 'sql']),
+ 'meta' => ts('Message Template Workflow for Meta Templates', ['escape' => 'sql']),
+ 'pledge' => ts('Message Template Workflow for Pledges', ['escape' => 'sql']),
+ 'uf' => ts('Message Template Workflow for Profiles', ['escape' => 'sql']),
+ 'petition' => ts('Message Template Workflow for Petition', ['escape' => 'sql']),
+ ];
+ $ovNames = [
+ 'case' => [
+ 'case_activity' => ts('Cases - Send Copy of an Activity', ['escape' => 'sql']),
+ ],
+ 'contribution' => [
+ 'contribution_dupalert' => ts('Contributions - Duplicate Organization Alert', ['escape' => 'sql']),
+ 'contribution_offline_receipt' => ts('Contributions - Receipt (off-line)', ['escape' => 'sql']),
+ 'contribution_online_receipt' => ts('Contributions - Receipt (on-line)', ['escape' => 'sql']),
+ 'contribution_invoice_receipt' => ts('Contributions - Invoice', ['escape' => 'sql']),
+ 'contribution_recurring_notify' => ts('Contributions - Recurring Start and End Notification', ['escape' => 'sql']),
+ 'contribution_recurring_cancelled' => ts('Contributions - Recurring Cancellation Notification', ['escape' => 'sql']),
+ 'contribution_recurring_billing' => ts('Contributions - Recurring Billing Updates', ['escape' => 'sql']),
+ 'contribution_recurring_edit' => ts('Contributions - Recurring Updates', ['escape' => 'sql']),
+ 'pcp_notify' => ts('Personal Campaign Pages - Admin Notification', ['escape' => 'sql']),
+ 'pcp_status_change' => ts('Personal Campaign Pages - Supporter Status Change Notification', ['escape' => 'sql']),
+ 'pcp_supporter_notify' => ts('Personal Campaign Pages - Supporter Welcome', ['escape' => 'sql']),
+ 'pcp_owner_notify' => ts('Personal Campaign Pages - Owner Notification', ['escape' => 'sql']),
+ 'payment_or_refund_notification' => ts('Additional Payment Receipt or Refund Notification', ['escape' => 'sql']),
+ ],
+ 'event' => [
+ 'event_offline_receipt' => ts('Events - Registration Confirmation and Receipt (off-line)', ['escape' => 'sql']),
+ 'event_online_receipt' => ts('Events - Registration Confirmation and Receipt (on-line)', ['escape' => 'sql']),
+ 'event_registration_receipt' => ts('Events - Receipt only', ['escape' => 'sql']),
+ 'participant_cancelled' => ts('Events - Registration Cancellation Notice', ['escape' => 'sql']),
+ 'participant_confirm' => ts('Events - Registration Confirmation Invite', ['escape' => 'sql']),
+ 'participant_expired' => ts('Events - Pending Registration Expiration Notice', ['escape' => 'sql']),
+ 'participant_transferred' => ts('Events - Registration Transferred Notice', ['escape' => 'sql']),
+ ],
+ 'friend' => [
+ 'friend' => ts('Tell-a-Friend Email', ['escape' => 'sql']),
+ ],
+ 'membership' => [
+ 'membership_offline_receipt' => ts('Memberships - Signup and Renewal Receipts (off-line)', ['escape' => 'sql']),
+ 'membership_online_receipt' => ts('Memberships - Receipt (on-line)', ['escape' => 'sql']),
+ 'membership_autorenew_cancelled' => ts('Memberships - Auto-renew Cancellation Notification', ['escape' => 'sql']),
+ 'membership_autorenew_billing' => ts('Memberships - Auto-renew Billing Updates', ['escape' => 'sql']),
+ ],
+ 'meta' => [
+ 'test_preview' => ts('Test-drive - Receipt Header', ['escape' => 'sql']),
+ ],
+ 'pledge' => [
+ 'pledge_acknowledge' => ts('Pledges - Acknowledgement', ['escape' => 'sql']),
+ 'pledge_reminder' => ts('Pledges - Payment Reminder', ['escape' => 'sql']),
+ ],
+ 'uf' => [
+ 'uf_notify' => ts('Profiles - Admin Notification', ['escape' => 'sql']),
+ ],
+ 'petition' => [
+ 'petition_sign' => ts('Petition - signature added', ['escape' => 'sql']),
+ 'petition_confirmation_needed' => ts('Petition - need verification', ['escape' => 'sql']),
+ ],
+ ];
+ $smarty->assign('ogNames', $ogNames);
+ $smarty->assign('ovNames', $ovNames);
+ $dir = $smarty->get_template_vars()['gencodeXmlDir'] . '/templates/message_templates/sample';
+ $templates = [];
+ foreach (preg_grep('/\.tpl$/', scandir($dir)) as $filename) {
+ $templates[] = ['name' => basename($filename, '.tpl'), 'filename' => "$dir/$filename"];
+ }
+ $smarty->assign('templates', $templates);
+ }
+
+}
diff --git a/CRM/Core/CodeGen/Util/Smarty.php b/CRM/Core/CodeGen/Util/Smarty.php
index d45989504d55..a1eb1f29c963 100644
--- a/CRM/Core/CodeGen/Util/Smarty.php
+++ b/CRM/Core/CodeGen/Util/Smarty.php
@@ -59,9 +59,9 @@ public function createSmarty() {
require_once 'CRM/Core/Smarty/plugins/block.localize.php';
$smarty->register_block('localize', 'smarty_block_localize');
-
$smarty->assign('gencodeXmlDir', dirname(dirname(dirname(dirname(__DIR__)))) . '/xml');
-
+ require_once 'CRM/Core/CodeGen/Util/MessageTemplates.php';
+ CRM_Core_CodeGen_Util_MessageTemplates::assignSmartyVariables($smarty);
return $smarty;
}
diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php
index bd7147725b03..554d89b11f7e 100644
--- a/CRM/Core/DAO.php
+++ b/CRM/Core/DAO.php
@@ -780,6 +780,10 @@ public function copyValues($params) {
}
}
elseif (is_array($value) && !empty($field['serialize'])) {
+ if (!empty($field['pseudoconstant'])) {
+ // Pseudoconstant implies 1-1 option matching; duplicates would not make sense
+ $value = array_unique($value);
+ }
$this->$dbName = CRM_Core_DAO::serializeField($value, $field['serialize']);
$allNull = FALSE;
}
@@ -3142,7 +3146,16 @@ protected static function getDynamicFkAclClauses(string $entityTableField, strin
// Prevent infinite recursion
$subquery = $table === static::getTableName() ? NULL : CRM_Utils_SQL::mergeSubquery($ent);
if ($subquery) {
- $relatedClauses[] = "= '$table' AND {{$entityIdField}} " . implode(" AND {{$entityIdField}} ", $subquery);
+ foreach ($subquery as $index => $condition) {
+ // Join OR clauses
+ if (is_array($condition)) {
+ $subquery[$index] = "(({{$entityIdField}} " . implode(") OR ({{$entityIdField}} ", $condition) . '))';
+ }
+ else {
+ $subquery[$index] = "{{$entityIdField}} $condition";
+ }
+ }
+ $relatedClauses[] = "= '$table' AND " . implode(" AND ", $subquery);
}
// If it's the only value with no conditions, don't need to add it
elseif (!$entityTableValues || count($relatedEntities) > 1) {
diff --git a/CRM/Core/DAO/ActionSchedule.php b/CRM/Core/DAO/ActionSchedule.php
index f75590e0648b..1f00ac68b866 100644
--- a/CRM/Core/DAO/ActionSchedule.php
+++ b/CRM/Core/DAO/ActionSchedule.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/ActionSchedule.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7cd61559377e23d6ad4c833616f22a12)
+ * (GenCodeChecksum:e6121895aa480e9b4fdbf171b01b91dc)
*/
/**
@@ -57,10 +57,10 @@ class CRM_Core_DAO_ActionSchedule extends CRM_Core_DAO {
public $id;
/**
- * Name of the action(reminder)
+ * Name of the scheduled action
*
* @var string
- * (SQL type: varchar(64))
+ * (SQL type: varchar(128))
* Note that values will be retrieved from the database as a string.
*/
public $name;
@@ -491,10 +491,10 @@ public static function &fields() {
'name' => 'name',
'type' => CRM_Utils_Type::T_STRING,
'title' => ts('Name'),
- 'description' => ts('Name of the action(reminder)'),
+ 'description' => ts('Name of the scheduled action'),
'required' => TRUE,
- 'maxlength' => 64,
- 'size' => CRM_Utils_Type::BIG,
+ 'maxlength' => 128,
+ 'size' => CRM_Utils_Type::HUGE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
diff --git a/CRM/Core/DAO/AllCoreTables.php b/CRM/Core/DAO/AllCoreTables.php
index 4c22ee769bc1..ba28171ba925 100644
--- a/CRM/Core/DAO/AllCoreTables.php
+++ b/CRM/Core/DAO/AllCoreTables.php
@@ -358,7 +358,7 @@ public static function getTableForClass($className) {
*
* @param string $briefName
*
- * @return FALSE|string
+ * @return string
*/
public static function getTableForEntityName($briefName): string {
self::init();
diff --git a/CRM/Core/DAO/CustomGroup.php b/CRM/Core/DAO/CustomGroup.php
index 17c0bd892208..f1efcc5ca554 100644
--- a/CRM/Core/DAO/CustomGroup.php
+++ b/CRM/Core/DAO/CustomGroup.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/CustomGroup.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7a53822fedde32eeb1089f09654a2d88)
+ * (GenCodeChecksum:05aa9cfdd47acd56178a0a33a2f6ffc1)
*/
/**
@@ -87,7 +87,7 @@ class CRM_Core_DAO_CustomGroup extends CRM_Core_DAO {
public $extends;
/**
- * FK to civicrm_option_value.id (for option group custom_data_type.)
+ * FK to civicrm_option_value.value (for option group custom_data_type)
*
* @var int|string|null
* (SQL type: int unsigned)
@@ -384,6 +384,7 @@ public static function &fields() {
'name',
'label',
'grouping',
+ 'icon',
],
],
'add' => '1.1',
@@ -392,7 +393,7 @@ public static function &fields() {
'name' => 'extends_entity_column_id',
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Custom Group Subtype List'),
- 'description' => ts('FK to civicrm_option_value.id (for option group custom_data_type.)'),
+ 'description' => ts('FK to civicrm_option_value.value (for option group custom_data_type)'),
'usage' => [
'import' => FALSE,
'export' => FALSE,
diff --git a/CRM/Core/DAO/EntityTag.php b/CRM/Core/DAO/EntityTag.php
index 3f57d572bdec..df3e79bd2ae8 100644
--- a/CRM/Core/DAO/EntityTag.php
+++ b/CRM/Core/DAO/EntityTag.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/EntityTag.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2fccc138a26fe391325fd641c891cd91)
+ * (GenCodeChecksum:5bca5ff1c4ba7d85034410408464f0ac)
*/
/**
@@ -200,7 +200,8 @@ public static function &fields() {
'pseudoconstant' => [
'table' => 'civicrm_tag',
'keyColumn' => 'id',
- 'labelColumn' => 'name',
+ 'labelColumn' => 'label',
+ 'nameColumn' => 'name',
'condition' => 'is_tagset != 1',
],
'add' => '1.1',
diff --git a/CRM/Core/DAO/Managed.php b/CRM/Core/DAO/Managed.php
index a82a5cae3619..d23d84643e13 100644
--- a/CRM/Core/DAO/Managed.php
+++ b/CRM/Core/DAO/Managed.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/Managed.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:1f1273f734c559351767e25b05b3925e)
+ * (GenCodeChecksum:4ff1b19106d4bc7810d4aa9eb2a73f65)
*/
/**
@@ -40,10 +40,10 @@ class CRM_Core_DAO_Managed extends CRM_Core_DAO {
public $id;
/**
- * Name of the module which declared this object
+ * Name of the module which declared this object (soft FK to civicrm_extension.full_name)
*
* @var string
- * (SQL type: varchar(127))
+ * (SQL type: varchar(255))
* Note that values will be retrieved from the database as a string.
*/
public $module;
@@ -51,8 +51,8 @@ class CRM_Core_DAO_Managed extends CRM_Core_DAO {
/**
* Symbolic name used by the module to identify the object
*
- * @var string|null
- * (SQL type: varchar(127))
+ * @var string
+ * (SQL type: varchar(255))
* Note that values will be retrieved from the database as a string.
*/
public $name;
@@ -67,9 +67,9 @@ class CRM_Core_DAO_Managed extends CRM_Core_DAO {
public $entity_type;
/**
- * Foreign key to the referenced item.
+ * Soft foreign key to the referenced item.
*
- * @var int|string
+ * @var int|string|null
* (SQL type: int unsigned)
* Note that values will be retrieved from the database as a string.
*/
@@ -78,8 +78,8 @@ class CRM_Core_DAO_Managed extends CRM_Core_DAO {
/**
* Policy on when to cleanup entity (always, never, unused)
*
- * @var string|null
- * (SQL type: varchar(32))
+ * @var string
+ * (SQL type: varchar(16))
* Note that values will be retrieved from the database as a string.
*/
public $cleanup;
@@ -146,9 +146,9 @@ public static function &fields() {
'name' => 'module',
'type' => CRM_Utils_Type::T_STRING,
'title' => ts('Module'),
- 'description' => ts('Name of the module which declared this object'),
+ 'description' => ts('Name of the module which declared this object (soft FK to civicrm_extension.full_name)'),
'required' => TRUE,
- 'maxlength' => 127,
+ 'maxlength' => 255,
'size' => CRM_Utils_Type::HUGE,
'usage' => [
'import' => FALSE,
@@ -161,6 +161,9 @@ public static function &fields() {
'entity' => 'Managed',
'bao' => 'CRM_Core_BAO_Managed',
'localizable' => 0,
+ 'pseudoconstant' => [
+ 'callback' => 'CRM_Core_BAO_Managed::getBaseModules',
+ ],
'add' => '4.2',
],
'name' => [
@@ -168,7 +171,8 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_STRING,
'title' => ts('Name'),
'description' => ts('Symbolic name used by the module to identify the object'),
- 'maxlength' => 127,
+ 'required' => TRUE,
+ 'maxlength' => 255,
'size' => CRM_Utils_Type::HUGE,
'usage' => [
'import' => FALSE,
@@ -208,8 +212,7 @@ public static function &fields() {
'name' => 'entity_id',
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Entity ID'),
- 'description' => ts('Foreign key to the referenced item.'),
- 'required' => TRUE,
+ 'description' => ts('Soft foreign key to the referenced item.'),
'usage' => [
'import' => FALSE,
'export' => FALSE,
@@ -228,8 +231,9 @@ public static function &fields() {
'type' => CRM_Utils_Type::T_STRING,
'title' => ts('Cleanup Setting'),
'description' => ts('Policy on when to cleanup entity (always, never, unused)'),
- 'maxlength' => 32,
- 'size' => CRM_Utils_Type::MEDIUM,
+ 'required' => TRUE,
+ 'maxlength' => 16,
+ 'size' => CRM_Utils_Type::TWELVE,
'usage' => [
'import' => FALSE,
'export' => FALSE,
@@ -237,6 +241,7 @@ public static function &fields() {
'token' => FALSE,
],
'where' => 'civicrm_managed.cleanup',
+ 'default' => 'always',
'table_name' => 'civicrm_managed',
'entity' => 'Managed',
'bao' => 'CRM_Core_BAO_Managed',
diff --git a/CRM/Core/DAO/MessageTemplate.php b/CRM/Core/DAO/MessageTemplate.php
index b39d92c08373..fd7f5cafd221 100644
--- a/CRM/Core/DAO/MessageTemplate.php
+++ b/CRM/Core/DAO/MessageTemplate.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/MessageTemplate.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:65e3ae090a60b085f252019d3d113ceb)
+ * (GenCodeChecksum:6dc7072586d725f18dd3c984091820f0)
*/
/**
@@ -23,6 +23,13 @@ class CRM_Core_DAO_MessageTemplate extends CRM_Core_DAO {
*/
public static $_tableName = 'civicrm_msg_template';
+ /**
+ * Field to show when displaying a record.
+ *
+ * @var string
+ */
+ public static $_labelField = 'msg_title';
+
/**
* Should CiviCRM log any modifications to this table in the civicrm_log table.
*
diff --git a/CRM/Core/DAO/Note.php b/CRM/Core/DAO/Note.php
index dff8197327fd..5fa11086cafb 100644
--- a/CRM/Core/DAO/Note.php
+++ b/CRM/Core/DAO/Note.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/Note.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c04c2c1404af638e1adf973fe845d0ac)
+ * (GenCodeChecksum:9036c8c92bb1abbbd67b08f5c06f7ea3)
*/
/**
@@ -37,6 +37,18 @@ class CRM_Core_DAO_Note extends CRM_Core_DAO {
*/
public static $_log = TRUE;
+ /**
+ * Paths for accessing this entity in the UI.
+ *
+ * @var string[]
+ */
+ protected static $_paths = [
+ 'add' => 'civicrm/note?reset=1&action=add&entity_table=[entity_table]&entity_id=[entity_id]',
+ 'view' => 'civicrm/note?reset=1&action=view&id=[id]',
+ 'update' => 'civicrm/note?reset=1&action=update&id=[id]',
+ 'delete' => 'civicrm/note?reset=1&action=delete&id=[id]',
+ ];
+
/**
* Note ID
*
diff --git a/CRM/Core/DAO/Tag.php b/CRM/Core/DAO/Tag.php
index b84fa0d5e4e1..b6c5a2f1a4d4 100644
--- a/CRM/Core/DAO/Tag.php
+++ b/CRM/Core/DAO/Tag.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/Tag.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f8d8698f48fbd60b8d8e0bf8eff40c47)
+ * (GenCodeChecksum:ded9d6a9f9c08146a0205da83c838c91)
*/
/**
@@ -35,7 +35,7 @@ class CRM_Core_DAO_Tag extends CRM_Core_DAO {
*
* @var string
*/
- public static $_labelField = 'name';
+ public static $_labelField = 'label';
/**
* Should CiviCRM log any modifications to this table in the civicrm_log table.
@@ -54,7 +54,7 @@ class CRM_Core_DAO_Tag extends CRM_Core_DAO {
public $id;
/**
- * Name of Tag.
+ * Unique machine name
*
* @var string
* (SQL type: varchar(64))
@@ -62,6 +62,15 @@ class CRM_Core_DAO_Tag extends CRM_Core_DAO {
*/
public $name;
+ /**
+ * User-facing tag name
+ *
+ * @var string
+ * (SQL type: varchar(64))
+ * Note that values will be retrieved from the database as a string.
+ */
+ public $label;
+
/**
* Optional verbose description of the tag.
*
@@ -206,7 +215,7 @@ public static function &fields() {
'name' => 'name',
'type' => CRM_Utils_Type::T_STRING,
'title' => ts('Tag Name'),
- 'description' => ts('Name of Tag.'),
+ 'description' => ts('Unique machine name'),
'required' => TRUE,
'maxlength' => 64,
'size' => CRM_Utils_Type::BIG,
@@ -223,6 +232,30 @@ public static function &fields() {
'localizable' => 0,
'add' => '1.1',
],
+ 'label' => [
+ 'name' => 'label',
+ 'type' => CRM_Utils_Type::T_STRING,
+ 'title' => ts('Tag Label'),
+ 'description' => ts('User-facing tag name'),
+ 'required' => TRUE,
+ 'maxlength' => 64,
+ 'size' => CRM_Utils_Type::BIG,
+ 'usage' => [
+ 'import' => FALSE,
+ 'export' => FALSE,
+ 'duplicate_matching' => FALSE,
+ 'token' => FALSE,
+ ],
+ 'where' => 'civicrm_tag.label',
+ 'table_name' => 'civicrm_tag',
+ 'entity' => 'Tag',
+ 'bao' => 'CRM_Core_BAO_Tag',
+ 'localizable' => 0,
+ 'html' => [
+ 'type' => 'Text',
+ ],
+ 'add' => '5.68',
+ ],
'description' => [
'name' => 'description',
'type' => CRM_Utils_Type::T_STRING,
@@ -267,7 +300,8 @@ public static function &fields() {
'pseudoconstant' => [
'table' => 'civicrm_tag',
'keyColumn' => 'id',
- 'labelColumn' => 'name',
+ 'labelColumn' => 'label',
+ 'nameColumn' => 'name',
],
'add' => '1.1',
],
@@ -375,6 +409,7 @@ public static function &fields() {
'localizable' => 0,
'FKClassName' => 'CRM_Contact_DAO_Contact',
'html' => [
+ 'type' => 'EntityRef',
'label' => ts("Created By"),
],
'add' => '3.4',
@@ -412,10 +447,17 @@ public static function &fields() {
'token' => FALSE,
],
'where' => 'civicrm_tag.created_date',
+ 'default' => 'CURRENT_TIMESTAMP',
'table_name' => 'civicrm_tag',
'entity' => 'Tag',
'bao' => 'CRM_Core_BAO_Tag',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select Date',
+ 'formatType' => 'activityDateTime',
+ 'label' => ts("Created Date"),
+ ],
+ 'readonly' => TRUE,
'add' => '3.4',
],
];
diff --git a/CRM/Core/DAO/UFMatch.php b/CRM/Core/DAO/UFMatch.php
index 38744177fa9a..aaa71a8278f2 100644
--- a/CRM/Core/DAO/UFMatch.php
+++ b/CRM/Core/DAO/UFMatch.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/UFMatch.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:03d955dcec4176dec67ec9fbc818e490)
+ * (GenCodeChecksum:ddf0ceeb22715a1ee0b7b93c90df31f2)
*/
/**
@@ -214,7 +214,7 @@ public static function &fields() {
'entity' => 'UFMatch',
'bao' => 'CRM_Core_BAO_UFMatch',
'localizable' => 0,
- 'add' => '1.9.kabissa',
+ 'add' => '1.9',
],
'contact_id' => [
'name' => 'contact_id',
diff --git a/CRM/Core/EntityTokens.php b/CRM/Core/EntityTokens.php
index 070b903b0183..ce76c40e2350 100644
--- a/CRM/Core/EntityTokens.php
+++ b/CRM/Core/EntityTokens.php
@@ -99,7 +99,7 @@ public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL)
$fieldValue = $this->getFieldValue($row, $field);
if (is_array($fieldValue)) {
// eg. role_id for participant would be an array here.
- $fieldValue = implode(',', $fieldValue);
+ $fieldValue = implode(', ', $fieldValue);
}
if ($this->isPseudoField($field)) {
@@ -701,4 +701,35 @@ protected function getCacheKey(): string {
return $cacheKey;
}
+ /**
+ * Get metadata for tokens for a related entity joined by a field on the main entity.
+ *
+ * @param string $entity
+ * @param string $joinField
+ * @param array $tokenList
+ * @param array $hiddenTokens
+ *
+ * @return array
+ * @throws \CRM_Core_Exception
+ */
+ protected function getRelatedTokensForEntity(string $entity, string $joinField, array $tokenList, $hiddenTokens = []): array {
+ $apiParams = ['checkPermissions' => FALSE];
+ if ($tokenList !== ['*']) {
+ $apiParams['where'] = [['name', 'IN', $tokenList]];
+ }
+ $relatedTokens = civicrm_api4($entity, 'getFields', $apiParams);
+ $tokens = [];
+ foreach ($relatedTokens as $relatedToken) {
+ $tokens[$joinField . '.' . $relatedToken['name']] = [
+ 'title' => $relatedToken['title'],
+ 'name' => $joinField . '.' . $relatedToken['name'],
+ 'type' => 'mapped',
+ 'data_type' => $relatedToken['data_type'],
+ 'input_type' => $relatedToken['input_type'],
+ 'audience' => in_array($relatedToken['name'], $hiddenTokens, TRUE) ? 'hidden' : 'user',
+ ];
+ }
+ return $tokens;
+ }
+
}
diff --git a/CRM/Core/Error.php b/CRM/Core/Error.php
index fd6ae04c1475..bdc6e6d03e8d 100644
--- a/CRM/Core/Error.php
+++ b/CRM/Core/Error.php
@@ -655,7 +655,9 @@ public static function debug_query_result($query) {
*/
public static function createDebugLogger($prefix = '') {
self::generateLogFileName($prefix);
- return Log::singleton('file', \Civi::$statics[__CLASS__]['logger_file' . $prefix], '');
+ return Log::singleton('file', \Civi::$statics[__CLASS__]['logger_file' . $prefix], '', [
+ 'timeFormat' => '%Y-%m-%d %H:%M:%S%z',
+ ]);
}
/**
diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php
index d0f17d883d0e..2172fff642a1 100644
--- a/CRM/Core/Form.php
+++ b/CRM/Core/Form.php
@@ -202,6 +202,10 @@ public function getContext() {
* to combine fields from the various screens & save the resulting 'submitted_values'
* to the UserJob.
*
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
* @return array
*/
public function getSubmittedValues(): array {
@@ -219,6 +223,10 @@ public function getSubmittedValues(): array {
* Contribution_Main and Contribution_Confirm) accessible you can override
* this function as CRM_Import_Forms does.
*
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
* @return string[]
*/
protected function getSubmittableFields(): array {
@@ -478,13 +486,9 @@ public function &add(
// Like select but accepts rich array data (with nesting, colors, icons, etc) as option list.
if ($inputType === 'select2') {
$type = 'text';
- $options = [];
- foreach ($attributes as $option) {
- // Transform options from api4.getFields format
- $option['text'] = $option['text'] ?? $option['label'];
- unset($option['label']);
- $options[] = $option;
- }
+ // Options stored in $attributes. Transform from api4.getFields format if needed.
+ $options = CRM_Utils_Array::formatForSelect2($attributes ?: []);
+ // Attributes stored in $extra
$attributes = ($extra ?: []) + ['class' => ''];
$attributes['class'] = ltrim($attributes['class'] . ' crm-select2 crm-form-select2');
$attributes['data-select-params'] = json_encode(['data' => $options, 'multiple' => !empty($attributes['multiple'])]);
@@ -785,7 +789,7 @@ public function addButtons($params) {
$this->submitOnce = TRUE;
}
- $attrs = ['class' => 'crm-form-submit'] + (array) CRM_Utils_Array::value('js', $button);
+ $attrs = ['class' => 'crm-form-submit'] + ($button['js'] ?? []);
// A lot of forms use the hacky method of looking at
// `$params['button name']` (dating back to them being inputs with a
@@ -1840,7 +1844,7 @@ public function addField($name, $props = [], $required = FALSE, $legacyDate = TR
}
if ($context == 'search') {
$widget = $widget == 'Select2' ? $widget : 'Select';
- $props['multiple'] = CRM_Utils_Array::value('multiple', $props, TRUE);
+ $props['multiple'] = $props['multiple'] ?? TRUE;
}
elseif (!empty($fieldSpec['serialize'])) {
$props['multiple'] = TRUE;
@@ -3004,6 +3008,8 @@ public function setSelectedChild($default = NULL) {
* they have permission to (setContactID does do that) and can be used to check if the user is
* accessing their own record.
*
+ * @deprecated use getAuthenticatedContactID()
+ *
* @return int|false
* @throws \CRM_Core_Exception
*/
@@ -3020,14 +3026,20 @@ protected function getContactIDIfAccessingOwnRecord() {
}
/**
- * Get values submitted by the user.
+ * Get value submitted by the user.
*
* These values have been validated against the fields added to the form.
* https://pear.php.net/manual/en/package.html.html-quickform.html-quickform.exportvalues.php
*
+ * Any money processing has also been done.
+ *
* @param string $fieldName
*
* @return mixed|null
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
*/
public function getSubmittedValue(string $fieldName) {
if (empty($this->exportedValues)) {
@@ -3037,6 +3049,15 @@ public function getSubmittedValue(string $fieldName) {
if (in_array($fieldName, $this->submittableMoneyFields, TRUE)) {
return CRM_Utils_Rule::cleanMoney($value);
}
+ else {
+ // Numeric fields are not in submittableMoneyFields (for now)
+ $fieldRules = $this->_rules[$fieldName] ?? [];
+ foreach ($fieldRules as $rule) {
+ if ('money' === $rule['type']) {
+ return CRM_Utils_Rule::cleanMoney($value);
+ }
+ }
+ }
return $value;
}
diff --git a/CRM/Core/Form/EntityFormTrait.php b/CRM/Core/Form/EntityFormTrait.php
index f6173a4e640e..3941da88d68c 100644
--- a/CRM/Core/Form/EntityFormTrait.php
+++ b/CRM/Core/Form/EntityFormTrait.php
@@ -176,11 +176,9 @@ public function buildQuickEntityForm() {
$this->entityFields[$index] = array_replace_recursive([
'template' => '',
'help' => ['id' => '', 'file' => ''],
- 'pre_html_text' => '',
'post_html_text' => '',
'description' => '',
'documentation_link' => ['page' => '', 'resource' => ''],
- 'place_holder' => '',
], $fields);
}
$this->assign('entityFields', $this->entityFields);
diff --git a/CRM/Core/Form/RecurringEntity.php b/CRM/Core/Form/RecurringEntity.php
index 6390726a755f..ce86c7a42ab2 100644
--- a/CRM/Core/Form/RecurringEntity.php
+++ b/CRM/Core/Form/RecurringEntity.php
@@ -20,6 +20,12 @@
* This class generates form components for processing Entity.
*/
class CRM_Core_Form_RecurringEntity {
+
+ private static $preDeleteFunction = [
+ 'Event' => 'CRM_Event_Form_ManageEvent_Repeat::checkRegistrationForEvents',
+ 'Activity' => NULL,
+ ];
+
/**
* Current entity id
* @var int
@@ -317,6 +323,7 @@ public static function formRule($values) {
*
* @param array $params
* @param string $type
+ * Redundant - always the same as `$params['entity_table']`
* @param array $linkedEntities
*
* @throws \CRM_Core_Exception
@@ -393,59 +400,22 @@ public static function postProcess($params, $type, $linkedEntities = []) {
}
}
- // FIXME: This is the worst way possible to convert a table name to an api entity name
- $apiEntityType = explode("_", $type);
- if (!empty($apiEntityType[1])) {
- $apiType = $apiEntityType[1];
- }
- //Delete relations if any from recurring entity tables before inserting new relations for this entity id
+ // Delete relations if any from recurring entity tables before inserting new relations for this entity id
if ($params['entity_id']) {
- //If entity has any pre delete function, consider that first
- if (!empty(CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['pre_delete_func']) &&
- !empty(CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['helper_class'])
- ) {
- // FIXME: This calls `CRM_Event_Form_ManageEvent_Repeat::checkRegistrationForEvents`
- // which then sets the static variable `CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted`
- // which is then accessed below and used to delete events with no registrations.
- // I can't think of a worse way to pass a variable back from a function.
- call_user_func_array(CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['pre_delete_func'], [$params['entity_id']]);
+ $entityType = CRM_Core_DAO_AllCoreTables::getEntityNameForTable($type);
+ // Use pre-delete function for events to exclude those with registered participants
+ if (!empty(self::$preDeleteFunction[$entityType])) {
+ $itemsToDelete = call_user_func_array(self::$preDeleteFunction[$entityType], [$params['entity_id']]);
}
- //Ready to execute delete on entities if it has delete function set
- if (!empty(CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['delete_func']) &&
- !empty(CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['helper_class'])
- ) {
- //Check if pre delete function has some ids to be deleted
- if (!empty(CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted)) {
- foreach (CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted as $eid) {
- $result = civicrm_api3(
- ucfirst(strtolower($apiType)),
- CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['delete_func'],
- [
- 'sequential' => 1,
- 'id' => $eid,
- ]
- );
- if ($result['error']) {
- CRM_Core_Error::statusBounce(ts('Error creating recurring list'));
- }
- }
- }
- else {
- $getRelatedEntities = CRM_Core_BAO_RecurringEntity::getEntitiesFor($params['entity_id'], $params['entity_table'], FALSE);
- foreach ($getRelatedEntities as $key => $value) {
- $result = civicrm_api3(
- ucfirst(strtolower($apiType)),
- CRM_Core_BAO_RecurringEntity::$_recurringEntityHelper[$params['entity_table']]['delete_func'],
- [
- 'sequential' => 1,
- 'id' => $value['id'],
- ]
- );
- if ($result['error']) {
- CRM_Core_Error::statusBounce(ts('Error creating recurring list'));
- }
- }
- }
+ else {
+ $getRelatedEntities = CRM_Core_BAO_RecurringEntity::getEntitiesFor($params['entity_id'], $params['entity_table'], FALSE);
+ $itemsToDelete = array_column($getRelatedEntities, 'id');
+ }
+ if ($itemsToDelete) {
+ civicrm_api4($entityType, 'delete', [
+ 'checkPermissions' => FALSE,
+ 'where' => [['id', 'IN', $itemsToDelete]],
+ ]);
}
// find all entities from the recurring set. At this point we 'll get entities which were not deleted
diff --git a/CRM/Core/Form/Renderer.php b/CRM/Core/Form/Renderer.php
index 92e23e7a505e..11f40d86ed84 100644
--- a/CRM/Core/Form/Renderer.php
+++ b/CRM/Core/Form/Renderer.php
@@ -217,6 +217,34 @@ public static function updateAttributes(&$element, $required, $error) {
$element->updateAttributes($attributes);
}
+ /**
+ * Process an template sourced in a string with Smarty
+ *
+ * This overrides the quick form function which has not been updated in a while.
+ *
+ * The function is called when render the code to mark a field as 'required'
+ *
+ * The notes on the quick form function seem to refer to older smarty - ie:
+ * Smarty has no core function to render a template given as a string.
+ * So we use the smarty eval plugin function to do this.
+ *
+ * @param string $tplSource The template source
+ */
+ public function _tplFetch($tplSource) {
+ // Smarty3 does not have this function defined so the parent fails.
+ // Adding this is preparatory to smarty 3....
+ if (!function_exists('smarty_function_eval') && !file_exists(SMARTY_DIR . '/plugins/function.eval.php')) {
+ $smarty = $this->_tpl;
+ $smarty->assign('var', $tplSource);
+ return $smarty->fetch("string:$tplSource");
+ }
+ // This part is what the parent does & is suitable to Smarty 2.
+ if (!function_exists('smarty_function_eval')) {
+ require SMARTY_DIR . '/plugins/function.eval.php';
+ }
+ return smarty_function_eval(['var' => $tplSource], $this->_tpl);
+ }
+
/**
* Convert IDs to values and format for display.
*
diff --git a/CRM/Core/ManagedEntities.php b/CRM/Core/ManagedEntities.php
index c6bc824419f1..09ea4c76a247 100644
--- a/CRM/Core/ManagedEntities.php
+++ b/CRM/Core/ManagedEntities.php
@@ -1,6 +1,7 @@
value properties of CRM_Core_DAO_Managed used to match an existing record
+ * @param string $entityType
+ * @param $entityId
+ * @return bool
*/
- public function revert(array $params) {
+ public function revert(string $entityType, $entityId): bool {
$mgd = new \CRM_Core_DAO_Managed();
- $mgd->copyValues($params);
+ $mgd->entity_type = $entityType;
+ $mgd->entity_id = $entityId;
$mgd->find(TRUE);
$declarations = $this->getDeclarations([$mgd->module]);
$declarations = CRM_Utils_Array::findAll($declarations, [
@@ -130,12 +133,39 @@ public function revert(array $params) {
'entity' => $mgd->entity_type,
]);
if ($mgd->id && isset($declarations[0])) {
- $this->updateExistingEntity(['update' => 'always'] + $declarations[0] + $mgd->toArray());
+ $item = ['update' => 'always'] + $declarations[0] + $mgd->toArray();
+ $this->backfillDefaults($item);
+ $this->updateExistingEntity($item);
return TRUE;
}
return FALSE;
}
+ /**
+ * Backfill default values to restore record to a pristine state
+ *
+ * @param array $item Managed APIv4 record
+ */
+ private function backfillDefaults(array &$item): void {
+ if ($item['params']['version'] != 4) {
+ return;
+ }
+ // Fetch default values for fields that are writeable
+ $condition = [['type', '=', 'Field'], ['readonly', 'IS EMPTY'], ['default_value', '!=', 'now']];
+ // Exclude "weight" as that auto-adjusts
+ if (CoreUtil::isType($item['entity_type'], 'SortableEntity')) {
+ $weightCol = CoreUtil::getInfoItem($item['entity_type'], 'order_by');
+ $condition[] = ['name', '!=', $weightCol];
+ }
+ $getFields = civicrm_api4($item['entity_type'], 'getFields', [
+ 'checkPermissions' => FALSE,
+ 'action' => 'create',
+ 'where' => $condition,
+ ]);
+ $defaultValues = $getFields->indexBy('name')->column('default_value');
+ $item['params']['values'] += $defaultValues;
+ }
+
/**
* Take appropriate action on every managed entity.
*
@@ -170,12 +200,18 @@ private function filterPlanByAction(array $plan, string $action): array {
}
/**
- * Create a new entity.
+ * Create a new entity (if policy allows).
*
* @param array $item
* Entity specification (per hook_civicrm_managedEntities).
*/
protected function insertNewEntity(array $item) {
+ // If entity has previously been created, only re-insert if 'update' policy is 'always'
+ // NOTE: $item[id] is the id of the `civicrm_managed` row not the entity itself
+ // If that id exists, then we know the entity was inserted previously and subsequently deleted.
+ if (!empty($item['id']) && $item['update'] !== 'always') {
+ return;
+ }
$params = $item['params'];
// APIv4
if ($params['version'] == 4) {
@@ -203,11 +239,13 @@ protected function insertNewEntity(array $item) {
}
$dao = new CRM_Core_DAO_Managed();
+ // If re-inserting the entity, we'll update instead of create the managed record.
+ $dao->id = $item['id'] ?? NULL;
$dao->module = $item['module'];
$dao->name = $item['name'];
$dao->entity_type = $item['entity_type'];
$dao->entity_id = $id;
- $dao->cleanup = $item['cleanup'] ?? NULL;
+ $dao->cleanup = $item['cleanup'] ?? 'always';
$dao->save();
}
@@ -261,7 +299,13 @@ private function updateExistingEntity(array $item) {
}
elseif ($doUpdate && $item['params']['version'] == 4) {
$params = ['checkPermissions' => FALSE] + $item['params'];
- $params['values']['id'] = $item['entity_id'];
+ $idField = CoreUtil::getIdFieldName($item['entity_type']);
+ $params['values'][$idField] = $item['entity_id'];
+ // Exclude "weight" as that auto-adjusts
+ if (CoreUtil::isType($item['entity_type'], 'SortableEntity')) {
+ $weightCol = CoreUtil::getInfoItem($item['entity_type'], 'order_by');
+ unset($params['values'][$weightCol]);
+ }
// 'match' param doesn't apply to "update" action
unset($params['match']);
try {
@@ -332,7 +376,7 @@ protected function removeStaleEntity(array $item) {
case 'unused':
if (CRM_Core_BAO_Managed::isApi4ManagedType($item['entity_type'])) {
- $getRefCount = \Civi\Api4\Utils\CoreUtil::getRefCount($item['entity_type'], $item['entity_id']);
+ $getRefCount = CoreUtil::getRefCount($item['entity_type'], $item['entity_id']);
}
else {
$getRefCount = civicrm_api3($item['entity_type'], 'getrefcount', [
@@ -399,30 +443,6 @@ protected function createModuleIndex($modules) {
return $result;
}
- /**
- * @param array $moduleIndex
- * @param array $declarations
- *
- * @return array
- * indexed by module,name
- */
- protected function createDeclarationIndex($moduleIndex, $declarations) {
- $result = [];
- if (!isset($moduleIndex[TRUE])) {
- return $result;
- }
- foreach ($moduleIndex[TRUE] as $moduleName => $module) {
- if ($module->is_active) {
- // need an empty array() for all active modules, even if there are no current $declarations
- $result[$moduleName] = [];
- }
- }
- foreach ($declarations as $declaration) {
- $result[$declaration['module']][$declaration['name']] = $declaration;
- }
- return $result;
- }
-
/**
* @param array $declarations
*
@@ -555,29 +575,20 @@ protected function createPlan(array $declarations, $modules = NULL): array {
$plan = [];
foreach ($managedEntities as $managedEntity) {
$key = "{$managedEntity['module']}_{$managedEntity['name']}_{$managedEntity['entity_type']}";
- // Set to disable or delete if module is disabled or missing - it will be overwritten below module is active.
+ // Set to disable or delete if module is disabled or missing - it will be overwritten below if module is active.
$action = $this->isModuleDisabled($managedEntity['module']) ? 'disable' : 'delete';
$plan[$key] = array_merge($managedEntity, ['managed_action' => $action]);
}
foreach ($declarations as $declaration) {
$key = "{$declaration['module']}_{$declaration['name']}_{$declaration['entity']}";
- if (isset($plan[$key])) {
- $plan[$key]['params'] = $declaration['params'];
- $plan[$key]['managed_action'] = 'update';
- $plan[$key]['cleanup'] = $declaration['cleanup'] ?? NULL;
- $plan[$key]['update'] = $declaration['update'] ?? 'always';
- }
- else {
- $plan[$key] = [
- 'module' => $declaration['module'],
- 'name' => $declaration['name'],
- 'entity_type' => $declaration['entity'],
- 'managed_action' => 'create',
- 'params' => $declaration['params'],
- 'cleanup' => $declaration['cleanup'] ?? NULL,
- 'update' => $declaration['update'] ?? 'always',
- ];
- }
+ // Set action to update if already managed
+ $plan[$key]['managed_action'] = empty($plan[$key]['entity_id']) ? 'create' : 'update';
+ $plan[$key]['module'] = $declaration['module'];
+ $plan[$key]['name'] = $declaration['name'];
+ $plan[$key]['entity_type'] = $declaration['entity'];
+ $plan[$key]['params'] = $declaration['params'];
+ $plan[$key]['cleanup'] = $declaration['cleanup'] ?? NULL;
+ $plan[$key]['update'] = $declaration['update'] ?? 'always';
}
return $plan;
}
diff --git a/CRM/Core/OptionValue.php b/CRM/Core/OptionValue.php
index 95662e6bd4b9..89f45a28da2a 100644
--- a/CRM/Core/OptionValue.php
+++ b/CRM/Core/OptionValue.php
@@ -181,7 +181,7 @@ public static function getRows($groupParams, $links, $orderBy = 'weight', $skipE
*
*/
public static function addOptionValue(&$params, $optionGroupName, $action, $optionValueID) {
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
// checking if the group name with the given id or name (in $groupParams) exists
$groupParams = ['name' => $optionGroupName, 'is_active' => 1];
$optionGroup = CRM_Core_BAO_OptionGroup::retrieve($groupParams, $defaults);
diff --git a/CRM/Core/Page.php b/CRM/Core/Page.php
index 41a8a57c693a..bfe554070fc6 100644
--- a/CRM/Core/Page.php
+++ b/CRM/Core/Page.php
@@ -132,6 +132,8 @@ class CRM_Core_Page {
// in 'body.tpl
'suppressForm',
'beginHookFormElements',
+ // This is checked in validate.tpl
+ 'snippet_type',
];
/**
diff --git a/CRM/Core/Page/Redirect.php b/CRM/Core/Page/Redirect.php
index 4f0b83dde4b6..3977e5ad3389 100644
--- a/CRM/Core/Page/Redirect.php
+++ b/CRM/Core/Page/Redirect.php
@@ -55,7 +55,7 @@ public static function createUrl($requestPath, $requestArgs, $pageArgs, $absolut
$urlParts = parse_url($urlString);
$url = CRM_Utils_System::url(
$urlParts['path'],
- CRM_Utils_Array::value('query', $urlParts, NULL),
+ $urlParts['query'] ?? NULL,
$absolute,
CRM_Utils_Array::value('fragment', $urlParts, NULL)
);
diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php
index 0453ac8ad712..9e0f2a33a87e 100644
--- a/CRM/Core/Payment.php
+++ b/CRM/Core/Payment.php
@@ -591,6 +591,24 @@ public function getText($context, $params) {
case 'contributionPageContinueText':
return ts('Click the Continue button to proceed with the payment.');
+ case 'contributionPageConfirmText':
+ if ($params['amount'] <= 0.0) {
+ return '';
+ }
+ if ((int) $this->_paymentProcessor['billing_mode'] !== 4) {
+ return ts('Your contribution will not be completed until you click the %1 button. Please click the button one time only.', [1 => ts('Make Contribution')]);
+ }
+ return '';
+
+ case 'contributionPageButtonText':
+ if ($params['amount'] <= 0.0 || (int) $this->_paymentProcessor['billing_mode'] === 4) {
+ return ts('Continue');
+ }
+ if ($params['is_payment_to_existing']) {
+ return ts('Make Payment');
+ }
+ return ts('Make Contribution');
+
case 'cancelRecurDetailText':
if ($params['mode'] === 'auto_renew') {
return ts('Click the button below if you want to cancel the auto-renewal option for your %1 membership. This will not cancel your membership. However you will need to arrange payment for renewal when your membership expires.',
diff --git a/CRM/Core/Payment/Manual.php b/CRM/Core/Payment/Manual.php
index 07a008c0ec37..26b348638b24 100644
--- a/CRM/Core/Payment/Manual.php
+++ b/CRM/Core/Payment/Manual.php
@@ -272,13 +272,16 @@ public function isSendReceiptForPending() {
*
* @return string
*/
- public function getText($context, $params) {
+ public function getText($context, $params): string {
switch ($context) {
case 'contributionPageContinueText':
- if ($params['amount'] <= 0) {
- return ts('To complete this transaction, click the Continue button below.');
- }
- return ts('To complete your contribution, click the Continue button below.');
+ return '';
+
+ case 'contributionPageButtonText':
+ return ts('Continue');
+
+ case 'contributionPageConfirmText':
+ return '';
default:
return parent::getText($context, $params);
diff --git a/CRM/Core/Payment/PayPalIPN.php b/CRM/Core/Payment/PayPalIPN.php
index 23be16e1afd0..232cad6e9f21 100644
--- a/CRM/Core/Payment/PayPalIPN.php
+++ b/CRM/Core/Payment/PayPalIPN.php
@@ -430,7 +430,7 @@ protected function getContribution(): CRM_Contribute_BAO_Contribution {
$this->contribution = new CRM_Contribute_BAO_Contribution();
$this->contribution->id = $this->getContributionID();
if (!$this->contribution->find(TRUE)) {
- throw new CRM_Core_Exception('Failure: Could not find contribution record for ' . (int) $contribution->id, NULL, ['context' => "Could not find contribution record: {$contribution->id} in IPN request: "]);
+ throw new CRM_Core_Exception('Failure: Could not find contribution record for ' . (int) $this->contribution->id, NULL, ['context' => "Could not find contribution record: {$this->contribution->id} in IPN request: "]);
}
if ((int) $this->contribution->contact_id !== $this->getContactID()) {
CRM_Core_Error::debug_log_message("Contact ID in IPN not found but contact_id found in contribution.");
diff --git a/CRM/Core/Payment/PayPalProIPN.php b/CRM/Core/Payment/PayPalProIPN.php
index 2106e136d425..61460ca9c33d 100644
--- a/CRM/Core/Payment/PayPalProIPN.php
+++ b/CRM/Core/Payment/PayPalProIPN.php
@@ -228,60 +228,29 @@ public function recur(array $input): void {
$first = !$this->isContributionCompleted();
$recur = $this->getContributionRecurObject();
if (!isset($input['txnType'])) {
- Civi::log()->debug('PayPalProIPN: Could not find txn_type in input request.');
+ Civi::log('paypal_pro')->debug('PayPalProIPN: Could not find txn_type in input request.');
echo 'Failure: Invalid parameters';
return;
}
- // 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']) {
- 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;
- }
-
$now = date('YmdHis');
- $sendNotification = FALSE;
- $subscriptionPaymentStatus = NULL;
- //List of Transaction Type
- /*
- recurring_payment_profile_created RP Profile Created
- recurring_payment RP Successful Payment
- recurring_payment_failed RP Failed Payment
- recurring_payment_profile_cancel RP Profile Cancelled
- recurring_payment_expired RP Profile Expired
- recurring_payment_skipped RP Profile Skipped
- recurring_payment_outstanding_payment RP Successful Outstanding Payment
- recurring_payment_outstanding_payment_failed RP Failed Outstanding Payment
- recurring_payment_suspended RP Profile Suspended
- recurring_payment_suspended_due_to_max_failed_payment RP Profile Suspended due to Max Failed Payment
- */
-
- //set transaction type
$txnType = $this->retrieve('txn_type', 'String');
- //Changes for paypal pro recurring payment
+
switch ($txnType) {
case 'recurring_payment_profile_created':
- if (in_array(CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $recur->contribution_status_id), [
- 'Pending', 'In Progress',
- ], TRUE)
- && !empty($recur->processor_id)
+ if (CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $recur->contribution_status_id) === 'In Progress'
) {
- echo 'already handled';
+ Civi::log('paypal_pro')->debug('already handled');
return;
}
- $recur->create_date = $now;
- $recur->contribution_status_id = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', 'Pending');
- $recur->processor_id = $this->retrieve('recurring_payment_id', 'String');
- $recur->trxn_id = $recur->processor_id;
- $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_START;
- $sendNotification = TRUE;
- break;
+ $this->processProfileCreated();
+ return;
case 'recurring_payment':
+ $recur->processor_id = $this->retrieve('recurring_payment_id', 'String');
+ $recur->trxn_id = $recur->processor_id;
+ $recur->save();
if (!$first) {
if ($input['paymentStatus'] !== 'Completed') {
throw new CRM_Core_Exception('Ignore all IPN payments that are not completed');
@@ -306,29 +275,18 @@ public function recur(array $input): void {
}
$recur->contribution_status_id = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', 'Completed');
$recur->end_date = $now;
- $sendNotification = TRUE;
- $subscriptionPaymentStatus = CRM_Core_Payment::RECURRING_PAYMENT_END;
+ $recur->save();
+ //send recurring Notification email for user
+ CRM_Contribute_BAO_ContributionPage::recurringNotify(
+ $this->getContributionID(),
+ CRM_Core_Payment::RECURRING_PAYMENT_END,
+ $recur
+ );
}
-
+ $this->single($input);
break;
}
- $recur->save();
-
- if ($sendNotification) {
- //send recurring Notification email for user
- CRM_Contribute_BAO_ContributionPage::recurringNotify(
- $this->getContributionID(),
- $subscriptionPaymentStatus,
- $recur
- );
- }
-
- if ($txnType !== 'recurring_payment') {
- return;
- }
-
- $this->single($input);
}
/**
@@ -355,11 +313,11 @@ protected function single(array $input): void {
'cancel_date' => 'now',
'contribution_status_id:name' => 'Failed',
])->addWhere('id', '=', $this->getContributionID())->execute();
- Civi::log()->debug('Setting contribution status to Failed');
+ Civi::log('paypal_pro')->debug('Setting contribution status to Failed');
return;
}
if ($status === 'Pending') {
- Civi::log()->debug('Returning since contribution status is Pending');
+ Civi::log('paypal_pro')->debug('Returning since contribution status is Pending');
return;
}
if ($status === 'Refunded' || $status === 'Reversed') {
@@ -367,16 +325,16 @@ protected function single(array $input): void {
'cancel_date' => 'now',
'contribution_status_id:name' => 'Cancelled',
])->addWhere('id', '=', $this->getContributionID())->execute();
- Civi::log()->debug('Setting contribution status to Cancelled');
+ Civi::log('paypal_pro')->debug('Setting contribution status to Cancelled');
return;
}
if ($status !== 'Completed') {
- Civi::log()->debug('Returning since contribution status is not handled');
+ Civi::log('paypal_pro')->debug('Returning since contribution status is not handled');
return;
}
if ($this->isContributionCompleted()) {
- Civi::log()->debug('PayPalProIPN: Returning since contribution has already been handled.');
+ Civi::log('paypal_pro')->debug('PayPalProIPN: Returning since contribution has already been handled.');
echo 'Success: Contribution has already been handled
';
return;
}
@@ -396,7 +354,7 @@ public function getPayPalPaymentProcessorID() {
// 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');
+ Civi::log('paypal_pro')->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'
@@ -449,7 +407,7 @@ public function main(): void {
$this->single($input);
}
catch (Exception $e) {
- Civi::log()->debug($e->getMessage() . ' input {input}', ['input' => $input]);
+ Civi::log('paypal_pro')->debug($e->getMessage() . ' input {input}', ['input' => $input]);
echo 'Invalid or missing data';
}
}
@@ -561,6 +519,15 @@ protected function getContributionRecurObject(): CRM_Contribute_BAO_Contribution
if (!$contributionRecur->find(TRUE)) {
throw new CRM_Core_Exception('Failure: Could not find contribution recur record');
}
+
+ // make sure the invoice ids match
+ // make sure the invoice is valid and matches what we have in
+ // the contribution record
+ $invoice = (string) $this->getValue('i');
+ if ((string) $contributionRecur->invoice_id !== $invoice) {
+ Civi::log('paypal_pro')->debug('PayPalProIPN: Invoice values dont match between database and IPN request recur is ' . $contributionRecur->invoice_id . ' input is ' . $invoice);
+ throw new CRM_Core_Exception('Failure: Invoice values dont match between database and IPN request recur is ' . $contributionRecur->invoice_id . " input is " . $invoice);
+ }
return $this->contributionRecurObject = $contributionRecur;
}
return $this->contributionRecurObject;
@@ -607,4 +574,30 @@ private function isContributionCompleted(): bool {
return $status === 'Completed';
}
+ /**
+ * Update a recurring contribution to in progress based on an ipn profile_create notification.
+ *
+ * recurring_payment_profile_created is called when the
+ * subscription has been authorized and confirmed by the user,
+ * but before a payment has been taken.
+ * The recurring_payment_id is POSTed to the IPN
+ * and we store it in the recurring contribution's processor_id.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function processProfileCreated(): void {
+ $recur = $this->getContributionRecurObject();
+ $recur->create_date = date('YmdHis');
+ $recur->contribution_status_id = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', 'Pending');
+ $recur->processor_id = $this->retrieve('recurring_payment_id', 'String');
+ $recur->trxn_id = $recur->processor_id;
+ $recur->save();
+ //send recurring Notification email for user
+ CRM_Contribute_BAO_ContributionPage::recurringNotify(
+ $this->getContributionID(),
+ CRM_Core_Payment::RECURRING_PAYMENT_START,
+ $recur
+ );
+ }
+
}
diff --git a/CRM/Core/PseudoConstant.php b/CRM/Core/PseudoConstant.php
index 4a86234f1f83..73275f3eb51a 100644
--- a/CRM/Core/PseudoConstant.php
+++ b/CRM/Core/PseudoConstant.php
@@ -68,12 +68,6 @@ class CRM_Core_PseudoConstant {
*/
private static $country;
- /**
- * CountryIsoCode.
- * @var array
- */
- private static $countryIsoCode;
-
/**
* group
* @var array
@@ -99,43 +93,6 @@ class CRM_Core_PseudoConstant {
*/
private static $currencyCode;
- /**
- * Payment processor
- * @var array
- */
- private static $paymentProcessor;
-
- /**
- * Payment processor types
- * @var array
- */
- private static $paymentProcessorType;
-
- /**
- * World Region
- * @var array
- */
- private static $worldRegions;
-
- /**
- * activity status
- * @var array
- * @deprecated Please use the buildOptions() method in the appropriate BAO object.
- */
- private static $activityStatus;
-
- /**
- * Visibility
- * @var array
- */
- private static $visibility;
-
- /**
- * Greetings
- * @var array
- */
- private static $greeting;
-
/**
* Extensions of type module
* @var array
@@ -466,8 +423,7 @@ public static function populate(
}
/**
- * Flush given pseudoconstant so it can be reread from db.
- * nex time it's requested.
+ * Flush static array cache.
*
* @param bool|string $name pseudoconstant to be flushed
*/
@@ -496,12 +452,12 @@ public static function flush($name = 'cache') {
*/
public static function &activityType() {
$args = func_get_args();
- $all = CRM_Utils_Array::value(0, $args, TRUE);
- $includeCaseActivities = CRM_Utils_Array::value(1, $args, FALSE);
- $reset = CRM_Utils_Array::value(2, $args, FALSE);
- $returnColumn = CRM_Utils_Array::value(3, $args, 'label');
- $includeCampaignActivities = CRM_Utils_Array::value(4, $args, FALSE);
- $onlyComponentActivities = CRM_Utils_Array::value(5, $args, FALSE);
+ $all = $args[0] ?? TRUE;
+ $includeCaseActivities = $args[1] ?? FALSE;
+ $reset = $args[2] ?? FALSE;
+ $returnColumn = $args[3] ?? 'label';
+ $includeCampaignActivities = $args[4] ?? FALSE;
+ $onlyComponentActivities = $args[5] ?? FALSE;
$index = (int) $all . '_' . $returnColumn . '_' . (int) $includeCaseActivities;
$index .= '_' . (int) $includeCampaignActivities;
$index .= '_' . (int) $onlyComponentActivities;
@@ -668,6 +624,7 @@ public static function stateProvinceAbbreviation($id = FALSE, $limit = TRUE) {
/**
* Get all the State/Province abbreviations from the database for the specified country.
+ * @deprecated
*
* @param int $countryID
*
@@ -675,21 +632,24 @@ public static function stateProvinceAbbreviation($id = FALSE, $limit = TRUE) {
* array of all State/Province abbreviations for the given country.
*/
public static function stateProvinceAbbreviationForCountry($countryID) {
- if (!isset(\Civi::$statics[__CLASS__]['stateProvinceAbbreviationForCountry'][$countryID])) {
- \Civi::$statics[__CLASS__]['stateProvinceAbbreviationForCountry'][$countryID] = [];
- }
- self::populate(\Civi::$statics[__CLASS__]['stateProvinceAbbreviationForCountry'][$countryID], 'CRM_Core_DAO_StateProvince', TRUE, 'abbreviation', 'is_active', "country_id = " . (int) $countryID, 'abbreviation');
- return \Civi::$statics[__CLASS__]['stateProvinceAbbreviationForCountry'][$countryID];
+ CRM_Core_Error::deprecatedFunctionWarning('API');
+ $abbrs = [];
+ self::populate($abbrs, 'CRM_Core_DAO_StateProvince', TRUE, 'abbreviation', 'is_active', "country_id = " . (int) $countryID, 'abbreviation');
+ return $abbrs;
}
/**
* Get all the State/Province abbreviations from the database for the default country.
+ * @deprecated
*
* @return array
* array of all State/Province abbreviations for the given country.
*/
public static function stateProvinceAbbreviationForDefaultCountry() {
- return CRM_Core_PseudoConstant::stateProvinceAbbreviationForCountry(Civi::settings()->get('defaultContactCountry'));
+ $countryID = Civi::settings()->get('defaultContactCountry');
+ $abbrs = [];
+ self::populate($abbrs, 'CRM_Core_DAO_StateProvince', TRUE, 'abbreviation', 'is_active', "country_id = " . (int) $countryID, 'abbreviation');
+ return $abbrs;
}
/**
@@ -754,31 +714,18 @@ public static function country($id = FALSE, $applyLimit = TRUE) {
/**
* Get all the country ISO Code abbreviations from the database.
*
- * The static array countryIsoCode is returned, and if it's
- * called the first time, the Country DAO is used
- * to get all the countries' ISO codes.
- *
- * Note: any database errors will be trapped by the DAO.
- *
- *
* @param bool $id
*
* @return array
- * array reference of all country ISO codes.
*/
- public static function &countryIsoCode($id = FALSE) {
- if (!self::$countryIsoCode) {
- self::populate(self::$countryIsoCode, 'CRM_Core_DAO_Country', TRUE, 'iso_code');
- }
+ public static function countryIsoCode($id = FALSE) {
+ $values = [];
+ self::populate($values, 'CRM_Core_DAO_Country', TRUE, 'iso_code');
+
if ($id) {
- if (array_key_exists($id, self::$countryIsoCode)) {
- return self::$countryIsoCode[$id];
- }
- else {
- return CRM_Core_DAO::$_nullObject;
- }
+ return $values[$id] ?? NULL;
}
- return self::$countryIsoCode;
+ return $values;
}
/**
@@ -803,12 +750,9 @@ public static function &countryIsoCode($id = FALSE) {
*/
public static function allGroup($groupType = NULL, $excludeHidden = TRUE) {
$condition = CRM_Contact_BAO_Group::groupTypeCondition($groupType, $excludeHidden);
- $groupKey = ($groupType ?: 'null') . !empty($excludeHidden);
-
- if (!isset(Civi::$statics[__CLASS__]['groups']['allGroup'][$groupKey])) {
- self::populate(Civi::$statics[__CLASS__]['groups']['allGroup'][$groupKey], 'CRM_Contact_DAO_Group', FALSE, 'title', 'is_active', $condition);
- }
- return Civi::$statics[__CLASS__]['groups']['allGroup'][$groupKey];
+ $values = [];
+ self::populate($values, 'CRM_Contact_DAO_Group', FALSE, 'title', 'is_active', $condition);
+ return $values;
}
/**
@@ -955,9 +899,6 @@ public static function relationshipTypeOptions() {
/**
* Get all the ISO 4217 currency codes
*
- * so far, we use this for validation only, so there's no point of putting this into the database
- *
- *
* @return array
* array reference of all currency codes
*/
@@ -966,7 +907,6 @@ public static function ¤cyCode() {
$query = "SELECT name FROM civicrm_currency";
$dao = CRM_Core_DAO::executeQuery($query);
- $currencyCode = [];
while ($dao->fetch()) {
self::$currencyCode[] = $dao->name;
}
@@ -1025,8 +965,7 @@ public static function &county($id = FALSE) {
* array of all payment processors
*/
public static function paymentProcessor($all = FALSE, $test = FALSE, $additionalCond = NULL) {
- $condition = "is_test = ";
- $condition .= ($test) ? '1' : '0';
+ $condition = 'is_test = ' . ($test ? '1' : '0');
if ($additionalCond) {
$condition .= " AND ( $additionalCond ) ";
@@ -1035,13 +974,10 @@ public static function paymentProcessor($all = FALSE, $test = FALSE, $additional
// CRM-7178. Make sure we only include payment processors valid in this
// domain
$condition .= " AND domain_id = " . CRM_Core_Config::domainID();
+ $values = [];
+ self::populate($values, 'CRM_Financial_DAO_PaymentProcessor', $all, 'name', 'is_active', $condition, 'is_default desc, name');
- $cacheKey = $condition . '_' . (int) $all;
- if (!isset(self::$paymentProcessor[$cacheKey])) {
- self::populate(self::$paymentProcessor[$cacheKey], 'CRM_Financial_DAO_PaymentProcessor', $all, 'name', 'is_active', $condition, 'is_default desc, name');
- }
-
- return self::$paymentProcessor[$cacheKey];
+ return $values;
}
/**
@@ -1060,40 +996,32 @@ public static function paymentProcessor($all = FALSE, $test = FALSE, $additional
* array of all payment processor types
*/
public static function &paymentProcessorType($all = FALSE, $id = NULL, $return = 'title') {
- $cacheKey = $id . '_' . $return;
- if (empty(self::$paymentProcessorType[$cacheKey])) {
- self::populate(self::$paymentProcessorType[$cacheKey], 'CRM_Financial_DAO_PaymentProcessorType', $all, $return, 'is_active', NULL, "is_default, $return", 'id');
- }
- if ($id && !empty(self::$paymentProcessorType[$cacheKey][$id])) {
- return self::$paymentProcessorType[$cacheKey][$id];
- }
- return self::$paymentProcessorType[$cacheKey];
+ CRM_Core_Error::deprecatedFunctionWarning('API');
+ $values = [];
+ self::populate($values, 'CRM_Financial_DAO_PaymentProcessorType', $all, $return, 'is_active', NULL, "is_default, $return", 'id');
+ // This is incredibly stupid, but the whole function is deprecated anyway...
+ if ($id && !empty($values[$id])) {
+ return $values[$id];
+ }
+ return $values;
}
/**
* Get all the World Regions from Database.
*
- *
* @param bool $id
*
* @return array
* array reference of all World Regions
*/
- public static function &worldRegion($id = FALSE) {
- if (!self::$worldRegions) {
- self::populate(self::$worldRegions, 'CRM_Core_DAO_Worldregion', TRUE, 'name', NULL, NULL, 'id');
- }
+ public static function worldRegion($id = FALSE) {
+ $values = [];
+ self::populate($values, 'CRM_Core_DAO_Worldregion', TRUE, 'name', NULL, NULL, 'id');
if ($id) {
- if (array_key_exists($id, self::$worldRegions)) {
- return self::$worldRegions[$id];
- }
- else {
- return CRM_Core_DAO::$_nullObject;
- }
+ return $values[$id] ?? NULL;
}
-
- return self::$worldRegions;
+ return $values;
}
/**
@@ -1101,25 +1029,12 @@ public static function &worldRegion($id = FALSE) {
*
* Get all Activity Statuses.
*
- * The static array activityStatus is returned
- *
- *
* @param string $column
*
* @return array
- * array reference of all activity statuses
*/
public static function &activityStatus($column = 'label') {
- if (NULL === self::$activityStatus) {
- self::$activityStatus = [];
- }
- if (!array_key_exists($column, self::$activityStatus)) {
- self::$activityStatus[$column] = [];
-
- self::$activityStatus[$column] = CRM_Core_OptionGroup::values('activity_status', FALSE, FALSE, FALSE, NULL, $column);
- }
-
- return self::$activityStatus[$column];
+ return CRM_Core_OptionGroup::values('activity_status', FALSE, FALSE, FALSE, NULL, $column);
}
/**
@@ -1135,16 +1050,8 @@ public static function &activityStatus($column = 'label') {
* @return array
* array reference of all Visibility levels.
*/
- public static function &visibility($column = 'label') {
- if (!isset(self::$visibility)) {
- self::$visibility = [];
- }
-
- if (!isset(self::$visibility[$column])) {
- self::$visibility[$column] = CRM_Core_OptionGroup::values('visibility', FALSE, FALSE, FALSE, NULL, $column);
- }
-
- return self::$visibility[$column];
+ public static function visibility($column = 'label') {
+ return CRM_Core_OptionGroup::values('visibility', FALSE, FALSE, FALSE, NULL, $column);
}
/**
diff --git a/CRM/Core/QuickForm/Action/Upload.php b/CRM/Core/QuickForm/Action/Upload.php
index c86d0b2f1602..9f7089893d2f 100644
--- a/CRM/Core/QuickForm/Action/Upload.php
+++ b/CRM/Core/QuickForm/Action/Upload.php
@@ -77,7 +77,7 @@ public function upload(&$page, &$data, $pageName, $uploadName) {
// rename the uploaded file with a unique number at the end
$value = $element->getValue();
- $newName = CRM_Utils_File::makeFileName($value['name']);
+ $newName = CRM_Utils_File::makeFileName($value['name'], TRUE);
$status = $element->moveUploadedFile($this->_uploadDir, $newName);
if (!$status) {
CRM_Core_Error::statusBounce(ts('We could not move the uploaded file %1 to the upload directory %2. Please verify that the \'Temporary Files\' setting points to a valid path which is writable by your web server.', [
diff --git a/CRM/Core/Resources.php b/CRM/Core/Resources.php
index b1818c689389..f1610b35f63c 100644
--- a/CRM/Core/Resources.php
+++ b/CRM/Core/Resources.php
@@ -429,7 +429,7 @@ public static function renderL10nJs(GenericHookEvent $e) {
$e->mimeType = 'application/javascript';
$params = $e->params;
$params += [
- 'contactSearch' => json_encode($params['includeEmailInName'] ? ts('Search by name/email or id...') : ts('Search by name or id...')),
+ 'contactSearch' => json_encode(!empty($params['includeEmailInName']) ? ts('Search by name/email or id...') : ts('Search by name or id...')),
'otherSearch' => json_encode(ts('Enter search term or id...')),
'entityRef' => self::getEntityRefMetadata(),
];
diff --git a/CRM/Core/SelectValues.php b/CRM/Core/SelectValues.php
index 0573b1a8a1f1..e550d54deceb 100644
--- a/CRM/Core/SelectValues.php
+++ b/CRM/Core/SelectValues.php
@@ -219,6 +219,11 @@ public static function customHtmlType() {
'name' => 'Link',
'label' => ts('Link'),
],
+ [
+ 'id' => 'Hidden',
+ 'name' => 'Hidden',
+ 'label' => ts('Hidden'),
+ ],
];
}
@@ -634,6 +639,7 @@ public static function contactTokens(): array {
* @return array
*/
public static function participantTokens(): array {
+ CRM_Core_Error::deprecatedFunctionWarning('user TokenProcessor');
$tokenProcessor = new TokenProcessor(Civi::dispatcher(), ['schema' => ['participantId']]);
$allTokens = $tokenProcessor->listTokens();
foreach (array_keys($allTokens) as $token) {
@@ -1079,16 +1085,19 @@ public static function getPermissionedRelationshipOptions() {
'id' => CRM_Contact_BAO_Relationship::NONE,
'name' => 'None',
'label' => ts('None'),
+ 'icon' => NULL,
],
[
'id' => CRM_Contact_BAO_Relationship::VIEW,
'name' => 'View only',
'label' => ts('View only'),
+ 'icon' => 'fa-eye',
],
[
'id' => CRM_Contact_BAO_Relationship::EDIT,
'name' => 'View and update',
'label' => ts('View and update'),
+ 'icon' => 'fa-pencil-square',
],
];
}
@@ -1127,6 +1136,7 @@ public static function quicksearchOptions() {
'address_primary.street_address' => ts('Street Address'),
'address_primary.city' => ts('City'),
'address_primary.postal_code' => ts('Postal Code'),
+ 'employer_id.sort_name' => ts('Current Employer'),
'job_title' => ts('Job Title'),
];
$custom = civicrm_api4('CustomField', 'get', [
diff --git a/CRM/Core/Selector/Controller.php b/CRM/Core/Selector/Controller.php
index c2cc8d196aa6..b2d899a30532 100644
--- a/CRM/Core/Selector/Controller.php
+++ b/CRM/Core/Selector/Controller.php
@@ -325,7 +325,7 @@ public function run() {
}
else {
// output requires paging/sorting capability
- $rows = self::getRows($this);
+ $rows = $this->getRows($this);
CRM_Utils_Hook::searchColumns($contextName, $columnHeaders, $rows, $this);
$reorderedHeaders = [];
$noWeightHeaders = [];
diff --git a/CRM/Core/Smarty.php b/CRM/Core/Smarty.php
index b5c22c62df57..60f6cfcb0973 100644
--- a/CRM/Core/Smarty.php
+++ b/CRM/Core/Smarty.php
@@ -22,14 +22,10 @@
use Civi\Core\Event\SmartyErrorEvent;
-if (!class_exists('Smarty')) {
- require_once 'Smarty/Smarty.class.php';
-}
-
/**
*
*/
-class CRM_Core_Smarty extends Smarty {
+class CRM_Core_Smarty extends CRM_Core_SmartyCompatibility {
const
// use print.tpl and bypass the CMS. Civi prints a valid html file
PRINT_PAGE = 1,
@@ -132,6 +128,15 @@ private function initialize() {
$this->assign('config', $config);
$this->assign('session', $session);
+ $this->assign('debugging', [
+ 'smartyDebug' => CRM_Utils_Request::retrieveValue('smartyDebug', 'Integer'),
+ 'sessionReset' => CRM_Utils_Request::retrieveValue('sessionReset', 'Integer'),
+ 'sessionDebug' => CRM_Utils_Request::retrieveValue('sessionDebug', 'Integer'),
+ 'directoryCleanup' => CRM_Utils_Request::retrieveValue('directoryCleanup', 'Integer'),
+ 'cacheCleanup' => CRM_Utils_Request::retrieveValue('cacheCleanup', 'Integer'),
+ 'configReset' => CRM_Utils_Request::retrieveValue('configReset', 'Integer'),
+ ]);
+ $this->assign('snippet_type', CRM_Utils_Request::retrieveValue('snippet', 'String'));
$tsLocale = CRM_Core_I18n::getLocale();
$this->assign('tsLocale', $tsLocale);
@@ -141,7 +146,12 @@ private function initialize() {
$this->assign('langSwitch', CRM_Core_I18n::uiLanguages());
}
- if (CRM_Utils_Constant::value('CIVICRM_SMARTY_DEFAULT_ESCAPE')) {
+ if (CRM_Utils_Constant::value('CIVICRM_SMARTY_DEFAULT_ESCAPE')
+ && !CRM_Utils_Constant::value('CIVICRM_SMARTY3_AUTOLOAD_PATH')) {
+ // Currently DEFAULT escape does not work with Smarty3
+ // dunno why - thought it would be the default with Smarty3 - but
+ // getting onto Smarty 3 is higher priority.
+ // The include below loads the v2 version which is why id doesn't work.
// When default escape is enabled if the core escape is called before
// any custom escaping is done the modifier_escape function is not
// found, so require_once straight away. Note this was hit on the basic
@@ -183,35 +193,6 @@ public static function &singleton() {
return self::$_singleton;
}
- /**
- * Executes & returns or displays the template results
- *
- * @param string $resource_name
- * @param string $cache_id
- * @param string $compile_id
- * @param bool $display
- *
- * @return bool|mixed|string
- *
- * @noinspection PhpDocMissingThrowsInspection
- * @noinspection PhpUnhandledExceptionInspection
- */
- public function fetch($resource_name, $cache_id = NULL, $compile_id = NULL, $display = FALSE) {
- if (preg_match('/^(\s+)?string:/', $resource_name)) {
- $old_security = $this->security;
- $this->security = TRUE;
- }
- try {
- $output = parent::fetch($resource_name, $cache_id, $compile_id, $display);
- }
- finally {
- if (isset($old_security)) {
- $this->security = $old_security;
- }
- }
- return $output;
- }
-
/**
* Handle smarty error in one off string.
*
diff --git a/CRM/Core/Smarty/plugins/block.crmButton.php b/CRM/Core/Smarty/plugins/block.crmButton.php
index 64543d595768..fbd6606329e7 100644
--- a/CRM/Core/Smarty/plugins/block.crmButton.php
+++ b/CRM/Core/Smarty/plugins/block.crmButton.php
@@ -24,33 +24,37 @@
* Contents of block.
* @param CRM_Core_Smarty $smarty
* The Smarty object.
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
*
- * @return string
+ * @return string|null
* The generated html.
*/
-function smarty_block_crmButton($params, $text, &$smarty) {
- // Generate url (pass 'html' param as false to avoid double-encode by htmlAttributes)
- if (empty($params['href'])) {
- $params['href'] = CRM_Utils_System::crmURL($params + ['h' => FALSE]);
- }
- // Always add class 'button' - fixme probably should be crm-button
- $params['class'] = empty($params['class']) ? 'button' : 'button ' . $params['class'];
- // Any FA icon works
- if (array_key_exists('icon', $params) && !$params['icon']) {
- // icon=0 should produce a button with no icon
- $iconMarkup = '';
- }
- else {
- $icon = $params['icon'] ?? 'fa-pencil';
- // Assume for now that all icons are Font Awesome v4.x but handle if it's
- // specified
- if (strpos($icon, 'fa-') !== 0) {
- $icon = "fa-$icon";
+function smarty_block_crmButton($params, $text, &$smarty, &$repeat) {
+ if (!$repeat) {
+ // Generate url (pass 'html' param as false to avoid double-encode by htmlAttributes)
+ if (empty($params['href'])) {
+ $params['href'] = CRM_Utils_System::crmURL($params + ['h' => FALSE]);
+ }
+ // Always add class 'button' - fixme probably should be crm-button
+ $params['class'] = empty($params['class']) ? 'button' : 'button ' . $params['class'];
+ // Any FA icon works
+ if (array_key_exists('icon', $params) && !$params['icon']) {
+ // icon=0 should produce a button with no icon
+ $iconMarkup = '';
+ }
+ else {
+ $icon = $params['icon'] ?? 'fa-pencil';
+ // Assume for now that all icons are Font Awesome v4.x but handle if it's
+ // specified
+ if (strpos($icon, 'fa-') !== 0) {
+ $icon = "fa-$icon";
+ }
+ $iconMarkup = " ";
}
- $iconMarkup = " ";
+ // All other params are treated as html attributes
+ CRM_Utils_Array::remove($params, 'icon', 'p', 'q', 'a', 'f', 'h', 'fb', 'fe');
+ $attributes = CRM_Utils_String::htmlAttributes($params);
+ return "$iconMarkup$text ";
}
- // All other params are treated as html attributes
- CRM_Utils_Array::remove($params, 'icon', 'p', 'q', 'a', 'f', 'h', 'fb', 'fe');
- $attributes = CRM_Utils_String::htmlAttributes($params);
- return "$iconMarkup$text ";
}
diff --git a/CRM/Core/Smarty/plugins/block.crmUpgradeSnapshot.php b/CRM/Core/Smarty/plugins/block.crmUpgradeSnapshot.php
index 9e95233751c7..44571c14ed27 100644
--- a/CRM/Core/Smarty/plugins/block.crmUpgradeSnapshot.php
+++ b/CRM/Core/Smarty/plugins/block.crmUpgradeSnapshot.php
@@ -32,11 +32,13 @@
* @param string|null $text
* The SELECT query which supplies the interesting data to be stored in the snapshot.
* @param CRM_Core_Smarty $smarty
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
* @return string|null
* @throws \CRM_Core_Exception
*/
-function smarty_block_crmUpgradeSnapshot($params, $text, &$smarty) {
- if ($text === NULL) {
+function smarty_block_crmUpgradeSnapshot($params, $text, &$smarty, &$repeat) {
+ if ($repeat || $text === NULL) {
return NULL;
}
diff --git a/CRM/Core/Smarty/plugins/block.edit.php b/CRM/Core/Smarty/plugins/block.edit.php
index d42fe44e0392..cb3d15479d59 100644
--- a/CRM/Core/Smarty/plugins/block.edit.php
+++ b/CRM/Core/Smarty/plugins/block.edit.php
@@ -30,11 +30,15 @@
* {edit} block contents from the template.
* @param CRM_Core_Smarty $smarty
* The Smarty object.
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
*
- * @return string
+ * @return string|null
* the string, translated by gettext
*/
-function smarty_block_edit($params, $text, &$smarty) {
- $action = $smarty->_tpl_vars['action'];
- return ($action & 3) ? $text : NULL;
+function smarty_block_edit($params, $text, &$smarty, &$repeat) {
+ if (!$repeat) {
+ $action = $smarty->get_template_vars()['action'];
+ return ($action & 3) ? $text : NULL;
+ }
}
diff --git a/CRM/Core/Smarty/plugins/block.htxt.php b/CRM/Core/Smarty/plugins/block.htxt.php
index cfd03732c13c..cc58bda7731a 100644
--- a/CRM/Core/Smarty/plugins/block.htxt.php
+++ b/CRM/Core/Smarty/plugins/block.htxt.php
@@ -26,16 +26,16 @@
* {ts} block contents from the template.
* @param CRM_Core_Smarty $smarty
* The Smarty object.
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
*
- * @return string
+ * @return string|null
* the string, translated by gettext
*/
-function smarty_block_htxt($params, $text, &$smarty) {
- if ($params['id'] == $smarty->_tpl_vars['id']) {
+function smarty_block_htxt($params, $text, $smarty, &$repeat) {
+ if (!$repeat && $params['id'] == $smarty->getTemplateVars('id')) {
$smarty->assign('override_help_text', !empty($params['override']));
return $text;
}
- else {
- return NULL;
- }
+ return NULL;
}
diff --git a/CRM/Core/Smarty/plugins/block.icon.php b/CRM/Core/Smarty/plugins/block.icon.php
index 97dbb6d55d80..84865c63d4ec 100644
--- a/CRM/Core/Smarty/plugins/block.icon.php
+++ b/CRM/Core/Smarty/plugins/block.icon.php
@@ -30,14 +30,19 @@
*
* @param $smarty
*
- * @return string
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
+ *
+ * @return string|null
*/
-function smarty_block_icon($params, $text, &$smarty) {
- $condition = array_key_exists('condition', $params) ? $params['condition'] : 1;
- $icon = $params['icon'] ?? 'fa-check';
- $dontPass = [
- 'condition' => 1,
- 'icon' => 1,
- ];
- return CRM_Core_Page::crmIcon($icon, $text, $condition, array_diff_key($params, $dontPass));
+function smarty_block_icon($params, $text, &$smarty, &$repeat) {
+ if (!$repeat) {
+ $condition = array_key_exists('condition', $params) ? $params['condition'] : 1;
+ $icon = $params['icon'] ?? 'fa-check';
+ $dontPass = [
+ 'condition' => 1,
+ 'icon' => 1,
+ ];
+ return CRM_Core_Page::crmIcon($icon, $text, $condition, array_diff_key($params, $dontPass));
+ }
}
diff --git a/CRM/Core/Smarty/plugins/block.localize.php b/CRM/Core/Smarty/plugins/block.localize.php
index 47e64fe6be3d..6b7f357d85ee 100644
--- a/CRM/Core/Smarty/plugins/block.localize.php
+++ b/CRM/Core/Smarty/plugins/block.localize.php
@@ -33,18 +33,19 @@
* @return string
* multilingualized query
*/
-function smarty_block_localize($params, $text, &$smarty, &$repeat) {
+function smarty_block_localize($params, $text, $smarty, &$repeat) {
if ($repeat) {
// For opening tag text is always null
return '';
}
-
- if (!array_key_exists('multilingual', $smarty->_tpl_vars) || !$smarty->_tpl_vars['multilingual']) {
+ $multiLingual = method_exists($smarty, 'get_template_vars') ? $smarty->get_template_vars('multilingual') : $smarty->getTemplateVars('multilingual');
+ if (!$multiLingual) {
return $text;
}
$lines = [];
- foreach ($smarty->_tpl_vars['locales'] as $locale) {
+ $locales = (array) (method_exists($smarty, 'get_template_vars') ? $smarty->get_template_vars('locales') : $smarty->getTemplateVars('locales'));
+ foreach ($locales as $locale) {
$line = $text;
if (isset($params['field'])) {
$fields = explode(',', $params['field']);
diff --git a/CRM/Core/Smarty/plugins/block.serialize.php b/CRM/Core/Smarty/plugins/block.serialize.php
deleted file mode 100644
index e716631050bf..000000000000
--- a/CRM/Core/Smarty/plugins/block.serialize.php
+++ /dev/null
@@ -1,37 +0,0 @@
-
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- */
-
-/**
- * Smarty block function providing serialization support
- *
- * See CRM_Core_I18n class documentation for details.
- *
- * @param array $params
- * Template call's parameters.
- * @param string $text
- * {serialize} block contents from the template.
- * @param CRM_Core_Smarty $smarty
- * The Smarty object.
- *
- * @return string
- * the string, translated by gettext
- */
-function smarty_block_serialize($params, $text, &$smarty) {
- return serialize($text);
-}
diff --git a/CRM/Core/Smarty/plugins/block.ts.php b/CRM/Core/Smarty/plugins/block.ts.php
index 785122d36e25..cb077675de66 100644
--- a/CRM/Core/Smarty/plugins/block.ts.php
+++ b/CRM/Core/Smarty/plugins/block.ts.php
@@ -29,13 +29,17 @@
* {ts} block contents from the template.
* @param CRM_Core_Smarty $smarty
* The Smarty object.
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
*
- * @return string
+ * @return string|null
* the string, translated by gettext
*/
-function smarty_block_ts($params, $text, &$smarty) {
- if (!isset($params['domain']) && $extensionKey = $smarty->get_template_vars('extensionKey')) {
- $params['domain'] = is_array($extensionKey) ? $extensionKey : [$extensionKey, NULL];
+function smarty_block_ts($params, $text, &$smarty, &$repeat) {
+ if (!$repeat) {
+ if (!isset($params['domain']) && $extensionKey = $smarty->get_template_vars('extensionKey')) {
+ $params['domain'] = is_array($extensionKey) ? $extensionKey : [$extensionKey, NULL];
+ }
+ return _ts($text, $params);
}
- return _ts($text, $params);
}
diff --git a/CRM/Core/Smarty/plugins/block.url.php b/CRM/Core/Smarty/plugins/block.url.php
index 71814af2a1b1..890d9d20b42e 100644
--- a/CRM/Core/Smarty/plugins/block.url.php
+++ b/CRM/Core/Smarty/plugins/block.url.php
@@ -34,10 +34,13 @@
* Contents of block.
* @param CRM_Core_Smarty $smarty
* The Smarty object.
+ * @param bool $repeat
+ * Repeat is true for the opening tag, false for the closing tag
+ *
* @return string
*/
-function smarty_block_url($params, $text, &$smarty) {
- if ($text === NULL) {
+function smarty_block_url($params, $text, &$smarty, &$repeat) {
+ if ($repeat || $text === NULL) {
return NULL;
}
diff --git a/CRM/Core/Smarty/plugins/function.help.php b/CRM/Core/Smarty/plugins/function.help.php
index 754d2ec401ed..a7010ef8edde 100644
--- a/CRM/Core/Smarty/plugins/function.help.php
+++ b/CRM/Core/Smarty/plugins/function.help.php
@@ -27,12 +27,12 @@
* the help html to be inserted
*/
function smarty_function_help($params, &$smarty) {
- if (!isset($params['id']) || !isset($smarty->_tpl_vars['config'])) {
+ if (!isset($params['id']) || !isset($smarty->get_template_vars()['config'])) {
return NULL;
}
- if (empty($params['file']) && isset($smarty->_tpl_vars['tplFile'])) {
- $params['file'] = $smarty->_tpl_vars['tplFile'];
+ if (empty($params['file']) && isset($smarty->get_template_vars()['tplFile'])) {
+ $params['file'] = $smarty->get_template_vars()['tplFile'];
}
elseif (empty($params['file'])) {
return NULL;
@@ -43,7 +43,6 @@ function smarty_function_help($params, &$smarty) {
if (empty($params['title'])) {
$vars = $smarty->get_template_vars();
- $smarty->assign('id', $params['id'] . '-title');
// The way this works is a bit bonkers. All the .hlp files are expecting an
// assign called $params (which is different from our php var here called
@@ -52,14 +51,16 @@ function smarty_function_help($params, &$smarty) {
// that we return at the bottom below). But right now when we fetch the
// file on the next line, there is no params. So it gives a notice. So
// let's assign something.
+ // We also need to assign the id for the title we are looking for, which
+ // will not be present in Smarty 3 otherwise.
// It's also awkward since the ONLY reason we're fetching the file
// now is to get the help section's title and we don't care about the rest
// of the file, but that is a bit of a separate issue.
- $temporary_vars = [];
+ $temporary_vars = ['id' => $params['id'] . '-title'];
if (!array_key_exists('params', $vars)) {
// In the unlikely event that params already exists, we don't want to
// overwrite it, so only do this if not already set.
- $temporary_vars = ['params' => []];
+ $temporary_vars += ['params' => []];
}
// Note fetchWith adds the temporary ones to the existing scope but then
// will reset, unsetting them if not already present before, which is what
diff --git a/CRM/Core/Smarty/plugins/modifier.smarty.php b/CRM/Core/Smarty/plugins/modifier.smarty.php
new file mode 100644
index 000000000000..000e87ecf3bb
--- /dev/null
+++ b/CRM/Core/Smarty/plugins/modifier.smarty.php
@@ -0,0 +1,45 @@
+assign_var` to
+ * `$smarty->assignVar()`
+ * 2) if someone adds the Smarty3 package onto their site and
+ * defines CIVICRM_SMARTY3_AUTOLOAD_PATH then Smarty3 will load from that
+ * location.
+ *
+ * Note that experimenting with `CIVICRM_SMARTY3_AUTOLOAD_PATH` will not
+ * go well if extensions are installed that have not run civix upgrade
+ * somewhat recently (ie have the old version of the hook_civicrm_config
+ * with reference to `$template =& CRM_Core_Smarty::singleton();`
+ */
+
+/**
+ * Fix for bug CRM-392. Not sure if this is the best fix or it will impact
+ * other similar PEAR packages. doubt it
+ */
+if (!class_exists('Smarty')) {
+ if (defined('CIVICRM_SMARTY3_AUTOLOAD_PATH')) {
+ // @todo - this is experimental but it allows someone to
+ // get Smarty3 to load instead of Smarty2 if set.
+ // It is likely the final Smarty3 solution will look
+ // different but this makes testing possible without re-inventing
+ // it each time we try...
+ require_once CIVICRM_SMARTY3_AUTOLOAD_PATH;
+ }
+ else {
+ require_once 'Smarty/Smarty.class.php';
+ }
+}
+
+/**
+ *
+ */
+class CRM_Core_SmartyCompatibility extends Smarty {
+
+ public function loadFilter($type, $name) {
+ if (method_exists(get_parent_class(), 'load_filter')) {
+ parent::load_filter($type, $name);
+ return;
+ }
+ parent::loadFilter($type, $name);
+ }
+
+ /**
+ * @deprecated
+ *
+ * @param string $type
+ * @param string $name
+ *
+ * @throws \SmartyException
+ */
+ public function load_filter($type, $name) {
+ if (method_exists(get_parent_class(), 'load_filter')) {
+ parent::load_filter($type, $name);
+ return;
+ }
+ parent::loadFilter($type, $name);
+ }
+
+ /**
+ * Registers modifier to be used in templates
+ *
+ * @deprecated
+ *
+ * @param string $modifier name of template modifier
+ * @param string $modifier_impl name of PHP function to register
+ */
+ public function register_modifier($modifier, $modifier_impl) {
+ if (method_exists(get_parent_class(), 'register_modifier')) {
+ parent::register_modifier($modifier, $modifier_impl);
+ return;
+ }
+ parent::registerPlugin('modifier', $modifier, $modifier_impl);
+ }
+
+ public function registerPlugin($type, $name, $callback, $cacheable = TRUE, $cache_attr = NULL) {
+ if (method_exists(get_parent_class(), 'registerPlugin')) {
+ parent::registerPlugin($type, $name, $callback, $cacheable = TRUE, $cache_attr = NULL);
+ return;
+ }
+ if ($type === 'modifier') {
+ parent::register_modifier($name, $callback);
+ }
+ }
+
+ /**
+ * Registers a resource to fetch a template
+ *
+ * @param string $type name of resource
+ * @param array $functions array of functions to handle resource
+ */
+ public function register_resource($type, $functions) {
+ if (method_exists(get_parent_class(), 'register_resource')) {
+ parent::register_resource($type, $functions);
+ return;
+ }
+ parent::registerResource($type, $functions);
+ }
+
+ /**
+ * Registers custom function to be used in templates
+ *
+ * @param string $function the name of the template function
+ * @param string $function_impl the name of the PHP function to register
+ * @param bool $cacheable
+ * @param null $cache_attrs
+ *
+ * @throws \SmartyException
+ */
+ public function register_function($function, $function_impl, $cacheable = TRUE, $cache_attrs = NULL) {
+ if (method_exists(get_parent_class(), 'register_function')) {
+ parent::register_function($function, $function_impl, $cacheable = TRUE, $cache_attrs = NULL);
+ return;
+ }
+ parent::registerPlugin('function', $function, $function, $cacheable, $cache_attrs);
+ }
+
+ /**
+ * Returns an array containing template variables
+ *
+ * @param string $name
+ *
+ * @return array
+ */
+ public function &get_template_vars($name = NULL) {
+ if (method_exists(get_parent_class(), 'get_template_vars')) {
+ return parent::get_template_vars($name);
+ }
+ $var = parent::getTemplateVars($name);
+ return $var;
+ }
+
+ /**
+ * Returns a single or all template variables
+ *
+ * @api Smarty::getTemplateVars()
+ * @link http://www.smarty.net/docs/en/api.get.template.vars.tpl
+ *
+ * @param string $varName variable name or NULL
+ * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $_ptr optional pointer to data object
+ * @param bool $searchParents include parent templates?
+ *
+ * @return mixed variable value or or array of variables
+ */
+ public function getTemplateVars($varName = NULL, Smarty_Internal_Data $_ptr = NULL, $searchParents = TRUE) {
+ if (method_exists(get_parent_class(), 'getTemplateVars')) {
+ return parent::getTemplateVars($varName . $_ptr, $searchParents);
+ }
+ return parent::get_template_vars($varName);
+ }
+
+ /**
+ * Generally Civi mis-uses this for perceived php4 conformance, avoid.
+ *
+ * @deprecated
+ * @param string $tpl_var
+ * @param mixed $value
+ *
+ * @return mixed|null|void
+ */
+ public function assign_by_ref($tpl_var, &$value) {
+ if (method_exists(get_parent_class(), 'assign_by_ref')) {
+ parent::assign_by_ref($tpl_var, $value);
+ return;
+ }
+ return parent::assignByRef($tpl_var, $value);
+ }
+
+ /**
+ * Generally Civi mis-uses this for perceived php4 conformance, avoid.
+ *
+ * @deprecated
+ * @param string $tpl_var
+ *
+ * @return mixed|null|void
+ */
+ public function clear_assign($tpl_var) {
+ if (method_exists(get_parent_class(), 'clear_assign')) {
+ parent::clear_assign($tpl_var);
+ return;
+ }
+ return parent::clearAssign($tpl_var);
+ }
+
+ /**
+ * Checks whether requested template exists.
+ *
+ * @param string $tpl_file
+ *
+ * @return bool
+ * @throws \SmartyException
+ */
+ public function template_exists($tpl_file) {
+ if (method_exists(get_parent_class(), 'template_exists')) {
+ return parent::template_exists($tpl_file);
+ }
+ return parent::templateExists($tpl_file);
+ }
+
+ /**
+ * Check if a template resource exists
+ *
+ * @param string $resource_name template name
+ *
+ * @return bool status
+ * @throws \SmartyException
+ */
+ public function templateExists($resource_name) {
+ if (method_exists(get_parent_class(), 'templateExists')) {
+ return parent::templateExists($resource_name);
+ }
+ return parent::template_exists($resource_name);
+ }
+
+}
diff --git a/CRM/Core/xml/Menu/Contact.xml b/CRM/Core/xml/Menu/Contact.xml
index ed81f2bc8273..5de7c2814364 100644
--- a/CRM/Core/xml/Menu/Contact.xml
+++ b/CRM/Core/xml/Menu/Contact.xml
@@ -176,12 +176,6 @@
Smart Groups
CRM_Contact_Page_View_ContactSmartGroup
- -
-
civicrm/contact/view/note
- cid=%%cid%%
- Notes
- CRM_Contact_Page_View_Note
-
-
civicrm/contact/view/tag
cid=%%cid%%
@@ -377,6 +371,7 @@
CRM_Contact_Form_Task_SMS
send SMS
+
-
civicrm/ajax/contactrelationships
CRM_Contact_Page_AJAX::getContactRelationships
diff --git a/CRM/Core/xml/Menu/Misc.xml b/CRM/Core/xml/Menu/Misc.xml
index 222e7ece8f20..396e13c6b429 100644
--- a/CRM/Core/xml/Menu/Misc.xml
+++ b/CRM/Core/xml/Menu/Misc.xml
@@ -286,4 +286,9 @@
CRM_Activity_Form_Activity
access CiviCRM
+ -
+
civicrm/note
+ CRM_Note_Form_Note
+ access CiviCRM
+
diff --git a/CRM/Custom/Form/Field.php b/CRM/Custom/Form/Field.php
index 9a8c2e3d7362..ece46e555556 100644
--- a/CRM/Custom/Form/Field.php
+++ b/CRM/Custom/Form/Field.php
@@ -58,10 +58,10 @@ class CRM_Custom_Form_Field extends CRM_Core_Form {
* @var array[]
*/
public static $_dataToHTML = [
- 'String' => ['Text', 'Select', 'Radio', 'CheckBox', 'Autocomplete-Select'],
- 'Int' => ['Text', 'Select', 'Radio'],
- 'Float' => ['Text', 'Select', 'Radio'],
- 'Money' => ['Text', 'Select', 'Radio'],
+ 'String' => ['Text', 'Select', 'Radio', 'CheckBox', 'Autocomplete-Select', 'Hidden'],
+ 'Int' => ['Text', 'Select', 'Radio', 'Hidden'],
+ 'Float' => ['Text', 'Select', 'Radio', 'Hidden'],
+ 'Money' => ['Text', 'Select', 'Radio', 'Hidden'],
'Memo' => ['TextArea', 'RichTextEditor'],
'Date' => ['Select Date'],
'Boolean' => ['Radio'],
diff --git a/CRM/Custom/Form/Group.php b/CRM/Custom/Form/Group.php
index 4f9baa454402..0c1dd26f6c24 100644
--- a/CRM/Custom/Form/Group.php
+++ b/CRM/Custom/Form/Group.php
@@ -18,61 +18,42 @@
/**
* form to process actions on the set aspect of Custom Data
*/
-class CRM_Custom_Form_Group extends CRM_Core_Form {
+class CRM_Custom_Form_Group extends CRM_Admin_Form {
/**
- * The set id saved to the session for an update.
- *
- * @var int
- */
- public $_id;
-
- /**
- * set is empty or not.
+ * Have any custom data records been saved yet?
+ * If not we can be more lenient about making changes.
*
* @var bool
*/
protected $_isGroupEmpty = TRUE;
/**
- * Array of existing subtypes set for a custom set.
- *
- * @var array
+ * Use APIv4 to load values.
+ * @var string
*/
- protected $_subtypes = [];
+ protected $retrieveMethod = 'api4';
/**
* Set variables up before form is built.
*
- *
* @return void
*/
public function preProcess() {
$this->preventAjaxSubmit();
- Civi::resources()->addScriptFile('civicrm', 'js/jquery/jquery.crmIconPicker.js');
+ parent::preProcess();
- // current set id
- $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
$this->setAction($this->_id ? CRM_Core_Action::UPDATE : CRM_Core_Action::ADD);
- if ($this->_id && CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_id, 'is_reserved', 'id')) {
- CRM_Core_Error::statusBounce("You cannot edit the settings of a reserved custom field-set.");
- }
-
if ($this->_id) {
- $title = CRM_Core_BAO_CustomGroup::getTitle($this->_id);
- $this->setTitle(ts('Edit %1', [1 => $title]));
- $params = ['id' => $this->_id];
- CRM_Core_BAO_CustomGroup::retrieve($params, $this->_defaults);
-
- $subExtends = $this->_defaults['extends_entity_column_value'] ?? NULL;
- if (!empty($subExtends)) {
- $this->_subtypes = explode(CRM_Core_DAO::VALUE_SEPARATOR, substr($subExtends, 1, -1));
+ if ($this->_values['is_reserved']) {
+ CRM_Core_Error::statusBounce("You cannot edit the settings of a reserved custom field-set.");
}
+ $this->_isGroupEmpty = CRM_Core_BAO_CustomGroup::isGroupEmpty($this->_id);
+ $this->setTitle(ts('Edit %1', [1 => $this->_values['title']]));
}
- else {
- $this->setTitle(ts('New Custom Field Set'));
- }
+ // Used by I18n/Dialog
+ $this->assign('gid', $this->_id);
}
/**
@@ -103,26 +84,6 @@ public static function formRule($fields, $files, $self) {
$errors['title'] = ts('Custom group \'%1\' already exists in Database.', [1 => $title]);
}
- if (!empty($fields['extends'][1])) {
- if (in_array('', $fields['extends'][1]) && count($fields['extends'][1]) > 1) {
- $errors['extends'] = ts("Cannot combine other option with 'Any'.");
- }
- }
-
- if (empty($fields['extends'][0])) {
- $errors['extends'] = ts("You need to select the type of record that this set of custom fields is applicable for.");
- }
-
- $extends = ['Activity', 'Relationship', 'Group', 'Contribution', 'Membership', 'Event', 'Participant'];
- if (in_array($fields['extends'][0], $extends) && $fields['style'] == 'Tab') {
- $errors['style'] = ts("Display Style should be Inline for this Class");
- $self->assign('showStyle', TRUE);
- }
-
- if (!empty($fields['is_multiple'])) {
- $self->assign('showMultiple', TRUE);
- }
-
if (empty($fields['is_multiple']) && $fields['style'] == 'Tab with table') {
$errors['style'] = ts("Display Style 'Tab with table' is only supported for multiple-record custom field sets.");
}
@@ -160,74 +121,67 @@ public function addRules() {
*/
public function buildQuickForm() {
$this->applyFilter('__ALL__', 'trim');
-
$attributes = CRM_Core_DAO::getAttribute('CRM_Core_DAO_CustomGroup');
- //title
- $this->add('text', 'title', ts('Set Name'), $attributes['title'], TRUE);
+ // This form is largely driven by a trio of related fields:
+ // 1. `extends` - entity name e.g. Activity, Contact, (plus contact types pretending to be entities e.g. Individual, Organization)
+ // 2. `extends_entity_column_id` - "category" of sub_type (usually null as most entities only have one category of sub_type)
+ // 3. `extends_entity_column_value` - sub_type value(s) e.g. options from `activity_type_id`
+ // Most entities have no options for field 2. For them, it will be hidden from the form, and
+ // the pair of fields 1 & 3 will act like a normal chain-select, (value of 1 controls the options shown in 3).
+ // For extra-complex entities like Participant, fields 1 + 2 will act like a compound key to
+ // control the options in field 3.
+
+ // Get options for the `extends` field.
+ $extendsOptions = CRM_Core_BAO_CustomGroup::getCustomGroupExtendsOptions();
+ // Sort by label
+ $labels = array_column($extendsOptions, 'label');
+ array_multisort($labels, SORT_NATURAL, $extendsOptions);
+
+ // Get options for `extends_entity_column_id` (rarely used except for participants)
+ // Format as an array keyed by entity to match with 'extends' values, e.g.
+ // [
+ // 'Participant' => [['id' => 'ParticipantRole', 'text' => 'Participants (Role)'], ...]],
+ // ]
+ $entityColumnIdOptions = [];
+ foreach (CRM_Core_BAO_CustomGroup::getExtendsEntityColumnIdOptions() as $idOption) {
+ $entityColumnIdOptions[$idOption['extends']][] = [
+ 'id' => $idOption['id'],
+ 'text' => $idOption['label'],
+ ];
+ }
- //Fix for code alignment, CRM-3058
- $contactTypes = array_merge(['Contact'], CRM_Contact_BAO_ContactType::basicTypes());
- $this->assign('contactTypes', json_encode($contactTypes));
+ $extendsValue = $this->_values['extends'] ?? NULL;
+ $initialEntityColumnIdOptions = $entityColumnIdOptions[$extendsValue] ?? [];
+
+ $initialEntityColumnValueOptions = [];
+ if ($extendsValue) {
+ $initialEntityColumnValueOptions = civicrm_api4('CustomGroup', 'getFields', [
+ 'where' => [['name', '=', 'extends_entity_column_value']],
+ 'action' => 'create',
+ 'loadOptions' => ['id', 'label'],
+ 'values' => $this->_values,
+ ], 0)['options'];
+ }
- $sel1 = ["" => ts("- select -")] + CRM_Core_SelectValues::customGroupExtends();
- ksort($sel1);
- $sel2 = CRM_Core_BAO_CustomGroup::getSubTypes();
+ // Assign data for use by js chain-selects
+ $this->assign('entityColumnIdOptions', $entityColumnIdOptions);
+ // List of entities that allow `is_multiple`
+ $this->assign('allowMultiple', array_column($extendsOptions, 'is_multiple', 'id'));
+ // Used by warnDataLoss
+ $this->assign('defaultSubtypes', $this->_values['extends_entity_column_value'] ?? []);
+ // Used to initially hide selects with no options
+ $this->assign('emptyEntityColumnId', empty($initialEntityColumnIdOptions));
+ $this->assign('emptyEntityColumnValue', empty($initialEntityColumnValueOptions));
+
+ // Add form fields
+ $this->add('text', 'title', ts('Set Name'), $attributes['title'], TRUE);
- foreach ($sel2 as $main => $sub) {
- if (!empty($sel2[$main])) {
- $sel2[$main] = [
- '' => ts("- Any -"),
- ] + $sel2[$main];
- }
- }
+ $this->add('select2', 'extends', ts('Used For'), $extendsOptions, TRUE, ['placeholder' => ts('Select')]);
- $sel = &$this->add('hierselect',
- 'extends',
- ts('Used For'),
- [
- 'name' => 'extends[0]',
- 'style' => 'vertical-align: top;',
- ],
- TRUE
- );
- $sel->setOptions([$sel1, $sel2]);
- if (is_a($sel->_elements[1], 'HTML_QuickForm_select')) {
- // make second selector a multi-select -
- $sel->_elements[1]->setMultiple(TRUE);
- $sel->_elements[1]->setSize(5);
- }
- if ($this->_action == CRM_Core_Action::UPDATE) {
- $subName = $this->_defaults['extends_entity_column_id'] ?? NULL;
- if ($this->_defaults['extends'] == 'Participant') {
- if ($subName == 1) {
- $this->_defaults['extends'] = 'ParticipantRole';
- }
- elseif ($subName == 2) {
- $this->_defaults['extends'] = 'ParticipantEventName';
- }
- elseif ($subName == 3) {
- $this->_defaults['extends'] = 'ParticipantEventType';
- }
- }
+ $this->add('select2', 'extends_entity_column_id', ts('Type'), $initialEntityColumnIdOptions, FALSE, ['placeholder' => ts('Any')]);
- //allow to edit settings if custom set is empty CRM-5258
- $this->_isGroupEmpty = CRM_Core_BAO_CustomGroup::isGroupEmpty($this->_id);
- if (!$this->_isGroupEmpty) {
- if (!empty($this->_subtypes)) {
- // we want to allow adding / updating subtypes for this case,
- // and therefore freeze the first selector only.
- $sel->_elements[0]->freeze();
- }
- else {
- // freeze both the selectors
- $sel->freeze();
- }
- }
- $this->assign('isCustomGroupEmpty', $this->_isGroupEmpty);
- $this->assign('gid', $this->_id);
- }
- $this->assign('defaultSubtypes', json_encode($this->_subtypes));
+ $this->add('select2', 'extends_entity_column_value', ts('Sub Type'), $initialEntityColumnValueOptions, FALSE, ['multiple' => TRUE, 'placeholder' => ts('Any')]);
// help text
$this->add('wysiwyg', 'help_pre', ts('Pre-form Help'), $attributes['help_pre']);
@@ -254,26 +208,21 @@ public function buildQuickForm() {
//Is this set visible on public pages?
$this->addElement('advcheckbox', 'is_public', ts('Is this Custom Data Set public?'));
- // does this set have multiple record?
- $multiple = $this->addElement('advcheckbox', 'is_multiple',
+ $this->addElement('advcheckbox', 'is_multiple',
ts('Does this Custom Field Set allow multiple records?'), NULL);
- // $min_multiple = $this->add('text', 'min_multiple', ts('Minimum number of multiple records'), $attributes['min_multiple'] );
- // $this->addRule('min_multiple', ts('is a numeric field') , 'numeric');
-
- $max_multiple = $this->add('number', 'max_multiple', ts('Maximum number of multiple records'), $attributes['max_multiple']);
+ $this->add('number', 'max_multiple', ts('Maximum number of multiple records'), $attributes['max_multiple']);
$this->addRule('max_multiple', ts('is a numeric field'), 'numeric');
- //allow to edit settings if custom set is empty CRM-5258
- $this->assign('isGroupEmpty', $this->_isGroupEmpty);
+ // Once data exists, certain options cannot be changed
if (!$this->_isGroupEmpty) {
- $multiple->freeze();
- //$min_multiple->freeze();
- $max_multiple->freeze();
+ $this->getElement('extends')->freeze();
+ $this->getElement('extends_entity_column_id')->freeze();
+ $this->getElement('is_multiple')->freeze();
+ // Don't allow max to be lowered if data already exists
+ $this->getElement('max_multiple')->setAttribute('min', $this->_values['max_multiple'] ?? '0');
}
- $this->assign('showStyle', FALSE);
- $this->assign('showMultiple', FALSE);
$buttons = [
[
'type' => 'next',
@@ -286,77 +235,41 @@ public function buildQuickForm() {
'name' => ts('Cancel'),
],
];
- if (!$this->_isGroupEmpty && !empty($this->_subtypes)) {
+ if (!$this->_isGroupEmpty && !empty($this->_values['extends_entity_column_value'])) {
$buttons[0]['class'] = 'crm-warnDataLoss';
}
$this->addButtons($buttons);
}
/**
- * Set default values for the form. Note that in edit/view mode
- * the default values are retrieved from the database
- *
- *
+ * Set default values for the form.
* @return array
- * array of default values
*/
- public function setDefaultValues() {
- $defaults = &$this->_defaults;
- $this->assign('showMaxMultiple', TRUE);
+ public function setDefaultValues(): array {
+ $defaults = &$this->_values;
if ($this->_action == CRM_Core_Action::ADD) {
$defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_CustomGroup');
- $defaults['is_multiple'] = $defaults['min_multiple'] = 0;
$defaults['is_active'] = $defaults['is_public'] = $defaults['collapse_adv_display'] = 1;
$defaults['style'] = 'Inline';
}
- elseif (empty($defaults['max_multiple']) && !$this->_isGroupEmpty) {
- $this->assign('showMaxMultiple', FALSE);
- }
-
- if (($this->_action & CRM_Core_Action::UPDATE) && !empty($defaults['is_multiple'])) {
- $defaults['collapse_display'] = 0;
- }
-
- if (isset($defaults['extends'])) {
- $extends = $defaults['extends'];
- unset($defaults['extends']);
-
- $defaults['extends'][0] = $extends;
-
- if (!empty($this->_subtypes)) {
- $defaults['extends'][1] = $this->_subtypes;
- }
- else {
- $defaults['extends'][1] = [0 => ''];
- }
-
- if ($extends == 'Relationship' && !empty($this->_subtypes)) {
- $relationshipDefaults = [];
- foreach ($defaults['extends'][1] as $donCare => $rel_type_id) {
- $relationshipDefaults[] = $rel_type_id;
- }
-
- $defaults['extends'][1] = $relationshipDefaults;
- }
- }
-
return $defaults;
}
/**
- * Process the form.
- *
- *
* @return void
*/
public function postProcess() {
// get the submitted form values.
$params = $this->controller->exportValues('Group');
+ if (!empty($params['extends_entity_column_value']) && is_string($params['extends_entity_column_value'])) {
+ // Because select2
+ $params['extends_entity_column_value'] = explode(',', $params['extends_entity_column_value']);
+ }
$params['overrideFKConstraint'] = 0;
if ($this->_action & CRM_Core_Action::UPDATE) {
$params['id'] = $this->_id;
- if ($this->_defaults['extends'][0] != $params['extends'][0]) {
+ if ($this->_values['extends'] != $params['extends']) {
$params['overrideFKConstraint'] = 1;
}
@@ -423,11 +336,14 @@ public function postProcess() {
}
}
+ public function getDefaultEntity(): string {
+ return 'CustomGroup';
+ }
+
/**
- * Return a formatted list of relationship labels.
+ * Function that's only ever called by another deprecated function.
*
- * @return array
- * Array (int $id => string $label).
+ * @deprecated
*/
public static function getRelationshipTypes() {
// Note: We include inactive reltypes because we don't want to break custom-data
diff --git a/CRM/Custom/Page/Field.php b/CRM/Custom/Page/Field.php
index 8d6b6aefb653..188e48ed4d14 100644
--- a/CRM/Custom/Page/Field.php
+++ b/CRM/Custom/Page/Field.php
@@ -133,27 +133,9 @@ public function browse() {
$action -= CRM_Core_Action::DISABLE;
}
- switch ($customFieldBAO->data_type) {
- case "String":
- case "Int":
- case "Float":
- case "Money":
- // if Multi Select field is selected in custom field
- if ($customFieldBAO->html_type == 'Text') {
- $action -= CRM_Core_Action::BROWSE;
- }
- break;
-
- case "ContactReference":
- case "Memo":
- case "Date":
- case "Boolean":
- case "StateProvince":
- case "Country":
- case "File":
- case "Link":
- $action -= CRM_Core_Action::BROWSE;
- break;
+ // Remove link to edit option group if there isn't one
+ if (!$customFieldBAO->option_group_id) {
+ $action -= CRM_Core_Action::BROWSE;
}
$customFieldDataType = array_column(CRM_Core_BAO_CustomField::dataType(), 'label', 'id');
diff --git a/CRM/Dedupe/MergeHandler.php b/CRM/Dedupe/MergeHandler.php
index 79c296fdccb6..cf64201bcdb4 100644
--- a/CRM/Dedupe/MergeHandler.php
+++ b/CRM/Dedupe/MergeHandler.php
@@ -398,7 +398,7 @@ public function mergeLocations(): void {
foreach ($block as $blkCount => $values) {
$otherBlockId = $migrationInfo['other_details']['location_blocks'][$name][$blkCount]['id'] ?? NULL;
- $mainBlockId = CRM_Utils_Array::value('mainContactBlockId', $migrationInfo['location_blocks'][$name][$blkCount], 0);
+ $mainBlockId = $migrationInfo['location_blocks'][$name][$blkCount]['mainContactBlockId'] ?? 0;
if (!$otherBlockId) {
continue;
}
diff --git a/CRM/Event/BAO/Event.php b/CRM/Event/BAO/Event.php
index 9b905aebfc68..6f843c7742c0 100644
--- a/CRM/Event/BAO/Event.php
+++ b/CRM/Event/BAO/Event.php
@@ -1161,8 +1161,6 @@ public static function sendMail($contactID, $values, $participantId, $isTest = F
'email' => $notifyEmail,
'confirm_email_text' => $values['event']['confirm_email_text'] ?? NULL,
'isShowLocation' => $values['event']['is_show_location'] ?? NULL,
- // The concept of contributeMode is deprecated.
- 'contributeMode' => $template->_tpl_vars['contributeMode'] ?? NULL,
'customPre' => $profilePre[0],
'customPre_grouptitle' => empty($profilePre[1]) ? NULL : [CRM_Core_BAO_UFGroup::getFrontEndTitle((int) $preProfileID)],
'customPost' => $profilePost[0],
@@ -1203,8 +1201,6 @@ public static function sendMail($contactID, $values, $participantId, $isTest = F
$displayAddress = $values['address'] ?? NULL;
if ($displayAddress) {
$sendTemplateParams['tplParams']['address'] = $displayAddress;
- // The concept of contributeMode is deprecated.
- $sendTemplateParams['tplParams']['contributeMode'] = NULL;
}
// set lineItem details
@@ -2023,7 +2019,7 @@ public static function checkRegistration($params) {
$participant = new CRM_Event_DAO_Participant();
$participant->copyValues($params);
- $participant->is_test = CRM_Utils_Array::value('is_test', $params, 0);
+ $participant->is_test = $params['is_test'] ?? 0;
$participant->selectAdd();
$participant->selectAdd('status_id');
if ($participant->find(TRUE) && array_key_exists($participant->status_id, $statusTypes)) {
diff --git a/CRM/Event/BAO/Participant.php b/CRM/Event/BAO/Participant.php
index 64768f27e0ff..e0946b03da3d 100644
--- a/CRM/Event/BAO/Participant.php
+++ b/CRM/Event/BAO/Participant.php
@@ -269,8 +269,8 @@ public static function create(&$params) {
);
}
if (CRM_Core_Permission::check('delete in CiviEvent')) {
- $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/participant',
- "action=delete&reset=1&id={$participant->id}&cid={$participant->contact_id}&context=home"
+ $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/participant/delete',
+ "reset=1&id={$participant->id}"
);
}
@@ -546,7 +546,7 @@ public static function priceSetOptionsCount(
if ($lineItem->html_type == 'Text') {
$count *= $lineItem->qty;
}
- $optionsCount[$lineItem->valueId] = $count + CRM_Utils_Array::value($lineItem->valueId, $optionsCount, 0);
+ $optionsCount[$lineItem->valueId] = $count + ($optionsCount[$lineItem->valueId] ?? 0);
}
return $optionsCount;
@@ -1744,8 +1744,8 @@ public static function addActivityForSelection($participantId, $activityType) {
$contactId = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Participant', $participantId, 'contact_id');
$date = CRM_Utils_Date::currentDBDate();
- $event = CRM_Event_BAO_Event::getEvents(0, $eventId);
- $subject = sprintf("Registration selections changed for %s", CRM_Utils_Array::value($eventId, $event));
+ $title = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $eventId, 'title');
+ $subject = ts('Registration selections changed for %1', [1 => $title]);
// activity params
$activityParams = [
diff --git a/CRM/Event/BAO/ParticipantStatusType.php b/CRM/Event/BAO/ParticipantStatusType.php
index 7176dcc48b9e..7632f634e707 100644
--- a/CRM/Event/BAO/ParticipantStatusType.php
+++ b/CRM/Event/BAO/ParticipantStatusType.php
@@ -17,33 +17,23 @@
class CRM_Event_BAO_ParticipantStatusType extends CRM_Event_DAO_ParticipantStatusType {
/**
+ * @deprecated
* @param array $params
*
* @return self|null
*/
public static function add(&$params) {
- if (empty($params)) {
- return NULL;
- }
- $dao = new CRM_Event_DAO_ParticipantStatusType();
- $dao->copyValues($params);
- return $dao->save();
+ return self::writeRecord($params);
}
/**
+ * @deprecated
* @param array $params
*
* @return self|null
*/
- public static function &create(&$params) {
- $transaction = new CRM_Core_Transaction();
- $statusType = self::add($params);
- if (is_a($statusType, 'CRM_Core_Error')) {
- $transaction->rollback();
- return $statusType;
- }
- $transaction->commit();
- return $statusType;
+ public static function create(&$params) {
+ return self::writeRecord($params);
}
/**
diff --git a/CRM/Event/DAO/Participant.php b/CRM/Event/DAO/Participant.php
index dee37a6c534d..62f514a41b97 100644
--- a/CRM/Event/DAO/Participant.php
+++ b/CRM/Event/DAO/Participant.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Event/Participant.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3faebf0fa49dd7b3bf527bd082dd1fb7)
+ * (GenCodeChecksum:54acecd8443b824933d1cae2e77b2f8e)
*/
/**
@@ -47,7 +47,7 @@ class CRM_Event_DAO_Participant extends CRM_Core_DAO {
'add' => 'civicrm/participant/add?action=add&context=standalone&reset=1',
'view' => 'civicrm/contact/view/participant?id=[id]&cid=[contact_id]&action=view&reset=1',
'update' => 'civicrm/contact/view/participant?id=[id]&cid=[contact_id]&action=update&reset=1',
- 'delete' => 'civicrm/contact/view/participant?id=[id]&cid=[contact_id]&action=delete&reset=1',
+ 'delete' => 'civicrm/participant/delete?id=[id]&reset=1',
];
/**
diff --git a/CRM/Event/Form/EventFees.php b/CRM/Event/Form/EventFees.php
index 5ef84b3c581c..b0601f014b7b 100644
--- a/CRM/Event/Form/EventFees.php
+++ b/CRM/Event/Form/EventFees.php
@@ -37,9 +37,6 @@ public static function preProcess(&$form) {
$form->_pId = CRM_Utils_Request::retrieve('participantId', 'Positive', $form);
$form->_discountId = CRM_Utils_Request::retrieve('discountId', 'Positive', $form);
- // @todo - stop setting this, call the function, as appropriate. This is in a weird place.
- $form->_fromEmails = CRM_Event_BAO_Event::getFromEmailIds($form->_eventId);
-
//CRM-6907 set event specific currency.
if ($form->_eventId &&
($currency = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $form->_eventId, 'currency'))
@@ -64,10 +61,10 @@ public static function setDefaultValues(&$form) {
$details = [];
CRM_Core_DAO::commonRetrieveAll('CRM_Event_DAO_Event', 'id', $form->_eventId, $details, $returnProperities);
if (!empty($details[$form->_eventId]['financial_type_id'])) {
- $defaults[$form->_pId]['financial_type_id'] = $details[$form->_eventId]['financial_type_id'];
+ $defaults['financial_type_id'] = $details[$form->_eventId]['financial_type_id'];
}
if (!empty($details[$form->_eventId]['confirm_email_text'])) {
- $defaults[$form->_pId]['receipt_text'] = $details[$form->_eventId]['confirm_email_text'];
+ $defaults['receipt_text'] = $details[$form->_eventId]['confirm_email_text'];
}
}
@@ -76,6 +73,8 @@ public static function setDefaultValues(&$form) {
$params = ['id' => $form->_pId];
CRM_Event_BAO_Participant::getValues($params, $defaults, $ids);
+ $defaults += $defaults[$form->_pId];
+ unset($defaults[$form->_pId]);
if ($form->_action == CRM_Core_Action::UPDATE) {
$discounts = [];
if (!empty($form->_values['discount'])) {
@@ -85,54 +84,54 @@ public static function setDefaultValues(&$form) {
}
}
- if ($form->_discountId && !empty($discounts[$defaults[$form->_pId]['discount_id']])) {
- $form->assign('discount', $discounts[$defaults[$form->_pId]['discount_id']]);
+ if ($form->_discountId && !empty($discounts[$defaults['discount_id']])) {
+ $form->assign('discount', $discounts[$defaults['discount_id']]);
}
- $form->assign('fee_amount', CRM_Utils_Array::value('fee_amount', $defaults[$form->_pId]));
- $form->assign('fee_level', CRM_Utils_Array::value('fee_level', $defaults[$form->_pId]));
+ $form->assign('fee_amount', CRM_Utils_Array::value('fee_amount', $defaults));
+ $form->assign('fee_level', CRM_Utils_Array::value('fee_level', $defaults));
}
- $defaults[$form->_pId]['send_receipt'] = 0;
+ $defaults['send_receipt'] = 0;
}
else {
- $defaults[$form->_pId]['send_receipt'] = (strtotime(CRM_Utils_Array::value('start_date', $details[$form->_eventId])) >= time()) ? 1 : 0;
- $defaults[$form->_pId]['receive_date'] = date('Y-m-d H:i:s');
+ $defaults['send_receipt'] = (strtotime(CRM_Utils_Array::value('start_date', $details[$form->_eventId])) >= time()) ? 1 : 0;
+ $defaults['receive_date'] = date('Y-m-d H:i:s');
}
//CRM-11601 we should keep the record contribution
//true by default while adding participant
if ($form->_action == CRM_Core_Action::ADD && !$form->_mode && $form->_isPaidEvent) {
- $defaults[$form->_pId]['record_contribution'] = 1;
+ $defaults['record_contribution'] = 1;
}
//CRM-13420
if (empty($defaults['payment_instrument_id'])) {
- $defaults[$form->_pId]['payment_instrument_id'] = key(CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1'));
+ $defaults['payment_instrument_id'] = key(CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1'));
}
if ($form->_mode) {
$config = CRM_Core_Config::singleton();
// set default country from config if no country set
- if (empty($defaults[$form->_pId]["billing_country_id-{$form->_bltID}"])) {
- $defaults[$form->_pId]["billing_country_id-{$form->_bltID}"] = $config->defaultContactCountry;
+ if (empty($defaults["billing_country_id-{$form->_bltID}"])) {
+ $defaults["billing_country_id-{$form->_bltID}"] = $config->defaultContactCountry;
}
if (empty($defaults["billing_state_province_id-{$form->_bltID}"])) {
- $defaults[$form->_pId]["billing_state_province_id-{$form->_bltID}"] = $config->defaultContactStateProvince;
+ $defaults["billing_state_province_id-{$form->_bltID}"] = $config->defaultContactStateProvince;
}
$billingDefaults = $form->getProfileDefaults('Billing', $form->_contactId);
- $defaults[$form->_pId] = array_merge($defaults[$form->_pId], $billingDefaults);
+ $defaults = array_merge($defaults, $billingDefaults);
}
// if user has selected discount use that to set default
if (isset($form->_discountId)) {
- $defaults[$form->_pId]['discount_id'] = $form->_discountId;
+ $defaults['discount_id'] = $form->_discountId;
//hack to set defaults for already selected discount value
if ($form->_action == CRM_Core_Action::UPDATE && !$form->_originalDiscountId) {
- $form->_originalDiscountId = $defaults[$form->_pId]['discount_id'];
+ $form->_originalDiscountId = $defaults['discount_id'];
if ($form->_originalDiscountId) {
- $defaults[$form->_pId]['discount_id'] = $form->_originalDiscountId;
+ $defaults['discount_id'] = $form->_originalDiscountId;
}
}
$discountId = $form->_discountId;
@@ -150,7 +149,7 @@ public static function setDefaultValues(&$form) {
if (($form->_action == CRM_Core_Action::ADD) && $form->_eventId && $discountId) {
// this case is for add mode, where we show discount automatically
- $defaults[$form->_pId]['discount_id'] = $discountId;
+ $defaults['discount_id'] = $discountId;
}
if ($priceSetId) {
@@ -165,7 +164,7 @@ public static function setDefaultValues(&$form) {
)) {
$priceSetValues = self::setDefaultPriceSet($form->_pId, $form->_eventId);
if (!empty($priceSetValues)) {
- $defaults[$form->_pId] = array_merge($defaults[$form->_pId], $priceSetValues);
+ $defaults = array_merge($defaults, $priceSetValues);
}
}
@@ -178,33 +177,33 @@ public static function setDefaultValues(&$form) {
}
if ($val['html_type'] == 'CheckBox') {
- $defaults[$form->_pId]["price_{$key}"][$keys] = 1;
+ $defaults["price_{$key}"][$keys] = 1;
}
else {
- $defaults[$form->_pId]["price_{$key}"] = $keys;
+ $defaults["price_{$key}"] = $keys;
}
}
}
}
}
- $form->assign('totalAmount', CRM_Utils_Array::value('fee_amount', $defaults[$form->_pId]));
+ $form->assign('totalAmount', CRM_Utils_Array::value('fee_amount', $defaults));
if ($form->_action == CRM_Core_Action::UPDATE) {
- $fee_level = $defaults[$form->_pId]['fee_level'];
+ $fee_level = $defaults['fee_level'];
CRM_Event_BAO_Participant::fixEventLevel($fee_level);
$form->assign('fee_level', $fee_level);
- $form->assign('fee_amount', CRM_Utils_Array::value('fee_amount', $defaults[$form->_pId]));
+ $form->assign('fee_amount', CRM_Utils_Array::value('fee_amount', $defaults));
}
}
//CRM-4453
- if (!empty($defaults[$form->_pId]['participant_fee_currency'])) {
- $form->assign('fee_currency', $defaults[$form->_pId]['participant_fee_currency']);
+ if (!empty($defaults['participant_fee_currency'])) {
+ $form->assign('fee_currency', $defaults['participant_fee_currency']);
}
// CRM-4395
if ($contriId = $form->get('onlinePendingContributionId')) {
- $defaults[$form->_pId]['record_contribution'] = 1;
+ $defaults['record_contribution'] = 1;
$contribution = new CRM_Contribute_DAO_Contribution();
$contribution->id = $contriId;
$contribution->find(TRUE);
@@ -215,10 +214,10 @@ public static function setDefaultValues(&$form) {
'receive_date',
'total_amount',
] as $f) {
- $defaults[$form->_pId][$f] = $contribution->$f;
+ $defaults[$f] = $contribution->$f;
}
}
- return $defaults[$form->_pId];
+ return $defaults;
}
/**
diff --git a/CRM/Event/Form/EventFormTrait.php b/CRM/Event/Form/EventFormTrait.php
new file mode 100644
index 000000000000..442cf5619a4f
--- /dev/null
+++ b/CRM/Event/Form/EventFormTrait.php
@@ -0,0 +1,95 @@
+isDefined('Event')) {
+ return $this->lookup('Event', $fieldName);
+ }
+ $id = $this->getEventID();
+ if ($id) {
+ $this->define('Event', 'Event', ['id' => $id]);
+ return $this->lookup('Event', $fieldName);
+ }
+ return NULL;
+ }
+
+ /**
+ * Get the selected Event ID.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ * @noinspection PhpDocMissingThrowsInspection
+ */
+ public function getEventID(): ?int {
+ throw new CRM_Core_Exception('`getEventID` must be implemented');
+ }
+
+ /**
+ * Get id of participant being acted on.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ */
+ public function getParticipantID(): ?int {
+ throw new CRM_Core_Exception('`getParticipantID` must be implemented');
+ }
+
+ /**
+ * Get a value from the participant being acted on.
+ *
+ * All values returned in apiv4 format. Escaping may be required.
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @param string $fieldName
+ *
+ * @return mixed
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function getParticipantValue(string $fieldName) {
+ if ($this->isDefined('Participant')) {
+ return $this->lookup('Participant', $fieldName);
+ }
+ $id = $this->getParticipantID();
+ if ($id) {
+ $this->define('Participant', 'Participant', ['id' => $id]);
+ return $this->lookup('Participant', $fieldName);
+ }
+ return NULL;
+ }
+
+}
diff --git a/CRM/Event/Form/ManageEvent.php b/CRM/Event/Form/ManageEvent.php
index f496bdc6704a..0bd71043f425 100644
--- a/CRM/Event/Form/ManageEvent.php
+++ b/CRM/Event/Form/ManageEvent.php
@@ -177,6 +177,9 @@ public function preProcess() {
if (CRM_Core_Permission::check($checkPermission) || !empty($ufCreate) || !empty($ufEdit)) {
$this->assign('perm', TRUE);
}
+ else {
+ $this->assign('perm', FALSE);
+ }
// also set up tabs
CRM_Event_Form_ManageEvent_TabHeader::build($this);
@@ -269,12 +272,6 @@ public function buildQuickForm() {
'name' => ts('Save'),
'isDefault' => TRUE,
],
- [
- 'type' => 'upload',
- 'name' => ts('Save and Done'),
- 'spacing' => ' ',
- 'subName' => 'done',
- ],
[
'type' => 'cancel',
'name' => ts('Cancel'),
diff --git a/CRM/Event/Form/ManageEvent/EventInfo.php b/CRM/Event/Form/ManageEvent/EventInfo.php
index 9743f45c4566..0fd442b025dc 100644
--- a/CRM/Event/Form/ManageEvent/EventInfo.php
+++ b/CRM/Event/Form/ManageEvent/EventInfo.php
@@ -217,12 +217,12 @@ public function postProcess() {
//format params
$params['start_date'] = $params['start_date'] ?? NULL;
$params['end_date'] = $params['end_date'] ?? NULL;
- $params['has_waitlist'] = CRM_Utils_Array::value('has_waitlist', $params, FALSE);
- $params['is_map'] = CRM_Utils_Array::value('is_map', $params, FALSE);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $params['is_public'] = CRM_Utils_Array::value('is_public', $params, FALSE);
- $params['is_share'] = CRM_Utils_Array::value('is_share', $params, FALSE);
- $params['default_role_id'] = CRM_Utils_Array::value('default_role_id', $params, FALSE);
+ $params['has_waitlist'] = $params['has_waitlist'] ?? FALSE;
+ $params['is_map'] = $params['is_map'] ?? FALSE;
+ $params['is_active'] = $params['is_active'] ?? FALSE;
+ $params['is_public'] = $params['is_public'] ?? FALSE;
+ $params['is_share'] = $params['is_share'] ?? FALSE;
+ $params['default_role_id'] = $params['default_role_id'] ?? FALSE;
$params['id'] = $this->_id;
//merge params with defaults from templates
@@ -244,22 +244,11 @@ public function postProcess() {
}
$this->set('id', $event->id);
-
$this->postProcessHook();
if ($this->_action & CRM_Core_Action::ADD) {
- $url = 'civicrm/event/manage/location';
- $urlParams = "action=update&reset=1&id={$event->id}";
- // special case for 'Save and Done' consistency.
- if ('_qf_EventInfo_upload_done' === $this->controller->getButtonName('submit')) {
- $url = 'civicrm/event/manage';
- $urlParams = 'reset=1';
- CRM_Core_Session::setStatus(ts("'%1' information has been saved.",
- [1 => $this->getTitle()]
- ), ts('Saved'), 'success');
- }
-
- CRM_Utils_System::redirect(CRM_Utils_System::url($url, $urlParams));
+ $url = CRM_Utils_System::url('civicrm/event/manage/location', "action=update&reset=1&id={$event->id}");
+ CRM_Utils_System::redirect($url);
}
parent::endPostProcess();
diff --git a/CRM/Event/Form/ManageEvent/Fee.php b/CRM/Event/Form/ManageEvent/Fee.php
index 52eb1eb987a7..901b1a8c9c2f 100644
--- a/CRM/Event/Form/ManageEvent/Fee.php
+++ b/CRM/Event/Form/ManageEvent/Fee.php
@@ -246,14 +246,15 @@ public function buildQuickForm() {
);
// financial type
- if (!CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus() ||
- (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus() && CRM_Core_Permission::check('administer CiviCRM Financial Types'))) {
- $this->addSelect('financial_type_id');
- }
- else {
- CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, CRM_Core_Action::ADD);
- $this->addSelect('financial_type_id', ['context' => 'search', 'options' => $financialTypes]);
+ CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, CRM_Core_Action::ADD);
+ $financialOptions = [
+ 'options' => $financialTypes,
+ ];
+ if (!CRM_Core_Permission::check('administer CiviCRM Financial Types')) {
+ $financialOptions['context'] = 'search';
}
+ $this->addSelect('financial_type_id', $financialOptions);
+
// add pay later options
$this->addElement('checkbox', 'is_pay_later', ts('Pay later option'), NULL,
['onclick' => "return showHideByValue('is_pay_later','','payLaterOptions','block','radio',false);"]
@@ -550,8 +551,8 @@ public function postProcess() {
$params['payment_processor'] = 'null';
}
- $params['is_pay_later'] = CRM_Utils_Array::value('is_pay_later', $params, 0);
- $params['is_billing_required'] = CRM_Utils_Array::value('is_billing_required', $params, 0);
+ $params['is_pay_later'] = $params['is_pay_later'] ?? 0;
+ $params['is_billing_required'] = $params['is_billing_required'] ?? 0;
if ($this->_id) {
diff --git a/CRM/Event/Form/ManageEvent/Registration.php b/CRM/Event/Form/ManageEvent/Registration.php
index 4d288953204c..7b51f7281d0a 100644
--- a/CRM/Event/Form/ManageEvent/Registration.php
+++ b/CRM/Event/Form/ManageEvent/Registration.php
@@ -33,10 +33,10 @@ class CRM_Event_Form_ManageEvent_Registration extends CRM_Event_Form_ManageEvent
* Set variables up before form is built.
*/
public function preProcess() {
- $this->_addProfileBottom = CRM_Utils_Array::value('addProfileBottom', $_GET, FALSE);
- $this->_profileBottomNum = CRM_Utils_Array::value('addProfileNum', $_GET, 0);
- $this->_addProfileBottomAdd = CRM_Utils_Array::value('addProfileBottomAdd', $_GET, FALSE);
- $this->_profileBottomNumAdd = CRM_Utils_Array::value('addProfileNumAdd', $_GET, 0);
+ $this->_addProfileBottom = $_GET['addProfileBottom'] ?? FALSE;
+ $this->_profileBottomNum = $_GET['addProfileNum'] ?? 0;
+ $this->_addProfileBottomAdd = $_GET['addProfileBottomAdd'] ?? FALSE;
+ $this->_profileBottomNumAdd = $_GET['addProfileNumAdd'] ?? 0;
parent::preProcess();
$this->setSelectedChild('registration');
@@ -783,12 +783,12 @@ public function postProcess() {
$params['id'] = $this->_id;
// format params
- $params['is_online_registration'] = CRM_Utils_Array::value('is_online_registration', $params, FALSE);
+ $params['is_online_registration'] = $params['is_online_registration'] ?? FALSE;
// CRM-11182
- $params['is_confirm_enabled'] = CRM_Utils_Array::value('is_confirm_enabled', $params, FALSE);
- $params['is_multiple_registrations'] = CRM_Utils_Array::value('is_multiple_registrations', $params, FALSE);
- $params['allow_same_participant_emails'] = CRM_Utils_Array::value('allow_same_participant_emails', $params, FALSE);
- $params['requires_approval'] = CRM_Utils_Array::value('requires_approval', $params, FALSE);
+ $params['is_confirm_enabled'] = $params['is_confirm_enabled'] ?? FALSE;
+ $params['is_multiple_registrations'] = $params['is_multiple_registrations'] ?? FALSE;
+ $params['allow_same_participant_emails'] = $params['allow_same_participant_emails'] ?? FALSE;
+ $params['requires_approval'] = $params['requires_approval'] ?? FALSE;
// reset is_email confirm if not online reg
if (!$params['is_online_registration']) {
@@ -922,7 +922,7 @@ public function postProcess() {
self::addMultipleProfiles($additionalProfileIds, $params, 'additional_custom_post_id_multiple');
$cantDedupe = FALSE;
- $rgId = CRM_Utils_Array::value('dedupe_rule_group_id', $params, 0);
+ $rgId = $params['dedupe_rule_group_id'] ?? 0;
switch (self::canProfilesDedupe($profileIds, $rgId)) {
case 0:
diff --git a/CRM/Event/Form/ManageEvent/Repeat.php b/CRM/Event/Form/ManageEvent/Repeat.php
index f84c3de49420..74c24246df7c 100644
--- a/CRM/Event/Form/ManageEvent/Repeat.php
+++ b/CRM/Event/Form/ManageEvent/Repeat.php
@@ -205,7 +205,7 @@ public static function getParticipantCountforEvent($listOfRelatedEntities = [])
*
* @return array
*/
- public static function checkRegistrationForEvents($eventID) {
+ public static function checkRegistrationForEvents($eventID): array {
$eventIdsWithNoRegistration = [];
if ($eventID) {
$getRelatedEntities = CRM_Core_BAO_RecurringEntity::getEntitiesFor($eventID, 'civicrm_event', TRUE);
@@ -218,8 +218,7 @@ public static function checkRegistrationForEvents($eventID) {
}
}
}
- CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted = $eventIdsWithNoRegistration;
- return CRM_Core_BAO_RecurringEntity::$_entitiesToBeDeleted;
+ return $eventIdsWithNoRegistration;
}
}
diff --git a/CRM/Event/Form/Participant.php b/CRM/Event/Form/Participant.php
index b066d7edd2d3..accef1c6737e 100644
--- a/CRM/Event/Form/Participant.php
+++ b/CRM/Event/Form/Participant.php
@@ -25,6 +25,7 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
use EntityLookupTrait;
use CRM_Contact_Form_ContactFormTrait;
+ use CRM_Event_Form_EventFormTrait;
/**
* Participant ID - use getParticipantID.
@@ -94,13 +95,6 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
*/
public $_contactId;
- /**
- * Array of event values.
- *
- * @var array
- */
- protected $_event;
-
/**
* Are we operating in "single mode", i.e. adding / editing only
* one participant record, or is this a batch add operation.
@@ -140,13 +134,6 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
*/
protected $_statusId = NULL;
- /**
- * Cache all the participant statuses.
- *
- * @var array
- */
- protected $_participantStatuses;
-
/**
* Participant mode.
*
@@ -207,13 +194,6 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
*/
public $_onlinePendingContributionId;
- /**
- * Stored participant record.
- *
- * @var array
- */
- protected $participantRecord;
-
/**
* Params for creating a payment to add to the contribution.
*
@@ -340,14 +320,6 @@ public function preProcess() {
CRM_Core_Error::statusBounce(ts('You do not have permission to access this page.'));
}
- if ($this->_action & CRM_Core_Action::DELETE) {
- // check delete permission for contribution
- if ($this->_id && $this->_paymentId && !CRM_Core_Permission::checkActionPermission('CiviContribute', $this->_action)) {
- CRM_Core_Error::statusBounce(ts("This Participant is linked to a contribution. You must have 'delete in CiviContribute' permission in order to delete this record."));
- }
- return;
- }
-
// when fee amount is included in form
if (!empty($_POST['hidden_feeblock']) || !empty($_POST['send_receipt'])) {
if ($this->_submitValues['event_id']) {
@@ -418,25 +390,22 @@ public function setDefaultValues(): array {
$defaults = [];
- if ($this->_action & CRM_Core_Action::DELETE) {
- return $defaults;
- }
-
if ($this->_id) {
$ids = [];
$params = ['id' => $this->_id];
CRM_Event_BAO_Participant::getValues($params, $defaults, $ids);
+ $defaults = $defaults[$this->_id];
$sep = CRM_Core_DAO::VALUE_SEPARATOR;
- if ($defaults[$this->_id]['role_id']) {
- $roleIDs = explode($sep, $defaults[$this->_id]['role_id']);
+ if ($defaults['role_id']) {
+ $roleIDs = explode($sep, $defaults['role_id']);
}
- $this->_contactId = $defaults[$this->_id]['contact_id'];
- $this->_statusId = $defaults[$this->_id]['participant_status_id'];
+ $this->_contactId = $defaults['contact_id'];
+ $this->_statusId = $defaults['participant_status_id'];
//set defaults for note
$noteDetails = CRM_Core_BAO_Note::getNote($this->_id, 'civicrm_participant');
- $defaults[$this->_id]['note'] = array_pop($noteDetails);
+ $defaults['note'] = array_pop($noteDetails);
// Check if this is a primaryParticipant (registered for others) and retrieve additional participants if true (CRM-4859)
if (CRM_Event_BAO_Participant::isPrimaryParticipant($this->_id)) {
@@ -445,31 +414,31 @@ public function setDefaultValues(): array {
$this->assign('additionalParticipants', $additionalParticipants ?? NULL);
// Get registered_by contact ID and display_name if participant was registered by someone else (CRM-4859)
- if (!empty($defaults[$this->_id]['participant_registered_by_id'])) {
+ if (!empty($defaults['participant_registered_by_id'])) {
$registered_by_contact_id = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant',
- $defaults[$this->_id]['participant_registered_by_id'],
+ $defaults['participant_registered_by_id'],
'contact_id', 'id'
);
- $this->assign('participant_registered_by_id', $defaults[$this->_id]['participant_registered_by_id']);
+ $this->assign('participant_registered_by_id', $defaults['participant_registered_by_id']);
$this->assign('registered_by_display_name', CRM_Contact_BAO_Contact::displayName($registered_by_contact_id));
}
$this->assign('registered_by_contact_id', $registered_by_contact_id ?? NULL);
}
elseif ($this->_contactID) {
- $defaults[$this->_id]['contact_id'] = $this->_contactID;
+ $defaults['contact_id'] = $this->_contactID;
}
//setting default register date
if ($this->_action == CRM_Core_Action::ADD) {
$statuses = array_flip(CRM_Event_PseudoConstant::participantStatus());
- $defaults[$this->_id]['status_id'] = $statuses['Registered'] ?? NULL;
- if (!empty($defaults[$this->_id]['event_id'])) {
+ $defaults['status_id'] = $statuses['Registered'] ?? NULL;
+ if (!empty($defaults['event_id'])) {
$financialTypeID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event',
- $defaults[$this->_id]['event_id'],
+ $defaults['event_id'],
'financial_type_id'
);
if ($financialTypeID) {
- $defaults[$this->_id]['financial_type_id'] = $financialTypeID;
+ $defaults['financial_type_id'] = $financialTypeID;
}
}
@@ -484,7 +453,7 @@ public function setDefaultValues(): array {
if (empty($defaults["email-{$this->_bltID}"]) &&
!empty($defaults['email-Primary'])
) {
- $defaults[$this->_id]["email-{$this->_bltID}"] = $defaults['email-Primary'];
+ $defaults["email-{$this->_bltID}"] = $defaults['email-Primary'];
}
}
@@ -496,16 +465,16 @@ public function setDefaultValues(): array {
if (!empty($submittedEvent[0])) {
$eventID = $submittedEvent[0];
}
- $defaults[$this->_id]['register_date'] = date('Y-m-d H:i:s');
+ $defaults['register_date'] = date('Y-m-d H:i:s');
}
else {
- $defaults[$this->_id]['record_contribution'] = 0;
+ $defaults['record_contribution'] = 0;
- if ($defaults[$this->_id]['participant_is_pay_later']) {
+ if ($defaults['participant_is_pay_later']) {
$this->assign('participant_is_pay_later', TRUE);
}
- $eventID = $defaults[$this->_id]['event_id'];
+ $eventID = $defaults['event_id'];
$this->_eventTypeId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $eventID, 'event_type_id', 'id');
@@ -517,8 +486,8 @@ public function setDefaultValues(): array {
//assign event and role id, this is needed for Custom data building
$sep = CRM_Core_DAO::VALUE_SEPARATOR;
- if (!empty($defaults[$this->_id]['participant_role_id'])) {
- $roleIDs = explode($sep, $defaults[$this->_id]['participant_role_id']);
+ if (!empty($defaults['participant_role_id'])) {
+ $roleIDs = explode($sep, $defaults['participant_role_id']);
}
if (isset($_POST['event_id'])) {
$eventID = $_POST['event_id'];
@@ -533,9 +502,9 @@ public function setDefaultValues(): array {
'default_role_id'
);
if (empty($roleIDs)) {
- $roleIDs = (array) $defaults[$this->_id]['participant_role_id'] = $roleID;
+ $roleIDs = (array) $defaults['participant_role_id'] = $roleID;
}
- $defaults[$this->_id]['event_id'] = $eventID;
+ $defaults['event_id'] = $eventID;
}
if (!empty($eventID)) {
$this->_eventTypeId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $eventID, 'event_type_id', 'id');
@@ -546,7 +515,7 @@ public function setDefaultValues(): array {
$roleIDs = explode(',', $urlRoleIDS);
}
if (isset($roleIDs)) {
- $defaults[$this->_id]['role_id'] = implode(',', $roleIDs);
+ $defaults['role_id'] = implode(',', $roleIDs);
}
if (isset($eventID)) {
@@ -556,8 +525,8 @@ public function setDefaultValues(): array {
$this->assign('eventTypeID', $this->_eventTypeId);
- $this->assign('event_is_test', CRM_Utils_Array::value('event_is_test', $defaults[$this->_id]));
- return $defaults[$this->_id];
+ $this->assign('event_is_test', CRM_Utils_Array::value('event_is_test', $defaults));
+ return $defaults;
}
/**
@@ -581,39 +550,6 @@ public function buildQuickForm() {
$this->applyFilter('__ALL__', 'trim');
- if ($this->_action & CRM_Core_Action::DELETE) {
- if ($this->_single) {
- $additionalParticipant = count(CRM_Event_BAO_Event::buildCustomProfile($this->_id,
- NULL,
- $this->_contactId,
- FALSE,
- TRUE
- )) - 1;
- if ($additionalParticipant) {
- $deleteParticipants = [
- 1 => ts('Delete this participant record along with associated participant record(s).'),
- 2 => ts('Delete only this participant record.'),
- ];
- $this->addRadio('delete_participant', NULL, $deleteParticipants, NULL, ' ');
- $this->setDefaults(['delete_participant' => 1]);
- }
- $this->assign('additionalParticipant', $additionalParticipant);
- }
- $this->addButtons([
- [
- 'type' => 'next',
- 'name' => ts('Delete'),
- 'spacing' => ' ',
- 'isDefault' => TRUE,
- ],
- [
- 'type' => 'cancel',
- 'name' => ts('Cancel'),
- ],
- ]);
- return;
- }
-
if ($this->_single) {
$contactField = $this->addEntityRef('contact_id', ts('Participant'), ['create' => TRUE, 'api' => ['extra' => ['email']]], TRUE);
if ($this->_context !== 'standalone') {
@@ -700,7 +636,7 @@ public function buildQuickForm() {
$notificationStatusIds = implode(',', array_keys(array_intersect($participantStatusName, $notificationStatuses)));
$this->assign('notificationStatusIds', $notificationStatusIds);
- $this->_participantStatuses = $statusOptions = CRM_Event_BAO_Participant::buildOptions('status_id', 'create');
+ $statusOptions = CRM_Event_BAO_Participant::buildOptions('status_id', 'create');
// Only show refund status when editing
if ($this->_action & CRM_Core_Action::ADD) {
@@ -733,7 +669,7 @@ public function buildQuickForm() {
'civicrm/contact/search',
'civicrm/group/search',
];
- if (!in_array($path, $excludeForPaths)) {
+ if (!$this->getParticipantID() && !in_array($path, $excludeForPaths)) {
$buttons[] = [
'type' => 'upload',
'name' => ts('Save and New'),
@@ -774,13 +710,12 @@ public function addRules(): void {
* list of errors to be posted back to the form
*/
public static function formRule($values, $files, $self) {
- // If $values['_qf_Participant_next'] is Delete or
// $values['event_id'] is empty, then return
- // instead of proceeding further.
-
- if ((($values['_qf_Participant_next'] ?? NULL) === 'Delete') ||
- empty($values['event_id'])
- ) {
+ // instead of proceeding further - this is legacy handling
+ // and it is unclear why but perhaps relates to the form's
+ // 'multitasking' & can go once the form is not overloaded?
+ // event_id is normally a required field..
+ if (empty($values['event_id'])) {
return TRUE;
}
@@ -853,26 +788,6 @@ public function postProcess() {
// get the submitted form values.
$params = $this->controller->exportValues($this->_name);
- if ($this->_action & CRM_Core_Action::DELETE) {
- if (($params['delete_participant'] ?? NULL) == 2) {
- $additionalId = (CRM_Event_BAO_Participant::getAdditionalParticipantIds($this->_id));
- $participantLinks = (CRM_Event_BAO_Participant::getAdditionalParticipantUrl($additionalId));
- }
- if (($params['delete_participant'] ?? NULL) == 1) {
- $additionalIds = CRM_Event_BAO_Participant::getAdditionalParticipantIds($this->_id);
- foreach ($additionalIds as $value) {
- CRM_Event_BAO_Participant::deleteParticipant($value);
- }
- }
- CRM_Event_BAO_Participant::deleteParticipant($this->_id);
- CRM_Core_Session::setStatus(ts('Selected participant was deleted successfully.'), ts('Record Deleted'), 'success');
- if (!empty($participantLinks)) {
- $status = ts('The following participants no longer have an event fee recorded. You can edit their registration and record a replacement contribution by clicking the links below:') . ' ' . $participantLinks;
- CRM_Core_Session::setStatus($status, ts('Group Payment Deleted'));
- }
- return;
- }
-
$statusMsg = $this->submit($params);
CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success');
$session = CRM_Core_Session::singleton();
@@ -931,7 +846,7 @@ public function submit($params) {
$params['total_amount'] = CRM_Utils_Rule::cleanMoney($params['total_amount']);
}
if ($this->_isPaidEvent) {
- [$contributionParams, $lineItem, $additionalParticipantDetails, $params] = $this->preparePaidEventProcessing($params);
+ [$contributionParams, $lineItem, $params] = $this->preparePaidEventProcessing($params);
}
$this->_params = $params;
@@ -951,15 +866,10 @@ public function submit($params) {
// Retrieve the name and email of the current user - this will be the FROM for the receipt email
$userName = CRM_Core_Session::singleton()->getLoggedInContactDisplayName();
- if ($this->_contactId) {
- [, $this->_contributorEmail, $this->_toDoNotEmail] = CRM_Contact_BAO_Contact::getContactDetails($this->_contactId);
- }
-
//modify params according to parameter used in create
//participant method (addParticipant)
$this->_params['participant_status_id'] = $params['status_id'];
$this->_params['participant_role_id'] = $this->getSubmittedValue('role_id');
- $this->assign('participant_status_id', $params['status_id']);
$now = date('YmdHis');
@@ -983,7 +893,7 @@ public function submit($params) {
// set email for primary location.
$fields['email-Primary'] = 1;
- $params['email-Primary'] = $params["email-{$this->_bltID}"] = $this->_contributorEmail;
+ $params['email-Primary'] = $params["email-{$this->_bltID}"] = $this->getContactValue('email_primary.email');
// now set the values for the billing location.
foreach ($this->_fields as $name => $dontCare) {
@@ -994,7 +904,7 @@ public function submit($params) {
$params["address_name-{$this->_bltID}"]
= ($params['billing_first_name'] ?? '') . ' ' .
($params['billing_middle_name'] ?? '') . ' ' .
- CRM_Utils_Array::value('billing_last_name', $params);
+ ($params['billing_last_name'] ?? '');
$params["address_name-{$this->_bltID}"] = trim($params["address_name-{$this->_bltID}"]);
$fields["address_name-{$this->_bltID}"] = 1;
@@ -1032,7 +942,7 @@ public function submit($params) {
// so we copy stuff over to first_name etc.
$paymentParams = $this->_params;
if (!empty($this->_params['send_receipt'])) {
- $paymentParams['email'] = $this->_contributorEmail;
+ $paymentParams['email'] = $this->getContactValue('email_primary.email');
}
// The only reason for merging in the 'contact_id' rather than ensuring it is set
@@ -1074,9 +984,6 @@ public function submit($params) {
}
$this->set('params', $this->_params);
- $this->assign('trxn_id', $result['trxn_id']);
- $this->assign('receive_date', $this->_params['receive_date']);
-
//add contribution record
$this->_params['financial_type_id']
= CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $params['event_id'], 'financial_type_id');
@@ -1178,16 +1085,7 @@ public function submit($params) {
foreach ($recordContribution as $f) {
$contributionParams[$f] = $this->_params[$f] ?? NULL;
- if ($f === 'trxn_id') {
- $this->assign('trxn_id', $contributionParams[$f]);
- }
}
-
- //insert financial type name in receipt.
- $this->assign('financialTypeName', CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType',
- $contributionParams['financial_type_id']));
- // legacy support
- $this->assign('contributionTypeName', CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $contributionParams['financial_type_id']));
$contributionParams['skipLineItem'] = 1;
if ($this->_id) {
$contributionParams['contribution_mode'] = 'participant';
@@ -1219,7 +1117,6 @@ public function submit($params) {
// the owed amount
$contributionParams['total_amount'] = $amountOwed;
$contributionParams['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
- $this->assign('balanceAmount', $amountOwed - $params['total_amount']);
$this->storePaymentCreateParams($params);
}
}
@@ -1281,7 +1178,7 @@ public function submit($params) {
}
$lineItem[$this->_priceSetId][$lineKey] = $line;
}
- CRM_Price_BAO_LineItem::processPriceSet($participants[$num]->id, $lineItem, CRM_Utils_Array::value($num, $contributions, NULL), 'civicrm_participant');
+ CRM_Price_BAO_LineItem::processPriceSet($participants[$num]->id, $lineItem, $contributions[$num] ?? NULL, 'civicrm_participant');
}
}
}
@@ -1305,7 +1202,7 @@ public function submit($params) {
}
if (!empty($params['send_receipt'])) {
- $result = $this->sendReceipts($params, $participants, $lineItem[0] ?? [], $additionalParticipantDetails ?? []);
+ $result = $this->sendReceipts($params, $participants);
}
// set the participant id if it is not set
@@ -1433,13 +1330,10 @@ public function buildEventFeeForm($form) {
$lineItem = [];
$totalTaxAmount = 0;
if (!CRM_Utils_System::isNull($form->_values['line_items'] ?? NULL)) {
- $lineItem[] = $form->_values['line_items'];
foreach ($form->_values['line_items'] as $key => $value) {
$totalTaxAmount = $value['tax_amount'] + $totalTaxAmount;
}
}
- $form->assign('totalTaxAmount', Civi::settings()->get('invoicing') ? ($totalTaxAmount ?? NULL) : NULL);
- $form->assign('lineItem', empty($lineItem) ? FALSE : $lineItem);
$discounts = [];
if (!empty($form->_values['discount'])) {
foreach ($form->_values['discount'] as $key => $value) {
@@ -1533,8 +1427,8 @@ public function buildEventFeeForm($form) {
// Retrieve the name and email of the contact - form will be the TO for receipt email ( only if context is not standalone)
if ($form->_context !== 'standalone') {
if ($form->getContactID()) {
- [, $form->_contributorEmail] = CRM_Contact_BAO_Contact_Location::getEmailDetails($form->_contactId);
- $form->assign('email', $form->_contributorEmail);
+ // @todo - this is likely unneeded now.
+ $form->assign('email', $this->getContactValue('email_primary.email'));
}
else {
//show email block for batch update for event
@@ -1585,7 +1479,7 @@ protected function preparePaidEventProcessing($params): array {
//also add additional participant's fee level/priceset
if (CRM_Event_BAO_Participant::isPrimaryParticipant($this->_id)) {
$additionalIds = CRM_Event_BAO_Participant::getAdditionalParticipantIds($this->_id);
- $hasLineItems = CRM_Utils_Array::value('priceSetId', $params, FALSE);
+ $hasLineItems = $params['priceSetId'] ?? FALSE;
$additionalParticipantDetails = $this->getFeeDetails($additionalIds, $hasLineItems);
}
}
@@ -1634,25 +1528,10 @@ protected function preparePaidEventProcessing($params): array {
$this->_lineItem = $lineItem;
$lineItem = array_merge($lineItem, $additionalParticipantDetails);
-
- $participantCount = [];
- foreach ($lineItem as $k) {
- foreach ($k as $v) {
- if (CRM_Utils_Array::value('participant_count', $v) > 0) {
- $participantCount[] = $v['participant_count'];
- }
- }
- }
}
- if (isset($participantCount)) {
- $this->assign('pricesetFieldsCount', $participantCount);
- }
- $this->assign('lineItem', empty($lineItem[0]) || $this->isQuickConfig() ? FALSE : $lineItem);
}
- else {
- $this->assign('amount_level', $params['amount_level']);
- }
- return [$contributionParams, $lineItem, $additionalParticipantDetails, $params];
+
+ return [$contributionParams, $lineItem, $params];
}
/**
@@ -1663,43 +1542,7 @@ protected function preparePaidEventProcessing($params): array {
* @throws \CRM_Core_Exception
*/
protected function assignEventDetailsToTpl($eventID, $participantRoles, $receiptText): void {
- //use of the message template below requires variables in different format
- $events = [];
- $returnProperties = ['event_type_id', 'fee_label', 'start_date', 'end_date', 'is_show_location', 'title'];
-
- //get all event details.
- CRM_Core_DAO::commonRetrieveAll('CRM_Event_DAO_Event', 'id', $eventID, $events, $returnProperties);
- $event = $events[$eventID];
- unset($event['start_date']);
- unset($event['end_date']);
-
- $role = CRM_Event_PseudoConstant::participantRole();
-
- if (is_array($participantRoles)) {
- $selectedRoles = [];
- foreach ($participantRoles as $roleId) {
- $selectedRoles[] = $role[$roleId];
- }
- $event['participant_role'] = implode(', ', $selectedRoles);
- }
- else {
- $event['participant_role'] = $role[$participantRoles] ?? NULL;
- }
- $event['is_monetary'] = $this->_isPaidEvent;
-
- if ($receiptText) {
- $event['confirm_email_text'] = $receiptText;
- }
- $this->assign('event', $event);
- $this->assign('isShowLocation', $event['is_show_location']);
- if (($event['is_show_location'] ?? NULL) == 1) {
- $locationParams = [
- 'entity_id' => $eventID,
- 'entity_table' => 'civicrm_event',
- ];
- $location = CRM_Core_BAO_Location::getValues($locationParams, TRUE);
- $this->assign('location', $location);
- }
+ $this->assign('event', ['confirm_email_text' => $receiptText]);
}
/**
@@ -1743,7 +1586,7 @@ protected function processContribution(
'invoice_id' => $params['invoiceID'],
'currency' => $params['currencyID'],
'source' => !empty($params['participant_source']) ? $params['participant_source'] : $params['description'],
- 'is_pay_later' => CRM_Utils_Array::value('is_pay_later', $params, 0),
+ 'is_pay_later' => $params['is_pay_later'] ?? 0,
'campaign_id' => $params['campaign_id'] ?? NULL,
'card_type_id' => $params['card_type_id'] ?? NULL,
'pan_truncation' => $params['pan_truncation'] ?? NULL,
@@ -1782,12 +1625,7 @@ protected function processContribution(
}
$contribParams['revenue_recognition_date'] = $this->getRevenueRecognitionDate();
- //create an contribution address
- // The concept of contributeMode is deprecated. Elsewhere we use the function processBillingAddress() - although
- // currently that is only inherited by back-office forms.
- if ($form->_contributeMode != 'notify' && empty($params['is_pay_later'])) {
- $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $form->_bltID);
- }
+ $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params);
$contribParams['skipLineItem'] = 1;
$contribParams['skipCleanMoney'] = 1;
@@ -1796,12 +1634,6 @@ protected function processContribution(
// CRM-11124
CRM_Event_BAO_Participant::createDiscountTrxn($form->_eventId, $contribParams, NULL, CRM_Price_BAO_PriceSet::parseFirstPriceSetValueIDFromParams($params));
- // process soft credit / pcp pages
- if (!empty($params['pcp_made_through_id'])) {
- CRM_Contribute_BAO_ContributionSoft::formatSoftCreditParams($params, $form);
- CRM_Contribute_BAO_ContributionSoft::processSoftContribution($params, $contribution);
- }
-
$transaction->commit();
return $contribution;
@@ -1835,7 +1667,7 @@ protected function addParticipant(&$form, $params, $contactID) {
$participantFields['participant_source']['maxlength']
),
'fee_level' => $params['amount_level'] ?? NULL,
- 'is_pay_later' => CRM_Utils_Array::value('is_pay_later', $params, 0),
+ 'is_pay_later' => $params['is_pay_later'] ?? 0,
'fee_amount' => $params['fee_amount'] ?? NULL,
'registered_by_id' => $params['registered_by_id'] ?? NULL,
'discount_id' => $params['discount_id'] ?? NULL,
@@ -1893,36 +1725,6 @@ protected function isPaymentOnExistingContribution(): bool {
return ($this->getParticipantID() && $this->_action & CRM_Core_Action::UPDATE) && $this->_paymentId;
}
- /**
- * Get the value for a field relating to the event.
- *
- * @param string $fieldName
- *
- * @return mixed
- * @throws \CRM_Core_Exception
- */
- protected function getEventValue(string $fieldName) {
- if (!isset($this->_event)) {
- $this->_event = civicrm_api3('Event', 'getsingle', ['id' => $this->_eventId]);
- }
- return $this->_event[$fieldName];
- }
-
- /**
- * Get a value from the existing participant record (applies to edits).
- *
- * @param string $fieldName
- *
- * @return array
- * @throws \CRM_Core_Exception
- */
- protected function getParticipantValue($fieldName) {
- if (!$this->participantRecord) {
- $this->participantRecord = civicrm_api3('Participant', 'getsingle', ['id' => $this->getParticipantID()]);
- }
- return $this->participantRecord[$fieldName] ?? $this->participantRecord['participant_' . $fieldName];
- }
-
/**
* Get id of participant being edited.
*
@@ -2085,159 +1887,61 @@ protected function assignUrlPath() {
/**
* @param $params
* @param array $participants
- * @param $lineItem
- * @param $additionalParticipantDetails
*
* @return array
* @throws \CRM_Core_Exception
* @throws \Brick\Money\Exception\UnknownCurrencyException
*/
- protected function sendReceipts($params, array $participants, $lineItem, $additionalParticipantDetails): array {
+ protected function sendReceipts($params, array $participants): array {
$sent = [];
$notSent = [];
- $this->assign('module', 'Event Registration');
$this->assignEventDetailsToTpl($params['event_id'], CRM_Utils_Array::value('role_id', $params), CRM_Utils_Array::value('receipt_text', $params));
- // @todo - this is no longer in core templates as of 5.63
- // we should remove once we have done a 'push upgrade' on addresses - ie advised
- // people to upgrade their templates in an upgrade message, as
- // opposed to just updating unmodified templates.
- $this->assign('isPrimary', (int) $this->_isPaidEvent);
- if ($this->_isPaidEvent) {
- $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument();
- if (!$this->_mode) {
- if (isset($params['payment_instrument_id'])) {
- $this->assign('paidBy',
- CRM_Utils_Array::value($params['payment_instrument_id'],
- $paymentInstrument
- )
- );
- }
- }
- }
- $this->assign('checkNumber', $params['check_number'] ?? NULL);
if ($this->_mode) {
- $this->assignBillingName($params);
- $this->assign('address', CRM_Utils_Address::getFormattedBillingAddressFieldsFromParameters(
- $this->_params,
- $this->_bltID
- ));
-
$valuesForForm = CRM_Contribute_Form_AbstractEditPayment::formatCreditCardDetails($params);
$this->assignVariables($valuesForForm, ['credit_card_exp_date', 'credit_card_type', 'credit_card_number']);
- $this->assign('is_pay_later', 0);
}
- $this->assign('register_date', $params['register_date']);
- if (isset($params['receive_date'])) {
- $this->assign('receive_date', $params['receive_date']);
- }
+ $fromEmails = CRM_Event_BAO_Event::getFromEmailIds($this->getEventID());
+ foreach ($participants as $num => $participant) {
+ $participantID = $participant->id;
+ $contactID = $participant->contact_id;
+ $key = 'contact_' . $contactID;
- $customGroup = [];
- $customFieldFilters = [
- 'ParticipantRole' => $this->getSubmittedValue('role_id'),
- 'ParticipantEventName' => $this->getEventID(),
- 'ParticipantEventType' => $this->getEventValue('event_type_id'),
- ];
- $customFields = CRM_Core_BAO_CustomField::getViewableCustomFields('Participant', $customFieldFilters);
- foreach ($params['custom'] as $fieldID => $values) {
- foreach ($values as $fieldValue) {
- $formattedValue = CRM_Core_BAO_CustomField::displayValue($fieldValue['value'], $fieldID, $participants[0]->id);
- $customGroup[$customFields[$fieldID]['custom_group_id.title']][$customFields[$fieldID]['label']] = str_replace(' ', '', $formattedValue);
+ $this->define('Contact', $key, ['id' => $contactID]);
+ if (!$this->lookup($key, 'email_primary.email') || $this->lookup($key, 'do_not_email')) {
+ // try to send emails only if email id is present
+ // and the do-not-email option is not checked for that contact
+ $notSent[] = $contactID;
+ continue;
}
- }
- $this->assign('customGroup', $customGroup);
- foreach ($this->_contactIds as $num => $contactID) {
- // Retrieve the name and email of the contact - this will be the TO for receipt email
- [, $this->_contributorEmail, $this->_toDoNotEmail] = CRM_Contact_BAO_Contact::getContactDetails($contactID);
-
$waitStatus = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Waiting'");
$waitingStatus = $waitStatus[$params['status_id']] ?? NULL;
if ($waitingStatus) {
$this->assign('isOnWaitlist', TRUE);
}
- $this->assign('contactID', $contactID);
- $this->assign('participantID', $participants[$num]->id);
-
$contributionID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment',
- $participants[$num]->id, 'contribution_id', 'participant_id'
+ $participantID, 'contribution_id', 'participant_id'
);
- $totalAmount = 0;
- if ($contributionID) {
- // @todo - this should be temporary - we are looking to remove this variable from the template
- // in favour of the {contribution.total_amount} token.
- // In case this needs back-porting I have kept it as simple as possible.
- $totalAmount = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution',
- $contributionID, 'id', 'total_amount'
- );
- }
- $this->assign('totalAmount', $params['total_amount'] ?? $totalAmount);
- $this->_id = $participants[$num]->id;
-
- if ($this->_isPaidEvent) {
- // fix amount for each of participants ( for bulk mode )
- $eventAmount = [];
- $totalTaxAmount = 0;
-
- // add dataArray in the receipts in ADD and UPDATE condition
- // dataArray contains the total tax amount for each tax rate, in the form [tax rate => total tax amount]
- // include 0% tax rate if it exists because if $dataArray controls if tax is shown for each line item
- // in the message templates and we want to show 0% tax if set, even if there is no total tax
- $dataArray = [];
- if ($this->_action & CRM_Core_Action::ADD) {
- $line = $lineItem ?? [];
- }
- elseif ($this->_action & CRM_Core_Action::UPDATE) {
- $line = $this->_values['line_items'];
- }
- if (Civi::settings()->get('invoicing')) {
- foreach ($line as $key => $value) {
- if (isset($value['tax_amount']) && isset($value['tax_rate'])) {
- $totalTaxAmount += $value['tax_amount'];
- if (isset($dataArray[(string) $value['tax_rate']])) {
- $dataArray[(string) $value['tax_rate']] += $value['tax_amount'];
- }
- else {
- $dataArray[(string) $value['tax_rate']] = $value['tax_amount'];
- }
- }
- }
- $this->assign('taxTerm', $this->getSalesTaxTerm());
- $this->assign('dataArray', $dataArray);
- }
- $eventAmount[$num] = [
- 'label' => preg_replace('//', '', $params['amount_level']),
- 'amount' => $params['fee_amount'],
- ];
- //as we are using same template for online & offline registration.
- //So we have to build amount as array.
- $eventAmount = array_merge($eventAmount, $additionalParticipantDetails);
- $this->assign('amount', $eventAmount);
- }
- $this->assign('totalTaxAmount', $totalTaxAmount ?? 0);
$sendTemplateParams = [
'workflow' => 'event_offline_receipt',
'contactId' => $contactID,
'isTest' => !empty($this->_defaultValues['is_test']),
'PDFFilename' => ts('confirmation') . '.pdf',
'modelProps' => [
- 'participantID' => $this->_id,
+ 'participantID' => $participantID,
'eventID' => $params['event_id'],
'contributionID' => $contributionID,
],
];
- // try to send emails only if email id is present
- // and the do-not-email option is not checked for that contact
- if ($this->_contributorEmail and !$this->_toDoNotEmail) {
- $sendTemplateParams['from'] = $params['from_email_address'];
- $sendTemplateParams['toName'] = $this->getContactValue('display_name');
- $sendTemplateParams['toEmail'] = $this->_contributorEmail;
- $sendTemplateParams['cc'] = $this->_fromEmails['cc'] ?? NULL;
- $sendTemplateParams['bcc'] = $this->_fromEmails['bcc'] ?? NULL;
- }
+ $sendTemplateParams['from'] = $params['from_email_address'];
+ $sendTemplateParams['toName'] = $this->lookup($key, 'display_name');
+ $sendTemplateParams['toEmail'] = $this->lookup($key, 'email_primary.email');
+ $sendTemplateParams['cc'] = $fromEmails['cc'] ?? NULL;
+ $sendTemplateParams['bcc'] = $fromEmails['bcc'] ?? NULL;
//send email with pdf invoice
if (Civi::settings()->get('invoice_is_email_pdf')) {
@@ -2247,13 +1951,8 @@ protected function sendReceipts($params, array $participants, $lineItem, $additi
[$mailSent] = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
if ($mailSent) {
$sent[] = $contactID;
- foreach ($participants as $ids => $values) {
- if ($values->contact_id == $contactID) {
- $values->details = $params['receipt_text'] ?? NULL;
- CRM_Activity_BAO_Activity::addActivity($values, 'Email');
- break;
- }
- }
+ $participant->details = $this->getSubmittedValue('receipt_text');
+ CRM_Activity_BAO_Activity::addActivity($participant, 'Email');
}
else {
$notSent[] = $contactID;
diff --git a/CRM/Event/Form/Participant/Delete.php b/CRM/Event/Form/Participant/Delete.php
new file mode 100644
index 000000000000..f9634ee4e746
--- /dev/null
+++ b/CRM/Event/Form/Participant/Delete.php
@@ -0,0 +1,158 @@
+participantID === NULL) {
+ $id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+ $this->participantID = $id ? (int) $id : FALSE;
+ }
+ return $this->participantID ?: NULL;
+ }
+
+ /**
+ * Get the selected Event ID.
+ *
+ * @return int|null
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpDocMissingThrowsInspection
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getEventID(): ?int {
+ return $this->getParticipantValue('event_id');
+ }
+
+ /**
+ * Get the relevant contact ID.
+ *
+ * @return int|null
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * @noinspection PhpDocMissingThrowsInspection
+ * @noinspection PhpUnhandledExceptionInspection
+ */
+ public function getContactID(): ?int {
+ return $this->getParticipantValue('contact_id');
+ }
+
+ /**
+ * Set variables up before form is built.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function preProcess(): void {
+ $this->setAction(CRM_Core_Action::DELETE);
+ $this->setTitle(ts('Delete participant record for %1', [1 => $this->getContactValue('display_name')]));
+ $contributionID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment',
+ $this->getParticipantID(), 'contribution_id', 'participant_id'
+ );
+ if ($contributionID && !CRM_Core_Permission::checkActionPermission('CiviContribute', CRM_Core_Action::DELETE)) {
+ CRM_Core_Error::statusBounce(ts("This Participant is linked to a contribution. You must have 'delete in CiviContribute' permission in order to delete this record."));
+ }
+ }
+
+ /**
+ * Build the form object.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function buildQuickForm(): void {
+ $additionalParticipant = (int) CRM_Core_DAO::singleValueQuery(
+ 'SELECT count(*) FROM civicrm_participant WHERE registered_by_id = %1 AND id <> registered_by_id',
+ [1 => [$this->getParticipantID(), 'Integer']]
+ );
+ if ($additionalParticipant) {
+ $deleteParticipants = [
+ 1 => ts('Delete this participant record along with associated participant record(s).'),
+ 2 => ts('Delete only this participant record.'),
+ ];
+ $this->addRadio('delete_participant', NULL, $deleteParticipants, NULL, ' ');
+ $this->setDefaults(['delete_participant' => 1]);
+ }
+ $this->assign('additionalParticipant', $additionalParticipant);
+ $this->addButtons([
+ [
+ 'type' => 'next',
+ 'name' => ts('Delete'),
+ 'spacing' => ' ',
+ 'isDefault' => TRUE,
+ ],
+ [
+ 'type' => 'cancel',
+ 'name' => ts('Cancel'),
+ ],
+ ]);
+ }
+
+ /**
+ * Process the form submission.
+ *
+ * @throws \Civi\Core\Exception\DBQueryException
+ */
+ public function postProcess(): void {
+ $deleteParticipantOption = (int) $this->getSubmittedValue('delete_participant');
+ if ($deleteParticipantOption === 2) {
+ $additionalID = (CRM_Event_BAO_Participant::getAdditionalParticipantIds($this->getParticipantID()));
+ $participantLinks = (CRM_Event_BAO_Participant::getAdditionalParticipantUrl($additionalID));
+ }
+ if ($deleteParticipantOption === 1) {
+ $additionalIDs = CRM_Event_BAO_Participant::getAdditionalParticipantIds($this->getParticipantID());
+ foreach ($additionalIDs as $value) {
+ CRM_Event_BAO_Participant::deleteParticipant($value);
+ }
+ }
+ CRM_Event_BAO_Participant::deleteParticipant($this->getParticipantID());
+ CRM_Core_Session::setStatus(ts('Selected participant was deleted successfully.'), ts('Record Deleted'), 'success');
+ if (!empty($participantLinks)) {
+ $status = ts('The following participants no longer have an event fee recorded. You can edit their registration and record a replacement contribution by clicking the links below:') . ' ' . $participantLinks;
+ CRM_Core_Session::setStatus($status, ts('Group Payment Deleted'));
+ }
+ }
+
+}
diff --git a/CRM/Event/Form/ParticipantFeeSelection.php b/CRM/Event/Form/ParticipantFeeSelection.php
index 1bfe38dee8d4..cbb5c49bc866 100644
--- a/CRM/Event/Form/ParticipantFeeSelection.php
+++ b/CRM/Event/Form/ParticipantFeeSelection.php
@@ -21,10 +21,17 @@
*
*/
class CRM_Event_Form_ParticipantFeeSelection extends CRM_Core_Form {
+ use CRM_Event_Form_EventFormTrait;
+ use CRM_Contact_Form_ContactFormTrait;
public $useLivePageJS = TRUE;
- protected $_contactId = NULL;
+ /**
+ * @var int
+ *
+ * @deprecated
+ */
+ protected $_contactId;
protected $_contributorDisplayName = NULL;
@@ -42,9 +49,12 @@ class CRM_Event_Form_ParticipantFeeSelection extends CRM_Core_Form {
public $_values = NULL;
- public $_participantId = NULL;
-
- protected $_participantStatus = NULL;
+ /**
+ * @var int
+ *
+ * @deprecated use getParticipantID().
+ */
+ public $_participantId;
protected $_paidAmount = NULL;
@@ -53,26 +63,21 @@ class CRM_Event_Form_ParticipantFeeSelection extends CRM_Core_Form {
protected $contributionAmt = NULL;
public function preProcess() {
- $this->_participantId = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);
- $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
- $this->_eventId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $this->_participantId, 'event_id');
- $this->_fromEmails = CRM_Event_BAO_Event::getFromEmailIds($this->_eventId);
+ $this->_fromEmails = CRM_Event_BAO_Event::getFromEmailIds($this->getEventID());
if ($this->getContributionID()) {
$this->_isPaidEvent = TRUE;
}
$this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, TRUE);
- [$this->_contributorDisplayName, $this->_contributorEmail] = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactId);
- $this->assign('displayName', $this->_contributorDisplayName);
- $this->assign('email', $this->_contributorEmail);
-
- $this->_participantStatus = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Participant', $this->_participantId, 'status_id');
//set the payment mode - _mode property is defined in parent class
$this->_mode = CRM_Utils_Request::retrieve('mode', 'String', $this);
- $this->assign('contactId', $this->_contactId);
- $this->assign('id', $this->_participantId);
+ [$this->_contributorDisplayName, $this->_contributorEmail] = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->getContactID());
+ $this->assign('displayName', $this->getContactValue('display_name'));
+ $this->assign('email', $this->getContactValue('email_primary.email'));
+ $this->assign('contactId', $this->getContactID());
+ $this->assign('id', $this->getParticipantID());
$paymentInfo = CRM_Contribute_BAO_Contribution::getPaymentInfo($this->_participantId, 'event');
$this->_paidAmount = $paymentInfo['paid'];
@@ -103,10 +108,10 @@ public function preProcess() {
*/
public function getContributionID(): ?int {
if ($this->contributionID === NULL) {
- $this->contributionID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $this->_participantId, 'contribution_id', 'participant_id') ?: FALSE;
+ $this->contributionID = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $this->getParticipantID(), 'contribution_id', 'participant_id') ?: FALSE;
if (!$this->contributionID) {
- $primaryParticipantID = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Participant', $this->_participantId, 'registered_by_id');
+ $primaryParticipantID = $this->getParticipantValue('registered_by_id');
if ($primaryParticipantID) {
$this->contributionID = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_ParticipantPayment', $primaryParticipantID, 'contribution_id', 'participant_id') ?: FALSE;
}
@@ -159,7 +164,7 @@ public function buildQuickForm() {
$statuses = CRM_Event_PseudoConstant::participantStatus();
$this->assign('partiallyPaid', array_search('Partially paid', $statuses));
$this->assign('pendingRefund', array_search('Pending refund', $statuses));
- $this->assign('participantStatus', $this->_participantStatus);
+ $this->assign('participantStatus', $this->getParticipantValue('status_id'));
$this->assign('currencySymbol', CRM_Core_BAO_Country::defaultCurrencySymbol());
@@ -365,11 +370,7 @@ private function emailReceipt(array $params): void {
$this->assign('totalAmount', $this->contributionAmt);
$this->assign('checkNumber', CRM_Utils_Array::value('check_number', $params));
}
- // @todo isPrimary no longer used from 5.63 in core templates, remove
- // once users have been 'pushed' to update their templates (via
- // upgrade message - which we don't always do whenever we change
- // a minor variable.
- $this->assign('isPrimary', $this->_isPaidEvent);
+
$this->assign('register_date', $params['register_date']);
// Retrieve the name and email of the contact - this will be the TO for receipt email
@@ -420,7 +421,7 @@ private function emailReceipt(array $params): void {
*/
public function getEventID(): int {
if (!$this->_eventId) {
- $this->_eventId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $this->_participantId, 'event_id');
+ $this->_eventId = $this->getParticipantValue('event_id');
}
return $this->_eventId;
}
@@ -451,4 +452,41 @@ public function getPriceSetID(): ?int {
return $priceSetID;
}
+ /**
+ * Get id of participant being acted on.
+ *
+ * @return int
+ *
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
+ *
+ * No exception should be thrown... as it should be unreachable/overridden.
+ * @noinspection PhpUnhandledExceptionInspection
+ * @noinspection PhpDocMissingThrowsInspection
+ */
+ public function getParticipantID(): int {
+ if (!$this->_participantId) {
+ $this->_participantId = (int) CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);
+ }
+ return $this->_participantId;
+ }
+
+ /**
+ * Get the contact ID.
+ *
+ * Override this for more complex retrieval as required by the form.
+ *
+ * @return int|null
+ *
+ * @noinspection PhpUnhandledExceptionInspection
+ * @noinspection PhpDocMissingThrowsInspection
+ */
+ public function getContactID(): ?int {
+ if (!$this->_contactId) {
+ $this->_contactId = (int) $this->getParticipantValue('contact_id');
+ }
+ return $this->_contactId;
+ }
+
}
diff --git a/CRM/Event/Form/ParticipantView.php b/CRM/Event/Form/ParticipantView.php
index 03406163fb59..c87906b92f89 100644
--- a/CRM/Event/Form/ParticipantView.php
+++ b/CRM/Event/Form/ParticipantView.php
@@ -180,8 +180,8 @@ public function preProcess() {
);
}
if (CRM_Core_Permission::check('delete in CiviEvent')) {
- $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/participant',
- "action=delete&reset=1&id={$values[$participantID]['id']}&cid={$values[$participantID]['contact_id']}&context=home"
+ $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/participant/delete',
+ "reset=1&id={$values[$participantID]['id']}}"
);
}
diff --git a/CRM/Event/Form/Registration.php b/CRM/Event/Form/Registration.php
index 84f61d77b5de..1595d77e05a2 100644
--- a/CRM/Event/Form/Registration.php
+++ b/CRM/Event/Form/Registration.php
@@ -20,20 +20,36 @@
class CRM_Event_Form_Registration extends CRM_Core_Form {
use CRM_Financial_Form_FrontEndPaymentFormTrait;
+ use CRM_Event_Form_EventFormTrait;
/**
* The id of the event we are processing.
*
* @var int
+ *
+ * @deprecated access via `getEventID`
*/
public $_eventId;
/**
- * Get the event it.
+ * Get the selected Event ID.
+ *
+ * @return int|null
+ *
+ * @throws \CRM_Core_Exception
+ * @api This function will not change in a minor release and is supported for
+ * use outside of core. This annotation / external support for properties
+ * is only given where there is specific test cover.
*
- * @return int
*/
- protected function getEventID(): int {
+ public function getEventID(): int {
+ if (!$this->_eventId) {
+ $this->_eventId = (int) CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);
+ // this is the first time we are hitting this, so check for permissions here
+ if (!CRM_Core_Permission::event(CRM_Core_Permission::EDIT, $this->_eventId, 'register for events')) {
+ CRM_Core_Error::statusBounce(ts('You do not have permission to register for this event'), $this->getInfoPageUrl());
+ }
+ }
return $this->_eventId;
}
@@ -179,9 +195,11 @@ protected function getEventID(): int {
/**
* Set variables up before form is built.
+ *
+ * @throws \CRM_Core_Exception
*/
public function preProcess() {
- $this->_eventId = (int) CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);
+ $this->setTitle($this->getEventValue('title'));
$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);
@@ -221,20 +239,16 @@ public function preProcess() {
$this->assign('showPaymentOnConfirm', $this->showPaymentOnConfirm);
if (!$this->_values) {
- // this is the first time we are hitting this, so check for permissions here
- if (!CRM_Core_Permission::event(CRM_Core_Permission::EDIT, $this->_eventId, 'register for events')) {
- CRM_Core_Error::statusBounce(ts('You do not have permission to register for this event'), $this->getInfoPageUrl());
- }
// get all the values from the dao object
$this->_values = $this->_fields = [];
//retrieve event information
- $params = ['id' => $this->_eventId];
+ $params = ['id' => $this->getEventID()];
CRM_Event_BAO_Event::retrieve($params, $this->_values['event']);
// check for is_monetary status
- $isMonetary = $this->_values['event']['is_monetary'] ?? NULL;
+ $isMonetary = $this->getEventValue('is_monetary');
// check for ability to add contributions of type
if ($isMonetary
&& CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()
@@ -260,7 +274,7 @@ public function preProcess() {
$this->set('additionalParticipantIds', $this->_additionalParticipantIds);
}
- $eventFull = CRM_Event_BAO_Participant::eventFull($this->_eventId, FALSE,
+ $eventFull = CRM_Event_BAO_Participant::eventFull($this->getEventID(), FALSE,
$this->_values['event']['has_waitlist'] ?? NULL
);
@@ -287,7 +301,7 @@ public function preProcess() {
$participant_role = CRM_Core_OptionGroup::values('participant_role');
$this->_values['event']['participant_role'] = $participant_role["{$this->_values['event']['default_role_id']}"];
}
- $isPayLater = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $this->_eventId, 'is_pay_later');
+ $isPayLater = $this->getEventValue('is_pay_later');
$this->setPayLaterLabel($isPayLater ? $this->_values['event']['pay_later_text'] : '');
//check for various combinations for paylater, payment
//process with paid event.
@@ -369,8 +383,6 @@ public function preProcess() {
$this->_contributeMode = $this->get('contributeMode');
$this->assign('contributeMode', $this->_contributeMode);
- $this->setTitle($this->_values['event']['title']);
-
$this->assign('paidEvent', $this->_values['event']['is_monetary']);
// we do not want to display recently viewed items on Registration pages
@@ -461,8 +473,7 @@ public function assignToTemplate() {
$this->assign('address', CRM_Utils_Address::getFormattedBillingAddressFieldsFromParameters($params, $this->_bltID));
- // The concept of contributeMode is deprecated.
- if ($this->_contributeMode === 'direct' && empty($params['is_pay_later'])) {
+ if ($this->getSubmittedValue('credit_card_number')) {
if (isset($params['credit_card_exp_date'])) {
$date = CRM_Utils_Date::format($params['credit_card_exp_date']);
$date = CRM_Utils_Date::mysqlToIso($date);
@@ -586,61 +597,54 @@ public static function initEventFee($form, $doNotIncludeExpiredFields, $priceSet
}
// get price info
- if ($priceSetId) {
- if ($form->_action & CRM_Core_Action::UPDATE) {
- if (in_array(CRM_Utils_System::getClassName($form), ['CRM_Event_Form_Participant', 'CRM_Event_Form_Task_Register'])) {
- $form->_values['line_items'] = CRM_Price_BAO_LineItem::getLineItems($form->_id, 'participant');
- }
- else {
- $form->_values['line_items'] = CRM_Price_BAO_LineItem::getLineItems($form->_participantId, 'participant');
- }
- $required = FALSE;
+ if ($form->_action & CRM_Core_Action::UPDATE) {
+ if (in_array(CRM_Utils_System::getClassName($form), ['CRM_Event_Form_Participant', 'CRM_Event_Form_Task_Register'])) {
+ $form->_values['line_items'] = CRM_Price_BAO_LineItem::getLineItems($form->_id, 'participant');
}
else {
- $required = TRUE;
+ $form->_values['line_items'] = CRM_Price_BAO_LineItem::getLineItems($form->_participantId, 'participant');
}
+ }
+ $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($priceSetId, NULL, $doNotIncludeExpiredFields);
+ $form->_priceSet = $priceSet[$priceSetId] ?? NULL;
+ $form->_values['fee'] = $form->_priceSet['fields'] ?? NULL;
- $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($priceSetId, $required, $doNotIncludeExpiredFields);
- $form->_priceSet = $priceSet[$priceSetId] ?? NULL;
- $form->_values['fee'] = $form->_priceSet['fields'] ?? NULL;
-
- //get the price set fields participant count.
- //get option count info.
- $form->_priceSet['optionsCountTotal'] = CRM_Price_BAO_PriceSet::getPricesetCount($priceSetId);
- if ($form->_priceSet['optionsCountTotal']) {
- $optionsCountDetails = [];
- if (!empty($form->_priceSet['fields'])) {
- foreach ($form->_priceSet['fields'] as $field) {
- foreach ($field['options'] as $option) {
- $count = CRM_Utils_Array::value('count', $option, 0);
- $optionsCountDetails['fields'][$field['id']]['options'][$option['id']] = $count;
- }
- }
- }
- $form->_priceSet['optionsCountDetails'] = $optionsCountDetails;
- }
-
- //get option max value info.
- $optionsMaxValueTotal = 0;
- $optionsMaxValueDetails = [];
-
+ //get the price set fields participant count.
+ //get option count info.
+ $form->_priceSet['optionsCountTotal'] = CRM_Price_BAO_PriceSet::getPricesetCount($priceSetId);
+ if ($form->_priceSet['optionsCountTotal']) {
+ $optionsCountDetails = [];
if (!empty($form->_priceSet['fields'])) {
foreach ($form->_priceSet['fields'] as $field) {
foreach ($field['options'] as $option) {
- $maxVal = CRM_Utils_Array::value('max_value', $option, 0);
- $optionsMaxValueDetails['fields'][$field['id']]['options'][$option['id']] = $maxVal;
- $optionsMaxValueTotal += $maxVal;
+ $count = $option['count'] ?? 0;
+ $optionsCountDetails['fields'][$field['id']]['options'][$option['id']] = $count;
}
}
}
+ $form->_priceSet['optionsCountDetails'] = $optionsCountDetails;
+ }
+
+ //get option max value info.
+ $optionsMaxValueTotal = 0;
+ $optionsMaxValueDetails = [];
- $form->_priceSet['optionsMaxValueTotal'] = $optionsMaxValueTotal;
- if ($optionsMaxValueTotal) {
- $form->_priceSet['optionsMaxValueDetails'] = $optionsMaxValueDetails;
+ if (!empty($form->_priceSet['fields'])) {
+ foreach ($form->_priceSet['fields'] as $field) {
+ foreach ($field['options'] as $option) {
+ $maxVal = $option['max_value'] ?? 0;
+ $optionsMaxValueDetails['fields'][$field['id']]['options'][$option['id']] = $maxVal;
+ $optionsMaxValueTotal += $maxVal;
+ }
}
- $form->set('priceSet', $form->_priceSet);
}
+ $form->_priceSet['optionsMaxValueTotal'] = $optionsMaxValueTotal;
+ if ($optionsMaxValueTotal) {
+ $form->_priceSet['optionsMaxValueDetails'] = $optionsMaxValueDetails;
+ }
+ $form->set('priceSet', $form->_priceSet);
+
$eventFee = $form->_values['fee'] ?? NULL;
if (!is_array($eventFee) || empty($eventFee)) {
$form->_values['fee'] = [];
@@ -1636,9 +1640,6 @@ private function sendMails($params, $registerByID, array $participantCount) {
foreach ($additionalIDs as $participantID => $contactId) {
if ($participantID == $registerByID) {
- //set as Primary Participant
- $this->assign('isPrimary', 1);
-
$customProfile = CRM_Event_BAO_Event::buildCustomProfile($participantID, $this->_values, NULL, $isTest);
if (count($customProfile)) {
@@ -1647,7 +1648,6 @@ private function sendMails($params, $registerByID, array $participantCount) {
}
}
else {
- $this->assign('isPrimary', 0);
$this->assign('customProfile', NULL);
}
diff --git a/CRM/Event/Form/Registration/Confirm.php b/CRM/Event/Form/Registration/Confirm.php
index 30161be569c1..5d84a66b683a 100644
--- a/CRM/Event/Form/Registration/Confirm.php
+++ b/CRM/Event/Form/Registration/Confirm.php
@@ -866,8 +866,6 @@ public function postProcess() {
foreach ($additionalIDs as $participantID => $contactId) {
$participantNum = 0;
if ($participantID == $registerByID) {
- //set as Primary Participant
- $this->assign('isPrimary', 1);
//build an array of custom profile and assigning it to template.
$customProfile = CRM_Event_BAO_Event::buildCustomProfile($participantID, $this->_values, NULL, $isTest);
@@ -887,8 +885,6 @@ public function postProcess() {
$participantParams = ['id' => $participantID];
CRM_Event_BAO_Participant::getValues($participantParams, $participantValues, $ids);
$this->_values['participant'] = $participantValues[$participantID];
-
- $this->assign('isPrimary', 0);
$this->assign('customProfile', NULL);
//Additional Participant should get only it's payment information
if (!empty($this->_amount)) {
@@ -896,6 +892,7 @@ public function postProcess() {
$params = $this->get('params');
$amount[$participantNum]['label'] = preg_replace('//', '', $params[$participantNum]['amount_level']);
$amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
+ // @todo - unused in core offline receipt template from 5.67. Remove at somepoint
$this->assign('amounts', $amount);
}
if ($this->_lineItem) {
@@ -1015,7 +1012,7 @@ private function processContribution(
// The concept of contributeMode is deprecated. Elsewhere we use the function processBillingAddress() - although
// currently that is only inherited by back-office forms.
if ($form->_contributeMode != 'notify' && empty($params['is_pay_later'])) {
- $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $form->_bltID);
+ $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params);
}
$contribParams['skipLineItem'] = 1;
@@ -1025,12 +1022,6 @@ private function processContribution(
// CRM-11124
CRM_Event_BAO_Participant::createDiscountTrxn($form->_eventId, $contribParams, NULL, CRM_Price_BAO_PriceSet::parseFirstPriceSetValueIDFromParams($params));
- // process soft credit / pcp pages
- if (!empty($params['pcp_made_through_id'])) {
- CRM_Contribute_BAO_ContributionSoft::formatSoftCreditParams($params, $form);
- CRM_Contribute_BAO_ContributionSoft::processSoftContribution($params, $contribution);
- }
-
$transaction->commit();
return $contribution;
@@ -1307,7 +1298,6 @@ public static function testSubmit($params) {
$form->_values['custom_pre_id'] = $params['custom_pre_id'] ?? NULL;
$form->_values['custom_post_id'] = $params['custom_post_id'] ?? NULL;
$form->_values['event'] = $params['event'] ?? NULL;
- $form->_contributeMode = $params['contributeMode'];
$eventParams = ['id' => $params['id']];
CRM_Event_BAO_Event::retrieve($eventParams, $form->_values['event']);
$form->set('registerByID', $params['registerByID']);
diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php
index 1a3e3adc1491..a3614cfba521 100644
--- a/CRM/Event/Form/Registration/Register.php
+++ b/CRM/Event/Form/Registration/Register.php
@@ -189,7 +189,26 @@ public function preProcess() {
// get the participant values from EventFees.php, CRM-4320
if ($this->_allowConfirmation) {
- CRM_Event_Form_EventFees::preProcess($this);
+ $this->eventFeeWrangling($this);
+ }
+ }
+
+ /**
+ * This is previously shared code which is probably of little value.
+ *
+ * @param CRM_Core_Form $form
+ *
+ * @throws \CRM_Core_Exception
+ */
+ private function eventFeeWrangling($form) {
+ $form->_pId = CRM_Utils_Request::retrieve('participantId', 'Positive', $form);
+ $form->_discountId = CRM_Utils_Request::retrieve('discountId', 'Positive', $form);
+
+ //CRM-6907 set event specific currency.
+ if ($this->getEventID() &&
+ ($currency = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $form->_eventId, 'currency'))
+ ) {
+ CRM_Core_Config::singleton()->defaultCurrency = $currency;
}
}
@@ -310,7 +329,7 @@ public function setDefaultValues() {
if ($this->_allowConfirmation) {
$this->_contactId = $contactID;
$this->_discountId = $discountId;
- $forcePayLater = CRM_Utils_Array::value('is_pay_later', $this->_defaults, FALSE);
+ $forcePayLater = $this->_defaults['is_pay_later'] ?? FALSE;
$this->_defaults = array_merge($this->_defaults, CRM_Event_Form_EventFees::setDefaultValues($this));
$this->_defaults['is_pay_later'] = $forcePayLater;
@@ -537,6 +556,10 @@ public function buildQuickForm() {
/**
* Build the radio/text form elements for the amount field
*
+ * @internal function is not currently called by any extentions in our civi
+ * 'universe' and is not supported for such use. Signature has changed & will
+ * change again.
+ *
* @param CRM_Event_Form_Registration_Register $form
* Form object.
* @param bool $required
@@ -547,7 +570,7 @@ public function buildQuickForm() {
*
* @throws \CRM_Core_Exception
*/
- public static function buildAmount(&$form, $required = TRUE, $discountId = NULL, $priceSetID = NULL) {
+ public static function buildAmount($form, $required, $discountId, $priceSetID) {
$feeFields = $form->_values['fee'] ?? NULL;
if (is_array($feeFields)) {
@@ -588,15 +611,8 @@ public static function buildAmount(&$form, $required = TRUE, $discountId = NULL,
$form->add('hidden', 'priceSetId', $priceSetID);
// CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
- $adminFieldVisible = FALSE;
- if (CRM_Core_Permission::check('administer CiviCRM data')) {
- $adminFieldVisible = TRUE;
- }
-
- $hideAdminValues = TRUE;
- if (CRM_Core_Permission::check('edit event participants')) {
- $hideAdminValues = FALSE;
- }
+ $adminFieldVisible = CRM_Core_Permission::check('administer CiviCRM data');
+ $hideAdminValues = !CRM_Core_Permission::check('edit event participants');
foreach ($form->_feeBlock as $field) {
// public AND admin visibility fields are included for back-office registration and back-office change selections
@@ -658,6 +674,7 @@ public static function buildAmount(&$form, $required = TRUE, $discountId = NULL,
}
else {
// Is this reachable?
+ CRM_Core_Error::deprecatedWarning('code believed to be unreachable');
$eventFeeBlockValues = $elements = $elementJS = [];
foreach ($form->_feeBlock as $fee) {
if (is_array($fee)) {
@@ -737,10 +754,10 @@ public static function formatFieldsForOptionFull(&$form) {
}
foreach ($field['options'] as & $option) {
$optId = $option['id'];
- $count = CRM_Utils_Array::value('count', $option, 0);
- $maxValue = CRM_Utils_Array::value('max_value', $option, 0);
- $dbTotalCount = CRM_Utils_Array::value($optId, $recordedOptionsCount, 0);
- $currentTotalCount = CRM_Utils_Array::value($optId, $currentOptionsCount, 0);
+ $count = $option['count'] ?? 0;
+ $maxValue = $option['max_value'] ?? 0;
+ $dbTotalCount = $recordedOptionsCount[$optId] ?? 0;
+ $currentTotalCount = $currentOptionsCount[$optId] ?? 0;
$totalCount = $currentTotalCount + $dbTotalCount;
$isFull = FALSE;
@@ -752,7 +769,7 @@ public static function formatFieldsForOptionFull(&$form) {
$optionFullIds[$optId] = $optId;
if ($field['html_type'] != 'Select') {
if (in_array($optId, $defaultPricefieldIds)) {
- $optionFullTotalAmount += CRM_Utils_Array::value('amount', $option);
+ $optionFullTotalAmount += $option['amount'] ?? 0;
}
}
else {
@@ -971,7 +988,7 @@ public function postProcess() {
$this->set('is_pay_later', $params['is_pay_later']);
// assign pay later stuff
- $this->_params['is_pay_later'] = CRM_Utils_Array::value('is_pay_later', $params, FALSE);
+ $this->_params['is_pay_later'] = $params['is_pay_later'] ?? FALSE;
$this->assign('is_pay_later', $params['is_pay_later']);
$this->assign('pay_later_text', $params['is_pay_later'] ? $this->_values['event']['pay_later_text'] : NULL);
$this->assign('pay_later_receipt', $params['is_pay_later'] ? $this->_values['event']['pay_later_receipt'] : NULL);
diff --git a/CRM/Event/Form/SelfSvcUpdate.php b/CRM/Event/Form/SelfSvcUpdate.php
index 149c88027638..ae9850714737 100644
--- a/CRM/Event/Form/SelfSvcUpdate.php
+++ b/CRM/Event/Form/SelfSvcUpdate.php
@@ -95,6 +95,10 @@ class CRM_Event_Form_SelfSvcUpdate extends CRM_Core_Form {
* @var bool
*/
protected $isBackoffice = FALSE;
+ /**
+ * @var string
+ */
+ protected $_userContext;
/**
* Set variables up before form is built based on participant ID from URL
diff --git a/CRM/Event/ICalendar.php b/CRM/Event/ICalendar.php
index cb1faa778d2f..0d16cfe2ad26 100644
--- a/CRM/Event/ICalendar.php
+++ b/CRM/Event/ICalendar.php
@@ -69,25 +69,7 @@ public static function run() {
$calendar = $template->fetch('CRM/Core/Calendar/GData.tpl');
}
else {
- if (count($info) > 0) {
- $date_min = min(
- array_map(function ($event) {
- return strtotime($event['start_date']);
- }, $info)
- );
- $date_max = max(
- array_map(function ($event) {
- return strtotime($event['end_date'] ?? $event['start_date']);
- }, $info)
- );
- $template->assign('timezones', CRM_Utils_ICalendar::generate_timezones($timezones, $date_min, $date_max));
- }
- else {
- $template->assign('timezones', NULL);
- }
-
- $calendar = $template->fetch('CRM/Core/Calendar/ICal.tpl');
- $calendar = preg_replace('/(?assign('registerClosed', !empty($values['event']['is_online_registration']) && !$isEventOpenForRegistration);
+ $this->assign('registerClosed', !empty($values['event']['is_online_registration']) && !$isEventOpenForRegistration && CRM_Core_Permission::check('register for events'));
$this->assign('allowRegistration', $allowRegistration);
$session = CRM_Core_Session::singleton();
diff --git a/CRM/Event/Page/Tab.php b/CRM/Event/Page/Tab.php
index 7b918028ba6a..295953a30cf1 100644
--- a/CRM/Event/Page/Tab.php
+++ b/CRM/Event/Page/Tab.php
@@ -101,16 +101,8 @@ public function edit() {
}
public function delete() {
- $controller = new CRM_Core_Controller_Simple(
- 'CRM_Event_Form_Participant',
- ts('Delete Participant'),
- $this->_action
- );
-
- $controller->setEmbedded(TRUE);
- $controller->set('id', $this->_id);
- $controller->set('cid', $this->_contactId);
- $controller->run();
+ CRM_Core_Error::deprecatedFunctionWarning('use civicrm/participant/delete / CRM_Event_Form_Participant_Delete');
+ CRM_Utils_System::redirect('civicrm/participant/delete', ['id' => CRM_Utils_Request::retrieveValue('id', NULL, TRUE), 'reset' => 1]);
}
public function preProcess() {
diff --git a/CRM/Event/PseudoConstant.php b/CRM/Event/PseudoConstant.php
index b8bd9f11a62b..8a67ed916d09 100644
--- a/CRM/Event/PseudoConstant.php
+++ b/CRM/Event/PseudoConstant.php
@@ -16,59 +16,10 @@
*/
/**
- * This class holds all the Pseudo constants that are specific to Event. This avoids
- * polluting the core class and isolates the Event
+ * @deprecated functions. Use the API instead.
*/
class CRM_Event_PseudoConstant extends CRM_Core_PseudoConstant {
- /**
- * Event
- *
- * @var array
- */
- private static $event;
-
- /**
- * Participant Status
- *
- * @var array
- */
- private static $participantStatus;
-
- /**
- * Participant Role
- *
- * @var array
- */
- private static $participantRole;
-
- /**
- * Participant Listing
- * @var array
- * @deprecated
- */
- private static $participantListing;
-
- /**
- * Event Type.
- *
- * @var array
- */
- private static $eventType;
-
- /**
- * Event template titles
- * @var array
- */
- private static $eventTemplates;
-
- /**
- * Personal campaign pages
- * @var array
- * @deprecated
- */
- private static $pcPage;
-
/**
* Get all events
*
@@ -81,28 +32,16 @@ class CRM_Event_PseudoConstant extends CRM_Core_PseudoConstant {
* array of all events if any
*/
public static function event($id = NULL, $all = FALSE, $condition = NULL) {
- $key = "{$id}_{$all}_{$condition}";
-
- if (!isset(self::$event[$key])) {
- self::$event[$key] = [];
- }
-
- if (!self::$event[$key]) {
- CRM_Core_PseudoConstant::populate(self::$event[$key],
- 'CRM_Event_DAO_Event',
- $all, 'title', 'is_active', $condition, NULL
- );
- }
+ $options = [];
+ CRM_Core_PseudoConstant::populate($options,
+ 'CRM_Event_DAO_Event',
+ $all, 'title', 'is_active', $condition, NULL
+ );
if ($id) {
- if (array_key_exists($id, self::$event[$key])) {
- return self::$event[$key][$id];
- }
- else {
- return NULL;
- }
+ return $options[$id] ?? NULL;
}
- return self::$event[$key];
+ return $options;
}
/**
@@ -119,26 +58,17 @@ public static function event($id = NULL, $all = FALSE, $condition = NULL) {
* @return array|string
* array reference of all participant statuses if any, or single value if $id was passed
*/
- public static function &participantStatus($id = NULL, $cond = NULL, $retColumn = 'name') {
- if (self::$participantStatus === NULL) {
- self::$participantStatus = [];
- }
-
- $index = $cond ?: 'No Condition';
- $index = "{$index}_{$retColumn}";
- if (empty(self::$participantStatus[$index])) {
- self::$participantStatus[$index] = [];
- CRM_Core_PseudoConstant::populate(self::$participantStatus[$index],
- 'CRM_Event_DAO_ParticipantStatusType',
- FALSE, $retColumn, 'is_active', $cond, 'weight'
- );
- }
+ public static function participantStatus($id = NULL, $cond = NULL, $retColumn = 'name') {
+ $statuses = [];
+ CRM_Core_PseudoConstant::populate($statuses,
+ 'CRM_Event_DAO_ParticipantStatusType',
+ FALSE, $retColumn, 'is_active', $cond, 'weight'
+ );
if ($id) {
- return self::$participantStatus[$index][$id];
+ return $statuses[$id] ?? NULL;
}
-
- return self::$participantStatus[$index];
+ return $statuses;
}
/**
@@ -161,13 +91,9 @@ public static function participantStatusClassOptions() {
* @return array
* Array of status classes, keyed by status type
*/
- public static function &participantStatusClass() {
- static $statusClasses = NULL;
-
- if ($statusClasses === NULL) {
- self::populate($statusClasses, 'CRM_Event_DAO_ParticipantStatusType', TRUE, 'class');
- }
-
+ public static function participantStatusClass() {
+ $statusClasses = [];
+ self::populate($statusClasses, 'CRM_Event_DAO_ParticipantStatusType', TRUE, 'class');
return $statusClasses;
}
@@ -182,26 +108,14 @@ public static function &participantStatusClass() {
* @return array|string
* array reference of all participant roles if any
*/
- public static function &participantRole($id = NULL, $cond = NULL) {
- $index = $cond ?: 'No Condition';
- if (empty(self::$participantRole[$index])) {
- self::$participantRole[$index] = [];
-
- $condition = NULL;
-
- if ($cond) {
- $condition = "AND $cond";
- }
-
- self::$participantRole[$index] = CRM_Core_OptionGroup::values('participant_role', FALSE, FALSE,
- FALSE, $condition
- );
- }
+ public static function participantRole($id = NULL, $cond = NULL) {
+ $condition = empty($cond) ? NULL : "AND $cond";
+ $options = CRM_Core_OptionGroup::values('participant_role', FALSE, FALSE, FALSE, $condition);
if ($id) {
- return self::$participantRole[$index][$id];
+ return $options[$id] ?? NULL;
}
- return self::$participantRole[$index];
+ return $options;
}
/**
@@ -212,18 +126,14 @@ public static function &participantRole($id = NULL, $cond = NULL) {
* @return array|string
* array reference of all participant listings if any
*/
- public static function &participantListing($id = NULL) {
+ public static function participantListing($id = NULL) {
CRM_Core_Error::deprecatedFunctionWarning('Function participantListing will be removed');
- if (!self::$participantListing) {
- self::$participantListing = [];
- self::$participantListing = CRM_Core_OptionGroup::values('participant_listing');
- }
+ $options = CRM_Core_OptionGroup::values('participant_listing');
if ($id) {
- return self::$participantListing[$id];
+ return $options[$id];
}
-
- return self::$participantListing;
+ return $options;
}
/**
@@ -234,17 +144,13 @@ public static function &participantListing($id = NULL) {
* @return array|string
* array reference of all event types.
*/
- public static function &eventType($id = NULL) {
- if (!self::$eventType) {
- self::$eventType = [];
- self::$eventType = CRM_Core_OptionGroup::values('event_type');
- }
+ public static function eventType($id = NULL) {
+ $options = CRM_Core_OptionGroup::values('event_type');
if ($id) {
- return self::$eventType[$id];
+ return $options[$id] ?? NULL;
}
-
- return self::$eventType;
+ return $options;
}
/**
@@ -257,21 +163,20 @@ public static function &eventType($id = NULL) {
*
* @deprecated Use the API instead
*/
- public static function &eventTemplates($id = NULL) {
+ public static function eventTemplates($id = NULL) {
CRM_Core_Error::deprecatedFunctionWarning('Use the api');
- if (!self::$eventTemplates) {
- CRM_Core_PseudoConstant::populate(self::$eventTemplates,
- 'CRM_Event_DAO_Event',
- FALSE,
- 'template_title',
- 'is_active',
- 'is_template = 1'
- );
- }
+ $options = [];
+ CRM_Core_PseudoConstant::populate($options,
+ 'CRM_Event_DAO_Event',
+ FALSE,
+ 'template_title',
+ 'is_active',
+ 'is_template = 1'
+ );
if ($id) {
- return self::$eventTemplates[$id];
+ return $options[$id];
}
- return self::$eventTemplates;
+ return $options;
}
/**
@@ -295,18 +200,17 @@ public static function flush($name = 'cache') {
* @return array
* array reference of all pcp if any
*/
- public static function &pcPage($id = NULL) {
+ public static function pcPage($id = NULL) {
CRM_Core_Error::deprecatedFunctionWarning('Function pcPage will be removed');
- if (!self::$pcPage) {
- CRM_Core_PseudoConstant::populate(self::$pcPage,
- 'CRM_PCP_DAO_PCP',
- FALSE, 'title'
- );
- }
+ $options = [];
+ CRM_Core_PseudoConstant::populate($options,
+ 'CRM_PCP_DAO_PCP',
+ FALSE, 'title'
+ );
if ($id) {
- return self::$pcPage[$id] ?? NULL;
+ return $options[$id] ?? NULL;
}
- return self::$pcPage;
+ return $options;
}
}
diff --git a/CRM/Event/Selector/Search.php b/CRM/Event/Selector/Search.php
index 9000dbbf90be..0b7c9273605f 100644
--- a/CRM/Event/Selector/Search.php
+++ b/CRM/Event/Selector/Search.php
@@ -200,7 +200,7 @@ public static function &links($qfKey = NULL, $context = NULL, $compContext = NUL
if ($compContext) {
$extraParams .= "&compContext={$compContext}";
}
- elseif ($context == 'search') {
+ elseif ($context === 'search') {
$extraParams .= '&compContext=participant';
}
@@ -226,8 +226,8 @@ public static function &links($qfKey = NULL, $context = NULL, $compContext = NUL
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
- 'url' => 'civicrm/contact/view/participant',
- 'qs' => 'reset=1&action=delete&id=%%id%%&cid=%%cid%%&context=%%cxt%%' . $extraParams,
+ 'url' => 'civicrm/participant/delete',
+ 'qs' => 'reset=1&id=%%id%%' . $extraParams,
'title' => ts('Delete Participation'),
'weight' => 100,
],
@@ -337,16 +337,6 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
$row['campaign'] = $allCampaigns[$result->participant_campaign_id] ?? NULL;
$row['campaign_id'] = $result->participant_campaign_id;
- // gross hack to show extra information for pending status
- $statusClass = NULL;
- if ((isset($row['participant_status_id'])) &&
- ($statusId = array_search($row['participant_status_id'], $statusTypes))
- ) {
- $statusClass = $statusClasses[$statusId];
- }
-
- $row['showConfirmUrl'] = $statusClass == 'Pending';
-
if (!empty($row['participant_is_test'])) {
$row['participant_status'] = CRM_Core_TestEntity::appendTestText($row['participant_status']);
}
diff --git a/CRM/Event/Tokens.php b/CRM/Event/Tokens.php
index e7b9436f1cee..ed4f80665606 100644
--- a/CRM/Event/Tokens.php
+++ b/CRM/Event/Tokens.php
@@ -177,10 +177,9 @@ protected function getEventTokenValues(int $eventID = NULL): array {
if (!Civi::cache('metadata')->has($cacheKey)) {
$event = Event::get($this->checkPermissions)->addWhere('id', '=', $eventID)
->setSelect(array_merge([
- 'loc_block_id.address_id.street_address',
- 'loc_block_id.address_id.city',
+ 'loc_block_id.address_id.*',
'loc_block_id.address_id.state_province_id:label',
- 'loc_block_id.address_id.postal_code',
+ 'loc_block_id.address_id.country_id:label',
'loc_block_id.email_id.email',
'loc_block_id.email_2_id.email',
'loc_block_id.phone_id.phone',
@@ -192,6 +191,9 @@ protected function getEventTokenValues(int $eventID = NULL): array {
'loc_block_id.phone_2_id.phone_ext',
'loc_block_id.phone_2_id.phone_type_id:label',
'is_show_location:label',
+ 'allow_selfcancelxfer',
+ 'allow_selfcancelxfer:label',
+ 'selfcancelxfer_time',
'is_public:label',
'is_share',
'is_share:label',
@@ -205,12 +207,13 @@ protected function getEventTokenValues(int $eventID = NULL): array {
'custom.*',
], $this->getExposedFields()))
->execute()->first();
- $tokens['location']['text/plain'] = \CRM_Utils_Address::format([
- 'street_address' => $event['loc_block_id.address_id.street_address'],
- 'city' => $event['loc_block_id.address_id.city'],
- 'state_province' => $event['loc_block_id.address_id.state_province_id:label'],
- 'postal_code' => $event['loc_block_id.address_id.postal_code'],
- ]);
+ $addressValues = ['address_name' => $event['loc_block_id.address_id.name']];
+ foreach ($event as $key => $value) {
+ if (strpos($key, 'loc_block_id.address_id.') === 0) {
+ $addressValues[str_replace('loc_block_id.address_id.', '', $key)] = $value;
+ }
+ }
+ $tokens['location']['text/plain'] = \CRM_Utils_Address::format($addressValues);
$tokens['info_url']['text/html'] = \CRM_Utils_System::url('civicrm/event/info', 'reset=1&id=' . $eventID, TRUE, NULL, FALSE, TRUE);
$tokens['registration_url']['text/html'] = \CRM_Utils_System::url('civicrm/event/register', 'reset=1&id=' . $eventID, TRUE, NULL, FALSE, TRUE);
$tokens['start_date']['text/html'] = !empty($event['start_date']) ? new DateTime($event['start_date']) : '';
@@ -263,6 +266,8 @@ protected function getExposedFields(): array {
'description',
'is_show_location',
'is_public',
+ 'allow_selfcancelxfer',
+ 'selfcancelxfer_time',
'confirm_email_text',
'is_monetary',
'fee_label',
@@ -285,6 +290,8 @@ protected function getTokenMetadataOverrides(): array {
'is_public' => ['audience' => 'sysadmin'],
'is_show_location' => ['audience' => 'sysadmin'],
'is_monetary' => ['audience' => 'sysadmin'],
+ 'allow_selfcancelxfer' => ['audience' => 'sysadmin'],
+ 'selfcancelxfer_time' => ['audience' => 'sysadmin'],
];
}
diff --git a/CRM/Event/WorkflowMessage/EventExamples.php b/CRM/Event/WorkflowMessage/EventExamples.php
index dbbdb6f589c3..9de84306fcae 100644
--- a/CRM/Event/WorkflowMessage/EventExamples.php
+++ b/CRM/Event/WorkflowMessage/EventExamples.php
@@ -1,5 +1,6 @@
$priceSet['is_multiple_registrations'],
'is_primary' => TRUE,
'price_set_id' => $priceSet['id'],
+ 'is_partially_paid' => FALSE,
+ ];
+ yield [
+ 'name' => 'workflow/' . $workflow . '/' . 'price_set_' . $priceSet['name'] . '_partially_paid',
+ 'title' => ts('Partially Paid Registration') . ($priceSet['is_multiple_registrations'] ? ' ' . ts('primary participant') : '') . ' : ' . $priceSet['title'],
+ 'tags' => ['preview'],
+ 'workflow' => $workflow,
+ 'is_show_line_items' => !$priceSet['is_quick_config'],
+ 'event_id' => $priceSet['event_id'],
+ 'is_multiple_registrations' => $priceSet['is_multiple_registrations'],
+ 'is_primary' => TRUE,
+ 'price_set_id' => $priceSet['id'],
+ 'is_partially_paid' => TRUE,
];
if ($priceSet['is_multiple_registrations']) {
yield [
@@ -56,6 +72,7 @@ public function getExamples(): iterable {
'is_multiple_registrations' => $priceSet['is_multiple_registrations'],
'is_primary' => FALSE,
'price_set_id' => $priceSet['id'],
+ 'is_partially_paid' => FALSE,
];
}
}
@@ -87,6 +104,7 @@ public function build(array &$example): void {
* @throws \Civi\API\Exception\UnauthorizedException
*/
private function addExampleData(GenericWorkflowMessage $messageTemplate, array $example): void {
+ $this->define('Event', 'event_' . $example['event_id'], ['id' => $example['event_id']]);
$messageTemplate->setContact(\Civi\Test::example('entity/Contact/Barb'));
$messageTemplate->setEventID($example['event_id']);
$isPrimary = $example['is_primary'];
@@ -112,10 +130,18 @@ private function addExampleData(GenericWorkflowMessage $messageTemplate, array $
$contribution['total_amount'] = $mockOrder->getTotalAmount();
$contribution['tax_amount'] = $mockOrder->getTotalTaxAmount() ? round($mockOrder->getTotalTaxAmount(), 2) : 0;
$contribution['tax_exclusive_amount'] = $contribution['total_amount'] - $contribution['tax_amount'];
+ $contribution['address_id.name'] = 'Barbara Johnson';
+ $contribution['address_id.display'] = '790L Lincoln St S
+Baltimore, New York 10545
+United States';
+ $contribution['is_pay_later'] = $example['is_partially_paid'] && $this->lookup('event_' . $example['event_id'], 'is_pay_later');
+ $contribution['paid_amount'] = $example['is_partially_paid'] ? $contribution['total_amount'] / 2 : 0;
+ $contribution['balance_amount'] = $contribution['total_amount'] - $contribution['paid_amount'];
$messageTemplate->setContribution($contribution);
$messageTemplate->setOrder($mockOrder);
$messageTemplate->setParticipantContacts($participantContacts);
- $messageTemplate->setParticipant(['id' => $isPrimary ? $primaryParticipantID : $otherParticipantID, 'registered_by_id' => $isPrimary ? NULL : $primaryParticipantID, 'register_date' => date('Y-m-d')]);
+ $roleID = Event::get(FALSE)->addWhere('id', '=', $example['event_id'])->addSelect('default_role_id')->execute()->first()['default_role_id'];
+ $messageTemplate->setParticipant(['id' => $isPrimary ? $primaryParticipantID : $otherParticipantID, 'registered_by_id' => $isPrimary ? NULL : $primaryParticipantID, 'register_date' => date('Y-m-d'), 'role_id' => $roleID]);
}
/**
diff --git a/CRM/Event/WorkflowMessage/EventOfflineReceipt.php b/CRM/Event/WorkflowMessage/EventOfflineReceipt.php
index 38ba48d1e457..1fbec19de263 100644
--- a/CRM/Event/WorkflowMessage/EventOfflineReceipt.php
+++ b/CRM/Event/WorkflowMessage/EventOfflineReceipt.php
@@ -10,6 +10,7 @@
*/
use Civi\WorkflowMessage\GenericWorkflowMessage;
+use Civi\WorkflowMessage\Traits\CustomFieldTrait;
/**
* Receipt sent when confirming a back office participation record.
@@ -22,7 +23,72 @@
class CRM_Event_WorkflowMessage_EventOfflineReceipt extends GenericWorkflowMessage {
use CRM_Event_WorkflowMessage_ParticipantTrait;
use CRM_Contribute_WorkflowMessage_ContributionTrait;
+ use CustomFieldTrait;
public const WORKFLOW = 'event_offline_receipt';
+ /**
+ * Viewable custom fields for the primary participant.
+ *
+ * This array is in the format
+ *
+ * ['customGroupLabel' => [['customFieldLabel' => 'customFieldValue'], ['customFieldLabel' => 'customFieldValue']]
+ *
+ * It is only added for the primary participant (which reflects historical
+ * form behaviour) and only fields were the group has is_public = TRUE
+ * and the field has is_view = FALSE. Fields are restricted to
+ * those viewable by the logged in user (reflecting the fact this
+ * is historically triggered by a back office user form submission
+ * and also preventing using an email to see acl-blocked custom fields).
+ *
+ * @var array
+ *
+ * @scope tplParams as customGroup
+ */
+ public $customFields;
+
+ /**
+ * Get the custom fields for display for the participant, if not primary.
+ *
+ * @return array
+ * @throws \CRM_Core_Exception
+ */
+ public function getCustomFields(): array {
+ // Non-primary custom field info can't be gathered on the back office
+ // form so historically it has not shown up. This keeps that behaviour
+ // (although a future person could probably change it if they wanted
+ // to think through any potential downsides.
+ if (!$this->getIsPrimary()) {
+ return [];
+ }
+ $participant = $this->getParticipant();
+ // We re-filter the custom fields to eliminate any custom groups
+ // not associated with the role, event_id etc. Realistically participants
+ // should not have such data. But, out of caution we do this becasue
+ // historical code did.
+ $filters = [
+ 'ParticipantRole' => $participant['role_id'],
+ 'ParticipantEventName' => $participant['event_id'],
+ 'ParticipantEventType' => $participant['event_id.event_type_id'],
+ ];
+ return $this->getCustomFieldDisplay($participant, 'Participant', $filters);
+ }
+
+ /**
+ * Get the participant fields we need to load.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ protected function getFieldsToLoadForParticipant(): array {
+ $fields = ['registered_by_id', 'role_id', 'event_id', 'event_id.event_type_id'];
+ // Request the relevant custom fields. This list is
+ // restricted by view-ability but we don't have the information
+ // at this point to filter by the finer tuned entity extends information
+ // which relies on us knowing role etc.
+ foreach ($this->getFilteredCustomFields('Participant') as $field) {
+ $fields[] = $field['custom_group_id.name'] . '.' . $field['name'];
+ }
+ return $fields;
+ }
+
}
diff --git a/CRM/Event/WorkflowMessage/ParticipantTrait.php b/CRM/Event/WorkflowMessage/ParticipantTrait.php
index 92d5409c3a55..22c02d19265f 100644
--- a/CRM/Event/WorkflowMessage/ParticipantTrait.php
+++ b/CRM/Event/WorkflowMessage/ParticipantTrait.php
@@ -37,6 +37,19 @@ trait CRM_Event_WorkflowMessage_ParticipantTrait {
*/
public $isPrimary;
+ /**
+ * Should a participant count column be shown.
+ *
+ * This would be true if there is a line item on the receipt
+ * with more than one participant in it. Otherwise it's confusing to
+ * show.
+ *
+ * @var bool
+ *
+ * @scope tplParams as isShowParticipantCount
+ */
+ public $isShowParticipantCount;
+
/**
* @var int
*
@@ -152,7 +165,26 @@ public function getPrimaryParticipantID(): int {
}
/**
- * Set contribution object.
+ * It is a good idea to show the participant count column.
+ *
+ * This would be true if there is a line item on the receipt
+ * with more than one participant in it. Otherwise it's confusing to
+ * show.
+ *
+ * @return bool
+ * @throws \CRM_Core_Exception
+ */
+ public function getIsShowParticipantCount(): bool {
+ foreach ($this->getLineItems() as $lineItem) {
+ if ((int) $lineItem['participant_count'] > 1) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ /**
+ * Set participant object.
*
* @param array $participant
*
@@ -179,11 +211,18 @@ public function getParticipant(): array {
if (!$this->participant) {
$this->participant = Participant::get(FALSE)
->addWhere('id', '=', $this->participantID)
- ->addSelect('registered_by_id')->execute()->first();
+ ->setSelect($this->getFieldsToLoadForParticipant())->execute()->first();
}
return $this->participant;
}
+ /**
+ * Get the participant fields we need to load.
+ */
+ protected function getFieldsToLoadForParticipant(): array {
+ return ['registered_by_id'];
+ }
+
/**
* Get the line items and tax information indexed by participant.
*
diff --git a/CRM/Event/xml/Menu/Event.xml b/CRM/Event/xml/Menu/Event.xml
index fad961b09140..032212ffd8db 100644
--- a/CRM/Event/xml/Menu/Event.xml
+++ b/CRM/Event/xml/Menu/Event.xml
@@ -270,6 +270,12 @@
CRM_Event_Page_Tab
4
+ -
+
civicrm/participant/delete
+ CRM_Event_Form_Participant_Delete
+ delete in CiviEvent
+ 4
+
-
civicrm/ajax/eventFee
CRM_Event_Page_AJAX::eventFee
diff --git a/CRM/Extension/Info.php b/CRM/Extension/Info.php
index 2546da5c5c67..6edd859057a7 100644
--- a/CRM/Extension/Info.php
+++ b/CRM/Extension/Info.php
@@ -261,8 +261,11 @@ public function parse($info) {
// and deeper into arrays. An exception for URLS section, since
// we want them in special format.
foreach ($info as $attr => $val) {
- if (count($val->children()) == 0) {
- $this->$attr = trim((string) $val);
+ if (!property_exists($this, $attr)) {
+ continue;
+ }
+ if (!count($val->children())) {
+ $this->$attr = is_array($this->$attr) ? [] : trim((string) $val);
}
elseif ($attr === 'urls') {
$this->urls = [];
@@ -335,7 +338,7 @@ public function parse($info) {
public function filterRequirements($requirements) {
$filtered = [];
$compatInfo = CRM_Extension_System::getCompatibilityInfo();
- foreach ($requirements->ext as $ext) {
+ foreach ($requirements->ext ?? [] as $ext) {
$ext = (string) $ext;
if (empty($compatInfo[$ext]['obsolete'])) {
$filtered[] = $ext;
diff --git a/CRM/Extension/Mapper.php b/CRM/Extension/Mapper.php
index 8f0747387e9c..62fdd94ede8a 100644
--- a/CRM/Extension/Mapper.php
+++ b/CRM/Extension/Mapper.php
@@ -383,7 +383,7 @@ public function getActiveModuleUrls() {
public function getKeysByPath($pattern) {
$keys = [];
- if (CRM_Utils_String::endsWith($pattern, '*')) {
+ if (str_ends_with($pattern, '*')) {
$prefix = rtrim($pattern, '*');
foreach ($this->container->getKeys() as $key) {
$path = CRM_Utils_File::addTrailingSlash($this->container->getPath($key));
diff --git a/CRM/Financial/BAO/FinancialType.php b/CRM/Financial/BAO/FinancialType.php
index a8a47383fe8f..458114015022 100644
--- a/CRM/Financial/BAO/FinancialType.php
+++ b/CRM/Financial/BAO/FinancialType.php
@@ -347,6 +347,8 @@ public static function buildPermissionedClause(string $component): string {
/**
* Function to check if lineitems present in a contribution have permissioned FTs.
*
+ * @deprecated since 5.68 not part of core - to be handled within financialacls extension
+ *
* @param int $id
* contribution id
* @param string $op
diff --git a/CRM/Financial/BAO/Order.php b/CRM/Financial/BAO/Order.php
index b2d0931b7fa3..ca74b7d44c94 100644
--- a/CRM/Financial/BAO/Order.php
+++ b/CRM/Financial/BAO/Order.php
@@ -78,6 +78,18 @@ class CRM_Financial_BAO_Order {
*/
protected $overridableFinancialTypeID;
+ private $isExcludeExpiredFields = FALSE;
+
+ /**
+ * @param bool $isExcludeExpiredFields
+ *
+ * @return CRM_Financial_BAO_Order
+ */
+ public function setIsExcludeExpiredFields(bool $isExcludeExpiredFields): CRM_Financial_BAO_Order {
+ $this->isExcludeExpiredFields = $isExcludeExpiredFields;
+ return $this;
+ }
+
/**
* Get overridable financial type id.
*
@@ -658,8 +670,30 @@ public function getPriceFieldMetadata(int $id): array {
*
* @param array $metadata
*/
- protected function setPriceFieldMetadata($metadata) {
+ protected function setPriceFieldMetadata(array $metadata): void {
+ foreach ($metadata as $index => $priceField) {
+ if ($this->isExcludeExpiredFields && !empty($priceField['active_on']) && time() < strtotime($priceField['active_on'])) {
+ unset($metadata[$index]);
+ }
+ elseif ($this->isExcludeExpiredFields && !empty($priceField['expire_on']) && strtotime($priceField['expire_on']) < time()) {
+ unset($metadata[$index]);
+ }
+ elseif (!empty($priceField['options'])) {
+ foreach ($priceField['options'] as $optionID => $option) {
+ if (!empty($option['membership_type_id'])) {
+ $membershipType = CRM_Member_BAO_MembershipType::getMembershipType((int) $option['membership_type_id']);
+ $metadata[$index]['options'][$optionID]['auto_renew'] = (int) $membershipType['auto_renew'];
+ if ($membershipType['auto_renew'] && empty($this->priceSetMetadata['auto_renew_membership_field'])) {
+ // Quick form layer supports one auto-renew membership type per price set. If we
+ // want more for any reason we can add another array property.
+ $this->priceSetMetadata['auto_renew_membership_field'] = (int) $option['price_field_id'];
+ }
+ }
+ }
+ }
+ }
$this->priceFieldMetadata = $metadata;
+
if ($this->getForm()) {
CRM_Utils_Hook::buildAmount($this->form->getFormContext(), $this->form, $this->priceFieldMetadata);
}
@@ -668,18 +702,18 @@ protected function setPriceFieldMetadata($metadata) {
/**
* Get the metadata for the fields in the price set.
*
+ * @return array
+ * @throws \CRM_Core_Exception
* @internal use in tested core code only.
*
- * @return array
*/
public function getPriceSetMetadata(): array {
if (empty($this->priceSetMetadata)) {
- $priceSetMetadata = CRM_Price_BAO_PriceSet::getCachedPriceSetDetail($this->getPriceSetID());
- // @todo - make sure this is an array - commented out for now as this PR is against the rc.
- // $priceSetMetadata['extends'] = explode(CRM_Core_DAO::VALUE_SEPARATOR, $priceSetMetadata['extends']);
- $this->setPriceFieldMetadata($priceSetMetadata['fields']);
- unset($priceSetMetadata['fields']);
- $this->priceSetMetadata = $priceSetMetadata;
+ $this->priceSetMetadata = CRM_Price_BAO_PriceSet::getCachedPriceSetDetail($this->getPriceSetID());
+ $this->priceSetMetadata['id'] = $this->getPriceSetID();
+ $this->priceSetMetadata['auto_renew_membership_field'] = NULL;
+ $this->setPriceFieldMetadata($this->priceSetMetadata['fields']);
+ unset($this->priceSetMetadata['fields']);
}
return $this->priceSetMetadata;
}
@@ -688,8 +722,9 @@ public function isMembershipPriceSet() {
if (!CRM_Core_Component::isEnabled('CiviMember')) {
return FALSE;
}
- $extends = explode(CRM_Core_DAO::VALUE_SEPARATOR, $this->getPriceSetMetadata()['extends']);
- return in_array(CRM_Core_Component::getComponentID('CiviMember'), $extends, FALSE);
+ // Access the property if set, to avoid a potential loop when the hook is called.
+ $priceSetMetadata = $this->priceSetMetadata ?: $this->getPriceSetMetadata();
+ return in_array(CRM_Core_Component::getComponentID('CiviMember'), $priceSetMetadata['extends'], FALSE);
}
/**
@@ -913,6 +948,7 @@ protected function calculateLineItems(): array {
$lineItem['tax_amount'] = ($taxRate / 100) * $lineItem['line_total'];
}
$lineItem['title'] = $this->getLineItemTitle($lineItem);
+ $lineItem['line_total_inclusive'] = $lineItem['line_total'] + $lineItem['tax_amount'];
}
return $lineItems;
}
@@ -1040,6 +1076,7 @@ public function setLineItem(array $lineItem, $index): void {
}
$lineItem['tax_rate'] = $this->getTaxRate($lineItem['financial_type_id']);
$lineItem['tax_amount'] = ($lineItem['tax_rate'] / 100) * $lineItem['line_total'];
+ $lineItem['line_total_inclusive'] = $lineItem['tax_amount'] + $lineItem['line_total'];
}
if (!empty($lineItem['membership_type_id'])) {
$lineItem['entity_table'] = 'civicrm_membership';
diff --git a/CRM/Financial/BAO/Payment.php b/CRM/Financial/BAO/Payment.php
index b9643f824389..82da1f25805b 100644
--- a/CRM/Financial/BAO/Payment.php
+++ b/CRM/Financial/BAO/Payment.php
@@ -223,7 +223,7 @@ public static function create(array $params): CRM_Financial_DAO_FinancialTrxn {
// change status to refunded.
self::updateContributionStatus($contribution['id'], 'Refunded');
}
- CRM_Contribute_BAO_Contribution::recordPaymentActivity($params['contribution_id'], CRM_Utils_Array::value('participant_id', $params), $params['total_amount'], $trxn->currency, $trxn->trxn_date);
+ CRM_Contribute_BAO_Contribution::recordPaymentActivity($params['contribution_id'], $params['participant_id'] ?? NULL, $params['total_amount'], $trxn->currency, $trxn->trxn_date);
return $trxn;
}
@@ -463,7 +463,6 @@ public static function filterUntestedTemplateVariables($params) {
// and assign. Note we should update the tpl to use {if $billingName}
// and ditch contributeMode - although it might need to be deprecated rather than removed.
$todoParams = [
- 'contributeMode',
'billingName',
'address',
'credit_card_type',
diff --git a/CRM/Financial/Form/BatchTransaction.php b/CRM/Financial/Form/BatchTransaction.php
index dee4265809c0..08870c4883e9 100644
--- a/CRM/Financial/Form/BatchTransaction.php
+++ b/CRM/Financial/Form/BatchTransaction.php
@@ -38,7 +38,7 @@ class CRM_Financial_Form_BatchTransaction extends CRM_Contribute_Form_Search {
public function preProcess() {
// This reuses some styles from search forms
CRM_Core_Resources::singleton()->addStyleFile('civicrm', 'css/searchForm.css', 1, 'html-header');
- self::$_entityID = CRM_Utils_Request::retrieve('bid', 'Positive') ? CRM_Utils_Request::retrieve('bid', 'Positive') : CRM_Utils_Array::value('batch_id', $_POST);
+ self::$_entityID = CRM_Utils_Request::retrieve('bid', 'Positive') ?: $_POST['batch_id'] ?? NULL;
$this->assign('entityID', self::$_entityID);
if (isset(self::$_entityID)) {
$this->_batchStatusId = CRM_Core_DAO::getFieldValue('CRM_Batch_BAO_Batch', self::$_entityID, 'status_id');
diff --git a/CRM/Financial/Form/FinancialAccount.php b/CRM/Financial/Form/FinancialAccount.php
index 7878fadb8e4b..727c2335e345 100644
--- a/CRM/Financial/Form/FinancialAccount.php
+++ b/CRM/Financial/Form/FinancialAccount.php
@@ -206,7 +206,7 @@ public function postProcess() {
'is_tax',
'is_default',
] as $field) {
- $params[$field] = CRM_Utils_Array::value($field, $params, FALSE);
+ $params[$field] = $params[$field] ?? FALSE;
}
$financialAccount = CRM_Financial_BAO_FinancialAccount::writeRecord($params);
CRM_Core_Session::setStatus(ts('The Financial Account \'%1\' has been saved.', [1 => $financialAccount->name]), ts('Saved'), 'success');
diff --git a/CRM/Financial/Form/FinancialBatch.php b/CRM/Financial/Form/FinancialBatch.php
index 7ab2c650826e..fbcf4bb3c784 100644
--- a/CRM/Financial/Form/FinancialBatch.php
+++ b/CRM/Financial/Form/FinancialBatch.php
@@ -77,11 +77,6 @@ public function buildQuickForm() {
'name' => ts('Save'),
'isDefault' => TRUE,
],
- [
- 'type' => 'next',
- 'name' => ts('Save and New'),
- 'subName' => 'new',
- ],
[
'type' => 'cancel',
'name' => ts('Cancel'),
diff --git a/CRM/Financial/Form/FinancialType.php b/CRM/Financial/Form/FinancialType.php
index 2b6f1079dde3..4521ca3afc41 100644
--- a/CRM/Financial/Form/FinancialType.php
+++ b/CRM/Financial/Form/FinancialType.php
@@ -122,7 +122,7 @@ public function postProcess() {
'is_reserved',
'is_deductible',
] as $field) {
- $params[$field] = CRM_Utils_Array::value($field, $params, FALSE);
+ $params[$field] = $params[$field] ?? FALSE;
}
$financialType = civicrm_api3('FinancialType', 'create', $params);
if ($this->_action & CRM_Core_Action::UPDATE) {
diff --git a/CRM/Financial/Page/BatchTransaction.php b/CRM/Financial/Page/BatchTransaction.php
index 381e5cdf21ef..39f5606a2e5a 100644
--- a/CRM/Financial/Page/BatchTransaction.php
+++ b/CRM/Financial/Page/BatchTransaction.php
@@ -63,11 +63,13 @@ public function &links() {
'url' => 'civicrm/contact/view/contribution',
'qs' => 'reset=1&id=%%contid%%&cid=%%cid%%&action=view&context=contribution&selectedChild=contribute',
'title' => ts('View Contribution'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::VIEW),
],
'remove' => [
'name' => ts('Remove'),
'title' => ts('Remove Transaction'),
'extra' => 'onclick = "removeFromBatch(%%id%%);"',
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
];
}
diff --git a/CRM/Friend/BAO/Friend.php b/CRM/Friend/BAO/Friend.php
index 6e97730cce81..2a0945ea4d9a 100644
--- a/CRM/Friend/BAO/Friend.php
+++ b/CRM/Friend/BAO/Friend.php
@@ -320,7 +320,7 @@ public static function sendMail($contactID, &$values) {
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->is_active = $params['is_active'] ?? FALSE;
$friendDAO->save();
return $friendDAO;
diff --git a/CRM/Friend/Form/Contribute.php b/CRM/Friend/Form/Contribute.php
index 0a85b96a1ada..5aa5cbcdd7ba 100644
--- a/CRM/Friend/Form/Contribute.php
+++ b/CRM/Friend/Form/Contribute.php
@@ -95,7 +95,7 @@ public function postProcess() {
$formValues['entity_table'] = 'civicrm_contribution_page';
$formValues['entity_id'] = $this->_id;
$formValues['title'] = $formValues['tf_title'];
- $formValues['is_active'] = CRM_Utils_Array::value('tf_is_active', $formValues, FALSE);
+ $formValues['is_active'] = $formValues['tf_is_active'] ?? FALSE;
$formValues['thankyou_title'] = $formValues['tf_thankyou_title'] ?? NULL;
$formValues['thankyou_text'] = $formValues['tf_thankyou_text'] ?? NULL;
diff --git a/CRM/Friend/Form/Event.php b/CRM/Friend/Form/Event.php
index cad46dde25c1..f87e0c68d54f 100644
--- a/CRM/Friend/Form/Event.php
+++ b/CRM/Friend/Form/Event.php
@@ -103,7 +103,7 @@ public function postProcess() {
$formValues['entity_table'] = 'civicrm_event';
$formValues['entity_id'] = $this->_id;
$formValues['title'] = $formValues['tf_title'];
- $formValues['is_active'] = CRM_Utils_Array::value('tf_is_active', $formValues, FALSE);
+ $formValues['is_active'] = $formValues['tf_is_active'] ?? FALSE;
$formValues['thankyou_title'] = $formValues['tf_thankyou_title'] ?? NULL;
$formValues['thankyou_text'] = $formValues['tf_thankyou_text'] ?? NULL;
diff --git a/CRM/Group/Form/Edit.php b/CRM/Group/Form/Edit.php
index 772cda0786c5..a850add6ead3 100644
--- a/CRM/Group/Form/Edit.php
+++ b/CRM/Group/Form/Edit.php
@@ -201,6 +201,8 @@ public function setDefaultValues() {
}
}
+ $parentGroupIds = explode(',', $this->_groupValues['parents']);
+ $defaults['parents'] = $parentGroupIds;
if (empty($defaults['parents'])) {
$defaults['parents'] = CRM_Core_BAO_Domain::getGroupId();
}
@@ -254,15 +256,9 @@ public function buildQuickForm() {
//build custom data
CRM_Custom_Form_CustomData::buildQuickForm($this);
- $doParentCheck = FALSE;
- if (CRM_Core_Permission::isMultisiteEnabled()) {
- $doParentCheck = !($this->_id && CRM_Core_BAO_Domain::isDomainGroup($this->_id));
- }
-
$options = [
'selfObj' => $this,
'parentGroups' => $parentGroups,
- 'doParentCheck' => $doParentCheck,
];
$this->addFormRule(['CRM_Group_Form_Edit', 'formRule'], $options);
}
@@ -281,29 +277,8 @@ public function buildQuickForm() {
public static function formRule($fields, $fileParams, $options) {
$errors = [];
- $doParentCheck = $options['doParentCheck'];
$self = &$options['selfObj'];
- if ($doParentCheck) {
- $parentGroups = $options['parentGroups'];
-
- $grpRemove = 0;
- foreach ($fields as $key => $val) {
- if (substr($key, 0, 20) == 'remove_parent_group_') {
- $grpRemove++;
- }
- }
-
- $grpAdd = 0;
- if (!empty($fields['parents'])) {
- $grpAdd++;
- }
-
- if ((count($parentGroups) >= 1) && (($grpRemove - $grpAdd) >= count($parentGroups))) {
- $errors['parents'] = ts('Make sure at least one parent group is set.');
- }
- }
-
// do check for both name and title uniqueness
if (!empty($fields['title'])) {
$title = trim($fields['title']);
@@ -356,8 +331,8 @@ public function postProcess() {
$params['group_type'] = [];
}
- $params['is_reserved'] = CRM_Utils_Array::value('is_reserved', $params, FALSE);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
+ $params['is_reserved'] = $params['is_reserved'] ?? FALSE;
+ $params['is_active'] = $params['is_active'] ?? FALSE;
$params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
$this->_id,
'Group'
@@ -402,9 +377,6 @@ public static function buildParentGroups(&$form) {
$parentGroups[$parentGroupId] = $groupNames[$parentGroupId];
if (array_key_exists($parentGroupId, $groupNames)) {
$parentGroupElements[$parentGroupId] = $groupNames[$parentGroupId];
- $form->addElement('checkbox', "remove_parent_group_$parentGroupId",
- $groupNames[$parentGroupId]
- );
}
}
}
@@ -412,6 +384,10 @@ public static function buildParentGroups(&$form) {
if (isset($form->_id)) {
$potentialParentGroupIds = CRM_Contact_BAO_GroupNestingCache::getPotentialCandidates($form->_id, $groupNames);
+ // put back current groups because they are selected by default
+ if (!empty($parentGroupIds)) {
+ $potentialParentGroupIds = array_merge($potentialParentGroupIds, $parentGroupIds);
+ }
}
else {
$potentialParentGroupIds = array_keys($groupNames);
@@ -431,7 +407,7 @@ public static function buildParentGroups(&$form) {
else {
$required = FALSE;
}
- $form->add('select', 'parents', ts('Add Parent'), $parentGroupSelectValues, $required, ['class' => 'crm-select2', 'multiple' => TRUE]);
+ $form->add('select', 'parents', ts('Parents'), $parentGroupSelectValues, $required, ['class' => 'crm-select2', 'multiple' => TRUE]);
}
return $parentGroups;
diff --git a/CRM/Import/ImportProcessor.php b/CRM/Import/ImportProcessor.php
index fbbe9d85ee42..4938dff9b742 100644
--- a/CRM/Import/ImportProcessor.php
+++ b/CRM/Import/ImportProcessor.php
@@ -583,11 +583,6 @@ protected function isValidRelationshipKey($key) {
public function getSavedQuickformDefaultsForColumn($column) {
$fieldMapping = [];
- // $sel1 is either unmapped, a relationship or a target field.
- if ($this->getFieldName($column) === 'do_not_import') {
- return $fieldMapping;
- }
-
if ($this->getValidRelationshipKey($column)) {
$fieldMapping[] = $this->getValidRelationshipKey($column);
}
diff --git a/CRM/Mailing/BAO/Mailing.php b/CRM/Mailing/BAO/Mailing.php
index 82e4010d09a9..5270a8a666fc 100644
--- a/CRM/Mailing/BAO/Mailing.php
+++ b/CRM/Mailing/BAO/Mailing.php
@@ -816,10 +816,11 @@ private function _getTokens($prop) {
*
* @param array $testParams
* Contains form values.
+ * @param int $mailingID
*
- * @return void
+ * @throws \Civi\Core\Exception\DBQueryException
*/
- public function getTestRecipients($testParams) {
+ public static function getTestRecipients(array $testParams, int $mailingID): void {
if (!empty($testParams['test_group']) && array_key_exists($testParams['test_group'], CRM_Core_PseudoConstant::group())) {
$contacts = civicrm_api('contact', 'get', [
'version' => 3,
@@ -852,6 +853,8 @@ public function getTestRecipients($testParams) {
'job_id' => $testParams['job_id'],
'email_id' => $dao->email_id,
'contact_id' => $groupContact,
+ 'mailing_id' => $mailingID,
+ 'is_test' => TRUE,
];
CRM_Mailing_Event_BAO_MailingEventQueue::create($params);
}
@@ -908,7 +911,7 @@ public static function addMessageIdHeader(&$headers, $prefix, $job_id, $event_qu
$fields = [];
$fields[] = 'Message-ID';
// CRM-17754 check if Resent-Message-id is set also if not add it in when re-laying reply email
- if ($prefix == 'r') {
+ if ($prefix === 'r') {
$fields[] = 'Resent-Message-ID';
}
foreach ($fields as $field) {
@@ -916,7 +919,6 @@ public static function addMessageIdHeader(&$headers, $prefix, $job_id, $event_qu
$headers[$field] = '<' . implode($config->verpSeparator,
[
$localpart . $prefix,
- $job_id,
$event_queue_id,
$hash,
]
@@ -1017,12 +1019,14 @@ public function getVerpAndUrlsAndHeaders($job_id, $event_queue_id, $hash, $email
$verp['reply'] = "\"{$this->from_name}\" <{$this->from_email}>";
}
+ // Generating URLs is expensive, so we only call it once for each of these 5 URLs.
+ $genericURL = CRM_Utils_System::url('civicrm/mailing/genericUrlPath', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", TRUE, NULL, TRUE, TRUE);
$urls = [
- 'forward' => CRM_Utils_System::url('civicrm/mailing/forward', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", TRUE, NULL, TRUE, TRUE),
- 'unsubscribeUrl' => CRM_Utils_System::url('civicrm/mailing/unsubscribe', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", TRUE, NULL, TRUE, TRUE),
- 'resubscribeUrl' => CRM_Utils_System::url('civicrm/mailing/resubscribe', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", TRUE, NULL, TRUE, TRUE),
- 'optOutUrl' => CRM_Utils_System::url('civicrm/mailing/optout', "reset=1&jid={$job_id}&qid={$event_queue_id}&h={$hash}", TRUE, NULL, TRUE, TRUE),
- 'subscribeUrl' => CRM_Utils_System::url('civicrm/mailing/subscribe', 'reset=1', TRUE, NULL, TRUE, TRUE),
+ 'forward' => str_replace('genericUrlPath', 'forward', $genericURL),
+ 'unsubscribeUrl' => str_replace('genericUrlPath', 'unsubscribe', $genericURL),
+ 'resubscribeUrl' => str_replace('genericUrlPath', 'resubscribe', $genericURL),
+ 'optOutUrl' => str_replace('genericUrlPath', 'optout', $genericURL),
+ 'subscribeUrl' => str_replace('genericUrlPath', 'subscribe', $genericURL),
];
$headers = [
@@ -2859,7 +2863,7 @@ public static function getContactMailingSelector(&$params) {
$mailing['openstats'] = "Opens: " .
CRM_Utils_Array::value($values['mailing_id'], $openCounts, 0) .
" Clicks: " .
- CRM_Utils_Array::value($values['mailing_id'], $clickCounts, 0);
+ $clickCounts[$values['mailing_id']] ?? 0;
$actionLinks = [
CRM_Core_Action::VIEW => [
diff --git a/CRM/Mailing/BAO/MailingJob.php b/CRM/Mailing/BAO/MailingJob.php
index ce90b95a6727..3d7598007937 100644
--- a/CRM/Mailing/BAO/MailingJob.php
+++ b/CRM/Mailing/BAO/MailingJob.php
@@ -45,7 +45,7 @@ public static function create($params) {
throw new CRM_Core_Exception("Failed to create job: Unknown mailing ID");
}
$op = empty($params['id']) ? 'create' : 'edit';
- CRM_Utils_Hook::pre($op, 'MailingJob', CRM_Utils_Array::value('id', $params), $params);
+ CRM_Utils_Hook::pre($op, 'MailingJob', $params['id'] ?? NULL, $params);
$jobDAO = new CRM_Mailing_BAO_MailingJob();
$jobDAO->copyValues($params);
@@ -407,23 +407,17 @@ private static function split_job(int $offset, int $jobID, int $mailingID, strin
}
/**
- * @param array $testParams
+ * @param ?array $testParams
*/
- public function queue($testParams = NULL) {
- $mailing = new CRM_Mailing_BAO_Mailing();
- $mailing->id = $this->mailing_id;
+ public function queue(?array $testParams = NULL) {
if (!empty($testParams)) {
- $mailing->getTestRecipients($testParams);
+ CRM_Mailing_BAO_Mailing::getTestRecipients($testParams, (int) $this->mailing_id);
}
else {
// We are still getting all the recipients from the parent job
// so we don't mess with the include/exclude logic.
$recipients = CRM_Mailing_BAO_MailingRecipients::mailingQuery($this->mailing_id, $this->job_offset, $this->job_limit);
- // FIXME: this is not very smart, we should move this to one DB call
- // INSERT INTO ... SELECT FROM ..
- // the thing we need to figure out is how to generate the hash automatically
- $now = time();
$params = [];
$count = 0;
// dev/core#1768 Get the mail sync interval.
@@ -434,31 +428,40 @@ public function queue($testParams = NULL) {
if (empty($recipients->email_id) && empty($recipients->phone_id)) {
continue;
}
-
- if ($recipients->phone_id) {
- $recipients->email_id = "null";
- }
- else {
- $recipients->phone_id = "null";
- }
-
$params[] = [
- $this->id,
- $recipients->email_id,
- $recipients->contact_id,
- $recipients->phone_id,
+ 'job_id' => $this->id,
+ 'email_id' => $recipients->email_id ? (int) $recipients->email_id : NULL,
+ 'phone_id' => $recipients->phone_id ? (int) $recipients->phone_id : NULL,
+ 'contact_id' => $recipients->contact_id ? (int) $recipients->contact_id : NULL,
+ 'mailing_id' => (int) $this->mailing_id,
+ 'is_test' => !empty($testParams),
];
$count++;
- // dev/core#1768 Mail sync interval is now configurable.
- if ($count % $mail_sync_interval == 0) {
- CRM_Mailing_Event_BAO_MailingEventQueue::bulkCreate($params, $now);
+ /*
+ The mail sync interval is used here to determine how
+ many rows to insert in each insert statement.
+ The discussion & name of the setting implies that the intent of the
+ setting is the frequency with which the mailing tables are updated
+ with information about actions taken on the mailings (ie if you send
+ an email & quickly update the delivered table that impacts information
+ availability.
+
+ However, here it is used to manage the size of each individual
+ insert statement. It is unclear why as the trade offs are out of sync
+ ie. you want you insert statements here to be 'big, but not so big they
+ stall out' but in the delivery context it's a trade off between
+ information availability & performance.
+ https://github.com/civicrm/civicrm-core/pull/17367 */
+
+ if ($count % $mail_sync_interval === 0) {
+ CRM_Mailing_Event_BAO_MailingEventQueue::writeRecords($params);
$count = 0;
$params = [];
}
}
if (!empty($params)) {
- CRM_Mailing_Event_BAO_MailingEventQueue::bulkCreate($params, $now);
+ CRM_Mailing_Event_BAO_MailingEventQueue::writeRecords($params);
}
}
}
diff --git a/CRM/Mailing/DAO/Mailing.php b/CRM/Mailing/DAO/Mailing.php
index 894028116b85..2bb67e0253ba 100644
--- a/CRM/Mailing/DAO/Mailing.php
+++ b/CRM/Mailing/DAO/Mailing.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Mailing/Mailing.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7370dea62ce328244525bac141d7fb62)
+ * (GenCodeChecksum:62a218e043b9abab2e816bf69272cca1)
*/
/**
@@ -51,8 +51,9 @@ class CRM_Mailing_DAO_Mailing extends CRM_Core_DAO {
* @var string[]
*/
protected static $_paths = [
- 'add' => 'civicrm/a/#/mailing/new',
- 'update' => 'civicrm/a/#/mailing/[id]',
+ 'add' => 'civicrm/mailing/send',
+ 'update' => 'civicrm/mailing/send?mid=[id]&continue=true',
+ 'copy' => 'civicrm/mailing/send?mid=[id]',
'view' => 'civicrm/mailing/report?mid=[id]&reset=1',
'preview' => 'civicrm/mailing/view?id=[id]&reset=1',
];
@@ -830,7 +831,7 @@ public static function &fields() {
'pseudoconstant' => [
'callback' => 'CRM_Mailing_BAO_Mailing::getTemplateTypeNames',
],
- 'add' => '4.7.16',
+ 'add' => '4.7',
],
'template_options' => [
'name' => 'template_options',
@@ -849,7 +850,7 @@ public static function &fields() {
'bao' => 'CRM_Mailing_BAO_Mailing',
'localizable' => 0,
'serialize' => self::SERIALIZE_JSON,
- 'add' => '4.7.16',
+ 'add' => '4.7',
],
'subject' => [
'name' => 'subject',
diff --git a/CRM/Mailing/DAO/MailingTrackableURL.php b/CRM/Mailing/DAO/MailingTrackableURL.php
index 599cda1ef707..985b1cac7da5 100644
--- a/CRM/Mailing/DAO/MailingTrackableURL.php
+++ b/CRM/Mailing/DAO/MailingTrackableURL.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Mailing/MailingTrackableURL.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5da2465e098de06d8a90975560c1cd91)
+ * (GenCodeChecksum:f446966734b2d351d7a1f8e7557dc08c)
*/
/**
@@ -136,6 +136,9 @@ public static function &fields() {
'entity' => 'MailingTrackableURL',
'bao' => 'CRM_Mailing_BAO_MailingTrackableURL',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'Text',
+ ],
'add' => NULL,
],
'mailing_id' => [
diff --git a/CRM/Mailing/Event/BAO/MailingEventQueue.php b/CRM/Mailing/Event/BAO/MailingEventQueue.php
index 056e159db396..d3f27f5aad48 100644
--- a/CRM/Mailing/Event/BAO/MailingEventQueue.php
+++ b/CRM/Mailing/Event/BAO/MailingEventQueue.php
@@ -31,6 +31,16 @@ public static function create($params) {
if (empty($params['id']) && empty($params['hash'])) {
$eq->hash = self::hash();
}
+ if (empty($params['id']) && !empty($params['job_id']) && empty($params['mailing_id'])) {
+ // mailing_id is a new field in 5.67. Calling code should pass it in going forwards
+ // but temporary handling will set it. (We should make the field required
+ // when we remove this in future)
+ CRM_Core_Error::deprecatedWarning('mailing_id should be passed into EventQueue create calls. Temporary handling has set it for now');
+ $query = CRM_Core_DAO::executeQuery('SELECT mailing_id, is_test
+ FROM civicrm_mailing_job job LEFT JOIN civicrm_mailing m ON m.id = mailing_id WHERE job.id = %1', [1 => [$params['job_id'], 'Integer']]);
+ $eq->mailing_id = $query->mailing_id;
+ $eq->is_test = $query->is_test;
+ }
$eq->save();
return $eq;
}
@@ -84,33 +94,6 @@ public static function verify($job_id, $queue_id, $hash) {
return $success;
}
- /**
- * Given a queue event ID, find the corresponding email address.
- *
- * @param int $queue_id
- * The queue event ID.
- *
- * @return string
- * The email address
- */
- public static function getEmailAddress($queue_id) {
- $email = CRM_Core_BAO_Email::getTableName();
- $eq = self::getTableName();
- $query = " SELECT $email.email as email
- FROM $email
- INNER JOIN $eq
- ON $eq.email_id = $email.id
- WHERE $eq.id = " . CRM_Utils_Type::rule($queue_id, 'Integer');
-
- $q = new CRM_Mailing_Event_BAO_MailingEventQueue();
- $q->query($query);
- if (!$q->fetch()) {
- return NULL;
- }
-
- return $q->email;
- }
-
/**
* Count up events given a mailing id and optional job id.
*
@@ -287,10 +270,39 @@ public static function getContactInfo($queueID) {
}
/**
+ * Bulk save multiple records.
+ *
+ * For performance reasons hooks are not called here.
+ *
+ * @param array[] $records
+ *
+ * @return array
+ */
+ public static function writeRecords(array $records): array {
+ $rows = [];
+ foreach ($records as $record) {
+ $record['hash'] = self::hash();
+ $rows[] = $record;
+ if (count($rows) >= CRM_Core_DAO::BULK_INSERT_COUNT) {
+ CRM_Utils_SQL_Insert::into('civicrm_mailing_event_queue')->rows($rows)->execute();
+ $rows = [];
+ }
+ }
+ if ($rows) {
+ CRM_Utils_SQL_Insert::into('civicrm_mailing_event_queue')->rows($rows)->execute();
+ }
+ // No point returning a big array but the standard function signature is to return an array
+ // records
+ return [];
+ }
+
+ /**
+ * @deprecated
* @param array $params
* @param null $now
*/
public static function bulkCreate($params, $now = NULL) {
+ CRM_Core_Error::deprecatedFunctionWarning('writeRecords');
if (!$now) {
$now = time();
}
diff --git a/CRM/Mailing/Info.php b/CRM/Mailing/Info.php
index bffbd7ca798e..2eec29a4382e 100644
--- a/CRM/Mailing/Info.php
+++ b/CRM/Mailing/Info.php
@@ -137,14 +137,6 @@ public function getInfo() {
* @see CRM_Utils_Hook::angularModules
*/
public function getAngularModules() {
- // load angular files only if valid permissions are granted to the user
- if (!CRM_Core_Permission::check('access CiviMail')
- && !CRM_Core_Permission::check('create mailings')
- && !CRM_Core_Permission::check('schedule mailings')
- && !CRM_Core_Permission::check('approve mailings')
- ) {
- return [];
- }
global $civicrm_root;
$result = [];
diff --git a/CRM/Member/Form.php b/CRM/Member/Form.php
index 9be5fbf658f2..f0a2ecba2126 100644
--- a/CRM/Member/Form.php
+++ b/CRM/Member/Form.php
@@ -346,22 +346,25 @@ public function buildQuickForm() {
]);
}
else {
- $this->addButtons([
+ $buttons = [
[
'type' => 'upload',
'name' => ts('Save'),
'isDefault' => TRUE,
],
- [
+ ];
+ if (!$this->_id) {
+ $buttons[] = [
'type' => 'upload',
'name' => ts('Save and New'),
'subName' => 'new',
- ],
- [
- 'type' => 'cancel',
- 'name' => ts('Cancel'),
- ],
- ]);
+ ];
+ };
+ $buttons[] = [
+ 'type' => 'cancel',
+ 'name' => ts('Cancel'),
+ ];
+ $this->addButtons($buttons);
}
}
diff --git a/CRM/Member/Form/Membership.php b/CRM/Member/Form/Membership.php
index 9a4cf9b0beed..e6e1debc70c2 100644
--- a/CRM/Member/Form/Membership.php
+++ b/CRM/Member/Form/Membership.php
@@ -377,8 +377,8 @@ public function buildQuickForm() {
NULL, ['onchange' => "buildAmount( this.value );"]
);
}
- $this->assign('hasPriceSets', $buildPriceSet);
}
+ $this->assign('hasPriceSets', $buildPriceSet ?? NULL);
if ($this->_action & CRM_Core_Action::DELETE) {
$this->addButtons([
diff --git a/CRM/Member/Form/MembershipBlock.php b/CRM/Member/Form/MembershipBlock.php
index 7910ad9d4695..72dd3f22c1ad 100644
--- a/CRM/Member/Form/MembershipBlock.php
+++ b/CRM/Member/Form/MembershipBlock.php
@@ -127,6 +127,7 @@ public function buildQuickForm() {
}
$membership = $membershipDefault = $params = [];
+ $renewOption = [];
foreach ($membershipTypes as $k => $v) {
$membership[] = $this->createElement('advcheckbox', $k, NULL, $v);
$membershipDefault[$k] = NULL;
@@ -143,7 +144,7 @@ public function buildQuickForm() {
$this->freeze("auto_renew_$k");
$params['id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipBlock', $this->_id, 'id', 'entity_id');
}
- $this->_renewOption[$k] = $autoRenew;
+ $renewOption[$k] = $autoRenew;
}
}
}
@@ -155,9 +156,7 @@ public function buildQuickForm() {
}
$this->add('hidden', "mem_price_field_id", '', ['id' => "mem_price_field_id"]);
$this->assign('is_recur', $isRecur);
- if (isset($this->_renewOption)) {
- $this->assign('auto_renew', $this->_renewOption);
- }
+ $this->assign('auto_renew', $renewOption);
$this->addGroup($membership, 'membership_type', ts('Membership Types'));
$this->addRadio('membership_type_default', ts('Membership Types Default'), $membershipDefault, ['allowClear' => TRUE]);
diff --git a/CRM/Member/Form/MembershipType.php b/CRM/Member/Form/MembershipType.php
index 9dc8251cc090..9781f1931957 100644
--- a/CRM/Member/Form/MembershipType.php
+++ b/CRM/Member/Form/MembershipType.php
@@ -53,7 +53,8 @@ protected function setEntityFields() {
'auto_renew' => [
'name' => 'auto_renew',
'options' => CRM_Core_SelectValues::memberAutoRenew(),
- 'place_holder' => ts('You will need to select and configure a supported payment processor (currently Authorize.Net, PayPal Pro, or PayPal Website Standard) in order to offer automatically renewing memberships.'),
+ // Note this doesn't get used currently because the template has its own code for this field. Note also the documentation link that you see in the template is added later here down below.
+ 'description' => ts('You will need to select and configure a supported payment processor (currently Authorize.Net, PayPal Pro, or PayPal Website Standard) in order to offer automatically renewing memberships.'),
],
'duration_interval' => [
'name' => 'duration_interval',
@@ -99,7 +100,7 @@ protected function setEntityFields() {
if (!CRM_Financial_BAO_PaymentProcessor::hasPaymentProcessorSupporting(['Recurring'])) {
$this->entityFields['auto_renew']['not-auto-addable'] = TRUE;
- $this->entityFields['auto_renew']['documentation_link'] = ['page' => 'user/contributions/payment-processors'];
+ $this->entityFields['auto_renew']['documentation_link'] = ['page' => 'user/contributions/payment-processors', 'resource' => ''];
}
}
diff --git a/CRM/Member/Page/Tab.php b/CRM/Member/Page/Tab.php
index 2433005403ac..e6c543f1cd66 100644
--- a/CRM/Member/Page/Tab.php
+++ b/CRM/Member/Page/Tab.php
@@ -240,7 +240,6 @@ public function browse() {
// Refresh other tabs with related data
$this->ajaxResponse['updateTabs'] = [
'#tab_activity' => CRM_Contact_BAO_Contact::getCountComponent('activity', $this->_contactId),
- '#tab_rel' => CRM_Contact_BAO_Contact::getCountComponent('rel', $this->_contactId),
];
if (CRM_Core_Permission::access('CiviContribute')) {
$this->ajaxResponse['updateTabs']['#tab_contribute'] = CRM_Contact_BAO_Contact::getCountComponent('contribution', $this->_contactId);
diff --git a/CRM/Note/Form/Note.php b/CRM/Note/Form/Note.php
index 33addb0e3785..b243a2719a08 100644
--- a/CRM/Note/Form/Note.php
+++ b/CRM/Note/Form/Note.php
@@ -41,26 +41,15 @@ class CRM_Note_Form_Note extends CRM_Core_Form {
*/
protected $_entityId;
- /**
- * The parent note id, used when adding a comment to a note
- *
- * @var int
- */
- protected $_parentId;
-
public function preProcess() {
- $this->_entityTable = $this->get('entityTable');
- $this->_entityId = $this->get('entityId');
- $this->_id = $this->get('id');
- $this->_parentId = CRM_Utils_Array::value('parentId', $_GET, 0);
- if ($this->_parentId) {
- $this->assign('parentId', $this->_parentId);
- }
+ $this->_id = CRM_Utils_Request::retrieve('id', 'Integer', $this);
+ $this->_entityTable = CRM_Utils_Request::retrieve('entity_table', 'String', $this);
+ $this->_entityId = CRM_Utils_Request::retrieve('entity_id', 'Integer', $this);
if ($this->_id && CRM_Core_BAO_Note::getNotePrivacyHidden($this->_id)) {
CRM_Core_Error::statusBounce(ts('You do not have access to this note.'));
}
- $this->setPageTitle($this->_parentId ? ts('Comment') : ts('Note'));
+ $this->setPageTitle($this->_entityTable === 'civicrm_note' ? ts('Comment') : ts('Note'));
}
/**
@@ -78,15 +67,12 @@ public function setDefaultValues() {
$params['id'] = $this->_id;
CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_Note', $params, $defaults);
}
- if ($defaults['entity_table'] == 'civicrm_note') {
- $defaults['parent_id'] = $defaults['entity_id'];
- }
}
elseif ($this->_action & CRM_Core_Action::ADD) {
+ $defaults['privacy'] = '0';
$defaults['note_date'] = date('Y-m-d H:i:s');
- if ($this->_parentId) {
- $defaults['parent_id'] = $this->_parentId;
- $defaults['subject'] = 'Re: ' . CRM_Core_BAO_Note::getNoteSubject($this->_parentId);
+ if ($this->_entityTable === 'civicrm_note') {
+ $defaults['subject'] = ts('Re: %1', [1 => CRM_Core_BAO_Note::getNoteSubject($this->_entityId)]);
}
}
return $defaults;
@@ -130,8 +116,10 @@ public function buildQuickForm() {
$this->addField('subject');
$this->addField('note_date', [], TRUE, FALSE);
$this->addField('note', [], TRUE);
- $this->addField('privacy');
- $this->add('hidden', 'parent_id');
+ $this->addField('privacy', [
+ 'placeholder' => NULL,
+ 'option_url' => NULL,
+ ]);
// add attachments part
CRM_Core_BAO_File::buildAttachment($this, 'civicrm_note', $this->_id, NULL, TRUE);
@@ -161,11 +149,7 @@ public function postProcess() {
$session = CRM_Core_Session::singleton();
$params['contact_id'] = $session->get('userID');
- if (!empty($params['parent_id'])) {
- $params['entity_table'] = 'civicrm_note';
- $params['entity_id'] = $params['parent_id'];
- }
- else {
+ if ($this->_action & CRM_Core_Action::ADD) {
$params['entity_table'] = $this->_entityTable;
$params['entity_id'] = $this->_entityId;
}
@@ -185,8 +169,7 @@ public function postProcess() {
// add attachments as needed
CRM_Core_BAO_File::formatAttachment($params, $params, 'civicrm_note', $params['id']);
- $ids = [];
- $note = CRM_Core_BAO_Note::add($params, $ids);
+ $note = CRM_Core_BAO_Note::add($params);
// Required for postProcess hooks
$this->setEntityId($note->id);
diff --git a/CRM/PCP/BAO/PCP.php b/CRM/PCP/BAO/PCP.php
index 3f78c9539242..3540790485e5 100644
--- a/CRM/PCP/BAO/PCP.php
+++ b/CRM/PCP/BAO/PCP.php
@@ -344,7 +344,11 @@ public static function &pcpLinks($pcpId = NULL) {
],
];
+ // pcp.user.actions emits a malformed set of $links. But it is locked-in via unit-test, so we'll grandfather
+ // the bad one and fire new variants that are well-formed.
CRM_Utils_Hook::links('pcp.user.actions', 'Pcp', $pcpId, self::$_pcpLinks);
+ CRM_Utils_Hook::links('pcp.user.actions.add', 'Pcp', $pcpId, self::$_pcpLinks['add']);
+ CRM_Utils_Hook::links('pcp.user.actions.all', 'Pcp', $pcpId, self::$_pcpLinks['all']);
}
return self::$_pcpLinks;
}
@@ -388,7 +392,7 @@ public static function buildPCPForm($form) {
$form->assign('profile', $profile);
}
- $form->add('select', 'supporter_profile_id', ts('Supporter Profile'), ['' => ts('- select -')] + $profile, TRUE, ['class' => 'crm-select2']);
+ $form->add('select', 'supporter_profile_id', ts('Supporter Profile'), ['' => ts('- select -')] + $profile, FALSE, ['class' => 'crm-select2']);
//CRM-15821 - To add new option for PCP "Owner" notification
$ownerNotifications = CRM_Core_OptionGroup::values('pcp_owner_notify');
diff --git a/CRM/PCP/Form/Contribute.php b/CRM/PCP/Form/Contribute.php
index 19f484099672..86bc12ba7944 100644
--- a/CRM/PCP/Form/Contribute.php
+++ b/CRM/PCP/Form/Contribute.php
@@ -72,11 +72,8 @@ public function setDefaultValues() {
* @return void
*/
public function buildQuickForm() {
- $this->_last = TRUE;
CRM_PCP_BAO_PCP::buildPCPForm($this);
-
$this->addElement('checkbox', 'pcp_active', ts('Enable Personal Campaign Pages? (for this contribution page)'), NULL, ['onclick' => "return showHideByValue('pcp_active',true,'pcpFields','table-row','radio',false);"]);
-
parent::buildQuickForm();
$this->addFormRule(['CRM_PCP_Form_Contribute', 'formRule'], $this);
}
@@ -95,7 +92,7 @@ public function buildQuickForm() {
*/
public static function formRule($params, $files, $self) {
$errors = [];
- if (!empty($params['is_active'])) {
+ if (!empty($params['pcp_active'])) {
if (!empty($params['is_tellfriend_enabled']) &&
(CRM_Utils_Array::value('tellfriend_limit', $params) <= 0)
@@ -147,9 +144,9 @@ public function postProcess() {
$dao->entity_id = $this->_id;
$dao->find(TRUE);
$params['id'] = $dao->id;
- $params['is_active'] = CRM_Utils_Array::value('pcp_active', $params, FALSE);
- $params['is_approval_needed'] = CRM_Utils_Array::value('is_approval_needed', $params, FALSE);
- $params['is_tellfriend_enabled'] = CRM_Utils_Array::value('is_tellfriend_enabled', $params, FALSE);
+ $params['is_active'] = $params['pcp_active'] ?? FALSE;
+ $params['is_approval_needed'] = $params['is_approval_needed'] ?? FALSE;
+ $params['is_tellfriend_enabled'] = $params['is_tellfriend_enabled'] ?? FALSE;
CRM_PCP_BAO_PCPBlock::writeRecord($params);
diff --git a/CRM/PCP/Form/Event.php b/CRM/PCP/Form/Event.php
index 636968f8a05d..5448225acc03 100644
--- a/CRM/PCP/Form/Event.php
+++ b/CRM/PCP/Form/Event.php
@@ -125,13 +125,19 @@ public function buildQuickForm() {
*/
public static function formRule($params, $files, $self) {
$errors = [];
- if (!empty($params['is_active'])) {
+ if (!empty($params['pcp_active'])) {
- if (!empty($params['is_tellfriend_enabled']) &&
- (CRM_Utils_Array::value('tellfriend_limit', $params) <= 0)
- ) {
- $errors['tellfriend_limit'] = ts('if Tell Friend is enable, Maximum recipients limit should be greater than zero.');
+ if (!empty($params['is_tellfriend_enabled']) && ($params['is_tellfriend_enabled'] <= 0)) {
+ $errors['tellfriend_limit'] = ts('If Tell a Friend is enabled, maximum recipients limit should be greater than zero.');
+ }
+
+ if (empty($params['target_entity_type'])) {
+ $errors['target_entity_type'] = ts('Campaign Type is a required field.');
}
+ elseif (($params['target_entity_type'] === 'contribute') && (empty($params['target_entity_id']))) {
+ $errors['target_entity_id'] = ts('Online Contribution Page is a required field.');
+ }
+
if (empty($params['supporter_profile_id'])) {
$errors['supporter_profile_id'] = ts('Supporter profile is a required field.');
}
@@ -181,9 +187,9 @@ public function postProcess() {
$dao->entity_id = $this->_id;
$dao->find(TRUE);
$params['id'] = $dao->id;
- $params['is_active'] = CRM_Utils_Array::value('pcp_active', $params, FALSE);
- $params['is_approval_needed'] = CRM_Utils_Array::value('is_approval_needed', $params, FALSE);
- $params['is_tellfriend_enabled'] = CRM_Utils_Array::value('is_tellfriend_enabled', $params, FALSE);
+ $params['is_active'] = $params['pcp_active'] ?? FALSE;
+ $params['is_approval_needed'] = $params['is_approval_needed'] ?? FALSE;
+ $params['is_tellfriend_enabled'] = $params['is_tellfriend_enabled'] ?? FALSE;
CRM_PCP_BAO_PCPBlock::writeRecord($params);
diff --git a/CRM/PCP/Page/PCP.php b/CRM/PCP/Page/PCP.php
index 2fb8c5f822c6..d18e6354d3d8 100644
--- a/CRM/PCP/Page/PCP.php
+++ b/CRM/PCP/Page/PCP.php
@@ -54,18 +54,21 @@ public function &links() {
'url' => 'civicrm/pcp/info',
'qs' => 'action=update&reset=1&id=%%id%%&context=dashboard',
'title' => ts('Edit Personal Campaign Page'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
CRM_Core_Action::RENEW => [
'name' => ts('Approve'),
'url' => 'civicrm/admin/pcp',
'qs' => 'action=renew&id=%%id%%',
'title' => ts('Approve Personal Campaign Page'),
+ 'weight' => 30,
],
CRM_Core_Action::REVERT => [
'name' => ts('Reject'),
'url' => 'civicrm/admin/pcp',
'qs' => 'action=revert&id=%%id%%',
'title' => ts('Reject Personal Campaign Page'),
+ 'weight' => 30,
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
@@ -73,18 +76,21 @@ public function &links() {
'qs' => 'action=delete&id=%%id%%',
'extra' => 'onclick = "return confirm(\'' . $deleteExtra . '\');"',
'title' => ts('Delete Personal Campaign Page'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
CRM_Core_Action::ENABLE => [
'name' => ts('Enable'),
'url' => 'civicrm/admin/pcp',
'qs' => 'action=enable&id=%%id%%',
'title' => ts('Enable'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE),
],
CRM_Core_Action::DISABLE => [
'name' => ts('Disable'),
'url' => 'civicrm/admin/pcp',
'qs' => 'action=disable&id=%%id%%',
'title' => ts('Disable'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE),
],
];
}
@@ -296,7 +302,7 @@ public function browse($action = NULL) {
'page_title' => $title,
'page_url' => $pageUrl,
'page_type' => $page_type,
- 'action' => CRM_Core_Action::formLink(self::links(), $action,
+ 'action' => CRM_Core_Action::formLink($this->links(), $action,
['id' => $pcp->id], ts('more'), FALSE, 'contributionpage.pcp.list', 'PCP', $pcp->id
),
'title' => $pcp->title,
diff --git a/CRM/Pledge/BAO/PledgeBlock.php b/CRM/Pledge/BAO/PledgeBlock.php
index 052a23fbbda6..e6e867dfbadd 100644
--- a/CRM/Pledge/BAO/PledgeBlock.php
+++ b/CRM/Pledge/BAO/PledgeBlock.php
@@ -118,8 +118,11 @@ public static function getPledgeBlock($pageID) {
* @param CRM_Core_Form $form
*
* @throws \CRM_Core_Exception
+ *
+ * @deprecated since 5.68 will be removed around 5.74
*/
public static function buildPledgeBlock($form) {
+ CRM_Core_Error::deprecatedFunctionWarning('no alternative');
//build pledge payment fields.
if (!empty($form->_values['pledge_id'])) {
//get all payments required details.
diff --git a/CRM/Pledge/Form/Pledge.php b/CRM/Pledge/Form/Pledge.php
index aa454fe5866c..ab873baa75fa 100644
--- a/CRM/Pledge/Form/Pledge.php
+++ b/CRM/Pledge/Form/Pledge.php
@@ -43,7 +43,7 @@ class CRM_Pledge_Form_Pledge extends CRM_Core_Form {
* The Pledge values if an existing pledge.
* @var array
*/
- public $_values;
+ public $_values = [];
/**
* The Pledge frequency Units.
@@ -195,33 +195,28 @@ public function buildQuickForm(): void {
$contactField->freeze();
}
- $showAdditionalInfo = FALSE;
- $formType = CRM_Utils_Request::retrieveValue('form_type', 'String');
- $defaults = [];
+ $formType = CRM_Utils_Request::retrieveValue('formType', 'String');
- $paneNames = [
- ts('Payment Reminders') => 'PaymentReminders',
+ $allPanes[ts('Payment Reminders')] = [
+ 'open' => 'false',
+ 'id' => 'PaymentReminders',
];
- foreach ($paneNames as $name => $type) {
- $urlParams = "snippet=4&formType={$type}";
- $allPanes[$name] = [
- 'url' => CRM_Utils_System::url('civicrm/contact/view/pledge', $urlParams),
- 'open' => 'false',
- 'id' => $type,
- ];
- // see if we need to include this paneName in the current form
- if ($formType == $type || !empty($_POST["hidden_{$type}"]) ||
- !empty($defaults["hidden_{$type}"])
- ) {
- $showAdditionalInfo = TRUE;
- $allPanes[$name]['open'] = 'true';
- }
- $fnName = "build{$type}";
- CRM_Contribute_Form_AdditionalInfo::$fnName($this);
+ // see if we need to include this paneName in the current form
+ if ($formType === 'PaymentReminders' || !empty($_POST['hidden_PaymentReminders'])
+ ) {
+ $allPanes[ts('Payment Reminders')]['open'] = 'true';
}
+ $this->add('hidden', 'hidden_PaymentReminders', 1);
+ $this->add('text', 'initial_reminder_day', ts('Send Initial Reminder'), ['size' => 3]);
+ $this->addRule('initial_reminder_day', ts('Please enter a valid reminder day.'), 'positiveInteger');
+ $this->add('text', 'max_reminders', ts('Send up to'), ['size' => 3]);
+ $this->addRule('max_reminders', ts('Please enter a valid No. of reminders.'), 'positiveInteger');
+ $this->add('text', 'additional_reminder_day', ts('Send additional reminders'), ['size' => 3]);
+ $this->addRule('additional_reminder_day', ts('Please enter a valid additional reminder day.'), 'positiveInteger');
+
$this->assign('allPanes', $allPanes);
- $this->assign('showAdditionalInfo', $showAdditionalInfo);
+ $this->assign('showAdditionalInfo', TRUE);
$this->assign('formType', $formType);
if ($formType) {
@@ -297,8 +292,8 @@ public function buildQuickForm(): void {
$frequencyUnit->freeze();
$frequencyDay->freeze();
$eachPaymentAmount = $this->_values['original_installment_amount'];
- $this->assign('eachPaymentAmount', $eachPaymentAmount);
}
+ $this->assign('eachPaymentAmount', $eachPaymentAmount ?? NULL);
if (($this->_values['status_id'] ?? NULL) !=
CRM_Core_PseudoConstant::getKey('CRM_Pledge_BAO_Pledge', 'status_id', 'Cancelled')
@@ -345,25 +340,28 @@ public function buildQuickForm(): void {
// make this form an upload since we dont know if the custom data injected dynamically
// is of type file etc $uploadNames = $this->get( 'uploadNames' );
- $this->addButtons([
- [
- 'type' => 'upload',
- 'name' => ts('Save'),
- 'js' => ['onclick' => 'return verify( );'],
- 'isDefault' => TRUE,
- ],
- [
- 'type' => 'upload',
- 'name' => ts('Save and New'),
- 'js' => ['onclick' => 'return verify( );'],
- 'subName' => 'new',
- ],
- [
- 'type' => 'cancel',
- 'name' => ts('Cancel'),
- ],
- ]);
+ $buttons = [
+ [
+ 'type' => 'upload',
+ 'name' => ts('Save'),
+ 'js' => ['onclick' => 'return verify();'],
+ 'isDefault' => TRUE,
+ ],
+ ];
+ if (!$this->_id) {
+ $buttons[] = [
+ 'type' => 'upload',
+ 'name' => ts('Save and New'),
+ 'js' => ['onclick' => 'return verify();'],
+ 'subName' => 'new',
+ ];
+ }
+ $buttons[] = [
+ 'type' => 'cancel',
+ 'name' => ts('Cancel'),
+ ];
+ $this->addButtons($buttons);
$this->addFormRule(['CRM_Pledge_Form_Pledge', 'formRule'], $this);
if ($this->_action & CRM_Core_Action::VIEW) {
diff --git a/CRM/Pledge/Selector/Search.php b/CRM/Pledge/Selector/Search.php
index 49b5c25c2b6d..8dba0e80336e 100644
--- a/CRM/Pledge/Selector/Search.php
+++ b/CRM/Pledge/Selector/Search.php
@@ -262,8 +262,8 @@ public function getTotalCount($action) {
* @param string $output
* What should the result set include (web/email/csv).
*
- * @return int
- * the total number of rows for this action
+ * @return array
+ * Rows number of rows for this action
*/
public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
$result = $this->_query->searchQuery($offset, $rowCount, $sort,
@@ -276,9 +276,6 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
// process the result of the query
$rows = [];
- // get all pledge status
- $pledgeStatuses = CRM_Pledge_BAO_Pledge::buildOptions('status_id');
-
// get all campaigns.
$allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
@@ -302,29 +299,30 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) {
// the columns we are interested in
foreach (self::$_properties as $property) {
- if (isset($result->$property)) {
- $row[$property] = $result->$property;
+ if (in_array($property, ['pledge_amount', 'pledge_total_paid', 'pledge_next_pay_amount', 'pledge_outstanding_amount'])) {
+ $row[$property] = $result->$property ? (float) $result->$property : 0;
+ }
+ else {
+ $row[$property] = $result->$property ?? NULL;
}
}
// carry campaign on selectors.
$row['campaign'] = $allCampaigns[$result->pledge_campaign_id] ?? NULL;
$row['campaign_id'] = $result->pledge_campaign_id;
-
- // add pledge status name
- if (!empty($row['pledge_status_id'])) {
- $row['pledge_status_name'] = CRM_Utils_Array::value($row['pledge_status_id'],
- $pledgeStatuses
- );
+ if (isset($row['pledge_total_paid'])) {
+ $row['pledge_balance_amount'] = $row['pledge_amount'] - $row['pledge_total_paid'];
}
+ // add pledge status name
+ $statusID = $row['pledge_status_id'] ?? NULL;
+ $row['pledge_status_name'] = CRM_Core_PseudoConstant::getLabel('CRM_Pledge_BAO_Pledge', 'status_id', $statusID);
+
// append (test) to status label
if (!empty($row['pledge_is_test'])) {
$row['pledge_status'] = CRM_Core_TestEntity::appendTestText($row['pledge_status']);
}
$hideOption = [];
- if (CRM_Utils_Array::key('Cancelled', $row) ||
- CRM_Utils_Array::key('Completed', $row)
- ) {
+ if (in_array(CRM_Core_PseudoConstant::getName('CRM_Pledge_BAO_Pledge', 'status_id', $statusID), ['Completed', 'Cancelled'])) {
$hideOption[] = 'Cancel';
}
diff --git a/CRM/Price/BAO/LineItem.php b/CRM/Price/BAO/LineItem.php
index 4d4069054a5e..4a1a81c85abe 100644
--- a/CRM/Price/BAO/LineItem.php
+++ b/CRM/Price/BAO/LineItem.php
@@ -311,7 +311,7 @@ public static function format($fid, $params, $fields, &$values, $amount_override
$qty = (float) $qty;
$price = (float) ($amount_override === NULL ? $options[$oid]['amount'] : $amount_override);
- $participantsPerField = (int) CRM_Utils_Array::value('count', $options[$oid], 0);
+ $participantsPerField = (int) ($options[$oid]['count'] ?? 0);
$values[$oid] = [
'price_field_id' => $fid,
@@ -329,7 +329,7 @@ public static function format($fid, $params, $fields, &$values, $amount_override
'auto_renew' => $options[$oid]['auto_renew'] ?? NULL,
'html_type' => $fields['html_type'],
'financial_type_id' => $options[$oid]['financial_type_id'] ?? NULL,
- 'tax_amount' => CRM_Utils_Array::value('tax_amount', $options[$oid], 0),
+ 'tax_amount' => $options[$oid]['tax_amount'] ?? 0,
'non_deductible_amount' => $options[$oid]['non_deductible_amount'] ?? NULL,
];
diff --git a/CRM/Price/BAO/PriceField.php b/CRM/Price/BAO/PriceField.php
index 0fb1c2e60907..39803c6d4f6a 100644
--- a/CRM/Price/BAO/PriceField.php
+++ b/CRM/Price/BAO/PriceField.php
@@ -236,6 +236,8 @@ public static function getTitle($id) {
*
* @param null $fieldOptions
* @param array $freezeOptions
+ * @param array $extra
+ * Passed through to the add element function, use to add js.
*
* @return null
*/
@@ -247,18 +249,20 @@ public static function addQuickFormElement(
$useRequired = TRUE,
$label = NULL,
$fieldOptions = NULL,
- $freezeOptions = []
+ $freezeOptions = [],
+ array $extra = []
) {
-
+ $incomingExtra = $extra;
$field = new CRM_Price_DAO_PriceField();
$field->id = $fieldId;
if (!$field->find(TRUE)) {
/* FIXME: failure! */
return NULL;
}
-
+ $label = $label ?: $field->label;
$is_pay_later = 0;
$isQuickConfig = CRM_Price_BAO_PriceSet::isQuickConfig($field->price_set_id);
+ // @todo - pass is_pay_later in rather than checking form properties
if (isset($qf->_mode) && empty($qf->_mode)) {
$is_pay_later = 1;
}
@@ -274,10 +278,7 @@ public static function addQuickFormElement(
// get currency name for price field and option attributes
$currencyName = $config->defaultCurrency;
- if (!isset($label)) {
- $label = (!empty($qf->_membershipBlock) && $field->name === 'contribution_amount') ? ts('Additional Contribution') : $field->label;
- }
-
+ // @todo - pass useRequired in rather than checking form properties
if (isset($qf->_online) && $qf->_online) {
$useRequired = FALSE;
}
@@ -310,21 +311,16 @@ public static function addQuickFormElement(
$max_value,
]);
- $extra = [];
if (!empty($fieldOptions[$optionKey]['label'])) {
//check for label.
- $label = $fieldOptions[$optionKey]['label'];
+ $label = CRM_Utils_String::purifyHTML($fieldOptions[$optionKey]['label']);
}
+ // @todo - move this back to the only calling function on Contribution_Form_Main.php
if ($isQuickConfig && $field->name === 'other_amount') {
if (!empty($qf->_membershipBlock)) {
$useRequired = 0;
}
$label .= ' ' . $currencySymbol;
- $qf->assign('priceset', $elementName);
- $extra = [
- 'onclick' => 'useAmountOther();',
- 'autocomplete' => 'off',
- ];
}
$element = &$qf->add('text', $elementName, $label,
@@ -353,7 +349,7 @@ public static function addQuickFormElement(
$type = 'money';
}
else {
- $message = ts('%1 must be a number (with or without decimal point).', [1 => $label]);
+ $message = ts('%1 must be a number (with or without decimals).', [1 => $label]);
$type = 'numeric';
}
// integers will have numeric rule applied to them.
@@ -363,10 +359,6 @@ public static function addQuickFormElement(
case 'Radio':
$choice = [];
- if ($isQuickConfig && $field->name === 'contribution_amount') {
- $qf->assign('contriPriceset', $elementName);
- }
-
foreach ($customOption as $opId => $opt) {
$priceOptionText = self::buildPriceOptionText($opt, $field->is_display_amounts, $valueFieldName);
if (isset($opt['visibility_id'])) {
@@ -381,10 +373,8 @@ public static function addQuickFormElement(
'data-currency' => $currencyName,
'data-price-field-values' => json_encode($customOption),
'visibility' => $visibility_id,
- ];
- if ($isQuickConfig && $field->name == 'contribution_amount') {
- $extra += ['onclick' => 'clearAmountOther();'];
- }
+ ] + $incomingExtra;
+ // @todo - move this back to the only calling function on Contribution_Form_Main.php
if ($field->name == 'membership_amount') {
$extra += [
'onclick' => "return showHideAutoRenew({$opt['membership_type_id']});",
@@ -393,12 +383,13 @@ public static function addQuickFormElement(
$qf->assign('membershipFieldID', $field->id);
}
- $choice[$opt['id']] = $priceOptionText['label'];
+ $choice[$opt['id']] = CRM_Utils_String::purifyHTML($priceOptionText['label']);
$choiceAttrs[$opt['id']] = $extra;
if ($is_pay_later) {
$qf->add('text', 'txt-' . $elementName, $label, ['size' => '4']);
}
}
+ // @todo - move this back to the only calling function on Contribution_Form_Main.php
if (!empty($qf->_membershipBlock) && $field->name == 'contribution_amount') {
$choice['-1'] = ts('No thank you');
$choiceAttrs['-1'] = [
@@ -435,6 +426,7 @@ public static function addQuickFormElement(
}
// make contribution field required for quick config when membership block is enabled
+ // @todo - move this back to the only calling function on Contribution_Form_Main.php
if (($field->name == 'membership_amount' || $field->name == 'contribution_amount')
&& !empty($qf->_membershipBlock) && !$field->is_required
) {
@@ -528,6 +520,7 @@ public static function addQuickFormElement(
}
break;
}
+ // @todo - move this action back to the calling function
if (isset($qf->_online) && $qf->_online) {
$element->freeze();
}
@@ -737,11 +730,11 @@ public static function priceSetValidation($priceSetId, $fields, &$error, $allowN
}
}
- list($componentName) = explode(':', $fields['_qf_default']);
+ [$componentName] = explode(':', $fields['_qf_default']);
// now we have all selected amount in hand.
$totalAmount = array_sum($selectedAmounts);
// The form offers a field to enter the amount paid. This may differ from the amount that is due to complete the purchase
- $totalPaymentAmountEnteredOnForm = CRM_Utils_Array::value('total_amount', $fields);
+ $totalPaymentAmountEnteredOnForm = $fields['total_amount'] ?? NULL;
if ($totalAmount < 0) {
$error['_qf_default'] = ts('%1 amount can not be less than zero. Please select the options accordingly.', [1 => $componentName]);
}
@@ -778,12 +771,12 @@ public static function priceSetValidation($priceSetId, $fields, &$error, $allowN
*/
public static function buildPriceOptionText($opt, $isDisplayAmounts, $valueFieldName) {
$preHelpText = $postHelpText = '';
- $optionLabel = !empty($opt['label']) ? '' . $opt['label'] . ' ' : '';
- if (!empty($opt['help_pre'])) {
- $preHelpText = '' . $opt['help_pre'] . ' : ';
+ $optionLabel = !empty($opt['label']) ? '' . CRM_Utils_String::purifyHTML($opt['label']) . ' ' : '';
+ if (CRM_Utils_String::purifyHTML($opt['help_pre'] ?? '')) {
+ $preHelpText = '' . CRM_Utils_String::purifyHTML($opt['help_pre']) . ' : ';
}
- if (!empty($opt['help_post'])) {
- $postHelpText = ': ' . $opt['help_post'] . ' ';
+ if (CRM_Utils_String::purifyHTML($opt['help_post'] ?? '')) {
+ $postHelpText = ': ' . CRM_Utils_String::purifyHTML($opt['help_post']) . ' ';
}
$invoicing = Civi::settings()->get('invoicing');
diff --git a/CRM/Price/BAO/PriceSet.php b/CRM/Price/BAO/PriceSet.php
index 874fcd208547..8d5661c9216d 100644
--- a/CRM/Price/BAO/PriceSet.php
+++ b/CRM/Price/BAO/PriceSet.php
@@ -15,6 +15,10 @@
* @copyright CiviCRM LLC https://civicrm.org/licensing
*/
+use Civi\Api4\PriceField;
+use Civi\Api4\PriceFieldValue;
+use Civi\Api4\PriceSet;
+
/**
* Business object for managing price sets.
*
@@ -449,7 +453,7 @@ public static function getSetDetail($setID, $required = TRUE, $doNotIncludeExpir
$visibility = CRM_Core_PseudoConstant::visibility('name');
while ($dao->fetch()) {
- $fieldID = $dao->id;
+ $fieldID = (int) $dao->id;
$setTree[$setID]['fields'][$fieldID] = [];
$setTree[$setID]['fields'][$fieldID]['id'] = $fieldID;
@@ -459,7 +463,7 @@ public static function getSetDetail($setID, $required = TRUE, $doNotIncludeExpir
continue;
}
- if ($field == 'visibility_id') {
+ if ($field === 'visibility_id') {
$setTree[$setID]['fields'][$fieldID]['visibility'] = $visibility[$dao->$field];
}
$setTree[$setID]['fields'][$fieldID][$field] = $dao->$field;
@@ -475,11 +479,11 @@ public static function getSetDetail($setID, $required = TRUE, $doNotIncludeExpir
$dao = CRM_Core_DAO::executeQuery($sql, $params);
if ($dao->fetch()) {
$setTree[$setID]['extends'] = $dao->extends;
- $setTree[$setID]['financial_type_id'] = $dao->financial_type_id;
+ $setTree[$setID]['financial_type_id'] = (int) $dao->financial_type_id;
$setTree[$setID]['help_pre'] = $dao->help_pre;
$setTree[$setID]['help_post'] = $dao->help_post;
- $setTree[$setID]['is_quick_config'] = $dao->is_quick_config;
- $setTree[$setID]['min_amount'] = $dao->min_amount;
+ $setTree[$setID]['is_quick_config'] = (bool) $dao->is_quick_config;
+ $setTree[$setID]['min_amount'] = (float) $dao->min_amount;
}
return $setTree;
}
@@ -595,7 +599,7 @@ public static function initSet(&$form, $entityTable = 'civicrm_event', $doNotInc
if (!empty($form->_priceSet['fields'])) {
foreach ($form->_priceSet['fields'] as $field) {
foreach ($field['options'] as $option) {
- $count = CRM_Utils_Array::value('count', $option, 0);
+ $count = $option['count'] ?? 0;
$optionsCountDetails['fields'][$field['id']]['options'][$option['id']] = $count;
}
}
@@ -610,7 +614,7 @@ public static function initSet(&$form, $entityTable = 'civicrm_event', $doNotInc
if (!empty($form->_priceSet['fields'])) {
foreach ($form->_priceSet['fields'] as $field) {
foreach ($field['options'] as $option) {
- $maxVal = CRM_Utils_Array::value('max_value', $option, 0);
+ $maxVal = $option['max_value'] ?? 0;
$optionsMaxValueDetails['fields'][$field['id']]['options'][$option['id']] = $maxVal;
$optionsMaxValueTotal += $maxVal;
}
@@ -757,30 +761,50 @@ public static function filterPriceFieldsFromParams($priceSetID, $params) {
}
/**
- * Wrapper for getSetDetail with caching.
+ * Get PriceSet + Fields + FieldValues nested, with caching.
+ *
+ * This gets the same values as getSet but uses apiv4 for more
+ * predictability & better variable typing.
*
* We seem to be passing this array around in a painful way - presumably to avoid the hit
* of loading it - so lets make it callable with caching.
*
- * Why not just add caching to the other function? We could do - it just seemed a bit unclear the best caching pattern
- * & the function was already pretty fugly. Also, I feel like we need to migrate the interaction with price-sets into
- * a more granular interaction - ie. retrieve specific data using specific functions on this class & have the form
- * think less about the price sets.
- *
* @param int $priceSetID
*
* @return array
+ *
+ * @noinspection PhpUnhandledExceptionInspection
*/
- public static function getCachedPriceSetDetail($priceSetID) {
+ public static function getCachedPriceSetDetail(int $priceSetID): array {
$cacheKey = __CLASS__ . __FUNCTION__ . '_' . $priceSetID;
$cache = CRM_Utils_Cache::singleton();
- $values = $cache->get($cacheKey);
- if (empty($values)) {
- $data = self::getSetDetail($priceSetID);
- $values = $data[$priceSetID];
- $cache->set($cacheKey, $values);
+ $data = $cache->get($cacheKey);
+ if (empty($data)) {
+ $data = PriceSet::get(FALSE)
+ ->addWhere('id', '=', $priceSetID)
+ ->addSelect('*', 'visibility_id:name', 'extends:name')
+ ->execute()->first();
+ $data['fields'] = (array) PriceField::get(FALSE)
+ ->addWhere('price_set_id', '=', $priceSetID)
+ ->addSelect('*', 'visibility_id:name')
+ ->execute()->indexBy('id');
+ foreach ($data['fields'] as &$field) {
+ $field['options'] = [];
+ // Add in visibility because Smarty templates expect it and it is hard to adjust them to colon format.
+ $field['visibility'] = $field['visibility_id:name'];
+ }
+ $options = PriceFieldValue::get(FALSE)
+ ->addWhere('price_field_id', 'IN', array_keys($data['fields']))
+ ->addSelect('*', 'membership_type_id.name', 'visibility_id:name')
+ ->execute();
+ foreach ($options as $option) {
+ // Add in visibility because Smarty templates expect it and it is hard to adjust them to colon format.
+ $option['visibility'] = $option['visibility_id:name'];
+ $data['fields'][$option['price_field_id']]['options'][$option['id']] = $option;
+ }
+ $cache->set($cacheKey, $data);
}
- return $values;
+ return $data;
}
/**
@@ -791,7 +815,8 @@ public static function getCachedPriceSetDetail($priceSetID) {
* @param bool $validFieldsOnly
*
* @return void
- * @throws \CRM_Core_Exception
+ *
+ * @deprecated since 5.68. Will be removed around 5.80.
*/
public static function buildPriceSet(&$form, $component = NULL, $validFieldsOnly = TRUE) {
$priceSetId = $form->get('priceSetId');
@@ -840,22 +865,53 @@ public static function buildPriceSet(&$form, $component = NULL, $validFieldsOnly
// Call the buildAmount hook.
CRM_Utils_Hook::buildAmount($component ?? 'contribution', $form, $feeBlock);
- self::addPriceFieldsToForm($form, $feeBlock, $validFieldsOnly, $className, $validPriceFieldIds);
- }
+ $hideAdminValues = !CRM_Core_Permission::check('edit contributions');
+ // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
+ $adminFieldVisible = CRM_Core_Permission::check('administer CiviCRM');
+ $checklifetime = FALSE;
+ foreach ($feeBlock as $id => $field) {
+ if (($field['visibility'] ?? NULL) == 'public' ||
+ (($field['visibility'] ?? NULL) == 'admin' && $adminFieldVisible == TRUE) ||
+ !$validFieldsOnly
+ ) {
+ $options = $field['options'] ?? NULL;
+ if ($className == 'CRM_Contribute_Form_Contribution_Main' && $component = 'membership') {
+ $contactId = $form->getVar('_membershipContactID');
+ if ($contactId && $options) {
+ $contactsLifetimeMemberships = CRM_Member_BAO_Membership::getAllContactMembership($contactId, FALSE, TRUE);
+ $contactsLifetimeMembershipTypes = array_column($contactsLifetimeMemberships, 'membership_type_id');
+ $memTypeIdsInPriceField = array_column($options, 'membership_type_id');
+ $isCurrentMember = (bool) array_intersect($memTypeIdsInPriceField, $contactsLifetimeMembershipTypes);
+ $checklifetime = $checklifetime ?: $isCurrentMember;
+ }
+ }
+
+ $formClasses = ['CRM_Contribute_Form_Contribution', 'CRM_Member_Form_Membership'];
+
+ if (!is_array($options) || !in_array($id, $validPriceFieldIds)) {
+ continue;
+ }
+ elseif ($hideAdminValues && !in_array($className, $formClasses)) {
+ foreach ($options as $key => $currentOption) {
+ if ($currentOption['visibility_id'] == CRM_Price_BAO_PriceField::getVisibilityOptionID('admin')) {
+ unset($options[$key]);
+ }
+ }
+ }
+ if (!empty($options)) {
+ CRM_Price_BAO_PriceField::addQuickFormElement($form,
+ 'price_' . $field['id'],
+ $field['id'],
+ FALSE,
+ $field['is_required'] ?? FALSE,
+ NULL,
+ $options
+ );
+ }
+ }
+ }
+ $form->assign('ispricelifetime', $checklifetime);
- /**
- * Check for lifetime membership types this contact has that are in this price field.
- *
- * @param array $options
- * @param int $contactId
- *
- * @return bool
- */
- private static function checkCurrentMembership(array $options, int $contactId) : bool {
- $contactsLifetimeMemberships = CRM_Member_BAO_Membership::getAllContactMembership($contactId, FALSE, TRUE);
- $contactsLifetimeMembershipTypes = array_column($contactsLifetimeMemberships, 'membership_type_id');
- $memTypeIdsInPriceField = array_column($options, 'membership_type_id');
- return (bool) array_intersect($memTypeIdsInPriceField, $contactsLifetimeMembershipTypes);
}
/**
@@ -1579,7 +1635,7 @@ public static function getLine(&$params, &$lineItem, $priceSetID, $field, $id):
$amount_override = NULL;
if ($priceSetID && count(self::filterPriceFieldsFromParams($priceSetID, $params)) === 1) {
- $amount_override = CRM_Utils_Array::value('total_amount', $params);
+ $amount_override = $params['total_amount'] ?? NULL;
}
CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem, $amount_override);
if (!empty($field['options'][$optionValueId]['tax_rate'])) {
@@ -1613,60 +1669,6 @@ public static function getLine(&$params, &$lineItem, $priceSetID, $field, $id):
return [$params, $lineItem];
}
- /**
- * Add the relevant price fields to the form.
- *
- * @param \CRM_Core_Form $form
- * @param array $feeBlock
- * @param bool $validFieldsOnly
- * @param string $className
- * @param array $validPriceFieldIds
- */
- protected static function addPriceFieldsToForm(CRM_Core_Form $form, $feeBlock, bool $validFieldsOnly, string $className, array $validPriceFieldIds) {
- $hideAdminValues = !CRM_Core_Permission::check('edit contributions');
- // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
- $adminFieldVisible = CRM_Core_Permission::check('administer CiviCRM');
- $checklifetime = FALSE;
- foreach ($feeBlock as $id => $field) {
- if (($field['visibility'] ?? NULL) == 'public' ||
- (($field['visibility'] ?? NULL) == 'admin' && $adminFieldVisible == TRUE) ||
- !$validFieldsOnly
- ) {
- $options = $field['options'] ?? NULL;
- if ($className == 'CRM_Contribute_Form_Contribution_Main' && $component = 'membership') {
- $contactId = $form->getVar('_membershipContactID');
- if ($contactId && $options) {
- $checklifetime = $checklifetime ?: self::checkCurrentMembership($options, $contactId);
- }
- }
-
- $formClasses = ['CRM_Contribute_Form_Contribution', 'CRM_Member_Form_Membership'];
-
- if (!is_array($options) || !in_array($id, $validPriceFieldIds)) {
- continue;
- }
- elseif ($hideAdminValues && !in_array($className, $formClasses)) {
- foreach ($options as $key => $currentOption) {
- if ($currentOption['visibility_id'] == CRM_Price_BAO_PriceField::getVisibilityOptionID('admin')) {
- unset($options[$key]);
- }
- }
- }
- if (!empty($options)) {
- CRM_Price_BAO_PriceField::addQuickFormElement($form,
- 'price_' . $field['id'],
- $field['id'],
- FALSE,
- CRM_Utils_Array::value('is_required', $field, FALSE),
- NULL,
- $options
- );
- }
- }
- }
- $form->assign('ispricelifetime', $checklifetime);
- }
-
/**
* Pseudoconstant options for the `extends` field
*
diff --git a/CRM/Price/Form/Field.php b/CRM/Price/Form/Field.php
index 3f2b2bd6a747..5496fdabd089 100644
--- a/CRM/Price/Form/Field.php
+++ b/CRM/Price/Form/Field.php
@@ -666,12 +666,12 @@ public function submit($params) {
$params['option_amount'][$key] = CRM_Utils_Rule::cleanMoney($amount);
}
- $params['is_display_amounts'] = CRM_Utils_Array::value('is_display_amounts', $params, FALSE);
- $params['is_required'] = CRM_Utils_Array::value('is_required', $params, FALSE);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $params, FALSE);
- $params['visibility_id'] = CRM_Utils_Array::value('visibility_id', $params, FALSE);
- $params['count'] = CRM_Utils_Array::value('count', $params, FALSE);
+ $params['is_display_amounts'] = $params['is_display_amounts'] ?? FALSE;
+ $params['is_required'] = $params['is_required'] ?? FALSE;
+ $params['is_active'] = $params['is_active'] ?? FALSE;
+ $params['financial_type_id'] = $params['financial_type_id'] ?? FALSE;
+ $params['visibility_id'] = $params['visibility_id'] ?? FALSE;
+ $params['count'] = $params['count'] ?? FALSE;
// need the FKEY - price set id
$params['price_set_id'] = $this->_sid;
@@ -689,7 +689,7 @@ public function submit($params) {
if (isset($params['option_name'])) {
$params['option_value'] = $params['option_name'];
}
- $params['is_enter_qty'] = CRM_Utils_Array::value('is_enter_qty', $params, FALSE);
+ $params['is_enter_qty'] = $params['is_enter_qty'] ?? FALSE;
if ($params['html_type'] === 'Text') {
// if html type is Text, force is_enter_qty on
diff --git a/CRM/Price/Form/Option.php b/CRM/Price/Form/Option.php
index 94e4f0d9a8f5..3aeecdc00f4c 100644
--- a/CRM/Price/Form/Option.php
+++ b/CRM/Price/Form/Option.php
@@ -328,9 +328,9 @@ public function postProcess() {
$params[$field] = CRM_Utils_Rule::cleanMoney(trim($params[$field]));
}
$params['price_field_id'] = $this->_fid;
- $params['is_default'] = CRM_Utils_Array::value('is_default', $params, FALSE);
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $params['visibility_id'] = CRM_Utils_Array::value('visibility_id', $params, FALSE);
+ $params['is_default'] = $params['is_default'] ?? FALSE;
+ $params['is_active'] = $params['is_active'] ?? FALSE;
+ $params['visibility_id'] = $params['visibility_id'] ?? FALSE;
$ids = [];
if ($this->_oid) {
$params['id'] = $this->_oid;
diff --git a/CRM/Price/Form/Set.php b/CRM/Price/Form/Set.php
index 5abbc00ca027..c9e630058ac4 100644
--- a/CRM/Price/Form/Set.php
+++ b/CRM/Price/Form/Set.php
@@ -243,8 +243,8 @@ public function postProcess() {
// get the submitted form values.
$params = $this->controller->exportValues('Set');
$nameLength = CRM_Core_DAO::getAttribute('CRM_Price_DAO_PriceSet', 'name');
- $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
- $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $params, FALSE);
+ $params['is_active'] = $params['is_active'] ?? FALSE;
+ $params['financial_type_id'] = $params['financial_type_id'] ?? FALSE;
$compIds = [];
$extends = $params['extends'] ?? NULL;
diff --git a/CRM/Price/Page/Field.php b/CRM/Price/Page/Field.php
index b519c129d657..fb4611979629 100644
--- a/CRM/Price/Page/Field.php
+++ b/CRM/Price/Page/Field.php
@@ -62,28 +62,33 @@ public static function &actionLinks() {
'url' => 'civicrm/admin/price/field/edit',
'qs' => 'action=update&reset=1&sid=%%sid%%&fid=%%fid%%',
'title' => ts('Edit Price'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
CRM_Core_Action::PREVIEW => [
'name' => ts('Preview Field'),
'url' => 'civicrm/admin/price/field/edit',
'qs' => 'action=preview&reset=1&sid=%%sid%%&fid=%%fid%%',
'title' => ts('Preview Price'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::PREVIEW),
],
CRM_Core_Action::DISABLE => [
'name' => ts('Disable'),
'ref' => 'crm-enable-disable',
'title' => ts('Disable Price'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE),
],
CRM_Core_Action::ENABLE => [
'name' => ts('Enable'),
'ref' => 'crm-enable-disable',
'title' => ts('Enable Price'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE),
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
'url' => 'civicrm/admin/price/field/edit',
'qs' => 'action=delete&reset=1&sid=%%sid%%&fid=%%fid%%',
'title' => ts('Delete Price'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
];
}
diff --git a/CRM/Price/Page/Set.php b/CRM/Price/Page/Set.php
index 039952f44bca..860b6f9e08d6 100644
--- a/CRM/Price/Page/Set.php
+++ b/CRM/Price/Page/Set.php
@@ -50,28 +50,33 @@ public function &actionLinks() {
'url' => 'civicrm/admin/price/field',
'qs' => 'reset=1&action=browse&sid=%%sid%%',
'title' => ts('View and Edit Price Fields'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::VIEW),
],
CRM_Core_Action::PREVIEW => [
'name' => ts('Preview'),
'url' => 'civicrm/admin/price/edit',
'qs' => 'action=preview&reset=1&sid=%%sid%%',
'title' => ts('Preview Price Set'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::PREVIEW),
],
CRM_Core_Action::UPDATE => [
'name' => ts('Settings'),
'url' => 'civicrm/admin/price/edit',
'qs' => 'action=update&reset=1&sid=%%sid%%',
'title' => ts('Edit Price Set'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
CRM_Core_Action::DISABLE => [
'name' => ts('Disable'),
'ref' => 'crm-enable-disable',
'title' => ts('Disable Price Set'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE),
],
CRM_Core_Action::ENABLE => [
'name' => ts('Enable'),
'ref' => 'crm-enable-disable',
'title' => ts('Enable Price Set'),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE),
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
@@ -79,6 +84,7 @@ public function &actionLinks() {
'qs' => 'action=delete&reset=1&sid=%%sid%%',
'title' => ts('Delete Price Set'),
'extra' => 'onclick = "return confirm(\'' . $deleteExtra . '\');"',
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
CRM_Core_Action::COPY => [
'name' => ts('Copy Price Set'),
@@ -86,6 +92,7 @@ public function &actionLinks() {
'qs' => 'action=copy&sid=%%sid%%',
'title' => ts('Make a Copy of Price Set'),
'extra' => 'onclick = "return confirm(\'' . $copyExtra . '\');"',
+ 'weight' => 120,
],
];
}
diff --git a/CRM/Profile/Form.php b/CRM/Profile/Form.php
index 80605866ecbc..e20bd8d40b92 100644
--- a/CRM/Profile/Form.php
+++ b/CRM/Profile/Form.php
@@ -889,13 +889,10 @@ public function buildQuickForm(): void {
$this->setDefaultsValues();
$action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, NULL);
-
if ($this->_mode == self::MODE_CREATE || $this->_mode == self::MODE_EDIT) {
CRM_Core_BAO_CMSUser::buildForm($this, $this->_gid, $emailPresent, $action);
}
- else {
- $this->assign('showCMS', FALSE);
- }
+ $this->assign('showCMS', FALSE);
$this->assign('groupId', $this->_gid);
diff --git a/CRM/Profile/Page/MultipleRecordFieldsListing.php b/CRM/Profile/Page/MultipleRecordFieldsListing.php
index 00e507f139cd..0a2454c1c66d 100644
--- a/CRM/Profile/Page/MultipleRecordFieldsListing.php
+++ b/CRM/Profile/Page/MultipleRecordFieldsListing.php
@@ -228,7 +228,7 @@ public function browse(): array {
if ($returnValues['data_type'] == 'Date') {
$dateFields[$fieldIDs[$key]] = 1;
$actualPHPFormats = CRM_Utils_Date::datePluginToPHPFormats();
- $dateFormat = (array) CRM_Utils_Array::value($returnValues['date_format'], $actualPHPFormats);
+ $dateFormat = (array) ($actualPHPFormats[$returnValues['date_format']] ?? []);
$timeFormat = $returnValues['time_format'] ?? NULL;
}
diff --git a/CRM/Queue/ErrorPolicy.php b/CRM/Queue/ErrorPolicy.php
index 178591bbd209..9246036f9bc2 100644
--- a/CRM/Queue/ErrorPolicy.php
+++ b/CRM/Queue/ErrorPolicy.php
@@ -26,7 +26,21 @@
* will be necessary to get reuse from the other parts of this class.
*/
class CRM_Queue_ErrorPolicy {
- public $active;
+
+ /**
+ * @var bool
+ */
+ protected $active;
+
+ /**
+ * @var int
+ */
+ protected $level;
+
+ /**
+ * @var array
+ */
+ protected $backup;
/**
* @param null|int $level
@@ -43,7 +57,7 @@ public function __construct($level = NULL) {
/**
* Enable the error policy.
*/
- public function activate() {
+ protected function activate() {
$this->active = TRUE;
$this->backup = [];
foreach ([
@@ -55,14 +69,12 @@ public function activate() {
ini_set($key, 0);
}
set_error_handler([$this, 'onError'], $this->level);
- // FIXME make this temporary/reversible
}
/**
* Disable the error policy.
*/
- public function deactivate() {
- $this->errorScope = NULL;
+ protected function deactivate() {
restore_error_handler();
foreach ([
'display_errors',
@@ -137,7 +149,7 @@ public function onShutdown() {
* @param array $error
* The PHP error (with "type", "message", etc).
*/
- public function reportError($error) {
+ protected function reportError($error) {
$response = [
'is_error' => 1,
'is_continue' => 0,
@@ -158,7 +170,7 @@ public function reportError($error) {
* @param Exception $e
* The unhandled exception.
*/
- public function reportException(Exception $e) {
+ protected function reportException(Exception $e) {
CRM_Core_Error::debug_var('CRM_Queue_ErrorPolicy_reportException', CRM_Core_Error::formatTextException($e));
$response = [
diff --git a/CRM/Queue/Queue.php b/CRM/Queue/Queue.php
index 9ad305a92809..a7774f20d9a2 100644
--- a/CRM/Queue/Queue.php
+++ b/CRM/Queue/Queue.php
@@ -59,9 +59,29 @@ public function __construct($queueSpec) {
* @throws \CRM_Core_Exception
*/
public function isActive(): bool {
+ return ($this->getStatus() === 'active');
+ }
+
+ /**
+ * @return string|null
+ * @throws \CRM_Core_Exception
+ * @see \CRM_Queue_BAO_Queue::getStatuses()
+ */
+ public function getStatus() {
+ // Queues work with concurrent processes. We want to make sure status info is up-to-date (never cached).
$status = CRM_Core_DAO::getFieldValue('CRM_Queue_DAO_Queue', $this->_name, 'status', 'name', TRUE);
- // Note: In the future, we may want to incorporate other data (like maintenance-mode or upgrade-status) in deciding active queues.
- return ($status === 'active');
+ if ($status === 'active') {
+ $suspend = CRM_Core_DAO::singleValueQuery('SELECT value FROM civicrm_setting WHERE name = "queue_paused" AND domain_id = %1', [
+ 1 => [CRM_Core_BAO_Domain::getDomain()->id, 'Positive'],
+ ]);
+ if (!empty(CRM_Utils_String::unserialize($suspend))) {
+ $status = 'paused';
+ }
+ }
+ CRM_Utils_Hook::queueActive($status, $this->getName(), $this->queueSpec);
+ // Note in future we might want to consider whether an upgrade is in progress.
+ // Should we set the setting at that point?
+ return $status;
}
/**
diff --git a/CRM/Queue/Runner.php b/CRM/Queue/Runner.php
index f89e31912777..2be2ceed648f 100644
--- a/CRM/Queue/Runner.php
+++ b/CRM/Queue/Runner.php
@@ -119,7 +119,7 @@ public function __construct($runnerSpec) {
$this->title = CRM_Utils_Array::value('title', $runnerSpec, ts('Queue Runner'));
$this->queue = $runnerSpec['queue'];
$this->errorMode = CRM_Utils_Array::value('errorMode', $runnerSpec, $this->pickErrorMode($this->queue));
- $this->isMinimal = CRM_Utils_Array::value('isMinimal', $runnerSpec, FALSE);
+ $this->isMinimal = $runnerSpec['isMinimal'] ?? FALSE;
$this->onEnd = $runnerSpec['onEnd'] ?? NULL;
$this->onEndUrl = $runnerSpec['onEndUrl'] ?? NULL;
$this->pathPrefix = CRM_Utils_Array::value('pathPrefix', $runnerSpec, 'civicrm/queue');
diff --git a/CRM/Report/BAO/ReportInstance.php b/CRM/Report/BAO/ReportInstance.php
index eb7ff8fd6fb0..5024788f40cc 100644
--- a/CRM/Report/BAO/ReportInstance.php
+++ b/CRM/Report/BAO/ReportInstance.php
@@ -47,7 +47,7 @@ public static function add(&$params) {
}
if (!$instanceID || !isset($params['id'])) {
- $params['is_reserved'] = CRM_Utils_Array::value('is_reserved', $params, FALSE);
+ $params['is_reserved'] = $params['is_reserved'] ?? FALSE;
$params['domain_id'] = CRM_Utils_Array::value('domain_id', $params, CRM_Core_Config::domainID());
// CRM-17256 set created_id on report creation.
$params['created_id'] = $params['created_id'] ?? CRM_Core_Session::getLoggedInContactID();
@@ -240,7 +240,7 @@ public static function self_hook_civicrm_pre(\Civi\Core\Event\PreEvent $event) {
// When deleting a report, also delete from navigation menu
$navId = CRM_Core_DAO::getFieldValue('CRM_Report_DAO_ReportInstance', $event->id, 'navigation_id');
if ($navId) {
- CRM_Core_BAO_Navigation::processDelete($navId);
+ CRM_Core_BAO_Navigation::deleteRecord(['id' => $navId]);
CRM_Core_BAO_Navigation::resetNavigation();
}
}
diff --git a/CRM/Report/Form.php b/CRM/Report/Form.php
index 29f0a4dad897..2c2605ce4f4d 100644
--- a/CRM/Report/Form.php
+++ b/CRM/Report/Form.php
@@ -1084,7 +1084,7 @@ public function setDefaultValues($freeze = TRUE) {
$order_by = [
'column' => $fieldName,
'order' => CRM_Utils_Array::value('default_order', $field, 'ASC'),
- 'section' => CRM_Utils_Array::value('default_is_section', $field, 0),
+ 'section' => $field['default_is_section'] ?? 0,
];
if (!empty($field['default_weight'])) {
@@ -3531,8 +3531,9 @@ public function filterStat(&$statistics) {
$val[$key] = $options[$valIds];
}
}
- $pair[$op] = (count($val) == 1) ? (($op == 'notin' || $op ==
- 'mnot') ? ts('Is Not') : ts('Is')) : CRM_Utils_Array::value($op, $pair);
+ $pair[$op] = (count($val) == 1) ?
+ (($op == 'notin' || $op == 'mnot') ? ts('Is Not') : ts('Is')) :
+ ($pair[$op] ?? '');
$val = implode(', ', $val);
$value = "{$pair[$op]} " . $val;
}
@@ -3540,8 +3541,7 @@ public function filterStat(&$statistics) {
isset($field['options']) &&
is_array($field['options']) && !empty($field['options'])
) {
- $value = ($pair[$op] ?? '') . " " .
- CRM_Utils_Array::value($val, $field['options'], $val);
+ $value = ($pair[$op] ?? '') . ' ' . ($field['options'][$val] ?? $val);
}
elseif ($val || $val == '0') {
$value = ($pair[$op] ?? '') . " " . $val;
@@ -3649,8 +3649,8 @@ public function getTemplateFileName() {
public function compileContent() {
$templateFile = $this->getHookedTemplateFileName();
return ($this->_formValues['report_header'] ?? '') .
- CRM_Core_Form::$_template->fetch($templateFile) .
- CRM_Utils_Array::value('report_footer', $this->_formValues);
+ CRM_Core_Form::$_template->fetch($templateFile) .
+ ($this->_formValues['report_footer'] ?? '');
}
/**
@@ -5038,7 +5038,7 @@ public function getBasicContactFilters($defaults = []) {
'is_deceased' => [
'title' => ts('Deceased'),
'type' => CRM_Utils_Type::T_BOOLEAN,
- 'default' => CRM_Utils_Array::value('deceased', $defaults, 0),
+ 'default' => $defaults['deceased'] ?? 0,
],
'do_not_email' => [
'title' => ts('Do not email'),
diff --git a/CRM/Report/Form/Campaign/SurveyDetails.php b/CRM/Report/Form/Campaign/SurveyDetails.php
index 0f8cc4fc343f..fe56fbdc8053 100644
--- a/CRM/Report/Form/Campaign/SurveyDetails.php
+++ b/CRM/Report/Form/Campaign/SurveyDetails.php
@@ -318,9 +318,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
@@ -357,11 +357,11 @@ public function where() {
public function compileContent() {
$coverSheet = $this->_surveyCoverSheet() .
- "
";
+ "
";
$templateFile = $this->getHookedTemplateFileName();
return $coverSheet .
CRM_Core_Form::$_template->fetch($templateFile) .
- CRM_Utils_Array::value('report_footer', $this->_formValues);
+ ($this->_formValues['report_footer'] ?? '');
}
/**
diff --git a/CRM/Report/Form/Case/Demographics.php b/CRM/Report/Form/Case/Demographics.php
index bba34f581024..0ef45be865c3 100644
--- a/CRM/Report/Form/Case/Demographics.php
+++ b/CRM/Report/Form/Case/Demographics.php
@@ -329,9 +329,9 @@ public function where() {
else {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Case/Detail.php b/CRM/Report/Form/Case/Detail.php
index f6307b165609..bc90feede728 100644
--- a/CRM/Report/Form/Case/Detail.php
+++ b/CRM/Report/Form/Case/Detail.php
@@ -449,8 +449,8 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
);
}
diff --git a/CRM/Report/Form/Case/TimeSpent.php b/CRM/Report/Form/Case/TimeSpent.php
index 432bf8d7061b..fb929b7a04da 100644
--- a/CRM/Report/Form/Case/TimeSpent.php
+++ b/CRM/Report/Form/Case/TimeSpent.php
@@ -262,9 +262,9 @@ public function where() {
else {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contact/CurrentEmployer.php b/CRM/Report/Form/Contact/CurrentEmployer.php
index be2d0ef48cb2..d04f9b9a0887 100644
--- a/CRM/Report/Form/Contact/CurrentEmployer.php
+++ b/CRM/Report/Form/Contact/CurrentEmployer.php
@@ -249,9 +249,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contact/Detail.php b/CRM/Report/Form/Contact/Detail.php
index ac71cce24596..e1348f6c31ec 100644
--- a/CRM/Report/Form/Contact/Detail.php
+++ b/CRM/Report/Form/Contact/Detail.php
@@ -606,9 +606,9 @@ public function where(): void {
$op = $this->_params["{$fieldName}_op"] ?? NULL;
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
if (!empty($clause)) {
diff --git a/CRM/Report/Form/Contact/Log.php b/CRM/Report/Form/Contact/Log.php
index 65589629d73f..652b3ad6a066 100644
--- a/CRM/Report/Form/Contact/Log.php
+++ b/CRM/Report/Form/Contact/Log.php
@@ -194,9 +194,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contact/Relationship.php b/CRM/Report/Form/Contact/Relationship.php
index 4cc4512c716d..62240a6010d2 100644
--- a/CRM/Report/Form/Contact/Relationship.php
+++ b/CRM/Report/Form/Contact/Relationship.php
@@ -485,8 +485,8 @@ public function where() {
$clause = $this->whereClause($field,
$op,
$contactTypes,
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
@@ -496,8 +496,8 @@ public function where() {
$subTypeClause = $this->whereClause($field,
$op,
$contactSubTypes,
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
if ($clause) {
$clause = '(' . $clause . ' OR ' . $subTypeClause . ')';
@@ -514,9 +514,9 @@ public function where() {
else {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contribute/History.php b/CRM/Report/Form/Contribute/History.php
index fb2141aa221f..658db8e0ffeb 100644
--- a/CRM/Report/Form/Contribute/History.php
+++ b/CRM/Report/Form/Contribute/History.php
@@ -424,9 +424,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
@@ -661,7 +661,7 @@ public function buildRows($sql, &$rows) {
$total = [];
$total['civicrm_contact_sort_name'] = ts('Total');
foreach ($summaryYears as $year) {
- $total[$year] = CRM_Utils_Array::value($year, $primaryRow, 0);
+ $total[$year] = $primaryRow[$year] ?? 0;
}
$relatedContact = FALSE;
@@ -673,7 +673,7 @@ public function buildRows($sql, &$rows) {
$relatedContact = TRUE;
$relatedRow = $relatedContributions[$relcid];
foreach ($summaryYears as $year) {
- $total[$year] += CRM_Utils_Array::value($year, $relatedRow, 0);
+ $total[$year] += $relatedRow[$year] ?? 0;
}
foreach (array_keys($this->_relationshipColumns) as $col) {
diff --git a/CRM/Report/Form/Contribute/HouseholdSummary.php b/CRM/Report/Form/Contribute/HouseholdSummary.php
index 474ce68efcfb..4003b58cee10 100644
--- a/CRM/Report/Form/Contribute/HouseholdSummary.php
+++ b/CRM/Report/Form/Contribute/HouseholdSummary.php
@@ -273,9 +273,9 @@ public function where() {
else {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contribute/Lybunt.php b/CRM/Report/Form/Contribute/Lybunt.php
index a8ec85026199..ee3c8d808ea9 100644
--- a/CRM/Report/Form/Contribute/Lybunt.php
+++ b/CRM/Report/Form/Contribute/Lybunt.php
@@ -644,9 +644,9 @@ public function buildChart(&$rows) {
foreach ($rows as $key => $row) {
// The final row contains the totals so we don't need to include it here.
if (!empty($row['civicrm_contribution_contact_id'])) {
- $display['life_time'] = CRM_Utils_Array::value('life_time', $display) +
+ $display['life_time'] = ($display['life_time'] ?? 0) +
$row['civicrm_contribution_civicrm_life_time_total'];
- $display[$previous_year] = CRM_Utils_Array::value($previous_year, $display) + $row['civicrm_contribution_last_year_total_amount'];
+ $display[$previous_year] = ($display[$previous_year] ?? 0) + $row['civicrm_contribution_last_year_total_amount'];
}
}
diff --git a/CRM/Report/Form/Contribute/OrganizationSummary.php b/CRM/Report/Form/Contribute/OrganizationSummary.php
index 109eb68841b2..ad54d42e08ca 100644
--- a/CRM/Report/Form/Contribute/OrganizationSummary.php
+++ b/CRM/Report/Form/Contribute/OrganizationSummary.php
@@ -291,9 +291,9 @@ public function where() {
else {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contribute/PCP.php b/CRM/Report/Form/Contribute/PCP.php
index f3effc38a379..ba48655fa0fb 100644
--- a/CRM/Report/Form/Contribute/PCP.php
+++ b/CRM/Report/Form/Contribute/PCP.php
@@ -259,9 +259,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Contribute/Repeat.php b/CRM/Report/Form/Contribute/Repeat.php
index f5e33a14ef45..ea83b16e7da6 100644
--- a/CRM/Report/Form/Contribute/Repeat.php
+++ b/CRM/Report/Form/Contribute/Repeat.php
@@ -407,9 +407,9 @@ public function whereContribution($replaceAliasWith = 'contribution1') {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
@@ -464,9 +464,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
if (!empty($clause)) {
@@ -877,15 +877,15 @@ public function postProcess() {
// hack to fix title
list($from1, $to1) = $this->getFromTo(CRM_Utils_Array::value("receive_date1_relative", $this->_params),
- CRM_Utils_Array::value("receive_date1_from", $this->_params),
- CRM_Utils_Array::value("receive_date1_to", $this->_params)
+ $this->_params["receive_date1_from"] ?? NULL,
+ $this->_params["receive_date1_to"] ?? NULL
);
$from1 = CRM_Utils_Date::customFormat($from1, NULL, ['d']);
$to1 = CRM_Utils_Date::customFormat($to1, NULL, ['d']);
list($from2, $to2) = $this->getFromTo(CRM_Utils_Array::value("receive_date2_relative", $this->_params),
- CRM_Utils_Array::value("receive_date2_from", $this->_params),
- CRM_Utils_Array::value("receive_date2_to", $this->_params)
+ $this->_params["receive_date2_from"] ?? NULL,
+ $this->_params["receive_date2_to"] ?? NULL
);
$from2 = CRM_Utils_Date::customFormat($from2, NULL, ['d']);
$to2 = CRM_Utils_Date::customFormat($to2, NULL, ['d']);
@@ -914,13 +914,13 @@ public function postProcess() {
* Rows generated by SQL, with an array for each row.
*/
public function alterDisplay(&$rows) {
- list($from1, $to1) = $this->getFromTo(CRM_Utils_Array::value("receive_date1_relative", $this->_params),
- CRM_Utils_Array::value("receive_date1_from", $this->_params),
- CRM_Utils_Array::value("receive_date1_to", $this->_params)
+ [$from1, $to1] = $this->getFromTo(CRM_Utils_Array::value("receive_date1_relative", $this->_params),
+ $this->_params["receive_date1_from"] ?? NULL,
+ $this->_params["receive_date1_to"] ?? NULL
);
- list($from2, $to2) = $this->getFromTo(CRM_Utils_Array::value("receive_date2_relative", $this->_params),
- CRM_Utils_Array::value("receive_date2_from", $this->_params),
- CRM_Utils_Array::value("receive_date2_to", $this->_params)
+ [$from2, $to2] = $this->getFromTo(CRM_Utils_Array::value("receive_date2_relative", $this->_params),
+ $this->_params["receive_date2_from"] ?? NULL,
+ $this->_params["receive_date2_to"] ?? NULL
);
$dateUrl = "";
diff --git a/CRM/Report/Form/Contribute/SoftCredit.php b/CRM/Report/Form/Contribute/SoftCredit.php
index 3def8e31888e..7fa7cee8574d 100644
--- a/CRM/Report/Form/Contribute/SoftCredit.php
+++ b/CRM/Report/Form/Contribute/SoftCredit.php
@@ -308,11 +308,7 @@ public function __construct() {
parent::__construct();
}
- public function preProcess() {
- parent::preProcess();
- }
-
- public function select() {
+ public function select(): void {
$select = [];
$this->_columnHeaders = [];
foreach ($this->_columns as $tableName => $table) {
@@ -376,24 +372,12 @@ public function select() {
}
}
}
- $this->selectClause = $select;
+ $this->_selectClauses = $select;
$this->_select = 'SELECT ' . implode(', ', $select) . ' ';
}
- /**
- * @param array $fields
- * @param array $files
- * @param CRM_Core_Form $self
- *
- * @return array
- */
- public static function formRule($fields, $files, $self) {
- $errors = $grouping = [];
- return $errors;
- }
-
- public function from() {
+ public function from(): void {
$alias_constituent = 'constituentname';
$alias_creditor = 'contact_civireport';
$this->_from = "
@@ -457,7 +441,7 @@ public function from() {
public function groupBy() {
$this->_rollup = 'WITH ROLLUP';
- $this->_select = CRM_Contact_BAO_Query::appendAnyValueToSelect($this->selectClause, ["{$this->_aliases['civicrm_contribution_soft']}.contact_id", "constituentname.id"]);
+ $this->_select = CRM_Contact_BAO_Query::appendAnyValueToSelect($this->_selectClauses, ["{$this->_aliases['civicrm_contribution_soft']}.contact_id", "constituentname.id"]);
$this->_groupBy = "
GROUP BY {$this->_aliases['civicrm_contribution_soft']}.contact_id, constituentname.id {$this->_rollup}";
}
diff --git a/CRM/Report/Form/Contribute/Summary.php b/CRM/Report/Form/Contribute/Summary.php
index 474c4e21da34..32b51586568d 100644
--- a/CRM/Report/Form/Contribute/Summary.php
+++ b/CRM/Report/Form/Contribute/Summary.php
@@ -58,6 +58,7 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
* Class constructor.
*/
public function __construct() {
+ $batches = CRM_Batch_BAO_Batch::getBatches();
$this->_columns = [
'civicrm_contact' => [
'dao' => 'CRM_Contact_DAO_Contact',
@@ -155,12 +156,6 @@ public function __construct() {
'default' => [1],
'type' => CRM_Utils_Type::T_INT,
],
- 'contribution_page_id' => [
- 'title' => ts('Contribution Page'),
- 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
- 'options' => CRM_Contribute_PseudoConstant::contributionPage(),
- 'type' => CRM_Utils_Type::T_INT,
- ],
'currency' => [
'title' => ts('Currency'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
@@ -276,7 +271,7 @@ public function __construct() {
'batch_id' => [
'title' => ts('Batch Title'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
- 'options' => CRM_Batch_BAO_Batch::getBatches(),
+ 'options' => $batches,
'type' => CRM_Utils_Type::T_INT,
],
],
@@ -342,6 +337,9 @@ public function __construct() {
$this->addCampaignFields('civicrm_contribution', TRUE);
+ if (!$batches) {
+ unset($this->_columns['civicrm_batch']);
+ }
// Add charts support
$this->_charts = [
'' => ts('Tabular'),
@@ -383,7 +381,7 @@ public function select() {
case 'FISCALYEAR':
$config = CRM_Core_Config::singleton();
$fy = $config->fiscalYearStart;
- $fiscal = self::fiscalYearOffset($field['dbAlias']);
+ $fiscal = $this->fiscalYearOffset($field['dbAlias']);
$select[] = "DATE_ADD(MAKEDATE({$fiscal}, 1), INTERVAL ({$fy['M']})-1 MONTH) AS {$tableName}_{$fieldName}_start";
$select[] = "{$fiscal} AS {$tableName}_{$fieldName}_subtotal";
@@ -750,7 +748,7 @@ public function statistics(&$rows) {
foreach ($currencies as $currency) {
$softTotalAmount[] = CRM_Utils_Money::format($currSoftAmount[$currency], $currency) .
- " (" . $currSoftCount[$currency] . ")";
+ ' (' . $currSoftCount[$currency] . ')';
$softAverage[] = CRM_Utils_Money::format(($currSoftAverage[$currency] / $averageSoftCount[$currency]), $currency);
}
}
diff --git a/CRM/Report/Form/Contribute/Sybunt.php b/CRM/Report/Form/Contribute/Sybunt.php
index ed9a2080a1c3..318e007cacc3 100644
--- a/CRM/Report/Form/Contribute/Sybunt.php
+++ b/CRM/Report/Form/Contribute/Sybunt.php
@@ -370,9 +370,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
if (($fieldName == 'contribution_status_id' ||
$fieldName == 'financial_type_id') && !empty($clause)
@@ -526,13 +526,13 @@ public function buildChart(&$rows) {
foreach ($rows as $key => $row) {
$display["upto_{$upto}"]
- = CRM_Utils_Array::value("upto_{$upto}", $display) + CRM_Utils_Array::value("civicrm_upto_{$upto}", $row);
+ = ($display["upto_{$upto}"] ?? 0) + ($row["civicrm_upto_{$upto}"] ?? 0);
$display[$previous_year]
- = CRM_Utils_Array::value($previous_year, $display) + CRM_Utils_Array::value($previous_year, $row);
+ = ($display[$previous_year] ?? 0) + ($row[$previous_year] ?? 0);
$display[$previous_two_year]
- = CRM_Utils_Array::value($previous_two_year, $display) + CRM_Utils_Array::value($previous_two_year, $row);
+ = ($display[$previous_two_year] ?? 0) + ($row[$previous_two_year] ?? 0);
$display[$previous_three_year]
- = CRM_Utils_Array::value($previous_three_year, $display) + CRM_Utils_Array::value($previous_three_year, $row);
+ = ($display[$previous_three_year] ?? 0) + ($row[$previous_three_year] ?? 0);
}
$graphRows['value'] = $display;
diff --git a/CRM/Report/Form/Contribute/TopDonor.php b/CRM/Report/Form/Contribute/TopDonor.php
index 0dcff4a211c2..6d2f7beb754a 100644
--- a/CRM/Report/Form/Contribute/TopDonor.php
+++ b/CRM/Report/Form/Contribute/TopDonor.php
@@ -266,9 +266,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Event/IncomeCountSummary.php b/CRM/Report/Form/Event/IncomeCountSummary.php
index e42e0036fa1c..d0865aa4eae1 100644
--- a/CRM/Report/Form/Event/IncomeCountSummary.php
+++ b/CRM/Report/Form/Event/IncomeCountSummary.php
@@ -218,9 +218,9 @@ public function where(): void {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Event/Summary.php b/CRM/Report/Form/Event/Summary.php
index ca86340dcd82..c11d4935864f 100644
--- a/CRM/Report/Form/Event/Summary.php
+++ b/CRM/Report/Form/Event/Summary.php
@@ -132,50 +132,48 @@ public function select() {
$this->_select = 'SELECT ' . implode(', ', $select);
}
- public function from() {
+ public function from(): void {
$this->_from = " FROM civicrm_event {$this->_aliases['civicrm_event']} ";
}
- public function where() {
+ public function where(): void {
$clauses = [];
- $this->_participantWhere = "";
- foreach ($this->_columns as $tableName => $table) {
+ foreach ($this->_columns as $table) {
if (array_key_exists('filters', $table)) {
foreach ($table['filters'] as $fieldName => $field) {
- $clause = NULL;
if (($field['type'] ?? 0) & CRM_Utils_Type::T_DATE) {
$relative = $this->_params["{$fieldName}_relative"] ?? NULL;
$from = $this->_params["{$fieldName}_from"] ?? NULL;
$to = $this->_params["{$fieldName}_to"] ?? NULL;
if ($relative || $from || $to) {
- $clause = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
+ $clauses[] = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
}
}
else {
$op = $this->_params["{$fieldName}_op"] ?? NULL;
if ($op) {
- $clause = $this->whereClause($field,
+ $clauses[] = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL,
);
}
}
- if (!empty($this->_params['id_value'])) {
- $idValue = is_array($this->_params['id_value']) ? implode(',', $this->_params['id_value']) : $this->_params['id_value'];
- $this->_participantWhere = " AND civicrm_participant.event_id IN ( $idValue ) ";
- }
-
- if (!empty($clause)) {
- $clauses[] = $clause;
- }
}
}
}
$clauses[] = "{$this->_aliases['civicrm_event']}.is_template = 0";
- $this->_where = 'WHERE ' . implode(' AND ', $clauses);
+ $this->_where = 'WHERE ' . implode(' AND ', array_filter($clauses));
+ }
+
+ public function getEventFilter(): string {
+ $eventID = array_filter((array) $this->_params['id_value']);
+ if (empty($eventID)) {
+ return '';
+ }
+ return ' AND civicrm_participant.event_id IN ( ' . implode(',', $eventID) . ') ';
}
public function groupBy() {
@@ -192,7 +190,7 @@ public function participantInfo() {
$statusType1 = CRM_Event_PseudoConstant::participantStatus(NULL, 'is_counted = 1');
$statusType2 = CRM_Event_PseudoConstant::participantStatus(NULL, 'is_counted = 0');
- $sql = "
+ $sql = '
SELECT civicrm_participant.event_id AS event_id,
civicrm_participant.status_id AS statusId,
COUNT( civicrm_participant.id ) AS participant,
@@ -202,11 +200,11 @@ public function participantInfo() {
FROM civicrm_participant
WHERE civicrm_participant.is_test = 0
- $this->_participantWhere
+ ' . $this->getEventFilter() . '
GROUP BY civicrm_participant.event_id,
civicrm_participant.status_id,
- civicrm_participant.fee_currency";
+ civicrm_participant.fee_currency';
$info = CRM_Core_DAO::executeQuery($sql);
$participant_data = $participant_info = $currency = [];
@@ -306,8 +304,8 @@ public function postProcess() {
while ($dao->fetch()) {
$row = [];
foreach ($this->_columnHeaders as $key => $value) {
- if (($key == 'civicrm_event_start_date') ||
- ($key == 'civicrm_event_end_date')
+ if (($key === 'civicrm_event_start_date') ||
+ ($key === 'civicrm_event_end_date')
) {
//get event start date and end date in custom datetime format
$row[$key] = CRM_Utils_Date::customFormat($dao->$key);
diff --git a/CRM/Report/Form/Instance.php b/CRM/Report/Form/Instance.php
index ecd39427156b..fe77273cfcae 100644
--- a/CRM/Report/Form/Instance.php
+++ b/CRM/Report/Form/Instance.php
@@ -318,7 +318,7 @@ public static function postProcess(&$form, $redirect = TRUE) {
// Delete navigation if exists.
$navId = CRM_Core_DAO::getFieldValue('CRM_Report_DAO_ReportInstance', $instanceID, 'navigation_id', 'id');
if ($navId) {
- CRM_Core_BAO_Navigation::processDelete($navId);
+ CRM_Core_BAO_Navigation::deleteRecord(['id' => $navId]);
CRM_Core_BAO_Navigation::resetNavigation();
}
}
diff --git a/CRM/Report/Form/Mailing/Bounce.php b/CRM/Report/Form/Mailing/Bounce.php
index ebe9d1a84644..67bd05b1adc9 100644
--- a/CRM/Report/Form/Mailing/Bounce.php
+++ b/CRM/Report/Form/Mailing/Bounce.php
@@ -349,9 +349,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
diff --git a/CRM/Report/Form/Mailing/Summary.php b/CRM/Report/Form/Mailing/Summary.php
index d2e4e61942a3..7125920631a5 100644
--- a/CRM/Report/Form/Mailing/Summary.php
+++ b/CRM/Report/Form/Mailing/Summary.php
@@ -436,9 +436,9 @@ public function where() {
else {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Member/Lapse.php b/CRM/Report/Form/Member/Lapse.php
index 236c4cd30987..d2443dd7e3b6 100644
--- a/CRM/Report/Form/Member/Lapse.php
+++ b/CRM/Report/Form/Member/Lapse.php
@@ -232,9 +232,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Membership/Summary.php b/CRM/Report/Form/Membership/Summary.php
index 4ba26fb9d8ef..68fc16695cf5 100644
--- a/CRM/Report/Form/Membership/Summary.php
+++ b/CRM/Report/Form/Membership/Summary.php
@@ -197,9 +197,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Form/Walklist/Walklist.php b/CRM/Report/Form/Walklist/Walklist.php
index 14b40773b37a..de15f85827c2 100644
--- a/CRM/Report/Form/Walklist/Walklist.php
+++ b/CRM/Report/Form/Walklist/Walklist.php
@@ -130,9 +130,9 @@ public function where() {
if ($op) {
$clause = $this->whereClause($field,
$op,
- CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
- CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
+ $this->_params["{$fieldName}_value"] ?? NULL,
+ $this->_params["{$fieldName}_min"] ?? NULL,
+ $this->_params["{$fieldName}_max"] ?? NULL
);
}
}
diff --git a/CRM/Report/Page/Options.php b/CRM/Report/Page/Options.php
index a82c931d7cf9..4fb9d81b1361 100644
--- a/CRM/Report/Page/Options.php
+++ b/CRM/Report/Page/Options.php
@@ -94,22 +94,26 @@ public function &links() {
'url' => 'civicrm/admin/report/register/' . self::$_gName,
'qs' => 'action=update&id=%%id%%&reset=1',
'title' => ts('Edit %1', [1 => self::$_gLabel]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::UPDATE),
],
CRM_Core_Action::DISABLE => [
'name' => ts('Disable'),
'ref' => 'crm-enable-disable',
'title' => ts('Disable %1', [1 => self::$_gLabel]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DISABLE),
],
CRM_Core_Action::ENABLE => [
'name' => ts('Enable'),
'ref' => 'crm-enable-disable',
'title' => ts('Enable %1', [1 => self::$_gLabel]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::ENABLE),
],
CRM_Core_Action::DELETE => [
'name' => ts('Delete'),
'url' => 'civicrm/admin/report/register/' . self::$_gName,
'qs' => 'action=delete&id=%%id%%&reset=1',
'title' => ts('Delete %1 Type', [1 => self::$_gLabel]),
+ 'weight' => CRM_Core_Action::getWeight(CRM_Core_Action::DELETE),
],
];
}
diff --git a/CRM/SMS/Form/Provider.php b/CRM/SMS/Form/Provider.php
index 1f5e2313e125..602f0e68475d 100644
--- a/CRM/SMS/Form/Provider.php
+++ b/CRM/SMS/Form/Provider.php
@@ -157,8 +157,8 @@ public function postProcess() {
}
$recData = $values = $this->controller->exportValues($this->_name);
- $recData['is_active'] = CRM_Utils_Array::value('is_active', $recData, 0);
- $recData['is_default'] = CRM_Utils_Array::value('is_default', $recData, 0);
+ $recData['is_active'] = $recData['is_active'] ?? 0;
+ $recData['is_default'] = $recData['is_default'] ?? 0;
if ($this->_action && (CRM_Core_Action::UPDATE || CRM_Core_Action::ADD)) {
if ($this->_id) {
diff --git a/CRM/Tag/Form/Edit.php b/CRM/Tag/Form/Edit.php
index 09d38c00f06f..6fa36b90f284 100644
--- a/CRM/Tag/Form/Edit.php
+++ b/CRM/Tag/Form/Edit.php
@@ -102,13 +102,9 @@ public function buildQuickForm() {
$this->applyFilter('__ALL__', 'trim');
- $this->add('text', 'name', ts('Name'),
- CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'name'), TRUE
+ $this->add('text', 'label', ts('Label'),
+ CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'label'), TRUE
);
- $this->addRule('name', ts('Name already exists in Database.'), 'objectExists', [
- 'CRM_Core_DAO_Tag',
- $this->_id,
- ]);
$this->add('text', 'description', ts('Description'),
CRM_Core_DAO::getAttribute('CRM_Core_DAO_Tag', 'description')
@@ -142,7 +138,7 @@ public function setDefaultValues() {
if (empty($this->_id) && $cloneFrom) {
$params = ['id' => $cloneFrom];
CRM_Core_BAO_Tag::retrieve($params, $this->_values);
- $this->_values['name'] .= ' (' . ts('copy') . ')';
+ $this->_values['label'] .= ' (' . ts('copy') . ')';
if (!empty($this->_values['is_reserved']) && !CRM_Core_Permission::check('administer reserved tags')) {
$this->_values['is_reserved'] = 0;
}
@@ -171,10 +167,10 @@ public function postProcess() {
}
if (count($this->_id) == 1 && $deleted == 1) {
if ($tag['is_tagset']) {
- CRM_Core_Session::setStatus(ts("The tag set '%1' has been deleted.", [1 => $tag['name']]), ts('Deleted'), 'success');
+ CRM_Core_Session::setStatus(ts("The tag set '%1' has been deleted.", [1 => $tag['label']]), ts('Deleted'), 'success');
}
else {
- CRM_Core_Session::setStatus(ts("The tag '%1' has been deleted.", [1 => $tag['name']]), ts('Deleted'), 'success');
+ CRM_Core_Session::setStatus(ts("The tag '%1' has been deleted.", [1 => $tag['label']]), ts('Deleted'), 'success');
}
}
else {
@@ -211,7 +207,7 @@ public function postProcess() {
$params['is_selectable'] = 0;
}
$tag = CRM_Core_BAO_Tag::add($params);
- CRM_Core_Session::setStatus(ts("The tag '%1' has been saved.", [1 => $tag->name]), ts('Saved'), 'success');
+ CRM_Core_Session::setStatus(ts("The tag '%1' has been saved.", [1 => $tag->label]), ts('Saved'), 'success');
$this->ajaxResponse['tag'] = $tag->toArray();
}
CRM_Core_Session::singleton()->pushUserContext(CRM_Utils_System::url('civicrm/tag'));
diff --git a/CRM/Tag/Page/Tag.php b/CRM/Tag/Page/Tag.php
index 772439b7c4e1..6d4a26c69431 100644
--- a/CRM/Tag/Page/Tag.php
+++ b/CRM/Tag/Page/Tag.php
@@ -40,7 +40,7 @@ public function run() {
}
$result = civicrm_api3('Tag', 'get', [
- 'return' => ["name", "used_for", "description", "created_id.display_name", "created_date", "is_reserved"],
+ 'return' => ["name", "label", "used_for", "description", "created_id.display_name", "created_date", "is_reserved"],
'is_tagset' => 1,
'options' => ['limit' => 0],
]);
diff --git a/CRM/UF/Form/Field.php b/CRM/UF/Form/Field.php
index 5e9e87a22987..053e61c13a26 100644
--- a/CRM/UF/Form/Field.php
+++ b/CRM/UF/Form/Field.php
@@ -725,11 +725,11 @@ public static function formRulePrimaryCheck($fields, $profileFieldName, $groupFi
* list of errors to be posted back to the form
*/
public static function formRule($fields, $files, $self) {
- $is_required = CRM_Utils_Array::value('is_required', $fields, FALSE);
- $is_registration = CRM_Utils_Array::value('is_registration', $fields, FALSE);
- $is_view = CRM_Utils_Array::value('is_view', $fields, FALSE);
- $in_selector = CRM_Utils_Array::value('in_selector', $fields, FALSE);
- $is_active = CRM_Utils_Array::value('is_active', $fields, FALSE);
+ $is_required = $fields['is_required'] ?? FALSE;
+ $is_registration = $fields['is_registration'] ?? FALSE;
+ $is_view = $fields['is_view'] ?? FALSE;
+ $in_selector = $fields['in_selector'] ?? FALSE;
+ $is_active = $fields['is_active'] ?? FALSE;
$errors = [];
if ($is_view && $is_registration) {
diff --git a/CRM/Upgrade/Form.php b/CRM/Upgrade/Form.php
index 87ad4c5cc31e..27cfa35e24be 100644
--- a/CRM/Upgrade/Form.php
+++ b/CRM/Upgrade/Form.php
@@ -141,34 +141,6 @@ public function checkVersionRelease($version, $release) {
return ($versionParts[2] == $release);
}
- /**
- * @param $constraints
- *
- * @return array
- */
- public function checkSQLConstraints(&$constraints) {
- $pass = $fail = 0;
- foreach ($constraints as $constraint) {
- if ($this->checkSQLConstraint($constraint)) {
- $pass++;
- }
- else {
- $fail++;
- }
- return [$pass, $fail];
- }
- }
-
- /**
- * @param $constraint
- *
- * @return bool
- */
- public function checkSQLConstraint($constraint) {
- // check constraint here
- return TRUE;
- }
-
/**
* @param string $fileName
* @param bool $isQueryString
diff --git a/CRM/Upgrade/Incremental/MessageTemplates.php b/CRM/Upgrade/Incremental/MessageTemplates.php
index 58e605a1e9dd..22ae1f1098a7 100644
--- a/CRM/Upgrade/Incremental/MessageTemplates.php
+++ b/CRM/Upgrade/Incremental/MessageTemplates.php
@@ -359,6 +359,15 @@ protected function getTemplateUpdates() {
['name' => 'petition_sign', 'type' => 'subject'],
],
],
+ [
+ 'version' => '5.68.alpha1',
+ 'upgrade_descriptor' => ts('Significant changes to the template and available variables. Text version is discontinued'),
+ 'templates' => [
+ ['name' => 'event_offline_receipt', 'type' => 'text'],
+ ['name' => 'event_offline_receipt', 'type' => 'html'],
+ ['name' => 'event_offline_receipt', 'type' => 'subject'],
+ ],
+ ],
];
}
@@ -572,7 +581,7 @@ public static function updateReservedAndMaybeDefaultTemplates(CRM_Queue_TaskCont
continue;
}
$content = file_get_contents($filePath);
- if ($content) {
+ if ($content !== FALSE) {
CRM_Core_DAO::executeQuery(
"UPDATE civicrm_msg_template SET msg_{$type} = %1 WHERE id = %2", [
1 => [$content, 'String'],
diff --git a/CRM/Upgrade/Incremental/php/FiveFour.php b/CRM/Upgrade/Incremental/php/FiveFour.php
index b327366a14ec..07ce677392de 100644
--- a/CRM/Upgrade/Incremental/php/FiveFour.php
+++ b/CRM/Upgrade/Incremental/php/FiveFour.php
@@ -69,7 +69,7 @@ public static function addActivityDefaultAssigneeOptions() {
'option_group_id' => 'activity_default_assignee',
'name' => $option['name'],
'label' => $option['label'],
- 'is_default' => CRM_Utils_Array::value('is_default', $option, 0),
+ 'is_default' => $option['is_default'] ?? 0,
'is_active' => TRUE,
]);
}
diff --git a/CRM/Upgrade/Incremental/php/FiveSixtyEight.php b/CRM/Upgrade/Incremental/php/FiveSixtyEight.php
new file mode 100644
index 000000000000..c1bedfa946ad
--- /dev/null
+++ b/CRM/Upgrade/Incremental/php/FiveSixtyEight.php
@@ -0,0 +1,44 @@
+addTask('Add Tag.label field', 'addColumn', 'civicrm_tag', 'label', "varchar(64) NOT NULL COMMENT 'User-facing tag name' AFTER `name`");
+ $this->addTask('Update Tag.name field', 'alterColumn', 'civicrm_tag', 'name', "varchar(64) NOT NULL COMMENT 'Unique machine name'");
+ $this->addTask('Update Tag.created_date field', 'alterColumn', 'civicrm_tag', 'created_date', "datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'Date and time that tag was created.'");
+ $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
+ $this->addTask('Update civicrm_managed.entity_id', 'alterColumn', 'civicrm_managed', 'entity_id', "int unsigned COMMENT 'Soft foreign key to the referenced item.'");
+ $this->addTask('Update civicrm_managed.module', 'alterColumn', 'civicrm_managed', 'module', "varchar(255) NOT NULL COMMENT 'Name of the module which declared this object (soft FK to civicrm_extension.full_name)'");
+ $this->addTask('Update civicrm_managed.name', 'alterColumn', 'civicrm_managed', 'name', "varchar(255) NOT NULL COMMENT 'Symbolic name used by the module to identify the object'");
+ $this->addTask('Update civicrm_managed.cleanup', 'alterColumn', 'civicrm_managed', 'cleanup', "varchar(16) NOT NULL DEFAULT 'always' COMMENT 'Policy on when to cleanup entity (always, never, unused)'");
+ $this->addTask('Update civicrm_acl.is_active', 'alterColumn', 'civicrm_acl', 'is_active', "tinyint NOT NULL DEFAULT 1 COMMENT 'Is this property active?'");
+ $this->addTask('Update civicrm_dashboard_contact.is_active', 'alterColumn', 'civicrm_dashboard_contact', 'is_active', "tinyint NOT NULL DEFAULT 0 COMMENT 'Is this widget active?'");
+ }
+
+}
diff --git a/CRM/Upgrade/Incremental/php/FiveSixtySeven.php b/CRM/Upgrade/Incremental/php/FiveSixtySeven.php
index 4ed4c2b2e301..1f4941cf7776 100644
--- a/CRM/Upgrade/Incremental/php/FiveSixtySeven.php
+++ b/CRM/Upgrade/Incremental/php/FiveSixtySeven.php
@@ -21,6 +21,8 @@
*/
class CRM_Upgrade_Incremental_php_FiveSixtySeven extends CRM_Upgrade_Incremental_Base {
+ const MAILING_BATCH_SIZE = 500000;
+
public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
parent::setPreUpgradeMessage($preUpgradeMessage, $rev, $currentVer);
if ($rev === '5.67.alpha1') {
@@ -54,7 +56,41 @@ public function upgrade_5_67_alpha1($rev): void {
$this->addTask('Add cache_fill_took column to Group table', 'addColumn', 'civicrm_group', 'cache_fill_took',
'DOUBLE DEFAULT NULL COMMENT "Seconds taken to fill smart group cache, not always related to cache_date"',
FALSE);
- $this->addTask('Update civicrm_mailing_event_queue to permit deleting records from civicrm_mailing_job', 'updateMailingEventQueueTable', 'updateMailingEventQueueTable');
+ $this->addTask('Update civicrm_mailing_event_queue to permit deleting records from civicrm_mailing_job', 'updateMailingEventQueueTable');
+ $this->addTask('Update CiviMail menus labels', 'updateMailingMenuLabels');
+ }
+
+ /**
+ * Upgrade step; adds tasks including 'runSql'.
+ *
+ * @param string $rev
+ * The version number matching this function name
+ */
+ public function upgrade_5_67_beta2($rev): void {
+ // Repeat step from 5.66 because it was added late in the release-cycle
+ $this->addTask('Make ActionSchedule.name required', 'alterColumn', 'civicrm_action_schedule', 'name', "varchar(128) NOT NULL COMMENT 'Name of the scheduled action'");
+ $this->addTask('Make Discount.entity_table required', 'alterColumn', 'civicrm_discount', 'entity_table', "varchar(64) NOT NULL COMMENT 'physical tablename for entity being joined to discount, e.g. civicrm_event'");
+ }
+
+ /**
+ * Some time ago, the labels for Mailing menu items were simplified for new
+ * installs. Now that the old strings have been removed from Transifex, it
+ * breaks translations, so we force the update, but only if the label was not
+ * customized (if name=label).
+ */
+ public static function updateMailingMenuLabels(CRM_Queue_TaskContext $ctx): bool {
+ $changes = [
+ 'Draft and Unscheduled Mailings' => 'Draft Mailings',
+ 'Scheduled and Sent Mailings' => 'Sent Mailings',
+ ];
+ foreach ($changes as $old => $new) {
+ CRM_Core_DAO::executeQuery('UPDATE civicrm_navigation SET label = %1 WHERE name = %2 AND label = %3', [
+ 1 => [$new, 'String'],
+ 2 => [$old, 'String'],
+ 3 => [$old, 'String'],
+ ]);
+ }
+ return TRUE;
}
/**
@@ -85,6 +121,16 @@ public static function updateMailingEventQueueTable(CRM_Queue_TaskContext $ctx):
FOREIGN KEY (`job_id`)
REFERENCES `civicrm_mailing_job`(`id`) ON DELETE SET NULL
', [], FALSE, FALSE, FALSE, FALSE);
+
+ [$minId, $maxId] = CRM_Core_DAO::executeQuery("SELECT coalesce(min(id),0), coalesce(max(id),0)
+ FROM civicrm_mailing_event_queue ")->getDatabaseResult()->fetchRow();
+ for ($startId = $minId; $startId <= $maxId; $startId += self::MAILING_BATCH_SIZE) {
+ $endId = min($maxId, $startId + self::MAILING_BATCH_SIZE - 1);
+ $task = new CRM_Queue_Task([static::class, 'fillMailingEvents'],
+ [$startId, $endId],
+ sprintf('Backfill civicrm_mailing_event_queue (%d => %d)', $startId, $endId));
+ $ctx->queue->createItem($task, ['weight' => -1]);
+ }
}
catch (\Civi\Core\Exception\DBQueryException $e) {
throw new CRM_Core_Exception(
@@ -103,6 +149,20 @@ public static function updateMailingEventQueueTable(CRM_Queue_TaskContext $ctx):
return TRUE;
}
+ public static function fillMailingEvents(CRM_Queue_TaskContext $ctx, int $startId, int $endId): bool {
+ CRM_Core_DAO::executeQuery('
+UPDATE civicrm_mailing_event_queue q
+INNER JOIN civicrm_mailing_job job ON job.id = q.job_id
+SET q.mailing_id = job.mailing_id, q.is_test=job.is_test
+WHERE q.id >= %1 AND q.id <= %2 AND q.mailing_id IS NULL',
+ [
+ 1 => [$startId, 'Int'],
+ 2 => [$endId, 'Int'],
+ ]
+ );
+ return TRUE;
+ }
+
public static function addNoteNote(CRM_Queue_TaskContext $ctx): bool {
CRM_Core_BAO_OptionValue::ensureOptionValueExists([
'option_group_id' => 'note_used_for',
diff --git a/CRM/Upgrade/Incremental/php/FiveSixtySix.php b/CRM/Upgrade/Incremental/php/FiveSixtySix.php
index 55c6d1df36d0..cc0bdd2853c8 100644
--- a/CRM/Upgrade/Incremental/php/FiveSixtySix.php
+++ b/CRM/Upgrade/Incremental/php/FiveSixtySix.php
@@ -35,12 +35,12 @@ public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NU
* The version number matching this function name
*/
public function upgrade_5_66_alpha1($rev): void {
+ // Increase column length before the upgrade sql writes to it
+ $this->addTask('Increase ActionSchedule.name length', 'alterColumn', 'civicrm_action_schedule', 'name', "varchar(128) COMMENT 'Name of the scheduled action'");
$this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
+ // These run after the sql file
$this->addTask('Make Contribution.tax_amount required', 'alterColumn', 'civicrm_contribution', 'tax_amount', "decimal(20,2) DEFAULT 0 NOT NULL COMMENT 'Total tax amount of this contribution.'");
$this->addTask('Make LineItem.tax_amount required', 'alterColumn', 'civicrm_line_item', 'tax_amount', "decimal(20,2) DEFAULT 0 NOT NULL COMMENT 'tax of each item'");
- // These run after the sql file
- $this->addTask('Make Discount.entity_table required', 'alterColumn', 'civicrm_discount', 'entity_table', "varchar(64) NOT NULL COMMENT 'Name of the action(reminder)'");
- $this->addTask('Make ActionSchedule.name required', 'alterColumn', 'civicrm_action_schedule', 'name', "varchar(64) NOT NULL COMMENT 'physical tablename for entity being joined to discount, e.g. civicrm_event'");
$this->addTask(ts('Create index %1', [1 => 'civicrm_action_schedule.UI_name']), 'addIndex', 'civicrm_action_schedule', 'name', 'UI');
$this->addTask('Add fields to civicrm_mail_settings to allow more flexibility for email to activity', 'addMailSettingsFields');
$this->addTask('Move serialized contents of civicrm_survey.recontact_interval into civicrm_option_value.filter', 'migrateRecontactInterval');
diff --git a/CRM/Upgrade/Incremental/sql/5.67.alpha1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.67.alpha1.mysql.tpl
index 4b47ee98b060..54afcfc924a4 100644
--- a/CRM/Upgrade/Incremental/sql/5.67.alpha1.mysql.tpl
+++ b/CRM/Upgrade/Incremental/sql/5.67.alpha1.mysql.tpl
@@ -5,7 +5,9 @@ UPDATE civicrm_note SET privacy = 0 WHERE privacy IS NULL;
{* NULL values would be nonsensical and useless - no reason to keep them *}
DELETE FROM civicrm_entity_file WHERE entity_table IS NULL;
-SELECT @country_id := id from civicrm_country where name = 'India' AND iso_code = 'IN';
+{* Delete navigation links to old campaign dashboard *}
+DELETE FROM `civicrm_navigation` WHERE `url` LIKE 'civicrm/campaign?reset=1%';
+SELECT @country_id := id from civicrm_country where name = 'India' AND iso_code = 'IN';
UPDATE `civicrm_state_province` SET abbreviation = 'MH' WHERE name = 'Maharashtra' AND country_id = @country_id;
UPDATE `civicrm_state_province` SET abbreviation = 'CG' WHERE name = 'Chhattisgarh' AND country_id = @country_id;
diff --git a/CRM/Upgrade/Incremental/sql/5.68.alpha1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.68.alpha1.mysql.tpl
new file mode 100644
index 000000000000..ddfb5373fbe9
--- /dev/null
+++ b/CRM/Upgrade/Incremental/sql/5.68.alpha1.mysql.tpl
@@ -0,0 +1,11 @@
+{* file to handle db changes in 5.68.alpha1 during upgrade *}
+
+UPDATE `civicrm_acl` SET `is_active` = 0 WHERE `is_active` IS NULL;
+UPDATE `civicrm_dashboard_contact` SET `is_active` = 0 WHERE `is_active` IS NULL;
+
+UPDATE `civicrm_tag` SET `label` = `name` WHERE `label` = '';
+
+{* This column is now required. Delete any null values; a managed entity without a name is useless *}
+DELETE FROM civicrm_managed WHERE name IS NULL;
+{* This column is now required. Set to default value if null or invalid *}
+UPDATE civicrm_managed SET cleanup = 'always' WHERE cleanup IS NULL OR cleanup NOT IN ('always', 'never', 'unused');
diff --git a/CRM/Utils/Address.php b/CRM/Utils/Address.php
index 62c5b2a88faa..aa0703e518be 100644
--- a/CRM/Utils/Address.php
+++ b/CRM/Utils/Address.php
@@ -32,7 +32,7 @@ class CRM_Utils_Address {
* The desired address format.
* @param bool $microformat
* If true indicates, the address to be built in hcard-microformat standard.
- * @param bool $mailing
+ * @param bool $unused
* Should ALWAYS be false.
* @param string[] $tokenFields
*
@@ -44,24 +44,18 @@ public static function format(
$fields,
$format = NULL,
$microformat = FALSE,
- $mailing = FALSE,
+ $unused = FALSE,
$tokenFields = NULL
) {
- $mailing = FALSE;
if (!$format) {
$format = Civi::settings()->get('address_format');
}
-
- if ($mailing) {
- $format = Civi::settings()->get('mailing_format');
- }
-
$formatted = $format;
$fullPostalCode = $fields['postal_code'] ?? NULL;
if (!empty($fields['postal_code_suffix'])) {
- $fullPostalCode .= "-$fields[postal_code_suffix]";
+ $fullPostalCode .= '-' . $fields['postal_code_suffix'];
}
// make sure that some of the fields do have values
@@ -78,47 +72,29 @@ public static function format(
}
}
- //CRM-16876 Display countries in all caps when in mailing mode.
- if ($mailing && !empty($fields['country'])) {
- if (Civi::settings()->get('hideCountryMailingLabels')) {
- $domain = CRM_Core_BAO_Domain::getDomain();
- $domainLocation = CRM_Core_BAO_Location::getValues(['contact_id' => $domain->contact_id]);
- $domainAddress = $domainLocation['address'][1];
- $domainCountryId = $domainAddress['country_id'];
- if ($fields['country'] == CRM_Core_PseudoConstant::country($domainCountryId)) {
- $fields['country'] = NULL;
- }
- else {
- //Capitalization display on uppercase to contries with special characters
- $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8");
- }
- }
- else {
- $fields['country'] = mb_convert_case($fields['country'], MB_CASE_UPPER, "UTF-8");
- }
- }
-
if (!$microformat) {
// replacements in case of Individual Name Format
$replacements = [
'contact.display_name' => $fields['display_name'] ?? NULL,
- 'contact.individual_prefix' => $fields['individual_prefix'] ?? NULL,
'contact.formal_title' => $fields['formal_title'] ?? NULL,
'contact.first_name' => $fields['first_name'] ?? NULL,
'contact.middle_name' => $fields['middle_name'] ?? NULL,
'contact.last_name' => $fields['last_name'] ?? NULL,
- 'contact.individual_suffix' => $fields['individual_suffix'] ?? NULL,
+ 'contact.individual_prefix' => $fields['prefix_id:label'] ?? ($fields['individual_prefix'] ?? NULL),
+ 'contact.prefix_id:label' => $fields['prefix_id:label'] ?? ($fields['individual_prefix'] ?? NULL),
+ 'contact.individual_suffix' => $fields['suffix_id:label'] ?? ($fields['individual_suffix'] ?? NULL),
+ 'contact.suffix_id:label' => $fields['suffix_id:label'] ?? ($fields['individual_suffix'] ?? NULL),
'contact.address_name' => $fields['address_name'] ?? NULL,
'contact.street_address' => $fields['street_address'] ?? NULL,
'contact.supplemental_address_1' => $fields['supplemental_address_1'] ?? NULL,
'contact.supplemental_address_2' => $fields['supplemental_address_2'] ?? NULL,
'contact.supplemental_address_3' => $fields['supplemental_address_3'] ?? NULL,
'contact.city' => $fields['city'] ?? NULL,
- 'contact.state_province_name' => $fields['state_province_name'] ?? NULL,
- 'contact.county' => $fields['county'] ?? NULL,
- 'contact.state_province' => $fields['state_province'] ?? NULL,
+ 'contact.state_province_name' => $fields['state_province_id:label'] ?? ($fields['state_province_name'] ?? NULL),
+ 'contact.county' => $fields['county_id:label'] ?? ($fields['county'] ?? NULL),
+ 'contact.state_province' => $fields['state_province_id:label'] ?? ($fields['state_province'] ?? NULL),
'contact.postal_code' => $fullPostalCode,
- 'contact.country' => $fields['country'] ?? NULL,
+ 'contact.country' => $fields['country_id:label'] ?? ($fields['country'] ?? NULL),
'contact.world_region' => $fields['world_region'] ?? NULL,
'contact.geo_code_1' => $fields['geo_code_1'] ?? NULL,
'contact.geo_code_2' => $fields['geo_code_2'] ?? NULL,
diff --git a/CRM/Utils/Array.php b/CRM/Utils/Array.php
index da71c1197120..b4aad583b6c9 100644
--- a/CRM/Utils/Array.php
+++ b/CRM/Utils/Array.php
@@ -43,18 +43,23 @@ public static function cast($value) {
}
/**
- * Returns $list[$key] if such element exists, or a default value otherwise.
+ * Returns $list[$key] if such element exists, or $default otherwise.
*
- * If $list is not actually an array at all, then the default value is
- * returned. We hope to deprecate this behaviour.
+ * If $list is not an array or ArrayAccess object, $default is returned.
*
+ * @deprecated
+ * In most cases this can be replaced with
+ * $list[$key] ?? $default
+ * with the minor difference that when $list[$key] exists and is NULL, this function will always
+ * return NULL.
*
* @param string $key
* Key value to look up in the array.
* @param array|ArrayAccess $list
* Array from which to look up a value.
* @param mixed $default
- * (optional) Value to return $list[$key] does not exist.
+ * (optional) Value to return when $list[$key] does not exist. If $default
+ * is not specified, NULL is used.
*
* @return mixed
* Can return any type, since $list might contain anything.
@@ -64,11 +69,8 @@ public static function value($key, $list, $default = NULL) {
return array_key_exists($key, $list) ? $list[$key] : $default;
}
if ($list instanceof ArrayAccess) {
- // ArrayAccess requires offsetExists is implemented for the equivalent to array_key_exists.
return $list->offsetExists($key) ? $list[$key] : $default;
}
- // @todo - eliminate these from core & uncomment this line.
- // CRM_Core_Error::deprecatedFunctionWarning('You have passed an invalid parameter for the "list"');
return $default;
}
@@ -1413,4 +1415,28 @@ public static function filterByPrefix(array &$collection, string $prefix): array
return $filtered;
}
+ /**
+ * Changes array keys to meet the expectations of select2.js
+ *
+ * @param array $options
+ * @param string $label
+ * @param string $id
+ * @return array
+ */
+ public static function formatForSelect2(array $options, string $label = 'label', string $id = 'id'): array {
+ foreach ($options as &$option) {
+ if (isset($option[$label])) {
+ $option['text'] = (string) $option[$label];
+ }
+ if (isset($option[$id])) {
+ $option['id'] = (string) $option[$id];
+ }
+ if (!empty($option['children'])) {
+ $option['children'] = self::formatForSelect2($option['children'], $label, $id);
+ }
+ $option = array_intersect_key($option, array_flip(['id', 'text', 'children', 'color', 'icon', 'description']));
+ }
+ return $options;
+ }
+
}
diff --git a/CRM/Utils/Check/Component/Env.php b/CRM/Utils/Check/Component/Env.php
index 2ac6246f6f2f..f0a88a71624a 100644
--- a/CRM/Utils/Check/Component/Env.php
+++ b/CRM/Utils/Check/Component/Env.php
@@ -1106,4 +1106,25 @@ public function checkPHPIntlExists() {
return $messages;
}
+ public function checkAngularModuleSettings() {
+ $messages = [];
+ $modules = Civi::container()->get('angular')->getModules();
+ foreach ($modules as $name => $module) {
+ if (!empty($module['settings'])) {
+ $messages[] = new CRM_Utils_Check_Message(
+ __FUNCTION__ . $name,
+ ts('The Angular file "%1" from extension "%2" must be updated to use "settingsFactory" instead of "settings". Developer info... ', [
+ 1 => $name,
+ 2 => $module['ext'],
+ 3 => 'target="_blank" href="https://github.com/civicrm/civicrm-core/pull/19052"',
+ ]),
+ ts('Unsupported Angular Setting'),
+ \Psr\Log\LogLevel::WARNING,
+ 'fa-code'
+ );
+ }
+ }
+ return $messages;
+ }
+
}
diff --git a/CRM/Utils/Date.php b/CRM/Utils/Date.php
index 2434fb33e06c..8fcf8690726e 100644
--- a/CRM/Utils/Date.php
+++ b/CRM/Utils/Date.php
@@ -280,16 +280,16 @@ function(int $monthNum) use ($intlFormatter) {
* @return int
*/
public static function unixTime($string) {
- if (empty($string)) {
+ if (!$string) {
return 0;
}
$parsedDate = date_parse($string);
- return mktime(CRM_Utils_Array::value('hour', $parsedDate),
- CRM_Utils_Array::value('minute', $parsedDate),
+ return mktime($parsedDate['hour'],
+ $parsedDate['minute'],
59,
- CRM_Utils_Array::value('month', $parsedDate),
- CRM_Utils_Array::value('day', $parsedDate),
- CRM_Utils_Array::value('year', $parsedDate)
+ $parsedDate['month'],
+ $parsedDate['day'],
+ $parsedDate['year']
);
}
diff --git a/CRM/Utils/EnglishNumber.php b/CRM/Utils/EnglishNumber.php
index c95bb6af21b6..37a8663ccef9 100644
--- a/CRM/Utils/EnglishNumber.php
+++ b/CRM/Utils/EnglishNumber.php
@@ -136,14 +136,14 @@ public static function toInt(string $english) {
$strBuf = strtolower(str_replace('-', '', $english));
foreach (self::$intervalsOfTen as $num => $name) {
- if (CRM_Utils_String::startsWith($strBuf, strtolower($name))) {
+ if (str_starts_with($strBuf, strtolower($name))) {
$intBuf += 10 * $num;
$strBuf = substr($strBuf, strlen($name));
break;
}
}
foreach (array_reverse(self::$lowNumbers, TRUE) as $num => $name) {
- if (CRM_Utils_String::startsWith($strBuf, strtolower($name))) {
+ if (str_starts_with($strBuf, strtolower($name))) {
$intBuf += $num;
$strBuf = substr($strBuf, strlen($name));
break;
diff --git a/CRM/Utils/File.php b/CRM/Utils/File.php
index 833204adbf58..e9d97505306a 100644
--- a/CRM/Utils/File.php
+++ b/CRM/Utils/File.php
@@ -418,22 +418,29 @@ public static function cleanFileName($name) {
* Make a valid file name.
*
* @param string $name
+ * @param bool $unicode
*
* @return string
*/
- public static function makeFileName($name) {
+ public static function makeFileName($name, bool $unicode = FALSE) {
$uniqID = md5(uniqid(rand(), TRUE));
$info = pathinfo($name);
$basename = substr($info['basename'],
0, -(strlen($info['extension'] ?? '') + (($info['extension'] ?? '') == '' ? 0 : 1))
);
if (!self::isExtensionSafe($info['extension'] ?? '')) {
+ if ($unicode) {
+ return self::makeFilenameWithUnicode("{$basename}_" . ($info['extension'] ?? '') . "_{$uniqID}", '_', 240) . ".unknown";
+ }
// munge extension so it cannot have an embbeded dot in it
// The maximum length of a filename for most filesystems is 255 chars.
// We'll truncate at 240 to give some room for the extension.
return CRM_Utils_String::munge("{$basename}_" . ($info['extension'] ?? '') . "_{$uniqID}", '_', 240) . ".unknown";
}
else {
+ if ($unicode) {
+ return self::makeFilenameWithUnicode("{$basename}_{$uniqID}", '_', 240) . "." . ($info['extension'] ?? '');
+ }
return CRM_Utils_String::munge("{$basename}_{$uniqID}", '_', 240) . "." . ($info['extension'] ?? '');
}
}
diff --git a/CRM/Utils/Geocode/Google.php b/CRM/Utils/Geocode/Google.php
index 247a54109600..abab6b313ae6 100644
--- a/CRM/Utils/Geocode/Google.php
+++ b/CRM/Utils/Geocode/Google.php
@@ -66,7 +66,7 @@ public static function format(&$values, $stateName = FALSE) {
if (!empty($values['state_province']) || (!empty($values['state_province_id']) && $values['state_province_id'] != 'null')) {
if (!empty($values['state_province_id'])) {
- $stateProvince = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $values['state_province_id']);
+ $stateProvince = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $values['state_province_id']) ?? '';
}
else {
if (!$stateName) {
@@ -74,10 +74,10 @@ public static function format(&$values, $stateName = FALSE) {
$values['state_province'],
'name',
'abbreviation'
- );
+ ) ?? '';
}
else {
- $stateProvince = $values['state_province'];
+ $stateProvince = $values['state_province'] ?? '';
}
}
diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php
index aa30ca09548b..e96b976ce4f4 100644
--- a/CRM/Utils/Hook.php
+++ b/CRM/Utils/Hook.php
@@ -409,11 +409,27 @@ public static function postCommit($op, $objectName, $objectId, $objectRef = NULL
* @param string $op
* The type of operation being performed.
* @param string $objectName
- * The name of the object.
+ * The name of the object. This is generally a CamelCase entity (eg `Contact` or `Activity`).
+ * Historical exceptions: 'CRM_Core_BAO_LocationType', 'CRM_Core_BAO_MessageTemplate'
* @param int $objectId
* The unique identifier for the object.
* @param array $links
* (optional) the links array (introduced in v3.2).
+ * Each of the links may have properties:
+ * - 'name' (string): the link text
+ * - 'url' (string): the link URL base path (like civicrm/contact/view, and fillable from $values)
+ * - 'qs' (string|array): the link URL query parameters to be used by sprintf() with $values (like reset=1&cid=%%id%% when $values['id'] is the contact ID)
+ * - 'title' (string) (optional): the text that appears when hovering over the link
+ * - 'extra' (optional): additional attributes for the tag (fillable from $values)
+ * - 'bit' (optional): a binary number that will be filtered by $mask (sending nothing as $links['bit'] means the link will always display)
+ * - 'ref' (optional, recommended): a CSS class to apply to the tag.
+ * - 'class' (string): Optional list of CSS classes
+ * - 'weight' (int): Weight is used to order the links. If not set 0 will be used but e-notices could occur. This was introduced in CiviCRM 5.63 so it will not have any impact on earlier versions of CiviCRM.
+ * - 'accessKey' (string) (optional): HTML access key. Single letter or empty string.
+ * - 'icon' (string) (optional): FontAwesome class name
+ *
+ * Depending on the specific screen, some fields (e.g. `icon`) may be ignored.
+ * If you have any idea of a clearer rule, then please update the docs.
* @param int|null $mask
* (optional) the bitmask to show/hide links.
* @param array $values
@@ -661,7 +677,7 @@ public static function xmlMenu(&$files) {
}
/**
- * (Experimental) This hook is called when build the menu table.
+ * This hook is called when building the menu table.
*
* @param array $items
* List of records to include in menu table.
@@ -1129,6 +1145,9 @@ public static function eventDiscount(&$form, &$params) {
* - title: string
* - callback: string|array, the function which starts the setup process.
* The function is expected to return a 'url' for the config screen.
+ * - url: string (optional), a URL which starts the setup process.
+ * If omitted, then a default URL is generated. The effect of opening the URL is
+ * to invoke the `callback`.
* @return mixed
*/
public static function mailSetupActions(&$setupActions) {
@@ -1160,7 +1179,7 @@ public static function mailingGroups(&$form, &$groups, &$mailings) {
}
/**
- * (Experimental) Modify the list of template-types used for CiviMail composition.
+ * Modify the list of template-types used for CiviMail composition.
*
* @param array $types
* Sequentially indexed list of template types. Each type specifies:
@@ -1554,7 +1573,8 @@ public static function alterLocationMergeData(&$blocksDAO, $mainId, $otherId, $m
/**
* Deprecated: use hook_civicrm_selectWhereClause instead.
- * @deprecated
+ * @deprecated since 5.67 will be removed around 5.85
+ * .
* @param array &$noteValues
*/
public static function notePrivacy(&$noteValues) {
@@ -1847,10 +1867,9 @@ public static function buildGroupContactCache(array $savedSearch, int $groupID,
}
/**
- * (EXPERIMENTAL) Scan extensions for a list of auto-registered interfaces.
+ * Scan extensions for a list of auto-registered interfaces.
*
- * This hook is currently experimental. It is a means to implementing `mixin/scan-classes@1`.
- * If there are no major difficulties circa 5.55, then it can be marked stable.
+ * @see mixin/scan-classes@1
*
* @param string[] $classes
* List of classes which may be of interest to the class-scanner.
@@ -2653,7 +2672,7 @@ public static function alterResourceSettings(&$data) {
}
/**
- * EXPERIMENTAL: This hook allows one to register additional Angular modules
+ * Register Angular modules
*
* @param array $angularModules
* List of modules. Each module defines:
@@ -2999,6 +3018,33 @@ public static function alterEntityRefParams(&$params, $formName) {
);
}
+ /**
+ * Should queue processing proceed.
+ *
+ * This hook is called when a background process attempts to claim an item from
+ * the queue to process. A hook could alter the status from 'active' to denote
+ * that the server is busy & hence no item should be claimed and processed at
+ * this time.
+ *
+ * @param string $status
+ * This will be set to active. It is recommended hooks change it to 'paused'
+ * to prevent queue processing (although currently any value other than active
+ * is treated as inactive 'paused')
+ * @param string $queueName
+ * The name of the queue. Equivalent to civicrm_queue.name
+ * @param array $queueSpecification
+ * Array of information about the queue loaded from civicrm_queue.
+ *
+ * @see https://docs.civicrm.org/dev/en/latest/framework/queues/
+ */
+ public static function queueActive(string &$status, string $queueName, array $queueSpecification): void {
+ $null = NULL;
+ self::singleton()->invoke(['status', 'queueName', 'queueSpecification'], $status,
+ $queueName, $queueSpecification, $null, $null, $null,
+ 'civicrm_queueActive'
+ );
+ }
+
/**
* Fire `hook_civicrm_queueRun_{$runner}`.
*
diff --git a/CRM/Utils/ICalendar.php b/CRM/Utils/ICalendar.php
index 40707d98c0e3..fddefbfec849 100644
--- a/CRM/Utils/ICalendar.php
+++ b/CRM/Utils/ICalendar.php
@@ -215,4 +215,59 @@ protected static function format_tz_offset($offset) {
return sprintf('%+03d%02d', $hours, $minutes);
}
+ /**
+ * @param array|NULL $info
+ * Information of the events to create an iCal file for, as returned by
+ * CRM_Event_BAO_Event::getCompleteInfo().
+ *
+ * @return string
+ * The rendered contents of the iCal file.
+ */
+ public static function createCalendarFile($info) {
+ $template = \CRM_Core_Smarty::singleton();
+
+ // Decode HTML entities in relevant fields.
+ foreach (['title', 'description', 'event_type', 'location', 'contact_email'] as $field) {
+ if (isset($info[0][$field])) {
+ $info[0][$field] = html_entity_decode($info[0][$field], ENT_QUOTES | ENT_HTML401, 'UTF-8');
+ }
+ }
+
+ // Calculate timezones.
+ if (count($info) > 0) {
+ $date_min = min(
+ array_map(function ($event) {
+ return strtotime($event['start_date']);
+ }, $info)
+ );
+ $date_max = max(
+ array_map(function ($event) {
+ return strtotime($event['end_date'] ?? $event['start_date']);
+ }, $info)
+ );
+ $template->assign('timezones', CRM_Utils_ICalendar::generate_timezones($timezones, $date_min, $date_max));
+ }
+ else {
+ $template->assign('timezones', NULL);
+ }
+ $template->assign('timezone', @date_default_timezone_get());
+
+ $template->assign('events', $info);
+ $ical_data = $template->fetch('CRM/Core/Calendar/ICal.tpl');
+ $ical_data = preg_replace('/(?activity_source));
// create an array of all of to, from, cc, bcc that are in use for this Mail Account, so we don't create contacts for emails we aren't adding to the activity.
$emailFields = array_merge($targetFields, $assigneeFields, $sourceFields);
- $createContact = !($dao->is_contact_creation_disabled_if_no_match);
+ $createContact = !($dao->is_contact_creation_disabled_if_no_match) && !$isBounceProcessing;
$bounceActivityTypeID = $activityTypeID = (int) $dao->activity_type_id;
$activityTypes = Activity::getFields(TRUE)
->setLoadOptions(['id', 'name'])
diff --git a/CRM/Utils/SQL.php b/CRM/Utils/SQL.php
index 5f7311d6096e..2f5e07843273 100644
--- a/CRM/Utils/SQL.php
+++ b/CRM/Utils/SQL.php
@@ -71,7 +71,7 @@ public static function mergeSubquery($entityName, $joinColumn = 'id') {
}
// Arrays of arrays get joined with OR (similar to CRM_Core_Permission::check)
elseif (is_array($formattedClause)) {
- $subClauses[] = "($fieldName " . implode(" OR $fieldName ", $formattedClause) . ')';
+ $subClauses[] = "(($fieldName " . implode(") OR ($fieldName ", $formattedClause) . '))';
}
else {
$subClauses[] = "$fieldName $formattedClause";
diff --git a/CRM/Utils/SQL/Insert.php b/CRM/Utils/SQL/Insert.php
index 0a3c509866a0..dc256fc95c33 100644
--- a/CRM/Utils/SQL/Insert.php
+++ b/CRM/Utils/SQL/Insert.php
@@ -145,7 +145,12 @@ public function row($row) {
$escapedRow = [];
foreach ($this->columns as $column) {
- $escapedRow[$column] = $this->escapeString($row[$column]);
+ if (is_bool($row[$column])) {
+ $escapedRow[$column] = (int) $row[$column];
+ }
+ else {
+ $escapedRow[$column] = $this->escapeString($row[$column]);
+ }
}
$this->rows[] = $escapedRow;
@@ -186,4 +191,19 @@ public function toSQL() {
return $sql;
}
+ /**
+ * Execute the query.
+ *
+ * @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($i18nRewrite = TRUE) {
+ return CRM_Core_DAO::executeQuery($this->toSQL(), [], TRUE, NULL,
+ FALSE, $i18nRewrite);
+ }
+
}
diff --git a/CRM/Utils/SQL/Select.php b/CRM/Utils/SQL/Select.php
index 2e9338653134..3ffcb18a4379 100644
--- a/CRM/Utils/SQL/Select.php
+++ b/CRM/Utils/SQL/Select.php
@@ -581,13 +581,13 @@ public function toSQL() {
$sql .= $join . "\n";
}
if ($this->wheres) {
- $sql .= 'WHERE (' . implode(') AND (', $this->wheres) . ")\n";
+ $sql .= 'WHERE (' . implode(")\n AND (", $this->wheres) . ")\n";
}
if ($this->groupBys) {
$sql .= 'GROUP BY ' . implode(', ', $this->groupBys) . "\n";
}
if ($this->havings) {
- $sql .= 'HAVING (' . implode(') AND (', $this->havings) . ")\n";
+ $sql .= 'HAVING (' . implode(")\n AND (", $this->havings) . ")\n";
}
if ($this->orderBys) {
$orderBys = CRM_Utils_Array::crmArraySortByField($this->orderBys,
diff --git a/CRM/Utils/String.php b/CRM/Utils/String.php
index 920edf7a842b..bb83724dc294 100644
--- a/CRM/Utils/String.php
+++ b/CRM/Utils/String.php
@@ -445,8 +445,7 @@ public static function strtoboolstr($str) {
*/
public static function htmlToText($html) {
$token_html = preg_replace('!\{([a-z_.]+)\}!i', 'token:{$1}', $html);
- $converter = new \Html2Text\Html2Text($token_html, ['do_links' => 'table', 'width' => 75]);
- $token_text = $converter->getText();
+ $token_text = \Soundasleep\Html2Text::convert($token_html, ['ignore_errors' => TRUE]);
$text = preg_replace('!token\:\{([a-z_.]+)\}!i', '{$1}', $token_text);
return $text;
}
@@ -876,7 +875,7 @@ public static function htmlAttributes($attributes) {
}
/**
- * Determine if $string starts with $fragment.
+ * @deprecated
*
* @param string $string
* The long string.
@@ -885,15 +884,12 @@ public static function htmlAttributes($attributes) {
* @return bool
*/
public static function startsWith($string, $fragment) {
- if ($fragment === '') {
- return TRUE;
- }
- $len = strlen($fragment ?? '');
- return substr(($string ?? ''), 0, $len) === $fragment;
+ CRM_Core_Error::deprecatedFunctionWarning('str_starts_with');
+ return str_starts_with((string) $string, (string) $fragment);
}
/**
- * Determine if $string ends with $fragment.
+ * @deprecated
*
* @param string $string
* The long string.
@@ -902,11 +898,8 @@ public static function startsWith($string, $fragment) {
* @return bool
*/
public static function endsWith($string, $fragment) {
- if ($fragment === '') {
- return TRUE;
- }
- $len = strlen($fragment ?? '');
- return substr(($string ?? ''), -1 * $len) === $fragment;
+ CRM_Core_Error::deprecatedFunctionWarning('str_ends_with');
+ return str_ends_with((string) $string, (string) $fragment);
}
/**
@@ -920,7 +913,7 @@ public static function filterByWildcards($patterns, $allStrings, $allowNew = FAL
$patterns = (array) $patterns;
$result = [];
foreach ($patterns as $pattern) {
- if (!\CRM_Utils_String::endsWith($pattern, '*')) {
+ if (!str_ends_with($pattern, '*')) {
if ($allowNew || in_array($pattern, $allStrings)) {
$result[] = $pattern;
}
@@ -928,7 +921,7 @@ public static function filterByWildcards($patterns, $allStrings, $allowNew = FAL
else {
$prefix = rtrim($pattern, '*');
foreach ($allStrings as $key) {
- if (\CRM_Utils_String::startsWith($key, $prefix)) {
+ if (str_starts_with($key, $prefix)) {
$result[] = $key;
}
}
diff --git a/CRM/Utils/System.php b/CRM/Utils/System.php
index c70d83af3ad0..f3359d58a0b2 100644
--- a/CRM/Utils/System.php
+++ b/CRM/Utils/System.php
@@ -26,7 +26,7 @@
* @method static mixed permissionDenied() Show access denied screen.
* @method static mixed logout() Log out the current user.
* @method static mixed updateCategories() Clear CMS caches related to the user registration/profile forms.
- * @method static void appendBreadCrumb(array $breadCrumbs) Append an additional breadcrumb tag to the existing breadcrumbs.
+ * @method static void appendBreadCrumb(array $breadCrumbs) Append an additional breadcrumb link to the existing breadcrumbs.
* @method static void resetBreadCrumb() Reset an additional breadcrumb tag to the existing breadcrumb.
* @method static void addHTMLHead(string $head) Append a string to the head of the HTML file.
* @method static string postURL(int $action) Determine the post URL for a form.
@@ -452,12 +452,12 @@ public static function crmURL($params) {
return self::url(
$p,
- CRM_Utils_Array::value('q', $params),
- CRM_Utils_Array::value('a', $params, FALSE),
- CRM_Utils_Array::value('f', $params),
- CRM_Utils_Array::value('h', $params, TRUE),
- CRM_Utils_Array::value('fe', $params, FALSE),
- CRM_Utils_Array::value('fb', $params, FALSE)
+ $params['q'] ?? NULL,
+ $params['a'] ?? FALSE,
+ $params['f'] ?? NULL,
+ $params['h'] ?? TRUE,
+ $params['fe'] ?? FALSE,
+ $params['fb'] ?? FALSE
);
}
diff --git a/CRM/Utils/System/Joomla.php b/CRM/Utils/System/Joomla.php
index b7f92257fc68..d61d3f4a3258 100644
--- a/CRM/Utils/System/Joomla.php
+++ b/CRM/Utils/System/Joomla.php
@@ -136,8 +136,8 @@ public function getEmailFieldName(CRM_Core_Form $form, array $fields):string {
public function checkUserNameEmailExists(&$params, &$errors, $emailName = 'email') {
$config = CRM_Core_Config::singleton();
- $name = CRM_Utils_Array::value('name', $params);
- $email = CRM_Utils_Array::value('mail', $params);
+ $name = $params['name'] ?? NULL;
+ $email = $params['mail'] ?? NULL;
//don't allow the special characters and min. username length is two
//regex \\ to match a single backslash would become '/\\\\/'
$isNotValid = (bool) preg_match('/[\<|\>|\"|\'|\%|\;|\(|\)|\&|\\\\|\/]/im', $name);
diff --git a/CRM/Utils/System/Standalone.php b/CRM/Utils/System/Standalone.php
index db6a0039751f..1a5c7902e746 100644
--- a/CRM/Utils/System/Standalone.php
+++ b/CRM/Utils/System/Standalone.php
@@ -221,9 +221,7 @@ public function url(
*/
public static function currentPath() {
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
- if ($path[0] == '/') {
- $path = substr($path, 1);
- }
+ $path = trim($path, '/');
return $path;
}
@@ -287,7 +285,7 @@ public function theme(&$content, $print = FALSE, $maintenance = FALSE) {
// Q. what does this do? Why do we only include this for maintenance?
if ($maintenance) {
$smarty = CRM_Core_Smarty::singleton();
- echo implode('', $smarty->_tpl_vars['pageHTMLHead']);
+ echo implode('', $smarty->getTemplateVars('pageHTMLHead'));
}
// @todo Add variables from the body tag? (for Shoreditch)
diff --git a/CRM/Utils/Token.php b/CRM/Utils/Token.php
index f2ef5ce99574..7cd3bf0c38e7 100644
--- a/CRM/Utils/Token.php
+++ b/CRM/Utils/Token.php
@@ -1585,7 +1585,7 @@ public static function getMembershipTokenReplacement($entity, $token, $membershi
default:
if (in_array($token, $supportedTokens)) {
$value = $membership[$token];
- if (CRM_Utils_String::endsWith($token, '_date')) {
+ if (str_ends_with($token, '_date')) {
$value = CRM_Utils_Date::customFormat($value);
}
}
@@ -1746,7 +1746,7 @@ protected static function convertPseudoConstantsUsingMetadata($value, $token) {
$value = CRM_Core_PseudoConstant::getLabel('CRM_Contact_BAO_Contact', $token, $value);
}
}
- elseif ($value && CRM_Utils_String::endsWith($token, '_date')) {
+ elseif ($value && str_ends_with($token, '_date')) {
$value = CRM_Utils_Date::customFormat($value);
}
return $value;
@@ -1764,7 +1764,7 @@ public static function getTokenDeprecations(): array {
'$display_name' => 'contact.display_name',
],
'contribution_online_receipt' => [
- '$contributeMode' => 'no longer available / relevant',
+ '$contributeMode' => ts('no longer available / relevant'),
'$first_name' => 'contact.first_name',
'$last_name' => 'contact.last_name',
'$displayName' => 'contact.display_name',
@@ -1772,19 +1772,39 @@ public static function getTokenDeprecations(): array {
'membership_offline_receipt' => [
// receipt_text_renewal appears to be long gone.
'receipt_text_renewal' => 'receipt_text',
- '$isAmountZero' => 'no longer available / relevant',
+ '$isAmountZero' => ts('no longer available / relevant'),
],
'event_offline_receipt' => [
- '$contributeMode' => 'no longer available / relevant',
- '$isAmountZero' => 'no longer available / relevant',
+ '$contributeMode' => ts('no longer available / relevant'),
+ '$isAmountZero' => ts('no longer available / relevant'),
+ '$dataArray' => ts('found within $participants'),
+ '$paidBy' => 'contribution.payment_instrument_id:label',
+ '$totalTaxAmount' => 'contribution.tax_amount',
+ '$amount' => ts('found within $participants'),
+ '$checkNumber' => 'contribution.check_number',
+ '$module' => ts('no longer available / relevant'),
+ '$register_date' => 'participant.register_date',
+ '$receive_date' => 'contribution.receive_date',
+ '$is_pay_later' => 'contribution.is_pay_later',
+ '$totalAmount' => 'contribution.total_amount',
+ '$location' => 'event.location',
+ '$isShowLocation' => 'event.is_show_location|boolean',
+ '$event.participant_role' => 'participant.role_id:label',
+ '$amount_level' => ts('found within $participants'),
+ 'balanceAmount' => 'contribution.balance_amount',
+ '$financialTypeName' => 'contribution.financial_type_id:label',
+ '$contributionTypeName' => 'contribution.financial_type_id:label',
+ '$trxn_id' => 'contribution.trxn_id',
+ '$participant_status_id' => 'participant.status_id',
+
],
'pledge_acknowledgement' => [
- '$domain' => 'no longer available / relevant',
- '$contact' => 'no longer available / relevant',
+ '$domain' => ts('no longer available / relevant'),
+ '$contact' => ts('no longer available / relevant'),
],
'pledge_reminder' => [
- '$domain' => 'no longer available / relevant',
- '$contact' => 'no longer available / relevant',
+ '$domain' => ts('no longer available / relevant'),
+ '$contact' => ts('no longer available / relevant'),
],
],
];
diff --git a/CRM/Utils/Type.php b/CRM/Utils/Type.php
index 510718060bc5..ea610939de19 100644
--- a/CRM/Utils/Type.php
+++ b/CRM/Utils/Type.php
@@ -70,7 +70,7 @@ class CRM_Utils_Type {
* @return string
* String identifying the data type, e.g. 'Int' or 'String'.
*/
- public static function typeToString($type) {
+ public static function typeToString($type): string {
// @todo Use constants in the case statements, e.g. "case T_INT:".
// @todo return directly, instead of assigning a value.
// @todo Use a lookup array, as a property or as a local variable.
@@ -134,7 +134,7 @@ public static function typeToString($type) {
break;
}
- return (isset($string)) ? $string : "";
+ return $string ?? '';
}
/**
diff --git a/CRM/Utils/Wrapper.php b/CRM/Utils/Wrapper.php
index 5efe9a89b66b..3638f75533c6 100644
--- a/CRM/Utils/Wrapper.php
+++ b/CRM/Utils/Wrapper.php
@@ -75,7 +75,7 @@ public function run($formName, $formLabel = NULL, $arguments = NULL) {
$sessionVar = $params['sessionVar'] ?? NULL;
$type = $params['type'] ?? NULL;
$default = $params['default'] ?? NULL;
- $abort = CRM_Utils_Array::value('abort', $params, FALSE);
+ $abort = $params['abort'] ?? FALSE;
$value = NULL;
$value = CRM_Utils_Request::retrieve(
diff --git a/Civi/API/Api3SelectQuery.php b/Civi/API/Api3SelectQuery.php
index 366223290e7f..66c5a3fa6787 100644
--- a/Civi/API/Api3SelectQuery.php
+++ b/Civi/API/Api3SelectQuery.php
@@ -157,8 +157,8 @@ protected function getField($fieldName) {
}
foreach ($this->apiFieldSpec as $field) {
if (
- $fieldName == \CRM_Utils_Array::value('uniqueName', $field) ||
- array_search($fieldName, \CRM_Utils_Array::value('api.aliases', $field, [])) !== FALSE
+ $fieldName == ($field['uniqueName'] ?? NULL) ||
+ array_search($fieldName, $field['api.aliases'] ?? []) !== FALSE
) {
return $field;
}
diff --git a/Civi/API/SelectQuery.php b/Civi/API/SelectQuery.php
index f22742e844e8..b384a0e625a5 100644
--- a/Civi/API/SelectQuery.php
+++ b/Civi/API/SelectQuery.php
@@ -217,7 +217,7 @@ protected function addFkField($fkFieldName, $side) {
}
$fieldInfo = $fkField['FKApiSpec'][$fieldName] ?? NULL;
- $keyColumn = \CRM_Utils_Array::value('FKKeyColumn', $fkField, 'id');
+ $keyColumn = $fkField['FKKeyColumn'] ?? 'id';
if (!$fieldInfo || !isset($fkField['FKApiSpec'][$keyColumn])) {
// Join doesn't exist - might be another param with a dot in it for some reason, we'll just ignore it.
return NULL;
@@ -404,7 +404,7 @@ protected function buildOrderBy() {
$words = preg_split("/[\s]+/", $item);
if ($words) {
// Direction defaults to ASC unless DESC is specified
- $direction = strtoupper(\CRM_Utils_Array::value(1, $words, '')) == 'DESC' ? ' DESC' : '';
+ $direction = strtoupper($words[1] ?? '') === 'DESC' ? ' DESC' : '';
$field = $this->getField($words[0]);
if ($field) {
$this->query->orderBy(self::MAIN_TABLE_ALIAS . '.' . $field['name'] . $direction, NULL, $index);
diff --git a/Civi/API/Subscriber/ChainSubscriber.php b/Civi/API/Subscriber/ChainSubscriber.php
index 84b011eed431..c258c56eefdc 100644
--- a/Civi/API/Subscriber/ChainSubscriber.php
+++ b/Civi/API/Subscriber/ChainSubscriber.php
@@ -162,17 +162,16 @@ protected function callNestedApi($apiKernel, &$params, &$result, $action, $entit
$defaultSubParams[$lowercase_entity . "_id"] = $parentAPIValues['id'];
}
}
- // @todo remove strtolower: $subEntity is already lower case
- if ($entity != 'Contact' && \CRM_Utils_Array::value(strtolower($subEntity . "_id"), $parentAPIValues)) {
+ if ($entity !== 'Contact' && !empty($parentAPIValues[$subEntity . '_id'])) {
//e.g. if event_id is in the values returned & subentity is event
//then pass in event_id as 'id' don't do this for contact as it
//does some weird things like returning primary email &
//thus limiting the ability to chain email
//TODO - this might need the camel treatment
- $defaultSubParams['id'] = $parentAPIValues[$subEntity . "_id"];
+ $defaultSubParams['id'] = $parentAPIValues[$subEntity . '_id'];
}
- if (\CRM_Utils_Array::value('entity_table', $result['values'][$idIndex]) == $subEntity) {
+ if (($result['values'][$idIndex]['entity_table'] ?? NULL) == $subEntity) {
$defaultSubParams['id'] = $result['values'][$idIndex]['entity_id'];
}
// if we are dealing with the same entity pass 'id' through
diff --git a/Civi/API/Subscriber/DynamicFKAuthorization.php b/Civi/API/Subscriber/DynamicFKAuthorization.php
index e84bbb901de6..1a6a684f5654 100644
--- a/Civi/API/Subscriber/DynamicFKAuthorization.php
+++ b/Civi/API/Subscriber/DynamicFKAuthorization.php
@@ -177,7 +177,7 @@ public function onApiAuthorize(\Civi\API\Event\AuthorizeEvent $event) {
$this->authorizeDelegate(
$apiRequest['action'],
$apiRequest['params']['entity_table'],
- \CRM_Utils_Array::value('entity_id', $apiRequest['params'], NULL),
+ $apiRequest['params']['entity_id'] ?? NULL,
$apiRequest
);
return;
diff --git a/Civi/API/WhitelistRule.php b/Civi/API/WhitelistRule.php
index 25d5e4f3c358..e23ee655ce50 100644
--- a/Civi/API/WhitelistRule.php
+++ b/Civi/API/WhitelistRule.php
@@ -181,7 +181,7 @@ public function matches($apiRequest) {
// Kind'a silly we need to (re(re))parse here for each rule; would be more
// performant if pre-parsed by Request::create().
$options = _civicrm_api3_get_options_from_params($apiRequest['params'], TRUE, $apiRequest['entity'], 'get');
- $return = \CRM_Utils_Array::value('return', $options, []);
+ $return = $options['return'] ?? [];
$activatedFields = array_merge($activatedFields, array_keys($return));
}
diff --git a/Civi/ActionSchedule/Mapping.php b/Civi/ActionSchedule/Mapping.php
new file mode 100644
index 000000000000..82f18404c13b
--- /dev/null
+++ b/Civi/ActionSchedule/Mapping.php
@@ -0,0 +1,4 @@
+ $info) {
// Merge in defaults
$angularModules[$module] += ['basePages' => ['civicrm/a']];
+ if (!empty($info['settings'])) {
+ \CRM_Core_Error::deprecatedWarning('Angular "settings" is not supported. See https://github.com/civicrm/civicrm-core/pull/19052');
+ }
// Validate settingsFactory callables
if (isset($info['settingsFactory'])) {
// To keep the cache small, we want `settingsFactory` to contain the string names of class & function, not an object
@@ -352,7 +355,14 @@ public function getStrings($name) {
}
/**
- * Get resources for one or more modules.
+ * Get resources for one or more modules, applying any changesets.
+ *
+ * NOTE: The output of this function is a little quirky; depending on the type of resource requested,
+ * the results will either be a non-associative array (for path and url-type resources)
+ * or an array indexed by moduleName (for pass-thru resources like settingsFactory, requires, permissions, bundles).
+ *
+ * Note: ChangeSets will be applied
+ * @see \CRM_Utils_Hook::alterAngular()
*
* @param string|array $moduleNames
* List of module names.
@@ -361,15 +371,20 @@ public function getStrings($name) {
* @param string $refType
* Type of reference to the resource ('cacheUrl', 'rawUrl', 'path', 'settings').
* @return array
- * List of URLs or paths.
+ * Indexed or non-associative array, depending on resource requested (see note)
* @throws \CRM_Core_Exception
*/
public function getResources($moduleNames, $resType, $refType) {
$result = [];
- $moduleNames = (array) $moduleNames;
- foreach ($moduleNames as $moduleName) {
+ // Properties that do not require interpolation - they are added to the output keyed by moduleName
+ $passThru = ['settings', 'settingsFactory', 'requires', 'permissions', 'bundles'];
+
+ foreach ((array) $moduleNames as $moduleName) {
$module = $this->getModule($moduleName);
- if (isset($module[$resType])) {
+ if (isset($module[$resType]) && in_array($resType, $passThru, TRUE)) {
+ $result[$moduleName] = $module[$resType];
+ }
+ elseif (isset($module[$resType])) {
foreach ($module[$resType] as $file) {
$refTypeSuffix = '';
if (is_string($file) && preg_match(';^(assetBuilder|ext)://;', $file)) {
@@ -416,16 +431,6 @@ public function getResources($moduleNames, $resType, $refType) {
$result[] = $this->res->getUrl(parse_url($file, PHP_URL_HOST), ltrim(parse_url($file, PHP_URL_PATH), '/'), TRUE);
break;
- case 'settings':
- case 'settingsFactory':
- case 'requires':
- case 'permissions':
- case 'bundles':
- if (!empty($module[$resType])) {
- $result[$moduleName] = $module[$resType];
- }
- break;
-
default:
throw new \CRM_Core_Exception("Unrecognized resource format");
}
diff --git a/Civi/Angular/Page/Modules.php b/Civi/Angular/Page/Modules.php
index 39a2e1ccfa8a..b26c2d54f6ff 100644
--- a/Civi/Angular/Page/Modules.php
+++ b/Civi/Angular/Page/Modules.php
@@ -2,6 +2,8 @@
namespace Civi\Angular\Page;
+use Civi\Angular\Manager;
+
/**
* This page aggregates data from Angular modules.
*
@@ -148,18 +150,17 @@ public function parseModuleNames($modulesExpr, $angular) {
* @param \Civi\Angular\Manager $angular
* @return array
*/
- public function getMetadata($moduleNames, $angular) {
- $modules = $angular->getModules();
+ public function getMetadata(array $moduleNames, Manager $angular): array {
$result = [];
foreach ($moduleNames as $moduleName) {
- if (isset($modules[$moduleName])) {
- $result[$moduleName] = [];
- $result[$moduleName]['domain'] = $modules[$moduleName]['ext'];
- $result[$moduleName]['js'] = $angular->getResources($moduleName, 'js', 'rawUrl');
- $result[$moduleName]['css'] = $angular->getResources($moduleName, 'css', 'rawUrl');
- $result[$moduleName]['partials'] = $angular->getPartials($moduleName);
- $result[$moduleName]['strings'] = $angular->getTranslatedStrings($moduleName);
- }
+ $module = $angular->getModule($moduleName);
+ $result[$moduleName] = [
+ 'domain' => $module['ext'],
+ 'js' => $angular->getResources($moduleName, 'js', 'rawUrl'),
+ 'css' => $angular->getResources($moduleName, 'css', 'rawUrl'),
+ 'partials' => $angular->getPartials($moduleName),
+ 'strings' => $angular->getTranslatedStrings($moduleName),
+ ];
}
return $result;
}
diff --git a/Civi/Api4/Action/Contact/GetDuplicates.php b/Civi/Api4/Action/Contact/GetDuplicates.php
index 9829af3b03b4..3ac73b781945 100644
--- a/Civi/Api4/Action/Contact/GetDuplicates.php
+++ b/Civi/Api4/Action/Contact/GetDuplicates.php
@@ -42,7 +42,8 @@ class GetDuplicates extends \Civi\Api4\Generic\DAOCreateAction {
*/
protected function getRuleGroupNames() {
$rules = [];
- foreach (\CRM_Contact_BAO_ContactType::basicTypes() as $contactType) {
+ $contactTypes = $this->getEntityName() === 'Contact' ? \CRM_Contact_BAO_ContactType::basicTypes() : [$this->getEntityName()];
+ foreach ($contactTypes as $contactType) {
$rules[] = $contactType . '.Unsupervised';
$rules[] = $contactType . '.Supervised';
}
@@ -142,14 +143,14 @@ private function transformCustomParams(array &$entityValues, array &$dedupeParam
public static function fields(BasicGetFieldsAction $action) {
$fields = [];
$ignore = ['id', 'contact_id', 'is_primary', 'on_hold', 'location_type_id', 'phone_type_id'];
- foreach (['Contact', 'Email', 'Phone', 'Address', 'IM'] as $entity) {
+ foreach ([$action->getEntityName(), 'Email', 'Phone', 'Address', 'IM'] as $entity) {
$entityFields = (array) civicrm_api4($entity, 'getFields', [
'checkPermissions' => FALSE,
'action' => 'create',
'loadOptions' => $action->getLoadOptions(),
'where' => [['name', 'NOT IN', $ignore], ['type', 'IN', ['Field', 'Custom']]],
]);
- if ($entity !== 'Contact') {
+ if ($entity !== $action->getEntityName()) {
$prefix = strtolower($entity) . '_primary.';
foreach ($entityFields as &$field) {
$field['name'] = $prefix . $field['name'];
diff --git a/Civi/Api4/Action/Queue/Run.php b/Civi/Api4/Action/Queue/Run.php
new file mode 100644
index 000000000000..80e230e26f31
--- /dev/null
+++ b/Civi/Api4/Action/Queue/Run.php
@@ -0,0 +1,136 @@
+queue);
+ $startTime = microtime(TRUE);
+ $requests = 0;
+ $errors = 0;
+ $successes = 0;
+ $message = NULL;
+ $perm = $this->getCheckPermissions();
+
+ while (TRUE) {
+ if (!$queue->isActive()) {
+ $message = sprintf('Queue is not active (status => %s)', $queue->getStatus());
+ break;
+ }
+
+ if (static::isFinite($this->maxRequests) && $requests >= $this->maxRequests) {
+ $message = sprintf('Reached request limit (%d)', $this->maxRequests);
+ break;
+ }
+ if (static::isFinite($this->maxDuration) && (microtime(TRUE) - $startTime) >= $this->maxDuration) {
+ $message = sprintf('Reached duration limit (%d)', $this->maxDuration);
+ break;
+ }
+
+ try {
+ $requests++;
+
+ $claims = Queue::claimItems($perm)->setQueue($this->queue)->execute()->getArrayCopy();
+ if (empty($claims)) {
+ $message = 'No claimable items';
+ break;
+ }
+
+ $batchResults = Queue::runItems($perm)->setQueue($this->queue)->setItems($claims)->execute();
+ }
+ catch (\Throwable $t) {
+ $errors++;
+ $message = sprintf('Queue-item raised unhandled exception (%s: %s)', get_class($t), $t->getMessage());
+ break;
+ }
+
+ foreach ($batchResults as $batchResult) {
+ if ($batchResult['outcome'] === 'ok') {
+ $successes++;
+ }
+ else {
+ $errors++;
+ // Should we stop? No, we're just reporting stats.
+ // What about queues with policy "error=>abort"? They must update ("status=>aborted") under the aegis of runItems().
+ // Stopping here would obscure problems that affect all main-loops.
+ }
+ }
+ }
+
+ $result[] = [
+ 'loop_duration' => sprintf('%.3f', microtime(TRUE) - $startTime),
+ 'loop_requests' => $requests,
+ 'item_successes' => $successes,
+ 'item_errors' => $errors,
+ 'queue_ready' => $queue->getStatistic('ready'),
+ 'queue_blocked' => $queue->getStatistic('blocked'),
+ 'queue_total' => $queue->getStatistic('total'),
+ 'exit_message' => $message,
+ ];
+ }
+
+ private static function isFinite($value): bool {
+ return $value !== NULL && $value >= 0;
+ }
+
+}
diff --git a/Civi/Api4/Action/Queue/RunItems.php b/Civi/Api4/Action/Queue/RunItems.php
index d711062e6ce9..e7e8bdbff784 100644
--- a/Civi/Api4/Action/Queue/RunItems.php
+++ b/Civi/Api4/Action/Queue/RunItems.php
@@ -30,8 +30,8 @@
* - 'retry': Task encountered an error. Will try again later.
* - 'fail': Task encountered an error. Will not try again later. Removed from queue.
*
- * @method $this setItem(?array $item)
- * @method ?array getItem()
+ * @method $this setItems(?array $items)
+ * @method ?array getItems()
* @method ?string setQueue
* @method $this setQueue(?string $queue)
*/
diff --git a/Civi/Api4/Contact.php b/Civi/Api4/Contact.php
index eeb05eb9a102..c71aabd35776 100644
--- a/Civi/Api4/Contact.php
+++ b/Civi/Api4/Contact.php
@@ -33,7 +33,7 @@ class Contact extends Generic\DAOEntity {
* @return Action\Contact\Create
*/
public static function create($checkPermissions = TRUE) {
- return (new Action\Contact\Create(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\Create(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -42,7 +42,7 @@ public static function create($checkPermissions = TRUE) {
* @return Action\Contact\Update
*/
public static function update($checkPermissions = TRUE) {
- return (new Action\Contact\Update(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\Update(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -51,7 +51,7 @@ public static function update($checkPermissions = TRUE) {
* @return Action\Contact\Save
*/
public static function save($checkPermissions = TRUE) {
- return (new Action\Contact\Save(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\Save(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -60,7 +60,7 @@ public static function save($checkPermissions = TRUE) {
* @return Action\Contact\Delete
*/
public static function delete($checkPermissions = TRUE) {
- return (new Action\Contact\Delete(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\Delete(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -69,7 +69,7 @@ public static function delete($checkPermissions = TRUE) {
* @return Action\Contact\GetChecksum
*/
public static function getChecksum($checkPermissions = TRUE) {
- return (new Action\Contact\GetChecksum(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\GetChecksum(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -78,7 +78,7 @@ public static function getChecksum($checkPermissions = TRUE) {
* @return Action\Contact\ValidateChecksum
*/
public static function validateChecksum($checkPermissions = TRUE) {
- return (new Action\Contact\ValidateChecksum(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\ValidateChecksum(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -87,7 +87,7 @@ public static function validateChecksum($checkPermissions = TRUE) {
* @return Action\Contact\GetDuplicates
*/
public static function getDuplicates($checkPermissions = TRUE) {
- return (new Action\Contact\GetDuplicates(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\GetDuplicates(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
@@ -96,8 +96,39 @@ public static function getDuplicates($checkPermissions = TRUE) {
* @return Action\Contact\MergeDuplicates
*/
public static function mergeDuplicates($checkPermissions = TRUE) {
- return (new Action\Contact\MergeDuplicates(__CLASS__, __FUNCTION__))
+ return (new Action\Contact\MergeDuplicates(self::getEntityName(), __FUNCTION__))
->setCheckPermissions($checkPermissions);
}
+ protected static function getDaoName(): string {
+ // Child classes (Individual, Organization, Household) need this.
+ return 'CRM_Contact_DAO_Contact';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public static function getInfo(): array {
+ $info = parent::getInfo();
+ $contactType = static::getEntityName();
+ // Adjust info for child classes (Individual, Organization, Household)
+ if ($contactType !== 'Contact') {
+ $contactTypeInfo = \CRM_Contact_BAO_ContactType::getContactType($contactType);
+ $info['icon'] = $contactTypeInfo['icon'] ?? $info['icon'];
+ $info['type'] = ['DAOEntity', 'ContactType'];
+ $info['description'] = ts('Contacts of type %1.', [1 => $contactTypeInfo['label']]);
+ // This forces the value into get and create api actions
+ $info['where'] = ['contact_type' => $contactType];
+ }
+ return $info;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public static function permissions() {
+ $permissions = \CRM_Core_Permission::getEntityActionPermissions();
+ return ($permissions['contact'] ?? []) + $permissions['default'];
+ }
+
}
diff --git a/Civi/Api4/CustomValue.php b/Civi/Api4/CustomValue.php
index 2ea7a3274a9e..4201d3397afd 100644
--- a/Civi/Api4/CustomValue.php
+++ b/Civi/Api4/CustomValue.php
@@ -135,6 +135,13 @@ public static function permissions() {
];
}
+ /**
+ * @return \CRM_Core_DAO|string|null
+ */
+ protected static function getDaoName(): ?string {
+ return 'CRM_Core_BAO_CustomValue';
+ }
+
/**
* @see \Civi\Api4\Generic\AbstractEntity::getInfo()
* @return array
@@ -145,7 +152,7 @@ public static function getInfo() {
'type' => ['CustomValue', 'DAOEntity'],
'searchable' => 'secondary',
'primary_key' => ['id'],
- 'dao' => 'CRM_Core_BAO_CustomValue',
+ 'dao' => self::getDaoName(),
'see' => [
'https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/#multiple-record-fieldsets',
'\Civi\Api4\CustomGroup',
diff --git a/Civi/Api4/Entity.php b/Civi/Api4/Entity.php
index fb2b4780e984..a595df8575dd 100644
--- a/Civi/Api4/Entity.php
+++ b/Civi/Api4/Entity.php
@@ -118,6 +118,11 @@ class Entity extends Generic\AbstractEntity {
'data_type' => 'Array',
'description' => 'Arguments needed by php action factory functions (used when multiple entities share a class, e.g. CustomValue).',
],
+ [
+ 'name' => 'where',
+ 'data_type' => 'Array',
+ 'description' => 'Constant values which will be force-set when reading/writing this entity (e.g. [contact_type => Individual])',
+ ],
[
'name' => 'bridge',
'data_type' => 'Array',
@@ -128,6 +133,11 @@ class Entity extends Generic\AbstractEntity {
'data_type' => 'Array',
'description' => 'When joining entities in the UI, which fields should be presented by default in the ON clause',
],
+ [
+ 'name' => 'match_fields',
+ 'data_type' => 'Array',
+ 'description' => 'Combination of fields used for unique matching',
+ ],
[
'name' => 'group_weights_by',
'data_type' => 'Array',
diff --git a/Civi/Api4/EntitySet.php b/Civi/Api4/EntitySet.php
index d11b33e7c8c8..867a3f5fa31c 100644
--- a/Civi/Api4/EntitySet.php
+++ b/Civi/Api4/EntitySet.php
@@ -39,6 +39,7 @@ public static function autocomplete($checkPermissions = TRUE) {
}
/**
+ * This isn't a "real" entity and doesn't have any fields
* @return \Civi\Api4\Generic\BasicGetFieldsAction
*/
public static function getFields($checkPermissions = TRUE) {
@@ -61,4 +62,11 @@ protected static function getEntityTitle(bool $plural = FALSE): string {
return $plural ? ts('Entity Sets') : ts('Entity Set');
}
+ public static function getInfo(): array {
+ $info = parent::getInfo();
+ // This isn't a "real" entity and doesn't have any fields, so no primary key
+ $info['primary_key'] = [];
+ return $info;
+ }
+
}
diff --git a/Civi/Api4/Generic/AbstractAction.php b/Civi/Api4/Generic/AbstractAction.php
index 43563bae3eba..ade0f637b7b8 100644
--- a/Civi/Api4/Generic/AbstractAction.php
+++ b/Civi/Api4/Generic/AbstractAction.php
@@ -153,12 +153,19 @@ abstract class AbstractAction implements \ArrayAccess {
* @param string $actionName
*/
public function __construct($entityName, $actionName) {
- // If a namespaced class name is passed in
- if (strpos($entityName, '\\') !== FALSE) {
- $entityName = substr($entityName, strrpos($entityName, '\\') + 1);
+ // If a namespaced class name is passed in, convert to entityName
+ $this->_entityName = CoreUtil::stripNamespace($entityName);
+ // Normalize action name case (because PHP is case-insensitive, we have to do an extra check)
+ $thisClassName = CoreUtil::stripNamespace(get_class($this));
+ // If this was called via magic method, $actionName won't necessarily have the
+ // correct case because PHP doesn't care about case when calling methods.
+ if (strtolower($thisClassName) === strtolower($actionName)) {
+ $this->_actionName = lcfirst($thisClassName);
+ }
+ // If called via static method, case should already be correct.
+ else {
+ $this->_actionName = $actionName;
}
- $this->_entityName = $entityName;
- $this->_actionName = $actionName;
$this->_id = \Civi\API\Request::getNextId();
}
diff --git a/Civi/Api4/Generic/AbstractEntity.php b/Civi/Api4/Generic/AbstractEntity.php
index 5caca47384fc..432ab7b8d434 100644
--- a/Civi/Api4/Generic/AbstractEntity.php
+++ b/Civi/Api4/Generic/AbstractEntity.php
@@ -12,6 +12,7 @@
namespace Civi\Api4\Generic;
use Civi\API\Exception\NotImplementedException;
+use Civi\Api4\Utils\CoreUtil;
use Civi\Api4\Utils\ReflectionUtils;
/**
@@ -75,7 +76,7 @@ public static function permissions() {
* @return string
*/
public static function getEntityName(): string {
- return self::stripNamespace(static::class);
+ return CoreUtil::stripNamespace(static::class);
}
/**
@@ -87,7 +88,7 @@ public static function getEntityName(): string {
*/
protected static function getEntityTitle(bool $plural = FALSE): string {
$name = static::getEntityName();
- $dao = \CRM_Core_DAO_AllCoreTables::getFullName($name);
+ $dao = self::getDaoName();
return $dao ? $dao::getEntityTitle($plural) : ($plural ? \CRM_Utils_String::pluralize($name) : $name);
}
@@ -116,6 +117,13 @@ public static function __callStatic($action, $args) {
return $actionObject;
}
+ /**
+ * @return \CRM_Core_DAO|string|null
+ */
+ protected static function getDaoName(): ?string {
+ return \CRM_Core_DAO_AllCoreTables::getFullName(static::getEntityName());
+ }
+
/**
* Reflection function called by Entity::get()
*
@@ -128,7 +136,7 @@ public static function getInfo() {
'name' => $entityName,
'title' => static::getEntityTitle(),
'title_plural' => static::getEntityTitle(TRUE),
- 'type' => [self::stripNamespace(get_parent_class(static::class))],
+ 'type' => [CoreUtil::stripNamespace(get_parent_class(static::class))],
'paths' => [],
'class' => static::class,
'primary_key' => ['id'],
@@ -137,7 +145,7 @@ public static function getInfo() {
'searchable' => 'secondary',
];
// Add info for entities with a corresponding DAO
- $dao = \CRM_Core_DAO_AllCoreTables::getFullName($info['name']);
+ $dao = static::getDaoName();
if ($dao) {
$info['paths'] = $dao::getEntityPaths();
$info['primary_key'] = $dao::$_primaryKey;
@@ -146,9 +154,18 @@ public static function getInfo() {
$info['dao'] = $dao;
$info['table_name'] = $dao::$_tableName;
$info['icon_field'] = (array) ($dao::fields()['icon']['name'] ?? NULL);
+ if (method_exists($dao, 'indices')) {
+ foreach (\CRM_Utils_Array::findAll($dao::indices(FALSE), ['unique' => TRUE, 'localizable' => FALSE]) as $index) {
+ foreach ($index['field'] as $field) {
+ // Trim `field(length)` to just `field`
+ [$field] = explode('(', $field);
+ $info['match_fields'][] = $field;
+ }
+ }
+ }
}
foreach (ReflectionUtils::getTraits(static::class) as $trait) {
- $info['type'][] = self::stripNamespace($trait);
+ $info['type'][] = CoreUtil::stripNamespace($trait);
}
// Get DocBlock from APIv4 Entity class
$reflection = new \ReflectionClass(static::class);
@@ -179,14 +196,4 @@ public static function getInfo() {
return $info;
}
- /**
- * Remove namespace prefix from a class name
- *
- * @param string $className
- * @return string
- */
- private static function stripNamespace(string $className): string {
- return substr($className, strrpos($className, '\\') + 1);
- }
-
}
diff --git a/Civi/Api4/Generic/AutocompleteAction.php b/Civi/Api4/Generic/AutocompleteAction.php
index 096ffa0551ad..183043e3a851 100644
--- a/Civi/Api4/Generic/AutocompleteAction.php
+++ b/Civi/Api4/Generic/AutocompleteAction.php
@@ -149,23 +149,29 @@ public function _run(Result $result) {
else {
// Default search and sort field
$labelField = $this->display['settings']['columns'][0]['key'];
- $idField = CoreUtil::getIdFieldName($this->savedSearch['api_entity']);
+ $primaryKeys = CoreUtil::getInfoItem($this->savedSearch['api_entity'], 'primary_key');
$this->display['settings'] += [
'sort' => [$labelField, 'ASC'],
];
// Always search on the first line of the display
$searchFields = [$labelField];
- // If input is an integer, search by id
- $numericInput = $this->page == 1 && \CRM_Utils_Rule::positiveInteger($this->input);
- if ($numericInput) {
- $searchFields = [$idField];
+ // If input is an integer...
+ $searchById = \CRM_Utils_Rule::positiveInteger($this->input) &&
+ // ...and there is exactly one primary key (e.g. EntitySet has zero, others might have compound keys)
+ count($primaryKeys) === 1 &&
+ // ...and the primary key field is type Integer (e.g. Afform.name is a String)
+ ($this->getField($primaryKeys[0])['data_type'] ?? NULL) === 'Integer';
+ // ...then search by primary key on first page
+ $initialSearchById = $searchById && $this->page == 1;
+ if ($initialSearchById) {
+ $searchFields = $primaryKeys;
}
- // For subsequent pages when searching numeric input
- elseif ($this->page > 1 && \CRM_Utils_Rule::positiveInteger($this->input)) {
+ // For subsequent pages when searching by id, subtract the "extra" first page
+ elseif ($searchById && $this->page > 1) {
$this->page -= 1;
}
// If first line uses a rewrite, search on those fields too
- if (!empty($this->display['settings']['columns'][0]['rewrite'])) {
+ if (!$initialSearchById && !empty($this->display['settings']['columns'][0]['rewrite'])) {
$searchFields = array_merge($searchFields, $this->getTokens($this->display['settings']['columns'][0]['rewrite']));
}
$this->display['settings']['limit'] = $this->display['settings']['limit'] ?? \Civi::settings()->get('search_autocomplete_count');
@@ -198,7 +204,7 @@ public function _run(Result $result) {
$result[] = $item;
}
$result->setCountMatched($apiResult->count());
- if (!empty($numericInput)) {
+ if (!empty($initialSearchById)) {
// Trigger "more results" after searching by exact id
$result->setCountMatched($apiResult->count() + 1);
}
@@ -279,16 +285,8 @@ private function augmentSelectClause(string $idField, array $displayFields) {
*/
private function getKeyField() {
$entityName = $this->savedSearch['api_entity'];
- if ($this->key) {
- /** @var \CRM_Core_DAO $dao */
- $dao = CoreUtil::getInfoItem($entityName, 'dao');
- if ($dao && method_exists($dao, 'indices')) {
- foreach ($dao::indices(FALSE) as $index) {
- if (!empty($index['unique']) && in_array($this->key, $index['field'], TRUE)) {
- return $this->key;
- }
- }
- }
+ if ($this->key && in_array($this->key, CoreUtil::getInfoItem($entityName, 'match_fields') ?? [], TRUE)) {
+ return $this->key;
}
return $this->display['settings']['keyField'] ?? CoreUtil::getIdFieldName($entityName);
}
diff --git a/Civi/Api4/Generic/BasicGetFieldsAction.php b/Civi/Api4/Generic/BasicGetFieldsAction.php
index 895701f2adb7..07ba072000fb 100644
--- a/Civi/Api4/Generic/BasicGetFieldsAction.php
+++ b/Civi/Api4/Generic/BasicGetFieldsAction.php
@@ -138,7 +138,7 @@ protected function formatResults(&$values, $isInternal) {
if (array_key_exists('label', $fieldDefaults)) {
$field['label'] = $field['label'] ?? $field['title'] ?? $field['name'];
}
- if (!empty($field['options']) && is_array($field['options']) && empty($field['suffixes']) && array_key_exists('suffixes', $field)) {
+ if (isset($field['options']) && is_array($field['options']) && empty($field['suffixes']) && array_key_exists('suffixes', $field)) {
$this->setFieldSuffixes($field);
}
if (isset($defaults['options'])) {
@@ -156,13 +156,14 @@ protected function formatResults(&$values, $isInternal) {
* @param array $field
*/
private function formatOptionList(&$field) {
- if (empty($field['options'])) {
+ $optionsExist = isset($field['options']) && is_array($field['options']);
+ if (!isset($field['options'])) {
$field['options'] = !empty($field['pseudoconstant']);
}
if (!empty($field['pseudoconstant']['optionGroupName'])) {
$field['suffixes'] = CoreUtil::getOptionValueFields($field['pseudoconstant']['optionGroupName']);
}
- if (!$this->loadOptions || !$field['options']) {
+ if (!$this->loadOptions || (!$optionsExist && empty($field['pseudoconstant']))) {
$field['options'] = (bool) $field['options'];
return;
}
@@ -324,6 +325,7 @@ public function fields() {
'Email' => ts('Email'),
'EntityRef' => ts('Autocomplete Entity'),
'File' => ts('File'),
+ 'Hidden' => ts('Hidden'),
'Location' => ts('Address Location'),
'Number' => ts('Number'),
'Radio' => ts('Radio Buttons'),
diff --git a/Civi/Api4/Generic/DAOGetFieldsAction.php b/Civi/Api4/Generic/DAOGetFieldsAction.php
index a3e2072d4cb9..8b4a5655ffd2 100644
--- a/Civi/Api4/Generic/DAOGetFieldsAction.php
+++ b/Civi/Api4/Generic/DAOGetFieldsAction.php
@@ -29,6 +29,14 @@ class DAOGetFieldsAction extends BasicGetFieldsAction {
protected function getRecords() {
$fieldsToGet = $this->_itemsToGet('name');
$typesToGet = $this->_itemsToGet('type');
+ // Force-set values supplied by entity definition
+ // e.g. if this is a ContactType pseudo-entity, set `contact_type` value which is used by the following:
+ // @see \Civi\Api4\Service\Spec\Provider\ContactGetSpecProvider
+ // @see \Civi\Api4\Service\Spec\SpecGatherer::addDAOFields
+ $presetValues = CoreUtil::getInfoItem($this->getEntityName(), 'where') ?? [];
+ foreach ($presetValues as $presetField => $presetValue) {
+ $this->addValue($presetField, $presetValue);
+ }
/** @var \Civi\Api4\Service\Spec\SpecGatherer $gatherer */
$gatherer = \Civi::container()->get('spec_gatherer');
$includeCustom = TRUE;
diff --git a/Civi/Api4/Generic/ExportAction.php b/Civi/Api4/Generic/ExportAction.php
index d7903a70e693..4561afa86076 100644
--- a/Civi/Api4/Generic/ExportAction.php
+++ b/Civi/Api4/Generic/ExportAction.php
@@ -24,7 +24,7 @@
* @method $this setId(int $id)
* @method int getId()
* @method $this setMatch(array $match) Specify fields to match for update.
- * @method bool getMatch()
+ * @method array getMatch()
* @method $this setCleanup(string $cleanup)
* @method string getCleanup()
* @method $this setUpdate(string $update)
@@ -40,17 +40,14 @@ class ExportAction extends AbstractAction {
protected $id;
/**
- * Specify fields to match when managed records are being reconciled.
+ * Fields to match when managed records are being reconciled.
*
- * To prevent "DB Error: Already Exists" errors, it's generally a good idea to set this
- * value to whatever unique fields this entity has (for most entities it's "name").
- * The managed system will then check if a record with that name already exists before
- * trying to create a new one.
+ * By default this will be set automatically based on the entity's unique fields.
*
* @var array
* @optionsCallback getMatchFields
*/
- protected $match = ['name'];
+ protected $match;
/**
* Specify rule for auto-updating managed entity
@@ -76,18 +73,17 @@ class ExportAction extends AbstractAction {
* @param \Civi\Api4\Generic\Result $result
*/
public function _run(Result $result) {
- $this->exportRecord($this->getEntityName(), $this->id, $result, $this->match);
+ $this->exportRecord($this->getEntityName(), $this->id, $result);
}
/**
* @param string $entityType
* @param int $entityId
* @param \Civi\Api4\Generic\Result $result
- * @param array $matchFields
* @param string $parentName
* @param array $excludeFields
*/
- private function exportRecord(string $entityType, int $entityId, Result $result, array $matchFields, $parentName = NULL, $excludeFields = []) {
+ private function exportRecord(string $entityType, int $entityId, Result $result, $parentName = NULL, $excludeFields = []) {
if (isset($this->exportedEntities[$entityType][$entityId])) {
throw new \CRM_Core_Exception("Circular reference detected: attempted to export $entityType id $entityId multiple times.");
}
@@ -121,27 +117,12 @@ private function exportRecord(string $entityType, int $entityId, Result $result,
}
// The get api always returns ID, but it should not be included in an export
unset($record['id']);
- // Should references be limited to the current domain?
- $limitRefsByDomain = $entityType === 'OptionGroup' && \CRM_Core_OptionGroup::isDomainOptionGroup($record['name']) ? \CRM_Core_BAO_Domain::getDomain()->id : FALSE;
- foreach ($allFields as $fieldName => $field) {
- if (($field['fk_entity'] ?? NULL) === 'Domain') {
- $alias = $fieldName . '.name';
- if (isset($record[$alias])) {
- // If this entity is for a specific domain, limit references to that same domain
- if ($fieldName === 'domain_id') {
- $limitRefsByDomain = \CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Domain', $record[$alias], 'id', 'name');
- }
- // Swap current domain for special API keyword
- if ($record[$alias] === \CRM_Core_BAO_Domain::getDomain()->name) {
- unset($record[$alias]);
- $record[$fieldName] = 'current_domain';
- }
- }
- }
- }
$name = ($parentName ?? '') . $entityType . '_' . ($record['name'] ?? count($this->exportedEntities[$entityType]));
- // Ensure safe characters, max length
- $name = \CRM_Utils_String::munge($name, '_', 127);
+ // Ensure safe characters, max length.
+ // This is used for the value of `civicrm_managed.name` which has a maxlength of 255, but is also used
+ // to generate a file by civix, and many filesystems have a maxlength of 255 including the suffix, so
+ // 255 - strlen('.mgd.php') = 247
+ $name = \CRM_Utils_String::munge($name, '_', 247);
// Include option group with custom field
if ($entityType === 'CustomField') {
if (
@@ -149,7 +130,7 @@ private function exportRecord(string $entityType, int $entityId, Result $result,
// Sometimes fields share an option group; only export it once.
empty($this->exportedEntities['OptionGroup'][$record['option_group_id']])
) {
- $this->exportRecord('OptionGroup', $record['option_group_id'], $result, $matchFields);
+ $this->exportRecord('OptionGroup', $record['option_group_id'], $result);
}
}
// Don't use joins/pseudoconstants if null or if it has the same value as the original
@@ -161,6 +142,12 @@ private function exportRecord(string $entityType, int $entityId, Result $result,
unset($record[$fieldName]);
}
}
+ // Unset values that match the default
+ foreach ($allFields as $fieldName => $field) {
+ if (($record[$fieldName] ?? NULL) === $field['default_value']) {
+ unset($record[$fieldName]);
+ }
+ }
$export = [
'name' => $name,
'entity' => $entityType,
@@ -171,8 +158,13 @@ private function exportRecord(string $entityType, int $entityId, Result $result,
'values' => $record,
],
];
- foreach (array_unique(array_intersect($matchFields, array_keys($allFields))) as $match) {
- $export['params']['match'][] = $match;
+ $matchFields = $this->match;
+ // Calculate $match param if not passed explicitly
+ if (!isset($matchFields)) {
+ $matchFields = (array) CoreUtil::getInfoItem($entityType, 'match_fields');
+ }
+ if ($matchFields) {
+ $export['params']['match'] = $matchFields;
}
$result[] = $export;
// Export entities that reference this one
@@ -188,15 +180,6 @@ private function exportRecord(string $entityType, int $entityId, Result $result,
if ($refEntity === 'CustomField' && $entityType === 'OptionGroup') {
continue;
}
- // Limit references by domain
- if (property_exists($reference, 'domain_id')) {
- if (!isset($reference->domain_id)) {
- $reference->find(TRUE);
- }
- if (isset($reference->domain_id) && $reference->domain_id != $limitRefsByDomain) {
- continue;
- }
- }
$references[$refEntity][] = $reference;
}
foreach ($references as $refEntity => $records) {
@@ -219,18 +202,8 @@ private function exportRecord(string $entityType, int $entityId, Result $result,
return $a->$weightCol < $b->$weightCol ? -1 : 1;
});
}
- $referenceMatchFields = $matchFields;
- // Add back-reference to "match" fields to enforce uniqueness
- // See https://lab.civicrm.org/dev/core/-/issues/4286
- if ($referenceMatchFields) {
- foreach ($reference::fields() as $field) {
- if (($field['FKClassName'] ?? '') === $daoName) {
- $referenceMatchFields[] = $field['name'];
- }
- }
- }
foreach ($records as $record) {
- $this->exportRecord($refEntity, $record->id, $result, $referenceMatchFields, $name . '_', $exclude);
+ $this->exportRecord($refEntity, $record->id, $result, $name . '_', $exclude);
}
}
}
@@ -275,6 +248,8 @@ private function getFieldsForExport($entityType, $loadOptions = FALSE, $excludeF
['type', 'IN', ['Field', 'Custom']],
['readonly', '!=', TRUE],
];
+ // Domains are handled automatically
+ $excludeFields[] = 'domain_id';
if ($excludeFields) {
$conditions[] = ['name', 'NOT IN', $excludeFields];
}
diff --git a/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php b/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php
index d0e943a9751b..eee54e51992f 100644
--- a/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php
+++ b/Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php
@@ -166,8 +166,12 @@ public static function filterCompare(array $row, array $condition, int $index =
case 'REGEXP':
case 'NOT REGEXP':
- $pattern = '/' . str_replace('/', '\\/', $expected) . '/';
- return !preg_match($pattern, $value) == ($operator != 'REGEXP');
+ case 'REGEXP BINARY':
+ case 'NOT REGEXP BINARY':
+ // Perform case-sensitive matching for BINARY operator, otherwise insensitive
+ $i = str_ends_with($operator, 'BINARY') ? '' : 'i';
+ $pattern = '/' . str_replace('/', '\\/', $expected) . "/$i";
+ return !preg_match($pattern, $value) == str_starts_with($operator, 'NOT');
case 'IN':
return in_array($value, $expected);
diff --git a/Civi/Api4/Generic/Traits/DAOActionTrait.php b/Civi/Api4/Generic/Traits/DAOActionTrait.php
index 3de18daa7ca6..3a7d72c4e891 100644
--- a/Civi/Api4/Generic/Traits/DAOActionTrait.php
+++ b/Civi/Api4/Generic/Traits/DAOActionTrait.php
@@ -13,7 +13,6 @@
namespace Civi\Api4\Generic\Traits;
use Civi\Api4\CustomField;
-use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable;
use Civi\Api4\Utils\FormattingUtil;
use Civi\Api4\Utils\CoreUtil;
use Civi\Api4\Utils\ReflectionUtils;
@@ -103,7 +102,7 @@ protected function fillDefaults(&$params) {
protected function writeObjects($items) {
$updateWeights = FALSE;
// Adjust weights for sortable entities
- if (in_array('SortableEntity', CoreUtil::getInfoItem($this->getEntityName(), 'type'))) {
+ if (CoreUtil::isType($this->getEntityName(), 'SortableEntity')) {
$weightField = CoreUtil::getInfoItem($this->getEntityName(), 'order_by');
// Only take action if updating a single record, or if no weights are specified in any record
// This avoids messing up a bulk update with multiple recalculations
@@ -112,6 +111,9 @@ protected function writeObjects($items) {
}
}
+ // Values specified by entity definition (e.g. 'Individual', 'Organization', 'Household' pseudo-entities specify `contact_type`)
+ $presetValues = CoreUtil::getInfoItem($this->getEntityName(), 'where') ?? [];
+
$result = [];
$idField = CoreUtil::getIdFieldName($this->getEntityName());
@@ -120,6 +122,10 @@ protected function writeObjects($items) {
FormattingUtil::formatWriteParams($item, $this->entityFields());
$this->formatCustomParams($item, $entityId);
+ if (!$entityId) {
+ $item = $presetValues + $item;
+ }
+
// Adjust weights for sortable entities
if ($updateWeights) {
$this->updateWeight($item);
@@ -311,7 +317,7 @@ protected function getCustomFieldInfo(string $fieldExpr) {
$field['table_name'] = $field['custom_group_id.table_name'];
unset($field['custom_group_id.table_name']);
$field['name'] = $groupName . '.' . $name;
- $field['entity'] = CustomGroupJoinable::getEntityFromExtends($field['custom_group_id.extends']);
+ $field['entity'] = \CRM_Core_BAO_CustomGroup::getEntityFromExtends($field['custom_group_id.extends']);
$info[$name] = $field;
}
\Civi::cache('metadata')->set($cacheKey, $info);
diff --git a/Civi/Api4/Generic/Traits/ManagedEntity.php b/Civi/Api4/Generic/Traits/ManagedEntity.php
index f014bc76a69e..1e0ebe4b2edc 100644
--- a/Civi/Api4/Generic/Traits/ManagedEntity.php
+++ b/Civi/Api4/Generic/Traits/ManagedEntity.php
@@ -27,8 +27,7 @@ trait ManagedEntity {
*/
public static function revert($checkPermissions = TRUE) {
return (new BasicBatchAction(static::getEntityName(), __FUNCTION__, function($item, BasicBatchAction $action) {
- $params = ['entity_type' => $action->getEntityName(), 'entity_id' => $item['id']];
- if (\CRM_Core_ManagedEntities::singleton()->revert($params)) {
+ if (\CRM_Core_ManagedEntities::singleton()->revert($action->getEntityName(), $item['id'])) {
return $item;
}
else {
diff --git a/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php b/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php
index 337f3c052fea..f10c09e818ee 100644
--- a/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php
+++ b/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php
@@ -148,7 +148,7 @@ protected function getJoins() {
*/
private function getQuery() {
if (!isset($this->_selectQuery) && !empty($this->savedSearch['api_entity'])) {
- if (!in_array('DAOEntity', CoreUtil::getInfoItem($this->savedSearch['api_entity'], 'type'), TRUE)) {
+ if (!CoreUtil::isType($this->savedSearch['api_entity'], 'DAOEntity')) {
return $this->_selectQuery = FALSE;
}
$api = Request::create($this->savedSearch['api_entity'], 'get', $this->savedSearch['api_params']);
@@ -282,7 +282,7 @@ protected function applyFilter($fieldName, $value) {
foreach ($fieldNames as $fieldName) {
$field = $this->getField($fieldName);
$dataType = $field['data_type'] ?? NULL;
- $operators = ($field['operators'] ?? []) ?: CoreUtil::getOperators();
+ $operators = array_values($field['operators'] ?? []) ?: CoreUtil::getOperators();
// Array is either associative `OP => VAL` or sequential `IN (...)`
if (is_array($value)) {
$value = array_filter($value, [$this, 'hasValue']);
@@ -290,13 +290,15 @@ protected function applyFilter($fieldName, $value) {
if (array_diff_key($value, array_flip(CoreUtil::getOperators()))) {
// Use IN for regular fields
if (empty($field['serialize'])) {
- $filterClauses[] = [$fieldName, 'IN', $value];
+ $op = in_array('IN', $operators, TRUE) ? 'IN' : $operators[0];
+ $filterClauses[] = [$fieldName, $op, $value];
}
// Use an OR group of CONTAINS for array fields
else {
+ $op = in_array('CONTAINS', $operators, TRUE) ? 'CONTAINS' : $operators[0];
$orGroup = [];
foreach ($value as $val) {
- $orGroup[] = [$fieldName, 'CONTAINS', $val];
+ $orGroup[] = [$fieldName, $op, $val];
}
$filterClauses[] = ['OR', $orGroup];
}
@@ -326,7 +328,8 @@ protected function applyFilter($fieldName, $value) {
$filterClauses[] = [$fieldName, 'IN', (array) $value];
}
else {
- $filterClauses[] = [$fieldName, '=', $value];
+ $op = in_array('=', $operators, TRUE) ? '=' : $operators[0];
+ $filterClauses[] = [$fieldName, $op, $value];
}
}
// Single field
diff --git a/Civi/Api4/Household.php b/Civi/Api4/Household.php
new file mode 100644
index 000000000000..260cc8852d20
--- /dev/null
+++ b/Civi/Api4/Household.php
@@ -0,0 +1,33 @@
+ Household]
+ * into get, create, and batch actions (however, when updating or deleting a single Contact by id,
+ * this will transparently pass-through to the Contact entity, so don't rely on this facade to enforce
+ * contact type for single-record-by-id write operations).
+ *
+ * @inheritDoc
+ * @searchable secondary
+ * @since 5.67
+ * @package Civi\Api4
+ */
+class Household extends Contact {
+
+ protected static function getEntityTitle(bool $plural = FALSE): string {
+ return $plural ? ts('Households') : ts('Household');
+ }
+
+}
diff --git a/Civi/Api4/Individual.php b/Civi/Api4/Individual.php
new file mode 100644
index 000000000000..9b701ef93611
--- /dev/null
+++ b/Civi/Api4/Individual.php
@@ -0,0 +1,32 @@
+ Individual]
+ * into get, create, and batch actions (however, when updating or deleting a single Contact by id,
+ * this will transparently pass-through to the Contact entity, so don't rely on this facade to enforce
+ * contact type for single-record-by-id write operations).
+ *
+ * @inheritDoc
+ * @since 5.67
+ * @package Civi\Api4
+ */
+class Individual extends Contact {
+
+ protected static function getEntityTitle(bool $plural = FALSE): string {
+ return $plural ? ts('Individuals') : ts('Individual');
+ }
+
+}
diff --git a/Civi/Api4/Navigation.php b/Civi/Api4/Navigation.php
index fc1d08e56d5e..5483dcb55fce 100644
--- a/Civi/Api4/Navigation.php
+++ b/Civi/Api4/Navigation.php
@@ -16,6 +16,7 @@
* @searchable none
* @orderBy weight
* @groupWeightsBy domain_id,parent_id
+ * @matchFields name,domain_id
* @since 5.19
* @package Civi\Api4
*/
diff --git a/Civi/Api4/OptionValue.php b/Civi/Api4/OptionValue.php
index a3486c3e7c76..9e2a580c1fc8 100644
--- a/Civi/Api4/OptionValue.php
+++ b/Civi/Api4/OptionValue.php
@@ -17,6 +17,7 @@
* @searchable secondary
* @orderBy weight
* @groupWeightsBy option_group_id
+ * @matchFields option_group_id,name
* @since 5.19
* @package Civi\Api4
*/
diff --git a/Civi/Api4/Organization.php b/Civi/Api4/Organization.php
new file mode 100644
index 000000000000..76c664e73bdc
--- /dev/null
+++ b/Civi/Api4/Organization.php
@@ -0,0 +1,32 @@
+ Organization]
+ * into get, create, and batch actions (however, when updating or deleting a single Contact by id,
+ * this will transparently pass-through to the Contact entity, so don't rely on this facade to enforce
+ * contact type for single-record-by-id write operations).
+ *
+ * @inheritDoc
+ * @since 5.67
+ * @package Civi\Api4
+ */
+class Organization extends Contact {
+
+ protected static function getEntityTitle(bool $plural = FALSE): string {
+ return $plural ? ts('Organizations') : ts('Organization');
+ }
+
+}
diff --git a/Civi/Api4/Provider/CustomEntityProvider.php b/Civi/Api4/Provider/CustomEntityProvider.php
index b454a55eedf3..41f40971596c 100644
--- a/Civi/Api4/Provider/CustomEntityProvider.php
+++ b/Civi/Api4/Provider/CustomEntityProvider.php
@@ -12,9 +12,9 @@
namespace Civi\Api4\Provider;
use Civi\Api4\CustomValue;
-use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable;
use Civi\Core\Event\GenericHookEvent;
use Civi\Core\Service\AutoService;
+use CRM_Core_BAO_CustomGroup;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@@ -44,7 +44,7 @@ public static function addCustomEntities(GenericHookEvent $e) {
$group = \CRM_Core_DAO::executeQuery($select);
while ($group->fetch()) {
$entityName = 'Custom_' . $group->name;
- $baseEntity = CustomGroupJoinable::getEntityFromExtends($group->extends);
+ $baseEntity = CRM_Core_BAO_CustomGroup::getEntityFromExtends($group->extends);
// Lookup base entity info using DAO methods not CoreUtil to avoid early-bootstrap issues
$baseEntityDao = \CRM_Core_DAO_AllCoreTables::getFullName($baseEntity);
$baseEntityTitle = $baseEntityDao ? $baseEntityDao::getEntityTitle(TRUE) : $baseEntity;
diff --git a/Civi/Api4/Query/Api4Query.php b/Civi/Api4/Query/Api4Query.php
index a40cfd4a67e7..4f13808e9384 100644
--- a/Civi/Api4/Query/Api4Query.php
+++ b/Civi/Api4/Query/Api4Query.php
@@ -27,7 +27,8 @@
* * '=', '<=', '>=', '>', '<', 'LIKE', "<>", "!=",
* * 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN',
* * 'IS NOT NULL', 'IS NULL', 'CONTAINS', 'NOT CONTAINS',
- * * 'IS EMPTY', 'IS NOT EMPTY', 'REGEXP', 'NOT REGEXP'.
+ * * 'IS EMPTY', 'IS NOT EMPTY', 'REGEXP', 'NOT REGEXP'
+ * * 'REGEXP BINARY', 'NOT REGEXP BINARY'
*/
abstract class Api4Query {
@@ -402,7 +403,7 @@ protected function createSQLClause($fieldAlias, $operator, $value, $field, int $
}
}
- if ($operator == 'REGEXP' || $operator == 'NOT REGEXP') {
+ if ($operator == 'REGEXP' || $operator == 'NOT REGEXP' || $operator == 'REGEXP BINARY' || $operator == 'NOT REGEXP BINARY') {
return sprintf('%s %s "%s"', $fieldAlias, $operator, \CRM_Core_DAO::escapeString($value));
}
diff --git a/Civi/Api4/Query/Api4SelectQuery.php b/Civi/Api4/Query/Api4SelectQuery.php
index 2d42a349603f..44833e9c6ddf 100644
--- a/Civi/Api4/Query/Api4SelectQuery.php
+++ b/Civi/Api4/Query/Api4SelectQuery.php
@@ -87,6 +87,12 @@ public function __construct($api) {
// Add ACLs first to avoid redundant subclauses
$this->query->where($this->getAclClause(self::MAIN_TABLE_ALIAS, $this->getEntity(), [], $this->getWhere()));
+ // Add required conditions if specified by entity
+ $requiredConditions = CoreUtil::getInfoItem($this->getEntity(), 'where') ?? [];
+ foreach ($requiredConditions as $requiredField => $requiredValue) {
+ $this->api->addWhere($requiredField, '=', $requiredValue);
+ }
+
// Add explicit joins. Other joins implied by dot notation may be added later
$this->addExplicitJoins();
}
@@ -415,7 +421,7 @@ public function getFieldSibling(array $field, string $siblingFieldName) {
*/
public function checkEntityAccess($entity) {
if (!$this->getCheckPermissions()) {
- return TRUE;
+ return CoreUtil::entityExists($entity);
}
if (!isset($this->entityAccess[$entity])) {
try {
@@ -425,7 +431,8 @@ public function checkEntityAccess($entity) {
])->first();
}
// Anonymous users might not even be allowed to use 'getActions'
- catch (UnauthorizedException $e) {
+ // Or tne entity might not exist
+ catch (\CRM_Core_Exception $e) {
$this->entityAccess[$entity] = FALSE;
}
}
@@ -467,6 +474,11 @@ private function addExplicitJoins() {
$side = 'LEFT';
$this->api->addWhere("$alias.id", 'IS NULL');
}
+ // Add required conditions if specified by entity
+ $requiredConditions = CoreUtil::getInfoItem($entity, 'where') ?? [];
+ foreach ($requiredConditions as $requiredField => $requiredValue) {
+ $join[] = [$alias . '.' . $requiredField, '=', "'$requiredValue'"];
+ }
// Add all fields from joined entity to spec
$joinEntityGet = \Civi\API\Request::create($entity, 'get', ['version' => 4, 'checkPermissions' => $this->getCheckPermissions()]);
$joinEntityFields = $joinEntityGet->entityFields();
diff --git a/Civi/Api4/Query/SqlExpression.php b/Civi/Api4/Query/SqlExpression.php
index 9555152db6fa..a58a580a73f9 100644
--- a/Civi/Api4/Query/SqlExpression.php
+++ b/Civi/Api4/Query/SqlExpression.php
@@ -11,6 +11,8 @@
namespace Civi\Api4\Query;
+use Civi\Api4\Utils\CoreUtil;
+
/**
* Base class for SqlColumn, SqlString, SqlBool, and SqlFunction classes.
*
@@ -66,6 +68,26 @@ public function __construct(string $expr, $alias = NULL) {
abstract protected function initialize();
+ private static function munge($name, $char = '_', $len = 63) {
+ // Replace all white space and non-alpha numeric with $char
+ // we only use the ascii character set since mysql does not create table names / field names otherwise
+ // CRM-11744
+ $name = preg_replace('/[^a-zA-Z0-9_]+/', $char, trim($name));
+
+ // If there are no ascii characters present.
+ if (!strlen(trim($name, $char))) {
+ $name = \CRM_Utils_String::createRandom($len, \CRM_Utils_String::ALPHANUMERIC);
+ }
+
+ if ($len) {
+ // lets keep variable names short
+ return substr($name, 0, $len);
+ }
+ else {
+ return $name;
+ }
+ }
+
/**
* Converts a string to a SqlExpression object.
*
@@ -80,7 +102,7 @@ abstract protected function initialize();
public static function convert(string $expression, $parseAlias = FALSE, $mustBe = []) {
$as = $parseAlias ? strrpos($expression, ' AS ') : FALSE;
$expr = $as ? substr($expression, 0, $as) : $expression;
- $alias = $as ? \CRM_Utils_String::munge(substr($expression, $as + 4), '_', 256) : NULL;
+ $alias = $as ? self::munge(substr($expression, $as + 4), '_', 256) : NULL;
$bracketPos = strpos($expr, '(');
$firstChar = substr($expr, 0, 1);
$lastChar = substr($expr, -1);
@@ -174,8 +196,7 @@ public function getAlias(): string {
* @return string
*/
public function getType(): string {
- $className = get_class($this);
- return substr($className, strrpos($className, '\\') + 1);
+ return CoreUtil::stripNamespace(get_class($this));
}
/**
diff --git a/Civi/Api4/Queue.php b/Civi/Api4/Queue.php
index f50486245719..3339d066294d 100644
--- a/Civi/Api4/Queue.php
+++ b/Civi/Api4/Queue.php
@@ -12,6 +12,7 @@
use Civi\Api4\Action\Queue\ClaimItems;
use Civi\Api4\Action\Queue\RunItems;
+use Civi\Api4\Action\Queue\Run;
/**
* Track a list of durable/scannable queues.
@@ -40,10 +41,14 @@ public static function permissions() {
}
/**
- * Claim an item from the queue. Returns zero or one items.
+ * Claim some items from the queue. Returns zero or more items.
*
* Note: This is appropriate for persistent, auto-run queues.
*
+ * The number of items depends on the specific queue. Most notably, batch sizes are
+ * influenced by queue-driver support (`BatchQueueInterface`) and queue-configuration
+ * (`civicrm_queue.batch_limit`).
+ *
* @param bool $checkPermissions
* @return \Civi\Api4\Action\Queue\ClaimItems
*/
@@ -53,10 +58,14 @@ public static function claimItems($checkPermissions = TRUE) {
}
/**
- * Run an item from the queue.
+ * Run some items from the queue.
*
* Note: This is appropriate for persistent, auto-run queues.
*
+ * The number of items depends on the specific queue. Most notably, batch sizes are
+ * influenced by queue-driver support (`BatchQueueInterface`) and queue-configuration
+ * (`civicrm_queue.batch_limit`).
+ *
* @param bool $checkPermissions
* @return \Civi\Api4\Action\Queue\RunItems
*/
@@ -65,4 +74,19 @@ public static function runItems($checkPermissions = TRUE) {
->setCheckPermissions($checkPermissions);
}
+ /**
+ * Run a series of items from a queue.
+ *
+ * This is a lightweight main-loop for development/testing. It may have some limited utility for
+ * sysadmins who want to fine-tune runners on a specific queue. See the class docblock for
+ * more information.
+ *
+ * @param bool $checkPermissions
+ * @return \Civi\Api4\Action\Queue\Run
+ */
+ public static function run($checkPermissions = TRUE) {
+ return (new Run(static::getEntityName(), __FUNCTION__))
+ ->setCheckPermissions($checkPermissions);
+ }
+
}
diff --git a/Civi/Api4/Service/Autocomplete/ActivityAutocompleteProvider.php b/Civi/Api4/Service/Autocomplete/ActivityAutocompleteProvider.php
index 843ef5fea361..70d305e359b8 100644
--- a/Civi/Api4/Service/Autocomplete/ActivityAutocompleteProvider.php
+++ b/Civi/Api4/Service/Autocomplete/ActivityAutocompleteProvider.php
@@ -12,6 +12,7 @@
namespace Civi\Api4\Service\Autocomplete;
+use Civi\Api4\Utils\CoreUtil;
use Civi\Core\Event\GenericHookEvent;
use Civi\Core\HookInterface;
@@ -95,7 +96,7 @@ public static function on_civi_search_defaultDisplay(GenericHookEvent $e) {
// If the savedSearch includes a contact join, add it to the output and the sort.
foreach ($e->savedSearch['api_params']['join'] ?? [] as $join) {
[$entity, $contactAlias] = explode(' AS ', $join[0]);
- if ($entity === 'Contact') {
+ if (CoreUtil::isContact($entity)) {
array_unshift($e->display['settings']['sort'], ["$contactAlias.sort_name", 'ASC']);
$e->display['settings']['columns'][0]['rewrite'] = "[$contactAlias.sort_name] - [subject]";
$e->display['settings']['columns'][0]['empty_value'] = "[$contactAlias.sort_name] (" . ts('no subject') . ')';
diff --git a/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php b/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php
index e28e6fbaf960..e3a4c7c956e3 100644
--- a/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php
+++ b/Civi/Api4/Service/Autocomplete/CaseAutocompleteProvider.php
@@ -12,6 +12,7 @@
namespace Civi\Api4\Service\Autocomplete;
+use Civi\Api4\Utils\CoreUtil;
use Civi\Core\Event\GenericHookEvent;
use Civi\Core\HookInterface;
@@ -92,7 +93,7 @@ public static function on_civi_search_defaultDisplay(GenericHookEvent $e) {
// If the savedSearch includes a contact join, add it to the output and the sort.
foreach ($e->savedSearch['api_params']['join'] ?? [] as $join) {
[$entity, $contactAlias] = explode(' AS ', $join[0]);
- if ($entity === 'Contact') {
+ if (CoreUtil::isContact($entity)) {
array_unshift($e->display['settings']['sort'], ["$contactAlias.sort_name", 'ASC']);
$e->display['settings']['columns'][0]['rewrite'] = "[$contactAlias.sort_name] - [subject]";
$e->display['settings']['columns'][0]['empty_value'] = "[$contactAlias.sort_name] (" . ts('no subject') . ')';
diff --git a/Civi/Api4/Service/Autocomplete/ContactAutocompleteProvider.php b/Civi/Api4/Service/Autocomplete/ContactAutocompleteProvider.php
index b676baa692b5..27440a78241d 100644
--- a/Civi/Api4/Service/Autocomplete/ContactAutocompleteProvider.php
+++ b/Civi/Api4/Service/Autocomplete/ContactAutocompleteProvider.php
@@ -13,6 +13,7 @@
namespace Civi\Api4\Service\Autocomplete;
use Civi\API\Event\PrepareEvent;
+use Civi\Api4\Utils\CoreUtil;
use Civi\Core\Event\GenericHookEvent;
use Civi\Core\HookInterface;
@@ -49,7 +50,7 @@ public static function on_civi_api_prepare(PrepareEvent $event) {
* @param \Civi\Core\Event\GenericHookEvent $e
*/
public static function on_civi_search_defaultDisplay(GenericHookEvent $e) {
- if ($e->display['settings'] || $e->display['type'] !== 'autocomplete' || $e->savedSearch['api_entity'] !== 'Contact') {
+ if ($e->display['settings'] || $e->display['type'] !== 'autocomplete' || !CoreUtil::isContact($e->savedSearch['api_entity'])) {
return;
}
$e->display['settings'] = [
diff --git a/Civi/Api4/Service/Schema/Joinable/CustomGroupJoinable.php b/Civi/Api4/Service/Schema/Joinable/CustomGroupJoinable.php
index 4ca50f079554..1a10075f7674 100644
--- a/Civi/Api4/Service/Schema/Joinable/CustomGroupJoinable.php
+++ b/Civi/Api4/Service/Schema/Joinable/CustomGroupJoinable.php
@@ -89,25 +89,4 @@ public function getSqlColumn($fieldName) {
return $this->columns[$fieldName];
}
- /**
- * Translate custom_group.extends to entity name.
- *
- * Custom_group.extends pretty much maps 1-1 with entity names, except for a couple oddballs.
- * @see \CRM_Core_SelectValues::customGroupExtends
- *
- * @param $extends
- * @return string
- * @throws \CRM_Core_Exception
- * @throws \Civi\API\Exception\UnauthorizedException
- */
- public static function getEntityFromExtends($extends) {
- if (strpos($extends, 'Participant') === 0) {
- return 'Participant';
- }
- if ($extends === 'Contact' || in_array($extends, \CRM_Contact_BAO_ContactType::basicTypes(TRUE))) {
- return 'Contact';
- }
- return $extends;
- }
-
}
diff --git a/Civi/Api4/Service/Schema/Joiner.php b/Civi/Api4/Service/Schema/Joiner.php
index d42caa170844..9908d3a566be 100644
--- a/Civi/Api4/Service/Schema/Joiner.php
+++ b/Civi/Api4/Service/Schema/Joiner.php
@@ -80,7 +80,8 @@ public static function getExtraJoinSql(array $field, Api4SelectQuery $query): st
$prefix = empty($field['explicit_join']) ? '' : $field['explicit_join'] . '.';
$prefix .= (empty($field['implicit_join']) ? '' : $field['implicit_join'] . '.');
$idField = $query->getField($prefix . $field['name'] . '.id');
- return $idField['sql_name'];
+ // If permission denied to join, SELECT NULL
+ return $idField['sql_name'] ?? 'NULL';
}
}
diff --git a/Civi/Api4/Service/Schema/SchemaMapBuilder.php b/Civi/Api4/Service/Schema/SchemaMapBuilder.php
index dc388ae4e80e..beb5862c6b6a 100644
--- a/Civi/Api4/Service/Schema/SchemaMapBuilder.php
+++ b/Civi/Api4/Service/Schema/SchemaMapBuilder.php
@@ -16,6 +16,7 @@
use Civi\Api4\Event\SchemaMapBuildEvent;
use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable;
use Civi\Api4\Service\Schema\Joinable\Joinable;
+use Civi\Api4\Utils\CoreUtil;
use Civi\Core\Service\AutoService;
use Civi\Core\CiviEventDispatcherInterface;
use CRM_Core_DAO_AllCoreTables as AllCoreTables;
@@ -40,13 +41,13 @@ class SchemaMapBuilder extends AutoService {
*/
public function __construct(CiviEventDispatcherInterface $dispatcher) {
$this->dispatcher = $dispatcher;
- $this->apiEntities = array_keys((array) Entity::get(FALSE)->addSelect('name')->execute()->indexBy('name'));
+ $this->apiEntities = Entity::get(FALSE)->addSelect('name')->execute()->column('name');
}
/**
* @return SchemaMap
*/
- public function build() {
+ public function build(): SchemaMap {
$map = new SchemaMap();
$this->loadTables($map);
@@ -142,7 +143,7 @@ private function addCustomFields(SchemaMap $map, Table $baseTable, string $entit
}
if ($fieldData->data_type === 'EntityReference' && isset($fieldData->fk_entity)) {
- $targetTable = AllCoreTables::getTableForEntityName($fieldData->fk_entity);
+ $targetTable = self::getTableName($fieldData->fk_entity);
$joinable = new Joinable($targetTable, 'id', $fieldData->name);
$customTable->addTableLink($fieldData->column_name, $joinable);
}
@@ -162,4 +163,15 @@ private function addCustomFields(SchemaMap $map, Table $baseTable, string $entit
}
}
+ /**
+ * @param string $entityName
+ * @return string
+ */
+ private static function getTableName(string $entityName) {
+ if (CoreUtil::isContact($entityName)) {
+ return 'civicrm_contact';
+ }
+ return AllCoreTables::getTableForEntityName($entityName);
+ }
+
}
diff --git a/Civi/Api4/Service/Spec/Provider/ContactGetSpecProvider.php b/Civi/Api4/Service/Spec/Provider/ContactGetSpecProvider.php
index 3e664c9c184c..9d630092b9c1 100644
--- a/Civi/Api4/Service/Spec/Provider/ContactGetSpecProvider.php
+++ b/Civi/Api4/Service/Spec/Provider/ContactGetSpecProvider.php
@@ -15,6 +15,7 @@
use Civi\Api4\Query\Api4SelectQuery;
use Civi\Api4\Service\Spec\FieldSpec;
use Civi\Api4\Service\Spec\RequestSpec;
+use Civi\Api4\Utils\CoreUtil;
/**
* @service
@@ -27,7 +28,7 @@ class ContactGetSpecProvider extends \Civi\Core\Service\AutoService implements G
*/
public function modifySpec(RequestSpec $spec) {
// Groups field
- $field = new FieldSpec('groups', 'Contact', 'Array');
+ $field = new FieldSpec('groups', $spec->getEntity(), 'Array');
$field->setLabel(ts('In Groups'))
->setTitle(ts('Groups'))
->setColumnName('id')
@@ -40,11 +41,10 @@ public function modifySpec(RequestSpec $spec) {
->setOptionsCallback([__CLASS__, 'getGroupList']);
$spec->addFieldSpec($field);
- // The following fields are specific to Individuals, so omit them if
- // `contact_type` value was passed to `getFields` and is not "Individual"
+ // The following fields are specific to Individuals
if (!$spec->getValue('contact_type') || $spec->getValue('contact_type') === 'Individual') {
// Age field
- $field = new FieldSpec('age_years', 'Contact', 'Integer');
+ $field = new FieldSpec('age_years', $spec->getEntity(), 'Integer');
$field->setLabel(ts('Age (years)'))
->setTitle(ts('Age (years)'))
->setColumnName('birth_date')
@@ -56,18 +56,16 @@ public function modifySpec(RequestSpec $spec) {
$spec->addFieldSpec($field);
// Birthday field
- if (!$spec->getValue('contact_type') || $spec->getValue('contact_type') === 'Individual') {
- $field = new FieldSpec('next_birthday', 'Contact', 'Integer');
- $field->setLabel(ts('Next Birthday in (days)'))
- ->setTitle(ts('Next Birthday in (days)'))
- ->setColumnName('birth_date')
- ->setInputType('Number')
- ->setDescription(ts('Number of days until next birthday'))
- ->setType('Extra')
- ->setReadonly(TRUE)
- ->setSqlRenderer([__CLASS__, 'calculateBirthday']);
- $spec->addFieldSpec($field);
- }
+ $field = new FieldSpec('next_birthday', $spec->getEntity(), 'Integer');
+ $field->setLabel(ts('Next Birthday in (days)'))
+ ->setTitle(ts('Next Birthday in (days)'))
+ ->setColumnName('birth_date')
+ ->setInputType('Number')
+ ->setDescription(ts('Number of days until next birthday'))
+ ->setType('Extra')
+ ->setReadonly(TRUE)
+ ->setSqlRenderer([__CLASS__, 'calculateBirthday']);
+ $spec->addFieldSpec($field);
}
// Address, Email, Phone, IM primary/billing virtual fields
@@ -118,7 +116,7 @@ public function modifySpec(RequestSpec $spec) {
foreach ($entities as $entity => $types) {
foreach ($types as $type => $info) {
$name = strtolower($entity) . '_' . $type;
- $field = new FieldSpec($name, 'Contact', 'Integer');
+ $field = new FieldSpec($name, $spec->getEntity(), 'Integer');
$field->setLabel($info['label'])
->setTitle($info['title'])
->setColumnName('id')
@@ -138,7 +136,8 @@ public function modifySpec(RequestSpec $spec) {
* @return bool
*/
public function applies($entity, $action) {
- return $entity === 'Contact' && $action === 'get';
+ // Applies to 'Contact' plus pseudo-entities 'Individual', 'Organization', 'Household'
+ return CoreUtil::isContact($entity) && $action === 'get';
}
/**
diff --git a/Civi/Api4/Service/Spec/Provider/CustomValueSpecProvider.php b/Civi/Api4/Service/Spec/Provider/CustomValueSpecProvider.php
index 1da2127af664..5ac7c1e6def8 100644
--- a/Civi/Api4/Service/Spec/Provider/CustomValueSpecProvider.php
+++ b/Civi/Api4/Service/Spec/Provider/CustomValueSpecProvider.php
@@ -14,6 +14,7 @@
use Civi\Api4\Service\Spec\FieldSpec;
use Civi\Api4\Service\Spec\RequestSpec;
+use Civi\Api4\Utils\CoreUtil;
/**
* @service
@@ -31,19 +32,26 @@ public function modifySpec(RequestSpec $spec) {
$idField->setType('Field');
$idField->setInputType('Number');
$idField->setColumnName('id');
- $idField->setNullable('false');
+ $idField->setNullable(FALSE);
$idField->setTitle(ts('Custom Value ID'));
$idField->setReadonly(TRUE);
$idField->setNullable(FALSE);
$spec->addFieldSpec($idField);
+ // Check which entity this group extends
+ $groupName = CoreUtil::getCustomGroupName($spec->getEntity());
+ $baseEntity = \CRM_Core_BAO_CustomGroup::getEntityForGroup($groupName);
+ // Lookup base entity info using DAO methods not CoreUtil to avoid early-bootstrap issues
+ $baseEntityDao = \CRM_Core_DAO_AllCoreTables::getFullName($baseEntity);
+ $baseEntityTitle = $baseEntityDao ? $baseEntityDao::getEntityTitle() : $baseEntity;
+
$entityField = new FieldSpec('entity_id', $spec->getEntity(), 'Integer');
$entityField->setType('Field');
$entityField->setColumnName('entity_id');
$entityField->setTitle(ts('Entity ID'));
- $entityField->setLabel(ts('Contact'));
+ $entityField->setLabel($baseEntityTitle);
$entityField->setRequired($action === 'create');
- $entityField->setFkEntity('Contact');
+ $entityField->setFkEntity($baseEntity);
$entityField->setReadonly(TRUE);
$entityField->setNullable(FALSE);
$entityField->setInputType('EntityRef');
@@ -54,7 +62,7 @@ public function modifySpec(RequestSpec $spec) {
* @inheritDoc
*/
public function applies($entity, $action) {
- return strstr($entity, 'Custom_');
+ return str_starts_with($entity, 'Custom_');
}
}
diff --git a/Civi/Api4/Service/Spec/Provider/ContactCreationSpecProvider.php b/Civi/Api4/Service/Spec/Provider/DashboardCreationSpecProvider.php
similarity index 64%
rename from Civi/Api4/Service/Spec/Provider/ContactCreationSpecProvider.php
rename to Civi/Api4/Service/Spec/Provider/DashboardCreationSpecProvider.php
index 15cb41cafd8d..beb34532fd74 100644
--- a/Civi/Api4/Service/Spec/Provider/ContactCreationSpecProvider.php
+++ b/Civi/Api4/Service/Spec/Provider/DashboardCreationSpecProvider.php
@@ -18,24 +18,21 @@
* @service
* @internal
*/
-class ContactCreationSpecProvider extends \Civi\Core\Service\AutoService implements Generic\SpecProviderInterface {
+class DashboardCreationSpecProvider extends \Civi\Core\Service\AutoService implements Generic\SpecProviderInterface {
/**
- * @param \Civi\Api4\Service\Spec\RequestSpec $spec
+ * @inheritDoc
*/
public function modifySpec(RequestSpec $spec) {
- $spec->getFieldByName('is_opt_out')->setRequired(FALSE);
- $spec->getFieldByName('is_deleted')->setRequired(FALSE);
+ // Arguably this is a bad default in the schema
+ $spec->getFieldByName('is_active')->setRequired(FALSE)->setDefaultValue(TRUE);
}
/**
- * @param string $entity
- * @param string $action
- *
- * @return bool
+ * @inheritDoc
*/
public function applies($entity, $action) {
- return $entity === 'Contact' && $action === 'create';
+ return in_array($entity, ['Dashboard', 'DashboardContact'], TRUE) && $action === 'create';
}
}
diff --git a/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php b/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php
index bdc05f6810ae..ac900b7299a5 100644
--- a/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php
+++ b/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php
@@ -74,7 +74,7 @@ public static function getTagFilterSql(array $field, string $fieldAlias, string
$value = array_unique(array_merge($value, $tagTree[$tagID]));
}
}
- $tags = \CRM_Utils_Type::validate(implode(',', $value), 'CommaSeparatedIntegers');
+ $tags = $value ? \CRM_Utils_Type::validate(implode(',', $value), 'CommaSeparatedIntegers') : '0';
return "$fieldAlias $operator (SELECT entity_id FROM `civicrm_entity_tag` WHERE entity_table = '$tableName' AND tag_id IN ($tags))";
}
diff --git a/Civi/Api4/Service/Spec/Provider/OptionGroupCreationSpecProvider.php b/Civi/Api4/Service/Spec/Provider/OptionGroupCreationSpecProvider.php
new file mode 100644
index 000000000000..738a80b6144c
--- /dev/null
+++ b/Civi/Api4/Service/Spec/Provider/OptionGroupCreationSpecProvider.php
@@ -0,0 +1,38 @@
+getFieldByName('name')->setRequired(FALSE);
+ $spec->getFieldByName('title')->setRequiredIf('empty($values.name)');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function applies($entity, $action) {
+ return $entity === 'OptionGroup' && $action === 'create';
+ }
+
+}
diff --git a/Civi/Api4/Service/Spec/Provider/RelationshipCacheSpecProvider.php b/Civi/Api4/Service/Spec/Provider/RelationshipCacheSpecProvider.php
index 051d7d0753ba..a7468f2c7372 100644
--- a/Civi/Api4/Service/Spec/Provider/RelationshipCacheSpecProvider.php
+++ b/Civi/Api4/Service/Spec/Provider/RelationshipCacheSpecProvider.php
@@ -61,6 +61,7 @@ public function modifySpec(RequestSpec $spec) {
// Fetches the value from the relationship
->setColumnName('relationship_id')
->setDescription($fieldInfo['description'])
+ ->setSuffixes(['name', 'label', 'icon'])
->setOptionsCallback(['CRM_Core_SelectValues', 'getPermissionedRelationshipOptions'])
->setSqlRenderer([__CLASS__, 'directionalRelationshipField']);
$spec->addFieldSpec($field);
diff --git a/Civi/Api4/Service/Spec/Provider/TagCreationSpecProvider.php b/Civi/Api4/Service/Spec/Provider/TagCreationSpecProvider.php
index dcfaeaff75ee..dce76d87fcd2 100644
--- a/Civi/Api4/Service/Spec/Provider/TagCreationSpecProvider.php
+++ b/Civi/Api4/Service/Spec/Provider/TagCreationSpecProvider.php
@@ -25,6 +25,8 @@ class TagCreationSpecProvider extends \Civi\Core\Service\AutoService implements
*/
public function modifySpec(RequestSpec $spec) {
$spec->getFieldByName('used_for')->setDefaultValue('civicrm_contact');
+ $spec->getFieldByName('name')->setRequired(FALSE)->setRequiredIf('empty($values.label)');
+ $spec->getFieldByName('label')->setRequired(FALSE)->setRequiredIf('empty($values.name)');
}
/**
diff --git a/Civi/Api4/Service/Spec/SpecFormatter.php b/Civi/Api4/Service/Spec/SpecFormatter.php
index d2c699192ab2..73bcd7a6cf56 100644
--- a/Civi/Api4/Service/Spec/SpecFormatter.php
+++ b/Civi/Api4/Service/Spec/SpecFormatter.php
@@ -130,14 +130,15 @@ public static function arrayToField(array $data, string $entityName): FieldSpec
* @return string
*/
private static function getDataType(array $data) {
- if (isset($data['data_type'])) {
- return !empty($data['time_format']) ? 'Timestamp' : $data['data_type'];
+ $dataType = $data['data_type'] ?? $data['dataType'] ?? NULL;
+ if (isset($dataType)) {
+ return !empty($data['time_format']) ? 'Timestamp' : $dataType;
}
$dataTypeInt = $data['type'] ?? NULL;
$dataTypeName = \CRM_Utils_Type::typeToString($dataTypeInt);
- return $dataTypeName;
+ return $dataTypeName === 'Int' ? 'Integer' : $dataTypeName;
}
/**
@@ -163,12 +164,12 @@ public static function getOptions($spec, $values, $returnFormat, $checkPermissio
$bao = CoreUtil::getBAOFromApiName($spec->getEntity());
$optionLabels = $bao::buildOptions($fieldName, NULL, $values);
- if (!is_array($optionLabels) || !$optionLabels) {
+ if (!is_array($optionLabels)) {
$options = FALSE;
}
else {
$options = \CRM_Utils_Array::makeNonAssociative($optionLabels, 'id', 'label');
- if (is_array($returnFormat)) {
+ if (is_array($returnFormat) && $options) {
self::addOptionProps($options, $spec, $bao, $fieldName, $values, $returnFormat);
}
}
@@ -303,10 +304,10 @@ public static function setInputTypeAndAttrs(FieldSpec &$fieldSpec, $data, $dataT
self::setLegacyDateFormat($inputAttrs);
}
// Number input for numeric fields
- if ($inputType === 'Text' && in_array($dataTypeName, ['Int', 'Float'], TRUE)) {
+ if ($inputType === 'Text' && in_array($dataTypeName, ['Integer', 'Float'], TRUE)) {
$inputType = 'Number';
// Todo: make 'step' configurable for the custom field
- $inputAttrs['step'] = $dataTypeName === 'Int' ? 1 : .01;
+ $inputAttrs['step'] = $dataTypeName === 'Integer' ? 1 : .01;
}
// Date/time settings from custom fields
if ($inputType == 'Date' && !empty($data['custom_group_id'])) {
diff --git a/Civi/Api4/Service/Spec/SpecGatherer.php b/Civi/Api4/Service/Spec/SpecGatherer.php
index 56fa359ef11b..d77e3a8bc49b 100644
--- a/Civi/Api4/Service/Spec/SpecGatherer.php
+++ b/Civi/Api4/Service/Spec/SpecGatherer.php
@@ -91,15 +91,12 @@ private function addDAOFields(string $entityName, string $action, RequestSpec $s
$DAOFields = $this->getDAOFields($entityName);
foreach ($DAOFields as $DAOField) {
- if (array_key_exists('contactType', $DAOField) && $spec->getValue('contact_type') && $DAOField['contactType'] != $spec->getValue('contact_type')) {
+ if (isset($DAOField['contactType']) && $spec->getValue('contact_type') && $DAOField['contactType'] !== $spec->getValue('contact_type')) {
continue;
}
if (!empty($DAOField['component']) && !\CRM_Core_Component::isEnabled($DAOField['component'])) {
continue;
}
- if ($DAOField['name'] == 'is_active' && empty($DAOField['default'])) {
- $DAOField['default'] = '1';
- }
$this->setDynamicFk($DAOField, $values);
$field = SpecFormatter::arrayToField($DAOField, $entityName);
$spec->addFieldSpec($field);
@@ -146,13 +143,24 @@ private function setDynamicFk(array &$DAOField, array $values): void {
* @see \CRM_Core_SelectValues::customGroupExtends
*/
private function addCustomFields(string $entity, RequestSpec $spec, bool $checkPermissions) {
+ $values = $spec->getValues();
+
+ // Handle contact type pseudo-entities
+ $contactTypes = \CRM_Contact_BAO_ContactType::basicTypes();
+ // If contact type is given
+ if ($entity === 'Contact' && !empty($values['contact_type'])) {
+ $entity = $values['contact_type'];
+ }
+
$customInfo = \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends($entity);
if (!$customInfo) {
return;
}
- $values = $spec->getValues();
$extends = $customInfo['extends'];
$grouping = $customInfo['grouping'];
+ if ($entity === 'Contact' || in_array($entity, $contactTypes, TRUE)) {
+ $grouping = 'contact_sub_type';
+ }
$query = CustomField::get(FALSE)
->setSelect(['custom_group_id.name', 'custom_group_id.title', '*'])
@@ -169,17 +177,6 @@ private function addCustomFields(string $entity, RequestSpec $spec, bool $checkP
$query->addWhere('custom_group_id', 'IN', $allowedGroups);
}
- // Contact custom groups are extra complicated because contact_type can be a value for extends
- if ($entity === 'Contact') {
- if (array_key_exists('contact_type', $values)) {
- $extends = ['Contact'];
- if ($values['contact_type']) {
- $extends[] = $values['contact_type'];
- }
- }
- // Now grouping can be treated normally
- $grouping = 'contact_sub_type';
- }
if (is_string($grouping) && array_key_exists($grouping, $values)) {
if (empty($values[$grouping])) {
$query->addWhere('custom_group_id.extends_entity_column_value', 'IS EMPTY');
diff --git a/Civi/Api4/Tag.php b/Civi/Api4/Tag.php
index 67e54a9fcf93..d8dae1953f1b 100644
--- a/Civi/Api4/Tag.php
+++ b/Civi/Api4/Tag.php
@@ -22,5 +22,6 @@
* @package Civi\Api4
*/
class Tag extends Generic\DAOEntity {
+ use Generic\Traits\ManagedEntity;
}
diff --git a/Civi/Api4/Utils/CoreUtil.php b/Civi/Api4/Utils/CoreUtil.php
index 473c6ff80321..bb53f94cb4e1 100644
--- a/Civi/Api4/Utils/CoreUtil.php
+++ b/Civi/Api4/Utils/CoreUtil.php
@@ -16,10 +16,15 @@
use Civi\API\Exception\UnauthorizedException;
use Civi\API\Request;
use Civi\Api4\Generic\AbstractAction;
+use Civi\Api4\Service\Schema\SchemaMap;
use CRM_Core_DAO_AllCoreTables as AllCoreTables;
class CoreUtil {
+ public static function entityExists(string $entityName): bool {
+ return (bool) self::getInfoItem($entityName, 'name');
+ }
+
/**
* @param $entityName
*
@@ -27,11 +32,18 @@ class CoreUtil {
* The BAO name for use in static calls. Return doc block is hacked to allow
* auto-completion of static methods
*/
- public static function getBAOFromApiName($entityName) {
+ public static function getBAOFromApiName($entityName): ?string {
+ // TODO: It would be nice to just call self::getInfoItem($entityName, 'dao')
+ // but that currently causes test failures, probably due to early-bootstrap issues.
if ($entityName === 'CustomValue' || strpos($entityName, 'Custom_') === 0) {
- return 'CRM_Core_BAO_CustomValue';
+ $dao = \Civi\Api4\CustomValue::getInfo()['dao'];
+ }
+ else {
+ $dao = AllCoreTables::getFullName($entityName);
+ }
+ if (!$dao && self::isContact($entityName)) {
+ $dao = 'CRM_Contact_DAO_Contact';
}
- $dao = AllCoreTables::getFullName($entityName);
return $dao ? AllCoreTables::getBAOClassName($dao) : NULL;
}
@@ -43,16 +55,16 @@ public static function getBAOFromApiName($entityName) {
* @param $baoClassName
* @return string|null
*/
- public static function getApiNameFromBAO($baoClassName) {
+ public static function getApiNameFromBAO($baoClassName): ?string {
$briefName = AllCoreTables::getBriefName($baoClassName);
return $briefName && self::getApiClass($briefName) ? $briefName : NULL;
}
/**
- * @param $entityName
- * @return string|\Civi\Api4\Generic\AbstractEntity
+ * @param string $entityName
+ * @return string|\Civi\Api4\Generic\AbstractEntity|null
*/
- public static function getApiClass($entityName) {
+ public static function getApiClass(string $entityName): ?string {
$className = 'Civi\Api4\\' . $entityName;
if (class_exists($className)) {
return $className;
@@ -60,6 +72,13 @@ public static function getApiClass($entityName) {
return self::getInfoItem($entityName, 'class');
}
+ /**
+ * Returns TRUE if `entityName` is 'Contact', 'Individual', 'Organization' or 'Household'
+ */
+ public static function isContact(string $entityName): bool {
+ return $entityName === 'Contact' || in_array($entityName, \CRM_Contact_BAO_ContactType::basicTypes(TRUE), TRUE);
+ }
+
/**
* Get a piece of metadata about an entity
*
@@ -72,6 +91,20 @@ public static function getInfoItem(string $entityName, string $keyToReturn) {
return $provider->getEntities()[$entityName][$keyToReturn] ?? NULL;
}
+ /**
+ * Check if entity is of given type.
+ *
+ * @param string $entityName
+ * e.g. 'Contact'
+ * @param string $entityType
+ * e.g. 'SortableEntity'
+ * @return bool
+ */
+ public static function isType(string $entityName, string $entityType): bool {
+ $entityTypes = (array) self::getInfoItem($entityName, 'type');
+ return in_array($entityType, $entityTypes, TRUE);
+ }
+
/**
* Get name of unique identifier, typically "id"
* @param string $entityName
@@ -95,19 +128,19 @@ public static function getSearchFields(string $entityName): array {
*
* @param string $entityName
*
- * @return string
+ * @return string|null
*/
- public static function getTableName(string $entityName) {
+ public static function getTableName(string $entityName): ?string {
return self::getInfoItem($entityName, 'table_name');
}
/**
* Given a sql table name, return the name of the api entity.
*
- * @param $tableName
+ * @param string $tableName
* @return string|NULL
*/
- public static function getApiNameFromTableName($tableName) {
+ public static function getApiNameFromTableName($tableName): ?string {
$provider = \Civi::service('action_object_provider');
foreach ($provider->getEntities() as $entityName => $info) {
if (($info['table_name'] ?? NULL) === $tableName) {
@@ -117,10 +150,14 @@ public static function getApiNameFromTableName($tableName) {
return NULL;
}
+ public static function getCustomGroupName(string $entityName): ?string {
+ return str_starts_with($entityName, 'Custom_') ? substr($entityName, 7) : NULL;
+ }
+
/**
* @return string[]
*/
- public static function getOperators() {
+ public static function getOperators(): array {
$operators = \CRM_Core_DAO::acceptedSQLOperators();
$operators[] = 'CONTAINS';
$operators[] = 'NOT CONTAINS';
@@ -128,21 +165,34 @@ public static function getOperators() {
$operators[] = 'IS NOT EMPTY';
$operators[] = 'REGEXP';
$operators[] = 'NOT REGEXP';
+ $operators[] = 'REGEXP BINARY';
+ $operators[] = 'NOT REGEXP BINARY';
return $operators;
}
/**
* For a given API Entity, return the types of custom fields it supports and the column they join to.
*
+ * Sort of the inverse of this function:
+ * @see \CRM_Core_BAO_CustomGroup::getEntityForGroup
+ *
* @param string $entityName
* @return array{extends: array, column: string, grouping: mixed}|null
*/
- public static function getCustomGroupExtends(string $entityName) {
+ public static function getCustomGroupExtends(string $entityName): ?array {
+ $contactTypes = \CRM_Contact_BAO_ContactType::basicTypes();
// Custom_group.extends pretty much maps 1-1 with entity names, except for Contact.
+ if (in_array($entityName, $contactTypes, TRUE)) {
+ return [
+ 'extends' => ['Contact', $entityName],
+ 'column' => 'id',
+ 'grouping' => ['contact_type', 'contact_sub_type'],
+ ];
+ }
switch ($entityName) {
case 'Contact':
return [
- 'extends' => array_merge(['Contact'], array_keys(\CRM_Core_SelectValues::contactType())),
+ 'extends' => array_merge(['Contact'], $contactTypes),
'column' => 'id',
'grouping' => ['contact_type', 'contact_sub_type'],
];
@@ -173,7 +223,7 @@ public static function getCustomGroupExtends(string $entityName) {
* @return bool
* @throws \CRM_Core_Exception
*/
- public static function isCustomEntity($customGroupName) {
+ public static function isCustomEntity($customGroupName): bool {
return $customGroupName && \CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $customGroupName, 'is_multiple', 'name');
}
@@ -184,10 +234,10 @@ public static function isCustomEntity($customGroupName) {
* @param array $record
* @param int|null $userID
* Contact ID of the user we are testing, 0 for the anonymous user.
- * @return bool
+ * @return bool|null
* @throws \CRM_Core_Exception
*/
- public static function checkAccessRecord(AbstractAction $apiRequest, array $record, int $userID = NULL) {
+ public static function checkAccessRecord(AbstractAction $apiRequest, array $record, int $userID = NULL): ?bool {
$userID = $userID ?? \CRM_Core_Session::getLoggedInContactID() ?? 0;
// Super-admins always have access to everything
@@ -250,7 +300,7 @@ public static function checkAccessDelegated(string $entityName, string $actionNa
/**
* @return \Civi\Api4\Service\Schema\SchemaMap
*/
- public static function getSchemaMap() {
+ public static function getSchemaMap(): SchemaMap {
$cache = \Civi::cache('metadata');
$schemaMap = $cache->get('api4.schema.map');
if (!$schemaMap) {
@@ -269,7 +319,7 @@ public static function getSchemaMap() {
* @return array{name: string, type: string, count: int, table: string|null, key: string|null}[]
* @throws NotImplementedException
*/
- public static function getRefCount(string $entityName, $entityId) {
+ public static function getRefCount(string $entityName, $entityId): array {
$daoName = self::getInfoItem($entityName, 'dao');
if (!$daoName) {
throw new NotImplementedException("Cannot getRefCount for $entityName - dao not found.");
@@ -430,4 +480,14 @@ public static function topSortFields(array &$fields): void {
}
}
+ /**
+ * Strips leading namespace from a classname
+ * @param string $className
+ * @return string
+ */
+ public static function stripNamespace(string $className): string {
+ $slashPos = strrpos($className, '\\');
+ return $slashPos === FALSE ? $className : substr($className, $slashPos + 1);
+ }
+
}
diff --git a/Civi/Api4/Utils/FormattingUtil.php b/Civi/Api4/Utils/FormattingUtil.php
index e05f3bd7f5bf..ba93b4a27875 100644
--- a/Civi/Api4/Utils/FormattingUtil.php
+++ b/Civi/Api4/Utils/FormattingUtil.php
@@ -401,9 +401,16 @@ public static function convertDataType($value, $dataType) {
case 'Float':
return (float) $value;
+ case 'Timestamp':
case 'Date':
+ // Convert mysql-style default to api-style default
+ if (str_contains($value, 'CURRENT_TIMESTAMP')) {
+ return 'now';
+ }
// Strip time from date-only fields
- return substr($value, 0, 10);
+ if ($dataType === 'Date' && $value) {
+ return substr($value, 0, 10);
+ }
}
}
return $value;
diff --git a/Civi/Api4/Utils/ReflectionUtils.php b/Civi/Api4/Utils/ReflectionUtils.php
index cc9b78d18912..446d06462111 100644
--- a/Civi/Api4/Utils/ReflectionUtils.php
+++ b/Civi/Api4/Utils/ReflectionUtils.php
@@ -206,7 +206,7 @@ public static function findMethodHelpers($class, string $prefix): iterable {
yield from [];
foreach ($clazz->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
- if (\CRM_Utils_String::startsWith($m->getName(), $prefix)) {
+ if (str_starts_with($m->getName(), $prefix)) {
yield $m;
}
}
diff --git a/Civi/Core/Format.php b/Civi/Core/Format.php
index d7041e00ef97..653186887145 100644
--- a/Civi/Core/Format.php
+++ b/Civi/Core/Format.php
@@ -44,10 +44,6 @@ public function money($amount, ?string $currency = NULL, ?string $locale = NULL)
if (!$currency) {
$currency = Civi::settings()->get('defaultCurrency');
}
- if (!isset($locale)) {
- global $civicrmLocale;
- $locale = $civicrmLocale->moneyFormat ?? (Civi::settings()->get('format_locale') ?? CRM_Core_I18n::getLocale());
- }
$currencyObject = CRM_Utils_Money::getCurrencyObject($currency);
$money = Money::of($amount, $currencyObject, NULL, RoundingMode::HALF_UP);
$formatter = $this->getMoneyFormatter($currency, $locale);
@@ -92,7 +88,7 @@ public function number($amount, ?string $locale = NULL, array $attributes = [
* @noinspection PhpDocMissingThrowsInspection
* @noinspection PhpUnhandledExceptionInspection
*/
- public function moneyNumber($amount, string $currency, $locale): string {
+ public function moneyNumber($amount, string $currency, $locale = NULL): string {
if (($amount = $this->checkAndConvertAmount($amount)) === '') {
return '';
}
@@ -195,9 +191,7 @@ protected function isUseSeparatorSettings(): bool {
}
/**
- * Get the money formatter for when we are using configured thousand separators.
- *
- * Our intent is to phase out these settings in favour of deriving them from the locale.
+ * Get the cached money formatter.
*
* @param string|null $currency
* @param string|null $locale
@@ -215,7 +209,10 @@ public function getMoneyFormatter(?string $currency = NULL, ?string $locale = NU
if (!$currency) {
$currency = Civi::settings()->get('defaultCurrency');
}
- $locale = $locale ?: \Civi\Core\Locale::detect()->moneyFormat;
+ if (!isset($locale)) {
+ global $civicrmLocale;
+ $locale = $civicrmLocale->moneyFormat ?? (Civi::settings()->get('format_locale') ?? CRM_Core_I18n::getLocale());
+ }
$cacheKey = __CLASS__ . $currency . '_' . $locale . '_' . $style . (!empty($attributes) ? md5(json_encode($attributes)) : '');
if (!isset(\Civi::$statics[$cacheKey])) {
diff --git a/Civi/Core/SettingsManager.php b/Civi/Core/SettingsManager.php
index feb3f86f66d1..6bf667c05cb3 100644
--- a/Civi/Core/SettingsManager.php
+++ b/Civi/Core/SettingsManager.php
@@ -239,7 +239,7 @@ protected function getDefaults($entity) {
*/
protected function getMandatory($entity) {
if ($this->mandatory === NULL) {
- $this->mandatory = self::parseMandatorySettings(\CRM_Utils_Array::value('civicrm_setting', $GLOBALS));
+ $this->mandatory = self::parseMandatorySettings($GLOBALS['civicrm_setting'] ?? NULL);
}
return $this->mandatory[$entity];
}
diff --git a/Civi/Core/SettingsMetadata.php b/Civi/Core/SettingsMetadata.php
index 00b8f034f0eb..4f31a8a53b3d 100644
--- a/Civi/Core/SettingsMetadata.php
+++ b/Civi/Core/SettingsMetadata.php
@@ -155,7 +155,7 @@ protected static function fillOptions(&$settingSpec, $optionsFormat) {
// but it's tightly coupled to DAO/field. However, if you really need to support
// more pseudoconstant types, then probably best to refactor it. For now, KISS.
if (!empty($pseudoconstant['optionGroupName'])) {
- $keyColumn = \CRM_Utils_Array::value('keyColumn', $pseudoconstant, 'value');
+ $keyColumn = $pseudoconstant['keyColumn'] ?? 'value';
if (is_array($optionsFormat)) {
$optionValues = \CRM_Core_OptionValue::getValues(['name' => $pseudoconstant['optionGroupName']]);
foreach ($optionValues as $option) {
diff --git a/Civi/Managed/MultisiteManaged.php b/Civi/Managed/MultisiteManaged.php
new file mode 100644
index 000000000000..12e8dd8f6d97
--- /dev/null
+++ b/Civi/Managed/MultisiteManaged.php
@@ -0,0 +1,107 @@
+ ['generateDomainEntities', -1000],
+ ];
+ }
+
+ /**
+ * @implements \CRM_Utils_Hook::managed()
+ * @param array $managedRecords
+ */
+ public function generateDomainEntities(array &$managedRecords): void {
+ $multisiteEnabled = Setting::get(FALSE)
+ ->addSelect('is_enabled')
+ ->execute()->first();
+ if (empty($multisiteEnabled['value'])) {
+ return;
+ }
+
+ // array_splice needs array keys to be orderly
+ $managedRecords = array_values($managedRecords);
+ // Replace every single-domain record with one record per domain
+ // Walk the array in reverse order so the keys being processed remain stable even as the length changes.
+ foreach (array_reverse(array_keys($managedRecords)) as $index) {
+ if ($this->isCopiable($managedRecords[$index])) {
+ array_splice($managedRecords, $index, 1, $this->makeCopies($managedRecords[$index]));
+ }
+ }
+ }
+
+ protected function makeCopies(array $managedRecord): array {
+ $copies = [];
+ foreach ($this->getDomains() as $index => $domainId) {
+ $copy = $managedRecord;
+ // For a smoother transition between enabling/disabling multisite, don't rename the first copy
+ if ($index) {
+ $copy['name'] .= '_' . $domainId;
+ }
+ $copy['params']['values']['domain_id'] = $domainId;
+ $copies[] = $copy;
+ }
+ return $copies;
+ }
+
+ /**
+ * Check if a managed record is an APIv4 Entity that should exist on all domains.
+ *
+ * Follows the same logic for determining an entity belongs on multiple domains as `FieldDomainIdSpecProvider`
+ * @see \Civi\Api4\Service\Spec\Provider\FieldDomainIdSpecProvider
+ *
+ * @param array $managedRecord
+ * @return bool
+ */
+ protected function isCopiable(array $managedRecord): bool {
+ if ($managedRecord['params']['version'] != 4) {
+ return FALSE;
+ }
+ // Extra guard so that clever extensions (which multiply entities themselves) don't get entities-squared.
+ if (is_numeric($managedRecord['params']['values']['domain_id'] ?? NULL) || !empty($managedRecord['params']['values']['domain_id.name'])) {
+ \CRM_Core_Error::deprecatedWarning(sprintf('Module "%s" has self-multiplied managed entity "%s" across domains. This is deprecated.', $managedRecord['module'], $managedRecord['name']));
+ return FALSE;
+ }
+ if (!isset($this->entities[$managedRecord['entity']])) {
+ try {
+ $this->entities[$managedRecord['entity']] = (bool) civicrm_api4($managedRecord['entity'], 'getFields', [
+ 'checkPermissions' => FALSE,
+ 'action' => 'create',
+ 'where' => [
+ ['name', '=', 'domain_id'],
+ ['default_value', '=', 'current_domain'],
+ ],
+ ])->count();
+ }
+ catch (\CRM_Core_Exception $e) {
+ $this->entities[$managedRecord['entity']] = FALSE;
+ }
+ }
+ return $this->entities[$managedRecord['entity']];
+ }
+
+ private function getDomains(): array {
+ if (!isset($this->domains)) {
+ $this->domains = Domain::get(FALSE)->addSelect('id')->addOrderBy('id')->execute()->column('id');
+ }
+ return $this->domains;
+ }
+
+}
diff --git a/Civi/Test.php b/Civi/Test.php
index f5e09b274008..5968f86031c6 100644
--- a/Civi/Test.php
+++ b/Civi/Test.php
@@ -125,7 +125,7 @@ public static function headless() {
->callback(function ($ctx) {
\Civi\Test::data()->populate();
}, 'populate');
- $builder->install(['org.civicrm.search_kit']);
+ $builder->install(['org.civicrm.search_kit', 'org.civicrm.afform', 'authx']);
return $builder;
}
diff --git a/Civi/Test/Api3TestTrait.php b/Civi/Test/Api3TestTrait.php
index d12f912bdb21..d68b04de1175 100644
--- a/Civi/Test/Api3TestTrait.php
+++ b/Civi/Test/Api3TestTrait.php
@@ -125,7 +125,7 @@ public function assertAPISuccess($apiResult, $prefix = '') {
* @param null $extraOutput
* @return array|int
*/
- public function callAPIFailure($entity, $action, $params, $expectedErrorMessage = NULL, $extraOutput = NULL) {
+ public function callAPIFailure($entity, $action, $params = [], $expectedErrorMessage = NULL, $extraOutput = NULL) {
if (is_array($params)) {
$params += [
'version' => $this->_apiversion,
diff --git a/Civi/Test/Api4TestTrait.php b/Civi/Test/Api4TestTrait.php
index b78e81c7b298..80ae3c6ecfc7 100644
--- a/Civi/Test/Api4TestTrait.php
+++ b/Civi/Test/Api4TestTrait.php
@@ -130,9 +130,9 @@ protected function getRequiredValuesToCreate(string $entity, array $values = [])
foreach ($requiredFields as $fieldName => $field) {
if (
!isset($values[$fieldName]) &&
- ($field['required'] || AbstractAction::evaluateCondition($field['required_if'], $values + $extraValues))
+ ($field['required'] || AbstractAction::evaluateCondition($field['required_if'], ['values' => $values + $extraValues]))
) {
- $extraValues[$fieldName] = $this->getRequiredValue($field, $requiredFields);
+ $extraValues[$fieldName] = $this->getRequiredValue($field);
}
}
diff --git a/Civi/Test/ContributionPageTestTrait.php b/Civi/Test/ContributionPageTestTrait.php
new file mode 100644
index 000000000000..d20bc0863fb2
--- /dev/null
+++ b/Civi/Test/ContributionPageTestTrait.php
@@ -0,0 +1,113 @@
+ 'Test Frontend title',
+ 'title' => 'Page Title',
+ 'name' => 'default_page',
+ 'financial_type_id:name' => 'Donation',
+ 'is_email_receipt' => TRUE,
+ 'is_pay_later' => $contributionPageValues['is_monetary'] ?: FALSE,
+ 'pay_later_text' => 'Send Money Now',
+ ];
+ $contributionPageValues += $contributionPageDefaults;
+ return $this->createTestEntity('ContributionPage', $contributionPageValues, $identifier);
+ }
+
+ /**
+ * @param array $contributionPageValues
+ * @param array $priceSetParameters
+ * Currently if 'id' is passed in then no update is made, but this could change
+ * @param string $identifier
+ *
+ * @return array
+ */
+ public function contributionPageCreatePaid(array $contributionPageValues, array $priceSetParameters = [], string $identifier = 'ContributionPage'): array {
+ $contributionPageValues['is_monetary'] = TRUE;
+ $contributionPageResult = $this->contributionPageCreate($contributionPageValues, $identifier);
+ $priceSetParameters += [
+ 'title' => 'Price Set',
+ 'is_quick_config' => TRUE,
+ 'extends' => 'CiviContribute',
+ 'financial_type_id:name' => 'Donation',
+ 'name' => $identifier,
+ ];
+ if (empty($priceSetParameters['id'])) {
+ $this->createTestEntity('PriceSet', $priceSetParameters, $identifier);
+ }
+ else {
+ $this->ids['PriceSet'][$identifier] = $priceSetParameters['id'];
+ // Maybe do update here??
+ }
+ $this->createTestEntity('PriceSetEntity', [
+ 'entity_table' => 'civicrm_contribution_page',
+ 'entity_id' => $contributionPageResult['id'],
+ 'price_set_id' => $this->ids['PriceSet'][$identifier],
+ ]);
+ return $contributionPageResult;
+ }
+
+ /**
+ * Get the id of the contribution page created in set up.
+ *
+ * If only one has been created it will be selected. Otherwise
+ * you should pass in the appropriate identifier.
+ *
+ * @param string $identifier
+ *
+ * @return int
+ */
+ protected function getContributionPageID(string $identifier = 'ContributionPage'): int {
+ if (isset($this->ids['ContributionPage'][$identifier])) {
+ return $this->ids['ContributionPage'][$identifier];
+ }
+ if (count($this->ids['ContributionPage']) === 1) {
+ return reset($this->ids['ContributionPage']);
+ }
+ $this->fail('Could not identify ContributionPage ID');
+ // Unreachable but reduces IDE noise.
+ return 0;
+ }
+
+}
diff --git a/Civi/Test/EventTestTrait.php b/Civi/Test/EventTestTrait.php
index c494e9470752..61629d21d5f5 100644
--- a/Civi/Test/EventTestTrait.php
+++ b/Civi/Test/EventTestTrait.php
@@ -22,10 +22,6 @@
/**
* Helper for event tests.
*
- * WARNING - this trait ships with core from 5.63 but I wasn't able to resolve
- * all the core tests onto it for 5.63 - hence the signatures may not yet be stable
- * and it is worth assuming that they will not be stable until 5.65.
- *
* This provides functions to set up valid events
* for unit tests.
*
diff --git a/Civi/Test/FormTrait.php b/Civi/Test/FormTrait.php
index 799a586a2b9c..a194768c1563 100644
--- a/Civi/Test/FormTrait.php
+++ b/Civi/Test/FormTrait.php
@@ -19,6 +19,11 @@
*/
trait FormTrait {
+ /**
+ * @var \Civi\Test\FormWrapper
+ */
+ private $form;
+
/**
* @param $formName
* @param $submittedValues
@@ -27,13 +32,65 @@ trait FormTrait {
* @return \Civi\Test\FormWrapper
*/
public function getTestForm($formName, $submittedValues, array $urlParameters = []) {
+ $this->form = NULL;
if ($formName === 'CRM_Event_Form_Participant') {
- return new EventFormParticipant($formName, $submittedValues, $urlParameters);
+ $this->form = new EventFormParticipant($formName, $submittedValues, $urlParameters);
}
if ($formName === 'CRM_Event_Form_Registration_Register') {
- return new EventFormOnline($formName, $submittedValues, $urlParameters);
+ $this->form = new EventFormOnline($formName, $submittedValues, $urlParameters);
+ }
+ if (!$this->form) {
+ $this->form = new FormWrapper($formName, $submittedValues, $urlParameters);
+ }
+ return $this->form;
+ }
+
+ /**
+ * Assert that the sent mail included the supplied strings.
+ *
+ * @param array $strings
+ * @param int $mailIndex
+ */
+ protected function assertMailSentContainingStrings(array $strings, int $mailIndex = 0): void {
+ foreach ($strings as $string) {
+ $this->assertMailSentContainingString($string, $mailIndex);
}
- return new FormWrapper($formName, $submittedValues, $urlParameters);
+ }
+
+ /**
+ * Assert that the sent mail included the supplied string.
+ *
+ * @param string $string
+ * @param int $mailIndex
+ */
+ protected function assertMailSentContainingString(string $string, int $mailIndex = 0): void {
+ $mail = $this->form->getMail()[$mailIndex];
+ $this->assertStringContainsString($string, $mail['body']);
+ }
+
+ /**
+ * Assert that the sent mail included the supplied strings.
+ *
+ * @param array $recipients
+ * @param int $mailIndex
+ */
+ protected function assertMailSentTo(array $recipients, int $mailIndex = 0): void {
+ $mail = $this->form->getMail()[$mailIndex];
+ foreach ($recipients as $string) {
+ $this->assertStringContainsString($string, $mail['headers']);
+ }
+ }
+
+ /**
+ * Retrieve a deprecated property, ensuring a deprecation notice is thrown.
+ *
+ * @param string $property
+ *
+ * @return mixed
+ * @throws \CRM_Core_Exception
+ */
+ protected function getDeprecatedProperty(string $property) {
+ return $this->form->getDeprecatedProperty($property);
}
}
diff --git a/Civi/Test/FormWrapper.php b/Civi/Test/FormWrapper.php
index 737ebb9389dd..e20b031061e8 100644
--- a/Civi/Test/FormWrapper.php
+++ b/Civi/Test/FormWrapper.php
@@ -50,10 +50,26 @@ public function getFirstMail(): array {
return $this->mail ? (array) reset($this->mail) : [];
}
+ /**
+ * Get the number of emails sent.
+ *
+ * @return int
+ */
+ public function getMailCount(): int {
+ return count((array) $this->mail);
+ }
+
public function getFirstMailBody() : string {
return $this->getFirstMail()['body'] ?? '';
}
+ /**
+ * @return array
+ */
+ public function getTemplateVariables(): array {
+ return $this->templateVariables;
+ }
+
private $redirects;
private $mailSpoolID;
@@ -103,6 +119,7 @@ public function processForm(int $state = self::SUBMITTED): self {
if ($state > self::VALIDATED) {
$this->postProcess();
}
+ $this->templateVariables = $this->form->get_template_vars();
return $this;
}
@@ -182,7 +199,7 @@ private function setFormObject(string $class, array $formValues = [], array $url
$_POST = $formValues;
$this->form = new $class();
$_SERVER['REQUEST_METHOD'] = 'GET';
- $_REQUEST += $urlParameters;
+ $_REQUEST = array_merge($_REQUEST, $urlParameters);
switch ($class) {
case 'CRM_Event_Cart_Form_Checkout_Payment':
case 'CRM_Event_Cart_Form_Checkout_ParticipantsAndPrices':
@@ -339,4 +356,25 @@ private function stopTrackingMail(): void {
\Civi::settings()->set('mailing_backend', $this->originalMailSetting);
}
+ /**
+ * Retrieve a deprecated property, ensuring a deprecation notice is thrown.
+ *
+ * @param string $property
+ *
+ * @return mixed
+ * @throws \CRM_Core_Exception
+ */
+ public function getDeprecatedProperty(string $property) {
+ try {
+ $this->form->$property;
+ }
+ catch (\Exception $e) {
+ $oldErrorLevel = error_reporting(0);
+ $value = $this->form->$property;
+ error_reporting($oldErrorLevel);
+ return $value;
+ }
+ throw new \CRM_Core_Exception('Deprecation should have been triggered');
+ }
+
}
diff --git a/Civi/Test/HttpTestTrait.php b/Civi/Test/HttpTestTrait.php
index e3384ecbec2a..e74ccd424192 100644
--- a/Civi/Test/HttpTestTrait.php
+++ b/Civi/Test/HttpTestTrait.php
@@ -75,7 +75,7 @@ protected function createGuzzle($options = []) {
* @return mixed
*/
protected function callApi4AjaxSuccess(string $entity, string $action, $params = []) {
- $method = \CRM_Utils_String::startsWith($action, 'get') ? 'GET' : 'POST';
+ $method = str_starts_with($action, 'get') ? 'GET' : 'POST';
$response = $this->createGuzzle()->request($method, "civicrm/ajax/api4/$entity/$action", [
'headers' => ['X-Requested-With' => 'XMLHttpRequest'],
// This should probably be 'form_params', but 'query' is more representative of frontend.
@@ -99,7 +99,7 @@ protected function callApi4AjaxSuccess(string $entity, string $action, $params =
* @return mixed
*/
protected function callApi4AjaxError(string $entity, string $action, $params = []) {
- $method = \CRM_Utils_String::startsWith($action, 'get') ? 'GET' : 'POST';
+ $method = str_starts_with($action, 'get') ? 'GET' : 'POST';
$response = $this->createGuzzle()->request($method, "civicrm/ajax/api4/$entity/$action", [
'headers' => ['X-Requested-With' => 'XMLHttpRequest'],
// This should probably be 'form_params', but 'query' is more representative of frontend.
diff --git a/Civi/Token/TokenRow.php b/Civi/Token/TokenRow.php
index 0379febff258..953154a2fc97 100644
--- a/Civi/Token/TokenRow.php
+++ b/Civi/Token/TokenRow.php
@@ -187,7 +187,7 @@ public function customToken($entity, $customFieldID, $entityID) {
'return' => $customFieldName,
'id' => $entityID,
]);
- $fieldValue = \CRM_Utils_Array::value($customFieldName, $record, '');
+ $fieldValue = $record[$customFieldName] ?? '';
$originalValue = $fieldValue;
// format the raw custom field value into proper display value
if (isset($fieldValue)) {
@@ -281,7 +281,7 @@ public function fill($format = NULL) {
if ($entity == 'activity' && $field == 'details') {
$htmlTokens[$entity][$field] = $value;
}
- elseif (\CRM_Utils_Array::value('data_type', \CRM_Utils_Array::value($field, $entityFields['values'])) == 'Memo') {
+ elseif (($entityFields['values'][$field]['data_type'] ?? NULL) === 'Memo') {
// Memo fields aka custom fields of type Note are html.
$htmlTokens[$entity][$field] = \CRM_Utils_String::purifyHTML($value);
}
diff --git a/Civi/WorkflowMessage/Traits/CustomFieldTrait.php b/Civi/WorkflowMessage/Traits/CustomFieldTrait.php
new file mode 100644
index 000000000000..af794d492d81
--- /dev/null
+++ b/Civi/WorkflowMessage/Traits/CustomFieldTrait.php
@@ -0,0 +1,67 @@
+getFilteredCustomFields($entity, $filters);
+
+ $fields = [];
+ foreach ($viewableFields as $fieldSpec) {
+ $fieldName = $fieldSpec['custom_group_id.name'] . '.' . $fieldSpec['name'];
+ $value = str_replace(' ', '', \CRM_Core_BAO_CustomField::displayValue($entityRecord[$fieldName], $fieldSpec['id'], $entityRecord['id']));
+ // I can't see evidence we have filtered out empty strings here historically
+ // but maybe we should?
+ $fields[$fieldSpec['custom_group_id.title']][$fieldSpec['label']] = $value;
+ }
+ return $fields;
+ }
+
+}
diff --git a/ang/afform/afsearchNoteComments.aff.html b/ang/afform/afsearchNoteComments.aff.html
new file mode 100644
index 000000000000..69d333efcae2
--- /dev/null
+++ b/ang/afform/afsearchNoteComments.aff.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/ang/afform/afsearchNoteComments.aff.php b/ang/afform/afsearchNoteComments.aff.php
new file mode 100644
index 000000000000..eb4788c32c1e
--- /dev/null
+++ b/ang/afform/afsearchNoteComments.aff.php
@@ -0,0 +1,13 @@
+ 'search',
+ 'title' => ts('Comments'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/contact/view/note/comments',
+ 'permission' => [
+ 'access CiviCRM',
+ 'view all notes',
+ ],
+ 'permission_operator' => 'OR',
+];
diff --git a/ang/afform/afsearchTabNote.aff.html b/ang/afform/afsearchTabNote.aff.html
new file mode 100644
index 000000000000..626cea7f6b1b
--- /dev/null
+++ b/ang/afform/afsearchTabNote.aff.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/ang/afform/afsearchTabNote.aff.php b/ang/afform/afsearchTabNote.aff.php
new file mode 100644
index 000000000000..c2a99ba08fd5
--- /dev/null
+++ b/ang/afform/afsearchTabNote.aff.php
@@ -0,0 +1,16 @@
+ 'search',
+ 'title' => ts('Notes'),
+ 'description' => '',
+ 'placement' => ['contact_summary_tab'],
+ 'summary_weight' => 100,
+ 'icon' => 'fa-sticky-note-o',
+ 'summary_contact_type' => NULL,
+ 'permission' => [
+ 'access CiviCRM',
+ ],
+ 'permission_operator' => 'AND',
+ 'navigation' => NULL,
+];
diff --git a/ang/afform/afsearchTabRel.aff.html b/ang/afform/afsearchTabRel.aff.html
new file mode 100644
index 000000000000..07fb4f4622d0
--- /dev/null
+++ b/ang/afform/afsearchTabRel.aff.html
@@ -0,0 +1,9 @@
+
+
+ {{:: ts('Permissioned Relationships:') }}
+ {{:: ts('This contact can be viewed by the other.') }}
+ {{:: ts('This contact can be viewed and edited by the other.') }}
+
+
+
+
diff --git a/ang/afform/afsearchTabRel.aff.php b/ang/afform/afsearchTabRel.aff.php
new file mode 100644
index 000000000000..43af4f00df36
--- /dev/null
+++ b/ang/afform/afsearchTabRel.aff.php
@@ -0,0 +1,13 @@
+ 'search',
+ 'title' => ts('Relationships'),
+ 'permission' => [
+ 'access CiviCRM',
+ ],
+ 'placement' => ['contact_summary_tab'],
+ 'icon' => 'fa-handshake-o',
+ 'summary_weight' => 80,
+ 'permission_operator' => 'AND',
+];
diff --git a/ang/crmMailing/EditUnsubGroupCtrl.js b/ang/crmMailing/EditUnsubGroupCtrl.js
index 56070e03e644..587e0faeee4d 100644
--- a/ang/crmMailing/EditUnsubGroupCtrl.js
+++ b/ang/crmMailing/EditUnsubGroupCtrl.js
@@ -1,10 +1,12 @@
(function(angular, $, _) {
- angular.module('crmMailing').controller('EditUnsubGroupCtrl', function EditUnsubGroupCtrl($scope) {
+ angular.module('crmMailing').controller('EditUnsubGroupCtrl', function EditUnsubGroupCtrl($scope, crmMailingLoader) {
// CRM.crmMailing.groupNames is a global constant - since it doesn't change, we can digest & cache.
var mandatoryIds = [];
$scope.isUnsubGroupRequired = function isUnsubGroupRequired(mailing) {
+ crmMailingLoader.getGroupNames(mailing);
+
if (!_.isEmpty(CRM.crmMailing.groupNames)) {
_.each(CRM.crmMailing.groupNames, function(grp) {
if (grp.is_hidden == "1") {
diff --git a/ang/crmMailing/ViewRecipCtrl.js b/ang/crmMailing/ViewRecipCtrl.js
index 5d137ce6038f..05f546351239 100644
--- a/ang/crmMailing/ViewRecipCtrl.js
+++ b/ang/crmMailing/ViewRecipCtrl.js
@@ -1,81 +1,12 @@
(function(angular, $, _) {
- angular.module('crmMailing').controller('ViewRecipCtrl', function ViewRecipCtrl($scope) {
- var mids = [];
- var gids = [];
- var groupNames = [];
- var mailings = [];
- var civimailings = [];
- var civimails = [];
-
- function getGroupNames(mailing) {
- if (-1 == mailings.indexOf(mailing.id)) {
- mailings.push(mailing.id);
- _.each(mailing.recipients.groups.include, function(id) {
- if (-1 == gids.indexOf(id)) {
- gids.push(id);
- }
- });
- _.each(mailing.recipients.groups.exclude, function(id) {
- if (-1 == gids.indexOf(id)) {
- gids.push(id);
- }
- });
- _.each(mailing.recipients.groups.base, function(id) {
- if (-1 == gids.indexOf(id)) {
- gids.push(id);
- }
- });
- if (!_.isEmpty(gids)) {
- CRM.api3('Group', 'get', {'id': {"IN": gids}}).then(function(result) {
- _.each(result.values, function(grp) {
- if (_.isEmpty(_.where(groupNames, {id: parseInt(grp.id)}))) {
- groupNames.push({id: parseInt(grp.id), title: grp.title, is_hidden: grp.is_hidden});
- }
- });
- CRM.crmMailing.groupNames = groupNames;
- $scope.$parent.crmMailingConst.groupNames = groupNames;
- });
- }
- }
- }
-
- function getCiviMails(mailing) {
- if (-1 == civimailings.indexOf(mailing.id)) {
- civimailings.push(mailing.id);
- _.each(mailing.recipients.mailings.include, function(id) {
- if (-1 == mids.indexOf(id)) {
- mids.push(id);
- }
- });
- _.each(mailing.recipients.mailings.exclude, function(id) {
- if (-1 == mids.indexOf(id)) {
- mids.push(id);
- }
- });
- if (!_.isEmpty(mids)) {
- CRM.api3('Mailing', 'get', {'id': {"IN": mids}}).then(function(result) {
- _.each(result.values, function(mail) {
- if (_.isEmpty(_.where(civimails, {id: parseInt(mail.id)}))) {
- civimails.push({id: parseInt(mail.id), name: mail.name});
- }
- });
- CRM.crmMailing.civiMails = civimails;
- $scope.$parent.crmMailingConst.civiMails = civimails;
- });
- }
- }
- }
+ angular.module('crmMailing').controller('ViewRecipCtrl', function ViewRecipCtrl($scope, crmMailingLoader) {
$scope.getIncludesAsString = function(mailing) {
var first = true;
var names = '';
- if (_.isEmpty(CRM.crmMailing.groupNames)) {
- getGroupNames(mailing);
- }
- if (_.isEmpty(CRM.crmMailing.civiMails)) {
- getCiviMails(mailing);
- }
+ crmMailingLoader.getGroupNames(mailing);
+ crmMailingLoader.getCiviMails(mailing);
_.each(mailing.recipients.groups.include, function(id) {
var group = _.where(CRM.crmMailing.groupNames, {id: parseInt(id)});
if (group.length) {
diff --git a/ang/crmMailing/services.js b/ang/crmMailing/services.js
index 6db1484af5a9..f72a12712f09 100644
--- a/ang/crmMailing/services.js
+++ b/ang/crmMailing/services.js
@@ -436,6 +436,79 @@
};
});
+ // @deprecated This code was moved from ViewRecipCtrl and is quarantined in this service.
+ // It's used to fetch data that ought to be available in other ways.
+ // It would be nice to refactor it out completely.
+ angular.module('crmMailing').factory('crmMailingLoader', function ($q, crmApi, crmFromAddresses, crmQueue) {
+
+ var mids = [];
+ var gids = [];
+ var groupNames = [];
+ var mailings = [];
+ var civimailings = [];
+ var civimails = [];
+
+ return {
+ // Populates the CRM.crmMailing.groupNames global
+ getGroupNames: function(mailing) {
+ if (-1 == mailings.indexOf(mailing.id)) {
+ mailings.push(mailing.id);
+ _.each(mailing.recipients.groups.include, function(id) {
+ if (-1 == gids.indexOf(id)) {
+ gids.push(id);
+ }
+ });
+ _.each(mailing.recipients.groups.exclude, function(id) {
+ if (-1 == gids.indexOf(id)) {
+ gids.push(id);
+ }
+ });
+ _.each(mailing.recipients.groups.base, function(id) {
+ if (-1 == gids.indexOf(id)) {
+ gids.push(id);
+ }
+ });
+ if (!_.isEmpty(gids)) {
+ CRM.api3('Group', 'get', {'id': {"IN": gids}}).then(function(result) {
+ _.each(result.values, function(grp) {
+ if (_.isEmpty(_.where(groupNames, {id: parseInt(grp.id)}))) {
+ groupNames.push({id: parseInt(grp.id), title: grp.title, is_hidden: grp.is_hidden});
+ }
+ });
+ CRM.crmMailing.groupNames = groupNames;
+ });
+ }
+ }
+ },
+ // Populates the CRM.crmMailing.civiMails global
+ getCiviMails: function(mailing) {
+ if (-1 == civimailings.indexOf(mailing.id)) {
+ civimailings.push(mailing.id);
+ _.each(mailing.recipients.mailings.include, function(id) {
+ if (-1 == mids.indexOf(id)) {
+ mids.push(id);
+ }
+ });
+ _.each(mailing.recipients.mailings.exclude, function(id) {
+ if (-1 == mids.indexOf(id)) {
+ mids.push(id);
+ }
+ });
+ if (!_.isEmpty(mids)) {
+ CRM.api3('Mailing', 'get', {'id': {"IN": mids}}).then(function(result) {
+ _.each(result.values, function(mail) {
+ if (_.isEmpty(_.where(civimails, {id: parseInt(mail.id)}))) {
+ civimails.push({id: parseInt(mail.id), name: mail.name});
+ }
+ });
+ CRM.crmMailing.civiMails = civimails;
+ });
+ }
+ }
+ }
+ };
+ });
+
// The preview manager performs preview actions while putting up a visible UI (e.g. dialogs & status alerts)
angular.module('crmMailing').factory('crmMailingPreviewMgr', function (dialogService, crmMailingMgr, crmStatus) {
return {
diff --git a/api/api.php b/api/api.php
index 42ebc7e36d35..bc307f1596e4 100644
--- a/api/api.php
+++ b/api/api.php
@@ -135,7 +135,7 @@ function civicrm_api3(string $entity, string $action, array $params = []) {
$params['version'] = 3;
$result = \Civi::service('civi_api_kernel')->runSafe($entity, $action, $params);
if (is_array($result) && !empty($result['is_error'])) {
- throw new CRM_Core_Exception($result['error_message'], CRM_Utils_Array::value('error_code', $result, 'undefined'), $result);
+ throw new CRM_Core_Exception($result['error_message'], $result['error_code'] ?? 'undefined', $result);
}
return $result;
}
diff --git a/api/v3/Activity.php b/api/v3/Activity.php
index 415f59876d88..0c4f19e5b93e 100644
--- a/api/v3/Activity.php
+++ b/api/v3/Activity.php
@@ -511,7 +511,7 @@ function _civicrm_api3_activity_get_formatResult($params, $activities, $options)
if (!empty($returnProperties) || !empty($params['contact_id'])) {
foreach ($activities as $activityId => $values) {
//@todo - should possibly load activity type id if not loaded (update with id)
- _civicrm_api3_custom_data_get($activities[$activityId], CRM_Utils_Array::value('check_permissions', $params), 'Activity', $activityId, NULL, CRM_Utils_Array::value('activity_type_id', $values));
+ _civicrm_api3_custom_data_get($activities[$activityId], $params['check_permissions'] ?? NULL, 'Activity', $activityId, NULL, $values['activity_type_id'] ?? NULL);
}
}
return $activities;
diff --git a/api/v3/Attachment.php b/api/v3/Attachment.php
index 5e16486707cb..2b7f12dcca0d 100644
--- a/api/v3/Attachment.php
+++ b/api/v3/Attachment.php
@@ -207,9 +207,9 @@ function _civicrm_api3_attachment_delete_spec(&$spec) {
$spec['entity_table'] = $entityFileFields['entity_table'];
// Historically this field had no pseudoconstant and APIv3 can't handle it
$spec['entity_table']['pseudoconstant'] = NULL;
- $spec['entity_table']['title'] = CRM_Utils_Array::value('title', $spec['entity_table'], 'Entity Table') . ' (write-once)';
+ $spec['entity_table']['title'] = ($spec['entity_table']['title'] ?? 'Entity Table') . ' (write-once)';
$spec['entity_id'] = $entityFileFields['entity_id'];
- $spec['entity_id']['title'] = CRM_Utils_Array::value('title', $spec['entity_id'], 'Entity ID') . ' (write-once)';
+ $spec['entity_id']['title'] = ($spec['entity_id']['title'] ?? 'Entity ID') . ' (write-once)';
}
/**
@@ -469,10 +469,10 @@ function _civicrm_api3_attachment_getfields() {
// Historically this field had no pseudoconstant and APIv3 can't handle it
$spec['entity_table']['pseudoconstant'] = NULL;
// Would be hard to securely handle changes.
- $spec['entity_table']['title'] = CRM_Utils_Array::value('title', $spec['entity_table'], 'Entity Table') . ' (write-once)';
+ $spec['entity_table']['title'] = ($spec['entity_table']['title'] ?? 'Entity Table') . ' (write-once)';
$spec['entity_id'] = $entityFileFields['entity_id'];
// would be hard to securely handle changes
- $spec['entity_id']['title'] = CRM_Utils_Array::value('title', $spec['entity_id'], 'Entity ID') . ' (write-once)';
+ $spec['entity_id']['title'] = ($spec['entity_id']['title'] ?? 'Entity ID') . ' (write-once)';
$spec['url'] = [
'title' => 'URL (read-only)',
'description' => 'URL for downloading the file (not searchable, expire-able)',
diff --git a/api/v3/Case.php b/api/v3/Case.php
index 51f021cee6db..533ab0c90c76 100644
--- a/api/v3/Case.php
+++ b/api/v3/Case.php
@@ -571,7 +571,7 @@ function civicrm_api3_case_delete($params) {
//check parameters
civicrm_api3_verify_mandatory($params, NULL, ['id']);
- if (CRM_Case_BAO_Case::deleteCase($params['id'], CRM_Utils_Array::value('move_to_trash', $params, FALSE))) {
+ if (CRM_Case_BAO_Case::deleteCase($params['id'], $params['move_to_trash'] ?? FALSE)) {
return civicrm_api3_create_success($params, $params, 'Case', 'delete');
}
else {
diff --git a/api/v3/Contact.php b/api/v3/Contact.php
index d3e35192ef12..747b62f07e2a 100644
--- a/api/v3/Contact.php
+++ b/api/v3/Contact.php
@@ -35,7 +35,7 @@
* @throws \CRM_Core_Exception
*/
function civicrm_api3_contact_create($params) {
- $contactID = CRM_Utils_Array::value('contact_id', $params, CRM_Utils_Array::value('id', $params));
+ $contactID = CRM_Utils_Array::value('contact_id', $params, $params['id'] ?? NULL);
if ($contactID && !empty($params['check_permissions']) && !CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::EDIT)) {
throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify contact record');
@@ -55,13 +55,14 @@ function civicrm_api3_contact_create($params) {
if (!$contactID) {
// If we get here, we're ready to create a new contact
- if (($email = CRM_Utils_Array::value('email', $params)) && !is_array($params['email'])) {
+ $email = $params['email'] ?? NULL;
+ if ($email && !is_array($params['email'])) {
$defLocType = CRM_Core_BAO_LocationType::getDefault();
$params['email'] = [
1 => [
'email' => $email,
'is_primary' => 1,
- 'location_type_id' => ($defLocType->id) ? $defLocType->id : 1,
+ 'location_type_id' => $defLocType->id ?: 1,
],
];
}
@@ -471,8 +472,7 @@ function civicrm_api3_contact_delete($params) {
if ($skipUndelete && CRM_Financial_BAO_FinancialItem::checkContactPresent([$contactID], $error)) {
throw new CRM_Core_Exception($error['_qf_default']);
}
- if (CRM_Contact_BAO_Contact::deleteContact($contactID, $restore, $skipUndelete,
- CRM_Utils_Array::value('check_permissions', $params))) {
+ if (CRM_Contact_BAO_Contact::deleteContact($contactID, $restore, $skipUndelete, $params['check_permissions'] ?? FALSE)) {
return civicrm_api3_create_success();
}
throw new CRM_Core_Exception('Could not delete contact');
@@ -763,7 +763,7 @@ function civicrm_api3_contact_merge($params) {
[],
$params['mode'],
FALSE,
- CRM_Utils_Array::value('check_permissions', $params)
+ $params['check_permissions'] ?? FALSE
)) != FALSE) {
return civicrm_api3_create_success($result, $params);
@@ -1204,9 +1204,9 @@ function civicrm_api3_contact_duplicatecheck($params) {
$params['match'],
$params['match']['contact_type'],
$params['rule_type'] ?? '',
- CRM_Utils_Array::value('exclude', $params, []),
- CRM_Utils_Array::value('check_permissions', $params),
- CRM_Utils_Array::value('dedupe_rule_id', $params)
+ $params['exclude'] ?? [],
+ $params['check_permissions'] ?? FALSE,
+ $params['dedupe_rule_id'] ?? NULL
);
$values = [];
if ($dupes && !empty($params['return'])) {
diff --git a/api/v3/CustomGroup.php b/api/v3/CustomGroup.php
index 55d5f51774ed..6eaf8f60186b 100644
--- a/api/v3/CustomGroup.php
+++ b/api/v3/CustomGroup.php
@@ -16,19 +16,17 @@
*/
/**
- * Create or modify a custom field group.
+ * This entire function consists of legacy handling, probably for a form that no longer exists.
+ * APIv3 is where code like this goes to die...
*
* @param array $params
* For legacy reasons, 'extends' can be passed as an array (for setting Participant column_value)
*
* @return array
- * @todo $params['extends'] is array format - is that std compatible
*/
function civicrm_api3_custom_group_create($params) {
if (isset($params['extends']) && is_string($params['extends'])) {
- $extends = explode(",", $params['extends']);
- unset($params['extends']);
- $params['extends'] = $extends;
+ $params['extends'] = explode(',', $params['extends']);
}
if (!isset($params['id']) && (!isset($params['extends'][0]) || !trim($params['extends'][0]))) {
diff --git a/api/v3/CustomValue.php b/api/v3/CustomValue.php
index f2b7fb31945f..40feb5c6d557 100644
--- a/api/v3/CustomValue.php
+++ b/api/v3/CustomValue.php
@@ -120,7 +120,7 @@ function civicrm_api3_custom_value_get($params) {
$getParams = [
'entityID' => $params['entity_id'],
- 'entityType' => CRM_Utils_Array::value('entity_table', $params, ''),
+ 'entityType' => $params['entity_table'] ?? '',
];
if (strstr($getParams['entityType'], 'civicrm_')) {
$getParams['entityType'] = ucfirst(substr($getParams['entityType'], 8));
diff --git a/api/v3/Cxn.php b/api/v3/Cxn.php
index 8c81f3c3944e..d306d2461552 100644
--- a/api/v3/Cxn.php
+++ b/api/v3/Cxn.php
@@ -123,7 +123,7 @@ function civicrm_api3_cxn_unregister($params) {
/** @var \Civi\Cxn\Rpc\RegistrationClient $client */
$client = \Civi::service('cxn_reg_client');
- list($cxnId, $result) = $client->unregister($appMeta, CRM_Utils_Array::value('force', $params, FALSE));
+ [$cxnId, $result] = $client->unregister($appMeta, $params['force'] ?? FALSE);
return $result;
}
diff --git a/api/v3/Dedupe.php b/api/v3/Dedupe.php
index c83a3c46cc93..bc070d81706a 100644
--- a/api/v3/Dedupe.php
+++ b/api/v3/Dedupe.php
@@ -89,10 +89,10 @@ function civicrm_api3_dedupe_create($params) {
function civicrm_api3_dedupe_getstatistics($params) {
$stats = CRM_Dedupe_Merger::getMergeStats(CRM_Dedupe_Merger::getMergeCacheKeyString(
$params['rule_group_id'],
- CRM_Utils_Array::value('group_id', $params),
- CRM_Utils_Array::value('criteria', $params, []),
+ $params['group_id'] ?? NULL,
+ $params['criteria'] ?? [],
!empty($params['check_permissions']),
- CRM_Utils_Array::value('search_limit', $params, 0)
+ $params['search_limit'] ?? 0
));
return civicrm_api3_create_success($stats);
}
@@ -139,7 +139,7 @@ function _civicrm_api3_dedupe_getstatistics_spec(&$params) {
*/
function civicrm_api3_dedupe_getduplicates($params) {
$options = _civicrm_api3_get_options_from_params($params);
- $dupePairs = CRM_Dedupe_Merger::getDuplicatePairs($params['rule_group_id'], NULL, TRUE, $options['limit'], FALSE, TRUE, $params['criteria'], CRM_Utils_Array::value('check_permissions', $params), CRM_Utils_Array::value('search_limit', $params, 0), CRM_Utils_Array::value('is_force_new_search', $params));
+ $dupePairs = CRM_Dedupe_Merger::getDuplicatePairs($params['rule_group_id'], NULL, TRUE, $options['limit'], FALSE, TRUE, $params['criteria'], $params['check_permissions'] ?? FALSE, $params['search_limit'] ?? 0, $params['is_force_new_search'] ?? 0);
return civicrm_api3_create_success($dupePairs);
}
diff --git a/api/v3/EntityTag.php b/api/v3/EntityTag.php
index cfc212a32800..d50c1e35ccb2 100644
--- a/api/v3/EntityTag.php
+++ b/api/v3/EntityTag.php
@@ -123,8 +123,7 @@ function _civicrm_api3_entity_tag_common($params, $op = 'add') {
if ($op == 'add') {
$values['total_count'] = $values['added'] = $values['not_added'] = 0;
foreach ($tagIDs as $tagID) {
- list($te, $a, $na) = CRM_Core_BAO_EntityTag::addEntitiesToTag($entityIDs, $tagID, $entityTable,
- CRM_Utils_Array::value('check_permissions', $params));
+ list($te, $a, $na) = CRM_Core_BAO_EntityTag::addEntitiesToTag($entityIDs, $tagID, $entityTable, $params['check_permissions'] ?? FALSE);
$values['total_count'] += $te;
$values['added'] += $a;
$values['not_added'] += $na;
@@ -133,7 +132,7 @@ function _civicrm_api3_entity_tag_common($params, $op = 'add') {
else {
$values['total_count'] = $values['removed'] = $values['not_removed'] = 0;
foreach ($tagIDs as $tagID) {
- list($te, $r, $nr) = CRM_Core_BAO_EntityTag::removeEntitiesFromTag($entityIDs, $tagID, $entityTable, CRM_Utils_Array::value('check_permissions', $params));
+ list($te, $r, $nr) = CRM_Core_BAO_EntityTag::removeEntitiesFromTag($entityIDs, $tagID, $entityTable, $params['check_permissions'] ?? FALSE);
$values['total_count'] += $te;
$values['removed'] += $r;
$values['not_removed'] += $nr;
diff --git a/api/v3/Extension.php b/api/v3/Extension.php
index d70fb5a050e6..278161213613 100644
--- a/api/v3/Extension.php
+++ b/api/v3/Extension.php
@@ -210,6 +210,7 @@ function _civicrm_api3_extension_uninstall_spec(&$fields) {
* API result
*/
function civicrm_api3_extension_download($params) {
+ $params += ['install' => TRUE];
if (!array_key_exists('url', $params)) {
if (!CRM_Extension_System::singleton()->getBrowser()->isEnabled()) {
throw new CRM_Core_Exception('Automatic downloading is disabled. Try adding parameter "url"');
@@ -241,7 +242,7 @@ function civicrm_api3_extension_download($params) {
}
CRM_Extension_System::singleton()->getCache()->flush();
CRM_Extension_System::singleton(TRUE);
- if (CRM_Utils_Array::value('install', $params, TRUE)) {
+ if ($params['install']) {
CRM_Extension_System::singleton()->getManager()->install([$params['key']]);
}
@@ -387,7 +388,7 @@ function civicrm_api3_extension_getremote($params) {
$info = array_merge($info, (array) $obj);
$result[] = $info;
}
- return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', CRM_Utils_Array::value('return', $params, []));
+ return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', $params['return'] ?? []);
}
/**
diff --git a/api/v3/Generic.php b/api/v3/Generic.php
index 85b44c5bc3c4..46294f1067b4 100644
--- a/api/v3/Generic.php
+++ b/api/v3/Generic.php
@@ -60,11 +60,11 @@ function civicrm_api3_generic_getfields($apiRequest, $unique = TRUE) {
}
$entity = $apiRequest['entity'];
$lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity);
- $subentity = $apiRequest['params']['contact_type'] ?? NULL;
+ $subentity = $apiRequest['params']['contact_type'] ?? NULL;
$action = $apiRequest['params']['action'] ?? NULL;
$sequential = empty($apiRequest['params']['sequential']) ? 0 : 1;
- $apiRequest['params']['options'] = CRM_Utils_Array::value('options', $apiRequest['params'], []);
- $optionsToResolve = (array) CRM_Utils_Array::value('get_options', $apiRequest['params']['options'], []);
+ $apiRequest['params']['options'] = $apiRequest['params']['options'] ?? [];
+ $optionsToResolve = (array) ($apiRequest['params']['options']['get_options'] ?? []);
if (!$action || $action == 'getvalue' || $action == 'getcount') {
$action = 'get';
@@ -477,7 +477,7 @@ function _civicrm_api3_generic_getoptions_spec(&$params, $apiRequest) {
$params['field']['options'] = [];
foreach ($fields['values'] as $name => $field) {
if (isset($field['pseudoconstant']) || CRM_Utils_Array::value('type', $field) == CRM_Utils_Type::T_BOOLEAN) {
- $params['field']['options'][$name] = CRM_Utils_Array::value('title', $field, $name);
+ $params['field']['options'][$name] = $field['title'] ?? $name;
}
}
}
diff --git a/api/v3/Generic/Setvalue.php b/api/v3/Generic/Setvalue.php
index 9445a2862a55..4e1f5082efd3 100644
--- a/api/v3/Generic/Setvalue.php
+++ b/api/v3/Generic/Setvalue.php
@@ -56,7 +56,7 @@ function civicrm_api3_generic_setValue($apiRequest) {
}
$def = $fields[$fieldKey];
- $title = CRM_Utils_Array::value('title', $def, ts('Field'));
+ $title = $def['title'] ?? ts('Field');
// Disallow empty values except for the number zero.
// TODO: create a utility for this since it's needed in many places
if (!empty($def['required']) || !empty($def['is_required'])) {
diff --git a/api/v3/GroupContact.php b/api/v3/GroupContact.php
index 1233cbff6c8c..6db637d70911 100644
--- a/api/v3/GroupContact.php
+++ b/api/v3/GroupContact.php
@@ -50,7 +50,7 @@ function civicrm_api3_group_contact_get($params) {
//ie. id passed in so we have to return something
return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
}
- $status = CRM_Utils_Array::value('status', $params, 'Added');
+ $status = $params['status'] ?? 'Added';
$groupId = $params['group_id'] ?? NULL;
$values = CRM_Contact_BAO_GroupContact::getContactGroup($params['contact_id'], $status, NULL, FALSE, TRUE, FALSE, TRUE, $groupId);
@@ -217,8 +217,8 @@ function _civicrm_api3_group_contact_common($params, $op = 'Added') {
}
}
- $method = CRM_Utils_Array::value('method', $params, 'API');
- $status = CRM_Utils_Array::value('status', $params, $op);
+ $method = $params['method'] ?? 'API';
+ $status = $params['status'] ?? $op;
$tracking = $params['tracking'] ?? NULL;
if ($op == 'Added' || $op == 'Pending') {
@@ -274,9 +274,9 @@ function civicrm_api3_group_contact_update_status($params) {
CRM_Contact_BAO_GroupContact::addContactsToGroup(
[$params['contact_id']],
$params['group_id'],
- CRM_Utils_Array::value('method', $params, 'API'),
+ $params['method'] ?? 'API',
'Added',
- CRM_Utils_Array::value('tracking', $params)
+ $params['tracking'] ?? NULL
);
return TRUE;
diff --git a/api/v3/Job.php b/api/v3/Job.php
index 0303bc29ccc5..6da5a3288107 100644
--- a/api/v3/Job.php
+++ b/api/v3/Job.php
@@ -535,11 +535,10 @@ function civicrm_api3_job_process_batch_merge($params) {
'options' => ['limit' => 1],
]);
}
- $rgid = $params['rgid'] ?? NULL;
$gid = $params['gid'] ?? NULL;
- $mode = CRM_Utils_Array::value('mode', $params, 'safe');
+ $mode = $params['mode'] ?? 'safe';
- $result = CRM_Dedupe_Merger::batchMerge($rule_group_id, $gid, $mode, 1, 2, CRM_Utils_Array::value('criteria', $params, []), CRM_Utils_Array::value('check_permissions', $params), NULL, $params['search_limit']);
+ $result = CRM_Dedupe_Merger::batchMerge($rule_group_id, $gid, $mode, 1, 2, $params['criteria'] ?? [], $params['check_permissions'] ?? FALSE, NULL, $params['search_limit']);
return civicrm_api3_create_success($result, $params);
}
@@ -622,15 +621,15 @@ function civicrm_api3_job_run_payment_cron($params) {
* @return array
*/
function civicrm_api3_job_cleanup($params) {
- $session = CRM_Utils_Array::value('session', $params, TRUE);
- $tempTable = CRM_Utils_Array::value('tempTables', $params, TRUE);
- $jobLog = CRM_Utils_Array::value('jobLog', $params, TRUE);
- $expired = CRM_Utils_Array::value('expiredDbCache', $params, TRUE);
- $prevNext = CRM_Utils_Array::value('prevNext', $params, TRUE);
- $dbCache = CRM_Utils_Array::value('dbCache', $params, FALSE);
- $memCache = CRM_Utils_Array::value('memCache', $params, FALSE);
- $tplCache = CRM_Utils_Array::value('tplCache', $params, FALSE);
- $wordRplc = CRM_Utils_Array::value('wordRplc', $params, FALSE);
+ $session = $params['session'] ?? TRUE;
+ $tempTable = $params['tempTables'] ?? TRUE;
+ $jobLog = $params['jobLog'] ?? TRUE;
+ $expired = $params['expiredDbCache'] ?? TRUE;
+ $prevNext = $params['prevNext'] ?? TRUE;
+ $dbCache = $params['dbCache'] ?? FALSE;
+ $memCache = $params['memCache'] ?? FALSE;
+ $tplCache = $params['tplCache'] ?? FALSE;
+ $wordRplc = $params['wordRplc'] ?? FALSE;
if ($session || $tempTable || $prevNext || $expired) {
CRM_Core_BAO_Cache::cleanup($session, $tempTable, $prevNext, $expired);
diff --git a/api/v3/LocBlock.php b/api/v3/LocBlock.php
index b8c1a2d6c62c..84cbb2237571 100644
--- a/api/v3/LocBlock.php
+++ b/api/v3/LocBlock.php
@@ -54,7 +54,7 @@ function civicrm_api3_loc_block_create($params) {
}
// Bother calling the api.
else {
- $info['contact_id'] = CRM_Utils_Array::value('contact_id', $info, 'null');
+ $info['contact_id'] = $info['contact_id'] ?? 'null';
$result = civicrm_api3($item, 'create', $info);
$entities[$key] = $result['values'][$result['id']];
$params[$key . '_id'] = $result['id'];
diff --git a/api/v3/Logging.php b/api/v3/Logging.php
index 1401abbb1710..69d75bfc103f 100644
--- a/api/v3/Logging.php
+++ b/api/v3/Logging.php
@@ -27,7 +27,7 @@
*/
function civicrm_api3_logging_revert($params) {
$schema = new CRM_Logging_Schema();
- $reverter = new CRM_Logging_Reverter($params['log_conn_id'], CRM_Utils_Array::value('log_date', $params));
+ $reverter = new CRM_Logging_Reverter($params['log_conn_id'], $params['log_date'] ?? NULL);
$tables = !empty($params['tables']) ? (array) $params['tables'] : $schema->getLogTablesForContact();
$reverter->calculateDiffsFromLogConnAndDate($tables);
$reverter->revert();
@@ -79,7 +79,7 @@ function _civicrm_api3_logging_revert_spec(&$params) {
function civicrm_api3_logging_get($params) {
$schema = new CRM_Logging_Schema();
$interval = (empty($params['log_date'])) ? NULL : $params['interval'];
- $differ = new CRM_Logging_Differ($params['log_conn_id'], CRM_Utils_Array::value('log_date', $params), $interval);
+ $differ = new CRM_Logging_Differ($params['log_conn_id'], $params['log_date'] ?? NULL, $interval);
$tables = !empty($params['tables']) ? (array) $params['tables'] : $schema->getLogTablesForContact();
return civicrm_api3_create_success($differ->getAllChangesForConnection($tables));
}
diff --git a/api/v3/Mailing.php b/api/v3/Mailing.php
index 73f4172aee82..c26d6b02e56c 100644
--- a/api/v3/Mailing.php
+++ b/api/v3/Mailing.php
@@ -294,7 +294,7 @@ function civicrm_api3_mailing_submit($params) {
if (isset($params['approval_date'])) {
$updateParams['approval_date'] = $params['approval_date'];
$updateParams['approver_id'] = CRM_Core_Session::getLoggedInContactID();
- $updateParams['approval_status_id'] = CRM_Utils_Array::value('approval_status_id', $updateParams, CRM_Core_OptionGroup::getDefaultValue('mail_approval_status'));
+ $updateParams['approval_status_id'] = $updateParams['approval_status_id'] ?? CRM_Core_OptionGroup::getDefaultValue('mail_approval_status');
}
if (isset($params['approval_note'])) {
$updateParams['approval_note'] = $params['approval_note'];
@@ -663,8 +663,10 @@ function civicrm_api3_mailing_send_test($params) {
civicrm_api3('MailingEventQueue', 'create',
[
'job_id' => $job['id'],
+ 'is_test' => TRUE,
'email_id' => $emailId,
'contact_id' => $contactId,
+ 'mailing_id' => $params['mailing_id'],
]
);
}
diff --git a/api/v3/Membership.php b/api/v3/Membership.php
index 7cb21fee7da0..19588a01f1d1 100644
--- a/api/v3/Membership.php
+++ b/api/v3/Membership.php
@@ -95,10 +95,10 @@ function civicrm_api3_membership_create($params) {
// This is a new membership, calculate the membership dates.
$calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType(
$params['membership_type_id'],
- CRM_Utils_Array::value('join_date', $params),
- CRM_Utils_Array::value('start_date', $params),
- CRM_Utils_Array::value('end_date', $params),
- CRM_Utils_Array::value('num_terms', $params, 1)
+ $params['join_date'] ?? NULL,
+ $params['start_date'] ?? NULL,
+ $params['end_date'] ?? NULL,
+ $params['num_terms'] ?? 1
);
}
else {
@@ -108,7 +108,7 @@ function civicrm_api3_membership_create($params) {
$calcDates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType(
$params['id'],
NULL,
- CRM_Utils_Array::value('membership_type_id', $params),
+ $params['membership_type_id'] ?? NULL,
$params['num_terms']
);
}
@@ -212,7 +212,7 @@ function civicrm_api3_membership_get($params) {
$activeOnly = $params['filters']['is_current'];
unset($params['filters']['is_current']);
}
- $activeOnly = CRM_Utils_Array::value('active_only', $params, $activeOnly);
+ $activeOnly = $params['active_only'] ?? $activeOnly;
if ($activeOnly && empty($params['status_id'])) {
$params['status_id'] = ['IN' => CRM_Member_BAO_MembershipStatus::getMembershipStatusCurrent()];
}
@@ -269,7 +269,7 @@ function _civicrm_api3_membership_relationsship_get_customv2behaviour(&$params,
$membershipValues[$membershipId]['relationship_name'] = $relationshipType->name_a_b;
}
- _civicrm_api3_custom_data_get($membershipValues[$membershipId], CRM_Utils_Array::value('check_permissions', $params), 'Membership', $membershipId, NULL, $values['membership_type_id']);
+ _civicrm_api3_custom_data_get($membershipValues[$membershipId], $params['check_permissions'] ?? FALSE, 'Membership', $membershipId, NULL, $values['membership_type_id']);
}
$members = $membershipValues;
diff --git a/api/v3/MembershipStatus.php b/api/v3/MembershipStatus.php
index 064c2f7d1f7f..29d112651890 100644
--- a/api/v3/MembershipStatus.php
+++ b/api/v3/MembershipStatus.php
@@ -148,7 +148,7 @@ function civicrm_api3_membership_status_calc($membershipParams) {
$dao = CRM_Core_DAO::executeQuery($query, $params);
if ($dao->fetch()) {
$membershipTypeID = empty($membershipParams['membership_type_id']) ? $dao->membership_type_id : $membershipParams['membership_type_id'];
- $result = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dao->start_date, $dao->end_date, $dao->join_date, 'now', CRM_Utils_Array::value('ignore_admin_only', $membershipParams), $membershipTypeID, $membershipParams);
+ $result = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dao->start_date, $dao->end_date, $dao->join_date, 'now', $membershipParams['ignore_admin_only'] ?? FALSE, $membershipTypeID, $membershipParams);
//make is error zero only when valid status found.
if (!empty($result['id'])) {
$result['is_error'] = 0;
diff --git a/api/v3/Note.php b/api/v3/Note.php
index e1866d1196c3..c8e1493e882e 100644
--- a/api/v3/Note.php
+++ b/api/v3/Note.php
@@ -92,7 +92,7 @@ function _civicrm_api3_note_get_spec(&$params) {
*
* @param array $params
* array; only required 'id' parameter is used.
- *
+ * @deprecated
* @return array
* Nested associative array beginning with direct children of given note.
*/
@@ -111,3 +111,12 @@ function civicrm_api3_note_tree_get($params) {
$noteTree = CRM_Core_BAO_Note::getNoteTree($params['id'], $params['max_depth'], $params['snippet']);
return civicrm_api3_create_success($noteTree, $params);
}
+
+/**
+ * Declare deprecated api functions.
+ *
+ * @return array
+ */
+function _civicrm_api3_note_deprecation() {
+ return ['tree_get' => 'Unused api action.'];
+}
diff --git a/api/v3/Participant.php b/api/v3/Participant.php
index e37625d8a9d4..8f1076b61cb3 100644
--- a/api/v3/Participant.php
+++ b/api/v3/Participant.php
@@ -151,7 +151,7 @@ function civicrm_api3_participant_get($params) {
$query->convertToPseudoNames($dao, FALSE, TRUE);
$participant[$dao->participant_id] = $query->store($dao);
//@todo - is this required - contribution & pledge use the same query but don't self-retrieve custom data
- _civicrm_api3_custom_data_get($participant[$dao->participant_id], CRM_Utils_Array::value('check_permissions', $params), 'Participant', $dao->participant_id, NULL);
+ _civicrm_api3_custom_data_get($participant[$dao->participant_id], $params['check_permissions'] ?? FALSE, 'Participant', $dao->participant_id, NULL);
}
return civicrm_api3_create_success($participant, $params, 'Participant', 'get', $dao);
diff --git a/api/v3/Profile.php b/api/v3/Profile.php
index c9c0af59604a..202ca7fc41c8 100644
--- a/api/v3/Profile.php
+++ b/api/v3/Profile.php
@@ -81,7 +81,7 @@ function civicrm_api3_profile_get($params) {
$contactFields = $activityFields = [];
foreach ($profileFields as $fieldName => $field) {
- if (CRM_Utils_Array::value('field_type', $field) == 'Activity') {
+ if (($field['field_type'] ?? NULL) === 'Activity') {
$activityFields[$fieldName] = $field;
}
else {
@@ -244,7 +244,7 @@ function civicrm_api3_profile_submit($params) {
];
}
- $contactParams['contact_id'] = empty($params['contact_id']) ? CRM_Utils_Array::value('id', $params) : $params['contact_id'];
+ $contactParams['contact_id'] = empty($params['contact_id']) ? ($params['id'] ?? NULL) : $params['contact_id'];
$contactParams['profile_id'] = $profileID;
$contactParams['skip_custom'] = 1;
@@ -298,7 +298,7 @@ function _civicrm_api3_profile_submit_spec(&$params, $apirequest) {
// we don't resolve state, country & county for performance reasons
$resolveOptions = ($apirequest['params']['get_options'] ?? NULL) == 'all';
$profileID = _civicrm_api3_profile_getProfileID($apirequest['params']['profile_id']);
- $params = _civicrm_api3_buildprofile_submitfields($profileID, $resolveOptions, CRM_Utils_Array::value('cache_clear', $params));
+ $params = _civicrm_api3_buildprofile_submitfields($profileID, $resolveOptions, $params['cache_clear'] ?? FALSE);
}
elseif (isset($apirequest['params']['cache_clear'])) {
_civicrm_api3_buildprofile_submitfields(FALSE, FALSE, TRUE);
@@ -360,10 +360,10 @@ function civicrm_api3_profile_apply($params) {
list($data, $contactDetails) = CRM_Contact_BAO_Contact::formatProfileContactParams($params,
$profileFields,
- CRM_Utils_Array::value('contact_id', $params),
+ $params['contact_id'] ?? NULL,
$params['profile_id'],
- CRM_Utils_Array::value('contact_type', $params),
- CRM_Utils_Array::value('skip_custom', $params, FALSE)
+ $params['contact_type'] ?? NULL,
+ $params['skip_custom'] ?? FALSE
);
if (empty($data)) {
diff --git a/api/v3/Setting.php b/api/v3/Setting.php
index 2420e6586599..a2c422bb7104 100644
--- a/api/v3/Setting.php
+++ b/api/v3/Setting.php
@@ -45,10 +45,10 @@ function civicrm_api3_setting_getfields($params) {
$params['filters']['name'] = $params['name'];
}
$result = CRM_Core_BAO_Setting::getSettingSpecification(
- CRM_Utils_Array::value('component_id', $params),
- CRM_Utils_Array::value('filters', $params, []),
- CRM_Utils_Array::value('domain_id', $params, NULL),
- CRM_Utils_Array::value('profile', $params, NULL)
+ $params['component_id'] ?? NULL,
+ $params['filters'] ?? [],
+ $params['domain_id'] ?? NULL,
+ $params['profile'] ?? NULL
);
// find any supplemental information
if (!empty($params['action'])) {
@@ -296,7 +296,7 @@ function _civicrm_api3_setting_create_spec(&$params) {
*/
function civicrm_api3_setting_get($params) {
$domains = _civicrm_api3_setting_getDomainArray($params);
- $result = CRM_Core_BAO_Setting::getItems($params, $domains, CRM_Utils_Array::value('return', $params, []));
+ $result = CRM_Core_BAO_Setting::getItems($params, $domains, $params['return'] ?? []);
return civicrm_api3_create_success($result, $params, 'Setting', 'get');
}
@@ -338,11 +338,11 @@ function civicrm_api3_setting_getvalue($params) {
//}
return CRM_Core_BAO_Setting::getItem(
NULL,
- CRM_Utils_Array::value('name', $params),
- CRM_Utils_Array::value('component_id', $params),
- CRM_Utils_Array::value('default_value', $params),
- CRM_Utils_Array::value('contact_id', $params),
- CRM_Utils_Array::value('domain_id', $params)
+ $params['name'] ?? NULL,
+ $params['component_id'] ?? NULL,
+ $params['default_value'] ?? NULL,
+ $params['contact_id'] ?? NULL,
+ $params['domain_id'] ?? NULL
);
}
diff --git a/api/v3/System.php b/api/v3/System.php
index 9ce36d94cfa0..63078987fa52 100644
--- a/api/v3/System.php
+++ b/api/v3/System.php
@@ -29,8 +29,8 @@
*/
function civicrm_api3_system_flush($params) {
CRM_Core_Invoke::rebuildMenuAndCaches(
- CRM_Utils_Array::value('triggers', $params, FALSE),
- CRM_Utils_Array::value('session', $params, FALSE)
+ $params['triggers'] ?? FALSE,
+ $params['session'] ?? FALSE
);
return civicrm_api3_create_success();
}
diff --git a/api/v3/Tag.php b/api/v3/Tag.php
index 89bc9070cef1..57434e434151 100644
--- a/api/v3/Tag.php
+++ b/api/v3/Tag.php
@@ -45,7 +45,6 @@ function civicrm_api3_tag_create($params) {
*/
function _civicrm_api3_tag_create_spec(&$params) {
$params['used_for']['api.default'] = 'civicrm_contact';
- $params['name']['api.required'] = 1;
$params['id']['api.aliases'] = ['tag'];
}
diff --git a/api/v3/utils.php b/api/v3/utils.php
index 7dff36515b28..189b6efdd60a 100644
--- a/api/v3/utils.php
+++ b/api/v3/utils.php
@@ -497,12 +497,12 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti
$options = _civicrm_api3_get_options_from_params($params, TRUE);
$inputParams = array_merge(
- CRM_Utils_Array::value('input_params', $options, []),
- CRM_Utils_Array::value('input_params', $additional_options, [])
+ $options['input_params'] ?? [],
+ $additional_options['input_params'] ?? []
);
$returnProperties = array_merge(
- CRM_Utils_Array::value('return', $options, []),
- CRM_Utils_Array::value('return', $additional_options, [])
+ $options['return'] ?? [],
+ $additional_options['return'] ?? []
);
if (empty($returnProperties)) {
$returnProperties = $defaultReturnProperties;
@@ -579,7 +579,7 @@ function _civicrm_api3_get_query_object($params, $mode, $entity) {
$sort = $options['sort'] ?? NULL;
$offset = $options['offset'] ?? NULL;
$rowCount = $options['limit'] ?? NULL;
- $inputParams = CRM_Utils_Array::value('input_params', $options, []);
+ $inputParams = $options['input_params'] ?? [];
$returnProperties = $options['return'] ?? NULL;
if (empty($returnProperties)) {
$returnProperties = CRM_Contribute_BAO_Query::defaultReturnProperties($mode);
@@ -767,15 +767,15 @@ function _civicrm_api3_get_options_from_params($params, $queryObject = FALSE, $e
$sort = $params['option_sort'] ?? $params['option.sort'] ?? $params['sort'] ?? 0;
$offset = $params['option_offset'] ?? $params['option.offset'] ?? $params['offset'] ?? 0;
- $limit = CRM_Utils_Array::value('rowCount', $params, 25);
- $limit = CRM_Utils_Array::value('option.limit', $params, $limit);
- $limit = CRM_Utils_Array::value('option_limit', $params, $limit);
+ $limit = $params['rowCount'] ?? 25;
+ $limit = $params['option.limit'] ?? $limit;
+ $limit = $params['option_limit'] ?? $limit;
if (isset($params['options']) && is_array($params['options'])) {
// is count is set by generic getcount not user
$is_count = $params['options']['is_count'] ?? FALSE;
$offset = $params['options']['offset'] ?? $offset;
- $limit = CRM_Utils_Array::value('limit', $params['options'], $limit);
+ $limit = $params['options']['limit'] ?? $limit;
$sort = $params['options']['sort'] ?? $sort;
}
@@ -931,7 +931,7 @@ function _civicrm_api3_build_fields_array(&$bao, $unique = TRUE) {
function _civicrm_api3_get_unique_name_array(&$bao) {
$fields = $bao->fields();
foreach ($fields as $field => $values) {
- $uniqueFields[$field] = CRM_Utils_Array::value('name', $values, $field);
+ $uniqueFields[$field] = $values['name'] ?? $field;
}
return $uniqueFields;
}
@@ -1694,7 +1694,7 @@ function _civicrm_api3_validate_date(&$params, &$fieldName, &$fieldInfo) {
if (!empty($params[$fieldInfo['name']])) {
$fieldValue = _civicrm_api3_getValidDate($fieldValue, $fieldInfo['name'], $fieldInfo['type']);
}
- if ((CRM_Utils_Array::value('name', $fieldInfo) != $fieldName) && !empty($fieldValue)) {
+ if (($fieldInfo['name'] ?? NULL) !== $fieldName && !empty($fieldValue)) {
$fieldValue = _civicrm_api3_getValidDate($fieldValue, $fieldName, $fieldInfo['type']);
}
@@ -1975,7 +1975,7 @@ function _civicrm_api_get_custom_fields($entity, &$params) {
FALSE,
FALSE,
// we could / should probably test for other subtypes here - e.g. activity_type_id
- CRM_Utils_Array::value('contact_sub_type', $params),
+ $params['contact_sub_type'] ?? NULL,
NULL,
FALSE,
FALSE,
@@ -1988,7 +1988,7 @@ function _civicrm_api_get_custom_fields($entity, &$params) {
// Regular fields have a 'name' property
$value['name'] = 'custom_' . $key;
$value['title'] = $value['label'];
- if ($value['data_type'] == 'Date' && CRM_Utils_Array::value('time_format', $value, 0) > 0) {
+ if ($value['data_type'] == 'Date' && ($value['time_format'] ?? 0) > 0) {
$value['data_type'] = 'DateTime';
}
$value['type'] = CRM_Utils_Array::value($value['data_type'], CRM_Core_BAO_CustomField::dataToType());
@@ -2317,7 +2317,7 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
}
$options = civicrm_api($entity, 'getoptions', $options_lookup_params);
- $options = CRM_Utils_Array::value('values', $options, []);
+ $options = $options['values'] ?? [];
}
if (is_string($fieldValue) && strpos($fieldValue, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE) {
@@ -2327,12 +2327,12 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam
if (is_array($fieldValue)) {
foreach ($fieldValue as &$value) {
if (!is_array($value)) {
- _civicrm_api3_api_match_pseudoconstant_value($value, $options, $fieldName, CRM_Utils_Array::value('api.required', $fieldInfo));
+ _civicrm_api3_api_match_pseudoconstant_value($value, $options, $fieldName, $fieldInfo['api.required'] ?? FALSE);
}
}
}
else {
- _civicrm_api3_api_match_pseudoconstant_value($fieldValue, $options, $fieldName, CRM_Utils_Array::value('api.required', $fieldInfo));
+ _civicrm_api3_api_match_pseudoconstant_value($fieldValue, $options, $fieldName, $fieldInfo['api.required'] ?? FALSE);
}
}
@@ -2439,10 +2439,10 @@ function _civicrm_api3_api_resolve_alias($entity, $fieldName, $action = 'create'
return $meta[$fieldName]['name'];
}
foreach ($meta as $info) {
- if ($fieldName == $info['name'] || $fieldName == CRM_Utils_Array::value('uniqueName', $info)) {
+ if ($fieldName == $info['name'] || $fieldName == ($info['uniqueName'] ?? NULL)) {
return $info['name'];
}
- if (array_search($fieldName, CRM_Utils_Array::value('api.aliases', $info, [])) !== FALSE) {
+ if (array_search($fieldName, $info['api.aliases'] ?? []) !== FALSE) {
return $info['name'];
}
}
@@ -2615,7 +2615,7 @@ function _civicrm_api3_basic_array_get($entity, $params, $records, $idCol, $filt
}
}
- $return = CRM_Utils_Array::value('return', $options, []);
+ $return = $options['return'] ?? [];
if (!empty($return)) {
$return['id'] = 1;
$matches = CRM_Utils_Array::filterColumns($matches, array_keys($return));
diff --git a/composer.json b/composer.json
index 3e3eb8982962..932417d5a134 100644
--- a/composer.json
+++ b/composer.json
@@ -102,7 +102,7 @@
"symfony/polyfill-php80": "^1.0",
"symfony/polyfill-php81": "^1.0",
"symfony/polyfill-php82": "^1.0",
- "html2text/html2text": "^4.3.1",
+ "soundasleep/html2text": "^2.1",
"psr/container": "~1.0 || ~2.0",
"ext-fileinfo": "*"
},
@@ -202,9 +202,6 @@
"path": "bower_components/es-module-shims/dist/es-module-shims.js",
"_comment": "See also https://github.com/guybedford/es-module-shims/. MIT license."
},
- "es6-promise": {
- "url": "https://github.com/components/es6-promise/archive/v4.2.4.zip"
- },
"ext-greenwich-bootstrap3": {
"url": "https://github.com/twbs/bootstrap-sass/archive/v{$version}.zip",
"path": "ext/greenwich/extern/bootstrap3",
@@ -275,9 +272,6 @@
"Update gitignore to ensure that sites that manage via git don't miss out on the important db.json file": "https://patch-diff.githubusercontent.com/raw/adrienrn/php-mimetyper/pull/15.patch",
"Apply patch to fix php8.2 deprecation notice on dynamic property $filename": "https://patch-diff.githubusercontent.com/raw/adrienrn/php-mimetyper/pull/17.patch"
},
- "html2text/html2text": {
- "Fix deprecation warning in php8.1 on html_entity_decode": "https://raw.githubusercontent.com/civicrm/civicrm-core/e758d20e9f613ca6c4cf652c23d2cd7e5d3af3ce/tools/scripts/composer/html2text_html2_text_php81_deprecation.patch"
- },
"pear/db": {
"Apply patch to ensure that MySQLI reporting remains the same in php8.1": "https://patch-diff.githubusercontent.com/raw/pear/DB/pull/13.patch",
"Apply patch to fix deprecations in php8.2": "https://patch-diff.githubusercontent.com/raw/pear/DB/pull/14.patch",
diff --git a/composer.lock b/composer.lock
index b4288d6318b5..072c5ee289bf 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "377176179275d0aa4262d031e5bc4559",
+ "content-hash": "d112a69d39ea11b6ad870811b2960200",
"packages": [
{
"name": "adrienrn/php-mimetyper",
@@ -966,47 +966,6 @@
],
"time": "2023-04-17T16:00:37+00:00"
},
- {
- "name": "html2text/html2text",
- "version": "4.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/mtibben/html2text.git",
- "reference": "61ad68e934066a6f8df29a3d23a6460536d0855c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/mtibben/html2text/zipball/61ad68e934066a6f8df29a3d23a6460536d0855c",
- "reference": "61ad68e934066a6f8df29a3d23a6460536d0855c",
- "shasum": ""
- },
- "require-dev": {
- "phpunit/phpunit": "~4"
- },
- "suggest": {
- "ext-mbstring": "For best performance",
- "symfony/polyfill-mbstring": "If you can't install ext-mbstring"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Html2Text\\": [
- "src/",
- "test/"
- ]
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "GPL-2.0-or-later"
- ],
- "description": "Converts HTML to formatted plain text",
- "support": {
- "issues": "https://github.com/mtibben/html2text/issues",
- "source": "https://github.com/mtibben/html2text/tree/4.3.1"
- },
- "time": "2020-04-16T23:44:31+00:00"
- },
{
"name": "laminas/laminas-escaper",
"version": "2.6.1",
@@ -3414,6 +3373,61 @@
},
"time": "2022-05-16T07:22:18+00:00"
},
+ {
+ "name": "soundasleep/html2text",
+ "version": "2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/soundasleep/html2text.git",
+ "reference": "83502b6f8f1aaef8e2e238897199d64f284b4af3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/soundasleep/html2text/zipball/83502b6f8f1aaef8e2e238897199d64f284b4af3",
+ "reference": "83502b6f8f1aaef8e2e238897199d64f284b4af3",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "php": "^7.3|^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.9",
+ "phpunit/phpunit": "^7.0|^8.0|^9.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Soundasleep\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jevon Wright",
+ "homepage": "https://jevon.org",
+ "role": "Developer"
+ }
+ ],
+ "description": "A PHP script to convert HTML into a plain text format",
+ "homepage": "https://github.com/soundasleep/html2text",
+ "keywords": [
+ "email",
+ "html",
+ "php",
+ "text"
+ ],
+ "support": {
+ "email": "support@jevon.org",
+ "issues": "https://github.com/soundasleep/html2text/issues",
+ "source": "https://github.com/soundasleep/html2text/tree/2.1.0"
+ },
+ "time": "2023-01-06T09:28:15+00:00"
+ },
{
"name": "symfony/config",
"version": "v4.4.42",
diff --git a/contributor-key.yml b/contributor-key.yml
index 48138fbb5ffa..4971db7104f1 100644
--- a/contributor-key.yml
+++ b/contributor-key.yml
@@ -255,6 +255,8 @@
name : Joan Cervan Andreu
organization: calbasi.net
+- github : cdhassell
+
- name : Cath O'Connell
- github : chagrawil
@@ -380,6 +382,9 @@
name : Detlev Sieber
organization: Digitalcourage
+- github : devappsoftware
+ organization: DevApp
+
- github : devarun
name : Arun Singh
@@ -1211,6 +1216,9 @@
- github : prondubuisi
name : Onyemenam Ndubuisi
+- github : PrzemyslawTabor
+ name : Przemysław Tabor
+
- name : Richard Edgar
- github : ogomez78
@@ -1702,6 +1710,8 @@
- github : YesusHDS
+- github : yurg
+
- github : Toby-fz
name : Toby Messerli
organization: Fuzion
@@ -1717,5 +1727,5 @@
- github : mikeybeck
name : Mike Beck
organization: Fuzion
-
+
- github : ziljah
diff --git a/css/joomla.css b/css/joomla.css
index 7e902f35ba8e..46eb7ab7d521 100644
--- a/css/joomla.css
+++ b/css/joomla.css
@@ -6,11 +6,9 @@
div#toolbar-box .icon-48-generic {
display: none;
}
-
div#toolbar-box {
height: 26px;
}
-
fieldset {
margin-bottom: 1em;
padding: .5em;
@@ -31,12 +29,10 @@ img {
#crm-container tr td {
font-size: 1em;
}
-
/* Added in CiviCRM 2.1 to overwrite tiny font in TinyMCE editor. */
#crm-container #content table.mceLayout td {
font-size: 0em;
}
-
th {
text-align: left;
padding-right: 1em;
@@ -52,11 +48,9 @@ tr.light {
border-bottom: 1px solid #ccc;
padding: 0.1em 0.6em;
}
-
td.active {
background-color: #ddd;
}
-
td.label {
background: none;
color: #3e3e3e;
@@ -67,7 +61,7 @@ td.label {
** Other common styles
*/
.breadcrumb {
- padding-bottom: .5em
+ padding-bottom: .5em;
}
.block ul {
margin: 0;
@@ -228,19 +222,9 @@ br.clear {
border-color: red;
color: red;
}
-#sidebar-left,
-#sidebar-right {
- background-color: #ddd;
- width: 16em;
- /* padding in px not ex because IE messes up 100% width tables otherwise */
- padding: 20px;
- vertical-align: top;
-}
-
-#content-right {
- background-color: #ffffff;
+#crm-content {
+ padding: 1rem;
}
-
#footer {
padding: 1em;
font-size: 0.8em;
@@ -289,7 +273,6 @@ br.clear {
.box .title {
font-size: 1.1em;
}
-
#module-status,
.version {
font-size: 11px;
@@ -304,19 +287,16 @@ br.clear {
/* Joomla Admin Menu alterations */
/* Moved from civicrm.css in v3.2 */
-
div#toolbar-box div.m {
padding: 0px !important;
min-height: 0;
border: 0;
margin-top: 8px;
}
-
div#toolbar-box,
div#toolbar-box div.m {
height: auto;
}
-
.crm-tab-button,
.ui-tabs .ui-tabs-nav li {
border: 1px;
@@ -333,9 +313,6 @@ div#toolbar-box div.m {
padding-bottom: 0;
border: 1px solid #999 !important;
}
-#crm-container {
- font-size: 11px;
-}
#crm-container .col1 {
margin: 0;
}
@@ -345,11 +322,9 @@ div#toolbar-box div.m {
.ac_results .ac_odd {
background-color: #444;
}
-
#crm-notification-container {
top: 100px;
}
-
.crm-container textarea,
.crm-container input,
.crm-container select {
@@ -369,22 +344,18 @@ div#toolbar-box div.m {
.crm-container button[type=submit] {
height: auto;
}
-
.crm-container .disabled {
font-weight: normal;
}
-
#crm-container .form-layout td.label,
.crm-container .form-layout td.label {
width: inherit;
}
-
#crm-container .crm-event-form-fee-block .label {
background-color: inherit;
width: inherit;
display: block;
}
-
/* dev/core#874 the width:auto styling above causes the menubar colour picker to be squeezed */
.crm-container input.crm-form-color {
width: 3.6em;
@@ -405,10 +376,6 @@ body.admin.com_civicrm.task-civicrmupgrade .container-fluid.container-main {
body.admin.com_civicrm #crm-nav-menu-container {
padding-bottom: 0 !important;
}
-body.admin.com_civicrm #content-right {
- padding: 12px;
-}
-
/* Make footer admin bar hide behind popup windows (CRM-15723) */
body.ui-dialog-open #status {
z-index: 100 !important;
@@ -416,18 +383,12 @@ body.ui-dialog-open #status {
/* Joomla 4 */
-body.admin.com_civicrm.layout-default #content {
- padding: 0;
-}
-
body.admin.com_civicrm.layout-default #subhead-container {
display: none;
}
-
body.admin.com_civicrm.layout-default .crm-container .crm-dashlet {
max-width: 50vw; /* fixes over-wide news dashlet */
}
-
body.admin.com_civicrm.layout-default .crm-container .content {
padding: inherit; /* overrides J4 duplicated padding */
}
@@ -437,11 +398,9 @@ body.admin.com_civicrm.layout-default .crm-container .content {
body.admin.com_civicrm.layout-default .crm-container.ui-dialog.ui-resizable {
z-index: 1021;
}
-
body.admin.com_civicrm.layout-default .ui-widget-overlay {
z-index: 1;
}
-
body.admin.com_civicrm.layout-default .crm-container .modal-dialog {
max-width: inherit;
padding: 0;
diff --git a/distmaker/core-ext.txt b/distmaker/core-ext.txt
index 9e2a64087f9e..1021333ca7c7 100644
--- a/distmaker/core-ext.txt
+++ b/distmaker/core-ext.txt
@@ -35,3 +35,4 @@ civi_member
civi_pledge
civi_report
scheduled_communications
+user_dashboard
diff --git a/ext/afform/admin/Civi/AfformAdmin/AfformAdminInjector.php b/ext/afform/admin/Civi/AfformAdmin/AfformAdminInjector.php
new file mode 100644
index 000000000000..624844208287
--- /dev/null
+++ b/ext/afform/admin/Civi/AfformAdmin/AfformAdminInjector.php
@@ -0,0 +1,55 @@
+ 'preprocess',
+ ];
+ }
+
+ /**
+ * @param \Civi\Core\Event\GenericHookEvent $e
+ * @see CRM_Utils_Hook::alterAngular()
+ */
+ public static function preprocess($e) {
+ $changeSet = \Civi\Angular\ChangeSet::create('afformAdmin')
+ ->alterHtml(';\\.aff\\.html$;', function($doc, $path) {
+ try {
+ $moduleName = basename($path, '.aff.html');
+ // If the user has "administer CiviCRM", inject edit link
+ if (\CRM_Core_Permission::check('administer CiviCRM')) {
+ $url = \CRM_Utils_System::url('civicrm/admin/afform', NULL, FALSE, '/edit/' . $moduleName, TRUE);
+ // Append link to afform directive element (using loop but there should be only one)
+ foreach (pq('af-form[ctrl]', $doc) as $afForm) {
+ pq($afForm)->append(' ' . E::ts('Edit Form') . ' ');
+ }
+ }
+ }
+ catch (\Exception $e) {
+ }
+ });
+ $e->angular->add($changeSet);
+ }
+
+}
diff --git a/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php b/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php
index cf283b74a7f3..e1516a21e644 100644
--- a/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php
+++ b/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php
@@ -13,6 +13,12 @@ class AfformAdminMeta {
* @return array
*/
public static function getAdminSettings() {
+ $afformPlacement = \CRM_Utils_Array::formatForSelect2((array) \Civi\Api4\OptionValue::get(FALSE)
+ ->addSelect('value', 'label', 'icon', 'description')
+ ->addWhere('is_active', '=', TRUE)
+ ->addWhere('option_group_id:name', '=', 'afform_placement')
+ ->addOrderBy('weight')
+ ->execute(), 'label', 'value');
$afformTypes = (array) \Civi\Api4\OptionValue::get(FALSE)
->addSelect('name', 'label', 'icon')
->addWhere('is_active', '=', TRUE)
@@ -31,6 +37,7 @@ public static function getAdminSettings() {
}
return [
'afform_type' => $afformTypes,
+ 'afform_placement' => $afformPlacement,
'search_operators' => \Civi\Afform\Utils::getSearchOperators(),
];
}
diff --git a/ext/afform/admin/afformEntities/Household.php b/ext/afform/admin/afformEntities/Household.php
index 808565deab97..3e120a7fef94 100644
--- a/ext/afform/admin/afformEntities/Household.php
+++ b/ext/afform/admin/afformEntities/Household.php
@@ -11,5 +11,4 @@
'boilerplate' => [
['#tag' => 'afblock-name-household'],
],
- 'admin_tpl' => '~/afGuiEditor/entityConfig/Contact.html',
];
diff --git a/ext/afform/admin/afformEntities/Individual.php b/ext/afform/admin/afformEntities/Individual.php
index 3d124377d893..3a51fdc9b75e 100644
--- a/ext/afform/admin/afformEntities/Individual.php
+++ b/ext/afform/admin/afformEntities/Individual.php
@@ -11,5 +11,4 @@
'boilerplate' => [
['#tag' => 'afblock-name-individual'],
],
- 'admin_tpl' => '~/afGuiEditor/entityConfig/Contact.html',
];
diff --git a/ext/afform/admin/afformEntities/Organization.php b/ext/afform/admin/afformEntities/Organization.php
index b36455be1bba..eaf258446d9b 100644
--- a/ext/afform/admin/afformEntities/Organization.php
+++ b/ext/afform/admin/afformEntities/Organization.php
@@ -11,5 +11,4 @@
'boilerplate' => [
['#tag' => 'afblock-name-organization'],
],
- 'admin_tpl' => '~/afGuiEditor/entityConfig/Contact.html',
];
diff --git a/ext/afform/admin/afform_admin.civix.php b/ext/afform/admin/afform_admin.civix.php
index 52866d86b88f..eb9df12ea5e0 100644
--- a/ext/afform/admin/afform_admin.civix.php
+++ b/ext/afform/admin/afform_admin.civix.php
@@ -133,8 +133,8 @@ function _afform_admin_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/afform/admin/ang/afAdmin.js b/ext/afform/admin/ang/afAdmin.js
index 8d45473732ed..af06f68e98cb 100644
--- a/ext/afform/admin/ang/afAdmin.js
+++ b/ext/afform/admin/ang/afAdmin.js
@@ -11,7 +11,7 @@
// Load data for lists
afforms: function(crmApi4) {
return crmApi4('Afform', 'get', {
- select: ['name', 'title', 'type', 'server_route', 'is_public', 'submission_count', 'submission_date', 'submit_limit', 'submit_enabled', 'submit_currently_open', 'has_local', 'has_base', 'base_module', 'base_module:label', 'is_dashlet', 'contact_summary:label']
+ select: ['name', 'title', 'type', 'server_route', 'is_public', 'submission_count', 'submission_date', 'submit_limit', 'submit_enabled', 'submit_currently_open', 'has_local', 'has_base', 'base_module', 'base_module:label', 'placement:label']
});
}
}
diff --git a/ext/afform/admin/ang/afAdmin/afAdminList.controller.js b/ext/afform/admin/ang/afAdmin/afAdminList.controller.js
index 70c9536f936e..621947cf5234 100644
--- a/ext/afform/admin/ang/afAdmin/afAdminList.controller.js
+++ b/ext/afform/admin/ang/afAdmin/afAdminList.controller.js
@@ -24,14 +24,7 @@
this.afforms = _.transform(afforms, function(afforms, afform) {
afform.type = afform.type || 'system';
- // Aggregate a couple fields for the "Placement" column
- afform.placement = [];
- if (afform.is_dashlet) {
- afform.placement.push(ts('Dashboard'));
- }
- if (afform['contact_summary:label']) {
- afform.placement.push(afform['contact_summary:label']);
- }
+ afform.placement = afform['placement:label'];
if (afform.submission_date) {
afform.submission_date = CRM.utils.formatDate(afform.submission_date);
}
diff --git a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json
deleted file mode 100644
index 3584ff594892..000000000000
--- a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "system",
- "title": "Submissions",
- "server_route": "civicrm/admin/afform/submissions",
- "permission": ["administer CiviCRM", "administer afform"],
- "permission_operator": "OR"
-}
diff --git a/ext/afform/admin/ang/afAdminFormSubmissionList.aff.php b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.php
new file mode 100644
index 000000000000..8eda1f70cc1a
--- /dev/null
+++ b/ext/afform/admin/ang/afAdminFormSubmissionList.aff.php
@@ -0,0 +1,10 @@
+ 'system',
+ 'title' => E::ts('Submissions'),
+ 'server_route' => 'civicrm/admin/afform/submissions',
+ 'permission' => ["administer CiviCRM", "administer afform"],
+ 'permission_operator' => 'OR',
+];
diff --git a/ext/afform/admin/ang/afGuiEditor.js b/ext/afform/admin/ang/afGuiEditor.js
index 120798c72126..6b52f6228d27 100644
--- a/ext/afform/admin/ang/afGuiEditor.js
+++ b/ext/afform/admin/ang/afGuiEditor.js
@@ -141,7 +141,7 @@
});
},
- meta: CRM.afGuiEditor,
+ meta: _.extend(CRM.afGuiEditor, CRM.afAdmin),
getEntity: function(entityName) {
return CRM.afGuiEditor.entities[entityName];
diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js
index 07eb9fabeb69..d2279c950f66 100644
--- a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js
+++ b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js
@@ -99,10 +99,10 @@
delete editor.afform.name;
delete editor.afform.server_route;
delete editor.afform.navigation;
- editor.afform.is_dashlet = false;
editor.afform.title += ' ' + ts('(copy)');
}
editor.afform.icon = editor.afform.icon || 'fa-list-alt';
+ editor.afform.placement = editor.afform.placement || [];
$scope.canvasTab = 'layout';
$scope.layoutHtml = '';
$scope.entities = {};
@@ -332,14 +332,16 @@
return filter ? _.filter($scope.entities, filter) : _.toArray($scope.entities);
};
- this.toggleContactSummary = function() {
- if (editor.afform.contact_summary) {
- editor.afform.contact_summary = null;
+ this.isContactSummary = function() {
+ return editor.afform.placement.includes('contact_summary_block') || editor.afform.placement.includes('contact_summary_tab');
+ };
+
+ this.onChangePlacement = function() {
+ if (!editor.isContactSummary()) {
_.each(editor.searchDisplays, function(searchDisplay) {
delete searchDisplay.element.filters;
});
} else {
- editor.afform.contact_summary = 'block';
_.each(editor.searchDisplays, function(searchDisplay) {
var filterOptions = getSearchFilterOptions(searchDisplay.settings);
if (filterOptions.length) {
diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiFieldValue.directive.js b/ext/afform/admin/ang/afGuiEditor/afGuiFieldValue.directive.js
index 661eb4b6a32a..3f3d0c728252 100644
--- a/ext/afform/admin/ang/afGuiEditor/afGuiFieldValue.directive.js
+++ b/ext/afform/admin/ang/afGuiEditor/afGuiFieldValue.directive.js
@@ -75,12 +75,20 @@
}
}
+ function isSelect2() {
+ return $element.is('.select2-container + input');
+ }
+
// Copied from ng-list but applied conditionally if field is multi-valued
- var parseList = function(viewValue) {
+ var parseFieldInput = function(viewValue) {
// If the viewValue is invalid (say required but empty) it will be `undefined`
if (_.isUndefined(viewValue)) return;
- if (!multi) {
+ if ((viewValue === '1' || viewValue === '0') && ctrl.field.data_type === 'Boolean') {
+ return viewValue === '1';
+ }
+
+ if (!multi || !isSelect2()) {
return viewValue;
}
@@ -95,12 +103,20 @@
return list;
};
+ var formatViewValue = function(value) {
+ if (Array.isArray(value)) {
+ return value.join(',');
+ }
+ if (typeof value === 'boolean') {
+ return value ? '1' : '0';
+ }
+ return value;
+ };
+
this.$onInit = function() {
// Copied from ng-list
- ctrl.ngModel.$parsers.push(parseList);
- ctrl.ngModel.$formatters.push(function(value) {
- return _.isArray(value) ? value.join(',') : value;
- });
+ ctrl.ngModel.$parsers.push(parseFieldInput);
+ ctrl.ngModel.$formatters.push(formatViewValue);
// Copied from ng-list
ctrl.ngModel.$isEmpty = function(value) {
diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiSearch.html b/ext/afform/admin/ang/afGuiEditor/afGuiSearch.html
index 1d1001f88815..4f52e8b0e02d 100644
--- a/ext/afform/admin/ang/afGuiEditor/afGuiSearch.html
+++ b/ext/afform/admin/ang/afGuiEditor/afGuiSearch.html
@@ -77,4 +77,12 @@
+
+
+ {{:: ts('Options') }}
+ {{:: ts('Remember Filters') }}
+
+ {{:: ts('Filter fields will retain their value when the same user revisits the form.') }}
+
+
diff --git a/ext/afform/admin/ang/afGuiEditor/config-form.html b/ext/afform/admin/ang/afGuiEditor/config-form.html
index d18e23cfdca1..b439b4c81621 100644
--- a/ext/afform/admin/ang/afGuiEditor/config-form.html
+++ b/ext/afform/admin/ang/afGuiEditor/config-form.html
@@ -43,7 +43,7 @@
{{:: ts('Page Route') }}
-
+
{{:: ts('Expose the form as a standalone webpage. (Example: "civicrm/my-form")') }}
@@ -54,14 +54,6 @@
-
-
diff --git a/ext/afform/admin/ang/afGuiEditor/inputType/CheckBox.html b/ext/afform/admin/ang/afGuiEditor/inputType/CheckBox.html
index 1e6762315d27..d5d704b2a91f 100644
--- a/ext/afform/admin/ang/afGuiEditor/inputType/CheckBox.html
+++ b/ext/afform/admin/ang/afGuiEditor/inputType/CheckBox.html
@@ -1,7 +1,7 @@
-
- -
-
civicrm/admin/setting/authx
- Authentication
- CRM_Admin_Form_Generic
- System Settings
- Configure authentication for external systems
- administer CiviCRM
-
diff --git a/ext/civi_campaign/ang/afsearchCampaignDashboard.aff.html b/ext/civi_campaign/ang/afsearchCampaignDashboard.aff.html
new file mode 100644
index 000000000000..b429bdd53947
--- /dev/null
+++ b/ext/civi_campaign/ang/afsearchCampaignDashboard.aff.html
@@ -0,0 +1,25 @@
+
diff --git a/ext/civi_campaign/ang/afsearchCampaignDashboard.aff.php b/ext/civi_campaign/ang/afsearchCampaignDashboard.aff.php
new file mode 100644
index 000000000000..2134c1f285b7
--- /dev/null
+++ b/ext/civi_campaign/ang/afsearchCampaignDashboard.aff.php
@@ -0,0 +1,16 @@
+ 'search',
+ 'title' => E::ts('Campaign Dashboard'),
+ 'icon' => 'fa-table',
+ 'server_route' => 'civicrm/campaign',
+ 'permission' => ['administer CiviCampaign', 'manage campaign'],
+ 'permission_operator' => 'OR',
+ 'navigation' => [
+ 'parent' => 'Campaigns',
+ 'label' => E::ts('Campaign Dashboard'),
+ 'weight' => -1,
+ ],
+];
diff --git a/ext/civi_campaign/ang/afsearchSurveyOptionGroup.aff.html b/ext/civi_campaign/ang/afsearchSurveyOptionGroup.aff.html
new file mode 100644
index 000000000000..999b0d246953
--- /dev/null
+++ b/ext/civi_campaign/ang/afsearchSurveyOptionGroup.aff.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/ext/civi_campaign/ang/afsearchSurveyOptionGroup.aff.php b/ext/civi_campaign/ang/afsearchSurveyOptionGroup.aff.php
new file mode 100644
index 000000000000..7f5a56948f7d
--- /dev/null
+++ b/ext/civi_campaign/ang/afsearchSurveyOptionGroup.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => '',
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/survey/option-group',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civi_campaign/info.xml b/ext/civi_campaign/info.xml
index bdbdcaa6ed76..c965a30661d1 100644
--- a/ext/civi_campaign/info.xml
+++ b/ext/civi_campaign/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
@@ -29,6 +29,7 @@
scan-classes@1.0.0
+ mgd-php@1.0.0
CRM/Campaign
diff --git a/ext/civi_campaign/managed/SavedSearch_Administer_Campaigns.mgd.php b/ext/civi_campaign/managed/SavedSearch_Administer_Campaigns.mgd.php
new file mode 100644
index 000000000000..fa6f5fbe1930
--- /dev/null
+++ b/ext/civi_campaign/managed/SavedSearch_Administer_Campaigns.mgd.php
@@ -0,0 +1,205 @@
+ 'SavedSearch_Administer_Campaigns',
+ 'entity' => 'SavedSearch',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Administer_Campaigns',
+ 'label' => E::ts('Administer Campaigns'),
+ 'form_values' => NULL,
+ 'mapping_id' => NULL,
+ 'search_custom_id' => NULL,
+ 'api_entity' => 'Campaign',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => [
+ 'id',
+ 'title',
+ 'description',
+ 'is_active',
+ 'start_date',
+ 'end_date',
+ 'campaign_type_id:label',
+ 'status_id:label',
+ ],
+ 'orderBy' => [],
+ 'where' => [],
+ 'groupBy' => [],
+ 'join' => [],
+ 'having' => [],
+ ],
+ 'expires_date' => NULL,
+ 'description' => NULL,
+ ],
+ 'match' => [
+ 'name',
+ ],
+ ],
+ ],
+ [
+ 'name' => 'SavedSearch_Administer_Campaigns_SearchDisplay_Campaigns_Table',
+ 'entity' => 'SearchDisplay',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Campaigns_Table',
+ 'label' => E::ts('Administer Campaigns'),
+ 'saved_search_id.name' => 'Administer_Campaigns',
+ 'type' => 'table',
+ 'settings' => [
+ 'actions' => FALSE,
+ 'limit' => 50,
+ 'classes' => [
+ 'table',
+ 'table-striped',
+ ],
+ 'pager' => [
+ 'show_count' => FALSE,
+ 'expose_limit' => TRUE,
+ 'hide_single' => TRUE,
+ ],
+ 'placeholder' => 5,
+ 'sort' => [
+ ['is_active', 'DESC'],
+ ['title', 'ASC'],
+ ],
+ 'columns' => [
+ [
+ 'type' => 'field',
+ 'key' => 'title',
+ 'dataType' => 'String',
+ 'label' => E::ts('Title'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'description',
+ 'dataType' => 'String',
+ 'label' => E::ts('Description'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'start_date',
+ 'dataType' => 'Date',
+ 'label' => E::ts('Start Date'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'end_date',
+ 'dataType' => 'Date',
+ 'label' => E::ts('End Date'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'campaign_type_id:label',
+ 'dataType' => 'String',
+ 'label' => E::ts('Type'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'status_id:label',
+ 'dataType' => 'String',
+ 'label' => E::ts('Status'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'is_active',
+ 'dataType' => 'Boolean',
+ 'label' => E::ts('Enabled'),
+ 'sortable' => TRUE,
+ ],
+ [
+ 'size' => 'btn-xs',
+ 'links' => [
+ [
+ 'path' => '',
+ 'icon' => 'fa-pencil',
+ 'text' => E::ts('Edit'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'entity' => 'Campaign',
+ 'action' => 'update',
+ 'join' => '',
+ 'target' => 'crm-popup',
+ ],
+ [
+ 'task' => 'enable',
+ 'entity' => 'Campaign',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-toggle-on',
+ 'text' => E::ts('Enable'),
+ 'style' => 'default',
+ 'condition' => ['is_active', '=', FALSE],
+ ],
+ [
+ 'task' => 'disable',
+ 'entity' => 'Campaign',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-toggle-off',
+ 'text' => E::ts('Disable'),
+ 'style' => 'default',
+ 'condition' => ['is_active', '=', TRUE],
+ ],
+ [
+ 'entity' => 'Campaign',
+ 'action' => 'delete',
+ 'join' => '',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-trash',
+ 'text' => E::ts('Delete'),
+ 'style' => 'danger small-popup',
+ 'path' => '',
+ 'condition' => [],
+ ],
+ ],
+ 'type' => 'buttons',
+ 'alignment' => 'text-right',
+ ],
+ ],
+ 'toolbar' => [
+ [
+ 'entity' => 'Campaign',
+ 'action' => 'add',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-plus',
+ 'text' => E::ts('Add Campaign'),
+ 'style' => 'primary',
+ ],
+ ],
+ 'cssRules' => [
+ [
+ 'disabled',
+ 'is_active',
+ '=',
+ FALSE,
+ ],
+ ],
+ ],
+ 'acl_bypass' => FALSE,
+ ],
+ 'match' => [
+ 'name',
+ 'saved_search_id',
+ ],
+ ],
+ ],
+];
diff --git a/ext/civi_campaign/managed/SavedSearch_Administer_Petitions.mgd.php b/ext/civi_campaign/managed/SavedSearch_Administer_Petitions.mgd.php
new file mode 100644
index 000000000000..fa36a617cf29
--- /dev/null
+++ b/ext/civi_campaign/managed/SavedSearch_Administer_Petitions.mgd.php
@@ -0,0 +1,218 @@
+ 'SavedSearch_Administer_Petitions',
+ 'entity' => 'SavedSearch',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Administer_Petitions',
+ 'label' => E::ts('Administer Petitions'),
+ 'form_values' => NULL,
+ 'mapping_id' => NULL,
+ 'search_custom_id' => NULL,
+ 'api_entity' => 'Survey',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => [
+ 'id',
+ 'title',
+ 'campaign_id:label',
+ 'is_active',
+ 'is_default',
+ ],
+ 'orderBy' => [],
+ 'where' => [
+ ['activity_type_id:name', '=', 'Petition'],
+ ],
+ 'groupBy' => [],
+ 'join' => [],
+ 'having' => [],
+ ],
+ 'expires_date' => NULL,
+ 'description' => NULL,
+ ],
+ 'match' => [
+ 'name',
+ ],
+ ],
+ ],
+ [
+ 'name' => 'SavedSearch_Administer_Petitions_SearchDisplay_Petitions_Table',
+ 'entity' => 'SearchDisplay',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Petitions_Table',
+ 'label' => E::ts('Administer Petitions'),
+ 'saved_search_id.name' => 'Administer_Petitions',
+ 'type' => 'table',
+ 'settings' => [
+ 'actions' => FALSE,
+ 'limit' => 50,
+ 'classes' => [
+ 'table',
+ 'table-striped',
+ ],
+ 'pager' => [
+ 'show_count' => FALSE,
+ 'expose_limit' => TRUE,
+ 'hide_single' => TRUE,
+ ],
+ 'placeholder' => 5,
+ 'sort' => [
+ ['is_active', 'DESC'],
+ ['title', 'ASC'],
+ ],
+ 'columns' => [
+ [
+ 'type' => 'field',
+ 'key' => 'title',
+ 'dataType' => 'String',
+ 'label' => E::ts('Title'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'campaign_id:label',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Survey'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'is_default',
+ 'dataType' => 'Boolean',
+ 'label' => E::ts('Default'),
+ 'sortable' => TRUE,
+ 'rewrite' => ' ',
+ 'icons' => [
+ [
+ 'icon' => 'fa-check-square-o',
+ 'side' => 'left',
+ 'if' => [
+ 'is_default',
+ '=',
+ TRUE,
+ ],
+ ],
+ ],
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'is_active',
+ 'dataType' => 'Boolean',
+ 'label' => E::ts('Enabled'),
+ 'sortable' => TRUE,
+ ],
+ [
+ 'size' => 'btn-xs',
+ 'type' => 'buttons',
+ 'alignment' => 'text-right',
+ 'links' => [
+ [
+ 'path' => 'civicrm/petition/add?reset=1&action=update&id=[id]',
+ 'icon' => 'fa-pencil',
+ 'text' => E::ts('Edit'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'target' => 'crm-popup',
+ ],
+ [
+ 'task' => 'enable',
+ 'entity' => 'Survey',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-toggle-on',
+ 'text' => E::ts('Enable'),
+ 'style' => 'default',
+ 'condition' => ['is_active', '=', FALSE],
+ ],
+ [
+ 'task' => 'disable',
+ 'entity' => 'Survey',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-toggle-off',
+ 'text' => E::ts('Disable'),
+ 'style' => 'default',
+ 'condition' => ['is_active', '=', TRUE],
+ ],
+ [
+ 'entity' => 'Survey',
+ 'action' => 'delete',
+ 'join' => '',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-trash',
+ 'text' => E::ts('Delete'),
+ 'style' => 'danger small-popup',
+ 'path' => '',
+ 'condition' => [],
+ ],
+ ],
+ ],
+ [
+ 'text' => E::ts('Signatures'),
+ 'style' => 'default',
+ 'size' => 'btn-xs',
+ 'icon' => 'fa-bars',
+ 'type' => 'menu',
+ 'alignment' => 'text-right',
+ 'links' => [
+ [
+ 'path' => 'civicrm/petition/sign?reset=1&sid=[id]',
+ 'icon' => 'fa-clipboard',
+ 'text' => E::ts('Sign'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'target' => '_blank',
+ ],
+ [
+ 'path' => 'civicrm/activity/search?force=1&survey=[id]',
+ 'icon' => 'fa-list-alt',
+ 'text' => E::ts('View Signatures'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'target' => '_blank',
+ ],
+ ],
+ ],
+ ],
+ 'toolbar' => [
+ [
+ 'path' => 'civicrm/petition/add?reset=1',
+ 'text' => E::ts('Add Petition'),
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-plus',
+ 'style' => 'primary',
+ 'condition' => [
+ 'check user permission',
+ 'CONTAINS',
+ ['administer CiviCampaign', 'manage campaign'],
+ ],
+ ],
+ ],
+ 'cssRules' => [
+ [
+ 'disabled',
+ 'is_active',
+ '=',
+ FALSE,
+ ],
+ ],
+ ],
+ 'acl_bypass' => FALSE,
+ ],
+ 'match' => [
+ 'name',
+ 'saved_search_id',
+ ],
+ ],
+ ],
+];
diff --git a/ext/civi_campaign/managed/SavedSearch_Administer_Survey_Options.mgd.php b/ext/civi_campaign/managed/SavedSearch_Administer_Survey_Options.mgd.php
new file mode 100644
index 000000000000..6615e5437451
--- /dev/null
+++ b/ext/civi_campaign/managed/SavedSearch_Administer_Survey_Options.mgd.php
@@ -0,0 +1,101 @@
+ 'SavedSearch_Administer_Survey_Options',
+ 'entity' => 'SavedSearch',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Administer_Survey_Options',
+ 'label' => E::ts('Administer Survey Options'),
+ 'form_values' => NULL,
+ 'mapping_id' => NULL,
+ 'search_custom_id' => NULL,
+ 'api_entity' => 'OptionValue',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => [
+ 'label',
+ 'value',
+ 'filter',
+ ],
+ 'orderBy' => [],
+ 'where' => [],
+ 'groupBy' => [],
+ 'join' => [],
+ 'having' => [],
+ ],
+ 'expires_date' => NULL,
+ 'description' => NULL,
+ ],
+ 'match' => [
+ 'name',
+ ],
+ ],
+ ],
+ [
+ 'name' => 'SavedSearch_Administer_Survey_Options_SearchDisplay_Administer_Survey_Options_Table',
+ 'entity' => 'SearchDisplay',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Administer_Survey_Options_Table',
+ 'label' => E::ts('Administer Survey Options'),
+ 'saved_search_id.name' => 'Administer_Survey_Options',
+ 'type' => 'table',
+ 'settings' => [
+ 'description' => NULL,
+ 'sort' => [],
+ 'limit' => 50,
+ 'actions' => FALSE,
+ 'classes' => [
+ 'table',
+ 'table-striped',
+ ],
+ 'draggable' => 'weight',
+ 'pager' => [
+ 'hide_single' => TRUE,
+ ],
+ 'placeholder' => 5,
+ 'columns' => [
+ [
+ 'type' => 'field',
+ 'key' => 'label',
+ 'dataType' => 'String',
+ 'label' => E::ts('Label'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'value',
+ 'dataType' => 'String',
+ 'label' => E::ts('Value'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'filter',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Recontact Interval'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ ],
+ ],
+ 'acl_bypass' => FALSE,
+ ],
+ 'match' => [
+ 'name',
+ 'saved_search_id',
+ ],
+ ],
+ ],
+];
diff --git a/ext/civi_campaign/managed/SavedSearch_Administer_Surveys.mgd.php b/ext/civi_campaign/managed/SavedSearch_Administer_Surveys.mgd.php
new file mode 100644
index 000000000000..98eafea94093
--- /dev/null
+++ b/ext/civi_campaign/managed/SavedSearch_Administer_Surveys.mgd.php
@@ -0,0 +1,303 @@
+ 'SavedSearch_Administer_Surveys',
+ 'entity' => 'SavedSearch',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Administer_Surveys',
+ 'label' => E::ts('Administer Surveys'),
+ 'form_values' => NULL,
+ 'mapping_id' => NULL,
+ 'search_custom_id' => NULL,
+ 'api_entity' => 'Survey',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => [
+ 'id',
+ 'title',
+ 'campaign_id:label',
+ 'activity_type_id:label',
+ 'release_frequency',
+ 'default_number_of_contacts',
+ 'max_number_of_contacts',
+ 'is_active',
+ 'is_default',
+ 'result_id:label',
+ ],
+ 'orderBy' => [],
+ 'where' => [
+ ['activity_type_id:name', '!=', 'Petition'],
+ ],
+ 'groupBy' => [],
+ 'join' => [],
+ 'having' => [],
+ ],
+ 'expires_date' => NULL,
+ 'description' => NULL,
+ ],
+ 'match' => [
+ 'name',
+ ],
+ ],
+ ],
+ [
+ 'name' => 'SavedSearch_Administer_Surveys_SearchDisplay_Surveys_Table',
+ 'entity' => 'SearchDisplay',
+ 'cleanup' => 'always',
+ 'update' => 'unmodified',
+ 'params' => [
+ 'version' => 4,
+ 'values' => [
+ 'name' => 'Surveys_Table',
+ 'label' => E::ts('Administer Surveys'),
+ 'saved_search_id.name' => 'Administer_Surveys',
+ 'type' => 'table',
+ 'settings' => [
+ 'actions' => FALSE,
+ 'limit' => 50,
+ 'classes' => [
+ 'table',
+ 'table-striped',
+ ],
+ 'pager' => [
+ 'show_count' => FALSE,
+ 'expose_limit' => TRUE,
+ 'hide_single' => TRUE,
+ ],
+ 'placeholder' => 5,
+ 'sort' => [
+ ['is_active', 'DESC'],
+ ['title', 'ASC'],
+ ],
+ 'columns' => [
+ [
+ 'type' => 'field',
+ 'key' => 'title',
+ 'dataType' => 'String',
+ 'label' => E::ts('Title'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'campaign_id:label',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Survey'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'activity_type_id:label',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Type'),
+ 'sortable' => TRUE,
+ 'editable' => TRUE,
+ 'icons' => [
+ [
+ 'field' => 'activity_type_id:icon',
+ 'side' => 'left',
+ ],
+ ],
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'release_frequency',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Release Frequency'),
+ 'sortable' => TRUE,
+ 'empty_value' => '',
+ 'rewrite' => '[release_frequency] Days',
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'default_number_of_contacts',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Reserve Each Time'),
+ 'sortable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'max_number_of_contacts',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Total Reserve'),
+ 'sortable' => TRUE,
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'result_id:label',
+ 'dataType' => 'Integer',
+ 'label' => E::ts('Result Set'),
+ 'sortable' => TRUE,
+ 'link' => [
+ 'path' => 'civicrm/survey/option-group#?option_group_id=[result_id]',
+ 'entity' => '',
+ 'action' => '',
+ 'join' => '',
+ 'target' => 'crm-popup',
+ ],
+ 'empty_value' => E::ts('Incomplete'),
+ 'cssRules' => [
+ [
+ 'bg-danger',
+ 'result_id:label',
+ 'IS EMPTY',
+ ],
+ ],
+ 'rewrite' => E::ts('View Options'),
+ 'icons' => [],
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'is_default',
+ 'dataType' => 'Boolean',
+ 'label' => E::ts('Default'),
+ 'sortable' => TRUE,
+ 'rewrite' => ' ',
+ 'icons' => [
+ [
+ 'icon' => 'fa-check-square-o',
+ 'side' => 'left',
+ 'if' => [
+ 'is_default',
+ '=',
+ TRUE,
+ ],
+ ],
+ ],
+ ],
+ [
+ 'type' => 'field',
+ 'key' => 'is_active',
+ 'dataType' => 'Boolean',
+ 'label' => E::ts('Enabled'),
+ 'sortable' => TRUE,
+ ],
+ [
+ 'size' => 'btn-xs',
+ 'links' => [
+ [
+ 'path' => '',
+ 'icon' => 'fa-pencil',
+ 'text' => E::ts('Edit'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'entity' => 'Survey',
+ 'action' => 'update',
+ 'join' => '',
+ 'target' => '',
+ ],
+ [
+ 'task' => 'enable',
+ 'entity' => 'Survey',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-toggle-on',
+ 'text' => E::ts('Enable'),
+ 'style' => 'default',
+ 'condition' => ['is_active', '=', FALSE],
+ ],
+ [
+ 'task' => 'disable',
+ 'entity' => 'Survey',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-toggle-off',
+ 'text' => E::ts('Disable'),
+ 'style' => 'default',
+ 'condition' => ['is_active', '=', TRUE],
+ ],
+ [
+ 'entity' => 'Survey',
+ 'action' => 'delete',
+ 'join' => '',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-trash',
+ 'text' => E::ts('Delete'),
+ 'style' => 'danger small-popup',
+ 'path' => '',
+ 'condition' => [],
+ ],
+ ],
+ 'type' => 'buttons',
+ 'alignment' => 'text-right',
+ ],
+ [
+ 'text' => E::ts('Respondents'),
+ 'style' => 'default',
+ 'size' => 'btn-xs',
+ 'icon' => 'fa-bars',
+ 'type' => 'menu',
+ 'alignment' => 'text-right',
+ 'links' => [
+ [
+ 'entity' => '',
+ 'action' => '',
+ 'join' => '',
+ 'target' => '_blank',
+ 'icon' => 'fa-user-plus',
+ 'text' => E::ts('Reserve'),
+ 'style' => 'default',
+ 'path' => 'civicrm/survey/search?sid=[id]&reset=1&op=reserve',
+ 'task' => '',
+ 'condition' => [],
+ ],
+ [
+ 'path' => 'civicrm/survey/search?sid=[id]&reset=1&op=interview&force=1',
+ 'icon' => 'fa-clipboard',
+ 'text' => E::ts('Interview'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'task' => '',
+ 'entity' => '',
+ 'action' => '',
+ 'join' => '',
+ 'target' => '_blank',
+ ],
+ [
+ 'path' => 'civicrm/survey/search?sid=[id]&reset=1&op=release&force=1',
+ 'icon' => 'fa-user-times',
+ 'text' => E::ts('Release'),
+ 'style' => 'default',
+ 'condition' => [],
+ 'task' => '',
+ 'entity' => '',
+ 'action' => '',
+ 'join' => '',
+ 'target' => '_blank',
+ ],
+ ],
+ ],
+ ],
+ 'toolbar' => [
+ [
+ 'entity' => 'Survey',
+ 'action' => 'add',
+ 'target' => 'crm-popup',
+ 'icon' => 'fa-plus',
+ 'text' => E::ts('Add Survey'),
+ 'style' => 'primary',
+ ],
+ ],
+ 'cssRules' => [
+ [
+ 'disabled',
+ 'is_active',
+ '=',
+ FALSE,
+ ],
+ ],
+ ],
+ 'acl_bypass' => FALSE,
+ ],
+ 'match' => [
+ 'name',
+ 'saved_search_id',
+ ],
+ ],
+ ],
+];
diff --git a/ext/civi_case/civi_case.php b/ext/civi_case/civi_case.php
index d35d421086a2..43d5b6770615 100644
--- a/ext/civi_case/civi_case.php
+++ b/ext/civi_case/civi_case.php
@@ -17,3 +17,22 @@ function civi_case_civicrm_managed(&$entities, $modules) {
);
}
}
+
+/**
+ * Applies Case permissions to Activities
+ *
+ * @implements CRM_Utils_Hook::selectWhereClause
+ */
+function civi_case_civicrm_selectWhereClause($entityName, &$clauses, $userId, $conditions) {
+ if ($entityName === 'Activity') {
+ // OR group: either it's a non-case activity OR case permissions apply
+ $orGroup = [
+ 'NOT IN (SELECT activity_id FROM civicrm_case_activity)',
+ ];
+ $casePerms = CRM_Utils_SQL::mergeSubquery('Case');
+ if ($casePerms) {
+ $orGroup[] = 'IN (SELECT activity_id FROM civicrm_case_activity WHERE case_id ' . implode(' AND case_id ', $casePerms) . ')';
+ }
+ $clauses['id'][] = $orGroup;
+ }
+}
diff --git a/ext/civi_case/info.xml b/ext/civi_case/info.xml
index 746a4bd1e5d5..7890b7dd5388 100644
--- a/ext/civi_case/info.xml
+++ b/ext/civi_case/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civi_contribute/info.xml b/ext/civi_contribute/info.xml
index 1f4c64b3a179..dc12f1431cd5 100644
--- a/ext/civi_contribute/info.xml
+++ b/ext/civi_contribute/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventCreationSpecProvider.php b/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventCreationSpecProvider.php
index 5a31a2419353..3b3af3681cc8 100644
--- a/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventCreationSpecProvider.php
+++ b/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventCreationSpecProvider.php
@@ -29,6 +29,8 @@ public function modifySpec(RequestSpec $spec) {
$spec->getFieldByName('title')->setRequiredIf('empty($values.is_template)');
$spec->getFieldByName('start_date')->setRequiredIf('empty($values.is_template)');
$spec->getFieldByName('template_title')->setRequiredIf('!empty($values.is_template)');
+ // Arguably this is a bad default in the schema
+ $spec->getFieldByName('is_active')->setRequired(FALSE)->setDefaultValue(TRUE);
$template_id = (new FieldSpec('template_id', 'Event', 'Integer'))
->setTitle(ts('Event Template'))
diff --git a/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventGetSpecProvider.php b/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventGetSpecProvider.php
new file mode 100644
index 000000000000..3c32afc7a9ae
--- /dev/null
+++ b/ext/civi_event/Civi/Api4/Service/Spec/Provider/EventGetSpecProvider.php
@@ -0,0 +1,59 @@
+setTitle(ts('Remaining Participants'))
+ ->setDescription(ts('Maximum participants minus registered participants'))
+ ->setInputType('Number')
+ ->setColumnName('max_participants')
+ ->setSqlRenderer([__CLASS__, 'getRemainingParticipants']);
+ $spec->addFieldSpec($field);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function applies($entity, $action) {
+ return $entity === 'Event' && $action === 'get';
+ }
+
+ /**
+ * Subtracts max_participants from number of counted (non-test, non-deleted) participants.
+ *
+ * @param array $maxField
+ * @param \Civi\Api4\Query\Api4SelectQuery $query
+ * return string
+ */
+ public static function getRemainingParticipants(array $maxField, Api4SelectQuery $query): string {
+ $statuses = \CRM_Event_PseudoConstant::participantStatus(NULL, 'is_counted = 1');
+ $statusIds = implode(',', array_keys($statuses));
+ $idField = $query->getFieldSibling($maxField, 'id');
+ return "IF($maxField[sql_name], (CAST($maxField[sql_name] AS SIGNED) - (SELECT COUNT(`p`.`id`) FROM `civicrm_participant` `p`, `civicrm_contact` `c` WHERE `p`.`event_id` = $idField[sql_name] AND `p`.`contact_id` = `c`.`id` AND `p`.`is_test` = 0 AND `c`.`is_deleted` = 0 AND `p`.status_id IN ($statusIds))), NULL)";
+ }
+
+}
diff --git a/ext/civi_event/info.xml b/ext/civi_event/info.xml
index 5b84e467af1f..855c8bc27e55 100644
--- a/ext/civi_event/info.xml
+++ b/ext/civi_event/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civi_mail/info.xml b/ext/civi_mail/info.xml
index 9bddead50ffd..f718531b1f8e 100644
--- a/ext/civi_mail/info.xml
+++ b/ext/civi_mail/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civi_member/info.xml b/ext/civi_member/info.xml
index 36b0e4bc4b98..ad35cbf93dbe 100644
--- a/ext/civi_member/info.xml
+++ b/ext/civi_member/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civi_pledge/info.xml b/ext/civi_pledge/info.xml
index 93597d6996b0..380e5ded5840 100644
--- a/ext/civi_pledge/info.xml
+++ b/ext/civi_pledge/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civi_report/info.xml b/ext/civi_report/info.xml
index 90e073060bda..b58133a7eec1 100644
--- a/ext/civi_report/info.xml
+++ b/ext/civi_report/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-04-08
- 5.67.alpha1
+ 5.68.alpha1
stable
component
- 5.67
+ 5.68
Core Component
CRM_Extension_Upgrader_Component
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminContactTypes.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdminContactTypes.aff.json
deleted file mode 100644
index 902c469d7f2a..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdminContactTypes.aff.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "type": "search",
- "title": "Contact Types",
- "description": "Administer contact types and sub-types",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/options/subtype",
- "permission": "access CiviCRM"
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminContactTypes.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdminContactTypes.aff.php
new file mode 100644
index 000000000000..b10d7e5754ac
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdminContactTypes.aff.php
@@ -0,0 +1,11 @@
+ 'search',
+ 'title' => E::ts('Contact Types'),
+ 'description' => E::ts('Administer contact types and sub-types'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/options/subtype',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminCustomFields.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdminCustomFields.aff.json
deleted file mode 100644
index 185667191eaf..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdminCustomFields.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Fields",
- "description": "Administer custom fields list",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/custom/group/fields",
- "permission": "administer CiviCRM data",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminCustomFields.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdminCustomFields.aff.php
new file mode 100644
index 000000000000..4ac083954a4c
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdminCustomFields.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Fields'),
+ 'description' => E::ts('Administer custom fields list'),
+ 'server_route' => 'civicrm/admin/custom/group/fields',
+ 'permission' => ['administer CiviCRM data'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminCustomGroups.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdminCustomGroups.aff.json
deleted file mode 100644
index 449a7e5f6583..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdminCustomGroups.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Custom Field Groups",
- "description": "Administer custom field groups list",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/custom/group",
- "permission": "administer CiviCRM data",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminCustomGroups.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdminCustomGroups.aff.php
new file mode 100644
index 000000000000..5a5ab28623c7
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdminCustomGroups.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Custom Field Groups'),
+ 'description' => E::ts('Administer custom field groups list'),
+ 'server_route' => 'civicrm/admin/custom/group',
+ 'permission' => ['administer CiviCRM data'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminFinancialTypes.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdminFinancialTypes.aff.json
deleted file mode 100644
index fb689cbac641..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdminFinancialTypes.aff.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "type": "search",
- "title": "Financial Types",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/financial/financialType",
- "permission": "administer CiviCRM",
- "requires": [],
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "entity_type": null,
- "join_entity": null,
- "contact_summary": null,
- "redirect": null,
- "create_submission": null,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminFinancialTypes.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdminFinancialTypes.aff.php
new file mode 100644
index 000000000000..962b9b69dd37
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdminFinancialTypes.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Financial Types'),
+ 'server_route' => 'civicrm/admin/financial/financialType',
+ 'permission' => ['administer CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminScheduledReminders.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdminScheduledReminders.aff.json
deleted file mode 100644
index 36136fa0be35..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdminScheduledReminders.aff.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "type": "search",
- "title": "Scheduled Reminders",
- "description": "Administer scheduled reminders",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/scheduleReminders",
- "permission": "administer CiviCRM data"
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdminScheduledReminders.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdminScheduledReminders.aff.php
new file mode 100644
index 000000000000..ba517ce1d2df
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdminScheduledReminders.aff.php
@@ -0,0 +1,11 @@
+ 'search',
+ 'title' => E::ts('Scheduled Reminders'),
+ 'description' => E::ts('Administer scheduled reminders'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/scheduleReminders',
+ 'permission' => ['administer CiviCRM data'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdministerLocationTypes.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdministerLocationTypes.aff.json
deleted file mode 100644
index 04f482bc209e..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdministerLocationTypes.aff.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "search",
- "title": "Location Types",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/locationType",
- "permission": "administer CiviCRM"
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdministerLocationTypes.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdministerLocationTypes.aff.php
new file mode 100644
index 000000000000..dc57cde4d051
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdministerLocationTypes.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Location Types'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/locationType',
+ 'permission' => ['administer CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdministerPaymentProcessors.aff.json b/ext/civicrm_admin_ui/ang/afsearchAdministerPaymentProcessors.aff.json
deleted file mode 100644
index de7115a392af..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAdministerPaymentProcessors.aff.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "search",
- "title": "Administer Payment Processors",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/paymentProcessor",
- "permission": "administer payment processors"
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAdministerPaymentProcessors.aff.php b/ext/civicrm_admin_ui/ang/afsearchAdministerPaymentProcessors.aff.php
new file mode 100644
index 000000000000..1982c9b5e96a
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAdministerPaymentProcessors.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Administer Payment Processors'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/paymentProcessor',
+ 'permission' => ['administer payment processors'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAssignUsersToRoles.aff.json b/ext/civicrm_admin_ui/ang/afsearchAssignUsersToRoles.aff.json
deleted file mode 100644
index 189261d8964f..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAssignUsersToRoles.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Assign Users to Roles",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/acl/entityrole",
- "permission": "administer CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAssignUsersToRoles.aff.php b/ext/civicrm_admin_ui/ang/afsearchAssignUsersToRoles.aff.php
new file mode 100644
index 000000000000..bdab1bcc2b9c
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAssignUsersToRoles.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Assign Users to Roles'),
+ 'server_route' => 'civicrm/acl/entityrole',
+ 'permission' => ['administer CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchAssignedFinancialAccounts.aff.json b/ext/civicrm_admin_ui/ang/afsearchAssignedFinancialAccounts.aff.json
deleted file mode 100644
index 30fbd772c6fd..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchAssignedFinancialAccounts.aff.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "type": "search",
- "title": "Assigned Financial Accounts",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/financial/financialType/accounts/list",
- "permission": "administer CiviCRM",
- "requires": [],
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "entity_type": null,
- "join_entity": null,
- "contact_summary": null,
- "redirect": null,
- "create_submission": null,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchAssignedFinancialAccounts.aff.php b/ext/civicrm_admin_ui/ang/afsearchAssignedFinancialAccounts.aff.php
new file mode 100644
index 000000000000..161225a32a1d
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchAssignedFinancialAccounts.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Assigned Financial Accounts'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/financial/financialType/accounts/list',
+ 'permission' => ['administer CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchFinancialAccounts.aff.json b/ext/civicrm_admin_ui/ang/afsearchFinancialAccounts.aff.json
deleted file mode 100644
index b675e79b84eb..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchFinancialAccounts.aff.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "type": "search",
- "title": "Financial Accounts",
- "description": "Administer Financial Accounts",
- "is_public": false,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/financial/financialAccount",
- "permission": "administer CiviCRM"
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchFinancialAccounts.aff.php b/ext/civicrm_admin_ui/ang/afsearchFinancialAccounts.aff.php
new file mode 100644
index 000000000000..4d5a52999766
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchFinancialAccounts.aff.php
@@ -0,0 +1,12 @@
+ 'search',
+ 'title' => E::ts('Financial Accounts'),
+ 'description' => E::ts('Administer Financial Accounts'),
+ 'is_public' => FALSE,
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/financial/financialAccount',
+ 'permission' => ['administer CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchMailAccounts.aff.json b/ext/civicrm_admin_ui/ang/afsearchMailAccounts.aff.json
deleted file mode 100644
index 19168345dae0..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchMailAccounts.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "title": "Mail Accounts",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/mailSettings",
- "permission": "administer CiviCRM",
- "requires": [],
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "entity_type": null,
- "join_entity": null,
- "contact_summary": null,
- "summary_contact_type": null,
- "redirect": null,
- "create_submission": null,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchMailAccounts.aff.php b/ext/civicrm_admin_ui/ang/afsearchMailAccounts.aff.php
new file mode 100644
index 000000000000..b0e774557bf1
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchMailAccounts.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Mail Accounts'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/mailSettings',
+ 'permission' => ['administer CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageACLs.aff.json b/ext/civicrm_admin_ui/ang/afsearchManageACLs.aff.json
deleted file mode 100644
index 9c7f2567ab67..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchManageACLs.aff.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "type": "search",
- "title": "Manage ACLs",
- "icon": "fa-list-alt",
- "server_route": "civicrm/acl",
- "permission": "administer CiviCRM",
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageACLs.aff.php b/ext/civicrm_admin_ui/ang/afsearchManageACLs.aff.php
new file mode 100644
index 000000000000..c99bee4b4168
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchManageACLs.aff.php
@@ -0,0 +1,11 @@
+ 'search',
+ 'title' => E::ts('Manage ACLs'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/acl',
+ 'permission' => ['administer CiviCRM'],
+ 'navigation' => NULL,
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageContributionPages.aff.json b/ext/civicrm_admin_ui/ang/afsearchManageContributionPages.aff.json
deleted file mode 100644
index 06408ef48c21..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchManageContributionPages.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Manage Contribution Pages",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/contribute",
- "permission": "access CiviContribute",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageContributionPages.aff.php b/ext/civicrm_admin_ui/ang/afsearchManageContributionPages.aff.php
new file mode 100644
index 000000000000..543c71ca772f
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchManageContributionPages.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Manage Contribution Pages'),
+ 'server_route' => 'civicrm/admin/contribute',
+ 'permission' => ['access CiviContribute'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageGroups.aff.json b/ext/civicrm_admin_ui/ang/afsearchManageGroups.aff.json
deleted file mode 100644
index cd904460ade2..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchManageGroups.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "title": "Manage Groups",
- "icon": "fa-list-alt",
- "server_route": "civicrm/group",
- "permission": "access CiviCRM",
- "requires": [],
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "entity_type": null,
- "join_entity": null,
- "contact_summary": null,
- "summary_contact_type": null,
- "redirect": null,
- "create_submission": null,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageGroups.aff.php b/ext/civicrm_admin_ui/ang/afsearchManageGroups.aff.php
new file mode 100644
index 000000000000..fd8f7811c53c
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchManageGroups.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Manage Groups'),
+ 'server_route' => 'civicrm/group',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageScheduledJobs.aff.json b/ext/civicrm_admin_ui/ang/afsearchManageScheduledJobs.aff.json
deleted file mode 100644
index 4aebf05131b4..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchManageScheduledJobs.aff.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "search",
- "title": "Manage Scheduled Jobs",
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/job",
- "permission": "access CiviCRM"
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchManageScheduledJobs.aff.php b/ext/civicrm_admin_ui/ang/afsearchManageScheduledJobs.aff.php
new file mode 100644
index 000000000000..6916dfd6c3e1
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchManageScheduledJobs.aff.php
@@ -0,0 +1,10 @@
+ 'search',
+ 'title' => E::ts('Manage Scheduled Jobs'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/admin/job',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchProfileFields.aff.json b/ext/civicrm_admin_ui/ang/afsearchProfileFields.aff.json
deleted file mode 100644
index 050dd2d1bf8f..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchProfileFields.aff.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Profile Fields",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/uf/group/field",
- "permission": "access CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchProfileFields.aff.php b/ext/civicrm_admin_ui/ang/afsearchProfileFields.aff.php
new file mode 100644
index 000000000000..76b7e6209084
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchProfileFields.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Profile Fields'),
+ 'server_route' => 'civicrm/admin/uf/group/field',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchProfiles.aff.json b/ext/civicrm_admin_ui/ang/afsearchProfiles.aff.json
deleted file mode 100644
index 9be0002e901c..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchProfiles.aff.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Profiles",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/uf/group",
- "permission": "access CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchProfiles.aff.php b/ext/civicrm_admin_ui/ang/afsearchProfiles.aff.php
new file mode 100644
index 000000000000..2fe4688d38f8
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchProfiles.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Profiles'),
+ 'server_route' => 'civicrm/admin/uf/group',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchRelationshipTypes.aff.json b/ext/civicrm_admin_ui/ang/afsearchRelationshipTypes.aff.json
deleted file mode 100644
index 58bc820a2f59..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchRelationshipTypes.aff.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Relationship Types",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/reltype",
- "permission": "access CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchRelationshipTypes.aff.php b/ext/civicrm_admin_ui/ang/afsearchRelationshipTypes.aff.php
new file mode 100644
index 000000000000..69236a7dc20e
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchRelationshipTypes.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Relationship Types'),
+ 'server_route' => 'civicrm/admin/reltype',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.html b/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.html
index c29768ddc130..2b596924efa1 100644
--- a/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.html
+++ b/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.html
@@ -2,12 +2,14 @@
-
+
diff --git a/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.json b/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.json
deleted file mode 100644
index 3bde1de42ddf..000000000000
--- a/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Scheduled Jobs Log",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/admin/joblog",
- "permission": "admin CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": null
-}
diff --git a/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.php b/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.php
new file mode 100644
index 000000000000..6a8d7b40e084
--- /dev/null
+++ b/ext/civicrm_admin_ui/ang/afsearchScheduledJobsLog.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Scheduled Jobs Log'),
+ 'server_route' => 'civicrm/admin/joblog',
+ 'permission' => ['admin CiviCRM'],
+];
diff --git a/ext/civicrm_admin_ui/info.xml b/ext/civicrm_admin_ui/info.xml
index 6eccca49a67a..03797673988c 100644
--- a/ext/civicrm_admin_ui/info.xml
+++ b/ext/civicrm_admin_ui/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2022-01-02
- 5.67.alpha1
+ 5.68.alpha1
beta
- 5.67
+ 5.68
org.civicrm.search_kit
diff --git a/ext/civicrm_admin_ui/managed/SavedSearch_Administer_Custom_Groups.mgd.php b/ext/civicrm_admin_ui/managed/SavedSearch_Administer_Custom_Groups.mgd.php
index 6fc669b84758..28d95458c44a 100644
--- a/ext/civicrm_admin_ui/managed/SavedSearch_Administer_Custom_Groups.mgd.php
+++ b/ext/civicrm_admin_ui/managed/SavedSearch_Administer_Custom_Groups.mgd.php
@@ -124,7 +124,7 @@
'dataType' => 'String',
'label' => E::ts('Fields'),
'sortable' => TRUE,
- 'rewrite' => "{capture assign=fields}[GROUP_CONCAT_CustomGroup_CustomField_custom_group_id_01_label]{/capture}{ \$fields|replace:',':' '}",
+ 'rewrite' => "{capture assign=fields}[GROUP_CONCAT_CustomGroup_CustomField_custom_group_id_01_label]{/capture}{\$fields|replace:',':' '}",
],
[
'size' => 'btn-xs',
diff --git a/ext/civicrm_admin_ui/managed/SavedSearch_Manage_Scheduled_Jobs.mgd.php b/ext/civicrm_admin_ui/managed/SavedSearch_Manage_Scheduled_Jobs.mgd.php
index 8e97c1cfb56c..261b8f696760 100644
--- a/ext/civicrm_admin_ui/managed/SavedSearch_Manage_Scheduled_Jobs.mgd.php
+++ b/ext/civicrm_admin_ui/managed/SavedSearch_Manage_Scheduled_Jobs.mgd.php
@@ -167,7 +167,7 @@
'icon' => 'fa-file-o',
'text' => E::ts('View joblog'),
'style' => 'default',
- 'path' => 'civicrm/admin/joblog?jid=[id]&reset=1',
+ 'path' => 'civicrm/admin/joblog#?job_id=[id]',
'condition' => [],
],
[
diff --git a/ext/civicrm_search_ui/ang/afsearchContactSearch.aff.json b/ext/civicrm_search_ui/ang/afsearchContactSearch.aff.json
deleted file mode 100644
index f56ff6fda189..000000000000
--- a/ext/civicrm_search_ui/ang/afsearchContactSearch.aff.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "search",
- "title": "Find Contacts",
- "icon": "fa-list-alt",
- "server_route": "civicrm/searchui/contact/search",
- "permission": "access CiviCRM",
- "navigation": null,
- "requires": [],
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "entity_type": null,
- "join_entity": null,
- "contact_summary": null,
- "summary_contact_type": null,
- "redirect": null,
- "create_submission": null
-}
diff --git a/ext/civicrm_search_ui/ang/afsearchContactSearch.aff.php b/ext/civicrm_search_ui/ang/afsearchContactSearch.aff.php
new file mode 100644
index 000000000000..4c77d94aff42
--- /dev/null
+++ b/ext/civicrm_search_ui/ang/afsearchContactSearch.aff.php
@@ -0,0 +1,9 @@
+ 'search',
+ 'title' => E::ts('Find Contacts'),
+ 'server_route' => 'civicrm/searchui/contact/search',
+ 'permission' => ['access CiviCRM'],
+];
diff --git a/ext/civicrm_search_ui/ang/afsearchFindContributions.aff.json b/ext/civicrm_search_ui/ang/afsearchFindContributions.aff.json
deleted file mode 100644
index f5dbd9da554f..000000000000
--- a/ext/civicrm_search_ui/ang/afsearchFindContributions.aff.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Find Contributions",
- "description": "The original searches for Contributions but also can show just soft credits and recurring contributions. Maybe recur is better as a separate search? And soft credits?",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-credit-card",
- "server_route": "civicrm/sk/contrib",
- "permission": "access CiviContribute",
- "redirect": null,
- "create_submission": false,
- "navigation": {
- "parent": "Experimental",
- "label": "Find Contributions",
- "weight": 0
- }
-}
diff --git a/ext/civicrm_search_ui/ang/afsearchFindContributions.aff.php b/ext/civicrm_search_ui/ang/afsearchFindContributions.aff.php
new file mode 100644
index 000000000000..2d9ee5553737
--- /dev/null
+++ b/ext/civicrm_search_ui/ang/afsearchFindContributions.aff.php
@@ -0,0 +1,16 @@
+ 'search',
+ 'title' => E::ts('Find Contributions'),
+ 'description' => 'The original searches for Contributions but also can show just soft credits and recurring contributions. Maybe recur is better as a separate search? And soft credits?',
+ 'icon' => 'fa-credit-card',
+ 'server_route' => 'civicrm/sk/contrib',
+ 'permission' => ['access CiviContribute'],
+ 'navigation' => [
+ 'parent' => 'Experimental',
+ 'label' => E::ts('Find Contributions'),
+ 'weight' => 0,
+ ],
+];
diff --git a/ext/civicrm_search_ui/info.xml b/ext/civicrm_search_ui/info.xml
index 4f4bfbd12c8e..0aa6af2c085b 100644
--- a/ext/civicrm_search_ui/info.xml
+++ b/ext/civicrm_search_ui/info.xml
@@ -15,14 +15,14 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-07-17
- 5.67.alpha1
+ 5.68.alpha1
alpha
org.civicrm.search_kit
org.civicrm.afform
- 5.67
+ 5.68
Replacement SearchKit/FormBuilder pages for core Search pages.
diff --git a/ext/civicrm_search_ui/managed/Navigation_Experimental.mgd.php b/ext/civicrm_search_ui/managed/Navigation_Experimental.mgd.php
index 94a6191f3bf0..c43b0b5623cb 100644
--- a/ext/civicrm_search_ui/managed/Navigation_Experimental.mgd.php
+++ b/ext/civicrm_search_ui/managed/Navigation_Experimental.mgd.php
@@ -6,7 +6,7 @@
[
'name' => 'Navigation_Experimental',
'entity' => 'Navigation',
- 'cleanup' => 'unused',
+ 'cleanup' => 'always',
'update' => 'unmodified',
'params' => [
'version' => 4,
@@ -20,7 +20,7 @@
'access CiviCRM',
],
'permission_operator' => 'AND',
- 'parent_id' => NULL,
+ 'parent_id.name' => 'Search',
'is_active' => TRUE,
'has_separator' => 0,
'weight' => 113,
diff --git a/ext/civigrant/ang/afsearchTabGrant.aff.json b/ext/civigrant/ang/afsearchTabGrant.aff.json
deleted file mode 100644
index 283f23b07ab6..000000000000
--- a/ext/civigrant/ang/afsearchTabGrant.aff.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "type": "search",
- "title": "Grants",
- "contact_summary": "tab",
- "summary_weight": 60,
- "icon": "fa-money",
- "server_route": "",
- "permission": "access CiviGrant"
-}
diff --git a/ext/civigrant/ang/afsearchTabGrant.aff.php b/ext/civigrant/ang/afsearchTabGrant.aff.php
new file mode 100644
index 000000000000..ae187701c0d0
--- /dev/null
+++ b/ext/civigrant/ang/afsearchTabGrant.aff.php
@@ -0,0 +1,12 @@
+ 'search',
+ 'title' => E::ts('Grants'),
+ 'placement' => ['contact_summary_tab'],
+ 'summary_weight' => 60,
+ 'icon' => 'fa-money',
+ 'server_route' => '',
+ 'permission' => ['access CiviGrant'],
+];
diff --git a/ext/civigrant/info.xml b/ext/civigrant/info.xml
index 8f3733c75b09..afa152e1a07e 100644
--- a/ext/civigrant/info.xml
+++ b/ext/civigrant/info.xml
@@ -13,10 +13,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2021-11-11
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
CiviGrant was originally a core component before migrating to an extension
diff --git a/ext/civiimport/Civi/Api4/Event/Subscriber/ImportSubscriber.php b/ext/civiimport/Civi/Api4/Event/Subscriber/ImportSubscriber.php
index b27d9d4470ff..5709bd5a28bb 100644
--- a/ext/civiimport/Civi/Api4/Event/Subscriber/ImportSubscriber.php
+++ b/ext/civiimport/Civi/Api4/Event/Subscriber/ImportSubscriber.php
@@ -226,9 +226,6 @@ public static function getImportForms(): array {
'type' => 'search',
'title' => $importSearch['label'],
'base_module' => E::LONG_NAME,
- 'is_dashlet' => FALSE,
- 'is_public' => FALSE,
- 'is_token' => FALSE,
'permission' => 'access CiviCRM',
'requires' => ['crmSearchDisplayTable'],
'layout' => '
diff --git a/ext/civiimport/ang/afsearchAllImports.aff.json b/ext/civiimport/ang/afsearchAllImports.aff.json
deleted file mode 100644
index 92f44df97414..000000000000
--- a/ext/civiimport/ang/afsearchAllImports.aff.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "All Imports",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/imports/all-imports",
- "permission": "administer queues",
- "redirect": null,
- "create_submission": false,
- "navigation": {
- "parent": "Reports",
- "label": "All imports",
- "weight": 17
- }
-}
diff --git a/ext/civiimport/ang/afsearchAllImports.aff.php b/ext/civiimport/ang/afsearchAllImports.aff.php
new file mode 100644
index 000000000000..c2302fb19789
--- /dev/null
+++ b/ext/civiimport/ang/afsearchAllImports.aff.php
@@ -0,0 +1,15 @@
+ 'search',
+ 'title' => E::ts('All Imports'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/imports/all-imports',
+ 'permission' => ['administer queues'],
+ 'navigation' => [
+ 'parent' => 'Reports',
+ 'label' => E::ts('All imports'),
+ 'weight' => 17,
+ ],
+];
diff --git a/ext/civiimport/ang/afsearchMyImports.aff.json b/ext/civiimport/ang/afsearchMyImports.aff.json
deleted file mode 100644
index a574500353c7..000000000000
--- a/ext/civiimport/ang/afsearchMyImports.aff.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "My Imports",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/imports/my-listing",
- "permission": "access CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": {
- "parent": "Reports",
- "label": "My Imports",
- "weight": 15
- }
-}
diff --git a/ext/civiimport/ang/afsearchMyImports.aff.php b/ext/civiimport/ang/afsearchMyImports.aff.php
new file mode 100644
index 000000000000..9b6c975cb7b9
--- /dev/null
+++ b/ext/civiimport/ang/afsearchMyImports.aff.php
@@ -0,0 +1,14 @@
+ 'search',
+ 'title' => E::ts('My Imports'),
+ 'server_route' => 'civicrm/imports/my-listing',
+ 'permission' => ['access CiviCRM'],
+ 'navigation' => [
+ 'parent' => 'Reports',
+ 'label' => E::ts('My Imports'),
+ 'weight' => 15,
+ ],
+];
diff --git a/ext/civiimport/ang/afsearchTemplates.aff.json b/ext/civiimport/ang/afsearchTemplates.aff.json
deleted file mode 100644
index 6948f1d48b35..000000000000
--- a/ext/civiimport/ang/afsearchTemplates.aff.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "type": "search",
- "requires": [],
- "entity_type": null,
- "join_entity": null,
- "title": "Import Templates",
- "description": "",
- "is_dashlet": false,
- "is_public": false,
- "is_token": false,
- "contact_summary": null,
- "summary_contact_type": null,
- "icon": "fa-list-alt",
- "server_route": "civicrm/imports/templates",
- "permission": "access CiviCRM",
- "redirect": null,
- "create_submission": false,
- "navigation": {
- "parent": "Reports",
- "label": "Import Templates",
- "weight": 16
- }
-}
diff --git a/ext/civiimport/ang/afsearchTemplates.aff.php b/ext/civiimport/ang/afsearchTemplates.aff.php
new file mode 100644
index 000000000000..d2329bca3592
--- /dev/null
+++ b/ext/civiimport/ang/afsearchTemplates.aff.php
@@ -0,0 +1,15 @@
+ 'search',
+ 'title' => E::ts('Import Templates'),
+ 'icon' => 'fa-list-alt',
+ 'server_route' => 'civicrm/imports/templates',
+ 'permission' => ['access CiviCRM'],
+ 'navigation' => [
+ 'parent' => 'Reports',
+ 'label' => E::ts('Import Templates'),
+ 'weight' => 16,
+ ],
+];
diff --git a/ext/civiimport/civiimport.civix.php b/ext/civiimport/civiimport.civix.php
index c912ca5bcfee..7e45e4530a30 100644
--- a/ext/civiimport/civiimport.civix.php
+++ b/ext/civiimport/civiimport.civix.php
@@ -133,8 +133,8 @@ function _civiimport_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/civiimport/info.xml b/ext/civiimport/info.xml
index 2e9d47ad07d3..f2865dc05d2a 100644
--- a/ext/civiimport/info.xml
+++ b/ext/civiimport/info.xml
@@ -15,12 +15,12 @@
http://www.gnu.org/licenses/agpl-3.0.html
2022-08-11
-
5.67.alpha1
+
5.68.alpha1
alpha
- 5.67
+ 5.68
-
Core extension for us to start moving import logic into, has more functionality
+
This extension contains import functionality which was previously in CiviCRM Core. If you use the import functionality it is recommended to enable this extension.
org.civicrm.afform
org.civicrm.search_kit
@@ -31,7 +31,7 @@
CRM/Civiimport
- 23.02.0
+ 23.02.1
crmCiviimport
@@ -39,6 +39,6 @@
scan-classes@1.0.0
setting-php@1.0.0
ang-php@1.0.0
- smarty-v2@1.0.0
+ smarty-v2@1.0.1
diff --git a/ext/ckeditor4/ckeditor4.civix.php b/ext/ckeditor4/ckeditor4.civix.php
index 39aa238b6717..8465f04a1dbc 100644
--- a/ext/ckeditor4/ckeditor4.civix.php
+++ b/ext/ckeditor4/ckeditor4.civix.php
@@ -133,8 +133,8 @@ function _ckeditor4_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/ckeditor4/info.xml b/ext/ckeditor4/info.xml
index a30862458432..a922e4846bf1 100644
--- a/ext/ckeditor4/info.xml
+++ b/ext/ckeditor4/info.xml
@@ -15,10 +15,10 @@
https://www.gnu.org/licenses/agpl-3.0.html
2021-05-23
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
This is the version of CKEditor that originally shipped with CiviCRM core
@@ -27,11 +27,11 @@
menu-xml@1.0.0
- smarty-v2@1.0.0
+ smarty-v2@1.0.1
CRM/Ckeditor4
- 23.02.0
+ 23.02.1
CRM_Ckeditor4_Upgrader
diff --git a/ext/ckeditor4/templates/CRM/Ckeditor4/Form/CKEditorConfig.tpl b/ext/ckeditor4/templates/CRM/Ckeditor4/Form/CKEditorConfig.tpl
index ae51de9d1815..47e8f4f744d3 100644
--- a/ext/ckeditor4/templates/CRM/Ckeditor4/Form/CKEditorConfig.tpl
+++ b/ext/ckeditor4/templates/CRM/Ckeditor4/Form/CKEditorConfig.tpl
@@ -47,7 +47,7 @@
{/literal}
{* Force the custom config file to reload by appending a new query string *}
diff --git a/ext/contributioncancelactions/contributioncancelactions.civix.php b/ext/contributioncancelactions/contributioncancelactions.civix.php
index f78d349348f2..fa52d8fda4c1 100644
--- a/ext/contributioncancelactions/contributioncancelactions.civix.php
+++ b/ext/contributioncancelactions/contributioncancelactions.civix.php
@@ -84,27 +84,17 @@ public static function findClass($suffix) {
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config
*/
-function _contributioncancelactions_civix_civicrm_config(&$config = NULL) {
+function _contributioncancelactions_civix_civicrm_config($config = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
- $template = CRM_Core_Smarty::singleton();
-
$extRoot = __DIR__ . DIRECTORY_SEPARATOR;
- $extDir = $extRoot . 'templates';
-
- if (is_array($template->template_dir)) {
- array_unshift($template->template_dir, $extDir);
- }
- else {
- $template->template_dir = [$extDir, $template->template_dir];
- }
-
$include_path = $extRoot . PATH_SEPARATOR . get_include_path();
set_include_path($include_path);
+ // Based on
, this does not currently require mixin/polyfill.php.
}
/**
@@ -114,35 +104,7 @@ function _contributioncancelactions_civix_civicrm_config(&$config = NULL) {
*/
function _contributioncancelactions_civix_civicrm_install() {
_contributioncancelactions_civix_civicrm_config();
- if ($upgrader = _contributioncancelactions_civix_upgrader()) {
- $upgrader->onInstall();
- }
-}
-
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function _contributioncancelactions_civix_civicrm_postInstall() {
- _contributioncancelactions_civix_civicrm_config();
- if ($upgrader = _contributioncancelactions_civix_upgrader()) {
- if (is_callable([$upgrader, 'onPostInstall'])) {
- $upgrader->onPostInstall();
- }
- }
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function _contributioncancelactions_civix_civicrm_uninstall(): void {
- _contributioncancelactions_civix_civicrm_config();
- if ($upgrader = _contributioncancelactions_civix_upgrader()) {
- $upgrader->onUninstall();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -152,56 +114,7 @@ function _contributioncancelactions_civix_civicrm_uninstall(): void {
*/
function _contributioncancelactions_civix_civicrm_enable(): void {
_contributioncancelactions_civix_civicrm_config();
- if ($upgrader = _contributioncancelactions_civix_upgrader()) {
- if (is_callable([$upgrader, 'onEnable'])) {
- $upgrader->onEnable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- * @return mixed
- */
-function _contributioncancelactions_civix_civicrm_disable(): void {
- _contributioncancelactions_civix_civicrm_config();
- if ($upgrader = _contributioncancelactions_civix_upgrader()) {
- if (is_callable([$upgrader, 'onDisable'])) {
- $upgrader->onDisable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_upgrade().
- *
- * @param $op string, the type of operation being performed; 'check' or 'enqueue'
- * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
- *
- * @return mixed
- * based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
- * for 'enqueue', returns void
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function _contributioncancelactions_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- if ($upgrader = _contributioncancelactions_civix_upgrader()) {
- return $upgrader->onUpgrade($op, $queue);
- }
-}
-
-/**
- * @return CRM_Contributioncancelactions_Upgrader
- */
-function _contributioncancelactions_civix_upgrader() {
- if (!file_exists(__DIR__ . '/CRM/Contributioncancelactions/Upgrader.php')) {
- return NULL;
- }
- else {
- return CRM_Contributioncancelactions_Upgrader_Base::instance();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -220,8 +133,8 @@ function _contributioncancelactions_civix_insert_navigation_menu(&$menu, $path,
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
@@ -285,14 +198,3 @@ function _contributioncancelactions_civix_fixNavigationMenuItems(&$nodes, &$maxN
}
}
}
-
-/**
- * (Delegated) Implements hook_civicrm_entityTypes().
- *
- * Find any *.entityType.php files, merge their content, and return.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function _contributioncancelactions_civix_civicrm_entityTypes(&$entityTypes) {
- $entityTypes = array_merge($entityTypes, []);
-}
diff --git a/ext/contributioncancelactions/info.xml b/ext/contributioncancelactions/info.xml
index 0cb51b5df363..4fed5ff1c824 100644
--- a/ext/contributioncancelactions/info.xml
+++ b/ext/contributioncancelactions/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2020-10-12
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
This code has been moved from core to a separate extension in 5.32. Note that if you disable it failed or cancelled contributions will not cause related memberships and participant records to be updated
@@ -27,6 +27,6 @@
CRM/Contributioncancelactions
- 22.10.0
+ 23.02.1
diff --git a/ext/contributioncancelactions/tests/phpunit/bootstrap.php b/ext/contributioncancelactions/tests/phpunit/bootstrap.php
index 5133778c8191..63c9148e8e1c 100644
--- a/ext/contributioncancelactions/tests/phpunit/bootstrap.php
+++ b/ext/contributioncancelactions/tests/phpunit/bootstrap.php
@@ -26,7 +26,7 @@
*/
function cv($cmd, $decode = 'json') {
$cmd = 'cv ' . $cmd;
- $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+ $descriptorSpec = [0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => STDERR];
$oldOutput = getenv('CV_OUTPUT');
putenv("CV_OUTPUT=json");
diff --git a/ext/elavon/elavon.civix.php b/ext/elavon/elavon.civix.php
index 22f149e02912..e26bb291b843 100644
--- a/ext/elavon/elavon.civix.php
+++ b/ext/elavon/elavon.civix.php
@@ -84,27 +84,17 @@ public static function findClass($suffix) {
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config
*/
-function _elavon_civix_civicrm_config(&$config = NULL) {
+function _elavon_civix_civicrm_config($config = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
- $template = CRM_Core_Smarty::singleton();
-
$extRoot = __DIR__ . DIRECTORY_SEPARATOR;
- $extDir = $extRoot . 'templates';
-
- if (is_array($template->template_dir)) {
- array_unshift($template->template_dir, $extDir);
- }
- else {
- $template->template_dir = [$extDir, $template->template_dir];
- }
-
$include_path = $extRoot . PATH_SEPARATOR . get_include_path();
set_include_path($include_path);
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -114,35 +104,7 @@ function _elavon_civix_civicrm_config(&$config = NULL) {
*/
function _elavon_civix_civicrm_install() {
_elavon_civix_civicrm_config();
- if ($upgrader = _elavon_civix_upgrader()) {
- $upgrader->onInstall();
- }
-}
-
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function _elavon_civix_civicrm_postInstall() {
- _elavon_civix_civicrm_config();
- if ($upgrader = _elavon_civix_upgrader()) {
- if (is_callable([$upgrader, 'onPostInstall'])) {
- $upgrader->onPostInstall();
- }
- }
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function _elavon_civix_civicrm_uninstall(): void {
- _elavon_civix_civicrm_config();
- if ($upgrader = _elavon_civix_upgrader()) {
- $upgrader->onUninstall();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -152,56 +114,7 @@ function _elavon_civix_civicrm_uninstall(): void {
*/
function _elavon_civix_civicrm_enable(): void {
_elavon_civix_civicrm_config();
- if ($upgrader = _elavon_civix_upgrader()) {
- if (is_callable([$upgrader, 'onEnable'])) {
- $upgrader->onEnable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- * @return mixed
- */
-function _elavon_civix_civicrm_disable(): void {
- _elavon_civix_civicrm_config();
- if ($upgrader = _elavon_civix_upgrader()) {
- if (is_callable([$upgrader, 'onDisable'])) {
- $upgrader->onDisable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_upgrade().
- *
- * @param $op string, the type of operation being performed; 'check' or 'enqueue'
- * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
- *
- * @return mixed
- * based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
- * for 'enqueue', returns void
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function _elavon_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- if ($upgrader = _elavon_civix_upgrader()) {
- return $upgrader->onUpgrade($op, $queue);
- }
-}
-
-/**
- * @return CRM_Elavon_Upgrader
- */
-function _elavon_civix_upgrader() {
- if (!file_exists(__DIR__ . '/CRM/Elavon/Upgrader.php')) {
- return NULL;
- }
- else {
- return CRM_Elavon_Upgrader_Base::instance();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -220,8 +133,8 @@ function _elavon_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
@@ -285,14 +198,3 @@ function _elavon_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID) {
}
}
}
-
-/**
- * (Delegated) Implements hook_civicrm_entityTypes().
- *
- * Find any *.entityType.php files, merge their content, and return.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function _elavon_civix_civicrm_entityTypes(&$entityTypes) {
- $entityTypes = array_merge($entityTypes, []);
-}
diff --git a/ext/elavon/elavon.php b/ext/elavon/elavon.php
index 7bd31d211003..f3f6556fa493 100644
--- a/ext/elavon/elavon.php
+++ b/ext/elavon/elavon.php
@@ -23,24 +23,6 @@ function elavon_civicrm_install() {
_elavon_civix_civicrm_install();
}
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function elavon_civicrm_postInstall() {
- _elavon_civix_civicrm_postInstall();
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function elavon_civicrm_uninstall() {
- _elavon_civix_civicrm_uninstall();
-}
-
/**
* Implements hook_civicrm_enable().
*
@@ -49,32 +31,3 @@ function elavon_civicrm_uninstall() {
function elavon_civicrm_enable() {
_elavon_civix_civicrm_enable();
}
-
-/**
- * Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- */
-function elavon_civicrm_disable() {
- _elavon_civix_civicrm_disable();
-}
-
-/**
- * Implements hook_civicrm_upgrade().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function elavon_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- return _elavon_civix_civicrm_upgrade($op, $queue);
-}
-
-/**
- * Implements hook_civicrm_entityTypes().
- *
- * Declare entity types provided by this module.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function elavon_civicrm_entityTypes(&$entityTypes) {
- _elavon_civix_civicrm_entityTypes($entityTypes);
-}
diff --git a/ext/elavon/info.xml b/ext/elavon/info.xml
index c167aa9e0f6a..caa727f5a064 100644
--- a/ext/elavon/info.xml
+++ b/ext/elavon/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2022-08-05
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
@@ -27,7 +27,7 @@
CRM/Elavon
- 22.10.0
+ 23.02.1
crmElavon
diff --git a/ext/eventcart/eventcart.civix.php b/ext/eventcart/eventcart.civix.php
index 91bd958e3b75..930d1acbd5c4 100644
--- a/ext/eventcart/eventcart.civix.php
+++ b/ext/eventcart/eventcart.civix.php
@@ -92,11 +92,6 @@ function _eventcart_civix_civicrm_config($config = NULL) {
$configured = TRUE;
$extRoot = __DIR__ . DIRECTORY_SEPARATOR;
- $extDir = $extRoot . 'templates';
- if (file_exists($extDir)) {
- CRM_Core_Smarty::singleton()->addTemplateDir($extDir);
- }
-
$include_path = $extRoot . PATH_SEPARATOR . get_include_path();
set_include_path($include_path);
// Based on , this does not currently require mixin/polyfill.php.
@@ -138,8 +133,8 @@ function _eventcart_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
@@ -203,14 +198,3 @@ function _eventcart_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID)
}
}
}
-
-/**
- * (Delegated) Implements hook_civicrm_entityTypes().
- *
- * Find any *.entityType.php files, merge their content, and return.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function _eventcart_civix_civicrm_entityTypes(&$entityTypes) {
- $entityTypes = array_merge($entityTypes, []);
-}
diff --git a/ext/eventcart/eventcart.php b/ext/eventcart/eventcart.php
index 771659a4c200..3fb283d20f3e 100644
--- a/ext/eventcart/eventcart.php
+++ b/ext/eventcart/eventcart.php
@@ -52,17 +52,6 @@ function eventcart_civicrm_enable() {
_eventcart_civix_civicrm_enable();
}
-/**
- * Implements hook_civicrm_entityTypes().
- *
- * Declare entity types provided by this module.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function eventcart_civicrm_entityTypes(&$entityTypes) {
- _eventcart_civix_civicrm_entityTypes($entityTypes);
-}
-
function eventcart_civicrm_tabset($name, &$tabs) {
if ($name === 'civicrm/event/manage' && Civi::settings()->get('enable_cart')) {
$tabs['conference'] = [
diff --git a/ext/eventcart/info.xml b/ext/eventcart/info.xml
index 131924abe730..dd4fd35565aa 100644
--- a/ext/eventcart/info.xml
+++ b/ext/eventcart/info.xml
@@ -13,13 +13,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2020-08-03
- 5.67.alpha1
+ 5.68.alpha1
mgmt:hidden
stable
- 5.67
+ 5.68
@@ -28,9 +28,10 @@
menu-xml@1.0.0
setting-php@1.0.0
+ smarty-v2@1.0.1
CRM/Event/Cart
- 22.12.1
+ 23.02.1
diff --git a/ext/ewaysingle/ewaysingle.civix.php b/ext/ewaysingle/ewaysingle.civix.php
index 33da14768524..c161575f7440 100644
--- a/ext/ewaysingle/ewaysingle.civix.php
+++ b/ext/ewaysingle/ewaysingle.civix.php
@@ -84,27 +84,17 @@ public static function findClass($suffix) {
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config
*/
-function _ewaysingle_civix_civicrm_config(&$config = NULL) {
+function _ewaysingle_civix_civicrm_config($config = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
- $template = CRM_Core_Smarty::singleton();
-
$extRoot = __DIR__ . DIRECTORY_SEPARATOR;
- $extDir = $extRoot . 'templates';
-
- if (is_array($template->template_dir)) {
- array_unshift($template->template_dir, $extDir);
- }
- else {
- $template->template_dir = [$extDir, $template->template_dir];
- }
-
$include_path = $extRoot . PATH_SEPARATOR . get_include_path();
set_include_path($include_path);
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -114,35 +104,7 @@ function _ewaysingle_civix_civicrm_config(&$config = NULL) {
*/
function _ewaysingle_civix_civicrm_install() {
_ewaysingle_civix_civicrm_config();
- if ($upgrader = _ewaysingle_civix_upgrader()) {
- $upgrader->onInstall();
- }
-}
-
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function _ewaysingle_civix_civicrm_postInstall() {
- _ewaysingle_civix_civicrm_config();
- if ($upgrader = _ewaysingle_civix_upgrader()) {
- if (is_callable([$upgrader, 'onPostInstall'])) {
- $upgrader->onPostInstall();
- }
- }
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function _ewaysingle_civix_civicrm_uninstall(): void {
- _ewaysingle_civix_civicrm_config();
- if ($upgrader = _ewaysingle_civix_upgrader()) {
- $upgrader->onUninstall();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -152,56 +114,7 @@ function _ewaysingle_civix_civicrm_uninstall(): void {
*/
function _ewaysingle_civix_civicrm_enable(): void {
_ewaysingle_civix_civicrm_config();
- if ($upgrader = _ewaysingle_civix_upgrader()) {
- if (is_callable([$upgrader, 'onEnable'])) {
- $upgrader->onEnable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- * @return mixed
- */
-function _ewaysingle_civix_civicrm_disable(): void {
- _ewaysingle_civix_civicrm_config();
- if ($upgrader = _ewaysingle_civix_upgrader()) {
- if (is_callable([$upgrader, 'onDisable'])) {
- $upgrader->onDisable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_upgrade().
- *
- * @param $op string, the type of operation being performed; 'check' or 'enqueue'
- * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
- *
- * @return mixed
- * based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
- * for 'enqueue', returns void
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function _ewaysingle_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- if ($upgrader = _ewaysingle_civix_upgrader()) {
- return $upgrader->onUpgrade($op, $queue);
- }
-}
-
-/**
- * @return CRM_Ewaysingle_Upgrader
- */
-function _ewaysingle_civix_upgrader() {
- if (!file_exists(__DIR__ . '/CRM/Ewaysingle/Upgrader.php')) {
- return NULL;
- }
- else {
- return CRM_Ewaysingle_Upgrader_Base::instance();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -220,8 +133,8 @@ function _ewaysingle_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
@@ -285,14 +198,3 @@ function _ewaysingle_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID
}
}
}
-
-/**
- * (Delegated) Implements hook_civicrm_entityTypes().
- *
- * Find any *.entityType.php files, merge their content, and return.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function _ewaysingle_civix_civicrm_entityTypes(&$entityTypes) {
- $entityTypes = array_merge($entityTypes, []);
-}
diff --git a/ext/ewaysingle/ewaysingle.php b/ext/ewaysingle/ewaysingle.php
index 9c146e341bf5..1f4441ea8f42 100644
--- a/ext/ewaysingle/ewaysingle.php
+++ b/ext/ewaysingle/ewaysingle.php
@@ -23,24 +23,6 @@ function ewaysingle_civicrm_install() {
_ewaysingle_civix_civicrm_install();
}
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function ewaysingle_civicrm_postInstall() {
- _ewaysingle_civix_civicrm_postInstall();
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function ewaysingle_civicrm_uninstall() {
- _ewaysingle_civix_civicrm_uninstall();
-}
-
/**
* Implements hook_civicrm_enable().
*
@@ -49,32 +31,3 @@ function ewaysingle_civicrm_uninstall() {
function ewaysingle_civicrm_enable() {
_ewaysingle_civix_civicrm_enable();
}
-
-/**
- * Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- */
-function ewaysingle_civicrm_disable() {
- _ewaysingle_civix_civicrm_disable();
-}
-
-/**
- * Implements hook_civicrm_upgrade().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function ewaysingle_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- return _ewaysingle_civix_civicrm_upgrade($op, $queue);
-}
-
-/**
- * Implements hook_civicrm_entityTypes().
- *
- * Declare entity types provided by this module.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function ewaysingle_civicrm_entityTypes(&$entityTypes) {
- _ewaysingle_civix_civicrm_entityTypes($entityTypes);
-}
diff --git a/ext/ewaysingle/info.xml b/ext/ewaysingle/info.xml
index 402b4de17c6c..33dc82269b02 100644
--- a/ext/ewaysingle/info.xml
+++ b/ext/ewaysingle/info.xml
@@ -6,22 +6,22 @@
AGPL-3.0
Seamus Lee
- seamuslee001@gmail.com
+ seamus.lee@jmaconsulting.biz
- https://github.com/civicrm/civicrm-core/blob/master/ext/ewayrecurring
- https://github.com/civicrm/civicrm-core/blob/master/ext/ewayrecurring
- https://github.com/civicrm/civicrm-core/blob/master/ext/ewayrecurring
+ https://github.com/civicrm/civicrm-core/blob/master/ext/ewaysingle
+ https://github.com/civicrm/civicrm-core/blob/master/ext/ewaysingle
+ https://github.com/civicrm/civicrm-core/blob/master/ext/ewaysingle
http://www.gnu.org/licenses/agpl-3.0.html
2020-10-07
- 5.67.alpha1
+ 5.68.alpha1
mgmt:hidden
stable
- 5.67
+ 5.68
This is an extension to contain the eWAY Single Currency Payment Processor
@@ -33,6 +33,6 @@
CRM/Ewaysingle
- 22.10.0
+ 23.02.1
diff --git a/ext/ewaysingle/tests/phpunit/bootstrap.php b/ext/ewaysingle/tests/phpunit/bootstrap.php
index 5133778c8191..63c9148e8e1c 100644
--- a/ext/ewaysingle/tests/phpunit/bootstrap.php
+++ b/ext/ewaysingle/tests/phpunit/bootstrap.php
@@ -26,7 +26,7 @@
*/
function cv($cmd, $decode = 'json') {
$cmd = 'cv ' . $cmd;
- $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+ $descriptorSpec = [0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => STDERR];
$oldOutput = getenv('CV_OUTPUT');
putenv("CV_OUTPUT=json");
diff --git a/ext/financialacls/financialacls.civix.php b/ext/financialacls/financialacls.civix.php
index d7b20fa37aca..430305c55352 100644
--- a/ext/financialacls/financialacls.civix.php
+++ b/ext/financialacls/financialacls.civix.php
@@ -133,8 +133,8 @@ function _financialacls_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/financialacls/financialacls.php b/ext/financialacls/financialacls.php
index 48b93922b32a..334105d92ebe 100644
--- a/ext/financialacls/financialacls.php
+++ b/ext/financialacls/financialacls.php
@@ -201,7 +201,7 @@ function financialacls_civicrm_buildAmount($component, $form, &$feeBlock) {
foreach ($feeBlock as $key => $value) {
foreach ($value['options'] as $k => $options) {
- if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) {
+ if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Core_PseudoConstant::getName('CRM_Contribute_DAO_Contribution', 'financial_type_id', $options['financial_type_id']))) {
unset($feeBlock[$key]['options'][$k]);
}
}
@@ -384,6 +384,23 @@ function financialacls_civicrm_alterMenu(array &$menu): void {
$menu['civicrm/admin/financial/financialType']['access_arguments'] = [['administer CiviCRM Financial Types']];
}
+/**
+ * @param string $formName
+ * @param \CRM_Core_Form $form
+ */
+function financialacls_civicrm_preProcess(string $formName, \CRM_Core_Form $form): void {
+ if (!financialacls_is_acl_limiting_enabled()) {
+ return;
+ }
+ if (str_starts_with($formName, 'CRM_Contribute_Form_Contribution_')) {
+ /* @var \CRM_Contribute_Form_Contribution_Main $form */
+ if (!CRM_Core_Permission::check('add contributions of type ' . $form->getContributionPageValue('financial_type_id:name'))) {
+ CRM_Core_Error::statusBounce(ts('You do not have permission to access this page.'));
+ }
+ }
+
+}
+
/**
* Hide edit/enable/disable links for memberships of a given Financial Type
* Note: The $objectID param can be an int, string or null, hence not typed
@@ -391,6 +408,9 @@ function financialacls_civicrm_alterMenu(array &$menu): void {
* Implements hook_civicrm_links()
*/
function financialacls_civicrm_links(string $op, ?string $objectName, $objectID, array &$links, ?int &$mask, array &$values) {
+ if (!financialacls_is_acl_limiting_enabled()) {
+ return;
+ }
if ($objectName === 'MembershipType') {
$financialType = CRM_Core_PseudoConstant::getName('CRM_Member_BAO_MembershipType', 'financial_type_id', CRM_Member_BAO_MembershipType::getMembershipType($objectID)['financial_type_id']);
$hasEditPermission = CRM_Core_Permission::check('edit contributions of type ' . $financialType);
diff --git a/ext/financialacls/info.xml b/ext/financialacls/info.xml
index a0554914e055..9511b97f3c5f 100644
--- a/ext/financialacls/info.xml
+++ b/ext/financialacls/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2020-08-27
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
mgmt:hidden
@@ -33,6 +33,6 @@
CRM/Financialacls
- 23.02.0
+ 23.02.1
diff --git a/ext/financialacls/settings/financialacls.setting.php b/ext/financialacls/settings/financialacls.setting.php
index e6ba889d5cbd..c90b37b46b8c 100644
--- a/ext/financialacls/settings/financialacls.setting.php
+++ b/ext/financialacls/settings/financialacls.setting.php
@@ -13,7 +13,7 @@
'is_domain' => 1,
'is_contact' => 0,
'help_text' => NULL,
- 'help' => ['id' => 'acl_financial_type'],
+ 'help' => ['id' => 'acl_financial_type', 'file' => 'CRM/Admin/Form/Preferences/Contribute.hlp'],
'settings_pages' => ['contribute' => ['weight' => 30]],
'on_change' => [
'financialacls_toggle',
diff --git a/ext/financialacls/tests/phpunit/Civi/Financialacls/FinancialTypeTest.php b/ext/financialacls/tests/phpunit/Civi/Financialacls/FinancialTypeTest.php
index e88e563afee0..ef9f5f58cc6c 100644
--- a/ext/financialacls/tests/phpunit/Civi/Financialacls/FinancialTypeTest.php
+++ b/ext/financialacls/tests/phpunit/Civi/Financialacls/FinancialTypeTest.php
@@ -3,6 +3,9 @@
namespace Civi\Financialacls;
use Civi;
+use Civi\Api4\PriceField;
+use Civi\Api4\PriceFieldValue;
+use Civi\Api4\PriceSet;
use CRM_Core_Session;
// I fought the Autoloader and the autoloader won.
@@ -47,7 +50,10 @@ public function testPermissionedFinancialTypes(): void {
foreach ($actions as $action => $action_ts) {
$this->assertEquals(
[
- ts('CiviCRM: %1 contributions of type %2', [1 => $action_ts, 2 => $type]),
+ ts('CiviCRM: %1 contributions of type %2', [
+ 1 => $action_ts,
+ 2 => $type,
+ ]),
ts('%1 contributions of type %2', [1 => $action_ts, 2 => $type]),
],
$permissions[$action . ' contributions of type ' . $type]
@@ -71,4 +77,84 @@ public function testGetIncomeFinancialType(): void {
$this->assertEquals([1 => 'Donation'], $type);
}
+ /**
+ * Check method testCheckPermissionedLineItems()
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function testCheckPermissionedLineItems(): void {
+ $priceSetID = PriceSet::create()->setValues([
+ 'title' => 'Price Set Financial ACLS',
+ 'name' => 'test_price_set',
+ 'extends' => 1,
+ 'financial_type_id:name' => 'Donation',
+ ])->execute()->first()['id'];
+
+ $paramsField = [
+ 'label' => 'Price Field',
+ 'name' => 'test_price_field',
+ 'html_type' => 'CheckBox',
+ 'is_display_amounts' => 1,
+ 'weight' => 1,
+ 'options_per_line' => 1,
+ 'price_set_id' => $priceSetID,
+ 'is_enter_qty' => 1,
+ 'financial_type_id:name' => 'Donation',
+ ];
+ $priceFieldID = PriceField::create()
+ ->setValues($paramsField)
+ ->execute()
+ ->first()['id'];
+ $priceFieldValueID = PriceFieldValue::create()->setValues([
+ 'price_field_id' => $priceFieldID,
+ 'amount' => 100,
+ 'name' => 'price_field_value',
+ 'label' => 'Price Field 1',
+ 'financial_type_id:name' => 'Donation',
+ 'weight' => 1,
+ ])->execute()->first()['id'];
+ $contributionParams = [
+ 'total_amount' => 300,
+ 'currency' => 'USD',
+ 'contact_id' => $this->individualCreate(),
+ 'financial_type_id' => 'Donation',
+ 'line_items' => [
+ [
+ 'line_item' => [
+ [
+ 'price_field_id' => $priceFieldID,
+ 'price_field_value_id' => $priceFieldValueID,
+ 'qty' => 3,
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ $contribution = $this->callAPISuccess('Order', 'create', $contributionParams);
+ Civi::settings()->set('acl_financial_type', TRUE);
+
+ $this->setPermissions([
+ 'view contributions of type Member Dues',
+ ]);
+
+ try {
+ \CRM_Financial_BAO_FinancialType::checkPermissionedLineItems($contribution['id'], 'view');
+ $this->fail('Missed expected exception');
+ }
+ catch (\CRM_Core_Exception $e) {
+ $this->assertEquals('You do not have permission to access this page.', $e->getMessage());
+ }
+
+ $this->setPermissions([
+ 'view contributions of type Donation',
+ ]);
+ try {
+ \CRM_Financial_BAO_FinancialType::checkPermissionedLineItems($contribution['id'], 'view');
+ }
+ catch (\CRM_Core_Exception $e) {
+ $this->fail('permissions should be established');
+ }
+ }
+
}
diff --git a/ext/financialacls/tests/phpunit/bootstrap.php b/ext/financialacls/tests/phpunit/bootstrap.php
index 5133778c8191..63c9148e8e1c 100644
--- a/ext/financialacls/tests/phpunit/bootstrap.php
+++ b/ext/financialacls/tests/phpunit/bootstrap.php
@@ -26,7 +26,7 @@
*/
function cv($cmd, $decode = 'json') {
$cmd = 'cv ' . $cmd;
- $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+ $descriptorSpec = [0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => STDERR];
$oldOutput = getenv('CV_OUTPUT');
putenv("CV_OUTPUT=json");
diff --git a/ext/flexmailer/flexmailer.civix.php b/ext/flexmailer/flexmailer.civix.php
index 2905f4898872..273986155d9c 100644
--- a/ext/flexmailer/flexmailer.civix.php
+++ b/ext/flexmailer/flexmailer.civix.php
@@ -133,8 +133,8 @@ function _flexmailer_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/flexmailer/info.xml b/ext/flexmailer/info.xml
index 199669802328..1f629c8c5490 100644
--- a/ext/flexmailer/info.xml
+++ b/ext/flexmailer/info.xml
@@ -15,7 +15,7 @@
http://www.gnu.org/licenses/agpl-3.0.html
2020-08-05
- 5.67.alpha1
+ 5.68.alpha1
stable
FlexMailer is an email delivery engine which replaces the internal guts
@@ -23,13 +23,14 @@
to provide richer email features.
- 5.67
+ 5.68
mgmt:required
+
menu-xml@1.0.0
@@ -37,6 +38,6 @@
CRM/Flexmailer
- 23.02.0
+ 23.02.1
diff --git a/ext/flexmailer/src/API/MailingPreview.php b/ext/flexmailer/src/API/MailingPreview.php
index 4d3810c4ff5e..448f9b9c09ed 100644
--- a/ext/flexmailer/src/API/MailingPreview.php
+++ b/ext/flexmailer/src/API/MailingPreview.php
@@ -24,7 +24,7 @@ public static function preview($apiRequest) {
/** @var \CRM_Mailing_BAO_Mailing $mailing */
$mailing = new \CRM_Mailing_BAO_Mailing();
- $mailingID = \CRM_Utils_Array::value('id', $params);
+ $mailingID = $params['id'] ?? NULL;
if ($mailingID) {
$mailing->id = $mailingID;
$mailing->find(TRUE);
@@ -59,13 +59,13 @@ public function save($hook = TRUE) {
$job->mailing_id = $mailing->id ?: NULL;
$job->status = 'Complete';
- $flexMailer = new FlexMailer(array(
+ $flexMailer = new FlexMailer([
'is_preview' => TRUE,
'mailing' => $mailing,
'job' => $job,
'attachments' => \CRM_Core_BAO_File::getEntityFile('civicrm_mailing',
$mailing->id),
- ));
+ ]);
if (count($flexMailer->validate()) > 0) {
throw new \CRM_Core_Exception("FlexMailer cannot execute: invalid context");
@@ -74,9 +74,9 @@ public function save($hook = TRUE) {
$task = new FlexMailerTask($job->id, $contactID, 'fakehash',
'placeholder@example.com');
- $flexMailer->fireComposeBatch(array($task));
+ $flexMailer->fireComposeBatch([$task]);
- return civicrm_api3_create_success(array(
+ return civicrm_api3_create_success([
'id' => isset($params['id']) ? $params['id'] : NULL,
'contact_id' => $contactID,
'subject' => $task->getMailParam('Subject'),
@@ -84,7 +84,7 @@ public function save($hook = TRUE) {
'body_text' => $task->getMailParam('text'),
// Flag our role in processing this - to support tests.
'_rendered_by_' => 'flexmailer',
- ));
+ ]);
}
}
diff --git a/ext/flexmailer/src/Event/CheckSendableEvent.php b/ext/flexmailer/src/Event/CheckSendableEvent.php
index 3a36f5adbc0f..8016d658d982 100644
--- a/ext/flexmailer/src/Event/CheckSendableEvent.php
+++ b/ext/flexmailer/src/Event/CheckSendableEvent.php
@@ -30,7 +30,7 @@ class CheckSendableEvent extends \Civi\Core\Event\GenericHookEvent {
* Ex: array('subject' => 'The Subject field is blank').
* Example keys: 'subject', 'name', 'from_name', 'from_email', 'body', 'body_html:unsubscribeUrl'.
*/
- protected $errors = array();
+ protected $errors = [];
/**
* CheckSendableEvent constructor.
diff --git a/ext/flexmailer/src/FlexMailer.php b/ext/flexmailer/src/FlexMailer.php
index 844ee666598b..194590dc553f 100644
--- a/ext/flexmailer/src/FlexMailer.php
+++ b/ext/flexmailer/src/FlexMailer.php
@@ -77,12 +77,12 @@ class FlexMailer {
* Array(string $event => string $class).
*/
public static function getEventTypes() {
- return array(
+ return [
self::EVENT_RUN => 'Civi\\FlexMailer\\Event\\RunEvent',
self::EVENT_WALK => 'Civi\\FlexMailer\\Event\\WalkBatchesEvent',
self::EVENT_COMPOSE => 'Civi\\FlexMailer\\Event\\ComposeBatchEvent',
self::EVENT_SEND => 'Civi\\FlexMailer\\Event\\SendBatchEvent',
- );
+ ];
}
/**
@@ -112,13 +112,13 @@ public static function getEventTypes() {
* TRUE if delivery completed.
*/
public static function createAndRun($job, $deprecatedMessageMailer, $deprecatedTestParams) {
- $flexMailer = new \Civi\FlexMailer\FlexMailer(array(
+ $flexMailer = new \Civi\FlexMailer\FlexMailer([
'mailing' => \CRM_Mailing_BAO_Mailing::findById($job->mailing_id),
'job' => $job,
'attachments' => \CRM_Core_BAO_File::getEntityFile('civicrm_mailing', $job->mailing_id),
'deprecatedMessageMailer' => $deprecatedMessageMailer,
'deprecatedTestParams' => $deprecatedTestParams,
- ));
+ ]);
return $flexMailer->run();
}
@@ -131,7 +131,7 @@ public static function createAndRun($job, $deprecatedMessageMailer, $deprecatedT
* - attachments: array
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
*/
- public function __construct($context = array(), EventDispatcherInterface $dispatcher = NULL) {
+ public function __construct($context = [], EventDispatcherInterface $dispatcher = NULL) {
$this->context = $context;
$this->dispatcher = $dispatcher ?: \Civi::service('dispatcher');
}
@@ -168,7 +168,7 @@ public function run() {
* List of error messages
*/
public function validate() {
- $errors = array();
+ $errors = [];
if (empty($this->context['mailing'])) {
$errors['mailing'] = 'Missing \"mailing\"';
}
diff --git a/ext/flexmailer/src/FlexMailerTask.php b/ext/flexmailer/src/FlexMailerTask.php
index 5b1748578477..738fff80d7a0 100644
--- a/ext/flexmailer/src/FlexMailerTask.php
+++ b/ext/flexmailer/src/FlexMailerTask.php
@@ -59,7 +59,7 @@ class FlexMailerTask {
* @see MailParams
* @see \CRM_Utils_Hook::alterMailParams()
*/
- private $mailParams = array();
+ private $mailParams = [];
/**
* FlexMailerTask constructor.
diff --git a/ext/flexmailer/src/Listener/BasicHeaders.php b/ext/flexmailer/src/Listener/BasicHeaders.php
index 025a165e4ec6..4a4483799625 100644
--- a/ext/flexmailer/src/Listener/BasicHeaders.php
+++ b/ext/flexmailer/src/Listener/BasicHeaders.php
@@ -37,9 +37,9 @@ public function onCompose(ComposeBatchEvent $e) {
$e->getJob()->id, $task->getEventQueueId(), $task->getHash(),
$task->getAddress());
- $mailParams = array();
+ $mailParams = [];
$mailParams['List-Unsubscribe'] = "";
- \CRM_Mailing_BAO_Mailing::addMessageIdHeader($mailParams, 'm', $e->getJob()->id, $task->getEventQueueId(), $task->getHash());
+ \CRM_Mailing_BAO_Mailing::addMessageIdHeader($mailParams, 'm', NULL, $task->getEventQueueId(), $task->getHash());
$mailParams['Precedence'] = 'bulk';
$mailParams['job_id'] = $e->getJob()->id;
diff --git a/ext/flexmailer/src/Listener/DefaultBatcher.php b/ext/flexmailer/src/Listener/DefaultBatcher.php
index 028f593c89d6..56f834ebf02e 100644
--- a/ext/flexmailer/src/Listener/DefaultBatcher.php
+++ b/ext/flexmailer/src/Listener/DefaultBatcher.php
@@ -39,7 +39,7 @@ public function onWalk(WalkBatchesEvent $e) {
$mailerBatchLimit = \CRM_Core_Config::singleton()->mailerBatchLimit;
$eq = \CRM_Mailing_BAO_MailingJob::findPendingTasks($job->id, 'email');
- $tasks = array();
+ $tasks = [];
while ($eq->fetch()) {
if ($mailerBatchLimit > 0 && \CRM_Mailing_BAO_MailingJob::$mailsProcessed >= $mailerBatchLimit) {
if (!empty($tasks)) {
@@ -61,7 +61,7 @@ public function onWalk(WalkBatchesEvent $e) {
$e->setCompleted($isDelivered);
return;
}
- $tasks = array();
+ $tasks = [];
}
}
diff --git a/ext/flexmailer/src/Listener/DefaultComposer.php b/ext/flexmailer/src/Listener/DefaultComposer.php
index 93559b8a1a13..25b2e69b5dce 100644
--- a/ext/flexmailer/src/Listener/DefaultComposer.php
+++ b/ext/flexmailer/src/Listener/DefaultComposer.php
@@ -96,13 +96,13 @@ public function onCompose(ComposeBatchEvent $e) {
* @return array
*/
public function createTokenProcessorContext(ComposeBatchEvent $e) {
- $context = array(
+ $context = [
'controller' => get_class($this),
// FIXME: Use template_type, template_options
'smarty' => defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY ? TRUE : FALSE,
'mailing' => $e->getMailing(),
'mailingId' => $e->getMailing()->id,
- );
+ ];
return $context;
}
@@ -119,16 +119,16 @@ public function createTokenRowContext(
ComposeBatchEvent $e,
FlexMailerTask $task
) {
- return array(
+ return [
'contactId' => $task->getContactId(),
'mailingJobId' => $e->getJob()->id,
- 'mailingActionTarget' => array(
+ 'mailingActionTarget' => [
'id' => $task->getEventQueueId(),
'hash' => $task->getHash(),
'email' => $task->getAddress(),
- ),
+ ],
'flexMailerTask' => $task,
- );
+ ];
}
/**
@@ -146,11 +146,11 @@ public function createMailParams(
FlexMailerTask $task,
TokenRow $row
) {
- return array(
+ return [
'Subject' => $row->render('subject'),
'text' => $row->render('body_text'),
'html' => $row->render('body_html'),
- );
+ ];
}
/**
diff --git a/ext/flexmailer/src/Listener/DefaultSender.php b/ext/flexmailer/src/Listener/DefaultSender.php
index d2e0d7b09dfc..d09386ff1156 100644
--- a/ext/flexmailer/src/Listener/DefaultSender.php
+++ b/ext/flexmailer/src/Listener/DefaultSender.php
@@ -29,7 +29,7 @@ public function onSend(SendBatchEvent $e) {
$job_date = \CRM_Utils_Date::isoToMysql($job->scheduled_date);
$mailer = \Civi::service('pear_mail');
- $targetParams = $deliveredParams = array();
+ $targetParams = $deliveredParams = [];
$count = 0;
$retryBatch = FALSE;
@@ -188,11 +188,11 @@ protected function isTemporaryError($message) {
* @param string $errorMessage
*/
protected function recordBounce($job, $task, $errorMessage) {
- $params = array(
+ $params = [
'event_queue_id' => $task->getEventQueueId(),
'job_id' => $job->id,
'hash' => $task->getHash(),
- );
+ ];
$params = array_merge($params,
\CRM_Mailing_BAO_BouncePattern::match($errorMessage)
);
diff --git a/ext/flexmailer/src/Listener/RequiredFields.php b/ext/flexmailer/src/Listener/RequiredFields.php
index a109b26728fc..4eaa02d7502c 100644
--- a/ext/flexmailer/src/Listener/RequiredFields.php
+++ b/ext/flexmailer/src/Listener/RequiredFields.php
@@ -60,9 +60,9 @@ public function onCheckSendable(CheckSendableEvent $e) {
}
if (!$found) {
- $e->setError($field, E::ts('Field %1 is required.', array(
+ $e->setError($field, E::ts('Field %1 is required.', [
1 => $fieldTitle,
- )));
+ ]));
}
unset($found);
}
diff --git a/ext/flexmailer/src/Listener/RequiredTokens.php b/ext/flexmailer/src/Listener/RequiredTokens.php
index e627243c977f..1d6a87af655f 100644
--- a/ext/flexmailer/src/Listener/RequiredTokens.php
+++ b/ext/flexmailer/src/Listener/RequiredTokens.php
@@ -66,21 +66,21 @@ public function onCheckSendable(CheckSendableEvent $e) {
return;
}
- foreach (array('body_html', 'body_text') as $field) {
+ foreach (['body_html', 'body_text'] as $field) {
$str = $e->getFullBody($field);
if (empty($str)) {
continue;
}
foreach ($this->findMissingTokens($str) as $token => $desc) {
$e->setError("{$field}:{$token}", E::ts('This message is missing a required token - {%1}: %2',
- array(1 => $token, 2 => $desc)
+ [1 => $token, 2 => $desc]
));
}
}
}
public function findMissingTokens($str) {
- $missing = array();
+ $missing = [];
foreach ($this->getRequiredTokens() as $token => $value) {
if (!is_array($value)) {
if (!preg_match('/(^|[^\{])' . preg_quote('{' . $token . '}') . '/', $str)) {
diff --git a/ext/flexmailer/src/Listener/SimpleFilter.php b/ext/flexmailer/src/Listener/SimpleFilter.php
index 4d0f1a5571f7..291be3be959f 100644
--- a/ext/flexmailer/src/Listener/SimpleFilter.php
+++ b/ext/flexmailer/src/Listener/SimpleFilter.php
@@ -65,7 +65,7 @@ public static function byValue(ComposeBatchEvent $e, $field, $filter) {
*/
public static function byColumn(ComposeBatchEvent $e, $field, $filter) {
$tasks = $e->getTasks();
- $values = array();
+ $values = [];
foreach ($tasks as $k => $task) {
/** @var \Civi\FlexMailer\FlexMailerTask $task */
@@ -75,7 +75,7 @@ public static function byColumn(ComposeBatchEvent $e, $field, $filter) {
}
}
- $values = call_user_func_array($filter, array($values, $e));
+ $values = call_user_func_array($filter, [$values, $e]);
foreach ($values as $k => $value) {
$tasks[$k]->setMailParam($field, $value);
diff --git a/ext/flexmailer/src/Listener/ToHeader.php b/ext/flexmailer/src/Listener/ToHeader.php
index a85a36139bb7..855cf85ca057 100644
--- a/ext/flexmailer/src/Listener/ToHeader.php
+++ b/ext/flexmailer/src/Listener/ToHeader.php
@@ -47,7 +47,7 @@ public function onCompose(ComposeBatchEvent $e) {
* Array(int $contactId => string $displayName).
*/
protected function getContactNames($tasks) {
- $ids = array();
+ $ids = [];
foreach ($tasks as $task) {
/** @var \Civi\FlexMailer\FlexMailerTask $task */
$ids[$task->getContactId()] = $task->getContactId();
@@ -55,14 +55,14 @@ protected function getContactNames($tasks) {
$ids = array_filter($ids, 'is_numeric');
if (empty($ids)) {
- return array();
+ return [];
}
$idString = implode(',', $ids);
$query = \CRM_Core_DAO::executeQuery(
"SELECT id, display_name FROM civicrm_contact WHERE id in ($idString)");
- $names = array();
+ $names = [];
while ($query->fetch()) {
$names[$query->id] = $query->display_name;
}
diff --git a/ext/flexmailer/src/MailParams.php b/ext/flexmailer/src/MailParams.php
index b7880e32d74a..60e7dde10504 100644
--- a/ext/flexmailer/src/MailParams.php
+++ b/ext/flexmailer/src/MailParams.php
@@ -89,7 +89,7 @@ public static function convertMailParamsToMime($mailParams) {
break;
default:
- $message->headers(array($key => $value), TRUE);
+ $message->headers([$key => $value], TRUE);
}
}
diff --git a/ext/flexmailer/src/Services.php b/ext/flexmailer/src/Services.php
index 9be823e167c0..899041e4c92c 100644
--- a/ext/flexmailer/src/Services.php
+++ b/ext/flexmailer/src/Services.php
@@ -29,27 +29,27 @@ public static function registerServices(ContainerBuilder $container) {
$apiOverrides = $container->setDefinition('civi_flexmailer_api_overrides', new Definition('Civi\API\Provider\ProviderInterface'))->setPublic(TRUE);
self::applyStaticFactory($apiOverrides, __CLASS__, 'createApiOverrides');
- $container->setDefinition('civi_flexmailer_required_fields', new Definition('Civi\FlexMailer\Listener\RequiredFields', array(
- array(
+ $container->setDefinition('civi_flexmailer_required_fields', new Definition('Civi\FlexMailer\Listener\RequiredFields', [
+ [
'subject',
'name',
'from_name',
'from_email',
'(body_html|body_text)',
- ),
- )))->setPublic(TRUE);
- $container->setDefinition('civi_flexmailer_required_tokens', new Definition('Civi\FlexMailer\Listener\RequiredTokens', array(
- array('traditional'),
- array(
+ ],
+ ]))->setPublic(TRUE);
+ $container->setDefinition('civi_flexmailer_required_tokens', new Definition('Civi\FlexMailer\Listener\RequiredTokens', [
+ ['traditional'],
+ [
'domain.address' => ts("Domain address - displays your organization's postal address."),
- 'action.optOutUrl or action.unsubscribeUrl' => array(
+ 'action.optOutUrl or action.unsubscribeUrl' => [
'action.optOut' => ts("'Opt out via email' - displays an email address for recipients to opt out of receiving emails from your organization."),
'action.optOutUrl' => ts("'Opt out via web page' - creates a link for recipients to click if they want to opt out of receiving emails from your organization. Alternatively, you can include the 'Opt out via email' token."),
'action.unsubscribe' => ts("'Unsubscribe via email' - displays an email address for recipients to unsubscribe from the specific mailing list used to send this message."),
'action.unsubscribeUrl' => ts("'Unsubscribe via web page' - creates a link for recipients to unsubscribe from the specific mailing list used to send this message. Alternatively, you can include the 'Unsubscribe via email' token or one of the Opt-out tokens."),
- ),
- ),
- )))->setPublic(TRUE);
+ ],
+ ],
+ ]))->setPublic(TRUE);
$container->setDefinition('civi_flexmailer_abdicator', new Definition('Civi\FlexMailer\Listener\Abdicator'))->setPublic(TRUE);
$container->setDefinition('civi_flexmailer_default_batcher', new Definition('Civi\FlexMailer\Listener\DefaultBatcher'))->setPublic(TRUE);
@@ -70,7 +70,7 @@ public static function registerServices(ContainerBuilder $container) {
$container->findDefinition('dispatcher')->addMethodCall('addListenerService', $listenerSpec);
}
- $container->findDefinition('civi_api_kernel')->addMethodCall('registerApiProvider', array(new Reference('civi_flexmailer_api_overrides')));
+ $container->findDefinition('civi_api_kernel')->addMethodCall('registerApiProvider', [new Reference('civi_flexmailer_api_overrides')]);
}
/**
@@ -84,27 +84,27 @@ public static function registerServices(ContainerBuilder $container) {
* Arguments to pass to addListenerService($eventName, $callbackSvc, $priority).
*/
protected static function getListenerSpecs() {
- $listenerSpecs = array();
+ $listenerSpecs = [];
- $listenerSpecs[] = array(Validator::EVENT_CHECK_SENDABLE, array('civi_flexmailer_abdicator', 'onCheckSendable'), FM::WEIGHT_START);
- $listenerSpecs[] = array(Validator::EVENT_CHECK_SENDABLE, array('civi_flexmailer_required_fields', 'onCheckSendable'), FM::WEIGHT_MAIN);
- $listenerSpecs[] = array(Validator::EVENT_CHECK_SENDABLE, array('civi_flexmailer_required_tokens', 'onCheckSendable'), FM::WEIGHT_MAIN);
+ $listenerSpecs[] = [Validator::EVENT_CHECK_SENDABLE, ['civi_flexmailer_abdicator', 'onCheckSendable'], FM::WEIGHT_START];
+ $listenerSpecs[] = [Validator::EVENT_CHECK_SENDABLE, ['civi_flexmailer_required_fields', 'onCheckSendable'], FM::WEIGHT_MAIN];
+ $listenerSpecs[] = [Validator::EVENT_CHECK_SENDABLE, ['civi_flexmailer_required_tokens', 'onCheckSendable'], FM::WEIGHT_MAIN];
- $listenerSpecs[] = array(FM::EVENT_RUN, array('civi_flexmailer_default_composer', 'onRun'), FM::WEIGHT_MAIN);
- $listenerSpecs[] = array(FM::EVENT_RUN, array('civi_flexmailer_abdicator', 'onRun'), FM::WEIGHT_END);
+ $listenerSpecs[] = [FM::EVENT_RUN, ['civi_flexmailer_default_composer', 'onRun'], FM::WEIGHT_MAIN];
+ $listenerSpecs[] = [FM::EVENT_RUN, ['civi_flexmailer_abdicator', 'onRun'], FM::WEIGHT_END];
- $listenerSpecs[] = array(FM::EVENT_WALK, array('civi_flexmailer_default_batcher', 'onWalk'), FM::WEIGHT_END);
+ $listenerSpecs[] = [FM::EVENT_WALK, ['civi_flexmailer_default_batcher', 'onWalk'], FM::WEIGHT_END];
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_basic_headers', 'onCompose'), FM::WEIGHT_PREPARE);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_to_header', 'onCompose'), FM::WEIGHT_PREPARE);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_bounce_tracker', 'onCompose'), FM::WEIGHT_PREPARE);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_default_composer', 'onCompose'), FM::WEIGHT_MAIN - 100);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_attachments', 'onCompose'), FM::WEIGHT_ALTER);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_open_tracker', 'onCompose'), FM::WEIGHT_ALTER);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_test_prefix', 'onCompose'), FM::WEIGHT_ALTER);
- $listenerSpecs[] = array(FM::EVENT_COMPOSE, array('civi_flexmailer_hooks', 'onCompose'), FM::WEIGHT_ALTER - 100);
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_basic_headers', 'onCompose'], FM::WEIGHT_PREPARE];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_to_header', 'onCompose'], FM::WEIGHT_PREPARE];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_bounce_tracker', 'onCompose'], FM::WEIGHT_PREPARE];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_default_composer', 'onCompose'], FM::WEIGHT_MAIN - 100];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_attachments', 'onCompose'], FM::WEIGHT_ALTER];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_open_tracker', 'onCompose'], FM::WEIGHT_ALTER];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_test_prefix', 'onCompose'], FM::WEIGHT_ALTER];
+ $listenerSpecs[] = [FM::EVENT_COMPOSE, ['civi_flexmailer_hooks', 'onCompose'], FM::WEIGHT_ALTER - 100];
- $listenerSpecs[] = array(FM::EVENT_SEND, array('civi_flexmailer_default_sender', 'onSend'), FM::WEIGHT_END);
+ $listenerSpecs[] = [FM::EVENT_SEND, ['civi_flexmailer_default_sender', 'onSend'], FM::WEIGHT_END];
return $listenerSpecs;
}
@@ -132,7 +132,7 @@ public static function createApiOverrides() {
*/
protected static function applyStaticFactory($def, $factoryClass, $factoryMethod) {
if (method_exists($def, 'setFactory')) {
- $def->setFactory(array($factoryClass, $factoryMethod));
+ $def->setFactory([$factoryClass, $factoryMethod]);
}
else {
$def->setFactoryClass($factoryClass)->setFactoryMethod($factoryMethod);
diff --git a/ext/flexmailer/src/Validator.php b/ext/flexmailer/src/Validator.php
index 549d028e3c3c..91ce47b25c7e 100644
--- a/ext/flexmailer/src/Validator.php
+++ b/ext/flexmailer/src/Validator.php
@@ -38,10 +38,10 @@ public static function createAndRun(array $params): array {
}
$mailing->copyValues($params);
- return (new Validator())->run(array(
+ return (new Validator())->run([
'mailing' => $mailing,
'attachments' => \CRM_Core_BAO_File::getEntityFile('civicrm_mailing', $mailing->id),
- ));
+ ]);
}
/**
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/HtmlClickTrackerTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/HtmlClickTrackerTest.php
index 4533fdaecdb6..687ca67bbda7 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/HtmlClickTrackerTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/HtmlClickTrackerTest.php
@@ -23,7 +23,7 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/TextClickTrackerTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/TextClickTrackerTest.php
index 14da23dd7889..d7df55307d4b 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/TextClickTrackerTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ClickTracker/TextClickTrackerTest.php
@@ -23,7 +23,7 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
@@ -45,19 +45,14 @@ public function getHrefExamples() {
'Foo
',
];
$exs[] = [
- // Messy looking URL, designed to trip-up quote handling
+ // Messy looking URL, designed to trip-up quote handling, no tracking as no http
'Foo
',
- 'Foo
',
+ 'Foo
',
];
$exs[] = [
- // Messy looking URL, designed to trip-up quote handling
+ // Messy looking URL, designed to trip-up quote handling, no tracking as no http
'Foo
',
- 'Foo
',
- ];
- $exs[] = [
- // Messy looking URL, funny whitespace
- 'Foo
',
- 'Foo
',
+ 'Foo
',
];
$exs[] = [
// Messy looking URL, funny whitespace
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ConcurrentDeliveryTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ConcurrentDeliveryTest.php
index f9f6061b3f1b..ae1e216beb21 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ConcurrentDeliveryTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ConcurrentDeliveryTest.php
@@ -37,7 +37,7 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php
index dbba1d7ab5fc..d91e6ec490cc 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/FlexMailerSystemTest.php
@@ -43,20 +43,20 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
$dispatcher = \Civi::service('dispatcher');
foreach (FlexMailer::getEventTypes() as $event => $class) {
- $dispatcher->addListener($event, array($this, 'handleEvent'));
+ $dispatcher->addListener($event, [$this, 'handleEvent']);
}
$hooks = \CRM_Utils_Hook::singleton();
$hooks->setHook('civicrm_alterMailParams',
- array($this, 'hook_alterMailParams'));
- $this->counts = array();
+ [$this, 'hook_alterMailParams']);
+ $this->counts = [];
}
public function handleEvent(GenericHookEvent $e) {
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/Listener/SimpleFilterTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/Listener/SimpleFilterTest.php
index b7d4d7904f1d..7ae2774f42e6 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/Listener/SimpleFilterTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/Listener/SimpleFilterTest.php
@@ -33,7 +33,7 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
@@ -49,10 +49,10 @@ public function testByValue(): void {
SimpleFilter::byValue($e, 'text', function ($value, $t, $e) use ($test) {
$test->assertInstanceOf('Civi\FlexMailer\FlexMailerTask', $t);
$test->assertInstanceOf('Civi\FlexMailer\Event\ComposeBatchEvent', $e);
- $test->assertTrue(in_array($value, array(
+ $test->assertTrue(in_array($value, [
'eat more cheese',
'eat more ice cream',
- )));
+ ]));
return preg_replace('/more/', 'thoughtfully considered quantities of', $value);
});
@@ -83,15 +83,15 @@ public function testByColumn(): void {
* @return array
*/
protected function createExampleBatch() {
- $tasks = array();
+ $tasks = [];
$tasks[0] = new FlexMailerTask(1000, 2000, 'asdf', 'foo@example.org');
$tasks[1] = new FlexMailerTask(1001, 2001, 'fdsa', 'bar@example.org');
- $e = new ComposeBatchEvent(array(), $tasks);
+ $e = new ComposeBatchEvent([], $tasks);
$tasks[0]->setMailParam('text', 'eat more cheese');
$tasks[1]->setMailParam('text', 'eat more ice cream');
- return array($tasks, $e);
+ return [$tasks, $e];
}
}
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/MailingPreviewTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/MailingPreviewTest.php
index d6c72e15c997..ecfe524a73ce 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/MailingPreviewTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/MailingPreviewTest.php
@@ -24,7 +24,7 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
@@ -35,7 +35,7 @@ public function setUp(): void {
$this->_contactID = $this->individualCreate();
$this->_groupID = $this->groupCreate();
$this->_email = 'test@test.test';
- $this->_params = array(
+ $this->_params = [
'subject' => 'Hello {contact.display_name}',
'body_text' => "This is {contact.display_name}.\nhttps://civicrm.org\nda=({domain.address}) optout=({action.optOutUrl}) subj=({mailing.subject})",
'body_html' => "This is {contact.display_name}.
CiviCRM.org
da=({domain.address}) optout=({action.optOutUrl}) subj=({mailing.subject})
",
@@ -43,14 +43,14 @@ public function setUp(): void {
'created_id' => $this->_contactID,
'header_id' => '',
'footer_id' => '',
- );
+ ];
- $this->footer = civicrm_api3('MailingComponent', 'create', array(
+ $this->footer = civicrm_api3('MailingComponent', 'create', [
'name' => 'test domain footer',
'component_type' => 'footer',
'body_html' => 'From {domain.address}. To opt out, go to {action.optOutUrl}.
',
'body_text' => 'From {domain.address}. To opt out, go to {action.optOutUrl}.',
- ));
+ ]);
}
public function tearDown(): void {
@@ -63,15 +63,15 @@ public function testMailerPreview(): void {
// BEGIN SAMPLE DATA
$contactID = $this->individualCreate();
$displayName = $this->callAPISuccess('contact', 'get',
- array('id' => $contactID));
+ ['id' => $contactID]);
$displayName = $displayName['values'][$contactID]['display_name'];
$this->assertTrue(!empty($displayName));
$params = $this->_params;
- $params['api.Mailing.preview'] = array(
+ $params['api.Mailing.preview'] = [
'id' => '$value.id',
'contact_id' => $contactID,
- );
+ ];
$params['options']['force_rollback'] = 1;
// END SAMPLE DATA
@@ -130,12 +130,12 @@ public function testMailerPreviewWithoutId(): void {
* Array(string $table => int $maxID).
*/
protected function getMaxIds() {
- return array(
+ return [
'civicrm_mailing' => \CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing'),
'civicrm_mailing_job' => \CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing_job'),
'civicrm_mailing_group' => \CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing_group'),
'civicrm_mailing_recipients' => \CRM_Core_DAO::singleValueQuery('SELECT MAX(id) FROM civicrm_mailing_recipients'),
- );
+ ];
}
/**
diff --git a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ValidatorTest.php b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ValidatorTest.php
index a0bd66b3d40f..08c2592f29b7 100644
--- a/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ValidatorTest.php
+++ b/ext/flexmailer/tests/phpunit/Civi/FlexMailer/ValidatorTest.php
@@ -21,14 +21,14 @@ public function setUp(): void {
// Activate before transactions are setup.
$manager = \CRM_Extension_System::singleton()->getManager();
if ($manager->getStatus('org.civicrm.flexmailer') !== \CRM_Extension_Manager::STATUS_INSTALLED) {
- $manager->install(array('org.civicrm.flexmailer'));
+ $manager->install(['org.civicrm.flexmailer']);
}
parent::setUp();
}
public function getExamples() {
- $defaults = array(
+ $defaults = [
'id' => 123,
'subject' => 'Default subject',
'name' => 'Default name',
@@ -37,44 +37,44 @@ public function getExamples() {
'body_html' => 'Default HTML body {action.unsubscribeUrl} {domain.address}',
'body_text' => 'Default text body {action.unsubscribeUrl} {domain.address}',
'template_type' => 'traditional',
- 'template_options' => array(),
- );
+ 'template_options' => [],
+ ];
- $es = array();
- $es[] = array(
- array_merge($defaults, array('subject' => NULL)),
- array('subject' => '/Field "subject" is required./'),
- );
- $es[] = array(
- array_merge($defaults, array('subject' => NULL, 'from_name' => NULL)),
- array(
+ $es = [];
+ $es[] = [
+ array_merge($defaults, ['subject' => NULL]),
+ ['subject' => '/Field "subject" is required./'],
+ ];
+ $es[] = [
+ array_merge($defaults, ['subject' => NULL, 'from_name' => NULL]),
+ [
'subject' => '/Field "subject" is required./',
'from_name' => '/Field "from_name" is required./',
- ),
- );
- $es[] = array(
- array_merge($defaults, array('body_text' => NULL)),
- array(),
- );
- $es[] = array(
- array_merge($defaults, array('body_html' => NULL)),
- array(),
- );
- $es[] = array(
- array_merge($defaults, array('body_html' => NULL, 'body_text' => NULL)),
- array('(body_html|body_text)' => '/Field "body_html" or "body_text" is required./'),
- );
- $es[] = array(
- array_merge($defaults, array('body_html' => 'Muahaha. I omit the mandatory tokens!')),
- array(
+ ],
+ ];
+ $es[] = [
+ array_merge($defaults, ['body_text' => NULL]),
+ [],
+ ];
+ $es[] = [
+ array_merge($defaults, ['body_html' => NULL]),
+ [],
+ ];
+ $es[] = [
+ array_merge($defaults, ['body_html' => NULL, 'body_text' => NULL]),
+ ['(body_html|body_text)' => '/Field "body_html" or "body_text" is required./'],
+ ];
+ $es[] = [
+ array_merge($defaults, ['body_html' => 'Muahaha. I omit the mandatory tokens!']),
+ [
'body_html:domain.address' => '/This message is missing.*postal address/',
'body_html:action.optOutUrl or action.unsubscribeUrl' => '/This message is missing.*Unsubscribe via web page/',
- ),
- );
- $es[] = array(
- array_merge($defaults, array('body_html' => 'I omit the mandatory tokens, but checking them is someone else\'s job!', 'template_type' => 'esperanto')),
- array(),
- );
+ ],
+ ];
+ $es[] = [
+ array_merge($defaults, ['body_html' => 'I omit the mandatory tokens, but checking them is someone else\'s job!', 'template_type' => 'esperanto']),
+ [],
+ ];
return $es;
}
diff --git a/ext/flexmailer/tests/phpunit/bootstrap.php b/ext/flexmailer/tests/phpunit/bootstrap.php
index ed4f208fece2..75b1128e99a0 100644
--- a/ext/flexmailer/tests/phpunit/bootstrap.php
+++ b/ext/flexmailer/tests/phpunit/bootstrap.php
@@ -32,7 +32,7 @@
*/
function cv($cmd, $decode = 'json') {
$cmd = 'cv ' . $cmd;
- $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+ $descriptorSpec = [0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => STDERR];
$oldOutput = getenv('CV_OUTPUT');
putenv("CV_OUTPUT=json");
$process = proc_open($cmd, $descriptorSpec, $pipes, __DIR__);
diff --git a/ext/greenwich/greenwich.civix.php b/ext/greenwich/greenwich.civix.php
index 2c4dfb13090e..97bf46e4ea9c 100644
--- a/ext/greenwich/greenwich.civix.php
+++ b/ext/greenwich/greenwich.civix.php
@@ -133,8 +133,8 @@ function _greenwich_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/greenwich/info.xml b/ext/greenwich/info.xml
index 6064f06d24b4..696c0356bc05 100644
--- a/ext/greenwich/info.xml
+++ b/ext/greenwich/info.xml
@@ -15,13 +15,13 @@
http://www.gnu.org/licenses/agpl-3.0.html
2020-07-21
- 5.67.alpha1
+ 5.68.alpha1
mgmt:hidden
stable
- 5.67
+ 5.68
@@ -29,6 +29,6 @@
CRM/Greenwich
- 23.02.0
+ 23.02.1
diff --git a/ext/legacycustomsearches/CRM/Utils/QueryFormatter.php b/ext/legacycustomsearches/CRM/Utils/QueryFormatter.php
index e11fdced70ce..beedd4efa42b 100644
--- a/ext/legacycustomsearches/CRM/Utils/QueryFormatter.php
+++ b/ext/legacycustomsearches/CRM/Utils/QueryFormatter.php
@@ -283,7 +283,7 @@ protected function _formatFtsBool($text, $mode) {
//Return if searched string ends with an unsupported operator.
//Or if the string contains an invalid joint occurrence of operators.
foreach ($operators as $val) {
- if ($text == '@' || CRM_Utils_String::endsWith($text, $val) || preg_match("/[{$expression}]{2,}/", $text)) {
+ if ($text == '@' || str_ends_with($text, $val) || preg_match("/[{$expression}]{2,}/", $text)) {
$csid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', 'CRM_Contact_Form_Search_Custom_FullText', 'value', 'name');
$url = CRM_Utils_System::url("civicrm/contact/search/custom", "csid={$csid}&reset=1");
$operators = implode("', '", $operators);
diff --git a/ext/legacycustomsearches/info.xml b/ext/legacycustomsearches/info.xml
index 171c3c3c8fc0..68da47644609 100644
--- a/ext/legacycustomsearches/info.xml
+++ b/ext/legacycustomsearches/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2021-07-25
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
This is our old search system which has limited support. All new effort is on SearchKit
@@ -28,11 +28,11 @@
menu-xml@1.0.0
mgd-php@1.0.0
- smarty-v2@1.0.0
+ smarty-v2@1.0.1
setting-php@1.0.0
CRM/Legacycustomsearches
- 23.02.0
+ 23.02.1
diff --git a/ext/legacycustomsearches/legacycustomsearches.civix.php b/ext/legacycustomsearches/legacycustomsearches.civix.php
index ffcb4eeb94c1..ac3bca24f322 100644
--- a/ext/legacycustomsearches/legacycustomsearches.civix.php
+++ b/ext/legacycustomsearches/legacycustomsearches.civix.php
@@ -133,8 +133,8 @@ function _legacycustomsearches_civix_insert_navigation_menu(&$menu, $path, $item
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/legacycustomsearches/managed/Navigation.mgd.php b/ext/legacycustomsearches/managed/Navigation.mgd.php
index 4175908fb765..1503cbca7b0c 100644
--- a/ext/legacycustomsearches/managed/Navigation.mgd.php
+++ b/ext/legacycustomsearches/managed/Navigation.mgd.php
@@ -1,15 +1,10 @@
addSelect('id')
- ->execute();
-foreach ($domains as $domain) {
- $menuItems[] = [
- 'name' => 'Custom Searches' . $domain['id'],
+return [
+ [
+ 'name' => 'Custom Searches',
'entity' => 'Navigation',
'cleanup' => 'always',
'update' => 'unmodified',
@@ -25,13 +20,12 @@
'is_active' => TRUE,
'has_separator' => 2,
'weight' => 15,
- 'domain_id' => $domain['id'],
],
'match' => ['domain_id', 'name'],
],
- ];
- $menuItems[] = [
- 'name' => 'Manage Custom Searches' . $domain['id'],
+ ],
+ [
+ 'name' => 'Manage Custom Searches',
'entity' => 'Navigation',
'cleanup' => 'always',
'update' => 'unmodified',
@@ -46,10 +40,8 @@
'parent_id.name' => 'Customize Data and Screens',
'is_active' => TRUE,
'weight' => 15,
- 'domain_id' => $domain['id'],
],
'match' => ['domain_id', 'name'],
],
- ];
-}
-return $menuItems;
+ ],
+];
diff --git a/ext/message_admin/CRM/MessageAdmin/Page/MsgtplBasePage.php b/ext/message_admin/CRM/MessageAdmin/Page/MsgtplBasePage.php
index 32a72afe5bb3..390b1a3cc258 100644
--- a/ext/message_admin/CRM/MessageAdmin/Page/MsgtplBasePage.php
+++ b/ext/message_admin/CRM/MessageAdmin/Page/MsgtplBasePage.php
@@ -25,9 +25,9 @@ public function run() {
/** @var \Civi\Angular\AngularLoader $loader */
$loader = \Civi::service('angularjs.loader');
$loader->addModules(['crmMsgadm']);
- $loader->useApp(array(
+ $loader->useApp([
'defaultRoute' => '/user',
- ));
+ ]);
parent::run();
}
diff --git a/ext/message_admin/info.xml b/ext/message_admin/info.xml
index 3afb75e2c679..d7dbe160db70 100644
--- a/ext/message_admin/info.xml
+++ b/ext/message_admin/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2021-06-12
- 5.67.alpha1
+ 5.68.alpha1
alpha
- 5.67
+ 5.68
org.civicrm.afform
@@ -31,10 +31,10 @@
ang-php@1.0.0
menu-xml@1.0.0
- smarty-v2@1.0.0
+ smarty-v2@1.0.1
CRM/MessageAdmin
- 23.02.0
+ 23.02.1
diff --git a/ext/message_admin/message_admin.civix.php b/ext/message_admin/message_admin.civix.php
index 78da356905da..432521c56e9f 100644
--- a/ext/message_admin/message_admin.civix.php
+++ b/ext/message_admin/message_admin.civix.php
@@ -133,8 +133,8 @@ function _message_admin_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php b/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php
index a5b2240cad17..bc9106e33265 100644
--- a/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php
+++ b/ext/oauth-client/Civi/Api4/Action/OAuthClient/AbstractGrantAction.php
@@ -47,10 +47,6 @@ abstract class AbstractGrantAction extends \Civi\Api4\Generic\AbstractBatchActio
*/
private $clientDef = NULL;
- public function __construct($entityName, $actionName) {
- parent::__construct($entityName, $actionName, ['*']);
- }
-
/**
* @throws \CRM_Core_Exception
*/
diff --git a/ext/oauth-client/Civi/Api4/Action/OAuthSysToken/Refresh.php b/ext/oauth-client/Civi/Api4/Action/OAuthSysToken/Refresh.php
index 3c75a945564b..5f7164e9cdf0 100644
--- a/ext/oauth-client/Civi/Api4/Action/OAuthSysToken/Refresh.php
+++ b/ext/oauth-client/Civi/Api4/Action/OAuthSysToken/Refresh.php
@@ -41,10 +41,6 @@ class Refresh extends BasicBatchAction {
private $selectFields = ['id', 'client_id', 'access_token', 'refresh_token', 'expires', 'token_type', 'raw'];
private $providers = [];
- public function __construct($entityName, $actionName) {
- parent::__construct($entityName, $actionName);
- }
-
protected function getSelect() {
return $this->selectFields;
}
diff --git a/ext/oauth-client/ang/oauthClientAdmin.aff.json b/ext/oauth-client/ang/oauthClientAdmin.aff.json
deleted file mode 100644
index dbc475018942..000000000000
--- a/ext/oauth-client/ang/oauthClientAdmin.aff.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "title": "OAuth2 Client Administration",
- "server_route": "civicrm/admin/oauth",
- "permission": "manage OAuth client"
-}
diff --git a/ext/oauth-client/ang/oauthClientAdmin.aff.php b/ext/oauth-client/ang/oauthClientAdmin.aff.php
new file mode 100644
index 000000000000..9e3783c2002a
--- /dev/null
+++ b/ext/oauth-client/ang/oauthClientAdmin.aff.php
@@ -0,0 +1,8 @@
+ E::ts('OAuth2 Client Administration'),
+ 'server_route' => 'civicrm/admin/oauth',
+ 'permission' => ['manage OAuth client'],
+];
diff --git a/ext/oauth-client/ang/oauthJwtDebug.aff.json b/ext/oauth-client/ang/oauthJwtDebug.aff.json
deleted file mode 100644
index a0ab1a28913d..000000000000
--- a/ext/oauth-client/ang/oauthJwtDebug.aff.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "title": "OAuth2 JWT Debug",
- "requires": ["unvalidatedJwtDecode", "afCore"],
- "server_route": "civicrm/admin/oauth-jwt-debug",
- "permission": "manage OAuth client secrets"
-}
\ No newline at end of file
diff --git a/ext/oauth-client/ang/oauthJwtDebug.aff.php b/ext/oauth-client/ang/oauthJwtDebug.aff.php
new file mode 100644
index 000000000000..20710ce96fdd
--- /dev/null
+++ b/ext/oauth-client/ang/oauthJwtDebug.aff.php
@@ -0,0 +1,9 @@
+ E::ts('OAuth2 JWT Debug'),
+ 'requires' => ["unvalidatedJwtDecode", "afCore"],
+ 'server_route' => 'civicrm/admin/oauth-jwt-debug',
+ 'permission' => ['manage OAuth client secrets'],
+];
diff --git a/ext/oauth-client/info.xml b/ext/oauth-client/info.xml
index 7c3666f0d9d0..5a053ade6bed 100644
--- a/ext/oauth-client/info.xml
+++ b/ext/oauth-client/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2020-10-23
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
org.civicrm.afform
@@ -33,11 +33,11 @@
ang-php@1.0.0
menu-xml@1.0.0
setting-php@1.0.0
- smarty-v2@1.0.0
+ smarty-v2@1.0.1
entity-types-php@1.0.0
CRM/OAuth
- 23.02.0
+ 23.02.1
diff --git a/ext/oauth-client/oauth_client.civix.php b/ext/oauth-client/oauth_client.civix.php
index bf8cc5fd0aa5..3134514b445d 100644
--- a/ext/oauth-client/oauth_client.civix.php
+++ b/ext/oauth-client/oauth_client.civix.php
@@ -133,8 +133,8 @@ function _oauth_client_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/oauth-client/tests/phpunit/bootstrap.php b/ext/oauth-client/tests/phpunit/bootstrap.php
index 4d64ac46f20b..a6f64881db1e 100644
--- a/ext/oauth-client/tests/phpunit/bootstrap.php
+++ b/ext/oauth-client/tests/phpunit/bootstrap.php
@@ -27,7 +27,7 @@
*/
function cv($cmd, $decode = 'json') {
$cmd = 'cv ' . $cmd;
- $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+ $descriptorSpec = [0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => STDERR];
$oldOutput = getenv('CV_OUTPUT');
putenv("CV_OUTPUT=json");
diff --git a/ext/payflowpro/info.xml b/ext/payflowpro/info.xml
index bf111f4c2bdc..035ce3f04fbb 100644
--- a/ext/payflowpro/info.xml
+++ b/ext/payflowpro/info.xml
@@ -15,10 +15,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2021-04-13
- 5.67.alpha1
+ 5.68.alpha1
stable
- 5.67
+ 5.68
This extension is extraction of the original Core Payflow Pro Payment Processor
@@ -30,6 +30,6 @@
CRM/Payflowpro
- 22.10.0
+ 23.02.1
diff --git a/ext/payflowpro/payflowpro.civix.php b/ext/payflowpro/payflowpro.civix.php
index ff6316d71584..a233c6862457 100644
--- a/ext/payflowpro/payflowpro.civix.php
+++ b/ext/payflowpro/payflowpro.civix.php
@@ -84,27 +84,17 @@ public static function findClass($suffix) {
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config
*/
-function _payflowpro_civix_civicrm_config(&$config = NULL) {
+function _payflowpro_civix_civicrm_config($config = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
- $template = CRM_Core_Smarty::singleton();
-
$extRoot = __DIR__ . DIRECTORY_SEPARATOR;
- $extDir = $extRoot . 'templates';
-
- if (is_array($template->template_dir)) {
- array_unshift($template->template_dir, $extDir);
- }
- else {
- $template->template_dir = [$extDir, $template->template_dir];
- }
-
$include_path = $extRoot . PATH_SEPARATOR . get_include_path();
set_include_path($include_path);
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -114,35 +104,7 @@ function _payflowpro_civix_civicrm_config(&$config = NULL) {
*/
function _payflowpro_civix_civicrm_install() {
_payflowpro_civix_civicrm_config();
- if ($upgrader = _payflowpro_civix_upgrader()) {
- $upgrader->onInstall();
- }
-}
-
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function _payflowpro_civix_civicrm_postInstall() {
- _payflowpro_civix_civicrm_config();
- if ($upgrader = _payflowpro_civix_upgrader()) {
- if (is_callable([$upgrader, 'onPostInstall'])) {
- $upgrader->onPostInstall();
- }
- }
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function _payflowpro_civix_civicrm_uninstall(): void {
- _payflowpro_civix_civicrm_config();
- if ($upgrader = _payflowpro_civix_upgrader()) {
- $upgrader->onUninstall();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -152,56 +114,7 @@ function _payflowpro_civix_civicrm_uninstall(): void {
*/
function _payflowpro_civix_civicrm_enable(): void {
_payflowpro_civix_civicrm_config();
- if ($upgrader = _payflowpro_civix_upgrader()) {
- if (is_callable([$upgrader, 'onEnable'])) {
- $upgrader->onEnable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- * @return mixed
- */
-function _payflowpro_civix_civicrm_disable(): void {
- _payflowpro_civix_civicrm_config();
- if ($upgrader = _payflowpro_civix_upgrader()) {
- if (is_callable([$upgrader, 'onDisable'])) {
- $upgrader->onDisable();
- }
- }
-}
-
-/**
- * (Delegated) Implements hook_civicrm_upgrade().
- *
- * @param $op string, the type of operation being performed; 'check' or 'enqueue'
- * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
- *
- * @return mixed
- * based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
- * for 'enqueue', returns void
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function _payflowpro_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- if ($upgrader = _payflowpro_civix_upgrader()) {
- return $upgrader->onUpgrade($op, $queue);
- }
-}
-
-/**
- * @return CRM_Payflowpro_Upgrader
- */
-function _payflowpro_civix_upgrader() {
- if (!file_exists(__DIR__ . '/CRM/Payflowpro/Upgrader.php')) {
- return NULL;
- }
- else {
- return CRM_Payflowpro_Upgrader_Base::instance();
- }
+ // Based on , this does not currently require mixin/polyfill.php.
}
/**
@@ -220,8 +133,8 @@ function _payflowpro_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
@@ -285,14 +198,3 @@ function _payflowpro_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID
}
}
}
-
-/**
- * (Delegated) Implements hook_civicrm_entityTypes().
- *
- * Find any *.entityType.php files, merge their content, and return.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function _payflowpro_civix_civicrm_entityTypes(&$entityTypes) {
- $entityTypes = array_merge($entityTypes, []);
-}
diff --git a/ext/payflowpro/payflowpro.php b/ext/payflowpro/payflowpro.php
index 3479e41c7344..7a30241d23db 100644
--- a/ext/payflowpro/payflowpro.php
+++ b/ext/payflowpro/payflowpro.php
@@ -23,24 +23,6 @@ function payflowpro_civicrm_install() {
_payflowpro_civix_civicrm_install();
}
-/**
- * Implements hook_civicrm_postInstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
- */
-function payflowpro_civicrm_postInstall() {
- _payflowpro_civix_civicrm_postInstall();
-}
-
-/**
- * Implements hook_civicrm_uninstall().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
- */
-function payflowpro_civicrm_uninstall() {
- _payflowpro_civix_civicrm_uninstall();
-}
-
/**
* Implements hook_civicrm_enable().
*
@@ -49,32 +31,3 @@ function payflowpro_civicrm_uninstall() {
function payflowpro_civicrm_enable() {
_payflowpro_civix_civicrm_enable();
}
-
-/**
- * Implements hook_civicrm_disable().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
- */
-function payflowpro_civicrm_disable() {
- _payflowpro_civix_civicrm_disable();
-}
-
-/**
- * Implements hook_civicrm_upgrade().
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
- */
-function payflowpro_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
- return _payflowpro_civix_civicrm_upgrade($op, $queue);
-}
-
-/**
- * Implements hook_civicrm_entityTypes().
- *
- * Declare entity types provided by this module.
- *
- * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
- */
-function payflowpro_civicrm_entityTypes(&$entityTypes) {
- _payflowpro_civix_civicrm_entityTypes($entityTypes);
-}
diff --git a/ext/payflowpro/tests/phpunit/bootstrap.php b/ext/payflowpro/tests/phpunit/bootstrap.php
index 5133778c8191..63c9148e8e1c 100644
--- a/ext/payflowpro/tests/phpunit/bootstrap.php
+++ b/ext/payflowpro/tests/phpunit/bootstrap.php
@@ -26,7 +26,7 @@
*/
function cv($cmd, $decode = 'json') {
$cmd = 'cv ' . $cmd;
- $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+ $descriptorSpec = [0 => ["pipe", "r"], 1 => ["pipe", "w"], 2 => STDERR];
$oldOutput = getenv('CV_OUTPUT');
putenv("CV_OUTPUT=json");
diff --git a/ext/recaptcha/info.xml b/ext/recaptcha/info.xml
index 5c67f330d660..856115e71c44 100644
--- a/ext/recaptcha/info.xml
+++ b/ext/recaptcha/info.xml
@@ -13,27 +13,27 @@
http://www.gnu.org/licenses/agpl-3.0.html
2021-04-03
- 5.67.alpha1
+ 5.68.alpha1
mgmt:hidden
stable
- 5.67
+ 5.68
- menu-xml@1.0.0
+ setting-admin@1.0.0
setting-php@1.0.0
ang-php@1.0.0
scan-classes@1.0.0
- smarty-v2@1.0.0
+ smarty-v2@1.0.1
CRM/Recaptcha
- 23.02.0
+ 23.02.1
diff --git a/ext/recaptcha/recaptcha.civix.php b/ext/recaptcha/recaptcha.civix.php
index 13f0af1218f2..6c1d618f1e4a 100644
--- a/ext/recaptcha/recaptcha.civix.php
+++ b/ext/recaptcha/recaptcha.civix.php
@@ -133,8 +133,8 @@ function _recaptcha_civix_insert_navigation_menu(&$menu, $path, $item) {
if (empty($path)) {
$menu[] = [
'attributes' => array_merge([
- 'label' => CRM_Utils_Array::value('name', $item),
- 'active' => 1,
+ 'label' => $item['name'] ?? NULL,
+ 'active' => 1,
], $item),
];
return TRUE;
diff --git a/ext/recaptcha/recaptcha.php b/ext/recaptcha/recaptcha.php
index e959cfb329c9..49e8e1c7b5a8 100644
--- a/ext/recaptcha/recaptcha.php
+++ b/ext/recaptcha/recaptcha.php
@@ -32,21 +32,6 @@ function recaptcha_civicrm_enable() {
_recaptcha_civix_civicrm_enable();
}
-/**
- * Implements hook_civicrm_navigationMenu().
- */
-function recaptcha_civicrm_navigationMenu(&$menu) {
- _recaptcha_civix_insert_navigation_menu($menu, 'Administer/System Settings', [
- 'label' => E::ts('reCAPTCHA Settings'),
- 'name' => 'recaptcha_settings',
- 'url' => 'civicrm/admin/setting/recaptcha',
- 'permission' => 'administer CiviCRM',
- 'operator' => 'OR',
- 'separator' => 0,
- ]);
- _recaptcha_civix_navigationMenu($menu);
-}
-
/**
* Intercept form functions
*/
diff --git a/ext/recaptcha/xml/Menu/recaptcha.xml b/ext/recaptcha/xml/Menu/recaptcha.xml
deleted file mode 100644
index 558cefcf2c4e..000000000000
--- a/ext/recaptcha/xml/Menu/recaptcha.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- -
-
civicrm/admin/setting/recaptcha
- reCAPTCHA Settings
- Configure anti-abuse/bot-prevention service
- CRM_Admin_Form_Generic
- administer CiviCRM
- System Settings
-
-
diff --git a/ext/scheduled_communications/info.xml b/ext/scheduled_communications/info.xml
index 7dd9c6766a46..be78bc666cf0 100644
--- a/ext/scheduled_communications/info.xml
+++ b/ext/scheduled_communications/info.xml
@@ -13,10 +13,10 @@
http://www.gnu.org/licenses/agpl-3.0.html
2023-09-04
- 5.67.alpha1
+ 5.68.alpha1
beta
- 5.67
+ 5.68
Click on the chat link above to discuss development, report problems or ask questions.
diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
index 427a34f71718..69acf8e3ff24 100644
--- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
+++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
@@ -177,7 +177,7 @@ private function getValue($key, $data, $rowIndex) {
default:
if (!empty($data[$key])) {
$item = $this->getSelectExpression($key);
- if ($item['expr'] instanceof SqlField && $item['fields'][$key]['fk_entity'] === 'File') {
+ if ($item['expr'] instanceof SqlField && isset($item['fields'][$key]) && $item['fields'][$key]['fk_entity'] === 'File') {
return $this->generateFileUrl($data[$key]);
}
}
@@ -519,9 +519,12 @@ protected function formatLink(array $link, array $data, string $text = NULL, $in
$link['url'] = $this->getUrl($path);
$keys = ['url', 'text', 'title', 'target', 'icon', 'style', 'autoOpen'];
}
- else {
+ elseif (!empty($link['task'])) {
$keys = ['task', 'text', 'title', 'icon', 'style'];
}
+ else {
+ return NULL;
+ }
$link = array_intersect_key($link, array_flip($keys));
return array_filter($link, function($value) {
// "0" is a valid title
@@ -590,6 +593,9 @@ private function checkLinkAccess(array $link, array $data, int $index = 0): bool
private function getPermittedLinkAction(string $entityName, string $actionName): ?string {
// Load api actions and cache for performance (this function may be called hundreds of times per request)
if (!isset($this->entityActions[$entityName])) {
+ if (!CoreUtil::entityExists($entityName)) {
+ return NULL;
+ }
$this->entityActions[$entityName] = [
'all' => civicrm_api4($entityName, 'getActions', ['checkPermissions' => FALSE])->column('name'),
'allowed' => civicrm_api4($entityName, 'getActions', ['checkPermissions' => TRUE])->column('name'),
@@ -668,10 +674,11 @@ private function getLinkInfo(array $link): array {
'text' => '',
'title' => '',
'prefix' => '',
+ 'key' => '',
];
$entity = $link['entity'];
- $idKey = $this->getIdKeyName($link['entity']);
- if ($entity) {
+ if ($entity && CoreUtil::entityExists($entity)) {
+ $idKey = $this->getIdKeyName($entity);
// Hack to support links to relationships
if ($entity === 'Relationship') {
$entity = 'RelationshipCache';
@@ -715,8 +722,8 @@ private function getLinkInfo(array $link): array {
$link['action'] = $task['apiBatch']['action'] ?? NULL;
}
}
+ $link['key'] = $link['prefix'] . $idKey;
}
- $link['key'] = $link['prefix'] . $idKey;
return $link;
}
@@ -1140,7 +1147,7 @@ protected function augmentSelectClause(&$apiParams): void {
}
// Add primary key field if actions are enabled
// (only needed for non-dao entities, as Api4SelectQuery will auto-add the id)
- if (!in_array('DAOEntity', CoreUtil::getInfoItem($this->savedSearch['api_entity'], 'type')) &&
+ if (!CoreUtil::isType($this->savedSearch['api_entity'], 'DAOEntity') &&
(!empty($this->display['settings']['actions']) || !empty($this->display['settings']['draggable']))
) {
$this->addSelectExpression(CoreUtil::getIdFieldName($this->savedSearch['api_entity']));
@@ -1388,14 +1395,17 @@ private function getAfformDirectiveFilters() {
if ($filterAttr && is_string($filterAttr) && $filterAttr[0] === '{') {
foreach (\CRM_Utils_JS::decode($filterAttr) as $filterKey => $filterVal) {
// Automatically apply filters from the markup if they have a value
- if ($filterVal !== NULL) {
+ // Only do this if there's one instance of the display on the form
+ if ($afform['searchDisplay']['count'] === 1 && $filterVal !== NULL) {
unset($this->filters[$filterKey]);
if ($this->hasValue($filterVal)) {
$this->applyFilter(explode(',', $filterKey), $filterVal);
}
}
// If it's a javascript variable it will have come back from decode() as NULL;
- // whitelist it to allow it to be passed to this api from javascript.
+ // Or if there's more than one instance of the display on the form, they might
+ // use different filters.
+ // Just whitelist it so the value passed in will be accepted.
else {
$filterKeys[] = $filterKey;
}
@@ -1423,22 +1433,37 @@ private function loadAfform() {
if (empty($afform['layout'])) {
return FALSE;
}
+ $afform['searchDisplay'] = NULL;
// Get all search display fieldsets (which will have an empty value for the af-fieldset attribute)
$fieldsets = \CRM_Utils_Array::findAll($afform['layout'], ['af-fieldset' => '']);
// As a fallback, search the entire afform in case the search display is not in a fieldset
$fieldsets['form'] = $afform['layout'];
- // Validate that the afform contains this search display
+ // Search for one or more instance of this search display
foreach ($fieldsets as $key => $fieldset) {
- $afform['searchDisplay'] = \CRM_Utils_Array::findAll(
- $fieldset,
- ['#tag' => $this->display['type:name'], 'search-name' => $this->savedSearch['name'], 'display-name' => $this->display['name']]
- )[0] ?? NULL;
+ if ($key === 'form' && $afform['searchDisplay']) {
+ // Already found in a fieldset, don't search the whole form
+ continue;
+ }
+ $displays = \CRM_Utils_Array::findAll(
+ $fieldset,
+ ['#tag' => $this->display['type:name'], 'search-name' => $this->savedSearch['name'], 'display-name' => $this->display['name']]
+ );
+ if (!$displays) {
+ continue;
+ }
+ // Already found, just increment the count
if ($afform['searchDisplay']) {
+ $afform['searchDisplay']['count'] += count($displays);
+ }
+ else {
+ $afform['searchDisplay'] = $displays[0];
+ $afform['searchDisplay']['count'] = count($displays);
// Set the fieldset for this display (if it is in one and we haven't fallen back to the whole form)
+ // TODO: This just uses the first fieldset, but there could be multiple. Potentially could use filters to match it.
$afform['searchDisplay']['fieldset'] = $key === 'form' ? [] : $fieldset;
- return $this->_afform = $afform;
}
}
+ $this->_afform = $afform;
}
return $this->_afform;
}
diff --git a/ext/search_kit/Civi/Api4/Service/Spec/Provider/SearchDisplayCreationSpecProvider.php b/ext/search_kit/Civi/Api4/Service/Spec/Provider/SearchDisplayCreationSpecProvider.php
index 963e63ef2dfa..618ecad57478 100644
--- a/ext/search_kit/Civi/Api4/Service/Spec/Provider/SearchDisplayCreationSpecProvider.php
+++ b/ext/search_kit/Civi/Api4/Service/Spec/Provider/SearchDisplayCreationSpecProvider.php
@@ -24,8 +24,7 @@ class SearchDisplayCreationSpecProvider extends \Civi\Core\Service\AutoService i
* @inheritDoc
*/
public function modifySpec(RequestSpec $spec) {
- $spec->getFieldByName('name')->setRequired(FALSE)->setRequiredIf('empty($values.label)');
- $spec->getFieldByName('label')->setRequired(FALSE)->setRequiredIf('empty($values.name)');
+ $spec->getFieldByName('name')->setRequired(FALSE);
}
/**
diff --git a/ext/search_kit/Civi/Search/Admin.php b/ext/search_kit/Civi/Search/Admin.php
index 8232f2523325..14e4adc53990 100644
--- a/ext/search_kit/Civi/Search/Admin.php
+++ b/ext/search_kit/Civi/Search/Admin.php
@@ -53,7 +53,7 @@ public static function getAdminSettings():array {
->setLoadOptions(['id', 'label'])
->execute()->first()['options'],
'tags' => Tag::get()
- ->addSelect('id', 'name', 'color', 'is_selectable', 'description')
+ ->addSelect('id', 'label', 'color', 'is_selectable', 'description')
->addWhere('used_for', 'CONTAINS', 'civicrm_saved_search')
->execute(),
];
@@ -95,6 +95,8 @@ public static function getOperators():array {
'NOT LIKE' => E::ts('Not Like'),
'REGEXP' => E::ts('Matches Pattern'),
'NOT REGEXP' => E::ts("Doesn't Match Pattern"),
+ 'REGEXP BINARY' => E::ts('Matches Pattern (case-sensitive)'),
+ 'NOT REGEXP BINARY' => E::ts("Doesn't Match Pattern (case-sensitive)"),
'BETWEEN' => E::ts('Is Between'),
'NOT BETWEEN' => E::ts('Not Between'),
'IS EMPTY' => E::ts('Is Empty'),
diff --git a/ext/search_kit/ang/crmSearchAdmin.module.js b/ext/search_kit/ang/crmSearchAdmin.module.js
index 01947260a024..1b9adf9ffdf0 100644
--- a/ext/search_kit/ang/crmSearchAdmin.module.js
+++ b/ext/search_kit/ang/crmSearchAdmin.module.js
@@ -55,7 +55,7 @@
modules.push({text: label, id: key});
}, []), 'text');
this.getTags = function() {
- return {results: formatForSelect2(CRM.crmSearchAdmin.tags, 'id', 'name', ['color', 'description'])};
+ return {results: formatForSelect2(CRM.crmSearchAdmin.tags, 'id', 'label', ['color', 'description'])};
};
this.getPrimaryEntities = function() {
diff --git a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminLinkGroup.component.js b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminLinkGroup.component.js
index 532541bcc6ab..ef28cde5517c 100644
--- a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminLinkGroup.component.js
+++ b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminLinkGroup.component.js
@@ -32,8 +32,10 @@
this.getField = searchMeta.getField;
this.fields = function() {
- var selectFields = ctrl.crmSearchAdmin.getSelectFields();
- var permissionField = [{
+ let selectFields = ctrl.crmSearchAdmin.getSelectFields();
+ // Use machine names not labels for option matching
+ selectFields.forEach((field) => field.id = field.id.replace(':label', ':name'));
+ let permissionField = [{
text: ts('Current User Permission'),
id: 'check user permission',
description: ts('Check permission of logged-in user')
diff --git a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.component.js b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.component.js
index 0527d1a1c458..a17d18c02d81 100644
--- a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.component.js
+++ b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.component.js
@@ -64,9 +64,9 @@
}
};
- this.makeTag = function(name) {
+ this.makeTag = function(label) {
crmApi4('Tag', 'create', {
- values: {name: name, color: ctrl.color, is_selectable: true, used_for: ['civicrm_saved_search']}
+ values: {label: label, color: ctrl.color, is_selectable: true, used_for: ['civicrm_saved_search']}
}, 0).then(function(tag) {
ctrl.allTags.push(tag);
ctrl.toggleTag(tag);
diff --git a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.html b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.html
index 31711443dc46..26e52e3bf072 100644
--- a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.html
+++ b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminTags.html
@@ -16,14 +16,14 @@
{{ $ctrl.search }}
-
+
- {{:: tag.name }}
+ {{:: tag.label }}
- {{:: $ctrl.getTag(id).name }}
+ {{:: $ctrl.getTag(id).label }}
diff --git a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminCssRules.component.js b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminCssRules.component.js
index 3111e4a8b528..008b19bb54bb 100644
--- a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminCssRules.component.js
+++ b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminCssRules.component.js
@@ -28,9 +28,12 @@
this.styles.strikethrough = ts('Strikethrough');
this.fields = function() {
- var allFields = ctrl.crmSearchAdmin.getAllFields(':name', ['Field', 'Custom', 'Extra', 'Pseudo']);
+ let allFields = ctrl.crmSearchAdmin.getAllFields(':name', ['Field', 'Custom', 'Extra', 'Pseudo']);
+ let selectFields = ctrl.crmSearchAdmin.getSelectFields();
+ // Use machine names not labels for option matching
+ selectFields.forEach((field) => field.id = field.id.replace(':label', ':name'));
return {
- results: ctrl.crmSearchAdmin.getSelectFields().concat(allFields)
+ results: selectFields.concat(allFields)
};
};
diff --git a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js
index 6a7d439f9e90..323b09c7734a 100644
--- a/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js
+++ b/ext/search_kit/ang/crmSearchAdmin/displays/common/searchAdminIcons.component.js
@@ -16,9 +16,12 @@
this.getField = searchMeta.getField;
this.fields = function() {
- var allFields = ctrl.crmSearchAdmin.getAllFields(':name', ['Field', 'Custom', 'Extra', 'Pseudo']);
+ let allFields = ctrl.crmSearchAdmin.getAllFields(':name', ['Field', 'Custom', 'Extra', 'Pseudo']);
+ let selectFields = ctrl.crmSearchAdmin.getSelectFields();
+ // Use machine names not labels for option matching
+ selectFields.forEach((field) => field.id = field.id.replace(':label', ':name'));
return {
- results: ctrl.crmSearchAdmin.getSelectFields().concat(allFields)
+ results: selectFields.concat(allFields)
};
};
diff --git a/ext/search_kit/ang/crmSearchDisplay/Pager.html b/ext/search_kit/ang/crmSearchDisplay/Pager.html
index 97c1e0009373..f50d93744b6a 100644
--- a/ext/search_kit/ang/crmSearchDisplay/Pager.html
+++ b/ext/search_kit/ang/crmSearchDisplay/Pager.html
@@ -20,7 +20,7 @@
>
-
+
{{:: ts('Page Size') }}
diff --git a/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js b/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
index 46eed4615d21..e9ddec24a94c 100644
--- a/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
+++ b/ext/search_kit/ang/crmSearchDisplay/crmSearchDisplayEditable.component.js
@@ -32,11 +32,12 @@
nullable: col.edit.nullable
};
- $(document).on('keydown.crmSearchDisplayEditable', function(e) {
+ $(document).on('keydown.crmSearchDisplayEditable', (e) => {
if (e.key === 'Escape') {
- $scope.$apply(function() {
- ctrl.cancel();
- });
+ $scope.$apply(() => ctrl.cancel());
+ }
+ else if (e.key === 'Enter') {
+ $scope.$apply(() => ctrl.save());
}
});
diff --git a/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js b/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
index ec7eee2d192b..7aa7a70ede4e 100644
--- a/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
+++ b/ext/search_kit/ang/crmSearchDisplay/traits/searchDisplayBaseTrait.service.js
@@ -51,7 +51,8 @@
// Update totalCount only if no user filters are set
if (typeof rowCount === 'number' && angular.equals({}, ctrl.getAfformFilters())) {
ctrl.totalCount = rowCount;
- if (contactTab) {
+ // The first display in a tab gets to control the count
+ if (contactTab && $element.is($('#' + contactTab + ' [search][display]').first())) {
CRM.tabHeader.updateCount(contactTab.replace('contact-', '#tab_'), rowCount);
}
}
diff --git a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html
index 81cfafe4a1ac..5ca040d1f6a0 100644
--- a/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html
+++ b/ext/search_kit/ang/crmSearchDisplayTable/crmSearchDisplayTable.html
@@ -11,7 +11,7 @@
-
+
{{:: col.label }}
diff --git a/ext/search_kit/ang/crmSearchTasks/crmSearchInput/crmSearchInputVal.component.js b/ext/search_kit/ang/crmSearchTasks/crmSearchInput/crmSearchInputVal.component.js
index 102e2bc36f78..8225a2f7e8ba 100644
--- a/ext/search_kit/ang/crmSearchTasks/crmSearchInput/crmSearchInputVal.component.js
+++ b/ext/search_kit/ang/crmSearchTasks/crmSearchInput/crmSearchInputVal.component.js
@@ -125,7 +125,7 @@
this.getTemplate = function() {
var field = ctrl.field || {};
- if (_.includes(['LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP'], ctrl.op)) {
+ if (_.includes(['LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP', 'REGEXP BINARY', 'NOT REGEXP BINARY'], ctrl.op)) {
return '~/crmSearchTasks/crmSearchInput/text.html';
}
diff --git a/ext/search_kit/ang/crmSearchTasks/crmSearchInput/date.html b/ext/search_kit/ang/crmSearchTasks/crmSearchInput/date.html
index f5c7508be3e6..5fdfa72670bf 100644
--- a/ext/search_kit/ang/crmSearchTasks/crmSearchInput/date.html
+++ b/ext/search_kit/ang/crmSearchTasks/crmSearchInput/date.html
@@ -10,7 +10,7 @@
-
+
diff --git a/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.ctrl.js b/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.ctrl.js
index bace4279079c..ed1ac2f9c228 100644
--- a/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.ctrl.js
+++ b/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.ctrl.js
@@ -14,16 +14,16 @@
crmApi4({
tags: ['Tag', 'get', {
- select: ['id', 'name', 'color', 'description', 'is_selectable', 'parent_id'],
+ select: ['id', 'label', 'color', 'description', 'is_selectable', 'parent_id'],
where: [
['is_tagset', '=', false],
['used_for:name', 'CONTAINS', this.entity],
['OR', [['parent_id', 'IS NULL'], ['parent_id.is_tagset', '=', false]]]
],
- orderBy: {name: 'ASC'}
+ orderBy: {label: 'ASC'}
}],
tagsets: ['Tag', 'get', {
- select: ['id', 'name'],
+ select: ['id', 'name', 'label'],
where: [['is_tagset', '=', true], ['used_for:name', 'CONTAINS', this.entity]]
}],
}).then(function(result) {
@@ -36,7 +36,7 @@
var sorted = _.transform(rawTags, function(sorted, tag) {
sorted[tag.id] = {
id: tag.id,
- text: tag.name,
+ text: tag.label,
description: tag.description,
color: tag.color,
disabled: !tag.is_selectable,
diff --git a/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.html b/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.html
index 51363c6e9d3b..d1bb6a09d8f2 100644
--- a/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.html
+++ b/ext/search_kit/ang/crmSearchTasks/crmSearchTaskTag.html
@@ -28,7 +28,7 @@
>
{else}
@@ -90,7 +90,7 @@
{ts}Activity Type{/ts}
{* activityTypeName means label here not name, but it's ok because label is desired here (dev/core#1116-ok-label) *}
- {$activityTypeName|escape}
+ {$activityTypeNameAndLabel.label|escape}
{$form.source_contact_id.label}
diff --git a/templates/CRM/Case/Form/ActivityTab.tpl b/templates/CRM/Case/Form/ActivityTab.tpl
index 2b778bbcc494..683da8bf18ff 100644
--- a/templates/CRM/Case/Form/ActivityTab.tpl
+++ b/templates/CRM/Case/Form/ActivityTab.tpl
@@ -31,12 +31,12 @@
- {assign var=activitylow value=activity_date_low_$caseID}
+ {assign var=activitylow value="activity_date_low_`$caseID`"}
{$form.$activitylow.label}
{$form.$activitylow.html}
- {assign var=activityhigh value=activity_date_high_$caseID}
+ {assign var=activityhigh value="activity_date_high_`$caseID`"}
{$form.$activityhigh.label}
{$form.$activityhigh.html}
diff --git a/templates/CRM/Case/Form/CaseView.tpl b/templates/CRM/Case/Form/CaseView.tpl
index bb5d90f05809..dc6b80ea4071 100644
--- a/templates/CRM/Case/Form/CaseView.tpl
+++ b/templates/CRM/Case/Form/CaseView.tpl
@@ -304,8 +304,8 @@
{foreach from=$tagSetTags item=displayTagset}
- {$displayTagset.name}:
- {', '|implode:$displayTagset.items}
+ {$displayTagset.label}:
+ {', '|implode:$displayTagset.items|escape}
{/foreach}
diff --git a/templates/CRM/Contact/Form/Domain.tpl b/templates/CRM/Contact/Form/Domain.tpl
index d1328bff1c74..cd5536da6e88 100644
--- a/templates/CRM/Contact/Form/Domain.tpl
+++ b/templates/CRM/Contact/Form/Domain.tpl
@@ -27,7 +27,7 @@
{ts}Default Organization Address{/ts}
- {ts 1={domain.address}}CiviMail mailings must include the sending organization's address. This is done by putting the %1 token in either the body or footer of the mailing. This token may also be used in regular 'Email - send now' messages and in other Message Templates. The token is replaced by the address entered below when the message is sent.{/ts}
+ {ts 1="{domain.address}"}CiviMail mailings must include the sending organization's address. This is done by putting the %1 token in either the body or footer of the mailing. This token may also be used in regular 'Email - send now' messages and in other Message Templates. The token is replaced by the address entered below when the message is sent.{/ts}
{include file="CRM/Contact/Form/Edit/Address.tpl" blockId=1 masterAddress='' parseStreetAddress='' className=''}
{ts}Organization Contact Information{/ts}
{ts}You can also include general email and/or phone contact information in mailings.{/ts} {help id="additional-contact"}
diff --git a/templates/CRM/Contact/Form/Edit/Address.tpl b/templates/CRM/Contact/Form/Edit/Address.tpl
index 6a1365111ebe..b0da0bf2ff71 100644
--- a/templates/CRM/Contact/Form/Edit/Address.tpl
+++ b/templates/CRM/Contact/Form/Edit/Address.tpl
@@ -50,9 +50,9 @@
diff --git a/templates/CRM/Contact/Form/Edit/Organization.tpl b/templates/CRM/Contact/Form/Edit/Organization.tpl
index 0aaf0d394213..db66fdc2837c 100644
--- a/templates/CRM/Contact/Form/Edit/Organization.tpl
+++ b/templates/CRM/Contact/Form/Edit/Organization.tpl
@@ -11,26 +11,28 @@
diff --git a/templates/CRM/Contact/Form/Inline/Address.tpl b/templates/CRM/Contact/Form/Inline/Address.tpl
index 2a9ceebcea34..1985b3a6de7b 100644
--- a/templates/CRM/Contact/Form/Inline/Address.tpl
+++ b/templates/CRM/Contact/Form/Inline/Address.tpl
@@ -43,9 +43,9 @@
diff --git a/templates/CRM/Contact/Form/RelatedContact.tpl b/templates/CRM/Contact/Form/RelatedContact.tpl
index e4eebab4a1a3..0a226a175565 100644
--- a/templates/CRM/Contact/Form/RelatedContact.tpl
+++ b/templates/CRM/Contact/Form/RelatedContact.tpl
@@ -9,7 +9,7 @@
*}
{* This file provides the HTML for the edit Related contact form *}
-{include file=CRM/Contact/Form/OnBehalfOf.tpl}
+{include file="CRM/Contact/Form/OnBehalfOf.tpl"}