SugarCRM SupportProduct GuidesSugar DeveloperSugar Developer Guide 11.0IntroductionComposer

Composer

Overview

As of Sugar® 7.5, the Composer dependency management integration has been made publicly available for  Sugar developers. Because Composer is the de facto standard for managing PHP dependencies, this enhancement to the Sugar platform will make customizations based on external libraries more intuitive.

Prerequisites

  • The Composer package must be available on your system if you wish to make any changes to the dependencies. Please refer to the Getting Started guide on Composer's website for more details on installation and usage.
  • Composer is a command-line tool, so you must have access to the command-line interface on the system.
  • You must have the proper file-system permissions to alter files in the Sugar instance directory.

Note: Before customizing the Composer configuration, be sure to read the documentation on this page in its entirety and feel confident in your knowledge of Composer. We strongly recommend reviewing the Composer website's documentation for more information.

Restrictions

Customizations to the composer.json file are restricted by a certain set of rules to ensure continuity in our product.

Note: The list of restrictions may change at any time, opening up certain configuration keys or making them more restrictive. These changes will be communicated through release notes, and this page will be updated to reflect the latest state.

Root Element Restriction Level Explanation
name Prohibited These elements are owned by SugarCRM and should never be modified.
description Prohibited
type Prohibited
license Prohibited
homepage Prohibited
support Prohibited
autoload Prohibited These elements are owned by SugarCRM and should not be modified. They are under consideration for relaxed restriction levels in the future.
minimum-stability Prohibited
config Prohibited
require Restricted
  • You may add new packages without restriction.
  • You may add new repositories as long as they do not conflict with SugarCRM-owned packages.
  • You may remove packages if they are not owned by SugarCRM.
  • You may remove repositories if they are not owned by SugarCRM.
repositories Restricted 
elements not listed here No Restrictions  All other root elements may be added/changed at the developer's discretion.

Please contact Sugar Support if the current restrictions block you from using the Composer integration in Sugar. Also, review the Frequently Asked Questions section of this page for additional information.

Finding Packages

Packages that are available to Composer are published through Packagist. This is the primary place to look for third-party libraries. Composer is not restricted to packages published on Packagist, so you may refer to public or private repositories that are not found on Packagist. For more information, please refer to the Repositories section of Composer's documentation.

Adding a New Package

To add a new package, you must modify the "require" element and then update the dependencies. To learn more about Composer's "require" element, please refer to the Composer documentation. For information on version constraints, please refer to Composer's package versions documentation.

Follow these steps to add a new package:

  1. Back up the files ./composer.json and ./composer.lock.
  2. Modify the "require" section for ./composer.json. For example, to add the monolog/monolog package to ./composer.json, add the package name and the required version constraint in the "require" section, as shown here:
    {
       "name": "sugarcrm/sugarcrm",
       ...
       "require": {
           "monolog/monolog": "~1.11",
           "ruflin/elastica": "v1.2.1.0",
           "php": ">=5.3.0"
       },
       "require-dev": {
           "phpunit/phpunit": "4.1.4"
       },
       ...
    }
  3. Next, update the dependencies. The easiest way to do this is by running composer update --no-dev from the directory where composer.json lives. This is the recommended method for production systems.
    • Composer will automatically determine which packages need to be fetched and updated.
    • All dependencies are stored in the ./vendor/ folder.
    • The ./composer.lock file is updated with the installed versions and repository information.
    • The --no-dev switch skips the packages in the require-dev section because those packages are only needed for development.
    • Using the example in step 2, you will see the Monolog package has a dependency of its own: the psr/log package. Composer automatically installed this dependency.
  4. Clear the cache used by Sugar's autoloader to be sure the newly installed dependencies are available. Manually remove these two files:
    • ./cache/file_map.php
    • ./cache/class_map.php

    Alternatively, when developing new code in Sugar, you could enable Developer Mode in Sugar. When enabled, the autoloader will automatically refresh itself.

Removing Packages

To remove a package, follow the steps in Adding a New Package, but this time, remove the package name and the required version constraint from the "require" section in step 2.

Note: Keep in mind the restrictions on the "require" section. Only remove packages that you control. Never remove packages that are owned by SugarCRM.

Adding and Removing Repositories

To configure additional repositories in ./composer.json, you must first remove  { "packagist.org": false } from the "repositories" section. You can then add or remove repository references and update composer as needed. Here is an example:

{
   "name" : "sugarcrm/sugarcrm",
   ...
   "repositories" : [
       {
           "type" : "git",
           "url" : "https://github.com/yours/Monolog"
       }
       {
           "type" : "git",
           "url" : "https://github.com/sugarcrm/Elastica"
       }
   ]
}

Autoloader

Sugar has a custom autoloader that is PSR-0 and PSR-4 compliant and integrates with Composer's mapping definitions.

Integrations

When updating the Composer configuration, Composer will generate different mappings based on the settings of every dependency:

  • Class map
  • PSR-0 map
  • PSR-4 map
  • Include paths (deprecated)

