Categories


Archives


Recent Posts


Categories


Sugar CRM Hello World for PHP Developers

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

This entry is part 1 of 3 in the series SugarCRM for PHP MVC Developers. Later posts include SugarCRM Models, and Sugar CRM Model Auditing.

Business programming frameworks are, as a rule, awful. Whether you call it “agile”, “scrum”, or “my chaotic job where no one seems to be in charge until a crisis hits and there’s always a new crisis”, the story of business software development over the past 10 years has been doing more with less, attacking the immediate problems now, and letting the long term problems sort themselves out via human intervention — even if that intervention needs to happen at 1:45 AM on a Saturday.

While this has been a smart move for quarter-to-quarter business metrics, it leads to chaotic system code, which is maddening for a professional programmer who needs to work with these sorts of systems. By “professional programmer” I mean me, and by “these sorts of systems”, I specifically mean SugarCRM.

SugarCRM is a “Customer Relationship Management” system built with PHP. If Magento is a system where the developers took their abstractions a little overboard, then SugarCRM is the system where business took “ignore the developer’s concerns” a little overboard. The result is a chaotic code-base with competing engineering visions that’s difficult for a newcomer to jump into.

Despite that, under the cruft and chaos, there is an MVC system in play, and understanding that system is your first step towards mastering SugarCRM programming. With business relying more and more on the sort of business intelligence you can extract from a CRM, SugarCRM seems like a good tool to have in your belt.

Over the next few months I’m going to be exploring SugarCRM’s core code from the point of view of a PHP MVC developer. These tutorials won’t be for everyone, but if you’re the sort of developer who needs to understand where all the pipes are going, then this series is for you.

The code samples in this article were tested against SugarCRM CE 6.5.10, but the concepts should apply to future and past versions of the platform.

Development Environment Pre-Flight

Before we get started, a quick note about your development environment.

SugarCRM was originally written in a PHP 4 world, and much of the code still uses PHP 4 idioms. Running SugarCRM with a modern version of PHP will result in a number of warnings being generated in your error logs, as well as in the browser if display_errors is set to true.

This is a perfect example of how a good business decision results in questionable engineering. Rather than refactor this code to use modern standards, the SugarCRM team handles the problem by setting strict system requirements and recommending users set display_errors to Off.

I know this is a bad idea, you know it’s a bad idea, but in certain business cultures it’s a hard sell to take on a refactoring project when there’s no direct line to a revenue stream.

For now I’m leaving my PHP error reporting cranked as high as it goes and keeping display_errors off. The ambitious among you might try creating a custom PHP error handler to filter these out, but that’s another topic for another day.

Also, the following code example were testing against SugarCRM CE 6.5.10, but the concepts should apply to all recent versions of the platform.

SugarCRM Modules

Step one to understanding Sugar CRM is to understand its module system. Module, of course, is software development’s second favorite overloaded word (right after “Object Oriented”). A SugarCRM module is not a Bertrand Meyer “lets have all the code play nice together” sort of thing. Instead, it’s the tight coupling of

The SugarCRM development culture seems to shy away from understanding how the three items are implemented — the system ships with a module builder application that auto generates the PHP code a developer needs, and the core system code is built around supporting the module builder.

We’re going to be taking the slow boat on this one. After enough articles we’ll eventually reach SugarCRM’s idea of a “module”, but for now think of SugarCRM as you would any other PHP MVC system.

SugarCRM Routing

The first shock an MVC developer faces when working with SugarCRM is there’s no URL based routing. SugarCRM requests do all go through a single index.php file, but it is query string parameters that drive which controller/action method combination is used.

For example, access the following URL

http://sugar-crm.dev/index.php?module=Accounts

and you land on the default accounts page. That is, we’ve added a single query string to the URL named module, and set its value to Accounts. In other words, the default page for the Accounts module.

This means if we want to create a module named Helloworld, we access its default landing page at the following URL

http://sugar-crm.dev/index.php?module=Helloworld

If you load the above URL in your SugarCRM system you’ll get the following error

Error: Module Helloworld does not exist.

That’s because (duh!) we haven’t added any code for our module to the system yet.

To do so, simply create a folder with your module’s name in the modules folder

$ mkdir modules/Helloworld

The modules folder is where all SugarCRM modules live. Create the above folder and reload you page. You should see something like this

So, we have our user interface chrome for the application, but now there’s a misleading error message

You do not have access to this area. Contact your site administrator to obtain access.

Although you wouldn’t think it, this is SugarCRM telling us it can’t find a view to display.

View First

SugarCRM is what I like to call a “view first” system. In most MVC systems when you’re creating a new entry point for your application, first you create a controller, then you add an action method, and then the action method determines which views to render and/or kicks off a more complicated rendering process.

