class FactorialExpression extends NumericExpression
{
    function evaluate()
    {
        $params = $this->getParameters();
        // params is an Expression object, so evaluate it
        // to get its numerical value
        $number = $params->evaluate();
        // exception handling
        if ( ! is_int( $number ) )
        {
            throw new Exception("factorial: Only accepts integers");
        }
        if ( $number < 0 )
        {
            throw new Exception("factorial: The number must be positive");
        }
        // special case 0! = 1
        if ( $number == 0 ) return 1;
        // calculate the factorial
        $factorial = 1;
        for ( $i = 2 ; $i <= $number ; $i ++ )
        {
            $factorial = $factorial * $i;
        }
        return $factorial;
     }
     // Define the javascript version of the function
     static function getJSEvaluate()
     {
        return <<<EOQ
        var params = this.getParameters();
        var number = params.evaluate();
        // reg-exp integer test
        if ( ! /^\d*$/.test(number) )
        throw "factorial: Only accepts integers";
        if ( number < 0 )
        throw "factorial: The number must be postitive";
        // special case, 0! = 1
        if ( number == 0 ) return 1;
        // compute factorial
        var factorial = 1;
        for ( var i = 2 ; i <= number ; i ++ )
        factorial = factorial * i;
        return factorial;
EOQ;
        }
        function getParameterCount()
        {


EOQ;
        }
        function getParameterCount()
        {
            return 1; // we only accept a single parameter
        }
        static function getOperationName()
        {
            return "factorial";
            // our function can be called by 'factorial'
        }
    }
?>
One of the key features of Sugar Logic is that the functions should be defined in both PHP and JavaScript and have the same functionality under both circumstances. As you can see above, the getJSEvaluate() method should return the JavaScript equivalent of your evaluate() method. The JavaScript code is compiled and assembled for you after you run the "Rebuild Sugar Logic Functions" script through Admin > Schedulers.
Writing a Custom Action
Using custom actions, you can easily create reusable custom logic or integrations that can include user-editable logic using the Sugar Formula Engine. Custom actions will be stored in ./custom/include/Expressions/Actions/{ActionName}.php. Actions files must end in Action.php and the class defined in the file must match the file name and extend the AbstractAction class. The basic functions that must be defined are fire, getDefinition, getActionName, getJavascriptClass, and getJavscriptFire. Unlike functions, there is no requirement that an action works exactly the sameÂ for both server and client side as this is not always sensible or feasible.
A simple action could be "WarningAction" that shows an alert warning the user that something may be wrong and logs a message to the ./sugarcrm.log file if triggered on the server side. It will take in a message as a formula so that the message can be customized at runtime. We would do this by creating a PHP file in ./custom/include/Expressions/Actions/WarningAction.php as shown below:
./custom/include/Expressions/Actions/WarningAction.php
<?php


./custom/include/Expressions/Actions/WarningAction.php
<?php
require_once("include/Expressions/Actions/AbstractAction.php");
class WarningAction extends AbstractAction    {
    protected $messageExp = "";
    /**
    * Returns the javascript class equavalent to this php class
    * @return string javascript.
    */
    static function getJavascriptClass()
    {
        return <<<EOQ
        SUGAR.forms.WarningAction = function(message)
        {
            this.messageExp = message;
        };
        //Use the sugar extend function to extend AbstractAction
        SUGAR.util.extend(SUGAR.forms.WarningAction, SUGAR.forms.AbstractAction,
        {
            //javascript exection code
            exec : function()
            {
            //assume the message is a formula
            var msg = SUGAR.forms.evalVariableExpression(this.messageExp);
            alert(msg.evaluate());
            }
        });
    EOQ;
    }
    /**
    * Returns the javascript code to generate this actions equivalent.
    * @return string javascript.
    */
    function getJavascriptFire()
    {
        return "new SUGAR.forms.WarningAction('{$this->messageExp}')";
    }
    /**
    * Applies the Action to the target.
    * @param SugarBean $target
    */
    function fire(&$target)
    {
        //Parse the message formula and log it to fatal.
        $expr = Parser::replaceVariables($this->messageExp, $target);
        $result = Parser::evaluate($expr)->evaluate();
        $GLOBALS['log']->warn($result);
    }
    /**
    * Returns the definition of this action in array format.
    */
    function getDefinition()
    {


*/
    function getDefinition()
    {
        return array("message" => $this->messageExp);
    }
    /**
    * Returns the short name used when defining dependencies that use this action.
    */
    static function getActionName()
    {
        return "Warn";
    }
}
?>
  	Last modified: 2023-02-03 21:04:03


Using Sugar Logic Directly
How to use Sugar Logic
TopicsAccessing an External API with a Sugar Logic ActionLet us say we were building a new Action called "SetZipCodeAction" that uses the Yahoo geocoding API to get the zip code for a given street + city + state address.Creating a Custom Dependency for a ViewDependencies can also be created and executed outside of the built in features. For example, if you wanted to have the description field of the Calls module become required when the subject contains a specific value, you could extend the calls edit view to include that dependency.Creating a Custom Dependency Using MetadataThe files should be located in ./custom/Extension/modules/{module}/Ext/Dependencies/{dependency name}.php and be rebuilt with a quick repair after modification.Using Dependencies in Logic HooksDependencies can not only be executed on the server side but can be useful entirely on the server. For example, you could have a dependency that sets a rating based on a formula defined in a language file.
  	Last modified: 2023-02-03 21:04:03


Creating a Custom Dependency for a View
Dependencies can also be created and executed outside of the built in features. For example, if you wanted to have the description field of the Calls module become required when the subject contains a specific value, you could extend the calls edit view to include that dependency.
./custom/modules/Calls/views/view.edit.php
<?php
require_once "include/MVC/View/views/view.edit.php";
require_once "include/Expressions/Dependency.php";
require_once "include/Expressions/Trigger.php";
require_once "include/Expressions/Expression/Parser/Parser.php";
require_once "include/Expressions/Actions/ActionFactory.php";
class CallsViewEdit extends ViewEdit
{
    function CallsViewEdit()
    {
        parent::ViewEdit();
    }
    function display()
    {
        parent::display();
        $dep = new Dependency("description_required_dep");
        $triggerExp = 'contains($name, "important")';
        //will be array('name')
        $triggerFields = Parser::getFieldsFromExpression($triggerExp);
        $dep->setTrigger(new Trigger($triggerExp, $triggerFields));
        //Set the description field to be required if "important" is in the call subject
        $dep->addAction(ActionFactory::getNewAction('SetRequired', array(
            'target' => 'description',
            'label' => 'description_label',
            'value' => 'true'
        )));
        //Set the description field to NOT be required if "important" is NOT in the call subject
        $dep->addFalseAction(ActionFactory::getNewAction('SetRequired', array(
            'target' => 'description',
            'label' => 'description_label',
            'value' => 'false'
        )));


'value' => 'false'
        )));
        //Evaluate the trigger immediatly when the page loads
        $dep->setFireOnLoad(true);
        $javascript = $dep->getJavascript();
        echo
        SUGAR.forms.AssignmentHandler.registerView('EditView');
        {$javascript}

EOQ;
    }
}
?>
The above code creates a new Dependency object with a trigger based on the 'name' (Subject) field in of the Calls module. It then adds two actions. The first will set the description field to be required when the trigger formula evaluates to true (when the subject contains "important"). The second will fire when the trigger is false and removes the required property on the description field. Finally, the javascript version of the Dependency is generated and echoed onto the page.
  	Last modified: 2023-02-03 21:04:03


Accessing an External API with a Sugar Logic Action
Let us say we were building a new Action called "SetZipCodeAction" that uses the Yahoo geocoding API to get the zip code for a given street + city + state address.
Since the Yahoo geocoding API requires JSON requests and returns XML data, we will have to write both PHP and JavaScript code to make and interpret the requests. Because accessing external APIs in a browser is considered cross-site scripting, a local proxy will have to be used. We will also allow the street, city, state parameters to be passed in as formulas so the action could be used in more complex Dependencies.
First, we should add a new action that acts as the proxy for retrieving data from the Yahoo API. The easiest place to add that would be a custom action in the "Home" module. The file that will act as the proxy will be .custom/modules/Home/geocode.php. It will take in the parameters via a REST call, make the call to the Yahoo API, and return the result in JSON format.
geocode.php contents:
<?php
function getZipCode($street, $city, $state)
{
    $appID = "6ruuUKjV34Fydi4TE.ca.I02rWh.9LTMPqQnSQo4QsCnjF5wIvyYRSXPIzqlDbI.jfE-";
    $street = urlencode($street);
    $city = urlencode($city);
    $state = urlencode($state);
    $base_url = "http://local.yahooapis.com/MapsService/V1/geocode?";
    $params = "appid={$appID}&street={$street}&city={$city}&state={$state}";
    //use file_get_contents to easily make the request
    $response = file_get_contents($base_url . $params);


$response = file_get_contents($base_url . $params);
    //The PHP XML parser is going to be overkill in this case, so just pull the zipcode with a regex.
    preg_match('/\([\d-]*)\/', $response, $matches);
    return $matches[1];
}
if (!empty($_REQUEST['execute']))
{
	if (empty($_REQUEST['street']) || empty($_REQUEST['city']) || empty($_REQUEST['state']))
	{
		echo("Bad Request");
	}
	else
	{
		echo json_encode(array('zip' => getZipCode($_REQUEST['street'], $_REQUEST['city'], $_REQUEST['state'])));
	}
}
?>
Next, we will need to map the geocode action to the geocode.php file. This is done by adding an action map to the Home Module. Create the file ./custom/modules/Home/action_file_map.php and add the following line of code:
<?php
$action_file_map['geocode'] = 'custom/modules/Home/geocode.php';
We are now ready to write our Action. Start by creating the file ./custom/include/Expressions/Actions/SetZipCodeAction.php. This file will use the proxy function directly from the PHP side and make an asynchronous call on the javascript side to the proxy.
SetZipCodeAction.php contents:
<?php
require_once "include/Expressions/Actions/AbstractAction.php";
class SetZipCodeAction extends AbstractAction
{
    protected $target = "";
    protected $streetExp = "";
    protected $cityExp = "";
    protected $stateExp = "";
    function SetZipCodeAction($params)
    {
        $this->target = empty($params['target']) ? " " : $params['target'];


$this->streetExp = empty($params['street']) ? " " : $params['street'];
        $this->cityExp = empty($params['city']) ? " " : $params['city'];
        $this->stateExp = empty($params['state']) ? " " : $params['state'];
    }
    static function getJavascriptClass()
    {
        return "'($this->target}', '{$this->streetExp}', '{$this->cityExp}', '{$this->stateExp}')";
    }
    function fire(&$bean)
    {
        require_once("custom/modules/Home/geocode.php");
        $vars = array(
            'street' => 'streetExp',
            'city' => 'cityExp',
            'state' => 'stateExp'
        );
        foreach($vars as $var => $exp)
        {
            $toEval = Parser::replaceVariables($this->$exp, $bean);
            $var = Parser::evaluate($toEval)->evaluate();
        }
        $target = $this->target;
        $bean->$target = getZipCode($street, $city, $state);
    }
    function getDefinition()
    {
        return array(
            "action" => $this->getActionName(),
            "target" => $this->target,
        );
    }
    static function getActionName()
    {
        return "SetZipCode";
    }
}
?>
Once you have the action written, you need to call it somewhere in the code. Currently, this must be done as shown above using custom views, logic hooks, or custom modules.
  	Last modified: 2023-02-03 21:04:03


