echo $due_date_time->asDb();
// The date/time 2016-12-28T11:01:09-08:00 is set in the timezone of America/Los_Angeles
echo "The date/time " . $due_date_time->format("c") . " is set in the timezone of " . $due_date_time->format("e");
// The time when this date/time object was created is 11:01:09 AM -0800
echo "The time when this date/time object was created is " . $due_date_time->format("H:i:s A O");
// There are 31 days in the month of December
echo "There are " . $due_date_time->format("t") . " days in the month of " . $due_date_time->format("F");


// There are 366 days in the year of 2016
echo "There are " . $due_date_time->__get("days_in_year") . " days in the year of " . $due_date_time->format("Y");
// Between Wed, 28 Dec 2016 11:01:09 -0800 and the end of the year, there are 4 days.
echo "Between " . $due_date_time . " and the end of the year, there are " . ($due_date_time->__get("days_in_year") - $due_date_time->format("z")) . " days.";
Â For more information on the available options, please refer to http://php.net/manual/en/function.date.phpÂ
TimeDate Class


TimeDate Class
The TimeDateÂ class, located in ./include/TimeDate.php, utilizes the SugarDateTime class to provide an extended toolset of methods for date/time usage.
Setting
With existing TimeDate objects, it is recommended to clone the object before modifying or performing operations on it.
$new_timedate = clone $timedate;
Another option is to instantiate a new TimeDateÂ object.
// current time in UTC
$timedate = new TimeDate();
$now_utcTZ = $timedate->getNow();
// current time in user's timezone
$timedate = new TimeDate($current_user);
$now_userTZ = $timedate->getNow(true);


$now_userTZ = $timedate->getNow(true);
Note : When creating a new TimeDateÂ object, the date and time will default to the current date and time in the UTC timezone unlessÂ a user object is passed in.Â
Formatting
TimeDate objects can return the Date/Time in either a string format or in a SugarDateTime object.Â The TimeDate object has many formatting options; some of the most common ones are :
getNow
Get the current date/time as aÂ SugarDateTimeÂ objectÂ
fromUser
Get SugarDateTime objectÂ from user's date/time string
asUser
Format DateTime object as user's date/time string
fromDb
Get SugarDateTimeÂ objectÂ from a DB date/time string
fromString
Create aÂ SugarDateTime object from a string


fromString
Create aÂ SugarDateTime object from a string
get_db_date_time_format
GetsÂ the current database date and time format
to_display_date_time
Format aÂ stringÂ as user's display date/time
getNow
returnsÂ SugarDateTime object
Parameters
Name
Data Type
Default
Description
$userTz
bool
false
Whether to useÂ the user's timezone or not. False will use UTC
Returns a SugarDateTime object set to the current date/time. If there is aÂ user object associateÂ to the TimeDate object, passing true to the $userTz parameter will return the object in user's timezone. If no user is associated or false is passed, the timezone returned will be in UTC.
Example
$timedate = new TimeDate($current_user);


Example
$timedate = new TimeDate($current_user);
// returns current date/time in UTC
$now_utcTZ = $timedate->getNow();
// returns current date/time in the user's timezone
$now_userTZ = $timedate->getNow(true);
fromUser
returnsÂ SugarDateTime object
Parameters
Name
Data Type
Default
Description
$date
string
n/a
Date/Time string to convert to an object
$user
User
null
User to utilize formatting and timezone info from
Returns a SugarDateTime objectÂ converted from the passed in string.Â If there is a user object passed in as a parameter will return the object in user's timezone. If no user is passed in, the timezone returned will be in UTC.
Example


Example
$date = "2016-12-28 13:09";
$timedate = new TimeDate();
$datetime = $timedate->fromUser($date, $current_user);
asUser
returnsÂ string
Parameters
Name
Data Type
Default
Description
$date
string
n/a
Date/Time string to convert to an object
$user
User
null
User to utilize formatting and timezone info from
Returns aÂ stringÂ of the date and time formatted based on the user's profile settings.Â If there is a user object passed in as a parameter it will return the object in user's timezone. If no user is passed in, the timezone returned will be in UTC.
Example
$datetime = new datetime("2016-12-28 13:09");
$timedate = new TimeDate();


$timedate = new TimeDate();
$formattedDate = $timedate->asUser($datetime, $current_user);
fromDb
returns SugarDateTime
Parameters
Name
Data Type
Default
Description
$date
string
n/a
Date/Time string in database format to convert to an object
Returns a SugarDateTime objectÂ converted from the passed in database formatted string.
Note : If the string does not match the database format exactly, this function will return boolean false.
Example
// Y-m-d H:i:s
$db_datetime = "2016-12-28 13:09:01";
$timedate = new TimeDate();
$datetime = $timedate->fromDb($db_datetime);
// returns bool(false)
$wrong_datetime = "2016-12-28 13:09";


