Code completion in your Sugar development environment

Code Completion

I have finally gotten around to improving my development environment and I chose to start with code completion. I use phpStorm but I think everything here would apply to any editor out there. When Sugar went to the BeanFactory to instantiate a bean, the code completion stopped working. If you define your bean class in the DocBlock or in an inline phpDocumentor tag, some of the functionality returns but not all. Custom fields and relationships are never available as they are never added to the public variable list on the class. To demonstrate what I am talking about this is how a DocBlock can handle code completion:
Code Completion Example

You see that the 'name' field is not available until after I tell the editor that $bean represents the Call class.  But, even then the custom fields that I have added to the Calls module are not available - only the stock ones. Of course you cannot define the $bean of every function as some function accept data from several modules.  It might be a Call one time and a Meeting another.  In these cases you can define the $bean as a SugarBean instead of a Call or Meeting and get some functionality out of it.

An inline tag works in a similar way and is used to define the class of a BeanFactory call.
Inline Tag Example
Again, the fields are not shown until after I tell the editor that $quoteBean represents the IN_Orders class.  After that, all the stock fields and relationships (and functions I guess) are available to you.

So, that's step one. I have to get better about documenting my functions and using inline tags to decorate my BeanFactory calls. Not hard I guess, but that is only getting me half my code completion options. I need my custom fields on that list. The code completion options are taken from the classes and the variables in them. So somehow we have to get the custom fields that were added to the modules onto the classes...

I went through about 10 different methods before I settled on 2. One is effortless but means you have to update stock files. The other is more coding work but uses custom files.  I use the first option as updating my stock files in this way is not a big deal.  My .gitignore file keeps them from getting added to my commits. So, the changes only exist on my development files and the utility I use to add them has a clean up option. We will get to that later but rest assured, unless you are actually editing your live files directly (don't do that) you will be fine with option one.

The Editor Helper Tool
The Editor Helper Tool

This tool is available for download from this blog post and is licensed under the MIT license. It allows you to update your class files all at once and has an option to remove everything it added if that becomes necessary. When you run it (It adds itself to the Admin menu) in either the 'Normal' or 'Custom' modes the first thing it does is remove any code it added on the previous run. Then it looks at every module for custom fields and adds them to the class files. So, if you do a git clone or a version upgrade, you can just go to the admin menu and run this tool. It will set everything up again no matter what.

So, if you run it in the 'Normal' mode, the Accounts class file (modules/Accounts/Accounts.php) will end up looking like this:

Accounts Class File

Now the class file has all my custom fields inserted into it and code completion will work for all fields - stock and custom. This is safe for me to do on my system as it only exists on my development box. My .gitignore will prevent me from ever creating a commit that would add these changes to production code as they are not needed to actually run Sugar and are only there to make the editor work better. Whenever I add or remove custom fields I can just re-run this tool and it will update the classes for me. In this mode I wouldn't have to change my coding style at all. I can just do things like this to make sure both $bean and $masterAccount are seen as Accounts in the code.

     /**
      * @param Account $bean
      * @param string $events
      * @param array $arguments
      */

     private function beforeSavePartner($bean, $events, $arguments): void
        {
           if (!empty($bean->parent_id)) {
              /** @var Account $masterAccount */
              $masterAccount = BeanFactory::getBean('Accounts', $bean->parent_id, IGNORE_TEAMS);
              if (!empty($masterAccount->dealerID) {
                  $bean->masterid_c = $masterAccount->dealerid_c;
              } else {
                  $bean->masterid_c = '';
                  $bean->parent_id = null;
              }
           } else {
              $bean->masterid_c = '';
           }
}

If I ran it in 'Custom' mode I would get a file created in 'custom/modules/Accounts/customAccounts.php' that looks like this:

Custom Accounts Class

In this scenario I would have to alter my .gitignore to keep these files from being committed to production code.  Then I would have to alter my code like in the following example. You should notice that in the DocBlock I had to define $bean as being either an Account or a customAccount.  Otherwise, PHP would complain.  Since $masterAccount is all mine, I can just define it as  customAccount.

     /**
      * @param Account|customAccount $bean
      * @param string $events
      * @param array $arguments
      */

     private function beforeSavePartner($bean, $events, $arguments): void
        {
           if (!empty($bean->parent_id)) {
              /** @var customAccount $masterAccount */
              $masterAccount = BeanFactory::getBean('Accounts', $bean->parent_id, IGNORE_TEAMS);
              if (!empty($masterAccount->dealerID) {
                  $bean->masterid_c = $masterAccount->dealerid_c;
              } else {
                  $bean->masterid_c = '';
                  $bean->parent_id = null;
              }
           } else {
              $bean->masterid_c = '';
           }
}


PHPStorm Live Templates

I know I said at the top that all of this would be compatible with all editors but I just wanted to share this one PHPStorm thing as I use it in relation to this all the time. I created a 'Live Template' for BeanFactory calls so I would not have to type the BeanFactory call AND the inline tag every time. I just type BF<tab> and then fill in the form like this:

Live Template

This can be created in your PHPStorm like this. Just open preferences and search for 'live' and you will see Live Templates, select that and then add a template to the PHP section.

Live Template Setup 1

Then you have to set up the variables for the template. This is done by clicking on the 'Edit variables' button and filling out the form there.

Live Templates Setup 2

Is any of this necessary to customize Sugar? No, not really. But, it has made coding for Sugar much easier for me. I hope it can do the same for you. 

_EditorHelper115.zip