SugarCRM's autoloader uses those generated maps directly to initialize itself and to figure out how to load different classes.

Internals

To prevent endless file stats, Sugar's autoloader maintains a full list of all files at its disposal. This list is only generated once and is maintained in ./cache/file_map.php. Most of the Sugar codebase uses the autoloader to determine whether a file is available rather than performing expensive file_exists calls.

A second file, stored in ./cache/class_map.php , maintains a flat list of class-name-to-file mappings. When you make any changes to the file system, clear both files before testing new code.

Optimization

When updating dependencies through Composer, it is advised that the production system uses the optimize flag: composer update --optimize-autoloader --no-dev".  By doing so, Composer will scan all files in the packages it manages and create a full list of PSR-0 and PSR-4 class name to file mappings, instead of performing this lookup on the fly by the autoloader itself on runtime.

Developer Mode

When Developer Mode is enabled, the autoloader will bypass any persistent setting from both file_map or class_map. Adding new files or updating dependencies will be directly picked up by the autoloader without performing a Quick Repair and Rebuild.

Handling Upgrades

Once you take control of the Composer configuration, there may be complications during upgrades. The upgrade logic will determine whether or not the Composer configuration has any customizations and whether a custom config is compatible for the upgrade.

When a custom configuration is not compatible (missing or conflicting dependencies), the upgrade process will generate a proposal. The administrator who is responsible for reviewing the proposal will need to make the necessary changes to the Composer configuration before running the upgrade again.

Upgrade Failure Notification

When an incompatible Composer configuration is detected, a notification will appear depending on which type of upgrader you are using.

Web Upgrader

Customizing_Composer_Web_Upgrader

CLI Upgrader

***************         Step "healthcheck" OK - 0 seconds
***************         Step "unpack" OK - 8 seconds
ERROR: A custom composer configuration has been detected which is incompatible with the upgrade process. Consult the SugarCRM Administration Guide for more details on how to resolve this issue. Detailed logs are available in UpgradeWizard.log.
***************         Step "pre" FAILED! - 5 seconds

The detailed logging is available in the upgrade wizard log file as reported in the above notifications. We will use the content to determine the course of action to solve the upgrade issues. When using the Web Upgrader, the UpgradeWizard.log file is located in the root directory of your SugarCRM instance. For the CLI Upgrader, the full path will be reported where you can find it.

Example Failure

Search for CheckComposerConfig in the upgrade log. Sections that are highlighted in red indicate detected problems.

Starting script CheckComposerConfig
Using sugarcrm/composer.json as composer.json source
Using sugarcrm/composer.lock as composer.lock source
Using cache/upgrades/temp/SugarPro-Upgrade-7.5.0.x-to-7.6.0.0/composer.json as composer.json target
Hash 3a5b0634383693d27c7c6054a69839fc does not match release hash for 7.5.0.0
Custom composer configuration detected
Found valid package ruflin/elastica with version constraint v1.2.1.0
Package onelogin/php-saml with version constraint 2.1.0.1 is missing
Skipping platform package php
Found valid repository https://github.com/sugarcrm/Elastica with type git
Repository https://github.com/sugarcrm/php-saml of type git is missing
Missing configuration key 'minimum-stability'
Generating proposal file cache/upgrades/temp/SugarPro-Upgrade-7.5.0.x-to-7.6.0.0/composer.json.proposal
Saving file cache/upgrades/temp/SugarPro-Upgrade-7.5.0.x-to-7.6.0.0/composer.json.proposal to disk
ERROR: A custom composer configuration has been detected which is incompatible with the upgrade process.
Finished script CheckComposerConfig

Process

The following actions are required:

  1. Backup the current composer.json and composer.lock files.
  2. Alter composer.json to match the requirements.
  3. Run "composer update -o --no-dev" to deploy the new dependencies.
  4. Clear cache (./cache/file_map.php and ./cache/class_map.php).
  5. Log in and test the instance.
  6. Perform upgrade again.

What's Wrong?

From the above log output we can learn that:

  • A package onelogin/php-saml is missing
  • A repository definition for php-saml is missing
  • The configuration key minimum-stability is missing

These definitions are owned by SugarCRM. In case one of these settings were already present before they were required by SugarCRM, a similar notice will be thrown stating any incompatible issues.

The Proposal

The upgrade logic provides us with a proposal on how to update the ./composer.json file to fix the missing dependencies in our custom configuration. The location of this proposal file can be seen above in the highlighted blue section.

Note: Do not blindly copy the proposal file over your existing ./composer.json file without verifying and understanding what the issue is. There can be an incompatibility between a dependency of one of your own explicitly defined packages and requirements from the upgrade process.

Resolving the Issues

As described in the chapter above we can make the change in our ./composer.json to satisfy all requirements. Based on the above example we make the following changes:

