• Cwestonr
  • NEWBIE
  • 0 Points
  • Member since 2008

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 3
    Questions
  • 5
    Replies

I have built a sample way to integrate the Salesforce API  with CakePHP.

 

The zip package is at http://www.contangoadvisors.com/work/SalesforceCakePHPdatasource.zip

 

This Datasource is for a Salesforce Enterprise implementation
to use the other types you will have to modify the code.

 

 This Package requires you to have the Salesforce PHP Toolkit 13.0  or greater.
(http://wiki.developerforce.com/index.php/PHP_Toolkit)
I wrote this as a simple implementation of the Salesforce enterprise API for read and login

!!!!THIS PACKAGE IS NOT COMPLETE USE AS A STARTING POINT!!!!

 

 

 

You will want to extend the salesforce_source.php file with other methods for "upsert", "delete", etc.
(SEE NEXT MESSAGE: I have updated the code to support all of the WSDL functions including any that will be changed or added it is now included in the zip)

How to install this package:

1. Bake a CakePHP app ( see CakePHP.org) "app" refers your newly baked application's directory
2. Place the following files in your App.
    models/datasources/salesforce_source.php     in app/models/datasources/ (replace with salesforce_source.php in next message it is now included in the zip)
    config/database.php                                        in app/config/


    models/account.php                                        in app/models/ (use below if using new salesforce_source.php in next message now included in the zip)


<?php
class Account extends AppModel {

var $useDbConfig='sftest';
var $useTable = false;

function first10account() {
$SOQL = "SELECT
a.AccountNumber,
a.AnnualRevenue,
a.BillingCity,
a.BillingCountry,
a.BillingPostalCode,
a.BillingState,
a.BillingStreet,
a.CreatedById,
a.CreatedDate,
a.Description,
a.Fax,
a.FirstName,
a.Id,
a.Industry,
a.IsDeleted,
a.IsPersonAccount,
a.LastActivityDate,
a.LastModifiedById,
a.LastModifiedDate,
a.LastName,
a.MasterRecordId,
a.Name,
a.NumberOfEmployees,
a.OwnerId,
a.Ownership,
a.ParentId,
a.Phone,
a.Rating,
a.RecordTypeId,
a.Salutation,
a.Type,
a.Website
FROM Account a
WHERE IsDeleted = Null
Limit 10";
return $this->query(array('query',$SOQL)); // changed to support new datasource
}

}
?>



 

    controllers/mytest_controller.php                    in app/controllers/
    views/mytest directory                                    in app/views/

   Your copy of the Salesforce PHP Toolkit "soapclient/" directory is placed in app/models/datasources/
   
3. Download your enterprise.wsdl.xml from your Production salesforce instance
4. Download your enterprise.wsdl.xml from your Sandbox salesforce instance and name it test.enterprise.wsdl.xml
5. copy your enterprise.wsdl.xml and test.enterprise.wsdl.xml to  app/models/datasources/soapclient
6. Edit your app/config/database.php add your usernames and passwords for BOOTH Instances.
   (change sflive to default if needed.)

You can then test your connection by going to your new cake app in a web browser:

http://URL_OF_YOUR_CAKE_INSTANCE/mytest
you should see the first 10 accounts on your test instance of salesforce.

The Model for account SOBJ (app/models/account.php) contains a SOQL query.
The controller (app/controllers/mytest_controller.php) gets the result of the query method in the model and passes it to the view.
The View (app/views/mytest/index.ctp) iterates through the query result and displays the data in a table.

Message Edited by Cwestonr on 01-04-2010 10:08 AM

We have known for some time if <select mult.....> object size in the system is non functional  all multi selects are 3 high in visual force.

 

 

this java script will allow you to apply height to your vf select multi fields.

Place the following on the VF page at the end before the   :

</apex:form></apex:page>

 

The script that willl  set the height to 15 lines

 

 

 

 

 

<script language="JavaScript" type="text/javascript"> var selected=document.getElementById('{!$Component.idpath.idname}_selected'); var unselected=document.getElementById('{!$Component.idpath.idname}_unselected'); selected.size="15"; unselected.size="15"; </script>

 

</apex:form>
</apex:page>

 

 

 


 

I am trying to update some optional fields in Account via a popup HTML form.

here is the code I am trying to use I keep getting an error in the Salesforce connection javascript

Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
 <title>Test S-control</title>
 <script type="text/javascript" language="javascript" src="/js/functions.js"></script> 
        <script type="text/javascript" src="/soap/ajax/10.0/connection.js"></script>
 <script type="text/javascript" >

 function Save_form() {
  //save the data from the form
  var recObject = new sforce.SObject("Account");
                recObject.Id = "{!Account.Id}";
  recObject.Cash_for_Capitol_Call_Notes__c = document.form.Cash_for_Capitol_Call_Notes.value;
  recObject.Cash_Held_for_Capitol_Calls__c = document.form.Cash_Held_for_Capitol_Calls.value;
  recObject.Client_Requested_Restrictions__c = document.form.Client_Requested_Restrictions.value;
  //recObject.Client_Restriction_Date__c = sforce.connection.getServerTimestamp();
  var result = sforce.connection.update([recObject]);

  if (result[0].getBoolean("success"))  { 
   alert("Update worked "); 
   self.close();
  } else { 
   alert("Faild with " + result[0] + ". "); 
  } 
 } 
 </script>
</head>
<body>
html form follows...

 

I have built a sample way to integrate the Salesforce API  with CakePHP.

 

The zip package is at http://www.contangoadvisors.com/work/SalesforceCakePHPdatasource.zip

 

This Datasource is for a Salesforce Enterprise implementation
to use the other types you will have to modify the code.

 

 This Package requires you to have the Salesforce PHP Toolkit 13.0  or greater.
(http://wiki.developerforce.com/index.php/PHP_Toolkit)
I wrote this as a simple implementation of the Salesforce enterprise API for read and login

!!!!THIS PACKAGE IS NOT COMPLETE USE AS A STARTING POINT!!!!

 

 

 

You will want to extend the salesforce_source.php file with other methods for "upsert", "delete", etc.
(SEE NEXT MESSAGE: I have updated the code to support all of the WSDL functions including any that will be changed or added it is now included in the zip)

How to install this package:

1. Bake a CakePHP app ( see CakePHP.org) "app" refers your newly baked application's directory
2. Place the following files in your App.
    models/datasources/salesforce_source.php     in app/models/datasources/ (replace with salesforce_source.php in next message it is now included in the zip)
    config/database.php                                        in app/config/


    models/account.php                                        in app/models/ (use below if using new salesforce_source.php in next message now included in the zip)


<?php
class Account extends AppModel {

var $useDbConfig='sftest';
var $useTable = false;

function first10account() {
$SOQL = "SELECT
a.AccountNumber,
a.AnnualRevenue,
a.BillingCity,
a.BillingCountry,
a.BillingPostalCode,
a.BillingState,
a.BillingStreet,
a.CreatedById,
a.CreatedDate,
a.Description,
a.Fax,
a.FirstName,
a.Id,
a.Industry,
a.IsDeleted,
a.IsPersonAccount,
a.LastActivityDate,
a.LastModifiedById,
a.LastModifiedDate,
a.LastName,
a.MasterRecordId,
a.Name,
a.NumberOfEmployees,
a.OwnerId,
a.Ownership,
a.ParentId,
a.Phone,
a.Rating,
a.RecordTypeId,
a.Salutation,
a.Type,
a.Website
FROM Account a
WHERE IsDeleted = Null
Limit 10";
return $this->query(array('query',$SOQL)); // changed to support new datasource
}

}
?>



 

    controllers/mytest_controller.php                    in app/controllers/
    views/mytest directory                                    in app/views/

   Your copy of the Salesforce PHP Toolkit "soapclient/" directory is placed in app/models/datasources/
   
3. Download your enterprise.wsdl.xml from your Production salesforce instance
4. Download your enterprise.wsdl.xml from your Sandbox salesforce instance and name it test.enterprise.wsdl.xml
5. copy your enterprise.wsdl.xml and test.enterprise.wsdl.xml to  app/models/datasources/soapclient
6. Edit your app/config/database.php add your usernames and passwords for BOOTH Instances.
   (change sflive to default if needed.)

You can then test your connection by going to your new cake app in a web browser:

http://URL_OF_YOUR_CAKE_INSTANCE/mytest
you should see the first 10 accounts on your test instance of salesforce.

The Model for account SOBJ (app/models/account.php) contains a SOQL query.
The controller (app/controllers/mytest_controller.php) gets the result of the query method in the model and passes it to the view.
The View (app/views/mytest/index.ctp) iterates through the query result and displays the data in a table.

Message Edited by Cwestonr on 01-04-2010 10:08 AM

I'm not sure who is maintaining the PHP Toolkit code, but I keep coming across things that don't seem to make any sense (and they seem easily fixable). For example, I just downloaded PHP Toolkit 13.1 and tried to upsert a record into a custom object.

 

Of course, there's no sample code for the upsert method for the Enterprise client - only the Partner client and that sample doesn't work at all. Inside SforceEnterpriseClient.php's upsert method, "Contact" is literally hardcoded as the object type.

 

I changed the code from:

 

  public function upsert($ext_Id, $sObjects) {
    $arg = new stdClass;
    $arg->externalIDFieldName = new SoapVar($ext_Id, XSD_STRING, 'string', 'http://www.w3.org/2001/XMLSchema');
    foreach ($sObjects as &$sObject) {
      $sObject = new SoapVar($sObject, SOAP_ENC_OBJECT, 'Contact', $this->namespace);
    }
    $arg->sObjects = $sObjects;
    return parent::_upsert($arg);
  }

 

to:

 

  public function upsert($ext_Id, $sObjects,$objectType = "Contact") {
    $arg = new stdClass;
    $arg->externalIDFieldName = new SoapVar($ext_Id, XSD_STRING, 'string', 'http://www.w3.org/2001/XMLSchema');
    foreach ($sObjects as &$sObject) {
      $sObject = new SoapVar($sObject, SOAP_ENC_OBJECT, $objectType, $this->namespace);
    }
    $arg->sObjects = $sObjects;
    return parent::_upsert($arg);
  }
 

That seems to solve the problem - I simply pass the custom object's name as the third argument, and the field list array as the second argument, and it works just fine. Why can't SalesForce just make that the default behavior? It's been hardcoded for years now... (and nobody's ever bothered to fill out the rest of the PHP Toolkit documentation)

I am trying to update some optional fields in Account via a popup HTML form.

here is the code I am trying to use I keep getting an error in the Salesforce connection javascript

Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
 <title>Test S-control</title>
 <script type="text/javascript" language="javascript" src="/js/functions.js"></script> 
        <script type="text/javascript" src="/soap/ajax/10.0/connection.js"></script>
 <script type="text/javascript" >

 function Save_form() {
  //save the data from the form
  var recObject = new sforce.SObject("Account");
                recObject.Id = "{!Account.Id}";
  recObject.Cash_for_Capitol_Call_Notes__c = document.form.Cash_for_Capitol_Call_Notes.value;
  recObject.Cash_Held_for_Capitol_Calls__c = document.form.Cash_Held_for_Capitol_Calls.value;
  recObject.Client_Requested_Restrictions__c = document.form.Client_Requested_Restrictions.value;
  //recObject.Client_Restriction_Date__c = sforce.connection.getServerTimestamp();
  var result = sforce.connection.update([recObject]);

  if (result[0].getBoolean("success"))  { 
   alert("Update worked "); 
   self.close();
  } else { 
   alert("Faild with " + result[0] + ". "); 
  } 
 } 
 </script>
</head>
<body>
html form follows...

 

I have created a Contact trigger that follows very closely to the cookbook Lead Duplicate Preventer code base.  It works fine and I have been able to deploy it to my production environment.  Now, I have some users that get the Query Exception error, and others that do not, even when adding the same new contact to the same account.  I can replicate this in both Dev and production, but can't figure out what the difference between users is, or what the user would have to do with the way the query executes.  I know the email field is not indexed, and that might be part of the problem, but am unclear as to why some users can execute successfully, and others get the error.  I hope that someone can help, and that this might be a good trigger that the entire SFDC Community can leverage.
Code is below!
Regards,
Jim Rae
 
 
Code:
TRIGGER CODE:

trigger ContactDuplicatePreventor on Contact (before insert, before update) {

    Map<String, Contact> ContactMap = new Map<String, Contact>();

    for (Contact contact : System.Trigger.new) {    

        // Make sure we don't treat an email address that
        // isn't changing during an update as a duplicate.

        if ((Contact.Email != null) && (System.Trigger.isInsert || (Contact.Email != System.Trigger.oldMap.get(Contact.Id).Email))) {
    
            // Make sure another new Contact isn't also a duplicate

            if (ContactMap.containsKey(Contact.Email)) {
                String errortext = 'Another new Contact has the same email address. ('+Contact.Email+') Please search for the existing Contact record with this address and update as appropriate, or contact your Administrator for assistance';
                Contact.Email.addError(errorText);
            } else {
                ContactMap.put(Contact.Email, Contact);
            }
        }
    }

    // Using a single database query, find all the Contacts in
    // the database that have the same email address as any
    // of the Contacts being inserted or updated.
 for(String test:ContactMap.keySet()){
 system.debug('\n\nContact added to Map was:'+test);  //only here for testing purposes
 system.debug('\n\nUser running trigger is:'+UserInfo.getUserName());
 system.debug('\n\n'+UserInfo.getProfileId());
 }
    for (Contact contact : [SELECT Email FROM Contact WHERE isDeleted = false and Email != null and Email IN :ContactMap.KeySet()]) {
        SYstem.debug('In the test loop');
        Contact newContact = ContactMap.get(Contact.Email);
  String errortext = 'Another Contact has the same email address. ('+newContact.Email+')  Please search for the existing Contact record with this address and update as appropriate, or contact your Administrator for assistance';
        newContact.Email.addError(errorText);
    }

TEST CASE CODE:
public class testBlockDuplicateContactEmails {
 
 static testMethod void testDuplicateContactEmailTrigger(){  
 
  //Creating all records against "Acme Corporation - HQ" Account (00100000002qK3l)
  Contact[] smith1 = new Contact[]{
   new Contact(  Email='smith@acme.org', LastName='Smith', Accountid='00100000002qK3l' )
  };
  insert smith1;  // add a known Contact
  
  Contact[] smith2 =new Contact[]{
   new Contact(  Email='smith@acme.org', LastName='Smith', Accountid='00100000002qK3l' )
  };
  // try to add a matching lead
  try {
   insert smith2;
   } catch (System.DmlException e) { 
   String errortext1 = 'FIELD_CUSTOM_VALIDATION_EXCEPTION, Another Contact has the same email address';
   system.debug('INSERT ERROR MESSAGE IS:'+e.getMessage());
   system.assert(e.getMessage().contains(errortext1), e.getMessage());
  }
  
  // test duplicates in the same batch for bulk Contact loading or lead conversion
  Contact[] bulkcontacts =new Contact[]{
   new Contact(  Email='Johnson@acme.org', LastName='Johnson', Accountid='00100000002qK3l' ),
   new Contact(  Email='Johnson@acme.org', LastName='Johnson', Accountid='00100000002qK3l' )
  };  
  try {
   System.debug('\n\n Insert Test');
    insert bulkcontacts;
    } catch ( System.DmlException e) { 
   String errortext2 = 'FIELD_CUSTOM_VALIDATION_EXCEPTION, Another new Contact has the same email address';   
   system.assert(e.getMessage().contains(errortext2), e.getMessage());
  }
  
  // test update also
  Contact[] contactup = new Contact[]{
   new Contact(  Email='jones@acme.org',  LastName='Jones', Accountid='00100000002qK3l' )
  };
  System.debug('\n\n Update Test');
  insert contactup;
  Contact updatetest = [ select id,Email from Contact where Email = 'jones@acme.org' and Accountid='00100000002qK3l' limit 1];
  system.assert(updatetest!=null);
  updatetest.Email = 'smith@acme.org'; 
    
  try { update updatetest; } catch ( System.DmlException e) { 
   String errortext3 = 'FIELD_CUSTOM_VALIDATION_EXCEPTION, Another Contact has the same email address';
   system.debug('UPDATE ERROR MESSAGE IS:'+e.getMessage());
   system.assert(e.getMessage().contains(errortext3), e.getMessage()); 
  }
  // Try a null email address
  Contact[] contactnull = new Contact[]{
   new Contact(  LastName='Anderson', Accountid='00100000002qK3l' )
  };
  System.debug('\n\n Null Test');
  try{ insert contactnull;} catch( System.DmlException e){
   system.debug('\n\nNull Insert ERROR MESSAGE IS:'+e.getMessage());
  }
  // Try a null email address Update
  Contact[] contactnull2 = new Contact[]{
   new Contact(  LastName='Anderson', Accountid='00100000002qK3l' )
  };
  System.debug('\n\n Null Update Test');
  insert contactnull2;
  Contact updatetest2 = [ select id,Email from Contact where Email=null and LastName = 'Anderson' and Accountid='00100000002qK3l' limit 1];
  system.assert(updatetest!=null);
  updatetest2.FirstName = 'Hans'; 
    
  try { update updatetest2; } catch ( System.DmlException e) { 
   system.debug('UPDATE ERROR MESSAGE IS:'+e.getMessage());
    
  }
 }
}