Archive for the ‘SugarCon’ Category

Quick ListView customization

Monday, March 23rd, 2009

As the next installment in the Sugar Tips and Tricks series from the Sugar engineering team, I will perform a quick and simple ListView customization which leverages the Carousel widget from the Yahoo UI (YUI) library. This customization completely changes the look and feel of the Contact ListView from a “rows and columns” view of your search results to a Yahoo UI Carousel view. The YUI library is included in SugarCRM and provides a ton of UI features beyond what we use in the core application.

Carousel Widget on Contacts Listview

I will only need to customize two files:

  1. view.list.php in the Contacts module
  2. ListViewContacts.tpl – a new smarty file which I have added to be used within the view.list.php file

Create a new file view.list.php file in custom/modules/Contacts/views. The beginning of the file including the constructor should look like:

require_once('include/MVC/View/views/view.list.php');
class ContactsViewList extends ViewList {

function ContactsViewList(){
parent::ViewList();
}

You can see that I am extending from the ViewList class as defined in ‘include/MVC/View/views/view.list.php’ so that I can take advantage of the methods which are already implemented and only override what I need. Since I only want to change how the ListView looks, I will do most of that in Smarty so I need to only override the method in ViewList which deals with rendering the template.

listViewProcess()

should do the trick.
Here is the full listing for the ContactsViewList class below:

require_once('include/MVC/View/views/view.list.php');
class ContactsViewList extends ViewList {

function ContactsViewList(){
parent::ViewList();
}
function listViewProcess(){
$this->processSearchForm();
$this->searchColumns = $this->searchColumns;
if(!$this->headers)
return;
if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){
$this->lv->setup($this->seed, 'custom/modules/Contacts/tpls/ListViewContacts.tpl', $this->where, $this->params);
$savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']);
echo get_form_header($GLOBALS['mod_strings']['LBL_LIST_FORM_TITLE'] . $savedSearchName, '', false);
echo $this->lv->display();
}
}
}

Now that we have provided a way to get my own custom smarty template loaded on the Contacts ListView, I will create my Smarty file in custom/modules/Contacts/tpls/ListViewContacts.tpl. My goal here will be to remove most of the table rendering logic defined in ListViewGeneric.tpl and replace it with my own rendering logic to display the carousel.


link rel="stylesheet" type="text/css" href='{sugar_getjspath file='include/javascript/yui/build/fonts/fonts.css'}'>
<link type="text/css" rel="stylesheet" href='{sugar_getjspath file='include/javascript/yui/build/carousel/assets/skins/sam/carousel.css'}'>
<script src='{sugar_getjspath file='include/javascript/yui/build/utilities/utilities.js'}'></script>
<script src='{sugar_getjspath file='include/javascript/yui/build/carousel/carousel-beta-min.js'}'></script>
{literal}

<style type="text/css">
.yui-carousel-element li {
height: 158px;
text-align: left;
}

#container {
font-size: 13px;
margin: 0 auto;
}

#container a {
text-decoration: none;
}

#container .intro {
display: inline;
margin: 0px 14px 0px 4px;
width: 202px;
}

#container .item {
display: inline;
margin: 0 22px 0 12px;
overflow: hidden;
padding-right: 80px;
width: 106px;
}

#container .item .authimg {
bottom: 2px;
margin-left: 61px;
position: absolute;
z-index: 1;
}

#container .item h3 {
line-height: 85%;
margin-top: 4px;
}

#container .item h3 a {
font: 77% Arial, sans-serif;
position: relative;
text-transform: uppercase;
z-index: 2;
}

#container .item h3 a:link {
color:#35a235;
}

#container .item h4 {
margin-top:5px;
}

#container .item h4 a {
font: 100% Georgia, Times, serif;
position: relative;
z-index:2;
}

#container .item h4 a:link {
color:#00639b;
}

#container .item cite {
color: #888;
display: block;
font-size: 77%;
line-height: normal;
margin-bottom: 30px;
}

#container .item p.all {
bottom: 25px;
position: absolute;
z-index: 2;
}

#container .item p.all a {
font-weight: bold;
font-size: 85%;
}
</style>
{/literal}
<div  class="yui-skin-sam">
<div id="container">
<ol id="carousel">
{foreach name=rowIteration from=$data key=id item=rowData}
<li class="item">
<a href='index.php?module={$pageData.bean.moduleDir}&amp;action=detailview&amp;record={$rowData.ID}'>
{foreach from=$displayColumns key=col item=params}
{if $params.link &amp;!$params.customCode}

