BitBucket is awesome, for unlimited free private repositories, you just can’t go wrong.  In two minutes you can get your website code for any project safely to their repositories, accessible from any where.  Of course, it has its limitations.  Take one instance where last week I committed revisions to ProflicFutility.com, a media-heavy website that sells stock video, images, etc, among other business media and services.  I accidentally forgot to exclude the media, so all these .mp4, video files, and stock photos were uploaded to the repository and exceeded the 2 GB limit for free repos.  On top of that, I also committed a bunch of useless files and folders from the Symfony cache, too.

This is where I usually have a ready-to-go .gitignore file in place in the web root to make sure that doesn’t happen, but I didn’t copy my template .gitignore file in there so I started getting “repository exceeded storage limits” notifications from BitBucket.

Also, in your .gitignore you can get the latest documentation from its built in help function on the command line:  “git help gitignore“.

The best way I found to exclude all files of a certain type is to create a .gitignore file in your web root and use wildcards.

So, to ignore all *.log files in any subfolder, use:

*.log

To ignore all files in a specific subfolder, use the “/**/" path wildcard after the sub folder.  So, perhaps in Symfony you don’t want anything in your app/ cache folders committed to your repo, you’d use:

 /app/*/cache/**/

Remember the paths in .gitignore are all relative to that .gitignore file!


To conform a datetime field to just a date in your results and make it easy to group TIMESTAMP fields in the format “2015-12-25 12:23:23” so you can group any datetime value into actual days for daily reports, use “DATE_FORMAT” below:

DATE_FORMAT(datetime_field, '%Y-%m-%d')

In other words, if you have values from a SELECT statement that are date AND time stamps and you want to group all those values into the DAY, DATE_FORMAT converts the value for you.

So, with these values in the field “created_at”:

2015-03-01 11:11:11
2015-03-01 16:13:132015-03-01 19:01:01
2015-03-03 11:19:23

The following MySQL SELECT statement

SELECT DATE_FORMAT(created_at,'%Y-%m-%d') as created_at_days FROM your_table GROUP BY created_at_days

Will result in the following results:
2015-03-01
2015-03-03


InfusionAPI call ORDER BY specific fields works, with a little finagling.  As usual, the InfusionSoft API documentation is spotty, but reverse engineering its PHP SDK, I found the “dsQueryOrderBy()” method in the InfusionSoft API, even though the documentation has it as dsQueryWithOrderBy() which you will find 500’s with “method does not exist”.  Remove “with” and presto, works like a charm!

public function fetchLatestInfusionList($limit=300,$page=0,$orderBy='LastUpdated',$ascBool=false){
   /**
    *  This will look through InfusionSoft to check for records that were most recently added that weren't sync'd with MailChimp
    *  ordered by most recent
    *
    *  $ascBool = true ASC, false DESC
    *
    *  $returnFields = array('Id','ShipFirstName', 'ShipLastName');
       $query = array('DateCreated' => $date);
       $jobs = $app->dsQuery("Job", 10, 0, $query, $returnFields);
    *
    * $results = $app->dsQueryWithOrderBy(
               'Contact', 10, 0,
               array('FirstName' => 'A%'),
               array('Id','Email','FirstName','LastName'),
               "FirstName",true);

    */

   // First, get a list of the last 300 contacts added to InfusionSoft without a 'externalSyncDate' field
   $query = array('_externalSyncDate'=>'~null~');
   $returnFields = array('Id','FirstName','LastName','Email','Phone1','City','State','PostalCode');

   $results = $this->infObj->dsQueryOrderBy(
            'Contact', $limit, $page,
            $query,
            $returnFields,
            $orderBy,$ascBool);   // false here is DESC since true is ASC for this query

   return $results;
   // InfusionSoft contacts NOT in Mail Chimp are priority, then updating contacts is second

}

Use the results to capture the latest contacts imported into InfusionSoft so you can synchronize only the contact records that would be missing and automatically pass these results into other platforms you use, like My Emma or Mail Chimp.  To make things even more effective, create a new field called “externalSyncDate” that you can then use to track and mark when the record was synchronized last to your external platforms so you can avoid repeatedly sending the same records to your API.  This is a very efficient way to only touch records that require synchronization, using InfusionSoft’s custom fields as the database to log those synchronization actions within each contact record.  Make that CRM earn its money, after all, you’re overpaying for it, right?

Any organizations/businesses in the Jacksonville Northeast Florida area looking for open source PHP web developers with experience in Symfony, Drupal, WordPress, Magento, or API integration experts, please contact me.  I have a list of competent web developers who I can recommend here in Jacksonville, Southwest Florida, and throughout the US, Canada, UK, Australia, and Germany as temporary web development consultants or remote web developers!


Virtual Box on Windows 10 suddenly throwing new error “VERR_LDR_MISMATCH_NATIVE”.

If you encounter this, deactivate your virus protection and firewall and try to restart.  Seems to work fine after turning virus protection back on again but whitelisting all Virtual Box apps should prevent this from happening in the future.  It’s confirmed that even though I use Avast for this particular server the same issue for McAfee and Norton have been reported.


Sometimes it’s obvious a company has a decent software product but there’s one part of their development they don’t put enough time and resources into.  For InfusionSoft, it’s their documentation, support, and their API.  It’s a pretty powerful tool for normal companies, like WordPress is great for most websites, but your company isn’t like most companies, is it?

All built-in InfusionSoft database table field names for any contact record and other records, like for campaigns, vendors, etc can be found at:  https://developer.infusionsoft.com/docs/table-schema/

Apparently, the two guys in the garage that cobbled this CRM together initially before handing it over to a larger team of developers now stuck in the initial constraints of the system they designed set some immovable and immutable rules that leaves any web developer with the sense of when using their API they’re dealing with some pretty old technology and design concepts that just won’t go away for the sake of better usability, speed, and stability.  The irony here is that if InfusionSoft improved their API, documentation and sped their platform up they would get more customers and make more money.

When searching for an InfusionSoft custom field that you want to check if it’s empty, you can use the search value of “~null~”, which the InfusionSoft developers created to define a blank field.

$queryArr = array('_customField'=> '~null~' );
$returnFieldsArr= array('Id','Email','LastName','Phone');
$resultsArr=$app->dsQuery("Contact",99,0,$queryArr,$returnFieldsArr);

This will return all contact records that were never populated with a value before, whatever the “_customField” for your system is.

Remember that ALL CUSTOM FIELDS in InfusionSoft are accessed with a leading underscore (“_”), by the way.   It’s not our place to ask why, that’s just the way they designed the system.

The code below will find all contact records at least once had the custom field populated but is currently empty or null:

$queryArr = array('_customField'=>'' );
$returnFieldsArr= array('Id','Email','LastName','Phone');
$contacts=$app->dsQuery("Contact",99,0,$queryArr ,$returnFieldsArr);

You only need to use the “~null~” parameter in these InfusionSoft API queries for your custom fields, of course, right?!  Why not “tilde null tilde”?!  Good grief…  For InfusionSoft’s standard fields, you can use the familiar empty string “” query and that will return all currently empty values, regardless if it they were ever populated or not.  InfusionSoft is a bit clunky and behind the times in some ways, in other ways, you may find it is a useful tool for your company.  I think it’s overpriced, but most CRMs are.  Look into Open ERP first, I think it’s still free though I see it was taken over by Odoo.  InfusionSoft’s just not meant to be strong and flexible for companies that have challenges more diverse than the cookie cutter solutions they provide, companies with many different groups of contacts, customers, and data sets may find their API is too slow to interface with their database and systems.