$wrong_datetime = "2016-12-28 13:09";
$timedate = new TimeDate();
$datetime = $timedate->fromDb($timedate);
fromString
returns SugarDateTime
Parameters
Name
Data Type
Default
Description
$date
string
n/a
Date/Time string to convert to an object
$user
User
null
User to utilize timezone info from
Returns a SugarDateTime objectÂ converted from the passed in database formatted string.Â If there is a user object passed in as a parameter it will return the object in user's timezone. If no user is passed in, the timezone returned will be in UTC.
Example
$datetime_str = "December 28th 2016 13:09";
$timedate = new TimeDate();


$timedate = new TimeDate();
$datetime = $timedate->fromString($datetime_str);
get_db_date_time_format
returnsÂ string
Parameters
N/a
Returns aÂ string of the current database date and time format settings.Â
Note : For just the date format useÂ get_db_date_format() and for just the time format useÂ get_db_time_format().
Example
$timedate = new TimeDate();
// Y-m-d H:i:s
$db_format = $timedate->get_db_date_time_format();
to_display_date_time
returnsÂ string
Parameters
Name
Data Type
Default
Description
$date
string
n/a
Date/Time string in database format
$meridiem
boolean


n/a
Date/Time string in database format
$meridiem
boolean
true
Deprecated -- Remains for backwards compatibility only
$convert_tz
boolean
true
Convert to user's timezone
$user
User
null
User to utilize formatting and timezone info from
Returns a string of the date and time formatted based on the user's profile settings. If no user is passed in, the current user's default will be used. If $convert_tz is true the string returned will beÂ in the passed in user's timezone. If no user is passed in, the timezone returned will be in UTC.
Note : If the string does not match the database format exactly, this function will return boolean false.
Example
$datetime_str = "2016-12-28 13:09:01";
// 12-28-2016 07:09


// 12-28-2016 07:09
$timedate = new TimeDate();
$datetime = $timedate->to_display_date_time($datetime_str);
// 2016-12-28 13:09
$timedate = new TimeDate();
$datetime = $timedate->to_display_date_time($datetime_str, true, false, $diff_user);
Parsing
In addition to formatting, TimeDate objects can also return Date/Time values based on special parameters.Â The TimeDate object has many date parsing options; some of the most common ones are :
parseDateRange
GetsÂ the start and end date/time from a range keywordÂ
parseDateRange
returns array
Parameters
Name
Data Type
Default
Description
$range
string
n/a


Parameters
Name
Data Type
Default
Description
$range
string
n/a
StringÂ from a predetermined list of available ranges
$user
User
null
User to utilize formatting and timezone info from
$adjustForTimezone
boolean
true
Convert to user's timezone
Returns an array ofÂ SugarDateTime objects containing the start and Date/Time values calculated based on the entered parameter. If no user is passed in, the current user's default will be used. If $adjustForTimezoneÂ is true the string returned will beÂ in the passed in user's timezone. If NULL is passed in as theÂ user, the timezone returned will be in UTC. The available values for $range are :
Range String
Description
yesterday
Yesterday's start and end date/time
today
Today's start and end date/time
tomorrow


today
Today's start and end date/time
tomorrow
Tomorrows's start and end date/time
last_7_days
Start and end date/time of the last seven days
next_7_days
Start and end date/time of the next seven days
last_30_days
Start and end date/time of the last thirty days
next_30_days
Start and end date/time of the next thirty days
next_month
Start and end date/time of next month
last_month
Start and end date/time of last month
this_month
Start and end date/time of the current month
last_year
Start and end date/time of last year
this_year
Start and end date/time of the current year
next_year
Start and end date/time of next year
Example
$timedate = new TimeDate($current_user);


Example
$timedate = new TimeDate($current_user);
// returns today's start and end date/time in UTC
$today_utcTZ = $timedate->parseDateRange("today", NULL, false);
// returns today's start and end date/time in the user's timezone
$today_userTZ = $timedate->parseDateRange("today", $current_user, true);
  	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


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


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']['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


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


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;


$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;