<{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href="#" onMouseOver="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$offset}, this)"  onFocus="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$offset}, this)">{$rowData.$col}</{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN}>

{elseif $params.customCode}
{sugar_evalcolumn_old var=$params.customCode rowData=$rowData}
{elseif $params.currency_format}
{sugar_currency_format
var=$rowData.$col
round=$params.currency_format.round
decimals=$params.currency_format.decimals
symbol=$params.currency_format.symbol
convert=$params.currency_format.convert
currency_symbol=$params.currency_format.currency_symbol
}
{elseif $params.type == 'bool'}
<input type='checkbox' disabled=disabled class='checkbox'
{if !empty($rowData[$col])}
checked=checked
{/if}
/>
{elseif $params.type == 'multienum'}
{if !empty($rowData.$col)}
{counter name="oCount" assign="oCount" start=0}
{assign var="vals" value='^,^'|explode:$rowData.$col}
{foreach from=$vals item=item}
{counter name="oCount"}
{sugar_translate label=$params.options select=$item}{if $oCount !=  count($vals)},{/if}
{/foreach}
{/if}
{else}
{$rowData.$col}
{/if}
{/foreach}
</a>
</li>
{/foreach}
</ol>
</div>
</div>
{literal}
<script>
(function () {
var carousel;

YAHOO.util.Event.onDOMReady(function (ev) {
var carousel    = new YAHOO.widget.Carousel("container", {
animation: { speed: 0.5 }
});

carousel.render(); // get ready for rendering the widget
carousel.show();   // display the widget
});
})();
</script>
{/literal}

You can see from the above I have stripped out the table HTML and now the meat of the display is done here:


<div id="container">
<ol id="carousel">
{foreach name=rowIteration from=$data key=id item=rowData}
<li class="item">

We simply loop through each of our rows and output it into the <li> tags and then once this has rendered the JavaScript:


(function () {
var carousel;

YAHOO.util.Event.onDOMReady(function (ev) {
var carousel    = new YAHOO.widget.Carousel("container", {
animation: { speed: 0.5 }
});

carousel.render(); // get ready for rendering the widget
carousel.show();   // display the widget
});
})();

will render the widget.

New vCal Updates Setting in 5.2.0c

Monday, March 23rd, 2009

In the Sugar 5.2.0c patch that was released last week, we included a new setting in the System Settings page that allows administrators to set the vCal time period.  Administrators can specify the number of months in advance of the current date that Free/Busy information for calls and meetings is published for each user. 

The new field in the System Settings page is titled “vCal Updates Time Period:”, and the default value is two months. Administrators can now enter the preferred number of months, from one to 12, as well as turn off Free/Busy publishing altogether by entering “0″.

The reason for this setting is to allow administrators to control VCal efficiency on saves of calls and meetings.  When calls and meetings are saved, queries are run to fetch vCal data for the assigned user.  Prior to 5.2.0c, the time period of information that the query was sent to retrieve was set to two months in advance of the current date, and entire VCal data was re-constructed for the next two months for each user/attendee.  The two month time period could not be changed, and vCal could not be disabled through the application UI, even if vCal was not being used.

Using vCal and retrieving data for a longer time period can have an impact on application performance when users have a lot of data to retrieve, or can unncessarily slow down the time to save a record if vCal is not being used and the queries are still run.

$tip = new TipsAndTricks(2, ‘New SugarFields In Studio’);

Monday, March 16th, 2009

In the last tip we showed how to add a new SugarField to the application. This time we’ll show you how to add that SugarField to Studio so administrators can add it as a custom field to layouts. It should be noted that we will be patching some core files. These same patches will be available in the next release of SugarCRM. As a side note empty() is getting rendered as emptyempty in this post. We are looking into the issue, but just make a mental note that if you see !emptyempty it should read just !empty.

Step 1:Patching Dynamic Fields

The first file we need to patch is modules/DynamicFields/FieldCases.php. This file is essentially a switch statement for Module Builder and Studio to retrieve the appropriate Sugar Field class. We’ll be changing to allow for supporting custom SugarFields.

Change the code inside the function get_widget from

default:
    $local_temp = new TemplateText(); break;

to

default:
	$file = false;
	//CHECK IF THERE IS A CUSTOM TEMPLATE
	if(file_exists('custom/modules/DynamicFields/templates/Fields/Template'. $type . '.php')){
		$file  =	'custom/modules/DynamicFields/templates/Fields/Template'. $type . '.php';
	//CHECK IF THERE IS A STANDARD TEMPLATE
	}else if(file_exists('modules/DynamicFields/templates/Fields/Template'. $type . '.php')){
		$file  =	'modules/DynamicFields/templates/Fields/Template'. $type . '.php';
	}
	//IF THERE WAS A CUSTOM OR STANDARD TEMPLATE USE IT
	if(!empty($file)){
		require_once($file);
		$class  = 'Template' . $type ;
		$customClass = 'Custom' . $class;
		//CHECK FOR A CUSTOM CLASS
		if(class_exists($customClass)){
			$local_temp = new $customClass();
		}else{
			//DEFAULT TO THE STANDARD CLASS NAME Template{$type}
			$local_temp = new $class();
		}
		break;
	}else{
		$local_temp = new TemplateText(); break;
	}

Step 2:Creating a YouTube Template Field

Now our code can load custom templates, so let’s create our custom YouTube template. We want it to behave like a normal text field, but when it’s creating it’s vardef it should have the type set to YouTube. To do this we create a new template in custom/modules/DynamicFields/templates/Fields/TemplateYouTube.php and we’ll create a TemplateYouTube class that extends TemplateField. Our code should look something like this

<?php
require_once('modules/DynamicFields/templates/Fields/TemplateField.php');
class TemplateYouTube extends TemplateField{
	//SET TYPE TO YouTube
	var $type='YouTube';

	//THIS FUNCTION GENERATES THE VARDEF
	function get_field_def(){
		//CALL ON PARENT FUNCTION TO RENDER VARDEF
		$def = parent::get_field_def();

		//IF WE HAVE A DEFAULT VALUE SET IT
		$def['default'] = !empty( $this->default) ? $this->default : $this->default_value;

		//LET'S SET THE MAX LENGTH
		$def['len'] = 50;

		//STILL HAVE THE DB THINK OF THE FIELD AS A varchar
		$def['dbType'] = 'varchar';

		return $def;
	}
}

Step 3:Adding YouTube to the custom field Drop Down

Now that we have a template class for our YouTube field we need it to actually show up in Studio and Module Builder. To do this we simply create a file custom/modules/ModuleBuilder/language/en_us.lang.php and put the following code in it

<?php
	$mod_strings['fieldTypes']['YouTube'] = 'YouTube';

You will need to delete the cached language file for Module Builder and Studio which is located in cache/modules/ModuleBuilder/langague/en_us.lang.php
Once you have done this you should be able to go to studio and add a custom field of type YouTube. Now your administrators can take advantage of all the new SugarFields you create.

$tip = new TipsAndTricks(1, ‘Creating a YouTube Sugar Field’);

Monday, March 16th, 2009

We just finished a great SugarCon event in San Francisco, and the engineering team really did a great job conveying a lot of tips and tricks to the community. We wanted to continue this momentum, and after discussing the idea with a few developers we have decided to release a new tip/trick every week up to next year’s SugarCon.  That’s 52 tips and tricks a year for those of you doing the math. As some of you may note SugarCon was actually 2 weeks ago, so we are already a week behind. Don’t fret, we’ll be releasing 2 tips and tricks this week.

Creating A YouTube Field

Sugar ships with several types of fields out-of-the-box including but not limited to – text, iframe, phone, link, enum …, but every now and then you want to have a new field type. In this article, we shall describe how to create a field for displaying YouTube© videos.

To begin with, let’s review the code that drives field behavior.  If you look into the base SugarField directory (include/SugarFields/Fields/Base), you will see the following files

  1. DetailView.tpl
  2. EditView.tpl
  3. SearchForm.tpl
  4. SugarFieldBase.php

The SugarFieldBase class defined in SugarFieldBase.php handles the processing of the SugarField and loads the appropriate Smarty template (.tpl) file for rendering the field.

Now if you open up any of the .tpl files you will notice that we use the double curly braces (e.g. {{ and }} ) instead of standard Smarty template syntax which uses single curly braces (e.g. { and } ). This is because the Smarty code these templates will create is based upon resolving EditView.tpl or DetailView.tpl with the metadata defined in editviewdefs.php and detailviewdefs.php respectively. For example the base DetailView.tpl code looks like the following:


{{sugarvar key='value'}}
{{if !empty($displayParams.enableConnectors)}}
{{sugarvar_connector view='DetailView'}}
{{/if}}

However, the runtime code that this would generate for the Accounts module (cache/modules/Accounts/DetailView.tpl) looks like:


{$fields.employees.value}

If we wanted to get the value of a field that is different from the one currently being rendered we could do the following:


{{sugarvar memberName='name' key='value'}}

And this would generate the following smarty code


{$fields.name.value}

The reason for the double curly brace ( {{ ) versus the single curly brace ( { ) is that this approach allows us to put a certain level of logic in the code so you could do something like changing the color of the text based on the value of a field:

{if {{sugarvar memberName='employees' key='value' stringFormat='false'}}>1000}

<span style='color:green'>

{else}

<span style='color:purple'>

{/if}

{{sugarvar memberName='employees' key='value'}}</span>

This is rendered at runtime as:


{if $fields.employees.value  > 1000}

<span style='color:green'>

{else}

<span style='color:purple'>

{/if}

{$fields.employees.value}</span>

One of the nice things about SugarFields is that they can inherit from parent fields – this is true for both the rendering class and the templates. Even better yet if there is no custom code that needs to be added to our rendering class, the base class can handle the rendering for us and we don’t even need to subclass it. For our YouTube example we will just need to create a custom DetailView.tpl

Step 1: Create the Sugar Field Directory

Create the directory:  include/SugarFields/Fields/YouTube

We could actually use the YouTube field in the code right now, but it would render using the base SugarField which is just a text input box.

Step 2: Create DetailView.tpl

Create the File:  include/SugarFields/Fields/YouTube/DetailView.tpl

Step 3: Edit DetailView.tpl

I went over to YouTube and grabbed the embed code that is displayed next to one of my favorite videos. We will be expecting users to enter in a YouTube video id in the edit view and based on that id we will render the appropriate video.

<object width="425" height="344">
<param name="movie"
value="http://www.youtube.com/v/{{sugarvar key='value'}}">
</param>
<param name="allowFullScreen" value="true">
</param>
<param name="allowscriptaccess" value="always">
</param>
<embed
src="http://www.youtube.com/v/{{sugarvar key='value'}}"
type="application/x-shockwave-flash"
allowscriptaccess="always" allowfullscreen="true" width="425"
height="344">
</embed>
</object>

Step 4: Using the YouTube Field

There are two ways that the YouTube field may be used, first you may specify a specifc field in the detailviewdefs.php of a module with type set to ‘YouTube’ for example in Accounts you can change website to be a YouTube video field:

array('name'=>'website', 'type'=>'YouTube')

The other way is in the vardefs where you need to set two parameters of a fields vardefs, type and dbType.

'website' =>array (
'name' => 'website',
'vname' => 'LBL_WEBSITE',
'type'=>'YouTube',
'dbType' =>'varchar'
),

Step 5: Don’t Render YouTube Fields That Don’t Have IDs


{if !empty({{sugarvar key='value' stringFormat=false}})}
<object width="425" height="344">
<param name="movie"
value="http://www.youtube.com/v/{{sugarvar key='value'}}">
</param>
<param name="allowFullScreen" value="true">
</param>
<param name="allowscriptaccess" value="always">
</param>
<embed
src="http://www.youtube.com/v/{{sugarvar key='value'}}"
type="application/x-shockwave-flash"
allowscriptaccess="always" allowfullscreen="true" width="425"
height="344">
</embed>
</object>

{else}

No YouTube Video Available

{/if}

Now you have a fully functioning “Custom SugarField”.   Stay tuned for this week’s 2nd tip on how to add your new SugarField to Studio.

Note: As of the writing of this article, Sugar 5.2.0a is the current patch version generally available.  In the upcoming Sugar 5.2.0c patch, you will be able to place the SugarField files in the custom directory (custom/include/SugarFields/Fields/) in order to override the default behavior in an upgrade-safe manner. However, it is okay to place these changes in the include/SugarFields/Fields/ for this exercise as long as your field names don’t conflict with default field names.

Build It, and They Will Use It!

Wednesday, February 25th, 2009

No doubt one of the biggest takeaways from SugarCon is how the focus we’ve placed on the Sugar platform over the last several 5.x releases has resulted in a highly flexible platform that is very easy for developers to extend in many different ways.  Throughout the SugarCon case studies, product feature demonstrations and technical “how-to” discussions, the message was that our developer community, partners and customers are all taking advantage of Sugar’s platform to build new plug-ins and extensions, to add new features and to customize Sugar to fit their business processes and goals.

I attended the SugarCON session on “Five Game-Changing Extensions”, presented by SugarCRM’s Reem Bazzari, and witnessed several eye-catching and popular extensions in action.  Among these are the following extensions are currently available on SugarExchange and SugarForge.

Contact Capture is a nifty tool for very easily capturing and importing lead and contact information from any file into Sugar.  Klipfolio for SugarCRM provides quick and convenient access to relevant information within Sugar within dashboards on the desktop.  SalesView by InsideView is business search application that brings insight gained from subscription-based and user-generated sources, such as Hoover’s, D&B, Reuters, Zoominfo, Jigsaw and LinkedIn, into an easy-to-use panel directly within the DetailView of Sugar records. Mobile Edge for SugarCRM allows sales representatives to access and update pipelines and contacts anytime and anywhere within seconds right on their Blackberry smartphones.

I also attended the session on “Five Extensions Yet to be Built That Users Would Love”, presented by Clint Oram, SugarCRM Co-Founder and VP of Product Management.  During his talk, Clint brought to attention the following categories that come up time and time again for highly-anticipated features and extensions that promise to have an impact on user productivity and adoption of Sugar.

1) Web Content Management

Integrations with:

* Blog software: Wordpress
* Forums software: vBulletin
* Wiki software: MediaWiki

2) Finance Systems

Integrations with:

* Magento
* Mas 90
* SQL-Ledger

3) Telephony

4) Productivity Tools