Creating a Custom Dependency Using Metadata
The files should be located in ./custom/Extension/modules/{module}/Ext/Dependencies/{dependency name}.php and be rebuilt with a quick repair after modification.
Dependencies can have the following properties:
hooks : Defines when the dependency should be evaluated. Possible values are edit (on edit/quickCreate views), view (Detail/Wireless views), save (during a save action), and all (any time the record is accessed/saved).
trigger : A boolean formula that defines if the actions should be fired. (optional, defaults to 'true')
triggerFields : An array of field names that when when modified should trigger re-evaluation of this dependency on edit views. (optional, defaults to the set of fields found in the trigger formula)
onload : If true, the dependency will be fired when an edit view loads (optional, defaults to true)
actions : An array of action definitions to fire when the trigger formula is true.
notActions : An array of action definitions to fire when the trigger formula is false. (optional)
The actions are defined as an array with the name of the action and a set of parameters to pass to that action. Each action takes different parameters, so you will have to check each actions class constructor to check what parameters it expects.
The following example dependency will set the resolution field of cases to be required when the status is Closed:
<?php
$dependencies['Cases']['required_resolution_dep'] = array(
    'hooks' => array("edit"),
    //Optional, the trigger for the dependency. Defaults to 'true'.
    'trigger' => 'true',
    'triggerFields' => array('status'),
    'onload' => true,
    //Actions is a list of actions to fire when the trigger is true
    'actions' => array(
        array(


'actions' => array(
        array(
            'name' => 'SetRequired',
            //The parameters passed in will depend on the action type set in 'name'
            'params' => array(
                'target' => 'resolution',
                //id of the label to add the required symbol to
                'label' => 'resolution_label',
                //Set required if the status is closed
                'value' => 'equal($status, "Closed")'
            )
        ),
    ),
    //Actions fire if the trigger is false. Optional.
    'notActions' => array(),
);
Â
  	Last modified: 2023-02-03 21:04:03


Using Dependencies in Logic Hooks
Overview
Dependencies can not only be executed on the server sideÂ but can be useful entirely on the server. For example, you could have a dependency that sets a rating based on a formula defined in a language file.
<?php
require_once "include/Expressions/Dependency.php";
require_once "include/Expressions/Trigger.php";
require_once "include/Expressions/Expression/Parser/Parser.php";
require_once "include/Expressions/Actions/ActionFactory.php";
class Update_Account_Hook
{
    function updateAccount($bean, $event, $args)
    {
        $formula = translate('RATING_FORMULA', 'Accounts');
        $triggerFields = Parser::getFieldsFromExpression($formula);
        $dep = new Dependency('updateRating');
        $dep->setTrigger(new Trigger('true', $triggerFields));
        $dep->addAction(ActionFactory::getNewAction('SetValue', array(
            'target' => 'rating',
            'value' => $formula
        )));
        $dep->fire($bean);
    }
}
Â
  	Last modified: 2023-02-03 21:04:03


Performance Tuning
The following sections detail ways to enhance the performance of your Sugar instance.
TopicsSugar PerformancePerformance recommendations when working with Sugar.PHP ProfilingAs of the 6.6.2 release, Sugar introduced the ability to profile via XHProf, which is an easy-to-use, hierarchical profiler for PHP. This allows developers to better manage and understand customer performance issues introduced by their customizations. This tool enables quick and accurate identification of the sources of performance sinks within the code by generating profiling logs. Profiling gives you the ability to see the call stack for the entire page load with timing details around function and method calls as well as statistics on call frequency.Integrating Sugar With New Relic APM for Performance ManagementSugarÂ® 7 includes support for New Relic APMâ¢, a third-party Application Performance Management (APM) tool that can facilitate deep insight into your Sugar instance in order to troubleshoot sluggish response times. This article explains how to set up and use New Relic in conjunction with Sugar for powerful performance management capabilities.
  	Last modified: 2023-02-03 21:04:03


Sugar Performance
Overview
As your company uses Sugar over time, the size of your database will naturally grow and, without the proper maintenance, performance will inevitably begin to degrade. The purpose of this article is to review some of the most common recommendations for increasing the performance in Sugar to help increase the system's efficiency for your users.
Note: This guide is intended for on-site installations. Customers hosted on Sugar's cloud service should file a support case for any performance issues.
General Settings in Sugar
The following recommendations can be modified in the Sugar admin interface
Do Not Set Listview and Subpanel Items Per Page to Excessive Settings. Under Admin > System Settings, there are two settings 'Listview items per page' and 'Subpanel items per page'. The defaults for these settings are 20 and 10 respectively. When increasing these values, it should be expected that general system wide performance will be impacted. We generally recommend keeping listview settings to 100 or less and subpanel settings to be set to 10 or less to keep system performance optimal.
Make sure 'Developer Mode' is disabled under Admin > System Settings. This setting should never be enabled in a production environment as it causes cached files to be rebuilt on every page load.
Set the 'Log Level' to 'Fatal' and 'Maximum log size' to '10M' under Admin > System Settings. The log level should only be set to more verbose levels when troubleshooting the application as it will cause a performance degradation as user activity increases.
Ensure the scheduled job, 'Prune Database on the 1st of Month', is set to 'Active'. This will go through your database and delete any records that have been deleted by your users. Sugar only soft deletes records when a user deletes a record and over time, this will cause performance degradation if these records are not removed from the database.


Make sure 'Tracker Performance' and 'Tracker Queries' are disabled under Admin > Tracker. These settings are intended to help diagnose performance issues and should never be left enabled in a production environment.
Ensure large scheduler jobs are running at slower intervals under Admin > Scheduler. Jobs such as 'Check Inbound Mailboxes' can decrease overall performance if they are running every minute and polling a lot of data. It is important to set these jobs to every 5 or 10 minutes to help offset the performance impacts for your users.
Sugar Performance Settings
General Settings
Disable client IP verificationÂ :Â Eliminates the system checking to see if the user is accessing Sugar from the IP address of their last page load.
$sugar_config['verify_client_ip'] = false;
BWC Modules
For modules running in Backward Compatibility mode, the following settings can be used to speed up performance:
Drop the absolute totals from listviews :Â Eliminates performing expensive count queries on the database when populating listviews and subpanels.
$sugar_config['disable_count_query'] = true;
Disable automatic searches on listviews :Â Forces a user to perform a search when they access a listview rather than loading the results from their last search.
$sugar_config['save_query'] = 'populate_only';
Â Hide all subpanelsÂ :Â  Increases performance by collapsing all subpanels when accessing a detailview every time and not querying for data until a user explicitly expands a subpanelÂ
$sugar_config['hide_subpanels'] = true;
Hide subpanels per sessionÂ :Â  Increases performance by collapsing all subpanels when accessing a detailview when the user logs in but any subpanels expanded during the user's session will remain expanded until the user logs out
$sugar_config['hide_subpanels_on_login'] = true;
General Environment Checks


$sugar_config['hide_subpanels_on_login'] = true;
General Environment Checks
Depending on your environment and version of Sugar, there may be additional changes your system administrator can make to improve performance.
If your instance is running Sugar 6.3.x or lower, we highly recommend upgrading to 6.4.x or 6.5.x. Beginning in 6.4.x, we made a number of query improvement to address overall application performance. With 6.5.x, we drastically improved the UI to improve the speed of page loads.
If your instance of Sugar is version 6.3.x or higher with a MySQL database, we highly recommend upgrading the MySQL 5.5. MySQL 5.5 offers performance improvements in a number of areas over 5.1 such as subselects in queries.
If you are using MySQL as your database, we strongly recommend using InnoDB. InnoDB is tested to be better performing than MyISAM and should be the default configuration for using MySQL with Sugar.
If you are running PHP 5.2.x, we strongly recommend upgrading to a supported version of PHP 5.3. Our current list of supported PHP versions can be found on our Supported Platforms page.
If you are using a single server setup (web server and database on the same server), we have the following recommendations.
The server should have a minimum of 8 GB of RAM and roughly follow the 60/40 rule (60% for database / 40% for web server). On a 8 GB server, this would mean 4.8 GB for database and 3.2 GB for web server.
Make sure the following parameters are set for MySQL (assumption is that the engine is InnoDB)
innodb_buffer_pool_size = 4294967296 (4 GB in size)


innodb_buffer_pool_size = 4294967296 (4 GB in size)
innodb_log_buffer_size = anywhere from 10485760 (10 MB - Minimal writes) to 104857600 (100 MB - Lots of writes)
If you are using IE 8 or lower, we recommend upgrading to IE 9 or using Google Chrome. Earlier versions of IE 8 exhibit poor performance with our application and we recommend updating your browser to IE 9 or changing to Chrome.
PHP Caching
Whether your instance of Sugar is deployed on a Linux or Windows server, you should utilize opcode caching to ensure optimal performance. For Linux servers, APC is the recommended opcode cache for PHP with the following guidelines and settings:
Use the latest stable version.
apc.shm size should be close to your program size. For Sugar, that's at least 150 MB (default for apc.shm is 32 MB). When in doubt, more is always better.
apc.stat_ctime should be enabled. This will ensure file changes are noticed. You should note that this may increase theÂ stat() activity to your NFS.
apc.file_update_protection should be enabled.Â This helps the system when trying to add multiple files toÂ the cache at the same time.
If your installation of Sugar is located on a network filesystem such as NFS or CIFS, make sure apc.stat is enabled.
apc.ttl should be set to 0. This parameter disables garbage collection and can cause fragmentation. Earlier APC releases had locking issues that made caches with many entries take forever to be garbage collected.


apc.shm_segments should be set to the default of 1. If you think you really need multiple shm_segments, you must also read the documentation on apc.mmap_file_mask as well and understand and set that value accordingly. If you don't understand apc.mmap_file_mask, you should leave apc.shm_segments at the default value.
APC ships with an additional apc.php file that when hit with a browser, will show settings, cache information, and fragmentation. If you suspect APC problems, this is a great tool to start checking things out.
  	Last modified: 2023-02-03 21:04:03


Integrating Sugar With New Relic APM for Performance Management
Overview
SugarÂ® 7 includes support for New Relic APMâ¢, a third-party Application Performance Management (APM) tool that can facilitate deep insight into your Sugar instance in order to troubleshoot sluggish response times. This article explains how to set up and use New Relic in conjunction with Sugar for powerful performance management capabilities.
Note:Â This article pertains to on-site installations of Sugar only.Â SugarCloud customers who are experiencing performance-related issues should contact the Sugar Support team for assistance.
Prerequisites
To install and configure New Relic for use with your Sugar instance, you must have Sugar hosted on-site and have access to the root directory.Â
You must be a New Relic account holder. To sign up for New Relic, please visit newrelic.com to find the subscription level best suited for your needs.
Steps to Complete
New Relic can provide useful information outside of the Sugar integration, but the feedback it provides will be limited to the instance's PHP file structure, which could make troubleshooting your instance a challenge. Follow these instructions to set up and use New Relic for PHP with your Sugar instance.
Installing the New Relic for PHP Agent
First, install the New Relic for PHP agent. For the most current installation steps, please refer to the Getting Started Guide on the documentation site for New Relic for PHP.
Configuring Sugar to Work With New Relic for PHP
Enable the Sugar integration with New Relic by editing theÂ ./config_override.phpÂ file. Add the following lines to the end of the file contents (explanation follows):
$sugar_config['metrics_enabled'] = 1;
$sugar_config['metric_providers']['SugarMetric_Provider_Newrelic'] = 'include/SugarMetric/Provider/Newrelic.php';


$sugar_config['metric_settings']['SugarMetric_Provider_Newrelic']['applicationname'] = "SugarCRM New Relic";
The first line of the configuration enables metrics collection for your Sugar instance.
The second line specifies the path where the New Relic provider files can be found. Note: When overwriting the New Relic provider, this path must be changed to the location where the files are located in the ./custom/ directory.
The last line allows you to configure a custom application name so that you may make a distinction between production, staging and development environments. This name will be displayed in your New Relic application list. Simply replace the text inside the double quotes with your desired application name. In the example above, we name the application, "SugarCRM New Relic".
Using New Relic for PHP
New Relic integrated with Sugar enables you to view the exact functions that cause unusual performance behavior in your instance, such as unexpected triggering of logic hooks, database queries that should be optimized, or customizations that are responding slower than expected.
Shortly after completing the configuration steps above, a new application will appear in the New Relic APM interface's application list.Â Click on the appropriate application's name to view the overview dashboard.
Overview Dashboard
The dashboard gives you a quick overview ofÂ server response times over a selected period. By default, it will show data collected within the last 30 minutes. To the right of this chart is the ApdexÂ (short for application performance index) chart. Apdex provides an easy way to measure whether performance meets user expectations.


In this instance, the Apdex threshold, or T-value, is configured to 0.5 seconds. This means that an app server response time of 0.5 seconds or less is satisfactory for the users, a response time between 0.5 seconds and 2.0 seconds is tolerable, and any value higher than 2.0 seconds becomes frustrating.Â
The default Apdex T-value for New RelicÂ is 0.5 seconds but it can be configured to match your current environment and user expectations. For information on changing the Apdex T-value, please refer to theÂ Change YourÂ Apdex SettingsÂ article in the New Relic documentation.
Transactions
The Transactions listing is one of the most powerful tools available in New Relic. It will reveal the specific calls or actions that are taking the most time and resources from the server, and speculate as to why. Select "Transactions" in the menu on the left to see a full overview of all the calls done in sugar, sorted by the most time consuming.
In thisÂ case, rest_Calls_filterList is selected, which monitors the length of time that it takes to call the Calls module's list view. The performance data for this transaction is displayed on the right. As you can see at the top of the chart, calling the Calls listview has an average response time of 1.5 seconds.
Refer to the breakdown tableÂ in the lower part of the screen to see which part of the call is taking the most time, with a representation of the performed actions on the database per segment.
Below the breakdown tableÂ is a list of transaction traces. New Relic will automatically generate a transaction trace when a response time is in the frustrating zone of the ApdexÂ or slower.Â Click on the transaction trace to learn what is having the negative impact on the performance for this activity.Â


The transaction trace shows how long various components took to load. In this case, the SELECT query on the Calls table took a significant amount of time.
Click on the Trace Details tab above the chart to investigate further. The details page displays specific functions that are being called and how long they took to execute. By drilling down in the tree to the child functions, it is possible to find the root cause of the impaired performance.
Scroll down to find the SELECT query on calls took 1 second to load.Â
Click on the database icon next to the action to reveal the SQL query called by Sugar.
To view all SQL queries at once, click on the SQL Statements tab.
Summary
For critical business applications like CRM, an APM tool can you help keep your system running fast soÂ end usersÂ stay productive and your organization sees a maximum return on investment. An integrated APM will monitor, analyze, and visualize the response times of your application to identify bottlenecks Â so that your team can proactively address them.Â
To learn more about using New Relic for PHP, please visit the New RelicÂ documentation website.
  	Last modified: 2023-02-03 21:04:03


PHP Profiling
Overview
As of the 6.6.2 release, Sugar introduced the ability to profile via XHProf, which is an easy-to-use, hierarchical profiler for PHP. This allows developers to better manage and understand customer performance issues introduced by their customizations. This tool enables quick and accurate identification of the sources of performance sinks within the code by generating profiling logs. Profiling gives you the ability to see the call stack for the entire page load with timing details around function and method calls as well as statistics on call frequency.
Assuming XHProf is installed and enabled in your PHP configuration (which you can learn how to do in the PHP Manual), you can enable profiling in Sugar by adding the following parameters to the ./config_override.php file:
$sugar_config['xhprof_config']['enable'] = true;
$sugar_config['xhprof_config']['log_to'] = '{instance server path}/cache/xhprof';
// x where x is a number and 1/x requests are profiled. So to sample all requests set it to 1
$sugar_config['xhprof_config']['sample_rate'] = 1;
// array of function names to ignore from the profile (pass into xhprof_enable)
$sugar_config['xhprof_config']['ignored_functions'] = array();
// flags for xhprof
$sugar_config['xhprof_config']['flags'] = XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY;
Please note that with the above 'log_to' parameter, you would need to create the Â ./cache/xhprof/ directory in your instance directory with proper permissions and ownership for the Apache user. You can also opt to leave the Â xhprof_config.log_toÂ parameter empty and set the logging path via the Â xhprof.output_dir parameter in the Â php.ini file.


Once the above parameters are set, XHProf profiling will log all output to the indicated directory and allow you to research any performance related issues encountered in the process of developing and maintaining the application.
  	Last modified: 2023-02-03 21:04:03


Caching
Overview
Much of Sugar'sÂ user interface is built dynamically using a combination of templates, metadata and language files. A file caching mechanism improves the performance of the system by reducing the number of static metadata and language files that need to be resolved at runtime. This cache directory stores the compiled files for JavaScript files, Handlebars templates, and language files.
In a stock instance, the cache is located in the ./cache/Â directory. If you would like to move this directory to a new location, you can update the config parameter cache_dir in config.php or config_override.php to meet your needs. It is not advisable to move the cacheÂ to another network serverÂ as it may impact system performance.
Developer Mode
To prevent caching while developing, a developer may opt to turn on Developer Mode by navigating to Admin > System Settings > Advanced > Developer Mode. This will disable caching so that developers can test code-level customizations without the need to manually rebuild the cache, which is especially helpful when developing templates, metadata, or language files. The system automatically refreshes the file cache. Make sure to deactivate Developer Mode after completing customizations because this mode degrades system performance.
  	Last modified: 2023-02-03 21:04:03


Web Accessibility
Overview
Learn about theÂ Sugar Accessibility Plugin for Sidecar.
Introduction
Making your application accessible -- per the standards defined by the W3C's WAI specifications -- is a hard thing to do and even harder to maintain. The goal of the Sugar Accessibility Plugin for Sidecar is to automatically apply rules to your rendered HTML, so that you don't have to be concerned with all of the intricacies of accessibility.
With respect to programmatically applying accessibility rules, you can generally assume that the rules fall into one of three categories:
Rules that are dependent on the context of the element's use and cannot be applied programmatically because the context is never clear.
Rules that can be applied programmatically, but only when the context is clear.
Rules that can always be applied programmatically.
We plan to continue to develop this plugin to address more and more accessibility concerns in an abstract way, with the intention of completely covering the latter two cases. In the meantime, the plugin handles two very specific cases: and (2) One from the third category.
How It Works
The plugin listens to the render event for all View.Component objects that are created. Anytime a component is rendered, the plugin runs its own plugins (hereinafter referred to as "helpers") on the component. Each of these helpers is responsible for determining if any modifications are necessary in order for the component's HTML to meet accessibility standards and then carrying out those changes in the DOM. This behavior is done automatically as a part of the sidecar framework, so you do not need to do anything to start using it.
Sometimes, a component that you write will modify the HTML after it has been rendered. The plugin has no means of becoming aware of these changes to the HTML and you will have to tell it to look for rules to apply. One example is found inView.Fields.Base.ActionmenuField.


When the user selects all records in a list view, an alert is flashed indicating that all visible records are now selected. Within this alert, a link can be clicked to select all records, even those that are not currently visible. A new onclick event listener is registered for this link. And because this link is added to the DOM after the component is rendered, the author of the component must make sure that the new HTML meets accessibility requirements. Here is how that is done:
var $el = $('a#select-all');
$el.on('click', function() {...});
app.accessiblity.run($el, 'click');
This will only run the click helper. If you want to run all helpers, then call app.accessiblity.run($el) (without the second parameter). But be aware that some helpers only support View.Component objects, while others support eitherView.Component objects or jQuery DOM elements. So running all helpers on a jQuery DOM element may fail, or at least fail to apply some accessibility rules as expected.
When the logger is configured for debug mode, messages are logged indicating which helpers are being run and which helpers could not be run when intended.
Plugins
A plugin (or helper) is a module that applies an accessibility rule to a View.Component (or jQuery DOM element). At runtime, these helpers can be found in app.accessibility.helpers and implement a run method. The run method takes aView.Component (or jQuery DOM element) and then checks its HTML to determine if anything needs to be done in order to make the HTML compliant with accessibility standards related to the rule or task with which the helper is concerned. If any changes are necessary, the helper then modifies the HTML to comply.
Click
The click helper is responsible for making an element compliant with accessibility standards when click events are bound to said element. Since this helper only deals with onclick events, it only inspects elements within the component that include onclick event listeners.


If the tag name cannot be determined for an element being inspected, then there is no way of knowing whether or not the element is accessible. Thus, the element is assumed to be compliant.
Inherently focusable elements are those elements that require no intervention. These elements include:
button
input
select
textarea
Conditionally focusable elements are those elements that require intervention under certain circumstances. In the case of<a> and <area> tags, these elements are compliant as long as they contain an href attribute. These elements include:
a
area
All other elements are not inherently focusable and require a tabindex attribute of -1 if a tabindex attribute does not already exist. This helper adds tabindex="-1" to any elements within the component that are not compliant.
When the logger is configured for debug mode, messages are logged...
In the event that no onclick events were found within the component. Thus, no action is taken.
In the event that an element being inspected has no tag name.
To report the type of element being made compliant.
To report the type of element that is already found to be compliant.
Label
The label helper adds an aria-label to the form element found within the component. This helper only inspects elements that can be found via the component's fieldTag selector and is consdered a "best effort" approach.
This helper will only work on View.Field components since it is extremely unlikely for the fieldTag selector forView.Layout or View.View components to match form elements.
A form element is considered to be compliant if the aria-label attribute is already present or if its tag is not one that requires a label. These elements include:
button
input
select
textarea


button
input
select
textarea
This helper adds aria-label="{label}" to the element that needs to be made compliant. View.Field.label is the label that is assigned to the attribute. The component must be a View.Component. Plain jQuery DOM elements are not sufficient since they do not include alabel property.
API
SUGAR.accessibility.init()
Initializes the accessibility module to execute all accessibility helpers on components as they are rendered. This is called by the application during bootstrapping.
SUGAR.accessibility.run()
Loads the accessibility helpers that are to be run and executes them on the component.
Arguments
Name
Type
Required
Description
component
View.Component/jQuery
true
The element to test for accessibility compliance.
helper
String/Array
false
One or more names of specified helpers to run. All registered helpers will be run if undefined.
Returns
Void
SUGAR.accessibility.whichHelpers()
Get the helpers registered on a specific element.
Name
Type
Required
Description
helper
String/Array
true
One or more names of specified helpers to run.
Returns
Array - The accessibility helpers that were requested. Filters out any named helpers that are not registered. All registered helpers are returned if no helper names are provided as a parameter.
SUGAR.accessibility.getElementTag()
Generates a human-readable string for identifying an element. For example, Â a[name="link"][class="btn btn-link"][href="http://www.sugarcrm.com/"]. Primarily used for logging purposes, this method is useful for debugging.
Arguments
Name
Type
Required
Description
$el
jQuery
true
The element for which the tag should be generated.
Returns
String - A string representing an element's tag, with all attributes. The element's selector, if one exists, is returned when a representation cannot be reasonably generated.


Last modified: 2023-02-03 21:04:03


Languages
Overview
Sugar as an application platform is internationalized and localizable. Data is stored and presented in the UTF-8 codepage, allowing for all character sets to be used. Sugar provides a language-pack framework that allows developers to build support for any language in the display of user interface labels. Each language pack has its own set of display strings which is the basis of language localization. You can add or modify languages using the information in this guide.Please scroll to the bottom of this page for additional language topics.
Language Keys
Sugar differentiates languages with unique language keys. These keys prefix the files that correspond with particular languages. For example, the default language for the application is English (US), which is represented by the language key en_us. Any file that contains data specific to the English (US) language begins with the characters en_us. Language label keys that are not recognized will default to the English (US) version.
The following table displays the list of current languages and their corresponding keys:
Language
Language Key
Albanian (Shqip)
sq_AL
Arabic (Ø§ÙØ¹Ø±Ø¨ÙØ©)
ar_SA
Bulgarian (ÐÑÐ»Ð³Ð°ÑÑÐºÐ¸)
bg_BG
Catalan (CatalÃ )
ca_ES
Chinese (ç®ä½ä¸æ)
zh_CN
Croatian (Hrvatski)
hr_HR
Czech (Äesky)
cs_CZ
Danish (Dansk)
da_DK
Dutch (Nederlands)
nl_NL
English (UK)
en_UK
English (US)
en_us
Estonian (Eesti)
et_EE


English (US)
en_us
Estonian (Eesti)
et_EE
Finnish (Suomi)
fi_FI
French (FranÃ§ais)
fr_FR
German (Deutsch)
de_DE
Greek (ÎÎ»Î»Î·Î½Î¹ÎºÎ¬)
el_EL
Hebrew (×¢××¨××ª)
he_IL
Hungarian (Magyar)
hu_HU
Italian (Italiano)
it_it
Japanese (æ¥æ¬èª)
ja_JP
Korean (íêµì´)
ko_KR
Latvian (LatvieÅ¡u)
lv_LV
Lithuanian (LietuviÅ³)
lt_LT
Norwegian (BokmÃ¥l)
nb_NO
Polish (Polski)
pl_PL
Portuguese (PortuguÃªs)
pt_PT
Portuguese Brazilian (PortuguÃªs Brasileiro)
pt_BR
Romanian (RomÃ¢nÄ)
ro_RO
Russian (Ð ÑÑÑÐºÐ¸Ð¹)
ru_RU
Serbian (Ð¡ÑÐ¿ÑÐºÐ¸)
sr_RS
Slovak (SlovenÄina)
sk_SK
Spanish (EspaÃ±ol)
es_ES
Spanish (Latin America) (EspaÃ±ol (LatinoamÃ©rica))
es_LA
Swedish (Svenska)
sv_SE
Thai (à¹à¸à¸¢)
th_TH


Thai (à¹à¸à¸¢)
th_TH
Traditional Chinese (ç¹é«ä¸æ)
zh_TW
Turkish (TÃ¼rkÃ§e)
tr_TR
Ukrainian (Ð£ÐºÑÐ°ÑÐ½ÑÑÐºÐ°)
uk_UA
Â
Change Log
The following table documents historical changes to Sugar's available languages.
Version
Change
7.8.0.0
Added Thai language pack.
7.8.0.0
Added Croatian language pack.
7.7.0.0
Added Traditional Chinese language pack.
7.6.0.0
Added Ukrainian language pack.
7.6.0.0
Added Arabic language pack.
7.2.0
Added Finnish language pack.
7.2.0
Added Spanish (Latin America) language pack.
6.6.0
Added Albanian language pack.
6.6.0
Added Slovak language pack.
6.6.0
Added Korean language pack.
6.6.0
Added Greek language pack.
6.5.1
Added Latvian language pack.
6.4.0
Added Serbian language pack.
6.4.0
Added Portuguese Brazilian language pack.
6.4.0
Added English (UK) language pack.
6.4.0
Added Catalan language pack.
6.2.0
Added Polish language pack.
6.2.0
Added Hebrew language pack.
6.2.0
Added Estonian language pack.
6.2.0
Added Czech language pack.
6.1.2
Added Turkish language pack.
6.1.2


6.1.2
Added Turkish language pack.
6.1.2
Added Swedish language pack.
6.1.2
Added Norwegian language pack.
6.1.2
Added Lithuanian language pack.
6.1.0
Added Chinese language pack.
6.1.0
Added Russian language pack.
6.1.0
Added Romanian language pack.
6.1.0
Added Portuguese language pack.
6.1.0
Added Dutch language pack.
6.1.0
Added Japanese language pack.
6.1.0
Added Italian language pack.
6.1.0
Added Hungarian language pack.
6.1.0
Added French language pack.
6.1.0
Added Spanish language pack.
6.1.0
Added German language pack.
6.1.0
Added Danish language pack.
6.1.0
Added Bulgarian language pack.
TopicsApplication Labels and ListsSugar, which is fully internationalized and localizable, differentiates languages with unique language keys. These keys prefix the files that correspond with particular languages. For example, the default language for the application is English (US), which is represented by the language key en_us. Any file that contains data specific to the English (US) language begins with the characters en_us. Language label keys that are not recognized will default to the English (US) version.Module Labelsrequire_once 'include/utils.php';Managing ListsThere are three ways to manage lists in Sugar: by using Studio in the application, by directly modifying the list's language strings, and via the code-level Dropdown Helper. This page explains all three methods.Language PacksLanguage packs are module-loadable packages that add support for new, localized languages to Sugar.
  	Last modified: 2023-02-03 21:04:03


Language Packs
Overview
Language packs are module-loadable packages that add support for new, localized languages to Sugar.
Creating a Language Pack
To create a language pack, choose a unique language key. This key is specific to your language definitions and should be unique from other language keys in the same instance to avoid conflicts. It is also important that your language key follows theÂ xx_xx format. For demonstrative purposes, we will create a Lorem Ipsum language pack with the language key Lo_Ip.
Application and Module Strings
In the module and application language definitions, there isÂ a combination of $app_list_strings, $mod_strings, and $mod_process_order_stringsÂ variables. Your custom language needsÂ to have a definition createdÂ to reflect each language key in a standard definition.Â To do this, duplicate an existing languageÂ and simply change the language values within the documentÂ andÂ replace the language key in the name of the file with your new key. BeÂ sureÂ to only change theÂ array valuesÂ and leave the array keys as they are inside of each file.
Note:Â Should you miss an index, it will default to English.Â
TheÂ first step is to identify all of the application and module languageÂ files.Â WhileÂ language files may vary from version to version due to new features, the stock language paths are generally as follows:
./include/language/xx_xx.lang.php
./include/SugarObjects/implements/assignable/language/xx_xx.lang.php
./include/SugarObjects/implements/email_address/language/xx_xx.lang.php
./include/SugarObjects/implements/team_security/language/xx_xx.lang.php
./include/SugarObjects/templates/basic/language/xx_xx.lang.php
./include/SugarObjects/templates/company/language/xx_xx.lang.php


./include/SugarObjects/templates/company/language/xx_xx.lang.php
./include/SugarObjects/templates/company/language/application/xx_xx.lang.php
./include/SugarObjects/templates/file/language/xx_xx.lang.php
./include/SugarObjects/templates/file/language/application/xx_xx.lang.php
./include/SugarObjects/templates/issue/language/xx_xx.lang.php
./include/SugarObjects/templates/issue/language/application/xx_xx.lang.php
./include/SugarObjects/templates/person/language/xx_xx.lang.php
./include/SugarObjects/templates/sale/language/xx_xx.lang.php
./include/SugarObjects/templates/sale/language/application/xx_xx.lang.php
./install/language/xx_xx.lang.php
./modules/Accounts/language/xx_xx.lang.php
./modules/ACL/language/xx_xx.lang.php
./modules/ACLActions/language/xx_xx.lang.php
./modules/ACLFields/language/xx_xx.lang.php
./modules/ACLRoles/language/xx_xx.lang.php
./modules/Activities/language/xx_xx.lang.php
./modules/ActivityStream/Activities/language/xx_xx.lang.php
./modules/Administration/language/xx_xx.lang.php
./modules/Audit/language/xx_xx.lang.php
./modules/Bugs/language/xx_xx.lang.php
./modules/Calendar/language/xx_xx.lang.php
./modules/Calls/language/xx_xx.lang.php
./modules/CampaignLog/language/xx_xx.lang.php
./modules/Campaigns/language/xx_xx.lang.php
./modules/CampaignTrackers/language/xx_xx.lang.php
./modules/Cases/language/xx_xx.lang.php
./modules/Charts/language/xx_xx.lang.php
./modules/Configurator/language/xx_xx.lang.php
./modules/Connectors/language/xx_xx.lang.php
./modules/Contacts/language/xx_xx.lang.php
./modules/Contracts/language/xx_xx.lang.php
./modules/ContractTypes/language/xx_xx.lang.php


./modules/ContractTypes/language/xx_xx.lang.php
./modules/Currencies/language/xx_xx.lang.php
./modules/CustomQueries/language/xx_xx.lang.php
./modules/DataSets/language/xx_xx.lang.php
./modules/DocumentRevisions/language/xx_xx.lang.php
./modules/Documents/language/xx_xx.lang.php
./modules/DynamicFields/language/xx_xx.lang.php
./modules/EAPM/language/xx_xx.lang.php
./modules/EmailAddresses/language/xx_xx.lang.php
./modules/EmailMan/language/xx_xx.lang.php
./modules/EmailMarketing/language/xx_xx.lang.php
./modules/Emails/language/xx_xx.lang.php
./modules/EmailTemplates/language/xx_xx.lang.php
./modules/Employees/language/xx_xx.lang.php
./modules/ExpressionEngine/language/xx_xx.lang.php
./modules/Expressions/language/xx_xx.lang.php
./modules/Feedbacks/language/xx_xx.lang.php
./modules/Filters/language/xx_xx.lang.php
./modules/ForecastManagerWorksheets/language/xx_xx.lang.php
./modules/Forecasts/language/xx_xx.lang.php
./modules/ForecastWorksheets/language/xx_xx.lang.php
./modules/Groups/language/xx_xx.lang.php
./modules/Help/language/xx_xx.lang.php
./modules/History/language/xx_xx.lang.php
./modules/Holidays/language/xx_xx.lang.php
./modules/Home/language/xx_xx.lang.php
./modules/Import/language/xx_xx.lang.php
./modules/InboundEmail/language/xx_xx.lang.php
./modules/KBDocuments/language/xx_xx.lang.php
./modules/KBTags/language/xx_xx.lang.php
./modules/LabelEditor/language/xx_xx.lang.php
./modules/Leads/language/xx_xx.lang.php
./modules/MailMerge/language/xx_xx.lang.php


./modules/MailMerge/language/xx_xx.lang.php
./modules/Manufacturers/language/xx_xx.lang.php
./modules/Meetings/language/xx_xx.lang.php
./modules/MergeRecords/language/xx_xx.lang.php
./modules/ModuleBuilder/language/xx_xx.lang.php
./modules/Notes/language/xx_xx.lang.php
./modules/Notifications/language/xx_xx.lang.php
./modules/OAuthKeys/language/xx_xx.lang.php
./modules/OAuthTokens/language/xx_xx.lang.php
./modules/Opportunities/language/xx_xx.lang.php
./modules/OptimisticLock/language/xx_xx.lang.php
./modules/PdfManager/language/xx_xx.lang.php
./modules/pmse_Business_Rules/language/xx_xx.lang.php
./modules/pmse_Emails_Templates/language/xx_xx.lang.php
./modules/pmse_Inbox/language/xx_xx.lang.php
./modules/pmse_Project/language/xx_xx.lang.php
./modules/ProductBundleNotes/language/xx_xx.lang.php
./modules/ProductBundles/language/xx_xx.lang.php
./modules/ProductCategories/language/xx_xx.lang.php
./modules/Products/language/xx_xx.lang.php
./modules/ProductTemplates/language/xx_xx.lang.php
./modules/ProductTypes/language/xx_xx.lang.php
./modules/Project/language/xx_xx.lang.php
./modules/ProjectTask/language/xx_xx.lang.php
./modules/ProspectLists/language/xx_xx.lang.php
./modules/Prospects/language/xx_xx.lang.php
./modules/Quotas/language/xx_xx.lang.php
./modules/Quotes/language/xx_xx.lang.php
./modules/Relationships/language/xx_xx.lang.php
./modules/Releases/language/xx_xx.lang.php
./modules/ReportMaker/language/xx_xx.lang.php
./modules/Reports/language/xx_xx.lang.php
./modules/RevenueLineItems/language/xx_xx.lang.php


./modules/RevenueLineItems/language/xx_xx.lang.php
./modules/Roles/language/xx_xx.lang.php
./modules/SavedSearch/language/xx_xx.lang.php
./modules/Schedulers/language/xx_xx.lang.php
./modules/SchedulersJobs/language/xx_xx.lang.php
./modules/Shippers/language/xx_xx.lang.php
./modules/SNIP/language/xx_xx.lang.php
./modules/Studio/language/xx_xx.lang.php
./modules/Styleguide/language/xx_xx.lang.php
./modules/SugarFavorites/language/xx_xx.lang.php
./modules/Sync/language/xx_xx.lang.php
./modules/Tasks/language/xx_xx.lang.php
./modules/TaxRates/language/xx_xx.lang.php
./modules/TeamNotices/language/xx_xx.lang.php
./modules/Teams/language/xx_xx.lang.php
./modules/TimePeriods/language/xx_xx.lang.php
./modules/Trackers/language/xx_xx.lang.php
./modules/UpgradeWizard/language/xx_xx.lang.php
./modules/Users/language/xx_xx.lang.php
./modules/UserSignatures/language/xx_xx.lang.php
./modules/WebLogicHooks/language/xx_xx.lang.php
./modules/WorkFlow/language/xx_xx.lang.php
./modules/WorkFlowActions/language/xx_xx.lang.php
./modules/WorkFlowActionShells/language/xx_xx.lang.php
./modules/WorkFlowAlerts/language/xx_xx.lang.php
./modules/WorkFlowAlertShells/language/xx_xx.lang.php
./modules/WorkFlowTriggerShells/language/xx_xx.lang.php
Dashlet Strings


./modules/WorkFlowTriggerShells/language/xx_xx.lang.php
Dashlet Strings
Dashlet strings are mostly specific to BWC dashboards. Within each dashlet language definitionÂ is aÂ $dashletStringsÂ variable. Create a definition to mimicÂ each dashlet fileÂ to reflect theÂ new language. To do this,Â duplicate an existing language of your choiceÂ and change the language key in the path.Â Be sure to only change theÂ array valuesÂ and leave the array keys as they are inside of each file.
The dashlet paths are listed below:
./modules/Calendar/Dashlets/CalendarDashlet/CalendarDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/CampaignROIChartDashlet/CampaignROIChartDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/MyModulesUsedChartDashlet/MyModulesUsedChartDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/MyOpportunitiesGaugeDashlet/MyOpportunitiesGaugeDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/MyPipelineBySalesStageDashlet/MyPipelineBySalesStageDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/MyTeamModulesUsedChartDashlet/MyTeamModulesUsedChartDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/OpportunitiesByLeadSourceByOutcomeDashlet/OpportunitiesByLeadSourceByOutcomeDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/OpportunitiesByLeadSourceDashlet/OpportunitiesByLeadSourceDashlet.xx_xx.lang.php
./modules/Charts/Dashlets/OutcomeByMonthDashlet/OutcomeByMonthDashlet.xx_xx.lang.php


./modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.xx_xx.lang.php
./modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.xx_xx.lang.php
./modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.xx_xx.lang.php
./modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.xx_xx.lang.php
./modules/Home/Dashlets/RSSDashlet/RSSDashlet.xx_xx.lang.php
./modules/SugarFavorites/Dashlets/SugarFavoritesDashlet/SugarFavoritesDashlet.xx_xx.lang.php
./modules/TeamNotices/Dashlets/TeamNoticesDashlet/TeamNoticesDashlet.xx_xx.lang.php
./modules/Trackers/Dashlets/TrackerDashlet/TrackerDashlet.xx_xx.lang.php
Templates
Sugar also contains templates that are used when emailing users. Duplicate an existing language templateÂ and change the language text as needed. This time, you will need to leave the language keys exactly as they are in the file.
The template paths are listed below:
./include/language/xx_xx.notify_template.html
Configuration
Once you have your language definitions ready, you will need to tell Sugar a new language should be listed for users. For development purposes, you can addÂ $sugar_config['languages']['Lo_Ip'] = 'Lorem Ipsum'; to your config_override.php. It is important to note that this language configuration will automatically be set for you during the installation of a module loadable language package.Â
Module Loadable Packages


Module Loadable Packages
Once you have the newÂ language files ready, create an installer package so the files can be installed to a new instance. To do this, create an empty directory and move the files into it, mimicking the folder structures shown above. Once that is completed, create a manifest.php in the root of theÂ new directory with a $manifest['type'] of "langpack". An example manifest file is shown below this section. For more information on building manifests, please visit the introduction to the manifestÂ page.
Note: Sugar Sell Essentials customers do not have the ability to upload custom file packages to Sugar using Module Loader.
Example Manifest File
<?php
$manifest = array (
  'acceptable_sugar_versions' =>
  array (
    'regex_matches' =>
    array (
      '13.0.*',
    ),
  ),
  'acceptable_sugar_flavors' =>
  array (
    'PRO',
    'ENT',
    'ULT',
  ),
  'readme' => '',
  'key' => 1454474352,
  'author' => 'SugarCRM',
  'description' => 'Installs an example Lorem Ipsum language pack',
  'icon' => '',
  'is_uninstallable' => true,
  'name' => 'Lorem Ipsum Language Pack',
  'published_date' => '2018-02-03 00:00:00',
  'type' => 'langpack',
  'version' => 1454474352,
  'remove_tables' => '',
);
?>


'remove_tables' => '',
);
?>
Once your manifest is completed, youÂ will need to zip up the contents of your new folder. An example of a language pack installer can be downloadedÂ here. When your language pack is ready, it can be installed through the module loader. The installationÂ will automatically add your new language to the $sugar_config['languages'] array in your config.php. AfterÂ installation. it is highly recommended to navigate to the Sugar Administration page, click on "Repairs", and execute the following repair tools:
Quick Repair and Rebuild
Rebuild Javascript Languages
The new language should now be available for use in your Sugar instance. If you do not see the language listed, please clear your browser cache and refresh the page.
  	Last modified: 2023-02-03 21:04:03


Application Labels and Lists
Overview
Â
Sugar, which is fully internationalized and localizable, differentiates languages with unique language keys. These keys prefix the files that correspond with particular languages. For example, the default language for the application is English (US), which is represented by the language key en_us. Any file that contains data specific to the English (US) language begins with the characters en_us. Language label keys that are not recognized willÂ default to the English (US) version.
For more information on language keys, please refer to the Languages page.
Application Labels and Lists
$app_list_strings and $app_strings
The $app_list_stringsÂ array contains the various dropdown lists for the systemÂ while $app_strings contains the system application labels. The initial set of definitions can be found in ./include/language/<language key>.lang.php. As you work within the system and deploy modules and lists through Studio, any changes to these listsÂ will be reflected in the language's extensionÂ directory: ./custom/Extension/application/Ext/Language/<language key>.<list name>.php.
Customizing Application Labels and Lists
If you are developing a customization and want to be able to create or edit existing label or list values, you will need to work within the extension application directory. To do this, createÂ ./custom/Extension/application/Ext/Language/<language key>.<unique name>.php.
The file shouldÂ contain your override values with each label index set individually. An example of this is:
<?php
$app_strings['LBL_KEY'] = 'My Display Label';
$app_list_strings['LIST_NAME']['Key_Value'] = 'My Display Value';


$app_list_strings['LIST_NAME']['Key_Value'] = 'My Display Value';
Once the file is created with your adjustments, navigate to Admin > Repair > Quick Rebuild & Repair. This will compile all of the Extension files from ./custom/Extension/application/Ext/Language/ to ./custom/application/Ext/Language/<language key>.lang.ext.php.
Hierarchy Diagram
Retrieving Labels
There are two ways to retrieve a label. The first is to use the translate()Â function found in ./include/utils.php. This function will retrieve the label for the current user's language and can also be used to retrieve labels from $mod_strings, $app_strings, or app_list_strings.
An example of this is:
require_once 'include/utils.php';
$label = translate('LBL_KEY');
Alternatively, you can also use the global variable $app_strings as follows:
global $app_strings;
$label = '';
if (isset($app_strings['LBL_KEY']))
{
    $label = $app_strings['LBL_KEY'];
}
Note: If a label key is not found for the user's preferred language, the system will default to "en_us" and pull the English (US) version of the label for display.Â
Retrieving Lists
There are two ways to retrieve a label. The first is to use the translate() function found in include/utils.php. This function will retrieve the label for the current user's language.
An example of this is:
require_once 'include/utils.php';
$list = translate('LIST_NAME');
//You can also retrieve a specific list value this way
$displayValue = translate('LIST_NAME', '', 'Key_Value');
Alternatively, you can also use the global variable $app_list_strings as follows:
global $app_list_strings;
$list = array();
if (isset($app_list_strings['LIST_NAME']))
{


$list = array();
if (isset($app_list_strings['LIST_NAME']))
{
    $list = $app_list_strings['LIST_NAME'];
}
Note: If a listÂ key is not found for the user's preferred language, the system will default to "en_us" and pull the English (US) version of the list for display.
Accessing Application Strings in Sidecar
All language-pack strings are accessible within the Sidecar framework.
$app_strings
To access $app_strings in Sidecar, use app.lang.getAppString:
app.lang.getAppString('LBL_MODULE');
To accessÂ $app_strings in your browser's console, use SUGAR.App.lang.getAppString:
SUGAR.App.lang.getAppString('LBL_MODULE');
For more information, please refer to the app.lang.getAppString section of the Languages page.
$app_list_strings
To access $app_list_strings in Sidecar, use app.lang.getAppListStrings:
app.lang.getAppListStrings('sales_stage_dom');
To accessÂ $app_list_strings in your browser's console, use SUGAR.App.lang.getAppListStrings:
SUGAR.App.lang.getAppListStrings('sales_stage_dom');
For more information, please refer to the app.lang.getAppListStrings section of the Languages page.
  	Last modified: 2023-02-03 21:04:03


Module Labels
require_once 'include/utils.php';
$label = translate('LBL_KEY', 'Accounts');
Overview
Sugar, which is fully internationalized and localizable, differentiates languages with unique language keys. These keys prefix the files that correspond to particular languages. For example, the default language for the application is English (US), which is represented by the language key en_us. Any file that contains data specific to the English (US) language begins with the characters en_us. Language label keys that are not recognized willÂ default to the English (US) version.
For more information on language keys, please refer to the Languages page.
Module Labels
$mod_strings
The module language strings are stored in $mod_strings. This section explains how the $mod_strings are compiled. All modules, whether out-of-box or custom, will have an initial set of language files in ./modules/<module>/language/<language key>.lang.php.
As you work with the system and modify labels through Studio, changes to the labels are reflected in the corresponding module's custom extension directory: ./custom/Extension/modules/<module>/Ext/Language/<language key>.lang.php.
Customizing Labels
If you are developing a customization and want to be able to create new or override existing label values, you will need to work within the extension modules directory. To do this, create ./custom/Extension/modules/<module>/Ext/Language/<language key>.<unique_name>.php.
The file should contain your override values with each label index set individually. An example of this is:
<?php
$mod_strings['LBL_KEY'] = 'My Display Label';


<?php
$mod_strings['LBL_KEY'] = 'My Display Label';
Once the file is created with your adjustments, navigate to Admin > Repair > Quick Rebuild & Repair. This will compile all of the Extension files from ./custom/Extension/modules/<module>/Ext/Language/ to ./custom/modules/<module>/Ext/Language/<language key>.lang.ext.php.
Label Cache
The file locations discussed above are compiled into the cache directory, ./cache/modules/<module>/language/<language key>.lang.php
The cached results of these files make up each module's $mod_strings definition.
Hierarchy Diagram
Retrieving Labels
There are two ways to retrieve a label. The first is to use the translate() function found in include/utils.php. This function will retrieve the label for the current user's language and can also be used to retrieve labels from $mod_strings, $app_strings, or app_list_strings.
An example of this is:
require_once 'include/utils.php';
$label = translate('LBL_KEY', 'Accounts');
Alternatively, you can use the global variable $mod_strings as follows:
global $mod_strings;
$label = '';
if (isset($mod_strings['LBL_KEY']))
{
    $label = $mod_strings['LBL_KEY'];
}
Accessing Module Strings in Sidecar
All language-pack strings are accessible within the Sidecar framework.
$mod_strings
To access the $mod_strings in Sidecar, use app.lang.get():
app.lang.get('LBL_NAME', 'Accounts');
To access the $mod_strings in your browser's console, use SUGAR.App.lang.get():
SUGAR.App.lang.get('LBL_NAME', 'Accounts');
For more information, please refer to the app.lang.get section of the Languages page.
  	Last modified: 2023-02-03 21:04:03


Managing Lists
Overview
There are three ways to manage lists in Sugar: by using Studio in the application, by directly modifying the list's language strings, and via the code-level Dropdown Helper. This page explains all three methods.
Managing Lists With Studio
If you know the name of the list you would like to edit, you can access the application's dropdown editor by navigating to Admin > Dropdown Editor. Alternatively, navigate to a field that uses the list (Admin > Studio > {Module} > Fields > {field_name}) and click "Edit" under the Dropdown List field:
For information on using the dropdown editor, please refer to the Developer Tools documentation in the Administration Guide.
Directly Modifying Lists
There are two ways to directly modify the language strings. The first way is to modify the custom language file, located at ./custom/include/language/<language key>.lang.php.
If you are developing a customization to be distributed and you want to be able to create new or override existing list values, you will need to work within the extension application directory. To do this you will create the following file: ./custom/Extension/application/Ext/Language/<language key>.<unique name>.php.
The file will contain your override values. Please note that within this file you will set each label index individually. An example of this is:
<?php
$app_list_strings['LIST_NAME']['Key_Value'] = 'My Display Value';
Once the file is created with your adjustments, navigate to Admin > Repair > Quick Rebuild & Repair. This will compile all of the Extension files from ./custom/Extension/application/Ext/Language/ to ./custom/application/Ext/Language/<language key>.lang.ext.php.
Managing Lists With Dropdown Helper
You can use the dropdown helper to manage lists at the code level. This example demonstrates how to add and update values for a specific dropdown list:


require_once 'modules/Studio/DropDowns/DropDownHelper.php';
$dropdownHelper = new DropDownHelper();
$parameters = array();
$parameters['dropdown_name'] = 'example_list';
$listValues = array(
    'Key_Value_1' => 'Display Value 1',
    'Key_Value_2' => 'Display Value 2',
    'Key_Value_3' => 'Display Value 3'
);
$count = 0;
foreach ($listValues as $key=>$value) {
    $parameters['slot_'. $count] = $count;
    $parameters['key_'. $count] = $key;
    $parameters['value_'. $count] = $value;
    //set 'use_push' to true to update/add values while keeping old values
    $parameters['use_push'] = true;
    $count++;
}
$dropdownHelper->saveDropDown($parameters);
  	Last modified: 2023-02-03 21:04:03


Module Loader
Module Loader is used when installingÂ customizations, plugins,languageÂ packs, andÂ hotfixes, and other customizations into a Sugar instance in the form of a Module Loadable Package. This documentation covers the basics and best practices for creating module loadable packages for a Sugar installation.
Note: Sugar Sell Essentials customers do not have the ability to upload custom file packages to Sugar using Module Loader.
TopicsIntroduction to the ManifestModule loadable packages rely on a manifest.php file to define the basic properties and installation steps for the package. This documentation explains the various components that make up the manifest file.Module Loader RestrictionsSugarCRM's hosting objective is to maintain the integrity of the standard Sugar functionality when we upgrade a customer instance and limit any negative impact our upgrade has on the customer's modifications. All instances hosted on Sugar's cloud service have package scanner enabled by default. This setting is not configurable and all packages must pass the package scan for installation on Sugar's cloud environment. This includes passing all health checks.Module Loader Restriction AlternativesThis article provides workarounds for commonly used functions that are denylisted by Sugar for Sugar's cloud environment.Sugar Exchange Package GuidelinesSugar Module Loadable Package development guidelines for apps listed on Sugar Exchange.
  	Last modified: 2023-02-03 21:04:03


Introduction to the Manifest
Overview
Module loadable packages rely on a manifest.php file to define the basic properties and installation steps for the package. This documentationÂ explains the various components that make up the manifest file.
Note: Sugar Sell Essentials customers do not have the ability to upload custom file packages to Sugar using Module Loader.
Manifest Definitions
Inside of the manifest.php file, there is a $manifest variable that defines the basic properties of the module loadable package. The various manifest properties are outlined below:
Name
Type
Displayed in Module Loader
Description
key
String
No
A unique identifier for the package$manifest['key'] = '32837';
name
String
Yes
The name of the package$manifest['name'] = 'Example Package';
description
String
Yes
The description of the package$manifest['description'] = 'Example Package Description';
built_in_version
String
No
The version of Sugar that the package was designed for$manifest['built_in_version'] = '13.0.0';
Note: Some packages designed for 6.x versions of Sugar are not compatible with 13.0 and should not be installed.
version
String
Yes
The version of the package, i.e. "1.0.0" $manifest['version'] = '1.0.0';
Note:Â The version string should be formatting according toÂ  theÂ Semantic Versioning 2.0Â standard.
acceptable_sugar_versions
Array
No
The Sugar versions that a package can be installed to$manifest['acceptable_sugar_versions'] = array(
    'exact_matches' => array(
        '13.0.0',
    ),
    //or
    'regex_matches' => array(
        '13.0.*',
    ),
);


'13.0.*',
    ),
);
Note: You can define exact versions and/or use a regex formula to define a range. Exact versions will be specified using the exact_matches index and will contain an array of exact version strings (i.e. '13.0.0'). Regex formulas will be specified using the regex_matches index and will contain an array of regular expressions designed to match a group of versions (i.e. '13.0.*').
acceptable_sugar_flavors
Array
No
The Sugar products that the package can be installed to$manifest['acceptable_sugar_flavors'] = array(
    'PRO',
    'ENT',
    'ULT'
);
author
String
No
The author of the package (i.e. "SugarCRM")$manifest['author'] = 'SugarCRM';
readme
String
No
The optional path to a readme document to be displayed to the user during installation $manifest['readme'] = 'README.txt';
icon
String
No
The optional path (within the package ZIP file) to an icon image to be displayed during installation (e.g. ./patch_directory/icon.gif and ./patch_directory/images/theme.gif)$manifest['icon'] = '';
is_uninstallable
Boolean
No
Whether or not the package can be uninstalledAcceptable values:
'true' will allow a Sugar administrator to uninstall the package
'false' will disable the uninstall feature
$manifest['is_uninstallable'] = true;
published_date
String
No
The date the package was published$manifest['published_date'] = '2018-04-09 00:00:00';
remove_tables
String
No