$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_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.


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


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['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


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


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


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


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.


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');


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


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...


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


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.


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


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


SugarPDF
Overview
An overview of SugarPDF and how it relates to TCPDF.Â As of versionÂ 6.7.x, Sugar includes a Smarty template engine calledÂ PDF Manager that is accessible by navigating to Admin > PDF Manager. TheÂ PDF Manager allows administrators to create and manage templates for deployed modules without having to write custom code. Â The following sections are only specific to developers looking to create their own custom TCPDFÂ templates using PHP.
PDF Classes
The various classes used in generating PDFs within Sugar.
TCPDF
Sugar uses the TCPDF 4.6.013Â library, located in ./vendor/tcpdf/,Â as the core engine to generate PDFs. This library is extended by SugarpdfÂ which is used by the core application to generate PDFs.Â
Sugarpdf


Sugarpdf
The Sugarpdf class, located in ./include/Sugarpdf/Sugarpdf.php, extends the TCPDF class. Within this class, we have overridden certain functions to integrate sugar features. Some key methods that were overridden are listed below:Â
Method
Description
Header
Overridden to enable custom logos.
SetFont
Overridden to allow for the loading of custom fonts. The custom fonts direction is defined by the K_PATH_CUSTOM_FONTS var. By default, this value is set to ./custom/vendor/tcpdf/fonts/
Cell
Overridden to apply the prepare_string() function. This allows for the ability to clean the string before sending to PDF. Â
Some key additional methods that were added are listed below:
Method
Description
predisplay


Some key additional methods that were added are listed below:
Method
Description
predisplay
Preprocessing before the display method is called. Is intended to setup general PDF document properties like margin, footer, header, etc.
display
Performs the actual PDF content generation. This is where the logic to display output to the PDF should be placed.
process
Calls predisplay and display.
writeCellTable
Method to print a table using the cell print method of TCPDF
writeHTMLTable
Method to print a table using the writeHTML print method of TCPDF
Custom PDF classes that extend Sugarpdf can be located in the following directories:
./include/Sugarpdf/sugarpdf/sugarpdf.<pdf view>.php
./modules/<module>/sugarpdf/sugarpdf.<pdf view>.php


./custom/modules/<module>/sugarpdf/sugarpdf.<pdf view>.php
PDF Manager classesÂ that extend Sugarpdf are located in the following directories:
./include/Sugarpdf/sugarpdf/sugarpdf.smarty.php
./include/Sugarpdf/sugarpdf/sugarpdf.pdfmanager.php
./custom/include/Sugarpdf/sugarpdf/sugarpdf.pdfmanager.php
Each extended class will define a specific PDF view that is accessible with the following URL parameters:
module=<module>
action=sugarpdf
sugarpdf=<pdf view>


action=sugarpdf
sugarpdf=<pdf view>
Within each custom PDF class, the display method will need to be redefined. If you would like, It is also possible to override other methods like Header. The process method of this class will be called from ViewSugarpdf. When a PDF is being generated, the most relevant sugarpdf.<pdf action>.pdf class is determined by the SugarpdfFactory.
ViewSugarpdf
The ViewSugarpdf class, located in ./include/MVC/View/views/view.sugarpdf.php,Â is used to create the SugarViews that generate PDFs. These views can be found and/or created in one of the following directory paths:
./modules/<module>/views/view.sugarpdf.php
./custom/modules/<module>/views/view.sugarpdf.php


./custom/modules/<module>/views/view.sugarpdf.php
SugarViews can be called by navigating to a URL in the format of:
http://<url>/index.php?module=<module>&action=sugarpdf&sugarpdf=<pdf action>
As of 6.7, PDFs are mainly generated using the PDF Manager templating system. To generate the PDF stored in the PDF Manager, you would call a URL in the format of:
http://<url>/index.php?module<module>&record=<record id>&action=sugarpdf&sugarpdf=pdfmanager&pdf_template_id=<template id>Â Â
SugarpdfFactory


SugarpdfFactory
The ViewSugarpdfÂ class uses the SugarpdfFactory class, located in ./include/Sugarpdf/SugarpdfFactory.php, to find the most relevant sugarpdf.<pdf action>.pdfÂ class which generates the PDF document for a given PDF view and module. If one is not found, then the coreÂ SugarpdfÂ class is used.
The SugarpdfFactoryÂ class loads the first class found for the specified PDF action as determined by the following order:
./custom/modules/<module>/sugarpdf/sugarpdf.<pdf view>.php
./modules/<module>/sugarpdf/sugarpdf.<pdf view>.php
./custom/include/Sugarpdf/sugarpdf/sugarpdf.<pdf view>.php


./include/Sugarpdf/sugarpdf/sugarpdf.<pdf view>.php
./include/Sugarpdf/sugarpdf.php
SugarpdfHelper
The SugarpdfHelper, located in ./include/Sugarpdf/SugarpdfHelper.php, is included by Sugarpdf. This is a utility file that contains many of the functions we use to generate PDFs. Available functions are:
wrapTag, wrapTD, wrapTable, etc. : These functions help to create an HTML code.
prepare_string : This function prepare a string to be ready for the PDF printing.
format_number_sugarpdf : This function is a copy of format_number() from currency with a fix for sugarpdf.
PdfManagerHelper


PdfManagerHelper
TheÂ PdfManagerHelper, located in ./modules/PdfManager/PdfManagerHelper.php, is primarily utilized by the pdfmanager SugarpdfÂ view. This class file contains methods useful for accessing PDF Manager templates. Some of the primary methods are:
getAvailableModules :Â Returns an array of available modules for use with PdfManager.
getFields :Â Takes an module name and returns a list of fields and links available for this module in PdfManager.
getPublishedTemplatesForModule :Â Returns an array ofÂ the available templates for a specific module.
FontManager
The FontManagerclass, located in ./include/Sugarpdf/FontManager.php, is a stand-alone class that manages all the fonts for TCPDF. More information can be found in the PDF FontsÂ section below.
Functionality:


Functionality:
List all the available fonts from the OOB font directory and the custom font directory (it can create a well-formatted list for select tag).
Get the details of each listed font (Type, size, encoding,...) by reading the font php file.
Add a new font to the custom font directory from a font file and a metric file.
Delete a font from the custom font directory.
Generating a PDF
To generate a custom PDF in Sugar, you will need to create a PDF view that extends the Sugarpdf class. To accomplishÂ this, create the file:
Â ./custom/modules/<module>/sugarpdf/sugarpdf.<pdf view>.php
<?php
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
require_once('include/Sugarpdf/Sugarpdf.php');


require_once('include/Sugarpdf/Sugarpdf.php');
class <module>Sugarpdf<pdf view> extends Sugarpdf
{
    /**
     * Override
     */
    function process(){
        $this->preDisplay();
        $this->display();
        $this->buildFileName();
    }
    /**
     * Custom header
     */
    public function Header()
    {
        $this->SetFont(PDF_FONT_NAME_MAIN, 'B', 16);
        $this->MultiCell(0, 0, 'TCPDF Header',0,'C');
        $this->drawLine();
    }
    /**
     * Custom header
     */
    public function Footer()
    {
        $this->SetFont(PDF_FONT_NAME_MAIN, '', 8);


$this->MultiCell(0,0,'TCPDF Footer', 0, 'C');
    }
    /**
     * Predisplay content
     */
    function preDisplay()
    {
        //Adds a predisplay page
        $this->AddPage();
        $this->SetFont(PDF_FONT_NAME_MAIN,'',PDF_FONT_SIZE_MAIN);
        $this->Ln();
        $this->MultiCell(0,0,'Predisplay Content',0,'C');
    }
    /**
     * Main content
     */
    function display()
    {
        //add a display page
        $this->AddPage();
        $this->SetFont(PDF_FONT_NAME_MAIN,'',PDF_FONT_SIZE_MAIN);
        $this->Ln();


$this->Ln();
        $this->MultiCell(0,0,'Display Content',0,'C');
    }
    /**
     * Build filename
     */
    function buildFileName()
    {
        $this->fileName = 'example.pdf';
    }
    /**
     * This method draw an horizontal line with a specific style.
     */
    protected function drawLine()
    {
        $this->SetLineStyle(array('width' => 0.85 / $this->getScaleFactor(), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(220, 220, 220)));
        $this->MultiCell(0, 0, '', 'T', 0, 'C');
    }
}


}
}
This file will contain the markup for the PDF. The main things to note are the Header(), Footer() and display() methods as they contain most of the styling and display logic. The method buildFileName() will generate the document's name when downloaded by the user.
Once in place, navigate to Admin > Repair > Quick Repair and Rebuild. The PDF will now be accessibleÂ byÂ navigating to the following url in your browser:
http://{sugar url}/index.php?module=<module>&action=sugarpdf&sugarpdf=<pdf action>
PDF Settings
This section will outline how to configure the PDF settings. These settings determine the widths, heights, images, pdf metadata, andÂ the UI configurations found in:
Admin > PDF Manager > Edit Report PDF Template
Settings


