Extending Relate Fields to Pull Dynamic Information

sugarcrmdevelopers —  October 19, 2011

Frequently end-users want to view more information from a different record or page without clicking anything. Relate fields are a perfect example. On your detail view, a Relate field forms a link which would provide a plethora of additional information about the particular record – but users may want certain key information (in this case, an email address and phone number) placed on the same page as the link to avoid needing to click away.

Please note that this guide is for the Relate Field, not to be confused with the field created via One-to-Many Relationship. They operate differently behind-the-scenes.

We’ll start by extending the Relate field itself with a new field we’ll call RelateWithContactInfo. In this way we keep all of the existing functionality and feature within the edit view and the data structure. We will only modify the detail view. Here’s what we do:

Create the file /custom/include/SugarFields/Fields/RelateWithContactInfo/SugarFieldRelateWithContactInfo.php with these contents:

<?php
require_once('include/SugarFields/Fields/Relate/SugarFieldRelate.php');
class SugarFieldRelateWithContactInfo extends SugarFieldRelate{
}

This extends the built-in Relate field. Now we want to modify some functionality that affects only the detail view, so that when the field is rendered it draws some of this additional contact information. Our files quickly becomes this:

<?php
require_once('include/SugarFields/Fields/Relate/SugarFieldRelate.php');
class SugarFieldRelateWithContactInfo extends SugarFieldRelate{

    function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) {

        global $beanList, $FOCUS,$current_user;
        $bean = new $beanList[$vardef['module']];
        // proceed with normal parent::getDetailViewSmarty
        // for some reason, calling it via parent:: doesn't work, so just copy-pasted it:
        $nolink = array('Users', 'Teams');
        if(in_array($vardef['module'], $nolink)){
            $this->ss->assign('nolink', true);
        }else{
            $this->ss->assign('nolink', false);
        }
        $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex);
        return $this->fetch($this->findTemplate('DetailView'));
    }
}

We might typically expect to use a line like parent::getDetailViewSmarty() in a method like this, to pick up on the parent’s method. I found issues doing so, possibly due to my PHP version or possibly due to the way Sugar is setup. Either way, being that it’s only about 8 lines, we’ve just copy-pasted the SugarFieldRelate::getDetailViewSmarty() method below our own code.

To that end, our own code doesn’t do anything here except establish some variables. Let’s fix this now. I went about this with the idea that a display parameter ($displayParmams) would include information about which additional data points to render, but I did limit the code to those options being quite limited to either a phone number of email (being email1 or email2, the legacy email fields) value. Here’s how I set this up:

    function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) {

        global $beanList, $FOCUS,$current_user;
        $bean = new $beanList[$vardef['module']];
        $bean->retrieve($FOCUS->$vardef['id_name']);
        $this->ss->clear_assign('phone_value');
        $this->ss->clear_assign('email');
        if(isset($displayParams['ExtraInfoFields']['phone']) && !empty($bean->$displayParams['ExtraInfoFields']['phone']))
            $this->ss->assign('phone_value',$bean->$displayParams['ExtraInfoFields']['phone']);
        if(isset($displayParams['ExtraInfoFields']['email']) && !empty($bean->$displayParams['ExtraInfoFields']['email'])){
            $email_link = $current_user->getEmailLink2($bean->$displayParams['ExtraInfoFields']['email'], $bean);
            $email_link = str_replace('{','{ldelim}',$email_link);
            $email_link = str_replace('}','{rdelim}',$email_link);
            $email_link = str_replace('{ldelim{rdelim}','{ldelim}',$email_link); // b/c we escaped the escaped deliminators LOL
            $this->ss->assign('email',$email_link.$bean->email1."</a>");
        }

        // proceed with normal parent::getDetailViewSmarty...

We begin with defining the bean we’re drawing data from and clearing our template variables (otherwise they retain the values from any previous Relate fields, creating issue if one record doesn’t have one field or the other). Then, examine the values in $displayParams[‘ExtraInfoFields’] – an arbitrary key I created to house the field choices.

If the fields are found in the $displayParams, then they are assigned to the appropriate template variable. In the case of the email address, we do some special Sugar functionality to create an email-link (which detects whether the user is using the SugarCRM email client or a desktop client and generates an appropriate http: or mailto: hyperlink). Notice also that the email link requires some string replacement before it is rendered via the Smarty template, as the curly brackets – { and } – are special to Smarty and not escaping them caused parsing issues.

Yes, I regularly “LOL” in my in-code commentary.

Let’s see how the fields are rendered. Create a file at /custom/include/SugarFields/Fields/RelateWithContactInfo/DetailView.tpl with these contents:

{* include normal stuffs *}
{{include file="include/SugarFields/Fields/Relate/DetailView.tpl"}}

{* handle the phone number *}
{{if !empty($phone_value)}}
<br>
{{sugar_phone value=$phone_value usa_format="1"}}
{{/if}}

{* handle an email address *}
{{if !empty($email)}}
<br>
{{$email}}
{{/if}}

This was all pretty simple – include the previous detail view file to enable the typical behavior (creating a link to the record), then render the phone number and email address as they were passed in (with line breaks in between).

The effects aren’t immediate. There is one last step: we must force a field to use this field type. Because this new field will only be used to modify the rendering of a field (not the function of it), we can do this without vardefs or database changes. I choose a custom Relate field called contacts_oprtunities_name that was placed on the Opportunities module. Modify the existing detail view definitions at /custom/modules/Opportunities/metadata/detailviewdefs.php and find the field we want to change. Mine happened to be in the panel ‘default’ in the fifth row.

The setup originally looked like this:

$viewdefs['Opportunities']['DetailView']['panels']['default'][5] = array(
  0 => array (
    'name' => 'contacts_oprtunities_name',
  ),
  1 => array (
    'name' => 'coborrower_1_credit_score_c',
    'label' => 'LBL_COBORROWER_1_CREDIT_SCORE',
  ),
);

To change the type and feed it the appropriate display parameters, we change the above to this:

$viewdefs['Opportunities']['DetailView']['panels']['default'][5] = array(
  0 => array (
    'name' => 'contacts_oprtunities_name',
    'type' => 'RelateWithContactInfo',
    'displayParams' => array (
      'ExtraInfoFields' => array (
        'phone' => 'phone_home',
        'email' => 'email1',
      ),
    ),
  ),
  1 => array (
    'name' => 'coborrower_1_credit_score_c',
    'label' => 'LBL_COBORROWER_1_CREDIT_SCORE',
  ),
);

Because this record relates back to a Contact, I used phone_home as the phone field. For Leads or Accounts, phone_work may be more appropriate.

Screenshots to demonstrate the before and after:

Relate Field Without Dynamic Info

Relate Field With Dynamic Info