Installation
composer require coffeebike/salesforce-bundle
Add to config/bundles.php:
CoffeeBike\SalesforceBundle\CoffeeBikeSalesforceBundle::class => ['all' => true],
Configuration Publish the default config:
php bin/console config:dump-reference CoffeeBikeSalesforceBundle
Update config/packages/coffee_bike_salesforce.yaml with your Salesforce credentials:
coffee_bike_salesforce:
client_id: '%env(SF_CLIENT_ID)%'
client_secret: '%env(SF_CLIENT_SECRET)%'
username: '%env(SF_USERNAME)%'
password: '%env(SF_PASSWORD)%'
security_token: '%env(SF_SECURITY_TOKEN)%'
domain: 'login' # or 'test' for sandbox
First Use Case: Querying Accounts
Inject the SalesforceClient service and execute a SOQL query:
use CoffeeBike\SalesforceBundle\Client\SalesforceClient;
class AccountService {
public function __construct(private SalesforceClient $sfClient) {}
public function getAccounts(): array {
return $this->sfClient->query('SELECT Id, Name FROM Account LIMIT 10')->getRecords();
}
}
Authentication & Session Management
SalesforceClient to ensure sessions persist across requests.$this->sfClient->refreshAccessToken();
CRUD Operations
create() with an associative array of field-value pairs.
$account = $this->sfClient->create('Account', [
'Name' => 'Acme Corp',
'Industry' => 'Technology'
]);
query() for SOQL or get() for single records by ID.
$account = $this->sfClient->get('Account', '001XXXXXXXXXXXX');
update() with the record ID and field updates.
$this->sfClient->update('Account', '001XXXXXXXXXXXX', ['Name' => 'Acme Inc']);
delete() with the record ID.
$this->sfClient->delete('Account', '001XXXXXXXXXXXX');
Bulk Operations
bulkQuery() and bulkQueryJobResults() for large datasets:
$jobId = $this->sfClient->bulkQuery('SELECT Id FROM Account');
$results = $this->sfClient->bulkQueryJobResults($jobId);
Metadata API
$objects = $this->sfClient->describe()->getSobjects();
salesforce.before_request and salesforce.after_response events for logging or custom logic.$this->sfClient->setCache($cacheItemPool);
SalesforceApiException:
try {
$this->sfClient->query('INVALID_SOQL');
} catch (SalesforceApiException $e) {
// Handle error (e.g., log or retry)
}
Authentication Failures
SalesforceApiException:
# config/packages/monolog.yaml
handlers:
salesforce:
type: stream
path: "%kernel.logs_dir%/salesforce.log"
level: debug
php bin/console debug:container coffee_bike_salesforce.client
SOQL Limitations
Rate Limiting
QUOTA_EXCEEDED errors.$this->sfClient->setRetryPolicy(new ExponentialBackoffRetryPolicy());
Sandbox vs. Production
login vs. test) can cause authentication failures.# config/packages/coffee_bike_salesforce.yaml
coffee_bike_salesforce:
domain: '%env(SF_DOMAIN)%' # Set via .env
debug in config/packages/coffee_bike_salesforce.yaml:
coffee_bike_salesforce:
debug: true
$this->sfClient->setEventDispatcher($dispatcher);
$dispatcher->addListener('salesforce.after_response', function (AfterResponseEvent $event) {
file_put_contents(
'sf_response.log',
print_r($event->getResponse()->getBody(), true)
);
});
Custom API Calls
Override the HttpClient implementation to add headers or modify requests:
$this->sfClient->setHttpClient($customHttpClient);
Example with Guzzle:
$client = new \GuzzleHttp\Client([
'headers' => ['X-Custom-Header' => 'value']
]);
Custom Serializers
Extend the SalesforceResponse class to handle custom Salesforce responses:
$this->sfClient->setResponseFactory(new CustomSalesforceResponseFactory());
Bulk API Extensions
Implement a custom BulkQueryJob class to handle large datasets with progress tracking:
$this->sfClient->setBulkQueryJobFactory(new CustomBulkQueryJobFactory());
security_token (often found in Salesforce under "Reset My Security Token") is required for username-password authentication. Omitting it will cause authentication failures.domain config must match your Salesforce instance URL (e.g., login.salesforce.com or test.salesforce.com). Incorrect values will fail authentication..env variables are loaded:
php bin/console cache:clear
How can I help you explore Laravel packages today?