Admin > PDF Manager > Edit Report PDF Template
Settings
The default PDF settings for TCPDF can be found in ./include/Sugarpdf/sugarpdf_default.php. You can add additional custom settings by creating the following file:
./custom/include/Sugarpdf/sugarpdf_default.php
<?php
$sugarpdf_default["PDF_NEW_SETTING"] = "Value";
You should note that values specified here will be the default values. Once edited, the updated values are stored in the database config table under the category "sugarpdf" and a name matching the setting name.
category: sugarpdf
name: pdf_new_setting
value: Value
Displaying and Editing Settings
A select set of settings can be edited within the Sugar UI by navigating to:
  Admin > PDF Manager > Edit Report PDF Template


Admin > PDF Manager > Edit Report PDF Template
The settings here are managed in the file ./modules/Configurator/metadata/SugarpdfSettingsdefs.php. A brief description of the settings parameters are listed below:
label : This is the display label for the setting.
info_label : Hover info text for the display label.
value : The PDF Setting.
class : Determines which panel the setting resides in. Possible values are 'basic' and 'logo'. 'advanced' is not currently an available value.
type : Determines the settings display widget. Possible values are: 'image', 'text', 'percent', 'multiselect', 'bool', 'password', and 'file'.
Custom settings can be added to this page by creating ./custom/modules/Configurator/metadata/SugarpdfSettingsdefs.php and specifying a new setting index. An example is below:


./custom/modules/Configurator/metadata/SugarpdfSettingsdefs.php
<?php
    //Retrieve setting info from db
    defineFromConfig("PDF_NEW_SETTING", $sugarpdf_default["PDF_NEW_SETTING"]);
    //Add setting display
    $SugarpdfSettings['sugarpdf_pdf_new_setting'] = array(
        "label" => $mod_strings["LBL_PDF_NEW_SETTING_TITLE"],
        "info_label" => $mod_strings["LBL_PDF_NEW_SETTING_INFO"],
        "value" => PDF_NEW_SETTING,
        "class" => "basic",
        "type" => "text",
    );


"type" => "text",
    );
