To add more file extensions to the approved list of valid extension types, add the file extensions to the validExt array. The example below adds a .log file extension and .htaccess to the valid extension type list in config_override.php:
$sugar_config['moduleInstaller']['validExt'] = array(
    'log',
    'htaccess'
);
Denylisting Additional Function Calls
Note: Denylist modifications are prohibitedÂ for instances on Sugar's cloud service.
To add additional function calls to the denylist, add the function calls to the blackList array. The example below blocks the strlen() and strtolower() functions from being included in the package:
$sugar_config['moduleInstaller']['blackList'] = array(
    'strlen',
    'strtolower'
);
Overriding Denylisted Function Calls
Note: Denylist modifications are prohibitedÂ for instances on Sugar's cloud service.
To override the denylist and allow a specific function to be included in packages, add the function call to the blackListExempt array. The example below removes the restriction for the file_put_contents() function, allowing it to be included in the package:
$sugar_config['moduleInstaller']['blackListExempt'] = array(
    'file_put_contents'
);
Disabling Restricted Copy
To ensure upgrade-safe customizations, System Administrators mustÂ restrict the copy action to prevent modifying the existing Sugar source code files. New files may be added anywhere (to allow new modules to be added), but core Sugar source code files must not be overwritten. This is enabled by default when you enable Package Scan.
Note: Disabling Restricted Copy is prohibited for instances on Sugar's cloud service.
To disable Restricted Copy, use this configuration setting:
$sugar_config['moduleInstaller']['disableRestrictedCopy'] = true;
Module Loader Actions


$sugar_config['moduleInstaller']['disableRestrictedCopy'] = true;
Module Loader Actions
Module loader actions, defined in ./ModuleInstall/ModuleScanner.php, are identifiers that map to the installation definitions used in the $installdefs of a manifest.
Action
$installdefÂ Actions
Description
install_administration
administration
Installs an administration section into the Admin page
install_connectors
connectors
Installs SugarCloud Connectors
install_copy
copy
InstallsÂ files or directories
install_dashlets
dashlets
Installs dashlets into the Sugar application
install_images
image_dir
Install images into the custom directory
install_languages
language
Installs language files
install_layoutdefs
layoutdefs
InstallsÂ layouts
install_layoutfields
layoutfields
Installs custom fields
install_logichooks
logic_hooks
Installs logic hooks
install_relationships
relationships
Installs relationships
install_userpage
user_page
InstallsÂ a section to the User record page
install_vardefs
vardefs
InstallsÂ vardefs
post_execute
post_execute
Called after a package is installed
pre_execute
pre_execute
Called before a package is installed
Disabling Module Loader Actions
Certain Module Loader actions may be considered less desirable than others by a System Administrator. A System Administrator may want to allow some Module Loader actions, but disable specific actions that could impact the upgrade-safe integrity of the Sugar instance.
Note: Disabling Module Loader actionsÂ is prohibitedÂ for instances on Sugar's cloud service.
By default, all Module Loader actions are allowed. Enabling Package Scan does not affect the Module Loader actions. To disable specific Module Loader actions, add the action to the disableActions array. The example below restricts the pre_execute and post_execute actions:
$sugar_config['moduleInstaller']['disableActions'] = array(
    'pre_execute',


'pre_execute',
    'post_execute'
);
Disabling Upgrade Wizard
If you are hosting Sugar and wish to lock down the upgrade wizard, you can set disable_uw_upload to 'true' in the config_override. This is intended for hosting providers to prevent unwanted upgrades.
$sugar_config['disable_uw_upload'] = true;
  	Last modified: 2023-02-03 21:04:03


Module Loader Restriction Alternatives
Overview
This article provides workarounds for commonly used functions that are denylisted by Sugar forÂ Sugar's cloud environment.
Denylisted Functions
$variable()
Variable functions areÂ sometimes used when trying to dynamically call a function. This is commonly used to retrieve a new bean object.
Restricted use:
$module = "Account";
$id = "6468238c-da75-fd9a-406b-50199fe6b5f8";
//creating a new bean
$focus = new $module()
//retrieving a specific record
$focus->retrieve($id);
As of 6.3.0, we have implemented newBean and getBean which can be found in the BeanFactory. Below is the recommended approach to create or fetch a bean:
$module = "Accounts";
$id = "6468238c-da75-fd9a-406b-50199fe6b5f8";
//creating a new bean
$focus = BeanFactory::newBean($module);
//or creating a new bean and retrieving a specific record
$focus = BeanFactory::getBean($module, $id);
array_filter()
The array_filter filters elements of an array using a callback function. ItÂ is restricted from use on Sugar's cloud service due to its ability to call otherÂ restricted functions.
Restricted use:
/**
 * Returns whether the input integer is odd
 * @param $var
 * @return int
 */
function odd($var) {
    return($var & 1);
}
$myArray = array(
    "a"=>1,
    "b"=>2,
    "c"=>3,
    "d"=>4,
    "e"=>5
);
$filteredArray = array_filter($myArray, "odd");


);
$filteredArray = array_filter($myArray, "odd");
An alternative to using array_filterÂ is to use a foreach loop.
$filteredArray = array();
$myArray = array(
    "a"=>1,
    "b"=>2,
    "c"=>3,
    "d"=>4,
    "e"=>5
);
foreach ($myArray as $key => $value) {
    // check whether the input integer is odd
    if($value & 1) {
        $filteredArray[$key] = $value;
    }
}
copy()
The copyÂ method is sometimes used by developers when duplicating files in the uploads directory.
Restricted use:
$result = copy($oldFile, $newFile);
Â An alternative to using copyÂ is theÂ duplicate_fileÂ method found in theÂ UploadFileÂ class.
require_once 'include/upload_file.php';
$uploadFile = new UploadFile();
$result = $uploadFile->duplicate_file($oldFileId, $newFileId);
file_exists()
The file_exists method is used by developers to determine if a file exists.
Restricted use:
if(file_exists($file_path)) {
    require_once($file);
}
An alternative to using file_exists is theÂ fileExistsÂ method found in the SugarAutoLoaderÂ class.
$file = 'include/utils.php';
if (SugarAutoloader::fileExists($file)) {
    require_once($file);
}
file_get_contents()
The file_get_contents method is used to retrieve the contents of a file.
Restricted use:
$file_contents = file_get_contents('file.txt');