Enhancements to:

* Sugar Calendar
* Sugar Feeds

Integrations with:

* Apple Mail and iCal
* Entourage

Address book and alerts


5) Connectors to Web Meeting applications

Got what it takes to build these extensions?  Or got any other great ideas?  Share them with us.

With the upcoming Web Services improvements, new Themes framework and other platform enhancements that will be included in Sugar 5.5, there’s no excuse to not get out there and start building!

Sugar 5.2 Dev Guide posted, Sugar 5.5 forums now live

Thursday, January 22nd, 2009

If you have already noticed Colline Lee’s post about writing cloud connectors we have posted an updated version of the developer guide for the 5.2 release.

There is a lot of activity around here as SugarCon is just over a week away.  On Februrary 2-4 customers, partners, and community members will gather in San Francisco to soak up a lot of great content we have put together around all things Sugar.

A big piece of SugarCon will be sessions by members of the Sugar Engineering team who will be covering a range of topics around the up and coming Sugar 5.5 release as well as what we are planning for Sugar 6 later at the end of the year.

In preperation for SugarCon we have launched some new forums around Sugar 5.5 so that we have a place to post content early and solicit feeback and questions from the community members.

With the 5.5 release we are finishing up a few platform updates that begun with the release of Sugar 5 and the new MVC framework.  Items such as updating the web services and theme frameworks, adding REST support, as well as a new addition to Studio to edit wireless layouts.

