Open main menu

Changes

3,848 bytes added ,  10:40, 28 October 2015
Adds brief call stack info
This article is a detailed walkthrough of debugging CiviCRM on Drupal (using NetBeans and XDebug). The overall process of request routing (Drupal menu system), data retrieval, content creation and output is intricate. It gets even more complex when you look at the internals of CiviCRM.
 
Since CiviCRM is a Drupal contrib module, a typical request has a call stack like this:
index.php
 
<pre>
sites/all/modules/contrib/civicrm/CRM/Utils/REST.php.CRM_Utils_REST::ajax:643
sites/all/modules/contrib/civicrm/CRM/Core/Invoke.php.call_user_func:{/var/www/equality-tech.com/www/drupal/sites/all/modules/contrib/civicrm/CRM/Core/Invoke.php:278}:278
sites/all/modules/contrib/civicrm/CRM/Core/Invoke.php.CRM_Core_Invoke::runItem:278
sites/all/modules/contrib/civicrm/CRM/Core/Invoke.php.CRM_Core_Invoke::_invoke:86
sites/all/modules/contrib/civicrm/CRM/Core/Invoke.php.CRM_Core_Invoke::invoke:54
sites/all/modules/contrib/civicrm/drupal/civicrm.module.civicrm_invoke:489
includes/menu.inc.call_user_func_array:{/var/www/equality-tech.com/www/drupal/includes/menu.inc:519}:519
includes/menu.inc.menu_execute_active_handler:519
index.php.{main}:21
</pre>
 
 
on line 524 of <code>civicrm/api/V3/Mailing.php</code>, in <source lang="php" inline>civicrm_api3_mailing_preview($params) </source> there is a call to <source lang=php inline>CRM_Mailing_BAO_Mailing::tokenReplace($mailing);</source>
On '''line 1264''', there is a foreach loop that runs through $custom and assigns values into $contactDetails[$contactID]["custom_{$cfID}"] but those are ALREADY correct, so is this just a formatter? CustomField::getDisplayValue() is called, which calls self::getDisplayValueCommon(). When CustomField::getDisplayValue($value, $id, &$options, $contactID = NULL, $fieldID = NULL) is called, $value is https://freephile.org/wiki/Main_Page, $id is "40", $options is an array of the custom values we care about with an 'attributes' key and I think $contactID was actually null. In any case, it's clear that these are formatter functions and the 'text' html element is returned as is, unless it's an array in which case it's imploded with commas (line 1309 of CustomField).
We jump back to "api/v3/Mailing.php" line 538 where $mailing->compose() is called. This is defined in CRM/Mailing/BAO/Mailing.php on line 1175. The function has 12 arguments! It does some odd things with "Prepared Templates" ($pTemplates, $pEmails, $pTemplate, $pEmail, $templates all get copied and referenced many times in loops where it's not clear why the data is being manipulated.) The 8th argument of the compose() method is $contactDetails. When compose() is called from '''line 90''' of CRM/Mailing/Page/Preview.php, the $contactDetails are $details[0][$session->get('userID')] But somehow the reference to $contact in all the getTokenData() calls is a lightweight array of 14 elements - not including things like 'general.base' I'm pretty sure those were in $details[0][2]
I then notice that we jumped to MagicFunctionProvider.php where invoke($apiRequest) is called, but only the contact.first_name is replaced correctly in the $result['values']['body_html']
Note: it also gets called with $fnSuffix = "civicrm_apiWrappers" so the hook function would be hook_civicrm_apiWrappers()
 
 
== AJAX ==
The form action is handled by AJAX, and we can see in the $_POST ['entity'] = "Mailing", ['action'] = "create", and ['json'] =
<source lang=javascript wrap>
"{"id":"17","domain_id":"1","footer_id":"2","reply_id":"8","unsubscribe_id":"5","resubscribe_id":"6","optout_id":"7","name":"Test of Custom Data","mailing_type":"standalone","from_name":"Greg Rundlett","from_email":"greg@eQuality-tech.com","replyto_email":"greg@eQuality-tech.com","subject":"test","body_html":"<p>Hi {contact.first_name}<br />\nwUrl data is stored as custom 40<br />\nbut the token in the UI is {general.wUrl}<br />\ncustom_40 {custom_40}<br />\ncontact.custom_40 {contact.custom_40}<br />\ngeneral.custom_40 {general.custom_40}<br />\ngeneral.general.custom_40 {general.general.custom_40}</p>\n\n<p>This is the &quot;dufus&quot; {contact.custom_71}</p>\n\n<p>More tests<br />\n{general.articlepath}<br />\n{general.base}<br />\n{general.favicon}<br />\n{general.logo}<br />\n{general.generator}<br />\n{stats.activeusers}<br />\n{stats.admins}<br />\n{stats.images}<br />\n{stats.pages}</p>\n\n<p></p>\n\n<p>And finally, the Bar test of multiple records</p>\n\n<p>\n{contact.custom_72}<br />\n{custom_72}</p>\n","url_tracking":"1","forward_replies":"0","auto_responder":"0","open_tracking":"1","override_verp":"1","created_id":"2","created_date":"2015-10-06 15:49:42","is_archived":"0","visibility":"Public Pages","dedupe_email":"1","hash":"0e95338dfdcbcc5c","email_selection_method":"automatic","is_error":0,"jobs":{},"scheduled_date":null,"groups":{"include":[17],"exclude":[],"base":[]},"mailings":{"include":[],"exclude":[]},"options":{"force_rollback":1},"api.Mailing.preview":{"id":"$value.id"}}"
</source>
 
== CRM_Utils_Array ==
At some point CRM_Utils_Array::value() gets called on $list, which is array[14] with 'contact_id', 'display_name', 'first_name', 'custom_40', 'custom_71', etc. but it does not have a key for 'general.wUrl' so that lookup fails and NULL is returned (the default).
== Results ==
4,558

edits