You should note that the $SugarpdfSettings index should following the format sugarpdf_pdf_<setting name>. If your setting does not follow this format, it will not be saved or retrieved from the database correctly.
Once the setting is defined, you will need to define the display text for the UI setting.
./custom/modules/Configurator/language/en_us.lang.php
Once finished, navigate to Admin > Repair > Quick Repair and Rebuild. This will rebuild the language files for your display text.
PDF Fonts
The stock fonts for TCPDF are stored in the directory ./vendor/tcpdf/fonts/. If you would like to add additional fonts to the system, they should be added to the ./custom/vendor/tcpdf/fonts/Â directory.
Font Cache


Font Cache
The font list is built by the font manager with the listFontFiles() or getSelectFontList() methods. The list is then saved in the cache as ./cache/Sugarpdf/cachedFontList.php. This caching process prevents unnecessary parsing of the fonts folder. The font cache is automatically cleared when the delete() or add() methods are used. When you create a module loader package to install fonts you will have to call the clearCachedFile() method in a post_execute and post_uninstall action in the manifest.php to clear the font cache.
  	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


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


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


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.
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


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.


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


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


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_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
flock
fnmatch
fopen
forward_static_call


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


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


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
simplexml_load_string
socket_accept
socket_addrinfo_bind
socket_addrinfo_connect
socket_addrinfo_explain
socket_addrinfo_lookup
socket_bind


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


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_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
sugar_chmod


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_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.


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.
To add more file extensions to the approved list of valid extension types, add the file extensions to the validExt array. The example below adds a .log file extension and .htaccess to the valid extension type list in config_override.php:
$sugar_config['moduleInstaller']['validExt'] = array(
    'log',
    'htaccess'
);
Denylisting Additional Function Calls


'htaccess'
);
Denylisting Additional Function Calls
Note: Denylist modifications are prohibitedÂ for instances on Sugar's cloud service.
To add additional function calls to the denylist, add the function calls to the blackList array. The example below blocks the strlen() and strtolower() functions from being included in the package:
$sugar_config['moduleInstaller']['blackList'] = array(
    'strlen',
    'strtolower'
);
Overriding Denylisted Function Calls
Note: Denylist modifications are prohibitedÂ for instances on Sugar's cloud service.
To override the denylist and allow a specific function to be included in packages, add the function call to the blackListExempt array. The example below removes the restriction for the file_put_contents() function, allowing it to be included in the package:


$sugar_config['moduleInstaller']['blackListExempt'] = array(
    'file_put_contents'
);
Disabling Restricted Copy
To ensure upgrade-safe customizations, System Administrators mustÂ restrict the copy action to prevent modifying the existing Sugar source code files. New files may be added anywhere (to allow new modules to be added), but core Sugar source code files must not be overwritten. This is enabled by default when you enable Package Scan.
Note: Disabling Restricted Copy is prohibited for instances on Sugar's cloud service.
To disable Restricted Copy, use this configuration setting:
$sugar_config['moduleInstaller']['disableRestrictedCopy'] = true;
Module Loader Actions


Module Loader Actions
Module loader actions, defined in ./ModuleInstall/ModuleScanner.php, are identifiers that map to the installation definitions used in the $installdefs of a manifest.
Action
$installdefÂ Actions
Description
install_administration
administration
Installs an administration section into the Admin page
install_connectors
connectors
Installs SugarCloud Connectors
install_copy
copy
InstallsÂ files or directories
install_dashlets
dashlets
Installs dashlets into the Sugar application
install_images
image_dir
Install images into the custom directory
install_languages
language
Installs language files
install_layoutdefs
layoutdefs
InstallsÂ layouts
install_layoutfields
layoutfields
Installs custom fields
install_logichooks
logic_hooks
Installs logic hooks
install_relationships


logic_hooks
Installs logic hooks
install_relationships
relationships
Installs relationships
install_userpage
user_page
InstallsÂ a section to the User record page
install_vardefs
vardefs
InstallsÂ vardefs
post_execute
post_execute
Called after a package is installed
pre_execute
pre_execute
Called before a package is installed
Disabling Module Loader Actions
Certain Module Loader actions may be considered less desirable than others by a System Administrator. A System Administrator may want to allow some Module Loader actions, but disable specific actions that could impact the upgrade-safe integrity of the Sugar instance.
Note: Disabling Module Loader actionsÂ is prohibitedÂ for instances on Sugar's cloud service.


By default, all Module Loader actions are allowed. Enabling Package Scan does not affect the Module Loader actions. To disable specific Module Loader actions, add the action to the disableActions array. The example below restricts the pre_execute and post_execute actions:
$sugar_config['moduleInstaller']['disableActions'] = array(
    'pre_execute',
    'post_execute'
);
Disabling Upgrade Wizard
If you are hosting Sugar and wish to lock down the upgrade wizard, you can set disable_uw_upload to 'true' in the config_override. This is intended for hosting providers to prevent unwanted upgrades.
$sugar_config['disable_uw_upload'] = true;
  	Last modified: 2023-02-03 21:04:03