Restricted use:
$file_contents = file_get_contents('file.txt');
An alternative to using file_get_contents and sugar_file_get_contents is theÂ get_file_contentsÂ method found in the UploadFile class.
require_once('include/upload_file.php');
$uploadFile = new UploadFile();
//get the file location
$uploadFile->temp_file_location = UploadFile::get_upload_path($file_id);
$file_contents = $uploadFile->get_file_contents();
fwrite()
The fwrite method is a function used to write content to a file. As there isn't currently a direct alternative for this function, you may find one of the following a good solution to what you are trying to achieve.
Adding/Removing Logic Hooks
When working with logic hooks, it is very common for a developer to need to modifyÂ ./custom/modules/<module>/logic_hooks.php. When creating module loadable packages, developers will sometimes useÂ fwrite to modify this file upon installation to include their additional hooks. As of Sugar 6.3,Â Logic Hook ExtensionsÂ were implemented to allow a developer to append custom hooks.Â If you would prefer to edit the logic_hooks.php file, you will need toÂ use theÂ check_logic_hook_fileÂ method as described below:
//Adding a logic hook
require_once("include/utils.php");
$my_hook = Array(
    999,
    'Example Logic Hook',
    'custom/modules/<module>/my_hook.php',
    'my_hook_class',
    'my_hook_function'
);
check_logic_hook_file("Accounts", "before_save", $my_hook);
Removing a logic hook can be done by using remove_logic_hook:
//Removing a logic hook
require_once("include/utils.php");
$my_hook = Array(
    999,
    'Example Logic Hook',


$my_hook = Array(
    999,
    'Example Logic Hook',
    'custom/modules/<module>/my_hook.php',
    'my_hook_class',
    'my_hook_function'
);
remove_logic_hook("Accounts", "before_save", $my_hook);
getimagesize()
The getimagesizeÂ method isÂ used to retrieve information about an image file.
Restricted use:
$img_size = getimagesize($path);
If you are looking to verify an image is .png or .jpeg, you can use theÂ verify_uploaded_imageÂ method:
require_once('include/utils.php');
if (verify_uploaded_image($path)) {
    //logic
}
If you are looking to get the mime type of an image, you can use theÂ get_file_mime_typeÂ method:
$mime_type = get_file_mime_type($path);
  	Last modified: 2023-02-03 21:04:03


Sugar Exchange Package Guidelines
Overview
The SugarÂ® platform is open and flexible. Developers can customize any feature or integrate any system with Sugar using a Sugar Module Loadable Package. This flexibility requires guidelines so that SugarExchange customers can rest assuredÂ that all package offerings adhere to consistent quality standards and will not interfere with existing customizations or prevent software upgrades.
This guide outlines the minimum standards we expect from any Sugar Developer writing code for the Sugar platform. From the development of Sugar packages to security, user interface, encapsulation, and performance considerations, SugarCRM takes the safety and integrity of the Sugar application and its community very seriously. Compliance with these guidelines is a requirement for any package installed into Sugar's cloud service. Failure to follow these guidelines is grounds for having your package removed from Sugar's cloud service and de-listed from SugarExchange.
SugarCRM reserves the right to change these guidelines at any time. Please send any questions or feedback on these guidelines to developers@sugarcrm.com.
Best Practices
These best practice guidelines have been curatedÂ based on years of collective experience working with Sugar Packages that get used by Sugar customers every day.
Use a consistent coding style
For all PHP code, the style standard that SugarCRM uses is PSR-2. For JavaScript code, we use the applicable PSR-2 conventions as well. For JavaScript code, we emphasize readability which means we make use of utilities like Underscore.js and avoid nested callbacks. All functions, methods, classes in our code are required to have PHPDoc and JSDoc. While not all the code in the Sugar code base currently complies with these standards, we do enforce it as the standard on new code. Using a consistent code style increases the readability and maintainability of application code for those that come after you.
Invest in unit testing during development


Invest in unit testing during development
For all JavaScript and PHP code, we strongly recommend the creation of unit tests. For PHP, we use PHPUnit and have developed a framework (to be shared) for testing Sugar server-side code using this framework. For JavaScript code, we use Jasmine and have also developed a framework (to be shared) there to bootstrap Sidecar metadata so that Jasmine tests can run without dependency on a Sugar server.
We recommend running unit tests frequently during the development process. We suggest developers run tests before each commit and as part of an automated continuous integration process. Running tests often means you catch failures sooner which makes them easier and cheaper to fix.
Use Sugar REST APIs
The easiest way to integrate with a Sugar instance is not to install anything into Sugar at all. For Sugar 7, we have a full client REST API that is used to drive our web interface, our mobile client, and our plug-ins. If you can do it from our user interface, you can use our REST API separately to do it as well. If the REST API doesn't do everything you need it to do, it is very easily extensible. You can easily write code that adds your custom API endpoints in a minimally invasive way.
Use Module Builder when possible
Many integrations can be accomplished with the help of Module Builder and the Sugar REST API. Module Builder allows you toÂ quicklyÂ design new modules for Sugar that match concepts that you want to add to a Sugar instance. These custom modules can then be installed and populated via the REST API, making it a powerful integration mechanism that doesn't require writing a line of Sugar code. Using custom modules will prevent conflicts with other customizations, as well. For more information, please refer to the Module Builder documentation.
Use Extension framework and Dashlets for Sugar code customizations


Use Extension framework and Dashlets for Sugar code customizations
The Extension framework is the way to add server-side changes to a Sugar instance in a loosely coupled way. Dashlets are the best way to add new, custom user interface components to a Sugar instance that gives users maximum flexibility in how they use your app. These mechanisms also avoid conflicts with other customizations since Extensions are additive and do not replace core files.
Security Guidelines
Protecting and controlling access to CRM data is of paramount importance. It is important that Sugar Packages are good stewards of CRM data and access control.
Use TLS/SSL for web services calls
Just as we don't recommend running Sugar in production without TLS/SSL, all web-services calls that are initiated from a Sugar Package should also use SSL. The concern is the exposure of user credentials, OAuth/session tokens, or sensitive CRM data via plaintext transmission that would otherwise be handledÂ securely.
Do not hardcode sensitive information
You also should not hardcode any credentials, API keys, tokens, etc, within a Sugar Package. Sugar Packages and Sugar application code is never encrypted so there is always a risk that an attacker could discover these things and abuse them. Usernames and passwords, OAuth tokens, and similar credentials for accessing 3rd party systems should be stored in the database (for example, on the config table). The Sugar platform also provides encryption utilities that allowÂ information to be stored in an encrypted form. These settings could then be changeable by the Administrator via the Administration panel or some other end-user input.
User Interface Guidelines
Sugar packages can be used to add new user interface components or front-end customizations to Sugar. It is important to consider the impact that these changes have on the user experience and the look and feel of the Sugar application.
Use the Sugar 7 Styleguide


Use the Sugar 7 Styleguide
In Sugar 7, we have doubled down on our emphasis on creating the best possible user experience. While other applications may use different usage patterns than the ones used in Sugar 7, it is important to think about how new functionality or integrations that you build in Sugar 7 fits within the overall Sugar 7 user experience. Users do not tolerate an inconsistent experience within a given tool - it makes it harder to learn to use, which lowers adoption of Sugar as well as your application.
We want to make it easier for you to build applications within Sugar that use a consistent theme and user experience patterns, so we have included a styleguide for the Sugar application. You can find a link to the styleguideÂ from the Sugar Administration page. There you can find all the information you need to leverage Sugar 7's styling including our CSS framework.
Don't use incompatible UI frameworks or external CSS libraries
Mixing outside user interface frameworks into the Sugar application via a Sugar Package can easily break many different parts of the application. Please only include as much CSS as you need and make sure that it is properly formed so that it doesn't affect other parts of the Sugar application. At the very least, using different frameworks or themes within your application will create a disjointed experience for the end user. While your package may be installed into Sugar, the user experience will not be seamless.
Encapsulation Guidelines
An important aspect of the quality of a Sugar Package is how well encapsulated and loosely coupled it is. A well encapsulated and loosely coupled package will encounter the fewest issues during upgrades, fewer breakages due to core code changes or due to interactions with other installed packages, as well minimizing bugs or problems that end users encounter.
Use Extensions framework and Custom Modules as much as possible


Use Extensions framework and Custom Modules as much as possible
A well-encapsulated package prefers the use of Custom Modules over customizing and repurposing existing Sugar Modules. A loosely coupled package uses Extensions framework for customizing and connecting with the core Sugar application. Only override the behavior of core Sugar application files as a last resort.
Avoid customizations to core Sugar application files
Developers are strongly discouraged from overriding core Sugar Modules or Sugar framework code. In many cases, a cleaner approach for accomplishing the same goal exists. For example, using a logic hook to extend the behavior of a SugarBean instead of overriding the SugarBean itself. Every core customization is a barrier to successful upgrades that creates recurring development costs over time. This is exacerbated in heavily customized Sugar instances as other customizations may exist on these files. Anytime there is a conflict then manual intervention by a Sugar Developer is required which is not only inconvenient but costly for everyone involved. If you do make core Sugar customizations then keeping track of such changes is very important to get in front of potential conflicts with other packages and upgrades.
Use Package Scanner to ensure your Sugar Package is ready for SugarCloud
Sugar Packages should be designed with Sugar's cloud service in mind, as many Sugar customers choose this hosting option over hosting on-site or through a Sugar partner. Code that gets loaded into Sugar's cloud service must pass the Package Scanner utility and must not adversely impact the SugarCRM infrastructure. This stipulation is outlined in theÂ SugarCloud Policy Guide. Package Scanner can be enabled on any Sugar instance via the Sugar Administration panel which allows this to be tested easily. You should also educate yourself in some alternatives toÂ denylisted functions.
Performance Guidelines


Performance Guidelines
Sugar is primarily a database application however with the introduction of Sugar 7, more and more business logic is executed within the user's web browser. It is best to avoid pre-optimization and use tools to properly identify the root causes of performance issues that users could encounter.
Sugar 7 has instrumentation built into it for New Relic APM,Â which can monitor browser and server performance simultaneously, as well as XHprof for Sugar PHP profiling. Slow query logging can also be enabled via the Sugar Administration panel under System Settings. For more information, refer to the System documentation. The Sugar Engineering team typically uses Chrome DevTools for JavaScript profiling.
Index for large frequently used queries
The most common performance bottleneck for Sugar is the database. Using slow query logging makes it possible to identify bottlenecks and correct them. One way to address query bottlenecks is to extend vardefs to add indices during package install to improve the performance of those queries.
Add scheduled jobs to prune large database tables
If your Package adds database tables that can tend to grow very large over time, it is a best practice to include scheduled jobs in your package that can be used to prune the size of this database over time. For Sugar, these background tasks can be created and managed using the Job Queue framework. At the very least, you'll want to create a Custom Job that Sugar Administrators can then run as needed. This will allow the package to remain in tip-top shape for your users over time. Especially if they are running on Sugar's cloud service because direct access to the underlying SQL database to do manual tuning and cleanup is not permitted.
Ensure your application does not block user interface during long running processes


Ensure your application does not block user interface during long running processes
If your application prevents the user from getting feedback or using the interface while it is running a long process, this will impact the perceived performance of the application. Users typically expect some UI feedback within half a second. If you have transactions that will take longer than that, it is best to use the Job Queue framework to defer them for later or move them into a scheduled Custom Job.
  	Last modified: 2023-02-03 21:04:03


TinyMCE
Overview
This article demonstrates how to work with the TinyMCE rich-editor field and customize its settings.Â
TinyMCE Field Type (htmleditable_tinymce)
Sugar provides a rich-text editor field using TinyMCE. This editor is used available when customizing templates and composing emails. As Sugar does not provide a way to create and use these field in Studio, we will demonstrate how to convert a text area field into a TinyMCE editor in the following sections.
Converting a Text Area to a TinyMCE Editor
As an example, we will use the Accounts' description field. The description fields type is by default text area. First of all, you will need to change the type of the field to htmleditable_tinymce using theÂ displayParamsÂ vardefÂ key.
$dictionary['Account']['fields']['description']['displayParams']['type'] = 'htmleditable_tinymce';
Additionally, having a rich-text editor will require you to have a longer database field to store the HTML content. You will need to change the dbType to longtext and its length to 4294967295.
$dictionary['Account']['fields']['description']['dbType'] = 'longtext';
$dictionary['Account']['fields']['description']['len'] = '4294967295';
After making these changes, the vardef definition will look as follows:
./custom/Extension/modules/Accounts/Ext/Vardefs/tinymce_description.php
<?php
$dictionary['Account']['fields']['description']['displayParams']['type'] = 'htmleditable_tinymce';
$dictionary['Account']['fields']['description']['dbType'] = 'longtext';
$dictionary['Account']['fields']['description']['len'] = '4294967295';
Last, you will need to navigate Admin > Repairs and Perform Quick Repair and Rebuild.Â


Configuring the TinyMCE Editor
Configuring the TinyMCE editors can be done using theÂ tinyConfig vardef key. TheÂ tinyConfig key maps to the TinyMCE configuration options. For example, if you would add a plugin into TinyMCE editor, you would modify theÂ tinyConfig.pluginsÂ vardef key. An example of a vardef definition that will change the accounts description field to a custom TinyMCE Editor and modify its default TinyMCE settings is shown below.
./custom/Extension/modules/Accounts/Ext/Vardefs/tinymce_description.php
<?php
$dictionary['Account']['fields']['description']['displayParams']['type'] = 'htmleditable_tinymce';
$dictionary['Account']['fields']['description']['dbType'] = 'longtext';
$dictionary['Account']['fields']['description']['len'] = '4294967295';
$dictionary['Account']['fields']['description']['tinyConfig'] = array(
    'plugins' => 'paste,autoresize,visualblocks,textcolor,table,emoticons,autolink',
    'table_default_attributes' => array(
        'border' => '1',
    ),
    'target_list' => array(
        array(
            'title' => 'New page',
            'value' => '_blank',
        ),
    ),
    'default_link_target' => '_blank',
    'extended_valid_elements' => "a[href|target|data-mce-href]",
    'codesample_languages' => array(
        array('text' => 'HTML/XML', 'value' => 'markup'),
        array('text' => 'JavaScript', 'value' => 'javascript'),
        array('text' => 'CSS', 'value' => 'css'),


array('text' => 'CSS', 'value' => 'css'),
        array('text' => 'PHP', 'value' => 'php'),
    ),
    'toolbar1' => 'formatselect | bold italic underline strikethrough | bullist numlist | forecolor backcolor ',
    'toolbar2' => 'table tabledelete emoticons codesample | tableprops tablerowprops tablecellprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | visualblocks removeformat',
);
Since you are making changes in the vardef, you will need to navigate Admin > Repairs and run Quick Repair and Rebuild. Once you perform Quick Repair and Rebuild, the description of the Account records will have TinyMCE Editor that allows you to write rich-text content.
Plugins
Sugar is using TinyMCE v4. Most of the settings that you can define in tinyConfig are exist in TinyMCE documentation. However, it is important to know that plugins are limited with plugins that are provided by Sugar. These plugins can be found in ./include/javascript/tinymce4/plugins.
Configuring the TinyMCE Editors used in BWC Modules
If you are looking for a solution with older TinyMCE that Sugar uses. You can try to create an override file and modify default settings. There are two different overrides that can be applied to buttons and default settings.
Overriding Buttons
The first override file is for the toolbar buttons. To do this, you must create ./custom/include/tinyButtonConfig.php. Within this file, you will be able to override the button layout for the TinyMCE editor.
There are 3 different layouts you can change:
default : Used when creating an email template
email_compose : Used when composing an email from the full form under the Emails module


email_compose : Used when composing an email from the full form under the Emails module
email_compose_light : Used when doing a quick compose from a listview or subpanel
Example File
./custom/include/tinyButtonConfig.php
<?php
    //create email template
    $buttonConfigs['default'] = array(
        'buttonConfig' => "code,help,separator,bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,forecolor,backcolor,separator,styleselect,formatselect,fontselect,fontsizeselect,",
        'buttonConfig2' => "cut,copy,paste,pastetext,pasteword,selectall,separator,search,replace,separator,bullist,numlist,separator,outdent,indent,separator,ltr,rtl,separator,undo,redo,separator, link,unlink,anchor,image,separator,sub,sup,separator,charmap,visualaid",
        'buttonConfig3' => "tablecontrols,separator,advhr,hr,removeformat,separator,insertdate,inserttime,separator,preview"
    );
    //Standard email compose
    $buttonConfigs['email_compose'] = array(
        'buttonConfig' => "code,help,separator,bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,forecolor,backcolor,separator,styleselect,formatselect,fontselect,fontsizeselect,",
        'buttonConfig2' => "", //empty
        'buttonConfig3' => "" //empty
    );
    //Quick email compose
    $buttonConfigs['email_compose_light'] = array(


//Quick email compose
    $buttonConfigs['email_compose_light'] = array(
        'buttonConfig' => "code,help,separator,bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,forecolor,backcolor,separator,styleselect,formatselect,fontselect,fontsizeselect,",
        'buttonConfig2' => "", //empty
        'buttonConfig3' => "" //empty
    );
Overriding Default Settings
The second override file is for basic TinyMCE functionality. To do this, you must create ./custom/include/tinyMCEDefaultConfig.php. TinyMCE has quite a few settings that can be altered, so the best reference for configuration settings can be found in the TinyMCE Configuration Documentation.
Example File
./custom/include/tinyMCEDefaultConfig.php
<?php
    $defaultConfig = array(
        'convert_urls' => false,
        'valid_children' => '+body[style]',
        'height' => 300,
        'width'    => '100%',
        'theme'    => 'advanced',
        'theme_advanced_toolbar_align' => "left",
        'theme_advanced_toolbar_location' => "top",
        'theme_advanced_buttons1' => "",
        'theme_advanced_buttons2' => "",
        'theme_advanced_buttons3' => "",
        'strict_loading_mode' => true,
        'mode'    => 'exact',
        'language' => 'en',
        'plugins' => 'advhr,insertdatetime,table,preview,paste,searchreplace,directionality',
        'elements' => '',


'elements' => '',
        'extended_valid_elements' => 'style[dir|lang|media|title|type],hr[class|width|size|noshade],@[class|style]',
        'content_css' => 'include/javascript/tiny_mce/themes/advanced/skins/default/content.css',
    );
Creating Plugins
Another alternative to customizing the TinyMCE is to create a plugin. Your plugins will be stored in ./include/javascript/tiny_mce/plugins/. You can find more information on creating plugins on theÂ TinyMCE website.
the use and customization of TinyMCE.
TopicsModifying the TinyMCE EditorThis article is a brief overview on how to modify the default settings for the TinyMCE editor by creating an override file. There are two different overrides that can be applied to buttons and default settings.
  	Last modified: 2023-02-03 21:04:03


Modifying the TinyMCE Editor
Overview
This article is a brief overview on how to modify the default settings for the TinyMCE editorÂ by creating an override file. There are two different overrides that can be applied to buttons and default settings.
Overriding Buttons
The first override file is for the toolbar buttons. To do this, you must create ./custom/include/tinyButtonConfig.php. Within this file, you will be able to override the button layout for the TinyMCE editor.
There are 3 different layouts you can change:
default : Used when creating an email template
email_compose : Used when composing an email from the full form under the Emails module
email_compose_light : Used when doing a quick compose from a listview or subpanel
Example File
./custom/include/tinyButtonConfig.php
<?php
    //create email template
    $buttonConfigs['default'] = array(
        'buttonConfig' => "code,help,separator,bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,forecolor,backcolor,separator,styleselect,formatselect,fontselect,fontsizeselect,",
        'buttonConfig2' => "cut,copy,paste,pastetext,pasteword,selectall,separator,search,replace,separator,bullist,numlist,separator,outdent,indent,separator,ltr,rtl,separator,undo,redo,separator, link,unlink,anchor,image,separator,sub,sup,separator,charmap,visualaid",
        'buttonConfig3' => "tablecontrols,separator,advhr,hr,removeformat,separator,insertdate,inserttime,separator,preview"
    );
    //Standard email compose
    $buttonConfigs['email_compose'] = array(


//Standard email compose
    $buttonConfigs['email_compose'] = array(
        'buttonConfig' => "code,help,separator,bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,forecolor,backcolor,separator,styleselect,formatselect,fontselect,fontsizeselect,",
        'buttonConfig2' => "", //empty
        'buttonConfig3' => "" //empty
    );
    //Quick email compose
    $buttonConfigs['email_compose_light'] = array(
        'buttonConfig' => "code,help,separator,bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,forecolor,backcolor,separator,styleselect,formatselect,fontselect,fontsizeselect,",
        'buttonConfig2' => "", //empty
        'buttonConfig3' => "" //empty
    );
Overriding Default Settings
The second override file is for basic TinyMCE functionality. To do this, you must create ./custom/include/tinyMCEDefaultConfig.php. TinyMCE has quite a few settings that can be altered, so the best reference for configuration settings can be found in the TinyMCE Configuration Documentation.
Example File
./custom/include/tinyMCEDefaultConfig.php
<?php
    $defaultConfig = array(
        'convert_urls' => false,
        'valid_children' => '+body[style]',
        'height' => 300,
        'width'    => '100%',
        'theme'    => 'advanced',
        'theme_advanced_toolbar_align' => "left",
        'theme_advanced_toolbar_location' => "top",


'theme_advanced_toolbar_location' => "top",
        'theme_advanced_buttons1' => "",
        'theme_advanced_buttons2' => "",
        'theme_advanced_buttons3' => "",
        'strict_loading_mode' => true,
        'mode'    => 'exact',
        'language' => 'en',
        'plugins' => 'advhr,insertdatetime,table,preview,paste,searchreplace,directionality',
        'elements' => '',
        'extended_valid_elements' => 'style[dir|lang|media|title|type],hr[class|width|size|noshade],@[class|style]',
        'content_css' => 'include/javascript/tiny_mce/themes/advanced/skins/default/content.css',
    );
Creating Plugins
Another alternative to customizing the TinyMCE is to create a plugin. Your plugins will be stored in ./include/javascript/tiny_mce/plugins/. You can find more information on creating plugins on theÂ TinyMCE website.
  	Last modified: 2023-02-03 21:04:03


Logic Hooks
Overview
The Logic Hook framework allows you toÂ append actions to systemÂ events such as when creating, editing, and deleting records.
Hook Definitions
A logic hook definition file defines the various actions to execute when an event is triggered. It is important to note that there are various ways to implement a logic hook. The following sections describe the different ways to implement a logic hook and when to use each.
Methodologies
Logic hook definitions canÂ pertainÂ toÂ aÂ specific module or to the entire application. Either way, you must decide if the logic hook definition will be implemented as an extension of or directly to the module or application. The following sections explain the difference between these methodologies.
Module Extension Hooks
Module extension hooks are located in ./custom/Extension/modules/<module>/Ext/LogicHooks/Â and allow a developerÂ to defineÂ hook actions that will be executed for the specifiedÂ events in a given module.Â Extensions are best used when creating customizations that may be installed in various environments. They help prevent conflicting edits that occur whenÂ modifying ./custom/modules/<module>/logic_hooks.php. More information can be found in theÂ Logic HooksÂ extension section.
Module Hooks
Module hooks are located inÂ ./custom/modules/<module>/logic_hooks.phpÂ and allow a developerÂ to defineÂ hook actions that will be executed for the specified events in a given module. This path can be used for private development, however, it is not recommended for useÂ withÂ distributed modules and plugins. For distributed code, please refer to using module extensions.
Application Extension Hooks


Application Extension Hooks
Application extension hooks are located in ./custom/Extension/application/Ext/LogicHooks/Â and allow a developer to defineÂ hook actions that will be executed for all specified application-level eventsÂ using the extension framework. More information can be found in theÂ Logic HooksÂ extension section.
Application Hooks
ApplicationÂ hooks are located inÂ ./custom/modules/logic_hooks.phpÂ and allow a developerÂ to defineÂ hook actions that will be executed for the specifiedÂ events in all modules. This path can be used for private development, however, it is not recommended for useÂ withÂ distributed modules and plugins. For distributed code, please refer to usingÂ application extensions.
Definition Properties
All logic hooks must have aÂ $hook_version and $hook_arrayÂ variable defined. The following sections cover each required variable.
hook_version
All logic hook definitions will define a $hook_version. This determines the version of the logic hook framework. Currently, the only supported hook version is 1.
$hook_version = 1;
hook_array
The logic hook definition will also contain a $hook_array. This defines the specific action to execute. The hook array will be defined as follows:
Name
Type
Description
event_name
String
The name of the event to append the action to
process_index
Integer
The order of action execution
description
String
A short description ofÂ the hook action
file_path
String
The path to the logic hook fileÂ in the ./custom/ directory, or null if using namespaces
class_name
String
The name of the logic hook action class including any namespaces
method_name
String
The name of the logic hook action method
Your definition should resemble the code block below:
<?php
    $hook_version = 1;


<?php
    $hook_version = 1;
    $hook_array['<event_name>'][] = array(
        <process_index>, //Integer
        '<description>', //String
        '<file_path>', //String or null if using namespaces
        '<class_name>', //String
        '<method_name>', //String
    );
Hook Method
The hook action class can be located anywhere you choose. WeÂ recommended grouping the hooks with the module they are associated with in the ./custom/ directory. You can create a hook action method either with a namespace or without.
Namespaced Hooks
As of 7.7, developers can create namespaced logic hooks. When using namespaces, the file path in ./custom/Â will be automatically built out when using the corresponding namespace. The filename defining the class must match the class name exactly to allow the autoloader to find the class definition.
Namespace
File Path
Sugarcrm\Sugarcrm\custom
./custom/
Sugarcrm\Sugarcrm\custom
./custom/src/
Sugarcrm\Sugarcrm\custom\any\path
./custom/any/path/
Sugarcrm\Sugarcrm\custom\any\path
./custom/src/any/path/
./custom/Extension/modules/Accounts/Ext/LogicHooks/<file>.php
<?php
    $hook_array['before_save'][] = array(
        1,
        'Hook description',
        null,
        'Sugarcrm\\Sugarcrm\\custom\\modules\\Accounts\\className',
        'methodName'
    );
?>
./custom/modules/Accounts/className.php
<?php
namespace Sugarcrm\Sugarcrm\custom\modules\Accounts;
    class className
    {
        function methodName($bean, $event, $arguments)
        {
            //logic
        }
    }
?>


{
            //logic
        }
    }
?>
The logic hook method signature may contain different arguments depending on the hook event you have selected.
Hooks without Namespaces
./custom/Extension/modules/Accounts/Ext/LogicHooks/<file>.php
<?php
    $hook_array['before_save'][] = array(
        1,
        'Hook description',
        'custom/modules/Accounts/customLogicHook.php',
        'className',
        'methodName'
    );
?>
./custom/modules/Accounts/customLogicHook.php
<?php
    class className
    {
        function methodName($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
The logic hook method signature may contain different arguments depending on the hook event you have selected.
Considerations
When using logic hooks, keep in mind the following best practices:
As of PHP 5.3, objects are automatically passed by reference. When creating logic hook signatures, do notÂ append the ampersand (&) to the $bean variable. Doing this will cause unexpected behavior.
There is no hook that fires specifically for the ListView, DetailView or EditView events. Instead,Â use either the process_recordÂ or after_retrieve logic hooks.
In order to compare new values with previous values, use fetched_row to determine whether a change has occurred: if ($bean->fetched_row['{field}'] != $bean->{field})
{
    //logic
}


{
    //logic
}
Make sure that the permissions on theÂ logic_hooks.php file and the class file that it references are readable by the web server. Otherwise, Sugar will not read the files and your business logic extensions will not work. For example, *nix developers who are extending the Tasks logic should use the following command for the logic_hooks file and the same command for the class file that will be called:
chmod +r ./custom/modules/Tasks/logic_hooks.php
Make sure that the entire ./custom/ directory is writable by the web server or else the logic hooks code will not work properly.
TopicsApplication HooksApplication hooks execute logic when working with the global application.Module HooksModule hooks execute logic when working with Sugar modules (e.g. Accounts, Cases, etc.).User HooksUser hooks execute logic around user actions such as logging in and logging out.Job Queue HooksJob Queue hooks execute logic when working with the Job Queue module.SNIP HooksSNIP hooks execute logic when working with the SNIP email-archiving service.API HooksAPI hooks execute logic when working with the REST API and routing.Web Logic HooksWeb logic hooks let administrators post record and event information to a specified URL when certain sugar events take place.Logic Hook Release NotesThis page documents historical changes to Sugar's logic hook libraries.
  	Last modified: 2023-02-03 21:04:03


Logic Hook Release Notes
This page documentsÂ historical changes to Sugar's logic hook libraries.
10.2.0
The following parameter was added in the 10.2.0 release:
after_save arguments.stateChanges
7.0.0RC1
Web Logic Hooks were introduced in this release.
The following hooks were also added in the 7.0.0RC1 release:
after_routing
before_api_call
before_filter
before_respond
before_routing
The following parameters were added in the 7.0.0RC1 release:
after_save arguments.isUpdate
after_save arguments.dataChanges
before_save arguments.isUpdate
6.6.0
The after_load_user hook was added in the 6.6.0 release.
6.5.0RC1
The following hooks were added in the 6.5.0RC1 release:
after_email_import
before_email_import
job_failure
job_failure_retry
6.4.5
The following hooks were added in the 6.4.5 release:
before_relationship_add
before_relationship_delete
6.4.4
The handle_exception hook was added in the 6.4.4 release.
6.4.3
The after_entry_point hook was added in the 6.4.3 release.
6.0.0RC1
The following hooks were added in the 6.0.0RC1 release:
after_relationship_add
after_relationship_delete
5.0.0a
The following hooks were added in the 5.0.0a release:
after_login
after_logout
after_ui_footer
after_ui_frame
before_logout
login_failed
process_record
server_round_trip
4.5.0c
The after_save hook was added in the 4.5.0c release.


The after_save hook was added in the 4.5.0c release.
  	Last modified: 2023-02-03 21:04:03


SNIP Hooks
SNIP hooks execute logic when working withÂ the SNIP email-archiving service.
Topicsafter_email_importThe after_email_import hook executes after a SNIP email has been imported.before_email_importThe before_email_import hook executes before a SNIP email has been imported.
  	Last modified: 2023-02-03 21:04:03


before_email_import
Overview
The before_email_import hook executes before a SNIP email has been imported.
Definition
function before_email_import($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The Email object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Considerations
This is a global logic hook where the logic hook reference must be placed in ./custom/modules/logic_hooks.php.
Change Log
Version
Note
6.5.0RC1
Added before_email_import hook
Example
./custom/modules/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['before_email_import'] = Array();
    $hook_array['before_email_import'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_email_import example',
        //The PHP file where your class is located.
        'custom/modules/SNIP/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'before_email_import_method'
    );
?>
./custom/modules/SNIP/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function before_email_import_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


after_email_import
Overview
The after_email_import hook executes after a SNIP email has been imported.
Definition
function after_email_import($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The Email object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Considerations
This is a global logic hook where the logic hook reference must be placed in ./custom/modules/logic_hooks.php.
Change Log
Version
Note
6.5.0RC1
Added after_email_import hook
Example
./custom/modules/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['after_email_import'] = Array();
    $hook_array['after_email_import'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_email_import example',
        //The PHP file where your class is located.
        'custom/modules/SNIP/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'after_email_import_method'
    );
?>
./custom/modules/SNIP/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function after_email_import_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


Job Queue Hooks
Job Queue hooks execute logic when working with the Job Queue module.
Topicsjob_failureThe job_failure hook executes when a job's final failure occurs.job_failure_retryThe job_failure_retry hook executes each time a job fails before its final failure. If you only want action on the final failure, use the job_failure logic hook.
  	Last modified: 2023-02-03 21:04:03


job_failure_retry
Overview
The job_failure_retry hook executes each time a job fails before its final failure. If you only want action on the final failure, use theÂ job_failure logic hook.
Definition
function job_failure_retry($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The SchedulersJob object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Change Log
Version
Note
6.5.0RC1
Added job_failure_retry hook
Example
./custom/modules/SchedulersJobs/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['job_failure_retry'] = Array();
    $hook_array['job_failure_retry'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'job_failure_retry example',
        //The PHP file where your class is located.
        'custom/modules/SchedulersJobs/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'job_failure_retry_method'
    );
?>
./custom/modules/SchedulersJobs/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function job_failure_retry_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


job_failure
Overview
The job_failure hook executes when a job's final failure occurs.
Definition
function job_failure($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The SchedulersJob object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Change Log
Version
Note
6.5.0RC1
Added job_failure hook
Example
./custom/modules/SchedulersJobs/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['job_failure'] = Array();
    $hook_array['job_failure'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'job_failure example',
        //The PHP file where your class is located.
        'custom/modules/SchedulersJobs/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'job_failure_method'
    );
?>
./custom/modules/SchedulersJobs/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function job_failure_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
  	Last modified: 2023-02-03 21:04:03


Web Logic Hooks
Overview
Web logic hooks let administrators post record and event information to a specified URL when certain sugar events take place.
The administration panel for web logic hooks can be found by navigating to Admin > Web Logic Hooks in the Sugar application. When a web logic hook is triggered, Sugar creates a record in the job queue.
Note: You must have the cron set up and running in order to process the job queue for web logic hooks. The POST of the information to the external URL will happen when the cron runs and not when the actual event occurs.
Arguments
Name
Description
URL
The URL to post JSON-encoded information
Module Name
The name of the module to which the web logic hook will apply
Trigger Event
The event that will trigger the web logic hookThe following events are applicable to a web logic hook:
after_save
after_delete
after_relationship_add
after_relationship_delete
after_login
after_logout
after_login_failed
Request Method
The request method to use when sending the informationThe following methods mayÂ be used:
POST
GET
PUT
DELETE
Example
The followingÂ example shows how to receive the information posted to the web logic hook URL parameter.
http://{url}/receive.php
<?php
//get the posted JSON data
$data = file_get_contents('php://input');
//decode the data
$decoded_data = json_decode(trim($data));
//use the data
$file = 'receivedData-'.time().'.txt';
file_put_contents($file, print_r($decoded_data, true));
?>
Result
receivedData-1380158171.txt
stdClass Object
(
    [isUpdate] => 1
    [dataChanges] => Array
    (
    )
    [bean] => Account
    [data] => stdClass Object
    (


[bean] => Account
    [data] => stdClass Object
    (
        [id] => e0623cdb-ac4b-e7ff-f681-5242e9116892
        [name] => Super Star Holdings Inc
        [date_modified] => 2013-09-25T21:16:06-04:00
        [modified_user_id] => 1
        [modified_by_name] => admin
        [created_by] => 1
        [created_by_name] => Administrator
        [description] =>
        [deleted] =>
        [assigned_user_id] => seed_will_id
        [assigned_user_name] => Will Westin
        [team_count] =>
        [team_name] => Array
        (
            [0] => stdClass Object
                (
                    [id] => East
                    [name] => East
                    [name_2] =>
                    [primary] => 1
                )
            [1] => stdClass Object
                (
                    [id] => West
                    [name] => West
                    [name_2] =>
                    [primary] =>
                )
        )
        [linkedin] =>
        [facebook] =>
        [twitter] =>
        [googleplus] =>
        [account_type] => Customer
        [industry] => Energy
        [annual_revenue] =>
        [phone_fax] =>
        [billing_address_street] => 111 Silicon Valley Road
        [billing_address_city] => Los Angeles
        [billing_address_state] => NY
        [billing_address_postalcode] => 84028
        [billing_address_country] => USA
        [rating] =>
        [phone_office] => (374) 791-2199
        [phone_alternate] =>


[phone_alternate] =>
        [website] =>
        [ownership] =>
        [employees] =>
        [ticker_symbol] =>
        [shipping_address_street] => 111 Silicon Valley Road
        [shipping_address_city] => Los Angeles
        [shipping_address_state] => NY
        [shipping_address_postalcode] => 84028
        [shipping_address_country] => USA
        [email] => Array
        (
            [0] => stdClass Object
                (
                    [email_address] => example@example.tw
                    [invalid_email] =>
                    [opt_out] =>
                    [primary_address] => 1
                    [reply_to_address] =>
                )
            [1] => stdClass Object
                (
                    [email_address] => the.example@example.name
                    [invalid_email] =>
                    [opt_out] =>
                    [primary_address] =>
                    [reply_to_address] =>
                )
        )
        [email1] => example@example.tw
        [parent_id] =>
        [sic_code] =>
        [parent_name] =>
        [email_opt_out] =>
        [invalid_email] =>
        [campaign_id] =>
        [campaign_name] =>
    )
    [event] => after_save
)
  	Last modified: 2023-02-03 21:04:03


User Hooks
User hooks execute logic aroundÂ user actions such as logging in and logging out.
Topicsafter_loginThe after_login hook executes after a user logs into the system.after_logoutThe after_logout hook executes after a user logs out of the system.before_logoutThe before_logout hook executes before a user logs out of the system.login_failedThe login_failed hook executes on a failed login attempt.
  	Last modified: 2023-02-03 21:04:03


after_login
Overview
The after_login hook executes after a user logs into the system.
Definition
function after_login($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Change Log
Version
Note
5.0.0a
Added after_login hook
Example
./custom/modules/Users/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['after_login'] = Array();
    $hook_array['after_login'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_login example',
        //The PHP file where your class is located.
        'custom/modules/Users/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'after_login_method'
    );
?>
./custom/modules/Users/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function after_login_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
  	Last modified: 2023-02-03 21:04:03


after_logout
Overview
The after_logoutÂ hook executes after a user logs out of the system.
Definition
function after_logout($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Change Log
Version
Note
5.0.0a
Added after_logoutÂ hook
Example
./custom/modules/Users/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['after_logout'] = Array();
    $hook_array['after_logout'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_logout example',
        //The PHP file where your class is located.
        'custom/modules/Users/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'after_logout_method'
    );
?>
./custom/modules/Users/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function after_logout_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
  	Last modified: 2023-02-03 21:04:03


login_failed
Overview
The login_failed hook executes on a failed login attempt.
Definition
function login_failed($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Change Log
Version
Note
5.0.0a
Added login_failed hook
Example
./custom/modules/Users/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['login_failed'] = Array();
    $hook_array['login_failed'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'login_failed example',
        //The PHP file where your class is located.
        'custom/modules/Users/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'login_failed_method'
    );
?>
./custom/modules/Users/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function login_failed_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


before_logout
Overview
The before_logoutÂ hook executes before a user logs out ofÂ the system.
Definition
function before_logout($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Change Log
Version
Note
5.0.0a
Added before_logoutÂ hook
Example
./custom/modules/Users/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['before_logout'] = Array();
    $hook_array['before_logout'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_logout example',
        //The PHP file where your class is located.
        'custom/modules/Users/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'before_logout_method'
    );
?>
./custom/modules/Users/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function before_logout_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
  	Last modified: 2023-02-03 21:04:03


API Hooks
APIÂ hooks execute logic when working with the REST API and routing.
Topicsafter_routingThe after_routing hook executes when the v10+ REST Service has found the route for the request.before_api_callThe before_api_call hook executes when the v10+ REST Service is about to call the API implementation.before_filterThe before_filter hook executes when the v10+ REST Service is about to route the request.before_respondThe before_respond hook executes before the v10+ REST Service call returns data to the user.before_routingThe before_routing hook executes when the v10+ REST Service is about to route the request.
  	Last modified: 2023-02-03 21:04:03


before_respond
Overview
The before_respond hook executes before the v10+ REST Service call returns data to the user.
Definition
function before_respond($event, $response){}
Arguments
Name
Type
Description
event
String
The name of the logic hook event
response
Object
The RestResponse Object
Considerations
This is a global logic hook where the logic hook reference must be placed in ./custom/modules/logic_hooks.php.
It is not advised to remove or unset any data. Sugar may be using this data and it can adversely affect your instance.
This hook should not be used for any type of display output.
This hook should be used when you want to add data to all API responses. If you are looking to modify data received from one specific endpoint, It is a much better approach to override that specific endpoint rather than to use this logic hook.
Change Log
Version
Note
7.0.0RC1
Added before_respond hook
Example
./custom/modules/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['before_respond'] = Array();
    $hook_array['before_respond'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_routing example',
        //The PHP file where your class is located.
        'custom/modules/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'before_respond_method'
    );
?>
./custom/modules/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');


class logic_hooks_class
    {
        function before_respond_method($event, $response)
        {
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


before_api_call
Overview
The before_api_call hook executes when the v10+ REST Service is about to call the API implementation.
Definition
function before_api_call($event, $arguments){}
Arguments
Name
Type
Description
event
String
The name of the logic hook event
arguments
Array
Additional information related to the event
arguments.api
Object
The RestService Object
arguments.request
Object
The RestResponse Object
Considerations
This is a global logic hook where the logic hook reference must be placed in ./custom/modules/logic_hooks.php.
This hook can change the method being called and the parameters.
This hook should not be used for any type of display output.
Change Log
Version
Note
7.0.0RC1
Added before_api_call hook
Example
./custom/modules/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['before_api_call'] = Array();
    $hook_array['before_api_call'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_api_call example',
        //The PHP file where your class is located.
        'custom/modules/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'before_api_call_method'
    );
?>
./custom/modules/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function before_api_call_method($event, $arguments)
        {
            //logic
        }
    }
?>


{
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


after_routing
Overview
The after_routing hook executes when the v10+ REST Service has found the route for the request.
Definition
function after_routing($event, $arguments){}
Arguments
Name
Type
Description
event
String
The name of the logic hook event
arguments
Array
Additional information related to the event
arguments.api
Object
The RestService Object
arguments.request
Object
The RestResponse Object
Considerations
This is a global logic hook where the logic hook reference must be placed in ./custom/modules/logic_hooks.php.
This hook can change request object parameters that influence routing.
This hook should not be used for any type of display output.
Change Log
Version
Note
7.0.0RC1
Added after_routing hook
Example
./custom/modules/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['after_routing'] = Array();
    $hook_array['after_routing'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_routing example',
        //The PHP file where your class is located.
        'custom/modules/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'after_routing_method'
    );
?>
./custom/modules/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function after_routing_method($event, $arguments)
        {
            //logic
        }
    }
?>Â


{
            //logic
        }
    }
?>Â
  	Last modified: 2023-02-03 21:04:03


before_routing
Overview
The before_routing hook executes when the v10+ REST Service is about to route the request.
Definition
function before_routing($event, $arguments){}
Arguments
Name
Type
Description
event
String
The name of the logic hook event
arguments
Array
Additional information related to the event
arguments.api
Object
The RestService Object
arguments.request
Object
The RestResponse Object
Considerations
This is a global logic hook where the logic hook reference must be placed in ./custom/modules/logic_hooks.php.
This hook can change request object parameters that influence routing.
This hook should not be used for any type of display output.
Change Log
Version
Note
7.0.0RC1
Added before_routing hook
Example
./custom/modules/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['before_routing'] = Array();
    $hook_array['before_routing'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_routing example',
        //The PHP file where your class is located.
        'custom/modules/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'before_routing_method'
    );
?>
./custom/modules/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function before_routing_method($event, $arguments)
        {
            //logic
        }
    }
?>


{
            //logic
        }
    }
?>
  	Last modified: 2023-02-03 21:04:03


before_filter
Overview
The before_filter hook executes when the v10+ REST Service is about to route the request.
Definition
function before_filter($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
An empty bean object of the module being queried.
event
String
The name of the logic hook event.
arguments
Array
Additional information related to the event.
arguments[0]
Object
The SugarQuery Object
arguments[1]
Array
The query options
Considerations
This hook can be executed for a specific module in ./custom/modules/<module>/logic_hooks.php or globally in ./custom/modules/logic_hooks.php.
This hook can change request object parameters that influence routing.
This hook should not be used for any type of display output.
Change Log
Version
Note
7.0.0RC1
Added before_filter hook
Example
./custom/modules/{module}/logic_hooks.php
<?php
    $hook_version = 1;
    $hook_array = Array();
    $hook_array['before_filter'] = Array();
    $hook_array['before_filter'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_filter example',
        //The PHP file where your class is located.
        'custom/modules/{module}/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'before_filter_method'
    );
?>
./custom/modules/{module}/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {


class logic_hooks_class
    {
        function before_filter_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Â
  	Last modified: 2023-02-03 21:04:03


Module Hooks
Module hooks execute logic when working with Sugar modules (e.g. Accounts, Cases, etc.).
Topicsafter_deleteThe after_delete hook executes after a record is deleted.after_fetch_queryThe after_fetch_query logic hook executes after a sugar query has been executed.after_relationship_addThe after_relationship_add hook executes after a relationship has been added between two records.after_relationship_deleteThe after_relationship_delete hook executes after a relationship between two records has been deleted.after_restoreThe after_restore hook executes after a record gets undeleted (i.e. the deleted field's value changes from 1 to 0).after_retrieveThe after_retrieve hook executes after a record has been retrieved from the database.after_saveThe after_save hook executes after a record is saved.before_deleteThe before_delete logic hook executes before a record is deleted.before_fetch_queryThe before_fetch_query logic hook executes before a sugar query has been executed.before_relationship_addThe before_relationship_add logic hook executes before a relationship has been added between two records.before_relationship_deleteThe before_relationship_delete logic hook executes before a relationship between two records is deleted.before_restoreThe before_restore logic hook executes before a record gets undeleted (i.e. the deleted field's value changes from 1 to 0).before_saveThe before_save logic hook executes before a record is saved.process_recordThe process_record logic hook executes when the record is being processed as a part of the ListView or subpanel list.
  	Last modified: 2023-02-03 21:04:03


after_retrieve
Overview
The after_retrieve hook executes after a record has been retrieved from the database.
Definition
function after_retrieve($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.id
String
ID of the record
arguments.encode
Boolean
Whether or not to encode
Considerations
The after_retrieve hook does not fire when a new record is being created.
Calling save on the bean in this hook can cause adverse side effects if not handled correctly and should be avoided. (i.e. $bean->save())
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['after_retrieve'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_retrieve example',
        //The PHP file where your class is located.
        'custom/modules/<module>/after_retrieve_class.php',
        //The class the method is in.
        'after_retrieve_class',
        //The method to call.
        'after_retrieve_method'
    );
?>
./custom/modules/{module}/{module}_hook.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class after_retrieve_class
    {
        function after_retrieve_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook


//logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['after_retrieve'] = Array();
   $hook_array['after_retrieve'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'after_retrieve example',
      //The PHP file where your class is located.
      'custom/modules/<module>/after_retrieve_class.php',
      //The class the method is in.
      'after_retrieve_class',
      //The method to call.
      'after_retrieve_method'
   );
?>
./custom/modules/<module>/after_retrieve_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class after_retrieve_class
   {
      function after_retrieve_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


process_record
Overview
The process_record logic hook executes when the record is being processed as a part of the ListView or subpanel list.
Definition
function process_record($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Considerations
This can be used to set values in a record's fields prior to display in the ListView or in the subpanel of a DetailView.
This event is not fired in the EditView.
You should not call save on the referenced bean. The bean is only populated for list fields and will result in a loss of information.
Change Log
Version
Note
5.0.0a
Added process_record hook
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['process_record'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'process_record example',
        //The PHP file where your class is located.
        'custom/modules/<module>/process_record_class.php',
        //The class the method is in.
        'process_record_class',
        //The method to call.
        'process_record_method'
    );
?>
./custom/modules/<module>/process_record_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class process_record_class
    {
        function process_record_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook


//logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['process_record'] = Array();
   $hook_array['process_record'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'process_record example',
      //The PHP file where your class is located.
      'custom/modules/<module>/process_record_class.php',
      //The class the method is in.
      'process_record_class',
      //The method to call.
      'process_record_method'
   );
?>
./custom/modules/<module>/process_record_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class process_record_class
   {
      function process_record_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


after_fetch_query
Overview
The after_fetch_queryÂ logic hook executes afterÂ a sugar queryÂ has been executed.
Definition
function after_fetch_query($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.beans
Array
An array of bean objects resulting from the query
arguments.fields
Array
An arrayÂ of selected fields
arguments.rows
Array
An array representation of the selected beansÂ
Change Log
Version
Note
7.7.0.0
Added after_fetch_queryÂ logic hook
Examples
Creating a Logic Hook using Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['after_fetch_query'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_fetch_query example',
        //The PHP file where your class is located.
        'custom/modules/<module>/after_fetch_query_class.php',
        //The class the method is in.
        'after_fetch_query_class',
        //The method to call.
        'after_fetch_query_method'
    );
?>
./custom/modules/<module>/after_fetch_query_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class after_fetch_query_class
    {
        function after_fetch_query_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook


//logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['after_fetch_query'] = Array();
   $hook_array['after_fetch_query'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'after_fetch_query example',
      //The PHP file where your class is located.
      'custom/modules/<module>/after_fetch_query_class.php',
      //The class the method is in.
      'logic_hooks_class',
      //The method to call.
      'after_fetch_query_method'
   );
?>
./custom/modules/<module>/after_fetch_query_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class after_fetch_query_class
   {
      function after_fetch_query_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


after_save
Overview
The after_save hook executes after a record is saved.
Definition
function after_save($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
arguments.isUpdate
Boolean
Whether or not the record is newly created or not. True is an existing record being saved. False is a new record being created
arguments.dataChanges
Array
A list of the fields in the auditable fields on the bean, including the ones that changed and the ones that did not.Note: This argument is deprecated and it is recommended to use arguments.stateChanges instead.
arguments.stateChanges
Array
AÂ list of only the fields in the auditable fields on the bean that changed
Considerations
Calling save on the bean in this hook will cause an infinite loop if not handled correctly. (i.e: $bean->save())
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['after_save'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_save example',
        //The PHP file where your class is located.
        'custom/modules/<module>/after_save_class.php',
        //The class the method is in.
        'after_save_class',
        //The method to call.
        'after_save_method'
    );
?>
./custom/modules/<module>/after_save_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class after_save_class
    {


class after_save_class
    {
        function after_save_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['after_save'] = Array();
   $hook_array['after_save'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'after_save example',
      //The PHP file where your class is located.
      'custom/modules/<module>/after_save_class.php',
      //The class the method is in.
      'after_save_class',
      //The method to call.
      'after_save_method'
   );
?>
./custom/modules/<module>/after_save_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class after_save_class
   {
      function after_save_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


after_delete
Overview
The after_delete hook executes after a record is deleted.
Definition
function after_delete($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.id
String
ID of the deleted record
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['after_delete'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_delete example',
        //The PHP file where your class is located.
        'custom/modules/<module>/logic_hooks_class.php',
        //The class the method is in.
        'logic_hooks_class',
        //The method to call.
        'after_delete_method'
    );
?>
./custom/modules/<module>/logic_hooks_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class logic_hooks_class
    {
        function after_delete_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['after_delete'] = Array();


$hook_array = Array();
   $hook_array['after_delete'] = Array();
   $hook_array['after_delete'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'after_delete example',
      //The PHP file where your class is located.
      'custom/modules/<module>/after_delete_class.php',
      //The class the method is in.
      'after_delete_class',
      //The method to call.
      'after_delete_method'
   );
?>
./custom/modules/<module>/after_delete_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class after_delete_class
   {
      function after_delete_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


after_restore
Overview
The after_restore hook executes after a record gets undeleted (i.e. the deleted field's value changes from 1 to 0).
Definition
function after_restore($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['after_restore'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_restore example',
        //The PHP file where your class is located.
        'custom/modules/<module>/after_restore_class.php',
        //The class the method is in.
        'after_restore_class',
        //The method to call.
        'after_restore_method'
    );
?>
./custom/modules/<module>/after_restore_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class after_restore_class
    {
        function after_restore_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['after_restore'] = Array();


$hook_array = Array();
   $hook_array['after_restore'] = Array();
   $hook_array['after_restore'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'after_restore example',
      //The PHP file where your class is located.
      'custom/modules/<module>/after_restore_class.php',
      //The class the method is in.
      'after_restore_class',
      //The method to call.
      'after_restore_method'
   );
?>
./custom/modules/<module>/after_restore_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class after_restore_class
   {
      function after_restore_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


before_delete
Overview
The before_delete logic hook executes before a record is deleted.
Definition
function before_delete($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.id
String
ID of the record to delete
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['before_delete'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_delete example',
        //The PHP file where your class is located.
        'custom/modules/<module>/before_delete_class.php',
        //The class the method is in.
        'before_delete_class',
        //The method to call.
        'before_delete_method'
    );
?>
./custom/modules/<module>/before_delete_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class before_delete_class
    {
        function before_delete_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['before_delete'] = Array();


$hook_array = Array();
   $hook_array['before_delete'] = Array();
   $hook_array['before_delete'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'before_delete example',
      //The PHP file where your class is located.
      'custom/modules/<module>/before_delete_class.php',
      //The class the method is in.
      'before_delete_class',
      //The method to call.
      'before_delete_method'
   );
?>
./custom/modules/<module>/before_delete_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class before_delete_class
   {
      function before_delete_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


after_relationship_add
Overview
The after_relationship_add hook executes after a relationship has been added between two records.
Definition
function after_relationship_add($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.id
String
Module ID
arguments.module
String
Module name
arguments.related_id
String
Related module ID
arguments.related_module
String
Related module name
arguments.link
String
Link field name
arguments.relationship
String
Relationship name
Considerations
This hook will be executed for each side of the relationship. An example is that if you add an association between an Account and Contact, the hook will be run for both.
The arguments parameter will have additional information regarding the records being modified. The $bean variable will not contain this information.
Change Log
Version
Note
6.0.0
Added after_relationship_add hook.
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['after_relationship_add'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'after_relationship_add example',
        //The PHP file where your class is located.
        'custom/modules/{module}/after_relationship_add_class.php',
        //The class the method is in.
        'after_relationship_add_class',
        //The method to call.
        'after_relationship_add_method'
    );
?>
./custom/modules/<module>/after_relationship_add_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');


class after_relationship_add_class
    {
        function after_relationship_add_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['after_relationship_add'] = Array();
   $hook_array['after_relationship_add'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'after_relationship_add example',
      //The PHP file where your class is located.
      'custom/modules/<module>/after_relationship_add_class.php',
      //The class the method is in.
      'after_relationship_add_class',
      //The method to call.
      'after_relationship_add_method'
   );
?>
./custom/modules/<module>/after_relationship_add_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class after_relationship_add_class
   {
      function after_relationship_add_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


before_save
Overview
The before_save logic hook executes before a record is saved.
Definition
function before_save($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.check_notify
Boolean
Whether or not to send notifications
arguments.isUpdate
Boolean
Whether or not the record is newly created
true = this is an update to an existing record
false = a newly created record
Considerations
For modules that contain a user-friendly record ID (e.g. the case_number field for the Cases module), the value of that field is not available for a before_save call. This is because this business logic has yet to be executed.
Calling save on the bean in this hook will cause an infinite loop if not handled correctly. (i.e: $bean->save())
Examples
Creating a Logic Hook using Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['before_save'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_save example',
        //The PHP file where your class is located.
        'custom/modules/<module>/before_save_class.php',
        //The class the method is in.
        'before_save_class',
        //The method to call.
        'before_save_method'
    );
?>
./custom/modules/<module>/before_save_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class before_save_class
    {
        function before_save_method($bean, $event, $arguments)
        {


function before_save_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
   $hook_version = 1;
   $hook_array = Array();
   $hook_array['before_save'] = Array();
   $hook_array['before_save'][] = Array(
      //Processing index. For sorting the array.
      1,
      //Label. A string value to identify the hook.
      'before_save example',
      //The PHP file where your class is located.
      'custom/modules/<module>/before_save_class.php',
      //The class the method is in.
      'before_save_class',
      //The method to call.
      'before_save_method'
   );
?>
./custom/modules/<module>/before_save_class.php
<?php
   if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   class before_save_class
   {
      function before_save_method($bean, $event, $arguments)
      {
         //logic
      }
   }
?>
  	Last modified: 2023-02-03 21:04:03


before_relationship_delete
Overview
The before_relationship_delete logic hook executes before a relationship between two records isÂ deleted.
Definition
function before_relationship_delete($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event
arguments.id
String
Module id
arguments.module
String
Module name
arguments.related_id
String
Related module id
arguments.related_module
String
Related module name
arguments.link
String
Link field name
arguments.relationship
String
Relationship name
Considerations
This hook will be executed for each side of the relationship. For example, if you delete an association between an account and a contact, the hook will run for both records.
The arguments parameter will have additional information regarding the records being modified. The $bean variable will not contain this information.
Change Log
Version
Note
6.4.5
Added before_relationship_delete hook.
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
    $hook_array['before_relationship_delete'][] = Array(
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_relationship_delete example',
        //The PHP file where your class is located.
        'custom/modules/<module>/before_relationship_delete_class.php',
        //The class the method is in.
        'before_relationship_delete_class',
        //The method to call.
        'before_relationship_delete_method'
    );
?>
./custom/modules/<module>/before_relationship_delete_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');


class before_relationship_delete_class
    {
        function before_relationship_delete_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
  	Last modified: 2023-02-03 21:04:03


before_restore
Overview
The before_restore logic hook executes before a record gets undeleted (i.e. the deleted field's value changes from 1 to 0).
Definition
function before_restore($bean, $event, $arguments){}
Arguments
Name
Type
Description
bean
Object
The bean object
event
String
The current event
arguments
Array
Additional information related to the event (typically empty)
Examples
Creating a Logic Hook using the Extension Framework
./custom/Extension/modules/<module>/Ext/LogicHooks/<file>.php
<?php
        //Processing index. For sorting the array.
        1,
        //Label. A string value to identify the hook.
        'before_restore example',
        //The PHP file where your class is located.
        'custom/modules/<module>/before_restore_class.php',
        //The class the method is in.
        'before_restore_class',
        //The method to call.
        'before_restore_method'
    );
?>
./custom/modules/<module>/before_restore_class.php
<?php
    if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    class before_restore_class
    {
        function before_restore_method($bean, $event, $arguments)
        {
            //logic
        }
    }
?>
Creating a Core Logic Hook
Prior to Sugar 6.3.x, logic hooks could only be created using the following method. Please note that this approach is still valid but is not recommended when building plugins as it may conflict with existing customizations.
./custom/modules/<module>/logic_hooks.php
<?php
$hook_version = 1;
$hook_array = Array();
$hook_array['before_restore'] = Array();
$hook_array['before_restore'][] = Array(


$hook_array['before_restore'][] = Array(
//Processing index. For sorting the array.
1,
//Label. A string value to identify the hook.
'before_restore example',
//The PHP file where your class is located.
'custom/modules/<module>/before_restore_class.php',
//The class the method is in.
'before_restore_class',
//The method to call.
'before_restore_method'
);
?>
./custom/modules/<module>/before_restore_class.php
<?php
if (!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
class before_restore_class
{
function before_restore_method($bean, $event, $arguments)
{
//logic
}
}
?>
  	Last modified: 2023-02-03 21:04:03