remove_tables
String
No
Whether or not tables generated by the $installdefs['beans'] index should be removed from an installed module (acceptable values: empty or 'prompt')$manifest['remove_tables'] = 'prompt';
type
String
No
Acceptable 'type' values:module : Use this type if you are installing a module or developing a plugin that should install via the Module Loader.
langpack : Use this type to install a language pack via the Module Loader. Any languages installed will automatically be added to the available languages on the Sugar login screen. For an example of a module loadable language pack, refer to the Language Framework page.
theme : Use this type to install a Sugar theme via the Upgrade Wizard. Themes are only supported in Sugar 6.x, and will be added to the "Theme" drop-down on the Sugar Login screen.
patch : Use this type to install a patch via the Upgrade Wizard.
dependencies
Array
No
Required dependency packages:
$manifest['dependencies'] = array(
    array(
        'id_name' => 'PackageName',
        'version' => '1.0.0'
    )
);
uninstall_before_upgrade
Boolean
No
This will allow Module Loader to ensure all traces of previously installed package versions (including packages that have been upgraded multiple times) have been removed.
$manifest['uninstall_before_upgrade'] = true;
Manifest Example
An example of a manifest is shown below:
$manifest = array(
  'key' => 1397052912,
  'name' => 'My manifest',
  'description' => 'My description',
  'author' => 'SugarCRM',
  'version' => '1.0.0',
  'is_uninstallable' => true,


'is_uninstallable' => true,
  'published_date' => '04/07/2023 14:15:12',
  'type' => 'module',
  'acceptable_sugar_versions' =>
  array(
    'exact_matches' => array(
        '13.0.0'
    ),
    //or
    'regex_matches' => array(
        '13.0.*' //any 13.0 release
    ),
  ),
  'acceptable_sugar_flavors' =>
  array(
    'PRO',
    'ENT',
    'ULT'
  ),
  'readme' => '',
  'icon' => '',
  'remove_tables' => '',
  'uninstall_before_upgrade' => false,
);
Installation Definitions
The following section outlines the indexes specified in the $installdefs array contained in the ./manifest.php file. The $installdefs array indexes are used by the Module Loader to determine the actual installation steps that need to be taken to install the package.
$installdef Actions
Name
Type
Description
action_file_map
ArrayÂ
ActionFileMapÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
action_remap
Â Array
ActionReMapÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
action_view_map
Â Array
ActionViewMapÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
administration
Â Array
AdministrationÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
appscheduledefs
Â Array