Module Loader Restriction Alternatives
Overview
This article provides workarounds for commonly used functions that are denylisted by Sugar forÂ Sugar's cloud environment.
Denylisted Functions
$variable()
Variable functions areÂ sometimes used when trying to dynamically call a function. This is commonly used to retrieve a new bean object.
Restricted use:
$module = "Account";
$id = "6468238c-da75-fd9a-406b-50199fe6b5f8";
//creating a new bean
$focus = new $module()
//retrieving a specific record
$focus->retrieve($id);
As of 6.3.0, we have implemented newBean and getBean which can be found in the BeanFactory. Below is the recommended approach to create or fetch a bean:
$module = "Accounts";


$module = "Accounts";
$id = "6468238c-da75-fd9a-406b-50199fe6b5f8";
//creating a new bean
$focus = BeanFactory::newBean($module);
//or creating a new bean and retrieving a specific record
$focus = BeanFactory::getBean($module, $id);
array_filter()
The array_filter filters elements of an array using a callback function. ItÂ is restricted from use on Sugar's cloud service due to its ability to call otherÂ restricted functions.
Restricted use:
/**
 * Returns whether the input integer is odd
 * @param $var
 * @return int
 */
function odd($var) {
    return($var & 1);
}
$myArray = array(
    "a"=>1,
    "b"=>2,


"a"=>1,
    "b"=>2,
    "c"=>3,
    "d"=>4,
    "e"=>5
);
$filteredArray = array_filter($myArray, "odd");
An alternative to using array_filterÂ is to use a foreach loop.
$filteredArray = array();
$myArray = array(
    "a"=>1,
    "b"=>2,
    "c"=>3,
    "d"=>4,
    "e"=>5
);
foreach ($myArray as $key => $value) {
    // check whether the input integer is odd
    if($value & 1) {
        $filteredArray[$key] = $value;
    }
}
copy()


}
}
copy()
The copyÂ method is sometimes used by developers when duplicating files in the uploads directory.
Restricted use:
$result = copy($oldFile, $newFile);
Â An alternative to using copyÂ is theÂ duplicate_fileÂ method found in theÂ UploadFileÂ class.
require_once 'include/upload_file.php';
$uploadFile = new UploadFile();
$result = $uploadFile->duplicate_file($oldFileId, $newFileId);
file_exists()
The file_exists method is used by developers to determine if a file exists.
Restricted use:
if(file_exists($file_path)) {
    require_once($file);
}


require_once($file);
}
An alternative to using file_exists is theÂ fileExistsÂ method found in the SugarAutoLoaderÂ class.
$file = 'include/utils.php';
if (SugarAutoloader::fileExists($file)) {
    require_once($file);
}
file_get_contents()
The file_get_contents method is used to retrieve the contents of a file.
Restricted use:
$file_contents = file_get_contents('file.txt');
An alternative to using file_get_contents and sugar_file_get_contents is theÂ get_file_contentsÂ method found in the UploadFile class.
require_once('include/upload_file.php');
$uploadFile = new UploadFile();
//get the file location


$uploadFile = new UploadFile();
//get the file location
$uploadFile->temp_file_location = UploadFile::get_upload_path($file_id);
$file_contents = $uploadFile->get_file_contents();
fwrite()
The fwrite method is a function used to write content to a file. As there isn't currently a direct alternative for this function, you may find one of the following a good solution to what you are trying to achieve.
Adding/Removing Logic Hooks


Adding/Removing Logic Hooks
When working with logic hooks, it is very common for a developer to need to modifyÂ ./custom/modules/<module>/logic_hooks.php. When creating module loadable packages, developers will sometimes useÂ fwrite to modify this file upon installation to include their additional hooks. As of Sugar 6.3,Â Logic Hook ExtensionsÂ were implemented to allow a developer to append custom hooks.Â If you would prefer to edit the logic_hooks.php file, you will need toÂ use theÂ check_logic_hook_fileÂ method as described below:
//Adding a logic hook
require_once("include/utils.php");
$my_hook = Array(
    999,
    'Example Logic Hook',
    'custom/modules/<module>/my_hook.php',


'custom/modules/<module>/my_hook.php',
    'my_hook_class',
    'my_hook_function'
);
check_logic_hook_file("Accounts", "before_save", $my_hook);
Removing a logic hook can be done by using remove_logic_hook:
//Removing a logic hook
require_once("include/utils.php");
$my_hook = Array(
    999,
    'Example Logic Hook',
    'custom/modules/<module>/my_hook.php',
    'my_hook_class',
    'my_hook_function'
);
remove_logic_hook("Accounts", "before_save", $my_hook);
getimagesize()
The getimagesizeÂ method isÂ used to retrieve information about an image file.


The getimagesizeÂ method isÂ used to retrieve information about an image file.
Restricted use:
$img_size = getimagesize($path);
If you are looking to verify an image is .png or .jpeg, you can use theÂ verify_uploaded_imageÂ method:
require_once('include/utils.php');
if (verify_uploaded_image($path)) {
    //logic
}
If you are looking to get the mime type of an image, you can use theÂ get_file_mime_typeÂ method:
$mime_type = get_file_mime_type($path);
  	Last modified: 2023-02-03 21:04:03