With a view first system there’s a default controller being used, and all the end-user-programmer needs to do is create a view file. To setup the a view for the default module landing page we created above, add the following folder to your system

mkdir modules/Helloworld/views

and then create the following file with the following content

#File: modules/Helloworld/views/view.list.php
<?php
class HelloworldViewList extends SugarView{
    public function display()
    {
        echo '<h1>Hello World</h1>';
    }
}    

Reload your page, and viola! The error message is gone and there’s your Hello World content

Before we flip out about HTML in PHP code, let’s breakdown what we just did. By default, every SugarCRM view has a type. The default view type is list. (This probably doesn’t seem very intuitive, but trust us, we’ll get there)

The view file’s naming convention is

view.[TYPE].php

which means view.list.php in our case. The view class is named

[Modulename]View[Type]

with the view type being “first letter uppercase”. Again, in our case that’s HelloworldViewList. All view classes ultimately inherit from the SugarView class.

Wait, what? View class? Where’s the template file!? In its simplest form, a view in Sugar CRM is a class with a method named display. The display method is responsible for creating the HTML to be returned to the browser. It’s also responsible for echoing or print this output — the SugarCRM framework will use output buffering to put off output until the appropriate time. You can see this in action by changing your view to the following.

#File: modules/Helloworld/views/view.list.php
<?php
class HelloworldViewList extends SugarView{
    public function display()
    {
        echo '<h1>Hello World</h1>';
        ob_end_clean();
        exit(__METHOD__);
    }
}        

Here we’ve echoed our Hello World message, and then immediately called the ob_end_clean function, which stops output buffering and discards the current buffer. Then, we immediately exit. If you’re not familiar with output buffering, you might expect the page to still display its chrome. However, if you refresh

you’ll see only the output from the exit. That’s because SugarCRM was holding all the output in the buffer, and normally wouldn’t release it until later in the bootstrap process. You’ll want to keep this default level of buffering in mind if you’re using output buffering yourself, plan to set any custom PHP headers, or do anything else where the timing of the output is important.

I know you’re probably cringing at echoing out raw HTML — and we share your distaste. This was only a pedagogical tactic. In practice, SugarCRM views will either include other PHP files, or pass off responsibility for output to another class.

For example, if you look at the view class which renders the home page

#File: modules/Home/views/view.list.php
class HomeViewList extends ViewList{
    //...
    function display(){
        global $mod_strings, $export_module, $current_language, $theme, $current_user, $dashletData, $sugar_flavor;
         $this->processMaxPostErrors();
        include('modules/Home/index.php');
    }
    //...
}     

you can see it’s main rendering logic is in the included PHP file modules/Home/index.php.

If you look at the view class which renders the User’s edit page

#File: modules/Users/views/view.edit.php
class UsersViewEdit extends ViewEdit {
    function display(){
        //...
        echo $this->ev->display($this->showTitle);
    }
}

you’ll see it ultimately calls the display method of another object stored in the $this->ev property.

Also, all view objects have a property named ss

$this->ss;

This ss property contains a reference to a Sugar_Smarty class. If you’re familiar with the Smarty PHP template system, you can use this object to render your page via Smarty templates.

The point isn’t to bless one method as canonical over the others. Rather, as a developer, you need to be aware there’s a wide variety in how SugarCRM might render its HTML, but that the view object’s display method is the one common entry point for all view rendering.

Creating a Controller

Even though SugarCRM is view first, there’s still a controller behind the scenes. If your module doesn’t have a controller, the system will assume you want to use the SugarController class for your controller object

#File: include/MVC/Controller/SugarController.php
<?php
class SugarController{    
    //...
}

This controller contains a number of default action methods and setup code, including the setup of the initial view type of list. If these defaults aren’t good enough, or you just feel naked without your own controller, creating one for your module is relatively simple. Just create a file at the following location with the following content

#File: modules/Helloworld/controller.php
<?php
class HelloworldController extends SugarController
{

}    

Each module in SugarCRM has a single controller file. There’s no file naming convention to be aware of — just put it in a file named controller.php at the root of the module. The controller’s class name format is

[Modulename]Controller

which in our case means HelloworldController, and all controllers extend the base SugarController.

If we reload the page with the above in place, we won’t see any change in behavior. That’s because we’ve defined an empty controller with no action methods — our module is effectively using the same base controller functionality it was before. Let’s change that!

The default action method name for a controller is listview, which means to define the listview action method, we’d change our controller to match the following

#File: modules/Helloworld/controller.php
<?php
class HelloworldController extends SugarController
{
    public function action_listview()
    {                
        var_dump(__METHOD__);
    }    
}    

An action method is a public method with the name format

action_[action name]

In our case, that’s action_listview. As you can see, we’ve added a single var_dump to the method. If you reload the page, you’ll see that this var_dump is called before any other output is sent to the browser, which outputs the magic __METHOD__ constant at the top of the page