If you are heading to SugarCon we look forward to seeing you there.  For the rest of you, head on over to the forums for 5.5.  We will be adding content during the event all the way up to the release.

Integrate with any Web 2.0 content using My Portal Dashlet

Thursday, January 8th, 2009

A feature of SugarCRM 5.2 that I’ve been playing with a lot is the new My Portal Dashlet. What it allows you to do is embed any website into your Home or Dashboard page by simply providing the URL to the website. While there is a lot of web content that really isn’t suitable for being contained within a window this small, there is quite a bit out there that works great for this. Let’s take a look at a few examples.

Google Talk

Google Talk is a very popular IM client built upon the Jabber protocol. One lesser known feature is that Google provides a gadget for Talk that is designed to be embedded into any web page. This works perfectly with the My Portal Dashlet in SugarCRM 5.2; simply add a new My Portal Dashlet with the URL as http://talkgadget.google.com/talkgadget/popout and the title as Google Talk.

Google Talk emedded in SugarCRM 5.2

Mobile Versions of Web Sites

With the proliferation of the mobile web, many web sites have developed mobile versions of their site optimized for mobile phones and PDAs. These websites are often accessible via a normal web browser as well, so embedding them into our SugarCRM Home or Dashboard page is very simple. Below is an example of adding the mobile version of the Lifehacker website; simply enter the URL as http://m.lifehacker.com/ and the title as Lifehacker.