Sugar Exchange Package Guidelines
Overview
The SugarÂ® platform is open and flexible. Developers can customize any feature or integrate any system with Sugar using a Sugar Module Loadable Package. This flexibility requires guidelines so that SugarExchange customers can rest assuredÂ that all package offerings adhere to consistent quality standards and will not interfere with existing customizations or prevent software upgrades.
This guide outlines the minimum standards we expect from any Sugar Developer writing code for the Sugar platform. From the development of Sugar packages to security, user interface, encapsulation, and performance considerations, SugarCRM takes the safety and integrity of the Sugar application and its community very seriously. Compliance with these guidelines is a requirement for any package installed into Sugar's cloud service. Failure to follow these guidelines is grounds for having your package removed from Sugar's cloud service and de-listed from SugarExchange.


SugarCRM reserves the right to change these guidelines at any time. Please send any questions or feedback on these guidelines to developers@sugarcrm.com.
Best Practices
These best practice guidelines have been curatedÂ based on years of collective experience working with Sugar Packages that get used by Sugar customers every day.
Use a consistent coding style


Use a consistent coding style
For all PHP code, the style standard that SugarCRM uses is PSR-2. For JavaScript code, we use the applicable PSR-2 conventions as well. For JavaScript code, we emphasize readability which means we make use of utilities like Underscore.js and avoid nested callbacks. All functions, methods, classes in our code are required to have PHPDoc and JSDoc. While not all the code in the Sugar code base currently complies with these standards, we do enforce it as the standard on new code. Using a consistent code style increases the readability and maintainability of application code for those that come after you.
Invest in unit testing during development


Invest in unit testing during development
For all JavaScript and PHP code, we strongly recommend the creation of unit tests. For PHP, we use PHPUnit and have developed a framework (to be shared) for testing Sugar server-side code using this framework. For JavaScript code, we use Jasmine and have also developed a framework (to be shared) there to bootstrap Sidecar metadata so that Jasmine tests can run without dependency on a Sugar server.
We recommend running unit tests frequently during the development process. We suggest developers run tests before each commit and as part of an automated continuous integration process. Running tests often means you catch failures sooner which makes them easier and cheaper to fix.
Use Sugar REST APIs


Use Sugar REST APIs
The easiest way to integrate with a Sugar instance is not to install anything into Sugar at all. For Sugar 7, we have a full client REST API that is used to drive our web interface, our mobile client, and our plug-ins. If you can do it from our user interface, you can use our REST API separately to do it as well. If the REST API doesn't do everything you need it to do, it is very easily extensible. You can easily write code that adds your custom API endpoints in a minimally invasive way.
Use Module Builder when possible


Use Module Builder when possible
Many integrations can be accomplished with the help of Module Builder and the Sugar REST API. Module Builder allows you toÂ quicklyÂ design new modules for Sugar that match concepts that you want to add to a Sugar instance. These custom modules can then be installed and populated via the REST API, making it a powerful integration mechanism that doesn't require writing a line of Sugar code. Using custom modules will prevent conflicts with other customizations, as well. For more information, please refer to the Module Builder documentation.
Use Extension framework and Dashlets for Sugar code customizations
The Extension framework is the way to add server-side changes to a Sugar instance in a loosely coupled way. Dashlets are the best way to add new, custom user interface components to a Sugar instance that gives users maximum flexibility in how they use your app. These mechanisms also avoid conflicts with other customizations since Extensions are additive and do not replace core files.
Security Guidelines


Security Guidelines
Protecting and controlling access to CRM data is of paramount importance. It is important that Sugar Packages are good stewards of CRM data and access control.
Use TLS/SSL for web services calls
Just as we don't recommend running Sugar in production without TLS/SSL, all web-services calls that are initiated from a Sugar Package should also use SSL. The concern is the exposure of user credentials, OAuth/session tokens, or sensitive CRM data via plaintext transmission that would otherwise be handledÂ securely.
Do not hardcode sensitive information


Do not hardcode sensitive information
You also should not hardcode any credentials, API keys, tokens, etc, within a Sugar Package. Sugar Packages and Sugar application code is never encrypted so there is always a risk that an attacker could discover these things and abuse them. Usernames and passwords, OAuth tokens, and similar credentials for accessing 3rd party systems should be stored in the database (for example, on the config table). The Sugar platform also provides encryption utilities that allowÂ information to be stored in an encrypted form. These settings could then be changeable by the Administrator via the Administration panel or some other end-user input.
User Interface Guidelines
Sugar packages can be used to add new user interface components or front-end customizations to Sugar. It is important to consider the impact that these changes have on the user experience and the look and feel of the Sugar application.
Use the Sugar 7 Styleguide


