Saving a case type can give a php warning, but the warning is more hidden than usual so it seems like everything is ok
Ignoring for the moment the part about the hidden warning, what's happening is:
When you retrieve a case type, e.g. via the api or lower level functions, this line is doing this:
$activityType = json_decode(json_encode($activityTypeXML), TRUE);
which seems to be a quickie way of converting the whole object and its children to an array. This works fine when none of the children have blank node text, and you get $caseType[...intermediate keys...]['default_assignee_contact'] = '203'
or whatever. If they are blank, like <default_assignee_contact></default_assignee_contact>
, then the blank node text is actually treated as an empty object, and so gets converted to an empty array and you get $caseType[...intermediate keys...]['default_assignee_contact'] = []
. By itself not too bad.
Now when you convert back to xml, either by saving or calling api.create or a lower level function, these lines do this:
$xmlFile .= "<ActivityType>\n";
foreach ($values as $key => $value) {
$xmlFile .= "<{$key}>" . self::encodeXmlString($value) . "</{$key}>\n";
}
$xmlFile .= "</ActivityType>\n";
The encodeXmlString function just calls htmlspecialchars. But if you pass an array to htmlspecialchars it gives a warning.
So at least two possibilities for how to fix:
-
Alter encodeXmlString to return the empty string if it's not passed a string to begin with.
-
Don't return mixed data types for elements and instead either return an empty string if it's an empty array, or omit the xml element completely. I'd hesitate a little because technically it would change for example what the api returns for CaseType.get for something like default_assignee_contact when it's blank.
Sample steps to reproduce:
- Create a new case type.
- Add a timeline.
- Add a followup activity to the timeline and for default assignee select By Relationship, and pick a relationship type.
- Click Save.
- Now go back and edit the case type and don't change anything just click save.
- Check drupal watchdog and you'll see the warning listed.
- At this point you can also do something further like this using cv, but you first have to edit CRM_Case_BAO_CaseType::convertDefinitionToXML() because for some reason when run through cv error_reporting gets set to E_ERROR only, so add a line at the top of that function
error_reporting(E_ALL);
. Yet another weirdness. - Then you can do this, but replace '3' with the case type id.
cv php:eval "$id = 3; $x = civicrm_api3('CaseType', 'get', ['id' => $id]); $y = CRM_Case_BAO_CaseType::convertDefinitionToXML($x['values'][$id]['name'], $x['values'][$id]['definition']);"
- Check drupal watchdog and you'll see the same warning.
Another way to think of this is that api.get followed directly by api.create without touching the data gives a warning.
Why this doesn't pop up a warning on the screen, or output anything during cv
calls, is a little bit of a mystery. What I can see is that drupal's error_handler is logging it to drupal watchdog, but in other places throughout civi warnings that get logged to drupal watchdog usually show up on the screen, if not on the same page then when you go to another page. I'd be curious if running this through cv in joomla or wordpress does output the warning.