<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Profiling Solutions</title>
	<atom:link href="http://www.profilingsolutions.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.profilingsolutions.com</link>
	<description>SugarCRM and Saleslogix for Atlanta, GA and Mobile, AL</description>
	<lastBuildDate>Wed, 16 May 2012 17:27:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>PHP 5.2 and 5.3 Differences and Work-Arounds</title>
		<link>http://www.profilingsolutions.com/archive/php-5-2-and-5-3-differences-workarounds/</link>
		<comments>http://www.profilingsolutions.com/archive/php-5-2-and-5-3-differences-workarounds/#comments</comments>
		<pubDate>Mon, 14 May 2012 13:09:39 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1158</guid>
		<description><![CDATA[Something I&#8217;ve been frustrated with as a developer is the subtle differences in PHP versions 5.2 and 5.3. One of our service providers hasn&#8217;t been able to upgrade to 5.3 yet, but all of my code that I write on my machine (using 5.3) has to run on their servers. While this isn&#8217;t often a [...]]]></description>
			<content:encoded><![CDATA[<p>Something I&#8217;ve been frustrated with as a developer is the subtle differences in PHP versions 5.2 and 5.3. One of our service providers hasn&#8217;t been able to upgrade to 5.3 yet, but all of my code that I write on my machine (using 5.3) has to run on their servers. While this isn&#8217;t often a problem, every now and then I find the subtle differences. PHP 5.3 actually has a lot of improvements over 5.2, here are a few of the differences I&#8217;ve found [the hard way] and the workarounds I use.</p>
<h3>nl2br</h3>
<p>The basic function for converting new-lines to HTML line breaks, nl2br in PHP 5.3 incorporates the ability to use (X)HTML-tailored tag ending (i.e. &lt;br /&gt; instead of &lt;br&gt;). But if you&#8217;re on 5.2 or under, the second parameter isn&#8217;t available and attempting to use it will result in errors.</p>
<pre class="brush: php; title: ; notranslate">if(version_compare(PHP_VERSION,'5.3.0') &gt; 1){
  $html = nl2br($text,1);
} else {
  $html = nl2br($text);
}</pre>
<h3>DateTime Objects and Methods</h3>
<p>PHP 5.3 has <em>awesome</em> new functionality for meddling with DateTime objects that just doesn&#8217;t exist in PHP 5.2. Just check out <a href="http://us3.php.net/manual/en/datetime.createfromformat.php" target="_blank">createFromFormat()</a>, <a href="http://us3.php.net/manual/en/datetime.diff.php" target="_blank">diff()</a>, <a href="http://us3.php.net/manual/en/datetime.add.php" target="_blank">add()</a> and <a href="http://us3.php.net/manual/en/datetime.sub.php" target="_blank">sub()</a>.</p>
<p>Here&#8217;s a work-around I use in place of diff():</p>
<pre class="brush: php; title: ; notranslate"> // start with two DateTime objects
$datetime_one = new DateTime();
$datetime_two = new DateTime();

// the necessary way using PHP 5.2
$datetime_one_string = $datetime_one-&gt;format('U');
$datetime_two_string = $datetime_two-&gt;format('U');
// get a difference represented as an int, number of seconds
$difference = abs($datetime_one_string - $datetime_two_string);

// the fun way using PHP 5.3, returning a DateInterval obj
$difference = $datetime_one-&gt;diff($datetime_two);</pre>
<p>The benefit of having <strong>$difference</strong> as a <a href="http://us3.php.net/manual/en/class.dateinterval.php" target="_blank">DateInterval object</a> is that you can then modify and format however you want. The PHP 5.2 return above is simply an integer as a number of seconds, which can be converted in a few more steps, but is more cumbersome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/php-5-2-and-5-3-differences-workarounds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SugarCRM System CleanUp</title>
		<link>http://www.profilingsolutions.com/archive/sugarcrm-system-cleanup/</link>
		<comments>http://www.profilingsolutions.com/archive/sugarcrm-system-cleanup/#comments</comments>
		<pubDate>Mon, 07 May 2012 23:46:57 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[SugarCRM]]></category>
		<category><![CDATA[Cleanup]]></category>
		<category><![CDATA[Database Admin]]></category>
		<category><![CDATA[Recycle Bin]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[unDelete]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1152</guid>
		<description><![CDATA[Spring is here, and maybe it&#8217;s time for your annual SugarCRM System Clean-up. Sugar&#8217;s database system is good, but don&#8217;t things just feel better when there isn&#8217;t ten-year-old data lurking around? Here are some scripts I use when I&#8217;m pruning a database to drop off deleted data or old data. Please don&#8217;t go blindly run [...]]]></description>
			<content:encoded><![CDATA[<p>Spring is here, and maybe it&#8217;s time for your annual SugarCRM System Clean-up. Sugar&#8217;s database system is good, but don&#8217;t things just feel better when there isn&#8217;t ten-year-old data lurking around? Here are some scripts I use when I&#8217;m pruning a database to drop off deleted data or old data.<span id="more-1152"></span></p>
<p>Please don&#8217;t go blindly run these snippits against your production system. This post is meant to be a guiding hand to cleaning up your system in case-specific ways that may or may not be applicable to your needs. And remember, always, always, <strong>always</strong> back up your system (and maybe even try these on a separate backup before your run them against production).</p>
<h3>Drop Accounts that don&#8217;t have any recorded history or Opportunities</h3>
<pre class="brush: sql; title: ; notranslate">delete accounts from accounts
LEFT JOIN accounts_cstm on accounts.id = accounts_cstm.id_c
LEFT JOIN accounts_opportunities on accounts.id = accounts_opportunities.account_id
LEFT JOIN calls on accounts.id=calls.parent_id
LEFT JOIN meetings on accounts.id=meetings.parent_id
LEFT JOIN tasks on accounts.id=tasks.parent_id
where
(
accounts_opportunities.id is null
and leads.id is null
and calls.id is null
and meetings.id is null
and tasks.id is null
)</pre>
<h3>Delete Activities that are older than a given date</h3>
<pre class="brush: sql; title: ; notranslate">delete from calls where date_start &lt;= '2008-01-01';
delete from meetings where date_start &lt;= '2008-01-01';
delete from tasks where date_start &lt;= '2008-01-01';</pre>
<h3>Analyze and Prune Deleted Data</h3>
<p>SugarCRM has a great feature of not actually deleting things. When you click the <em>delete</em> button on a record (or even a relationship), that record&#8217;s deleted field is set to true, and it&#8217;s ignored forever. This acts like your Windows Recycle Bin, so that your developer or DBA (or even you, <a title="unDelete (Recycle Bin for SugarCRM)" href="http://www.profilingsolutions.com/software-products/sugarcrm-modules/undelete-recycle-bin-for-sugarcrm/" target="_blank">using our unDelete module</a>) can restore records for you when you didn&#8217;t actually mean to click delete (and then didn&#8217;t mean to click &#8220;Yes&#8221; on the delete confirmation&#8230;).</p>
<p>The side-effect of this is that <em>nothing is ever actually deleted</em> and things pile up, using more of your storage and causing more and more overhead on your database queries. So once you&#8217;ve gotten your backup completed, you can use a script like this one to analyze how much deleted data Sugar hasn&#8217;t actually deleted, and then go ahead and actually delete it.</p>
<p>Drop this file into /custom/modules/Accounts/DeleteAnalysis.php:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
global $db;
$query = &quot;show tables;&quot;;
$result = $db-&gt;query($query);
$tables = array();
while($row = $db-&gt;fetchByAssoc($result)){
$tables[] = $row['Tables_in_database_name']; // database_name being the name of your database...
}

echo &quot;&lt;table&gt;&lt;tbody&gt;&quot;;
echo &quot;&lt;tr&gt;&lt;th&gt;Table Name&lt;/th&gt;&lt;th&gt;Total Records&lt;/th&gt;&lt;th&gt;Deleted Records&lt;/th&gt;&lt;/tr&gt;&quot;;
$sum_all = $sum_del = 0;
foreach($tables as $table){
echo &quot;&lt;tr&gt;&lt;td&gt;$table&lt;/td&gt;&quot;;
$count_all = $count_del = null;
$query = &quot;select count(*) as count from $table;&quot;;
$result = $db-&gt;query($query);
while($row = $db-&gt;fetchByAssoc($result)){
$count_all = $row['count'];
}
$query_del = &quot;select count(*) as count from $table where deleted = 1;&quot;;
$result_del = $db-&gt;query($query_del);
while($row = $db-&gt;fetchByAssoc($result_del)){
$count_del = $row['count'];
}
if(!is_null($count_del) &amp;&amp; ($count_del != $count_all) &amp;&amp; $_REQUEST['delete'] == 1){
$query = &quot;delete from $table where deleted = '1';&quot;;
$db-&gt;query($query,&quot;dropping deleted records from $table&quot;);
}

echo &quot;&lt;td&gt;$count_all&lt;/td&gt;&lt;td&gt;$count_del&lt;/td&gt;&lt;/tr&gt;&quot;;
$sum_all += $count_all;
$sum_del += $count_del;

}
echo &quot;&lt;/tbody&gt;&lt;/table&gt;&quot;;

// totals
echo &quot;Totals&quot;;
echo &quot;&lt;ul&gt;&lt;li&gt;$sum_all&lt;/li&gt;&lt;li&gt;$sum_del&lt;/li&gt;&lt;/ul&gt;&quot;;
</pre>
<p>To invoke it for analysis, simply navigate to <strong>index.php?module=Accounts&amp;action=DeleteAnalysis</strong>. When you&#8217;re ready to start dropping data out, append the additional GET parameter on the URL <strong>&amp;delete=1</strong>.</p>
<p>This may be a long process, depending on the size of the database. You may need to extend your PHP configuration&#8217;s <a href="http://us.php.net/manual/en/info.configuration.php#ini.max-execution-time" target="_blank">max_exeuction_time</a> property.</p>
<h3>Identify Contacts with an Assigned User different than their Related Accounts&#8217; Assigned User</h3>
<p>I said case-specific, right? Our client needed to update the database to ensure that all contacts had an assigned user to match their parent accounts&#8217; assigned user. It was a several-step process:</p>
<p>First we established a benchmark to see how many records we&#8217;d be changing with this:</p>
<pre class="brush: sql; title: ; notranslate">select accounts.id,accounts.name,accounts.assigned_user_id,
contacts.id,contacts.first_name,contacts.last_name,contacts.assigned_user_id
from accounts
join accounts_contacts on accounts_contacts.account_id = accounts.id and accounts_contacts.deleted = 0
join contacts on contacts.id = accounts_contacts.contact_id and contacts.deleted = 0
where accounts.deleted = 0
and accounts.assigned_user_id &lt;&gt; contacts.assigned_user_id</pre>
<p>Then we update all of the contacts in a basic way&#8230;</p>
<pre class="brush: sql; title: ; notranslate">update accounts
join accounts_contacts on accounts_contacts.account_id = accounts.id and accounts_contacts.deleted = 0
join contacts on contacts.id = accounts_contacts.contact_id and contacts.deleted = 0
set contacts.assigned_user_id = accounts.assigned_user_id
where accounts.deleted = 0;</pre>
<p>We then realized that some of our Contacts were related to multiple accounts, so making them match got tricky. We decided to take these leftovers and assign them to a particular user, a staff supervisor, so she could sort things out manually:</p>
<pre class="brush: sql; title: ; notranslate">update accounts
join accounts_contacts on accounts_contacts.account_id = accounts.id and accounts_contacts.deleted = 0
join contacts on contacts.id = accounts_contacts.contact_id and contacts.deleted = 0
set contacts.assigned_user_id = '1'
where accounts.deleted = 0 and accounts.assigned_user_id &lt;&gt; contacts.assigned_user_id
and contacts.assigned_user_id &lt;&gt; '1';</pre>
<p>Running the benchmark again, but adding an additional clause to filter by this user account, we should find zero rows.</p>
<pre class="brush: sql; title: ; notranslate">select accounts.id,accounts.name,accounts.assigned_user_id,
contacts.id,contacts.first_name,contacts.last_name,contacts.assigned_user_id
from accounts
join accounts_contacts on accounts_contacts.account_id = accounts.id and accounts_contacts.deleted = 0
join contacts on contacts.id = accounts_contacts.contact_id and contacts.deleted = 0
where accounts.deleted = 0
and accounts.assigned_user_id &lt;&gt; contacts.assigned_user_id
and contacts.assigned_user_id &lt;&gt; '1'</pre>
<h2>Update Contacts with values from related Accounts</h2>
<p>Similar to the above, but using custom fields:</p>
<pre class="brush: sql; title: ; notranslate">update
accounts
join accounts_cstm on accounts.id = accounts_cstm.id_c
join accounts_contacts on accounts.id = accounts_contacts.account_id
join contacts on contacts.id = accounts_contacts.contact_id
join contacts_cstm on contacts_cstm.id_c = contacts.id
set contacts_cstm.account_type_c = accounts_cstm.type_c
</pre>
<p>And to check:</p>
<pre class="brush: sql; title: ; notranslate">select accounts.name,accounts_cstm.type_c,contacts.last_name,contacts_cstm.account_type_c from
accounts
join accounts_cstm on accounts.id = accounts_cstm.id_c
join accounts_contacts on accounts.id = accounts_contacts.account_id
join contacts on contacts.id = accounts_contacts.contact_id
join contacts_cstm on contacts_cstm.id_c = contacts.id
where contacts_cstm.account_type_c &lt;&gt; accounts_cstm.type_c;</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/sugarcrm-system-cleanup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SugarCRM Labels Hierarchy</title>
		<link>http://www.profilingsolutions.com/archive/sugarcrm-system-label-hierarchy/</link>
		<comments>http://www.profilingsolutions.com/archive/sugarcrm-system-label-hierarchy/#comments</comments>
		<pubDate>Tue, 01 May 2012 12:27:08 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[SugarCRM]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1029</guid>
		<description><![CDATA[Labels can seem very straight forward when you&#8217;re working within Studio, but when you dive into code you&#8217;ll likely find that the system labels for a particular module or for dropdown definitions are strewn throughout several places in the system. Let&#8217;s examine the different places for label data and the hierarchy the system uses to [...]]]></description>
			<content:encoded><![CDATA[<p>Labels can seem very straight forward when you&#8217;re working within Studio, but when you dive into code you&#8217;ll likely find that the system labels for a particular module or for dropdown definitions are strewn throughout several places in the system. Let&#8217;s examine the different places for label data and the hierarchy the system uses to compile the labels together and resolve conflicts.</p>
<p><span id="more-1029"></span></p>
<p>First, know that there are three sets of labels within the system, <strong>$mod_strings</strong> is an array that carries the labels for a given module (e.g. Contacts or Accounts), while <strong>$app_strings</strong> and <strong>$app_list_strings</strong> contain system labels like translated module names, dropdown lists and system button labels (e.g. the &#8220;Print&#8221; link at the bottom of nearly every page). I find that $app_strings and $app_list_strings seem to have a bit of overlap, so the point to understand is consistency; if you define a label in $app_list_strings, you&#8217;ll want to call it from $app_list_strings.</p>
<h2>$mod_strings</h2>
<p>Let&#8217;s start with the module-specific labels. You&#8217;ll find the original, vanilla labels are stored in the module-specific directories. For Contacts, that would be <strong>/modules/Contacts/language/</strong>. Language files are prefixed with the international language identifier, and SugarCRM supports 22 languages (and more are available around the &#8216;net). An example would for American English would be <em>en_us</em>, or Spanish (Español) as es_ES.</p>
<p>That said, the English language file would be en_us.lang.php. In that file is a single array, $mod_strings. The array keys are code references, always in CAPS and usually prefixed by LBL_. The values are the translated labels. For example,</p>
<pre class="brush: php; title: ; notranslate">$mod_strings = array(
     ...
     'LBL_FIRST_NAME' =&gt; 'First Name:',
     ...
);</pre>
<p>This directory holds the <em>stock</em> language files, but to maintain an upgrade-safe system we don&#8217;t want to touch these files. Instead, we have two options for placing custom language definitions.</p>
<p>The easiest option for custom language files mirrors the original directory in the custom directory, again using Contacts that would be <strong>/custom/modules/Contacts/language/en_us.lang.php</strong>. This file will be structured the exact same way as the original file; the two arrays are merged when the screen is being generated for the user. If there are conflicts, the custom definition takes precedence. This method of custom language definition is ideal if you&#8217;re customizing a single system, i.e. not packaging changes up for mass-distribution and not having to work via Module Loader for a hosted system. Changes to language files made in Studio will write to this directory.</p>
<p>The second option for custom language files makes use of the Custom Extension directory and the cascading file-merge performed by Repair and Rebuild. If you&#8217;re not familiar, I&#8217;ll give an example. Let&#8217;s modify the LBL_FIRST_NAME label in Contacts. Create a file at <strong>/custom/Extension/modules/Contacts/Ext/Language/en_us.PSI_TopLevelLanguageChange.php</strong>. The file name itself is arbitrary, anything is allowed so long as you provide the proper language-determining prefix. It&#8217;s a good idea to also prepend an author key (similar to creating a module) to avoid collisions. Within that file we&#8217;ll create individual pieces of the $mod_strings array:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$mod_strings['LBL_FIRST_NAME'] = 'Forename';</pre>
<p>Notice how we are explicit about setting the key and value within the already-existing array. <strong>Do not create the entire array</strong>. This array is not merged into the master language list the same way that /custom/modules/Contacts/language/ is. It is actually lower-priority, because it is intended for mass-distribution. You may notice that when exporting changes from Studio, the generated module uses this method to load the language files.</p>
<p>Also realize that merely creating this file did nothing. What we&#8217;ve done is placed the file in a directory that Repair and Rebuild will scan and create a compiled language definition from all files within the directory. The Repair and Rebuild process will create <strong>/custom/modules/Contacts/Ext/Language/en_us.lang.ext.php</strong> which holds the compiled field-explicit language adjustments from the Extension language definitions. You&#8217;ll also notice that in this file is a repeated warning message, &#8220;WARNING: The contents of this file are auto-generated.&#8221; Heed this warning; adjustments to this direct file will be <em>wiped out</em> on the next Repair and Rebuild.</p>
<p>So the hierarchy is this, in order of precedence:</p>
<ol>
<li>custom/modules/&lt;ModuleName&gt;/language/en_us.lang.php</li>
<li>custom/modules/&lt;ModuleName&gt;/Ext/Language/en_us.lang.ext.php</li>
<li>modules/&lt;ModuleName&gt;/language/en_us.lang.php</li>
</ol>
<h2>$app_list_strings and $app_strings</h2>
<p>With an understanding of the hierarchy for $mod_strings, $app_strings and $app_list_strings make pretty good sense. These work similarly to $mod_strings, but base all custom definitions in slightly different directories:</p>
<ul>
<li><strong>/custom/include/language/en_us.lang.php</strong> for Studio-created or basic changes.</li>
<li><strong>/custom/Extension/application/Ext/Language/en_us.PSI_ArbitraryName.php</strong> for the more easily-distributed field-specific or labels-specific, explicit changes. Remember that creating this file doesn&#8217;t actually affect anything until you perform the Repair and Rebuild, which creates&#8230;</li>
<li><strong>/custom/application/Ext/Language/en_us.lang.ext.php</strong> for the compiled language files.</li>
<li>Default/Stock language definitions are kept in <strong>/include/language/en_us.lang.php</strong>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/sugarcrm-system-label-hierarchy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SugarCRM Announces Annual Global Partner Awards Program Winners at SugarCon 2012</title>
		<link>http://www.profilingsolutions.com/archive/sugarcrm-announces-annual-global-partner-awards-program-winners-at-sugarcon-2012/</link>
		<comments>http://www.profilingsolutions.com/archive/sugarcrm-announces-annual-global-partner-awards-program-winners-at-sugarcon-2012/#comments</comments>
		<pubDate>Mon, 30 Apr 2012 04:00:25 +0000</pubDate>
		<dc:creator>David Newberry</dc:creator>
				<category><![CDATA[Press Releases]]></category>
		<category><![CDATA[SugarCRM]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1209</guid>
		<description><![CDATA[SugarCRM, the world’s fastest-growing customer relationship management (CRM) company, today announced the winners of the company’s Annual Global Partner Awards Program at SugarCon 2012, the company’s annual customer, user and partner conference. Partners from North America, EMEA, Latin America, Asia, Australia and New Zealand were recognized for their successful growth and new customer acquisition and retention in 2011. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://cts.businesswire.com/ct/CT?id=smartlink&amp;url=http%3A%2F%2Fwww.sugarcrm.com%2Fcrm%2F&amp;esheet=50250131&amp;lan=en-US&amp;anchor=SugarCRM&amp;index=1&amp;md5=78313617606ac0bd6da287be82eb6048">SugarCRM</a>,<strong> </strong>the world’s fastest-growing customer relationship management (CRM) company, today announced the winners of the company’s Annual Global Partner Awards Program at <a href="http://sugarcon.sugarcrm.com">SugarCon 2012</a>, the company’s annual customer, user and partner conference. Partners from North America, EMEA, Latin America, Asia, Australia and New Zealand were recognized for their successful growth and new customer acquisition and retention in 2011. More than 40 companies were honored with awards, and two companies were given highest honors as the Partner of the Year and the Rookie of the Year.</p>
<p>The 2011 Partner of the Year Award was granted to Opensymbol. Each year, the award is given to one SugarCRM partner. The criteria for the award is based on the company having more than one year of SugarCRM experience, as well as success in new customer acquisition and customer retention, consistent growth and active participation in SugarCRM’s sponsored events. The partner must also be in good standing and nominated by a regional vice president.</p>
<p>W Systems, based in Ramsey, New Jersey received the Rookie of the Year Award. The company was selected because of their ability to engage quickly with SugarCRM and achieve major milestones since signing their agreement with SugarCRM in November 2011. Within 60 days of signing on with SugarCRM, W Systems secured more than 20 new customers and became a primary evangelist for SugarCRM by becoming the first partner to participate in a partner case study.</p>
<p>The Top Performer Awards were given to 29 companies by region. Each company achieved growth from 2010 to 2011 and secured at least $20,000 in new customer subscriptions with SugarCRM.</p>
<p>In North America, the winners were: Profiling Solutions, Cynergy Solutions, OA Solutions, ATCORE Systems, ApexTwo, Faye Business Systems Group, Technology Advisors, Inc., Concentrix, Highland Solutions, and Plus Consulting. In EMEA, the winners were: Smile Open Source Solutions Group, Corenet, Hubstone, OpenSymbol, Captivea, CS2, Ysance, Dupaco, and dotBase. In Latin America, the winners were: DISYTEL openConsulting, Palmtree Consulting, QuanticVision, and GrowIT. In Australia and New Zealand, the winners were: Innovent, CRM Online, and CRMLogic. In Asia, the winners were: Bhea Technologies Pte Ltd., CRMWorks Asia, and Signify.</p>
<p>The Most Valuable Player Awards were granted to 10 companies by region. Partners were nominated by a Regional Vice President based on their significant customer acquisition year over year and their ability to achieve customer retention of 80% or higher. In North America, the winners were: BrainSell, Epicom, ATCORE Systems, and Levementum. In EMEA the winners were: EnableIT Technologies, Insignio CRM, Synolia, and Jacobsons Direct Marketing. In Latin America, the winner was GrowIT. In Australia and New Zealand, the winner was InsightfulCRM. In Asia, the winner was BHEA Technologies Pte Ltd..</p>
<p>&#8220;We are thrilled to see a record number of top performers awarded and want to congratulate all our partners on their achievements,” said Jeff Campbell, Vice President of Worldwide Sales. “They have been diligent in 2011 to meet their business goals and deserve recognition for their accomplishments. We are looking forward to continued success in the channel in 2012.&#8221;</p>
<p>Special Recognition Awards were given to BrainSell, Epicom, Highland Solutions, InsightfulCRM, Insignio CRM, iZeno, Lampada Global Services, Levementum, OpenSymbol, Palmtree Consulting, REDK, and Synolia. Both iZeno and Epicom received multiple Partner of the Month Awards in 2011. Amanda Anderson of Epicom was the recipient of the Most Creative Marketer Award.</p>
<p>Please see other SugarCRM announcements from SugarCon about the company’s <a href="http://www.sugarcrm.com/newspress/q1-momentum" target="_blank">Q1 2012 momentum</a>, the latest <a href="http://www.sugarcrm.com/newspress/sugar-65" target="_blank">Sugar 6.5 product release</a>, and <a href="http://www.sugarcrm.com/newspress/sugarcrm-channel-partner-program-momentum">additions to the company’s channel partner program</a>.</p>
<p><strong>More About SugarCon 2012</strong></p>
<p>SugarCon 2012’s theme is “Explore the Possibilities of CRM,” inspiring attendees to dig deeper into the vast capabilities that CRM offers. In keeping with SugarCRM’s open approach to business, the CRM community, not SugarCRM, built the conference <a href="http://sugarcon.sugarcrm.com/program/session-schedule">schedule </a>based on attendee suggestions and online voting. The event will offer eight tracks with more than 80 breakout sessions, as well as separate UnCon and training programs.</p>
<p>For more information on SugarCon 2012, visit the event web site. To register for the event, visit the registration page.</p>
<p><strong>About SugarCRM</strong></p>
<p>SugarCRM makes CRM simple. As the world&#8217;s fastest growing customer relationship management (CRM) company, SugarCRM applications have been downloaded more than ten million times and currently serve over 1,000,000 end users in 192 countries. Over 7,000 organizations have chosen SugarCRM&#8217;s On-Site and Cloud Computing services over proprietary alternatives. SugarCRM has been recognized for its customer success and product innovation by <a href="http://www.destinationcrm.com/Articles/Editorial/Magazine-Features/The-2011-CRM-Market-Leaders-76485.aspx" target="_blank">CRM Magazine</a>, <a href="http://www.infoworld.com/d/open-source-software/bossie-awards-2011-the-best-open-source-applications-171572-1" target="_blank">InfoWorld</a> and <a href="http://www.tmcnet.com/topics/articles/251362-customer-interaction-solutions-magazines-2011-product-the-year.htm" target="_blank">Customer Interaction Solutions</a>.</p>
<p>For more information, call (408) 454-6900 or 1 87 SUGARCRM toll-free in the US, email <a href="mailto:contact@sugarcrm.com">contact@sugarcrm.com</a>, or visit <a href="www.sugarcrm.com">www.sugarcrm.com</a>. You can also connect with SugarCRM on <a href="http://cts.businesswire.com/ct/CT?id=smartlink&amp;url=http%3A%2F%2Fwww.facebook.com%2Fsugarcrm&amp;esheet=50250131&amp;lan=en-US&amp;anchor=Facebook&amp;index=13&amp;md5=59a45db1484c152e59ebfd65e318468d">Facebook</a>, <a href="http://cts.businesswire.com/ct/CT?id=smartlink&amp;url=http%3A%2F%2Ftwitter.com%2Fsugarcrm&amp;esheet=50250131&amp;lan=en-US&amp;anchor=Twitter&amp;index=14&amp;md5=9a37f3b12be342fb791ed82a9ae5e049">Twitter</a> and <a href="http://cts.businesswire.com/ct/CT?id=smartlink&amp;url=http%3A%2F%2Fwww.youtube.com%2Fuser%2FDiscoverSugarCRM&amp;esheet=50250131&amp;lan=en-US&amp;anchor=YouTube&amp;index=15&amp;md5=06bd9fa24edd9d21028439011e18cbf4">YouTube</a>.</p>
<p><a href="http://www.sys-con.com/node/2260364">http://www.sys-con.com/node/2260364</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/sugarcrm-announces-annual-global-partner-awards-program-winners-at-sugarcon-2012/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hiding Subpanels, thru Configuration and thru Code</title>
		<link>http://www.profilingsolutions.com/archive/hiding-subpanels-thru-configuration-and-thru-code/</link>
		<comments>http://www.profilingsolutions.com/archive/hiding-subpanels-thru-configuration-and-thru-code/#comments</comments>
		<pubDate>Wed, 25 Apr 2012 15:01:33 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[SugarCRM]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1134</guid>
		<description><![CDATA[SugarCRM&#8217;s subpanels are pretty configurable. Especially in later editions, a single reference to a subpanel can be overridden via Studio very easily. But what if you want to all-out hide a subpanel? Studio doesn&#8217;t offer this ability. Enter the Display Module Tabs and Subpanels menu, accessible from the Admin page under the Developer Tools section: [...]]]></description>
			<content:encoded><![CDATA[<p>SugarCRM&#8217;s subpanels are pretty configurable. Especially in later editions, a single reference to a subpanel can be overridden via Studio very easily. But what if you want to all-out hide a subpanel? Studio doesn&#8217;t offer this ability. Enter the Display Module Tabs and Subpanels menu, accessible from the Admin page under the Developer Tools section:</p>
<p><a href="http://www.profilingsolutions.com/wp-content/uploads/2012/04/Display-Module-Tabs-and-Subpanels.png"><img class="alignnone size-medium wp-image-1135" title="Display Module Tabs and Subpanels" src="http://www.profilingsolutions.com/wp-content/uploads/2012/04/Display-Module-Tabs-and-Subpanels-215x300.png" alt="Display Module Tabs and Subpanels" width="215" height="300" /></a></p>
<p>But suppose you didn&#8217;t want to hide all of the subpanels for a given module, but just to remove it from a particular view? For a real-life example, we recently had a need to remove the default Opportunities subpanel from the Accounts DetailView. Because it&#8217;s only for this view that we want to drop the Opportunity subpanel, the above dialog doesn&#8217;t fit the need, and Studio cannot help us either. We must go through code.</p>
<p>Subpanel layouts are defined originally within metadata, e.g. /modules/Accounts/metadata/subpaneldefs.php. These files hold the original, default layout of subpanels and the fields within them. They are overridden in custom Extension data, e.g. custom/Extension/modules/Accounts/Ext/Layoutdefs/accounts_opps.php. After a repair &#038; rebuild, you&#8217;ll find the data from the arbitrarily named files are merged and placed in /custom/modules/Accounts/Ext/Layoutdefs/layoutdefs.ext.php.</p>
<p>In these files we can define new subpanels or re-define existing ones. To actually remove one, we can use PHP&#8217;s unset function:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
unset($layout_defs[&quot;Accounts&quot;][&quot;subpanel_setup&quot;]['opportunities']);</pre>
<p>For further example, here is the described code, packaged and ready for distribution via Module Loader:<br />
<a href="http://www.profilingsolutions.com/wp-content/uploads/2012/04/AccountsDetailViewOppGeneric.zip">Accounts DetailView Hide Opp Subpanel</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/hiding-subpanels-thru-configuration-and-thru-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Longer SugarCRM Sessions</title>
		<link>http://www.profilingsolutions.com/archive/longer-sugarcrm-sessions/</link>
		<comments>http://www.profilingsolutions.com/archive/longer-sugarcrm-sessions/#comments</comments>
		<pubDate>Fri, 20 Apr 2012 18:31:33 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[SugarCRM]]></category>
		<category><![CDATA[session length]]></category>
		<category><![CDATA[sessions]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1117</guid>
		<description><![CDATA[In most server-setups, we find that the SugarCRM Session only lasts about half an hour. This is something I&#8217;ve gotten complaints about &#8212; users wanting longer sessions to ease the work day. I had spent time looking through the session-management code to find an answer and just wasn&#8217;t getting anywhere. I back-burned it until I [...]]]></description>
			<content:encoded><![CDATA[<p>In most server-setups, we find that the SugarCRM Session only lasts about half an hour. This is something I&#8217;ve gotten complaints about &#8212; users wanting longer sessions to ease the work day. I had spent time looking through the session-management code to find an answer and just wasn&#8217;t getting anywhere. I back-burned it until I stumbled on the solution today: SugarCRM sets session length according to a PHP configuration variable.</p>
<p>As it often does, the SugarCRM Forums held the question and answer. In <a href="http://forums.sugarcrm.com/f3/extending-30-minutes-session-timeout-6330/" target="_blank">extending the 30 minutes session timeout</a> forum user Duzoid posts the question and it is eventually correctly answered by user Sunside. The solution is to modify the PHP configuration variable <strong>session.gc_maxlifetime</strong>. Sunside suggests placing the changed configuration in an <em>.htaccess</em> file due to accessibility and hosting environment limitations, but having access to my core <em>php.ini</em> I went ahead and changed our local Sugar instance globally.</p>
<blockquote><p>If it is allowed on your host, then you may very well change this in the .htaccess file:</p>
<p>php_value session.gc_maxlifetime 14400</p>
<p>This should set the session lifetime to 4 hours.</p>
<p>Please note that if session files are shared between different scripts in different directories on your server, then you need to make this setting in each of the script directories&#8217; .htaccess file. That is because other scripts may erase your Sugar session files if they have a shorter session lifetime.</p>
<p>You could also create a separate directory for Sugar session files and set this with</p>
<p>php_value session.save_path /my/new/sugarsessiondir</p>
<p>in the .htaccess that you put in your Sugar root directory. You should NOT create this directory anywhere under your htdocs, but further up in the directory structure, so that these files cannot be accessed by the webserver for security reasons.</p>
<p>The preferred way of setting the garbage collector&#8217;s maxlifetime would be to do it serverwide in the php.ini, but this may not be possible in some shared hosting environments. </p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/longer-sugarcrm-sessions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Debian Squeeze Apache2 and GoDaddy SSL Certifications (https)</title>
		<link>http://www.profilingsolutions.com/archive/debian-squeeze-apache2-and-godaddy-ssl-certifications-https/</link>
		<comments>http://www.profilingsolutions.com/archive/debian-squeeze-apache2-and-godaddy-ssl-certifications-https/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 18:30:59 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1112</guid>
		<description><![CDATA[I recently set up my first ssl-certification for Apache for our SugarCRM server. The process wasn&#8217;t as difficult as I expected, as Debian has some built in tools to make it relatively easy. Following some instructions I piece-milled from a few web sites, here is the process I used: Within the Debian Squeeze Server (assuming [...]]]></description>
			<content:encoded><![CDATA[<p>I recently set up my first ssl-certification for Apache for our SugarCRM server. The process wasn&#8217;t as difficult as I expected, as Debian has some built in tools to make it relatively easy. <span id="more-1112"></span></p>
<p>Following some instructions I piece-milled from a few web sites, here is the process I used:</p>
<ol>
<li>Within the Debian Squeeze Server (assuming Apache2 is already set up and running)</li>
<ol>
<li>a2enmod ssl</li>
<li>mkdir /etc/apache2/ssl</li>
<li>cd /etc/apache2/ssl</li>
<li>openssl req -new -newkey rsa:2048 -nodes -keyout sugar.profilingsolutions.com.key -out sugar.profilingsolutions.com.csr</li>
<li>chmod 600 /etc/apache2/ssl/*</li>
<li>cat /etc/apache2/ssl/sugar.profilingsolutions.com.csr (copy the output of this so that you can provide it to GoDaddy later on)</li>
</ol>
<li>In your GoDaddy.com Account</li>
<ol>
<li>Click My Account, expand the SSL Certificates section and click the green Launch button by the certificate you want to set up (assuming you&#8217;ve already purchased one).</li>
<li>Follow prompts to select your certificate, server type and provide the CSR you copied from the server</li>
<li>wait&#8230; GoDaddy will take a few hours. In the mean time, you may be require to verify the domain. This typically involves setting up an specific and obscurely-named HTML file in the root directory of your server. Check your Pending Certificates page every 30 minutes or so to see if there is a &#8220;hold up&#8221; that you need to resolve.</li>
<li>Note that my domain wasn&#8217;t automatically verifying with their tool, so I had to request manual verification which may take up to 24 hours.</li>
</ol>
<li>Once the domain is verified, download your certificate from the GoDaddy SSL Certificates section.</li>
<li>Upload the certificate package bundle (zip archive) to your server at /etc/apache2/ssl/</li>
<li>unzip package with <strong>unzip -qq *zip</strong></li>
<li>**edit the file /etc/apache2/sites-available/default-ssl and adjust the CertificatesFile parameter to point to your new file.**</li>
<li>Again in your GoDaddy account, download your new Certificate file (.crt)</li>
<li>a2ensite default-ssl</li>
<li>service apache2 restart</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/debian-squeeze-apache2-and-godaddy-ssl-certifications-https/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Four Questions you Should Ask before buy a CRM System</title>
		<link>http://www.profilingsolutions.com/archive/1122/</link>
		<comments>http://www.profilingsolutions.com/archive/1122/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 11:31:31 +0000</pubDate>
		<dc:creator>David Newberry</dc:creator>
				<category><![CDATA[SugarCRM]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1122</guid>
		<description><![CDATA[&#8220;It is a very bad security model, the roach motels of clouds.  You can check in but you can’t check out. &#8220; Larry Ellison&#8217;s quote about SalesForce, Oct 2011 Larry Ellison is the founder of Oracle Software, the second largest applications provider in the world.   First and foremost he is a sales representative.  His quote [...]]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center;">&#8220;It is a very bad security model, the roach motels of clouds.  You can check in but you can’t check out. &#8220;</h1>
<div style="text-align: center;">Larry Ellison&#8217;s quote about SalesForce, Oct 2011</div>
<p>Larry Ellison is the founder of Oracle Software, the second largest applications provider in the world.   First and foremost he is a sales representative.  His quote is very much posturing and positioning.</p>
<p>I reference the quote only because as a consultant, I empathize with my customers being bombarded with statements and promises by Sales people. But how do you make an informed decision?</p>
<p>Many CRM sales representatives want you to buy the system without knowing what&#8217;s under the hood.  It would be like buying a car based solely on color and design only to find out afterwards that the engine does not have enough horsepower.</p>
<p>Every CRM has accounts, contacts, opportunities, activity management, leads, a few have quotes, most have custom reporting and dashboards, most integrate with other systems.  Whether you&#8217;re considering SugarCRM, SalesForce, Zoho or a plethora others, the basic CRM functionality is generally the same.  So, you might ask, what is the difference? Well, there&#8217;s a lot of difference that may not be seen. Here are 4 questions you should ask before buying a CRM system so you know what&#8217;s &#8216;under the hood&#8217; and away from &#8216;the roach motel&#8217;.</p>
<ol>
<li>Multi-tenant or Single tenant?  Do I own my data?</li>
<li>Is there additional cost for additional CRM functionality?</li>
<li>Are there restrictions regarding the number of custom modules, fields, workflows, etc?</li>
<li>What is the exit plan? How do I get my data back?</li>
</ol>
<p><strong>Answer 1:</strong> <a href="http://www.sapiensoftware.com/multitenant.aspx">Multi-tenant</a> are systems in which multiple ‘customers’ use the same database.  Information is segmented through database security.  A <a href="http://www.sapiensoftware.com/multitenant.aspx">single-tenant</a>system is a system were the ‘customer’ has their own database.  Single tenant systems allow you to customization the system more extensively without the restrictions of multi-tenant systems.  In a multi-tenant system, you are sharing a database with others.  Multi-tenant systems place restrictions on the number of fields, modules, integrations, workflows that can be supported.</p>
<p><strong>SugarCRM Answer 1</strong>: SugarCRM is a single-tenant system.  Each company has their own database.    And with SugarCRM, you have you choose of where you want to have SugarCRM hosted: the SugarCRM cloud, private cloud, or your own network.</p>
<hr />
<p><strong>Answer 2:</strong>  With almost any other CRM system, the answer is yes.  Extra CRM functionality is additional cost.</p>
<p><strong>SugarCRM Answer 2:</strong> With SugarCRM regardless of the SugarCRM version, the CRM functionality is the same.    Differences in  versions is based upon <a href="http://www.sugarcrm.com/page/editions-pricing/en">additional support, storage, mobile, and platform options</a>.  But not CRM functionality.</p>
<hr />
<p><strong>Answer 3:</strong> Yes</p>
<p><strong>SugarCRM Answer 3:</strong>  There are no limits of any kinds: unlimited modules, unlimited fields, unlimited workflows, unlimited API calls/webservices.</p>
<hr />
<p><strong>Answer 4:</strong>  Some companies will charge you to get a copy of your data or give you a collection of CSV files 4 to 6 weeks later.  Some require that you run reports for each entity and export to Excel.  And some have no way of getting your data back to you.</p>
<p><strong>SugarCRM Answer 4</strong>: On request, SugarCRM will give you a copy of your database (not CSV files) and a copy of all the files associated to SugarCRM and at no charge!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/1122/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP and Microsoft SQL Server</title>
		<link>http://www.profilingsolutions.com/archive/php-and-microsoft-sql-server/</link>
		<comments>http://www.profilingsolutions.com/archive/php-and-microsoft-sql-server/#comments</comments>
		<pubDate>Fri, 16 Mar 2012 13:29:01 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Customization]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1098</guid>
		<description><![CDATA[There are several methods of getting a PHP-enabled web server talking to your Microsoft SQL Server database. Depending on your requirements and available PHP versions, extensions, though, it can be a tedious process. Effectiveness of a particular solution may vary based on versions of SQL Server and PHP. There are options, though, and I&#8217;ll detail [...]]]></description>
			<content:encoded><![CDATA[<p>There are several methods of getting a PHP-enabled web server talking to your Microsoft SQL Server database. Depending on your requirements and available PHP versions, extensions, though, it can be a tedious process. Effectiveness of a particular solution may vary based on versions of SQL Server and PHP. There are options, though, and I&#8217;ll detail a few methods I&#8217;ve used to get PHP working with MSSQL. Hopefully one of them will work for you.</p>
<p>First, I&#8217;d like to plug a really great software called <a title="WAMP" href="http://www.wampserver.com/en/" target="_blank">WAMP Server</a>. WAMP is a pre-packaged Apache Web Server, MySQL Server, and PHP installation. It&#8217;s intended for development purposes, but it can just as easily be sat on a production box after some minor configuration changes. The neat feature in WAMP is that you can download additional versions of PHP; switching between versions is easily done via right-clicking an icon in the Windows system tray. Additionally, PHP extensions can be toggled on or off from the same menu. That&#8217;s a big deal if you want to make sure your code works in PHP 5.1, 5.2 and 5.3, or even check PHP 4 support. That said, <a title="XAMPP" href="http://www.apachefriends.org/en/xampp.html" target="_blank">XAMPP</a> is a similar tool that has all of the functionality of Apache, MySQL and PHP bundled up, but it&#8217;s a little less easy to drop in support for separate versions of PHP.</p>
<p>Note that both of those software come packaged with MySQL Database Server. The point here is to use MSSQL, so you&#8217;ll probably want to disable the mysqld service.</p>
<h3>Option 1, mssql</h3>
<p>PHP actually has a pre-bundled extension <em>mssql</em> or <em>php_mssql</em>. This gives the developer the ability to connect to a database, run queries and return query results. Very nice, if you can get it to work. I&#8217;ve found that recent versions of PHP running on WAMP (specifically 5.2.9, 5.3.1, 5.3.4, 5.3.5) simply will not connect to my locally-installed MSSQL Server running 2008. Some versions don&#8217;t appear to have the php_mssql extension packaged. I don&#8217;t really know if this is a failure to compile things from the distributors of WAMP or if there&#8217;s a more-upstream issue, but it doesn&#8217;t work. What <em>does</em> work for me is WAMP and PHP Version 5.2.11. Grab it from <a title="WAMP's PHP 5.2.11" href="http://sourceforge.net/projects/wampserver/files/WampServer%202%20-%20Extensions/PHP/WampServer2-PHP5211.exe/download" target="_blank">WAMP&#8217;s Sourceforge Page</a>.</p>
<p>Switching to PHP 5.2.11 and enabling the php_mssql extension via the UI is all I had to do to make my mssql_connect and mssql_query functions work. The down-side is that I&#8217;m stuck in PHP 5.2 and miss out on some of the cool new functions in 5.3. </p>
<p>I have probably 10 different versions of PHP installed on my machine, and 5.2.11 is the only one that works. Your mileage may vary, I&#8217;m guessing drastically based on your version of SQL Server.</p>
<h3>Option 2, ODBC</h3>
<p>ODBC support is built in to every version of PHP since PHP4. It&#8217;s basically a standardized way of connecting to and working with databases, and it works great. The down side of ODBC is that it&#8217;s said to be slower than the new OLE-DB. I maintain one PHP-based portal using ODBC and customers do not complain; like everything else, performance very depends on your resources and requirements.</p>
<p>Using ODBC, you&#8217;ll have to specify a specific connection string. Here&#8217;s a quick way of doing that:</p>
<pre class="brush: php; title: ; notranslate">function db_connect($host,$user,$pass,$db){
	// This connection string is used on the production box, Windows Server 2003
	// and SQL Server (hosted spearately but also Win 2003) version 2005
	$dsn = &quot;Driver={SQL Native Client};Server=$host;Database=$db; Uid=$user;Pwd=$pwd;&quot;;
	// This is a more generic one I use with to dev with, Windows 7 and SQL Server 2008
	$dsn = &quot;Driver={SQL Server};Server=$host;Database=$db&quot;; // only for dev. purposes

	try{
		$conn = odbc_connect($dsn, $user, $$pass);
	}catch (Exception $e){
		die('Could not connect to database.');
	}
	return $conn;
}</pre>
<h3>Option 3, OLE DB and/or Application-Specific Providers</h3>
<p>I recently worked with a Sage SalesLogix portal that needed to take advantage of some application-specific functions within an OLE DB Provider shipped from Sage. I was capable of using the MSSQL database functions directly with ODBC or mssql with above methods, but to access the extra functions I had to use their provider. This can only be done using Windows boxes because we must leverage the PHP <a href="http://us.php.net/COM" title="PHP COM class" target="_blank">COM Class</a>. This works similarly to the ODBC connection but methods&#8217; names are a bit different and, in my opinion, less intuitive. Here&#8217;s a sample from my database-connecting class that used an OLE DB-based COM Connection.</p>
<pre class="brush: php; title: ; notranslate">class oledb_database{
	var $user;
	var $pass;
	var $db;
	var $connection_string = 'Provider=SLXOLEDB.1;Data Source=localhost;Initial Catalog=$db;User Id=$user;Password=&quot;$pass&quot;;Persist Security Info=True;Extended Properties=&quot;PORT=1706;LOG=ON;&quot;';
    var $rows_count;

    function connect(){
        if(!class_exists('COM')){
            die(&quot;COM Class could not be found. Please run system from a Windows-based PHP system.&quot;);
        }
        $conn = new COM(&quot;ADODB.Connection&quot;) or die(&quot;Cannot start ADO&quot;);
        global $config;
        try {
            $conn-&gt;Open($connection_string);
            $this-&gt;link = $conn;
            return true;
        } catch (Exception $e) {
            echo 'Caught exception: ',  $e-&gt;getMessage(), &quot;&lt;br&gt;\n&quot;;
            return false;
        }
    }
    function query($query){
        try {
            $this-&gt;result = $this-&gt;link-&gt;Execute($query);
            $this-&gt;rows_count = $this-&gt;result-&gt;Fields-&gt;Count();
            return $this-&gt;result;
        } catch (Exception $e){
            echo 'Caught exception: ',  $e-&gt;getMessage(), &quot;&lt;br&gt;\n&quot;;
            echo &quot;&lt;h3&gt;$query&lt;/h3&gt;&quot;;
            die();
        }
    }
}</pre>
<p>The OLE DB method felt much more cumbersome, but in the end it had nice exception handling and worked fine (once I got the connection string right). </p>
<h3>Conclusion</h3>
<p>Your options are native mssql support if you can manage it, classic ODBC and or modern OLE DB connections. Surely one of these methods will allow you to connect and work with your data. </p>
<p>There is one final method for connecting to MSSQL databases that I am aware of, and it is FreeTDS. This is really a project geared to getting MSSQL connectivity supported in Linux-based Apache systems and is known to be difficult to work with. If you must use a Microsoft SQL Server database, you will have a easier time with things if you work with a Windows-based Apache and PHP configuration with one of the above methods.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/php-and-microsoft-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating Saleslogix IDs in PHP</title>
		<link>http://www.profilingsolutions.com/archive/creating-saleslogix-ids-in-php/</link>
		<comments>http://www.profilingsolutions.com/archive/creating-saleslogix-ids-in-php/#comments</comments>
		<pubDate>Wed, 07 Mar 2012 14:05:11 +0000</pubDate>
		<dc:creator>Matthew Poer</dc:creator>
				<category><![CDATA[SalesLogix]]></category>

		<guid isPermaLink="false">http://www.profilingsolutions.com/?p=1068</guid>
		<description><![CDATA[One of the fundamental aspects of working with any particular database-driven system is to understand how to properly create new records, and the most crucial aspect of that, as any amateur or pro DBA knows, is using proper table IDs. The Saleslogix ID system is 12 characters long, compromised of a leading-letter code to identify [...]]]></description>
			<content:encoded><![CDATA[<p>One of the fundamental aspects of working with any particular database-driven system is to understand how to properly create new records, and the most crucial aspect of that, as any amateur or pro DBA knows, is using proper table IDs. The Saleslogix ID system is 12 characters long, compromised of a leading-letter code to identify the record to a particular table, a 4-character &#8220;site code&#8221; and a 7-character base-36 encoded incrementing numerical ID string. The most-recent IDs for a given module are kept in a <strong>sitekeys</strong> table for reference for the next record. Don&#8217;t panic. It&#8217;s not that bad.<span id="more-1068"></span></p>
<p>First-off, give the Background section of the article <a href="http://www.slxdeveloper.com/page.aspx?action=viewarticle&amp;articleid=87" target="_blank">Creating SalesLogix Table ID Values</a> by Ryan Farley. This will expand a bit how the ID-string is composed. Don&#8217;t bother to read into the functions and methods of creating IDs. Ryan is writing from the perspective of a Saleslogix Developer and has access to nifty functions inside the system that automatically generate IDs (as most systems do). But, being that you&#8217;re writing this in PHP, presumably for some portal or integration, you&#8217;re not inside Saleslogix and thus do not have access to those nifty functions (unless you&#8217;re opting to work with the Saleslogix OLE DB Provider on a WinPHP System &#8230; more on that later). We&#8217;ll have to create our own function go generate these IDs.</p>
<p>First-off, recall that the first character of the ID will be module-specific (or entity-specific, or table-specific), i.e. all Account records start with &#8220;A&#8221; and all Contact records start with &#8220;C&#8221; and all &#8220;Other&#8221; records start with &#8220;Q.&#8221; Reference <strong>sitekeys.KEYDESC</strong> for more of these. If you&#8217;re note sure what your leading-letter ought to be, just look at the IDs of some existing records of your particular module type.</p>
<p>Next the site code. Again we look at our surroundings. Site codes designate the database used to create the record. Keep in mind that Saleslogix systems will have several databases, one for each client and one on the server. For the purposes of integrations and portals, find the site code for the server itself and use this. Use the <strong>siteoptions</strong> table for reference.</p>
<p>Now the automatically-incrementing, base-36 encoded part. We&#8217;ll use the standard PHP function <a href="http://us2.php.net/base_convert" target="_blank">base_convert</a> heavily here to decode the last-used ID and re-encode it after incrementing.</p>
<p>The last piece of the puzzle is the keytype. Key types aren&#8217;t part of the ID string itself, but are a way of referencing the auto-increment log in the sitekeys table. Given a keytype and sitecode we will be able to determine the desired key.</p>
<p>With all that said, I&#8217;ve come up with three methods to aide the creation of Saleslogix GUIDs. I offer these as an example and in the spirit of Open Source (also in the spirit of Open Source, please refer to article 11 of the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt" target="_blank">GPLv2</a> for notes on how I feel about supporting this code).</p>
<pre class="brush: php; title: ; notranslate">    public function create_guid($single_char,$site_code,$keytype){
        $current_string_base36 = $this-&gt;retrieve_last_key($site_code,$keytype);
        $current_string_base10 = base_convert($current_string_base36,36,10);
        $next_string_base10 = $current_string_base10 + 1;
        $next_string_base36 = base_convert($next_string_base10,10,36);
        $next_string_base36 = strtoupper($next_string_base36);

        $this-&gt;put_new_key_into_sitekeys($site_code,$keytype,$next_string_base36);

        $newId = $single_char.$site_code.$next_string_base36;

        return $newId;
    }

    private function put_new_key_into_sitekeys($sitecode,$keytype,$newvalue){
        global $db;
        $query = &quot;update sysdba.sitekeys set keyvalue = '$newvalue'
        where sitecode = '$sitecode' and keytype = '$keytype';&quot;;
        $db-&gt;query($query);
        return true;
    }

    private function retrieve_last_key($sitecode,$keytype){
        global $db;
        $query = &quot;select keyvalue from sysdba.sitekeys
        where sitecode = '$sitecode' and keytype = '$keytype'&quot;;
        $result = $db-&gt;query($query);
        while($row = $db-&gt;results_by_array($result)){
            return $row[0]['keyvalue'];
        }

        return false;
    }</pre>
<p>Now, to put that to use, we could have these methods built into a Notes class (or even better, a Basic class that the Notes and other classes can extend).</p>
<pre class="brush: php; title: ; notranslate">require_once('modules/basic.php');
class note extends basic{
    var $tablename = 'ticketactivity';
    var $id;
    function save($note,$ticketid){
        $this-&gt;id = $this-&gt;create_guid('Q','6UJ9','25');
        ...
    }
}</pre>
<p>In the above examples, I also have a global <strong>$db</strong> object that is a database-helper I created to connect to the database directly and run and process queries to it. You can create one too, or call queries directly with <a href="http://us2.php.net/mssql_query" target="_blank">mssql_query</a>. My helper object is really just an abstracted front-end to <a href="http://us.php.net/mssql_connect" target="_blank">mssql_connect</a>, <a href="http://us.php.net/mssql_query" target="_blank">mssql_query</a> and <a href="http://us.php.net/mssql_fetch_assoc" target="_blank">mssql_fetch_assoc</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.profilingsolutions.com/archive/creating-saleslogix-ids-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