Use the Sugar 7 Styleguide
In Sugar 7, we have doubled down on our emphasis on creating the best possible user experience. While other applications may use different usage patterns than the ones used in Sugar 7, it is important to think about how new functionality or integrations that you build in Sugar 7 fits within the overall Sugar 7 user experience. Users do not tolerate an inconsistent experience within a given tool - it makes it harder to learn to use, which lowers adoption of Sugar as well as your application.
We want to make it easier for you to build applications within Sugar that use a consistent theme and user experience patterns, so we have included a styleguide for the Sugar application. You can find a link to the styleguideÂ from the Sugar Administration page. There you can find all the information you need to leverage Sugar 7's styling including our CSS framework.
Don't use incompatible UI frameworks or external CSS libraries


Don't use incompatible UI frameworks or external CSS libraries
Mixing outside user interface frameworks into the Sugar application via a Sugar Package can easily break many different parts of the application. Please only include as much CSS as you need and make sure that it is properly formed so that it doesn't affect other parts of the Sugar application. At the very least, using different frameworks or themes within your application will create a disjointed experience for the end user. While your package may be installed into Sugar, the user experience will not be seamless.
Encapsulation Guidelines
An important aspect of the quality of a Sugar Package is how well encapsulated and loosely coupled it is. A well encapsulated and loosely coupled package will encounter the fewest issues during upgrades, fewer breakages due to core code changes or due to interactions with other installed packages, as well minimizing bugs or problems that end users encounter.
Use Extensions framework and Custom Modules as much as possible


Use Extensions framework and Custom Modules as much as possible
A well-encapsulated package prefers the use of Custom Modules over customizing and repurposing existing Sugar Modules. A loosely coupled package uses Extensions framework for customizing and connecting with the core Sugar application. Only override the behavior of core Sugar application files as a last resort.
Avoid customizations to core Sugar application files


Avoid customizations to core Sugar application files
Developers are strongly discouraged from overriding core Sugar Modules or Sugar framework code. In many cases, a cleaner approach for accomplishing the same goal exists. For example, using a logic hook to extend the behavior of a SugarBean instead of overriding the SugarBean itself. Every core customization is a barrier to successful upgrades that creates recurring development costs over time. This is exacerbated in heavily customized Sugar instances as other customizations may exist on these files. Anytime there is a conflict then manual intervention by a Sugar Developer is required which is not only inconvenient but costly for everyone involved. If you do make core Sugar customizations then keeping track of such changes is very important to get in front of potential conflicts with other packages and upgrades.
Use Package Scanner to ensure your Sugar Package is ready for SugarCloud


Use Package Scanner to ensure your Sugar Package is ready for SugarCloud
Sugar Packages should be designed with Sugar's cloud service in mind, as many Sugar customers choose this hosting option over hosting on-site or through a Sugar partner. Code that gets loaded into Sugar's cloud service must pass the Package Scanner utility and must not adversely impact the SugarCRM infrastructure. This stipulation is outlined in theÂ SugarCloud Policy Guide. Package Scanner can be enabled on any Sugar instance via the Sugar Administration panel which allows this to be tested easily. You should also educate yourself in some alternatives toÂ denylisted functions.
Performance Guidelines
Sugar is primarily a database application however with the introduction of Sugar 7, more and more business logic is executed within the user's web browser. It is best to avoid pre-optimization and use tools to properly identify the root causes of performance issues that users could encounter.


Sugar 7 has instrumentation built into it for New Relic APM,Â which can monitor browser and server performance simultaneously, as well as XHprof for Sugar PHP profiling. Slow query logging can also be enabled via the Sugar Administration panel under System Settings. For more information, refer to the System documentation. The Sugar Engineering team typically uses Chrome DevTools for JavaScript profiling.
Index for large frequently used queries
The most common performance bottleneck for Sugar is the database. Using slow query logging makes it possible to identify bottlenecks and correct them. One way to address query bottlenecks is to extend vardefs to add indices during package install to improve the performance of those queries.
Add scheduled jobs to prune large database tables


Add scheduled jobs to prune large database tables
If your Package adds database tables that can tend to grow very large over time, it is a best practice to include scheduled jobs in your package that can be used to prune the size of this database over time. For Sugar, these background tasks can be created and managed using the Job Queue framework. At the very least, you'll want to create a Custom Job that Sugar Administrators can then run as needed. This will allow the package to remain in tip-top shape for your users over time. Especially if they are running on Sugar's cloud service because direct access to the underlying SQL database to do manual tuning and cleanup is not permitted.
Ensure your application does not block user interface during long running processes


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


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';


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(


'exact_matches' => array(
        '13.0.0',
    ),
    //or
    'regex_matches' => array(
        '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',


'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


'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
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


)
);
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,
  'published_date' => '04/07/2023 14:15:12',
  'type' => 'module',
  'acceptable_sugar_versions' =>
  array(


'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


'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


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
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',


'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(


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


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((


Example:
$installdefs['custom_fields'] = array((
    array((
        'name' => 'text_c',
        'label' => 'LBL_TEXT_C',
        'type' => 'varchar',
        '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:


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


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
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


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',


'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 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<br>';
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',
);


'<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<br>';
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'] =
'<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',


'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((


'required' => true,
                ),
            3 =>
                array((
                    'name' => 'my_module_accountsmy_module_ida',
                    '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((


),
                ),
            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
Â 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Â 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


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