Lifehacker.com in SugarCRM 5.2

RSS Feeds

Just about every content site has some sort of RSS or Atom feed available, which are designed to work with many of the feed readers available such as Google Reader or Bloglines. One feature of newer browsers such as Firefox 2 and 3, Safari, and IE 7, is the ability to render these feeds directly in the browser as well. We can use this built in ability to have any RSS feed available in the My Portal Dashlet. The below image is an example of integrating the Slashdot RSS feed using the Safari web browser; we simply need to add the Dashlet with the URL http://rss.slashdot.org/Slashdot/slashdot and the title Slashdot.

Slashdot in SugarCRM 5.2

This is really just the tip of the iceberg for possibilities here. Feel free to post below in the comments ways you have used the My Portal dashlet.

SugarCon ‘09 – Save the Date

Thursday, October 23rd, 2008

If you are on the SugarCRM mailing list, you received an email this week to save the date for SugarCon ‘09.  The next Sugarcon will be on Monday, February 2nd through Wednesday, February 4th at the Palace Hotel in San Francisco, CA.

Registration will open soon. In the meantime, we suggest you:

.

I visited the Hotel Palace today with the SugarCon planning team.  Wow!  This is a fantastic hotel right in the heart of downtown San Francisco, just minutes from all the top attractions.  I was particularly impressed with the history of the hotel.  For instance when it was built in 1875, it was the largest hotel in the United States.