appscheduledefs
Â Array
Application ScheduledTasksÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
beans
Â Array
ModulesÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
connectors
Array
An array containing Connector definitions as outlined in the Connector documentation.
$installdefs['connectors'] = array (
     array (
         'connector' => '<basepath>/example/source',
         'formatter' => '<basepath>/example/formatter',
         'name' => 'ext_rest_example',
     ),
);
copy
Array
An array detailing the files and folders to be copied to SugarRequired parameters for each file in the array:
from (string) : The location of the file in the module loadable package$installdefs['copy'][0]['from'] = '<basepath>/Files/custom/modules/Accounts/accounts_save.php';
to (string) : The destination directory relative to the Sugar root$installdefs['copy'][0]['to'] = 'custom/modules/Accounts/accounts_save.php';
Example:
$installdefs['copy'] = array(
    array(
        'from' => '<basepath>/Files/custom/modules/Accounts/accounts_save.php',
        'to' => 'custom/modules/Accounts/accounts_save.php',
    ),
);
csp
Array
CSP directives needed for proper operation of the package should be represented as an associative arraywhere keys are directive names and values are corresponding trusted sources.Example:
  $installdefs = array(
          ...
          'csp' => [
             'default-src' => '*.trusted.com example.com',
             'img-src' => 'http: https:'
             ...
         ]
         ...
     );


