Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRM-21466 - Fix (obscure) enotice when updating greeting for contact,… #11310

Merged
merged 2 commits into from
Dec 4, 2017

Conversation

eileenmcnaughton
Copy link
Contributor

@eileenmcnaughton eileenmcnaughton commented Nov 22, 2017

Overview

If I try to update the greeting template on an existing contact I get an e-notice when trying to call

$contact = $this->callAPISuccess('Contact', 'create', array(
{{  'id' => $contact['id'], }}
 'postal_greeting_id' => 2,
));

Before

e-notice

After

resolved. Tests added and caching issues that are blockers to tests fixed

Technical Details

The issue occurs when calling
{{CRM_Core_PseudoConstant::greeting($filter); }}
with a filter for contact_type.

Contact type is unknown at this point. Further passing it in makes the code LESS efficient rather than MORE efficient. The code loads possible values to a static index. If it returns too many options no harm is done because the calling code is only looking for the one option for which it has an ID. If, however, it does filter it then it means it stores one static var for household, one for individual & one for organisation, resulting in marginally more queries running. (I think the performance is marginal in both scenarios but just trying to explore what reason, if any, there is for the filter.)

@@ -234,7 +234,7 @@ public static function add(&$params, $ids = array()) {

$optionValue->id = CRM_Utils_Array::value('optionValue', $ids);
$optionValue->save();
CRM_Core_PseudoConstant::flush();
CRM_Core_OptionGroup::flushAll();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling CRM_Core_PseudoConstant::flush() with no params simply results in CRM_Core_OptionGroup::flushAll() being called -so this is for clarity

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's not all it does. It also clears the CRM_Core_PseudoConstant::$cache variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like that is not a real property though. I can't see anywhere that self::cache is set - it seems to me that either you call the function with the implicit param 'cache' and it does nothing in the first bit because CRM_Core_PseudoConstant::cache does not exist AND it does an OptionGroup flush in the second part. Or you pass in a parameter to flush & it clears that and not the optionGroup

  /**
   * Flush given pseudoconstant so it can be reread from db.
   * nex time it's requested.
   *
   *
   * @param bool|string $name pseudoconstant to be flushed
   */
  public static function flush($name = 'cache') {
    if (isset(self::$$name)) {
      self::$$name = NULL;
    }
    if ($name == 'cache') {
      CRM_Core_OptionGroup::flushAll();
    }
  }

(It's called from 3 places outside unit tests - including this one)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of those 3 is CRM_Utils_PseudoConstant::flushAll(); - which DOES flush all properties that are set. The last is OptionValue::delete

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable is used by CRM_Core_PseudoConstant::get() so almost all pseudoconstant lookups rely on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - I can see it now - I'll flip that back

@@ -618,7 +618,6 @@ function _civicrm_api3_greeting_format_params($params) {

$nullValue = FALSE;
$filter = array(
'contact_type' => $params['contact_type'],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enotice fix when not set + this is not really the place to worry about filtering

}
// Refresh contact tokens in case they have changed. There is heavy caching
// in exportable fields so there is no benefit in doing this conditionally.
self::$_tokens['contact'] = array_merge(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditch static var which makes tests hard & does not acheive much

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -1650,6 +1650,10 @@ public static function countryIDForStateID($stateID) {
* array reference of all greetings.
*/
public static function greeting($filter, $columnName = 'label') {
if (!isset(Civi::$statics[__CLASS__]['greeting'])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the changes in CRM/Core/PseudoConstant.php are already merged, apparently in PR #11313. I think that explains the "merge conflict" error in the Jenkins checks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only thing that stands out to me, @eileenmcnaughton . Other changes look sensible, I can't think of any way to improve them.

But oddly, I'm not seeing the E_NOTICE you mention, using code like you provided, on master:

  public function testNotice() {
    // This will cause a failing test because of the NOTICE-level error:
    // trigger_error('Notice.', E_USER_NOTICE);
    // But with that line commented out, the test passes just fine.

    $contact_id = $this->individualCreate();    
    $contact = $this->callAPISuccess('Contact', 'create', array(
     'contact_type' => 'Individual',
     'id' => $contact_id,
     'postal_greeting_id' => 2,
    ));
  }

@eileenmcnaughton
Copy link
Contributor Author

I've rebased it - I actually have a few more related tidy ups on this code locally - which I will put up once this is merged - I think they tie in quite well with your goals

@@ -234,7 +234,7 @@ public static function add(&$params, $ids = array()) {

$optionValue->id = CRM_Utils_Array::value('optionValue', $ids);
$optionValue->save();
CRM_Core_PseudoConstant::flush();
CRM_Core_OptionGroup::flushAll();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's not all it does. It also clears the CRM_Core_PseudoConstant::$cache variable.

if (isset(Civi::$statics['CRM_Core_PseudoConstant']['greeting'])) {
unset(Civi::$statics['CRM_Core_PseudoConstant']['greeting']);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a strange oddball. Why is this cache variable being stored in Civi::$statics instead of in CRM_Core_PseudoConstant::$cache? If it was in the latter then no special function would be needed and CRM_Core_PseudoConstant::flush() would take care of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been consistently moving towards storing statics in Civi::Statics - I can go a different way if you want - but there are a lot of places where that has been done. Note that CiviStatics IS flushed between test runs - but there is sometimes a need to flush a value once it has been altered. We don't normally flush all PseudoConstants in order to achieve that since there is still a performance benefit in keeping most of our cached variables.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think putting it in CRM_Core_PseudoConstant::$cache would be better because we then wouldn't need this function. If we followed the pattern you're establishing here of a clear function for every variable, this file would get quite long & unwieldy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this function because I added in to unset Civi::statics[CLASS] in the CRM_Core_PseudoConstant function. There are already a few functions in that class using the Civi::statics.

…ulated.

This involves fixing the caching to be flushed during testing
@colemanw
Copy link
Member

colemanw commented Dec 4, 2017

Cool. We should probably also move CRM_Core_PseudoConstant::$cache over to Civi::$statics. Not necessarily in this PR.

@eileenmcnaughton
Copy link
Contributor Author

yep - that feels like what we are working towards. Is this merge-on-pass now?

@eileenmcnaughton eileenmcnaughton merged commit fa8ef27 into civicrm:master Dec 4, 2017
sluc23 pushed a commit to ixiam/civicrm-core that referenced this pull request Jan 10, 2018
CRM-21466 - Fix (obscure) enotice when updating greeting for contact,…
eileenmcnaughton added a commit to eileenmcnaughton/civicrm-core that referenced this pull request Feb 1, 2018
2 commits from civicrm#11310

CRM-21466 - Fix (obscure) enotice when updating greeting for contact, add test
CRM-21466 follow up, add unit test to ensure custom fields can be populated.

This involves fixing the caching to be flushed during testing

Change-Id: Ic296f2b37a8ea169b93df314b95d2502d2e2b3f1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants