CRM Stage tutorial:

Adding a Photo to a Contact Record

By jsweeney on 16 Jun 2009
Edited: 28 Dec 2009

Upgrade Safe: Yes
Target Audience: Developer
CRM: SugarCRM
Requirements:

No external resources are needed. The only requirement is that the cache/images directory is writable and that you have a basic understanding of Sugar.


There are cases where it would be helpful to be able to add a photo to a SugarCRM contact record in order to put a face with the name. However, there isn’t a way to do this out of the box in SugarCRM. Thankfully with SugarCRM’s customizable structure we can create that functionality on our own. Why stop with just contacts? After this tutorial we could add a photo to a lead, account, or any other module.


Section 1 - Creating a Photo "Sugar Field"

First, we need to create three files which will tell Sugar how to display the field on the edit and detail views.
1.1 - include/SugarFields/Fields/Photo/DetailView.tpl
  1. {if !empty({{sugarvar key='value' string=true}})}
  2. <img src='cache/images/{$fields.{{$displayParams.id}}.value}_{{sugarvar key='value'}}' height='100'>
  3. {/if}

1.2 -include/SugarFields/Fields/Photo/EditView.tpl
  1. <input type="hidden" id="old_{{sugarvar key='name'}}" name="old_{{sugarvar key='name'}}" value="{$fields[{{sugarvar key='name' stringFormat=true}}].value}"/>
  2. <input id="{{sugarvar key='name'}}" name="{{sugarvar key='name'}}" type="file" title='{{$vardef.help}}' size="{{$displayParams.size|default:30}}" {{if !empty($vardef.len)}}maxlength='{{$vardef.len}}'{{elseif !empty($displayParams.maxlength)}}maxlength="{{$displayParams.maxlength}}"{{else}}maxlength="255"{{/if}} value="{$fields[{{sugarvar key='name' stringFormat=true}}].value}" {{$displayParams.field}}>
  3. {$fields[{{sugarvar key='name' stringFormat=true}}].value}
  4.  
  5. {if !empty({{sugarvar key='value' string=true}})}
  6. <img src='cache/images/{$fields.{{$displayParams.id}}.value}_{{sugarvar key='value'}}' height='100'>
  7. {/if}

1.3 - include/SugarFields/Fields/Photo/SugarFieldPhoto.php
  1. <?php
  2. require_once('include/SugarFields/Fields/Base/SugarFieldBase.php');
  3.  
  4. class SugarFieldPhoto extends SugarFieldBase {
  5.  
  6. function getDetailViewSmarty($parentFieldArray, $vardef, $displayParams, $tabindex) {
  7.  
  8. global $app_strings;
  9.  
  10. if(!isset($displayParams['id'])) {
  11. $error = $app_strings['ERR_SMARTY_MISSING_DISPLAY_PARAMS'] . 'id';
  12. $GLOBALS['log']->error($error);
  13. $this->ss->trigger_error($error);
  14. return;
  15. }
  16.  
  17. $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex);
  18. return $this->fetch('include/SugarFields/Fields/Photo/DetailView.tpl');
  19. }
  20. }
  21. ?>

Section 2 - Create a Photo Field in Studio

2.1 - Go to Admin->Studio

2.2 - Open Contacts->Fields and "Add Field"

2.3 - Select "TextField" for Data Type, enter "contact_photo" for Field Name, change Label to "Photo", and change Max Size to "255".

2.4 - Add the new contact_photo_c field to the edit and detail views by opening Layouts->EditView, selecting Photo in the left column, and dragging to an empty slot in the grid layout. If there isn't an empty spot you may need to drag "New Row" to the desired area in the grid. Once done "Save & Deploy".

2.5 - Repeat for the DetailView and "Save & Deploy".

Section 3 - Editing the Views

3.1 - Open custom/modules/Contacts/metadata/detailviewdefs.php and look for "contact_photo_c". Now add the type and displayParams so that it looks like the following code. Don't forget to save!
  1. ....
  2. 'name' => 'contact_photo_c',
  3. 'label' => 'LBL_CONTACT_PHOTO',
  4. 'type' => 'photo',
  5. 'displayParams' =>
  6. 'id' => 'id',
  7. ),
  8. ....

3.2 - Open custom/modules/Contacts/metadata/editviewdefs.php and look for "contact_photo_c". Now add the type and displayParams so that it looks like the following code.
  1. ....
  2. 'name' => 'contact_photo_c',
  3. 'label' => 'LBL_CONTACT_PHOTO',
  4. 'type' => 'photo',
  5. 'displayParams' =>
  6. 'id' => 'id',
  7. ),
  8. ....

3.3 - Now we need to set the enctype for the edit form so that we can upload the photo. In editviewdefs.php add the enctype to the form key so that it looks like the following code. Then save the file.
  1. ....
  2. $viewdefs ['Contacts'] =
  3. 'EditView' =>
  4. 'templateMeta' =>
  5. 'form' =>
  6. 'enctype' => 'multipart/form-data',
  7. ....

