SugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
-
Upload
john-mertic -
Category
Technology
-
view
5.787 -
download
2
description
Transcript of SugarCon 2010 - Best Practices for Creating Custom Apps in Sugar
04/13/2023 ©2010 SugarCRM Inc. All rights reserved. 1
Best Practices for Creating Custom Apps in Sugar
John Mertic
SugarCRM
04/13/2023 ©2010 SugarCRM Inc. All rights reserved. 2
The golden rules of customizations
Use Module Builder/Studio for customizations if possible
Otherwise, put your code inside the custom directory
04/13/2023©2010 SugarCRM Inc. All rights reserved. 3
Why do this?
Module Builder/Studio changes are well supported and easier to manage
Customizations are separated from the shipped code
Allows you to manage your customizations via version control ( SVN, Git, etc )
Files in here aren’t disturbed by any Sugar upgrades
Exception – sometimes we will try to fix metadata templates on upgrades for new/removed fields.
Makes your app “Upgrade Safe”
04/13/2023©2010 SugarCRM Inc. All rights reserved. 4
Exceptions to this…
New modules need to be under modules/ directory.
Bean class customizations to OOTB modules need to be on the original bean file.
We’ll look at using logic hooks and other techniques to avoid this for many use cases.
Will need to manually manage this during upgrades, so best to avoid.
04/13/2023©2010 SugarCRM Inc. All rights reserved. 5
Let’s see what we can do
04/13/2023©2010 SugarCRM Inc. All rights reserved. 6
MVC Framework
MVC stands for Model View Controller
04/13/2023©2010 SugarCRM Inc. All rights reserved. 7
MVC Framework – The anatomy of a request
04/13/2023©2010 SugarCRM Inc. All rights reserved. 8
MVC Framework – SugarApplication
Bootstraps the application
Loads many of the default application settingsLanguage
Theme
Session
Handles User Authentication
Loads the controller
04/13/2023©2010 SugarCRM Inc. All rights reserved. 9
MVC Framework - SugarController
Manages all the actions of a module
Contains logic for handling requests that don’t require a view
Example: Record saving
Maps all other requests to the correct viewLogic for mapping an action of one name to a view of another
Can detect if we should be using MVC or classic views
04/13/2023©2010 SugarCRM Inc. All rights reserved. 10
MVC Framework – SugarController API
04/13/2023©2010 SugarCRM Inc. All rights reserved. 11
Method Description
public function pre_action() Called before the named action
public function action_action() Called for the named action
public function post_action() Called after the named action
public function loadBean() Loads the bean and the record for the module
public function preProcess() Used to interject logic into the controller before processing the controller.
MVC Framework – Controller Example
04/13/2023©2010 SugarCRM Inc. All rights reserved. 12
<?php
class ExampleController extends SugarController{ public function action_hello() { echo "Hello World!"; } public function action_goodbye() { $this->view = 'goodbye'; }}
MVC Framework – Controller-less mapping
If your module doesn’t need to have any controller logic, use action mapping insteads.
Create file named action_view_map.php with the following contents:
04/13/2023©2010 SugarCRM Inc. All rights reserved. 13
<?php
$action_view_map['goodbye'] = 'goodbye';
MVC Framework - SugarView
Contains the display logic for the actionUses a metadata backend for Edit, Detail, List, Popup views
And Convert Lead in Sugar 6.0
For other views, you write the code for the view and put it in modules/modulename/views/view.viewname.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 14
MVC Framework – SugarView API
04/13/2023©2010 SugarCRM Inc. All rights reserved. 15
Method Description
public function preDisplay() Called prior to outputing anything from the view
public function display() Called to display the view
protected function _getModuleTab() Returns the name of the module tab to be highlighted ( 6.0 only )
protected function _getModuleTitleParams() Returns the breadcrumbs to be displayed at the top of the view as an array ( 6.0 only )
MVC Framework – SugarView API
04/13/2023©2010 SugarCRM Inc. All rights reserved. 16
Property Description
public $ss Smarty object
public $module Name of module
public $action Name of action
public $errors Array of errors returned by the view or controller
public $options Options for the view, specified as an array:
Choices:show_headershow_titleshow_subpanelsshow_searchshow_footershow_javascriptview_print
MVC Framework – View Example
04/13/2023©2010 SugarCRM Inc. All rights reserved. 17
<?php
class ViewExample extends SugarView{ public function preDisplay() { if ( !is_admin($GLOBALS["current_user"]) )
sugar_die("Not an Admin"); } public function display() { echo "Hello Admin!"; }}
MVC Framework – ViewDetail Example
04/13/2023©2010 SugarCRM Inc. All rights reserved. 18
<?php
require_once('include/MVC/View/views/view.detail.php');
class ContactsViewDetail extends ViewDetail { public function display() { $admin = new Administration(); $admin->retrieveSettings(); if(isset($admin->settings['portal_on']) && $admin->settings['portal_on']) { $this->ss->assign("PORTAL_ENABLED", true); } parent::display(); }}
04/13/2023©2010 SugarCRM Inc. All rights reserved. 19
Where do I put my customizations?
Controllers/custom/modules/Modulename/controller.php
class CustomModulenameController extends SugarController
Views/custom/modules/Modulename/views/view.viewname.php
class CustomModulenameViewViewname extends ModulenameViewViewname
If that class doesn’t exist extend from ViewViewname or SugarView
Metadata Layer
04/13/2023©2010 SugarCRM Inc. All rights reserved. 20
Kinds of metadata
editviewdefs.php / detailviewdefs.php / quickcreatedefs.php
Wireless variants: wireless.editviewdefs.php, wireless.detailviewdefs.php
subpaneldefs.php
listviewdefs.phpwireless.listviewdefs.php
searchdefs.phpwireless.searchdefs.php
SearchFields.php
popupdefs.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 21
editviewdefs.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 22
<?php$viewdefs[$module_name]['EditView'] = array( 'templateMeta' => array( 'maxColumns' => '2', 'widths' => array( array('label' => '10', 'field' => '30'), array('label' => '10', 'field' => '30'), ), ), 'panels' =>array ( 'default' => array ( array ( 'name', 'assigned_user_name', ), array(array ( 'name' => 'date_modified', 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', 'label' => 'LBL_DATE_MODIFIED', )), ), array( array ( 'description', ), ), ), );
subpaneldefs.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 23
<?php$layout_defs[$module_name] = array( 'subpanel_setup' => array(
'contacts' => array('order' => 20,'module' => 'Contacts','sort_by' => 'last_name, first_name','sort_order' => 'asc','subpanel_name' => 'default','get_subpanel_data' => 'contacts','title_key' => 'LBL_CONTACTS_SUBPANEL_TITLE','top_buttons' => array(
array('widget_class' => 'SubPanelTopButtonQuickCreate'),array(
'widget_class'=>'SubPanelTopSelectButton','mode'=>'MultiSelect’
),),
), ),);
searchdefs.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 24
<?php$searchdefs[$module_name] = array( 'templateMeta' => array( 'maxColumns' => '3', 'widths' => array('label' => '10', 'field' => '30'), ), 'layout' => array( 'basic_search' => array( 'name', array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), ), 'advanced_search' => array( 'name',
array('name' => 'phone', 'label' =>'LBL_ANY_PHONE', 'type' => 'name'), array('name' => 'address_city', 'label' =>'LBL_CITY', 'type' => 'name'), array('name' => 'email', 'label' =>'LBL_ANY_EMAIL', 'type' => 'name'), array('name' => 'assigned_user_id', 'type' => 'enum',
'label' => 'LBL_ASSIGNED_TO', 'function' => array('name' => 'get_user_array',
'params' => array(false))), ), ),);
SearchFields.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 25
<?php$searchFields[$module_name] = array ( 'name' => array( 'query_type'=>'default'), 'current_user_only'=> array('query_type'=>'default',
'db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'),
'assigned_user_id'=> array('query_type'=>'default'),);
popupdefs.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 26
<?phpglobal $mod_strings;
$popupMeta = array( 'moduleMain' => 'Account', 'varName' => 'ACCOUNT', 'orderBy' => 'name', 'whereClauses' => array( 'name' => 'accounts.name', 'billing_address_city' => 'accounts.billing_address_city', 'phone_office' => 'accounts.phone_office'), 'searchInputs' => array('name', 'billing_address_city', 'phone_office'), 'create' => array( 'formBase' => 'AccountFormBase.php', 'formBaseClass' => 'AccountFormBase', 'getFormBodyParams' => array('','','AccountSave'), 'createButton' => $mod_strings['LNK_NEW_ACCOUNT’]), 'listviewdefs' => array( 'NAME' => array( 'width' => '40', 'label' => 'LBL_LIST_ACCOUNT_NAME', 'link' => true,'default' => true,), ), 'searchdefs' => array( 'name', array('name' => 'assigned_user_id', 'label'=>'LBL_ASSIGNED_TO', 'type' => 'enum', 'function' => array('name' => 'get_user_array', 'params' => array(false))), ),);
Where do I put my customizations?
Subpaneldefscustom/Extension/modules/Modulename/Ext/Layoutdefs/NameWhateverYouWant.php
Need to run ‘Quick Repair and Rebuild’ after changes are made
Everything else/custom/modules/Modulename/metadata
Watch for Studio blowing out your changes.
04/13/2023©2010 SugarCRM Inc. All rights reserved. 27
Logic Hooks
04/13/2023©2010 SugarCRM Inc. All rights reserved. 28
Logic Hook Types
04/13/2023©2010 SugarCRM Inc. All rights reserved. 29
Type Description
after_ui_frame Fired after the frame has been invoked and before the footer has been invoked. This hook does not have access to the current bean object ( meaning you can not view or change a record's values ).
after_ui_footer Fired after the footer has been invoked. This hook does not have access to the current bean object.
server_round_trip
Fired at the end of every SugarCRM page. It is called in the in the sugar_cleanup() method, which is called as the shutdown function for Sugar. This hook does not have access to the current bean object ( meaning you can not view or change a record's values ).
before_delete Fired before a record is deleted using the SugarBean::mark_deleted()
after_delete Fired after a record is deleted using the SugarBean::mark_deleted()
before_restore Fired before a record is undeleted using the SugarBean::mark_undeleted() method
after_restore Fired after a record is undeleted using the SugarBean::mark_undeleted() method
before_retrieve Fired before a record has been retrieved from the database using the SugarBean::retrieve() method. This hook does not fire when you create a new record.
after_retrieve Fired after a record has been retrieved from the database using the SugarBean::retrieve() method. This hook does not fire when you create a new record.
Logic Hook Types (cont)
04/13/2023©2010 SugarCRM Inc. All rights reserved. 30
Type Description
before_save
Fired before a record is saved using the SugarBean::save() method. One thing to note is that with certain modules, such as Cases and Bugs, the human-readable ID of the record (like the case_number field in the Case module), is not available within a before_save call since the business logic that calculates this value simply hasn't been executed yet.
after_save
Fired after a record is saved using the SugarBean::save() method. One thing to note is that with certain modules, such as Cases and Bugs, the human-readable ID of the record (like the case_number field in the Case module), is not available within a after_save call since the business logic that calculates this value simply hasn't been executed yet.
process_record
Fired immediately prior to the database query resulting in a record being made current. This gives developers an opportunity to examine and tailor the underlying queries. This is also a perfect place to set values in a record’s fields prior to display in the DetailView or ListView. This event is not fired in the EditView.
before_logout Fired before a user logs out of the system
after_logout Fired after a user logs out of the system. This hook does not have access to the current bean object. ( meaning you can not view or change a record's values ).
after_login Fired after a user successfully logs into the system.
before_login Fired before a user logs into the system. This hook does not have access to the current bean object. ( meaning you can not view or change a record's values ).
login_failed Fired on a failed login attempt. This hook does not have access to the current bean object. ( meaning you can not view or change a record's values ).
Logic Hook Types (new in 6.0)
04/13/2023©2010 SugarCRM Inc. All rights reserved. 31
Type Description
after_relationship_addFired after a relationship between two records is created. Called on both the records involved in the relationship.
after_relationship_deleteFired after a relationship between two records is deleted. Called on both the records involved in the relationship.
logic_hooks.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 32
<?php
$hook_version = 1; $hook_array = Array(); $hook_array['before_save'] = Array(); $hook_array['before_save'][] = Array(1, 'AccountHooks', 'custom/Accounts/AccountHooks.php','AccountHooks', 'getParentAccountIndustry');
Parameters for Logic Hook Definition
Parameter 1 - Sorting index used to sort the arrays of logic hook definitions before they are processed.Parameter 2 - A string value to identify the hookParameter 3 - Path to the PHP file to include which contains your logic hook codeParameter 4 - Name of the PHP class the logic hook method is inParameter 5 - Name of the PHP method to call
AccountHooks.php
04/13/2023©2010 SugarCRM Inc. All rights reserved. 33
<?php
class AccountHooks { public function getParentAccountIndustry( SugarBean $bean, $event, $arguments ) { if ( empty($bean->industry)
&& !empty($bean->parent_id) ) { $parentAccountFocus = new Account(); $parentAccountFocus->retrieve($bean->parent_id); if ( !empty($parentAccountFocus->id) ) $bean->industry = $parentAccountFocus->industry; } } }
Where do I put my customizations?
Application Level Logic Hooks/custom/modules/
Module Level Logic Hooks/custom/modules/Modulename/
04/13/2023©2010 SugarCRM Inc. All rights reserved. 34
Themes
04/13/2023©2010 SugarCRM Inc. All rights reserved. 35
Theme Directory Layout
12/30/08©2009 SugarCRM Inc. All rights reserved. 36
css/ - contains all css files
images/ - contains all images
js/ - contains any js files.
tpls/ - smarty templates
themedef.php definition file.
12/30/08©2009 SugarCRM Inc. All rights reserved. 37
Themes can inherit from other themes
Theme Inheritance Model
12/30/08©2009 SugarCRM Inc. All rights reserved. 38
Allow upgrade-safe modifications to themes
All themes can be modified by putting the replacement or overriding file in the custom/theme/<themename> directory
Image, HTML template file overrides are used as a replacement of the previous file
Example: an image custom/theme/<themename>/dog.gif would be used instead of theme/<themename>/dog.gif
CSS and Javascript files are combined in order of inheritance
Uses cssmin and jsmin to help reduce file size
No further code changes are required – changes are picked up automatically when themes cache is rebuilt.
Resources
04/13/2023©2010 SugarCRM Inc. All rights reserved. 39
http://developers.sugarcrm.com
Buy my book!
Thanks for coming!
04/13/2023 ©2010 SugarCRM Inc. All rights reserved. 40