...
         ]
         ...
     );
This parameter takes a space-delimited string of domains - just like the admin module. Setting the value of the default-src via MLP is an append operation. The values you put into the csp parameter of your manifest will be added to the CSP list in the admin module. Note that uninstall DOES NOT remove a value.
custom_fields
Array
An array of custom fields to be installed for the new moduleRequired sub-directives for each custom field formatted as:
$installdefs['custom_fields'][0]['<attribute>'] = <value>;
name (String) : The internal name of the custom fieldNote: The suffix "_c" is appended to all custom field names (e.g. fieldname_c).
label (String) : The display label for the custom field
type (String) : The type of custom field (e.g. varchar, text, textarea, double, float, int, date, bool, enum, relate)
max_size (Integer) : The custom field's maximum character storage size
require_option (String) : Defines whether fields are 'required' or 'optional'
default_value (String) : The default value for the custom field
ext1 (String) : Used to specify a drop-down name for enum and multienum type fields
ext2 (String) : Not used
ext3 (String) : Not used
audited (Boolean) : Denotes whether or not the custom field should be audited
module (String) : The module where the custom field will be added
Example:
$installdefs['custom_fields'] = array((
    array((
        'name' => 'text_c',
        'label' => 'LBL_TEXT_C',
        'type' => 'varchar',
        'max_size' => 255,
        'require_option' => 'optional',


'max_size' => 255,
        'require_option' => 'optional',
        'default_value' => '',
        'ext1' => '',
        'ext2' => '',
        'ext3' => '',
        'audited' => true,
        'module' => 'Accounts',
    ),
);
console
Array
ConsoleÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
dashlets
Array
An array containing the Dashlet definition.
Required parameters for each file in the array:
nameÂ (string) : The name of the dashlet. Used for the folder name where the Dashlet files will be stored in Sugar file system.
fromÂ (string) : The location of the dashlet files in the module loadable package.
$installdefs['dashlets'] = array(
	array(
		'name' => 'MyDashlet',
		'from' => '<basepath>/MyDashlet'
	)
);
dependencies
Â Array
DependenciesÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
entrypoints
Â Array
EntryPointRegistryÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
extensions
Â Array
ExtensionsÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
file_access
Â Array
FileAccessControlMapÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
hookdefs
Â Array
LogicHooksÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
id
String


id
String
A unique id for the installdef definition$installdefs['id'] = 'unique_name';
image_dir
String
The directory that contains the icons for the module$installdefs['image_dir'] = '<basepath>/icons';
jsgroups
Â Array
JSGroupingsÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
language
Â Array
LanguageÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
layoutdefs
Â Array
LayoutdefsÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
layoutfields
Array
An array of custom fields to be added to the edit and detail views of the target modules' existing layouts
logic_hooks
Â Array
Â An array containing full logic Hook definitions, as outlined in the LogicHook documentation.
$installdefs['logic_hooks'] = array(
      array(
          'module' => 'Accounts',
          'hook' => 'before_save',
          'order' => 99,
          'description' => 'Example Logic Hook - Logs account name',
          'file' => 'custom/modules/Accounts/accounts_save.php',
          'class' => 'Accounts_Save',
          'function' => 'before_save',
      ),
);
LogicHooks defined for install using the $installdefs['logic_hooks'] index, will be added to the module or application folder in the custom directory, in the logic_hooks.php file. Examples:
./custom/modules/Accounts/logic_hooks.php
./custom/application/logic_hooks.php
Note: You will still need to utilize a $installdefs['copy'] indexÂ to move the LogicHook class file into the system.
platforms
Array


platforms
Array
Platforms is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
pre_execute
Array
Executes logic from a file (or set of files) before a package is installedExample:$installdefs['pre_execute'] = array(
    '<basepath>/pre_execute.php',
);
Where the content of <basepath>/pre_execute.php is:
<?php
//pre_execute logic
echo 'pre_execute script
';
post_execute
Array
Executes logic from a file (or set of files) after a package is installedExample:$installdefs['post_execute'] = array(
    '<basepath>/post_execute.php',
);
Where the content of <basepath>/post_execute.php is:<?php
//post_execute logic
echo 'post_execute script
';
pre_uninstall
Array
Executes logic from a file (or set of files) before a package is uninstalledExample:$installdefs['pre_uninstall'] = array(
    '<basepath>/pre_uninstall.php',
);
Where the content of <basepath>/pre_uninstall.php is:<?php
//pre_uninstall logic
echo 'pre_uninstall script
';
post_uninstall
Array
Executes logic from a file (or set of files) after a package is uninstalled Example:$installdefs['post_uninstall'] = array(
    '<basepath>/post_uninstall.php'
);
Where the content of <basepath>/post_uninstall.php is:<?php
//post_uninstall logic
echo 'post_uninstall script
';
relationships
Array
An array of relationship files used to link the new modules to existing modulesNote: A metadata path must be defined using meta_data (string):
$installdefs['relationships'][0]['meta_data'] =


$installdefs['relationships'][0]['meta_data'] =
'<basepath>/SugarModules/relationships/relationships/my_module_accountsMetaData.php';
Where the content of my_module_accountsMetaData.php is:<?php
$dictionary['my_module_accounts'] = array (
    'true_relationship_type' => 'many-to-many',
    'relationships' =>
        array((
            'my_module_accounts' =>
                array((
                    'lhs_module' => 'my_Module',
                    'lhs_table' => 'my_module',
                    'lhs_key' => 'id',
                    'rhs_module' => 'Accounts',
                    'rhs_table' => 'accounts',
                    'rhs_key' => 'id',
                    'relationship_type' => 'many-to-many',
                    'join_table' => 'my_module_accounts_c',
                    'join_key_lhs' => 'my_module_accountsmy_module_ida',
                    'join_key_rhs' => 'my_module_accountsaccounts_idb',
                ),
        ),
    'table' => 'my_module_accounts_c',
    'fields' =>
        array((
            0 =>
                array((
                    'name' => 'id',
                    'type' => 'varchar',
                    'len' => 36,
                ),
            1 =>
                array((
                    'name' => 'date_modified',
                    'type' => 'datetime',
                ),
            2 =>
                array((
                    'name' => 'deleted',
                    'type' => 'bool',
                    'len' => '1',
                    'default' => '0',
                    'required' => true,
                ),
            3 =>
                array((
                    'name' => 'my_module_accountsmy_module_ida',
                    'type' => 'varchar',


'type' => 'varchar',
                    'len' => 36,
                ),
            4 =>
                array((
                    'name' => 'my_module_accountsaccounts_idb',
                    'type' => 'varchar',
                    'len' => 36,
                ),
        ),
    'indices' =>
        array((
            0 =>
                array((
                    'name' => 'my_module_accountsspk',
                    'type' => 'primary',
                    'fields' =>
                        array((
                            0 => 'id',
                        ),
                ),
            1 =>
                array((
                    'name' => 'my_module_accounts_alt',
                    'type' => 'alternate_key',
                    'fields' =>
                        array((
                            0 => 'my_module_accountsmy_module_ida',
                            1 => 'my_module_accountsaccounts_idb',
                        ),
                ),
        ),
);
scheduledefs
Â Array
ScheduledTasksÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
sidecar
Â Array
SidecarÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
tinymce
Â Array
TinyMCEÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
user_page
Â Array
UserPageÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
utils
Â Array
UtilsÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
vardefs
Â Array


vardefs
Â Array
VardefsÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
wireless_modules
Â Array
WirelessModuleRegisteryÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
wireless_subpanels
Â Array
WirelessLayoutDefsÂ is part of the Extension Framework. More detail can be found in theÂ Extension Framework documentation.
Note: Anything printed to the screen in the pre_execute, post_execute, pre_uninstall, or post_uninstall scripts will be displayed when clicking on the Display Log link.
  	Last modified: 2023-02-03 21:04:03


Module Loader Restrictions
Overview
SugarCRM's hosting objective is to maintain the integrity of the standard Sugar functionality when we upgrade a customer instanceÂ and limit any negative impact our upgrade has on the customer's modifications. All instances hosted on Sugar's cloud service have package scanner enabled by default. This setting is not configurable and all packages must pass the package scan for installation on Sugar's cloud environment. This includes passing all health checks.
Note: Sugar Sell Essentials customers do not have the ability to upload custom file packages to Sugar using Module Loader.
Access Controls
The Module Loader includes a Module Scanner, which grants system administrators the control they need to determine the precise set of actions that they are willing to offer in their hosting environment. This feature is available in all Sugar products. Anyone who is hosting Sugar products can take advantage of this feature, as well.
Enabling Package Scan
Scanning is disabled in default installations of SugarÂ and can be enabled through a configuration setting. This setting is added to ./config.php or ./config_override.php, and is not available to Administrator users to modify through the Sugar interface. Please note that this setting can only be managed on an on-site deployment and cannot be disabled for Sugar's cloud environment.
To enable Package Scan and its associated scans, add this setting to ./config_override.php:
$sugar_config['moduleInstaller']['packageScan'] = true;
There are two categories of access control in the Package Scan:
File Scan
Module Loader Actions
Enabling File Scan
By enabling Package Scan, File Scan will be performed on all files in the package uploaded through Module Loader. File Scan will be performed when a Sugar administrator attempts to install the package. Please note that these settings can only be managed on an on-site deployment. These settings are not permitted to be modified when hosted on Sugar's cloud service.
File Scan performs three checks:
File extensions must be in the approved list of valid extension types.


File extensions must be in the approved list of valid extension types.
Files mustÂ not contain anyÂ suspicious classes.
Files must not contain any suspicious function calls.
Please refer to the next three sections which outline the default requirements for the File Scan checks.Â
Valid Extension Types
File extensions must be in the approved list of valid extension types. The following extension types are valid by default:
css
gif
hbs
htm
html
jpg
js
md5
pdf
php
png
tpl
txt
xml
Denylisted Classes
Files must not contain any of the following classes that are considered suspicious by File Scan.Â
All variable classes (i.e., $class())Â are prohibited by default.
The following classes are denylisted by default:
lua
pclzip
reflection
reflectionclass
reflectionexception
reflectionextension
reflectionfunction
reflectionfunctionabstract
reflectionmethod
reflectionobject
reflectionparameter
reflectionproperty
reflectionzendextension
reflector
splfileinfo
splfileobject
ziparchive
Denylisted Function Calls
Files mustÂ not contain any of the following function calls that are considered suspicious by File Scan.
Variable functions (i.e., $func()) are prohibited by default.
Backticks (`) are prohibited by File Scan.
The following PHP functions are denylisted by default:
addfunction
addserver
array_diff_uassoc
array_diff_ukey
array_filter
array_intersect_uassoc
array_intersect_ukey
array_map
array_reduce
array_udiff
array_udiff_assoc
array_udiff_uassoc
array_uintersect
array_uintersect_assoc
array_uintersect_uassoc
array_walk
array_walk_recursive
call_user_func
call_user_func
call_user_func_array
call_user_func_array
chdir
chgrp
chmod
chroot
chwown
clearstatcache
construct
consume


chgrp
chmod
chroot
chwown
clearstatcache
construct
consume
consumerhandler
copy
copy_recursive
create_cache_directory
create_custom_directory
create_function
curl_copy_handle
curl_exec
curl_file_create
curl_init
curl_multi_add_handle
curl_multi_exec
curl_multi_getcontent
curl_multi_info_read
curl_multi_init
curl_multi_remove_handle
curl_multi_select
curl_multi_setopt
curl_setopt_array
curl_setopt
curl_share_init
curl_share_setopt
curl_share_strerror
dir
disk_free_space
disk_total_space
diskfreespace
eio_busy
eio_chmod
eio_chown
eio_close
eio_custom
eio_dup2
eio_fallocate
eio_fchmod
eio_fchown
eio_fdatasync
eio_fstat
eio_fstatvfs
eio_fsync
eio_ftruncate
eio_futime
eio_grp
eio_link
eio_lstat
eio_mkdir
eio_mknod
eio_nop
eio_open
eio_read
eio_readahead
eio_readdir
eio_readlink
eio_realpath
eio_rename
eio_rmdir
eio_sendfile
eio_stat
eio_statvfs
eio_symlink
eio_sync
eio_sync_file_range
eio_syncfs
eio_truncate
eio_unlink
eio_utime
eio_write
error_log
escapeshellarg
escapeshellcmd
eval
exec
fclose
fdf_enum_values
feof
fflush
fgetc
fgetcsv
fgets
fgetss
file
file_exists
file_get_contents
file_put_contents
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype


filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
flock
fnmatch
fopen
forward_static_call
forward_static_call_array
fpassthru
fputcsv
fputs
fread
fscanf
fseek
fstat
ftell
ftruncate
fwrite
get
getbykey
getdelayed
getdelayedbykey
getfunctionvalue
getimagesize
glob
header_register_callback
ibase_set_event_handler
ini_set
is_callable
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
iterator_apply
lchgrp
lchown
ldap_set_rebind_proc
libxml_set_external_entity_loader
link
linkinfo
lstat
mailparse_msg_extract_part
mailparse_msg_extract_part_file
mailparse_msg_extract_whole_part_file
mk_temp_dir
mkdir
mkdir_recursive
move_uploaded_file
newt_entry_set_filter
newt_set_suspend_callback
ob_start
open
opendir
parse_ini_file
parse_ini_string
passthru
passthru
pathinfo
pclose
pcntl_signal
popen
preg_replace_callback
proc_close
proc_get_status
proc_nice
proc_open
readdir
readfile
readline_callback_handler_install
readline_completion_function
readlink
realpath
realpath_cache_get
realpath_cache_size
register_shutdown_function
register_tick_function
rename
rewind
rmdir
rmdir_recursive
session_set_save_handler
set_error_handler
set_exception_handler
set_file_buffer
set_local_infile_handler
set_time_limit
setclientcallback
setcompletecallback
setdatacallback
setexceptioncallback
setfailcallback
setserverparams
setstatuscallback
setwarningcallback
setworkloadcallback
shell_exec
simplexml_load_file


setwarningcallback
setworkloadcallback
shell_exec
simplexml_load_file
simplexml_load_string
socket_accept
socket_addrinfo_bind
socket_addrinfo_connect
socket_addrinfo_explain
socket_addrinfo_lookup
socket_bind
socket_clear_error
socket_close
socket_cmsg_space
socket_connect
socket_create_listen
socket_create_pair
socket_create
socket_export_stream
socket_get_option
socket_getopt
socket_getpeername
socket_getsockname
socket_import_stream
socket_last_error
socket_listen
socket_read
socket_recv
socket_recvfrom
socket_recvmsg
socket_select
socket_send
socket_sendmsg
socket_sendto
socket_set_block
socket_set_nonblock
socket_set_option
socket_setopt
socket_shutdown
socket_write
fsockopen
spl_autoload_register
sqlite_create_aggregate
sqlite_create_function
sqlitecreateaggregate
sqlitecreatefunction
stat
stream_bucket_append
stream_bucket_make_writeable
stream_bucket_new
stream_bucket_prepend
stream_context_create
stream_context_get_default
stream_context_get_options
stream_context_get_params
stream_context_set_default
stream_context_set_option
stream_context_set_params
stream_copy_to_stream
stream_filter_append
stream_filter_prepend
stream_filter_register
stream_filter_remove
stream_get_contents
stream_get_filters
stream_get_line
stream_get_meta_data
stream_get_transports
stream_get_wrappers
stream_is_local
stream_isatty
stream_notification_callback
stream_register_wrapper
stream_resolve_include_path
stream_select
stream_set_blocking
stream_set_chunk_size
stream_set_read_buffer
stream_set_timeout
stream_set_write_buffer
stream_socket_accept
stream_socket_client
stream_socket_enable_crypto
stream_socket_get_name
stream_socket_pair
stream_socket_recvfrom
stream_socket_sendto
stream_socket_server
stream_socket_shutdown
stream_supports_lock
stream_wrapper_register
stream_wrapper_restore
stream_wrapper_unregister
sugar_chgrp


stream_wrapper_register
stream_wrapper_restore
stream_wrapper_unregister
sugar_chgrp
sugar_chmod
sugar_chown
sugar_file_put_contents
sugar_file_put_contents_atomic
sugar_fopen
sugar_mkdir
sugar_rename
sugar_touch
sybase_set_message_handler
symlink
system
tempnam
timestampnoncehandler
tmpfile
tokenhandler
touch
uasort
uksort
umask
unlink
unzip
unzip_file
usort
write_array_to_file
write_array_to_file_as_key_value_pair
write_encoded_file
xml_set_character_data_handler
xml_set_default_handler
xml_set_element_handler
xml_set_end_namespace_decl_handler
xml_set_external_entity_ref_handler
xml_set_notation_decl_handler
xml_set_processing_instruction_handler
xml_set_start_namespace_decl_handler
xml_set_unparsed_entity_decl_handler
The following class functions are denylisted by default:
All variable functions (i.e., $func()) are prohibited by default.Â
SugarLogger::setLevel
SugarAutoLoader::put
SugarAutoLoader::unlink
Health Check
Packages must pass all health checks in order to pass through the package scanner. For more information on troubleshooting Health Check output, see the collection of help articles inÂ Troubleshooting Health Check Output.
Disabling File Scan
Note: Disabling File Scan is prohibitedÂ for instances on Sugar's cloud service.
To disable File Scan, add the following configuration setting to config_override.php:
$sugar_config['moduleInstaller']['disableFileScan'] = false;
Extending the List of Valid Extension Types
Note: Modifying the valid extensions listÂ is prohibitedÂ for instances on Sugar's cloud service.