sugarcon 2010 - best practices for creating custom apps in sugar

Post on 17-Jun-2015

5.785 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

One of the most important features of SugarCRM for developers is the ability to build customizations, even custom apps, to suit your needs. In this talk, John Mertic will detail some of the most common customization use cases from the field and provide guidelines on how to build upgrade-safe customizations and custom apps that will help meet the needs of your given company.

TRANSCRIPT

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

top related