On top of the stellar location, the Sugar Team is also pulling together a fabulous conference agenda and some really fun activities for the evenings.  Stay tuned for details in the months to come.

Improving Performance for the End-User

Tuesday, October 7th, 2008

While PHP accelerators deliver better server-side performance and scalability, we can also do other things to speed up the end-user experience. HTTP compression is a common technique for improving performance across the network between the server and the client.  Sugar Labs measured the client-side performance of the SugarCRM application both with and without HTTP compression using Yahoo’s slick YSlow plug-in for Firebug on the FireFox browser. We sampled the SugarCRM application under a couple of different scenarios.

What are the benefits of HTTP Compression?

HTTP compression will compress data that is sent between the server and a user’s browser. In most cases it takes just a few lines to enable it on a Web server, and you can compress HTML, JavaScript and CSS. On average you will see the amount of data transferred between a Web server and a user’s browser decrease in size between 3x to 10x.

Depending on the latency between the server and browser, HTTP compression can have a dramatic effect on the performance of round trips.  The greater the latency, the better the impact.  That means implementing HTTP compression across a LAN connection normally doesn’t help and can often negatively impact performance as the time to compress/un-compress on a LAN outweighs the value of fewer network packets.  HTTP compression works best when there are many network hops between the server and the browser such as when your users connect to their Sugar application over a broadband connection.

A common compression utility used by Web servers and browsers is Gzip.  All browsers that Sugar supports also support accepting data that has been compressed using Gzip.  The Sugar Wiki details how to configure Gzip compression for Apache for the best results with SugarCRM.

Here is a brief sampling of the data collected:

This chart shows the amount of data being transferred the very first time a user views a page with an empty browser cache. Each page was tested independently and the browser cache was cleared between page views. This is a worst case scenario. In a real world scenario, many pages would share common JavaScript and CSS libraries that would be cached between round trips. It does however show the amount of savings per page view once you turn on compression.

Overall the average data size without cache headers and without compression came out to 925 Kb from 58 HTTP requests per page. The 58 requests included loading the page’s HTML and the referenced CSS, JavaScript and images. With compression enabled, the average page size reduces to 270 Kb.  Once the CSS, images, and JavaScript are cached in the browser, the majority of data being passed around is just the actual HTML. The following chart reflects the benefits of compression on the HTML payload.

After the initial page hit for each action, the average page size reduced to 101 Kb per page without compression.  Once you enable compression, that number is reduced to 14 Kb per page, but it still makes 58 HTTP requests to the server. Even though the files are cached by the browser, the browser still makes a call to the server asking if the file has changed. That is why the number of requests per page is still the same. The server will only send back data that has changed, but there is still the overhead of making all those HTTP requests.

