Fix OptionValue BAO to call pre/post hooks to prevent force-reset of managed entities
authorColeman Watts <coleman@civicrm.org>
Thu, 7 Apr 2022 19:40:30 +0000 (15:40 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 7 Apr 2022 23:28:54 +0000 (19:28 -0400)
Managed entities rely on pre/post hooks being called in order to track whether an entity
has been modified. Without those hooks OptionValues were being force-reverted by the
managed system even when the 'update' mode was set to 'unmodified', which is supposed
to defer to user modifications.

CRM/Core/BAO/OptionValue.php
tests/phpunit/api/v4/Entity/ManagedEntityTest.php

index 0214ca3072b40739f0b1a2eca32dc873433c2e2f..bb49356d77b4accb56d544633f382e5ed6e2d82f 100644 (file)
@@ -155,6 +155,9 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
       $params['option_group_id'], 'name', 'id'
     );
 
+    $op = $id ? 'edit' : 'create';
+    CRM_Utils_Hook::pre($op, 'OptionValue', $id, $params);
+
     // action is taken depending upon the mode
     $optionValue = new CRM_Core_DAO_OptionValue();
     $optionValue->copyValues($params);
@@ -218,6 +221,8 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
     $optionValue->save();
     CRM_Core_PseudoConstant::flush();
 
+    CRM_Utils_Hook::post($op, 'OptionValue', $id, $optionValue);
+
     // Create relationship for payment instrument options
     if (!empty($params['financial_account_id'])) {
       $optionName = civicrm_api3('OptionGroup', 'getvalue', [
index 13eb440498a0d82e129b8925a70b3a20ed2c70ed..ee238e7797200854d27cbcf4478d22e5646874bf 100644 (file)
@@ -307,11 +307,21 @@ class ManagedEntityTest extends UnitTestCase implements TransactionalInterface,
     \CRM_Core_ManagedEntities::singleton(TRUE)->reconcile();
 
     $values = OptionValue::get(FALSE)
+      ->addSelect('*', 'local_modified_date', 'has_base')
       ->addWhere('option_group_id.name', '=', 'testManagedOptionGroup')
       ->execute();
 
     $this->assertCount(1, $values);
     $this->assertEquals('Option Value 1', $values[0]['label']);
+    $this->assertNull($values[0]['local_modified_date']);
+    $this->assertTrue($values[0]['has_base']);
+
+    // Update option 1, now it should have a local_modified_date
+    // And the new label should persist after a reconcile
+    $result = OptionValue::update(FALSE)
+      ->addWhere('id', '=', $values[0]['id'])
+      ->addValue('label', '1 New Label')
+      ->execute();
 
     $optionValue2 = [
       'module' => 'civicrm',
@@ -333,8 +343,8 @@ class ManagedEntityTest extends UnitTestCase implements TransactionalInterface,
         ],
       ],
     ];
-
     $this->_managedEntities[] = $optionValue2;
+
     \CRM_Core_ManagedEntities::singleton(TRUE)->reconcile();
 
     $values = OptionValue::get(FALSE)
@@ -344,9 +354,12 @@ class ManagedEntityTest extends UnitTestCase implements TransactionalInterface,
       ->execute();
 
     $this->assertCount(2, $values);
-    $this->assertEquals('Option Value 2', $values[1]['label']);
-    $this->assertNull($values[0]['local_modified_date']);
+    $this->assertEquals('1 New Label', $values[0]['label']);
+    $this->assertNotNull($values[0]['local_modified_date']);
     $this->assertTrue($values[0]['has_base']);
+    $this->assertEquals('Option Value 2', $values[1]['label']);
+    $this->assertNull($values[1]['local_modified_date']);
+    $this->assertTrue($values[1]['has_base']);
 
     $this->_managedEntities = [];
     \CRM_Core_ManagedEntities::singleton(TRUE)->reconcile();