Setting the View Type

Let’s take a look at that screen shot again

Sharp eyes may have noticed something. Specifically, by adding a controller method, we seem to have lost our view!

That’s because the default SugarController was setting this for us in the default action_listview method.

#File: include/MVC/Controller/SugarController.php
//...
protected function action_listview(){
    //...
    $this->view = 'list';
}
//...

Specifically, the line $this->view = 'list'; is what set the view type to list.

We can fix this one of two ways. The first is to be a responsible object oriented programmer and call/return our parent method

#File: modules/Helloworld/controller.php
<?php
class HelloworldController extends SugarController
{
    public function action_listview()
    {                
        return parent::action_listview();
    }    
} 

Reload with the above in place, any our view will be back.

The second, and more interesting, fix would be to set the view type ourselves.

#File: modules/Helloworld/controller.php
<?php
class HelloworldController extends SugarController
{
    public function action_listview()
    {                
        $this->view = 'list';
    }    
} 

Now we’re starting to see a familiar MVC pattern emerge. The reason this is more interesting than just calling the parent method is we’re no longer limited to creating a view with the default name of list. We could now name our view anything we wanted

$this->view = 'hello';
$this->view = 'foobazbar';

or use conditional logic to set different views based on the system state. So long as our view files and classes are named named correctly

#File: modules/Helloworld/views/view.hello.php
<?php
class HelloworldViewHello extends SugarView{
    public function display()
    {
        echo '<h1>Some other View</h1>';
    }
}

we can name our views anything we like.

Setting View Variables

We now know how to create a view in SugarCRM. We also know how to create a controller. Next up is all important question

How does the controller tell the view about things

Both SugarCRM view and controller objects have a special array property named $this->view_object_map. This array is where you’ll set variables in your controller action for your view. For example, if you change your listview method to match the following

#File: modules/Helloworld/controller.php
public function action_listview()
{                
    $this->view = 'list';
    $this->view_object_map['message'] = 'Hello World at ' . date('Y-m-d H:i:s',time());
}    

and then change your view to reference the same key in the view_object_map

#File: modules/Helloworld/views/view.list.php
<?php
class HelloworldViewList extends SugarView{
    public function display()
    {
        echo '<h1>'.$this->view_object_map['message'].'</h1>';
    }
}

and then reload your page, you’ll see a Hello World message with the date and time included.

By setting the messages key in the controller, it’s been made available to the view.

Multiple Action Methods

While each module in SugarCRM has one, and only one, controller, each controller may have multiple action methods. Let’s say we wanted to create an action method named goodbye. First, we’d add the following method to our controller

#File: modules/Helloworld/controller.php
<?php
class HelloworldController extends SugarController
{
    //...
    public function action_goodbye()
    {
        $this->view = 'list';
        $this->view_object_map['message'] = 'Goodbye World!';                
    }    
    //...        
}   

Notice we’re reusing the list view, but we’re setting a different message.

Next, to access the entry point, we’d add an action query string to our URL

http://sugar-crm.dev/index.php?module=Helloworld&action=goodbye

Remember, there’s no “smart url” routing in SugarCRM, it’s parameters all the way down.

Reload the page, and there’s our new message

Earlier we said listview was the default controller action. Let’s test that out by being explicit with the URL. Access your SugarCRM installation with the following URL

http://sugar-crm.dev/index.php?module=Helloworld&action=listview

As you can see, this page has the same content as an action-less URL

http://sugar-crm.dev/index.php?module=Helloworld

It’s not exactly the sexiest of routing systems, but using the action paramaters means you can create an unlimited number of unique pages in your SugarCRM module/system.

Advanced Tip: Want to really confuse yourself? Try accessing your module with an action named index

http://sugar-crm.dev/index.php?module=Helloworld&action=index

You’ll see — the listview page?

That’s because we told you a little fib — the actual default action for a controller is index. However, SugarCRM’s bootstrap process includes an action aliasing system that automatically turns the index action into listview.

This isn’t something you need to worry about right now, but it’s worth knowing if you’re going to venture into the depths of SugarCRM’s application dispatch process, and is an example of how the core system code has been shaped by the needs of the specific application. The listview action is the default because most module’s default landing page is a list of all of the module’s objects.

Wrap Up

We now know how to

That’s the V and the C of MVC out of the way. Next time we’ll cover SugarCRM’s data Model, or as they’re known is SugarCRM speak — “beans”. Until then, happy coding, and corrections are more than welcome in the comments.

Originally published March 5, 2013
Series NavigationSugarCRM Models >>

Copyright © Alana Storm 1975 – 2023 All Rights Reserved

Originally Posted: 5th March 2013

email hidden; JavaScript is required