If you enable cache headers in your web server, the number of HTTP requests made reduces significantly.  On average, the browser will only make 1 request per page view with cache headers enabled.  You can set the cache for as long as you would like. I would recommend about a week. Note that if your users are connecting over HTTPS, the browser will only cache an object for a given session. As soon as a user logs out, the browser cache will clear by default.  Firefox does allow you to change this browser behavior for HTTPS connections by setting the browser.cache.disk_cache_ssl value to true by typing in “about:config” into your Firefox browser and navigating to this setting.

If you want to calculate the overall amount of data being transferred from the server to the client, the formula would be as follows:

for a single user who views z pages of which k are distinct actions

No Compression:

Total Data Transferred = 925 * k + n * (z – k ) * 101

With Compression :

Total Data Transferred =  270 * k + n * (z -k) * 14

So for 1 user viewing 40 pages of which five pages are distinct actions

No Compression:   925 * 5 + 100 * (40 – 5) * 101 = 8,160 Kb per user

With Compression:  270 * 5+ 100 * (40 – 5) * 14 = 1,840 Kb per user

Now assuming that each user views a new page every 30 seconds (i.e. a 30 second “think” time) we can calculate the bandwidth needed

40 page views * 30 seconds/page view = 1,200 seconds

bandwidth = Total Data Transferred/ Seconds

8,160 K/1200 s = 6.80 Kbps without compression per user

1,840 K/1200 s = 1.53 Kbps with compression per user

Now to get the bandwidth for n users, we simply multiply by n

so for 100 users it would be

6.8Kbps * 100  = 680 Kbps without compression for 100 users

1.53Kbps * 100 = 153 Kbps with compression for 100 users

Doesn’t the browser automatically cache files without cache headers?

The browser will try to cache files, but it will still send a request to the server for each file that it loads from cache that does not have a cache header associated to it.  This is to check if the browser should update the file or not. So there is still a slight request load on the server for each file.  Cache headers prevent this. So while you will see the browser caching, it is still beneficial to send cache headers down with XML, JavaScript, images, CSS, TXT, and SWF files.

Does compression work with everything?

For the most part compression works well, but I would recommend not using it for SOAP since there are several SOAP clients out there that do not handle Gzip compressed data very well. Also you may want to disable it for downloads since often times you will be downloading data that has already been compressed which won’t see any benefit from being Gziped again.  Also note the discussion above on the value of HTTP compression when the server and the browser are on the same LAN.

Were you there?

Wednesday, February 20th, 2008

It’s all great to talk about how wonderful the community is, but seeing the community actually meet in person is where the real fun is.

Did you make it to SugarCon two weeks ago? What a blast! The congratulatory emails have been rolling in from community members around the world who made the pilgrimage to Silicon Valley for SugarCon 08. Everybody enjoyed the mix of learning, sharing and partying. Kudos to John and the marketing team for pulling off a fantastic event.

I personally enjoyed the key note sessions quite a bit. We had Daniel Lyons, aka Fake Steve Jobs, kick off the event with the first key note. His irreverant and insightful commentary on open source and enterprise computing was a fun mix of hilarious and uncomfortable (thanks to Zack Urlocker for posting videos of Daniel’s talk and for NOT posting video 5).

Jonathan Schwartz, CEO of Sun Microsystems, gave a fantastic talk on the future of enterprise computing and why he bought MySQL for $1B. That guy gets open source!

Paul Greenberg, godfather of CRM and author of CRM at the Speed of Light, also gave a great keynote about the future of CRM. He just posted his thoughts on SugarCon today in his blog and I couldn’t help but grin at his comments on the Sugar culture. But what I most enjoyed was his review of the enthusiasm of the Sugar community.

From his post…
That said, this was not just a good party but the conference itself was extremely well planned and well done and had some of that high spirited sense of community. What was particularly interesting to me was to see the genuine interest the customers, the partners and the developers had for the company, the people and the product itself. They liked it, sure, but they were INTERESTED in it and where it was going . They seemed to feel they had a stake in its success, which is as Shakespeare said somewhere, a “devoutly to be wished” position for a vendor to be in. Part of that was there seems to be an open culture and I hear from my friends at SugarCRM that they enjoy the ride they are on.
/end quote

Thank you to the Sugar community for being so interested, enthusiastic, passionate, ornery, demanding and flat out engaged. That’s what makes this “ride” so much fun!
Clint

Have feedback for us? Drop us a line.
Terms & Conditions | Privacy | Trademark Info | Contact Info | FAQs | SugarCRM Inc.© 2004 - 2009 All rights reserved.