{
"name": "sugarcrm/sugarcrm",
...
},
   "require": {
       "psr/log": "1.0",
       "ruflin/elastica": "v1.2.1.0",
       "php": ">=5.3.0",
       "onelogin/php-saml": "2.1.0.1"
   },
   "require-dev": {
       "phpunit/phpunit": "4.1.4"
   },
   "repositories": [
       {
           "type": "git",
           "url": "https://github.com/sugarcrm/Elastica"
       },
       {
           "url": "https://github.com/sugarcrm/php-saml",
           "type": "git"
       }
   ],
   "minimum-stability": "stable"
}

From here,  follow the procedure to run composer update, clear the autoloader cache, and test drive the Sugar instance. When approved, you can try to upgrade again.

Retry Upgrade

After resolving all conflicts, the upgrade process will successfully resolve. The log output will look like this on success:

Starting script CheckComposerConfig
Using sugarcrm/composer.json as composer.json source
Using sugarcrm/composer.lock as composer.lock source
Using cache/upgrades/temp/SugarPro-Upgrade-7.5.0.x-to-7.6.0.0/composer.json as composer.json target
Hash 79626e71bad09bf1c09585c89a28875e does not match release hash for 7.5.0.0
Custom composer configuration detected
Found valid package ruflin/elastica with version constraint v1.2.1.0
Found valid package onelogin/php-saml with version constraint 2.1.0.1
Skipping platform package php
Found valid repository https://github.com/sugarcrm/Elastica with type git
Found valid repository https://github.com/sugarcrm/php-saml with type git
Custom composer configuration is valid for upgrade
Finished script CheckComposerConfig

Starting script 8_ComposerConfig
Restoring custom composer file 'composer.json.valid' to 'composer.json'
Restoring custom composer file 'composer.lock.valid' to 'composer.lock'
Finished script 8_ComposerConfig

Stock Composer Configuration

As a reference, the output in the log file when no custom Composer configuration is detected. The upgrader will automatically continue in this case without throwing any notices as the upgrade archive contains the necessary code base and an updated composer.json and composer.lock file.

Starting script CheckComposerConfig
Using sugarcrm/composer.json as composer.json source
Using sugarcrm/composer.lock as composer.lock source
Using cache/upgrades/temp/SugarPro-Upgrade-7.5.0.x-to-7.6.0.0/composer.json as composer.json target
Skipping merge, stock composer settings detected
Finished script CheckComposerConfig

Frequently Asked Questions

Is the composer package required to install a Sugar instance?

No. The Sugar installer ships with all required code bundled together. The installer process does not execute any Composer commands. The installer will deploy both composer.json and composer.lock in the web root directory as a reference of all dependencies which are controlled by Composer.

Why does Sugar ship ./composer.json and ./composer.lock if the installer doesn't rely on them?

Composer is used internally during development to manage Sugar's dependencies on third-party libraries and packages. The Composer files are shipped during development to manage Sugar's dependencies on third-party libraries and packages. The composer files are shipped with the product to give our customers the ability to expand from them.

Is the Composer package required to upgrade a Sugar instance?

No. The Sugar upgrader ships, just like the installer, with all required code bundled together. The upgrade process will validate the present Composer configuration and verify if it is compatible with the upgrade. In the case of a custom configuration, the upgrade process will report any issues which need to be resolved by the system administrator before the upgrade can proceed.

Why are there no wildcards in the version constraints? Doesn't composer.lock keep track of exact version numbers?

The lock file is designed to lock the dependencies to a specific version, but to protect our customers from unintentionally pulling in newer versions of dependencies owned by SugarCRM, we have chosen to use explicit version numbers in the composer.json file too.

May I change the version number of a package?

You cannot change version numbers for packages added by Sugar. Sugar will always configure exact version numbers for all of its dependencies. Changing these version numbers will result in an unsupported platform. The version constraints of packages not owned by Sugar may be modified at the developer's discretion.

Can I use Composer's autoloader?

We strongly recommend against using Composer's autoloader. The Sugar autoloader is fully compatible with the PSR-0 and PSR-4 autoloading recommendations from PHP-FIG, which makes the registration of an additional autoloader like the one from Composer redundant. Sugar's autoloader consumes the different mappings which are generated by Composer directly.

How can I optimize the autoloader?

Sugar ships with an optimized class map out of the box, which is pre-generated through Composer. This class map contains all different class to file mappings known to the dependencies managed by Composer. When customizing the Composer configuration, it is sufficient to run composer update --optimize-autoloader which will refresh the class map. SugarCRM's autoloader takes full advantage of this optimization.

Can I load customizations in Sugar through Composer?

Although not yet available out of the box, we are investigating this as a future capability.

Can I move the vendor directory out of the web root?

You cannot currently move the vendor directory, but we are investigating this as a future capability.

The Composer integration in Sugar is not flexible enough for me. What can I do?

We continuously strive to make our platform better and to facilitate both end users and developers. Our goal is to deliver a state-of-the-art environment. Do not hesitate to reach out to Sugar Support if we have overlooked your use case or if there too many constraints in the current implementation to make this a useful feature.

Last modified: 2021-02-17 02:44:13