Section 4 - Creating the Logic Hook

4.1 - Now we need to create a logic hook to save the image. Create a file called ContactPhoto.php in the custom/modules/Contacts directory with the following code:
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3.  
  4. class ContactPhoto {
  5.  
  6. function uploadPhoto(&$bean, $event, $arguments)
  7. {
  8. require_once('modules/Contacts/Contact.php');
  9. require_once('include/utils.php');
  10.  
  11. $GLOBALS['log']->debug("ContactPhoto->uploadPhoto");
  12.  
  13. //we need to manually set the id if it is not already set
  14. //so that we can name the file appropriately
  15. if(empty($bean->id)) {
  16. $bean->id = create_guid();
  17. $bean->new_with_id = true;
  18. }
  19.  
  20. //this is the name of the field that is created in studio for the photo
  21. $field_name = 'contact_photo_c';
  22. if (!empty($_FILES[$field_name]['name'])) {
  23. global $sugar_config;
  24.  
  25. //if a previous photo has been uploaded then remove it now
  26. if(!empty($_REQUEST['old_'.$field_name])) {
  27. // create a non UTF-8 name encoding
  28. // 176 + 36 char guid = windows' maximum filename length
  29. $old_file_name = $_REQUEST['old_'.$field_name];
  30. $end = (strlen($old_file_name) > 176) ? 176 : strlen($old_file_name);
  31. $stored_file_name = substr($old_file_name, 0, $end);
  32.  
  33. $old_photo = $sugar_config['cache_dir'].'images/'.$bean->id.'_'.$old_file_name;
  34. $GLOBALS['log']->debug("ContactPhoto->uploadPhoto: Deleting old photo: ".$old_photo);
  35. unlink($old_photo);
  36. }
  37.  
  38. $file_name = $bean->id.'_'.$_FILES[$field_name]['name'];
  39. //save the file name to the database
  40. $bean->contact_photo_c = $_FILES[$field_name]['name'];
  41.  
  42. if(!is_uploaded_file($_FILES[$field_name]['tmp_name'])) {
  43. die("ERROR: file did not upload");
  44. //return false;
  45. } elseif($_FILES[$this->field_name]['size'] > $sugar_config['upload_maxsize']) {
  46. die("ERROR: uploaded file was too big: max filesize: {$sugar_config['upload_maxsize']}");
  47. }
  48.  
  49. // create a non UTF-8 name encoding
  50. // 176 + 36 char guid = windows' maximum filename length
  51. $end = (strlen($file_name) > 176) ? 176 : strlen($file_name);
  52. $stored_file_name = substr($file_name, 0, $end);
  53.  
  54. $destination = $sugar_config['cache_dir'].'images/'.$stored_file_name;
  55.  
  56. if(!is_writable($sugar_config['upload_dir'])) {
  57. die("ERROR: cannot write to directory: {$sugar_config['upload_dir']} for uploads");
  58. }
  59.  
  60. //$destination = clean_path($this->get_upload_path($bean_id));
  61. if(!move_uploaded_file($_FILES[$field_name]['tmp_name'], $destination)) {
  62. die("ERROR: can't move_uploaded_file to $destination. You should try making the directory writable by the webserver");
  63. }
  64. }
  65. }
  66. }
  67. ?>

4.2 - To let Sugar know to call this file on save we create or use the existing custom/modules/Contacts/logic_hooks.php file and add our ContactPhoto->uploadPhoto function:
  1. <?php
  2. // Do not store anything in this file that is not part of the array or the hook version. This file will
  3. // be automatically rebuilt in the future.
  4. $hook_version = 1;
  5. $hook_array = Array();
  6. // position, file, function
  7. $hook_array['before_save'] = Array();
  8. $hook_array['before_save'][] = Array(1, 'uploadPhoto', 'custom/modules/Contacts/ContactPhoto.php','ContactPhoto', 'uploadPhoto');
  9. ?>

Section 5 - Trying it All Out

5.1 - Before we can try it we need to first clear the cache so that our changes in the edit and detail view definition files to affect. To do this you can either go to Admin->Repair->Quick Repair and Rebuild and run for the Contacts module or you can delete EditView.tpl and DetailView.tpl from cache/modules/Contacts.

5.2 - We're ready to rock and roll now. Open a contact to edit. You should see a file browse field now. Browse and select your photo to upload.

5.3 - Save the contact record. You should now see the photo!

5.4 - You can go back at any time and select a new photo to upload instead.

Section 6 - Known Limitations

6.1 - The logic hook does not resize the photo to a smaller thumbnail size.

6.2 - You are limited to one photo per contact.

6.3 - You can not completely remove a photo. They can only be replaced.

By: wichard
Jul 01, 2009
5

great piece of work, works as it should.

One happy customer here.