Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Salesforce Client Bundle Laravel Package

localfr/salesforce-client-bundle

Symfony bundle that wires a Salesforce API client into your PHP application, providing ready-made service definitions and configuration so you can authenticate and query Salesforce from your own code with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Do the reality check first. localfr/salesforce-client-bundle is a Symfony bundle: it extends Symfony\Component\HttpKernel\Bundle\Bundle and ships DependencyInjection/Configuration.php plus a Resources/config/services.yaml. Laravel has no bundle loader, so composer require inside a Laravel app gives you classes you must wire by hand — not a working integration, and no SalesforceClient facade will appear. Treat this repo as a reference implementation of a Salesforce auth/API client and a source of code you can lift, not as a drop-in dependency.

Minimal steps that actually work:

  1. composer require localfr/salesforce-client-bundle and run composer show localfr/salesforce-client-bundle. The require block tells you which underlying client package is doing the real work (likely localfr/salesforce-client or phpforce-style HTTP wrapper). That inner package is what you actually bind in Laravel; the bundle is just DI glue.
  2. Open DependencyInjection/Configuration.php before anything else. It is the authoritative list of credential/config keys — consumer key, consumer secret, username, password, security token, login/instance URL, API version. Every key you'll put in config/services.php is defined there.
  3. Check the service definition that constructs the client. It shows the constructor arguments, the PSR-18/HttpClientInterface it uses, and whether a cache/token-storage adapter is wired in.
  4. Ignore the bundle class itself. It only registers compiler passes and config; nothing transferable to Laravel.

First use case — authenticate and query. The classic flow is the OAuth2 username-password grant with the security token appended to the password. Wire it once in a service provider:

// config/services.php
'salesforce' => [
    'login_url'      => env('SF_LOGIN_URL', 'https://login.salesforce.com'),
    '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'),
    'version'        => env('SF_API_VERSION', 'v59.0'),
],
// AppServiceProvider::register()
$this->app->singleton(SalesforceClient::class, fn ($app) =>
    new SalesforceClient($app['config']->get('salesforce'))
);

Then hit GET /services/data/{version}/query?q=SELECT+Id,+Name+FROM+Account+LIMIT+10 with Authorization: Bearer {access_token}.

Implementation Patterns

Pattern A — extract the client, drop the bundle. Vendor the HTTP/auth class from the package into app/Services/Salesforce/ (MIT license makes this fine) and bind it in a service provider. You keep the battle-tested request/response handling and lose the Symfony container coupling. This is the path most Laravel shops take.

Pattern B — Symfony sidecar. Stand up a 200-line Symfony app with this bundle installed, expose two or three JSON endpoints (/query, /upsert), and call it from Laravel with Http::withToken(config('sidecar.token')). Worth it only if you need the bundle's Bulk API or streaming support and don't want to reimplement it.

Pattern C — token caching with a retry layer. Salesforce access tokens expire (typically ~2h) and the API returns 401 with INVALID_SESSION_ID. Cache the token in Laravel's cache under the instance URL key, and use Http::retry(2, 100)->beforeSending() or a small PendingRequest macro that catches 401, refreshes, and replays once. Do not re-authenticate per request; login calls count against limits.

Pattern D — queued sync jobs with external-ID upserts. Dispatch SyncContactToSalesforce jobs on ->onQueue('salesforce'). Use PATCH /sobjects/Contact/External_Id__c/{value} so retries are idempotent. Map Eloquent models to SObjects with a toSalesforce(): array method and $casts for dates/booleans — Salesforce rejects '1' where it expects true.

Pattern E — choose the right API. Under ~200 records use the Composite API (/composite/sobjects) to batch in one round trip. Above that, use Bulk API 2.0 (/jobs/ingest) and poll state until JobComplete. Do not loop 5,000 single-record REST calls; you'll burn the daily API allocation and time out workers.

Pattern F — test with Http::fake(). Because the client ultimately speaks HTTP, you can stub /services/data/* responses and assert your mapping layer without touching a sandbox org. Keep one integration test against a Salesforce Developer Edition behind an env flag.

Pattern G — inbound webhooks/Outbound Messages. Salesforce Outbound Messages are SOAP; newer orgs use Platform Events or Flow HTTP callouts. Receive them in a controller, verify the shared secret, and dispatch() immediately — never process inline.

Gotchas and Tips

  • Security token is not optional. With the username-password flow, the password sent is literally password + security_token. Forgetting this produces INVALID_LOGIN and hours of confusion. If your org IP-relaxes the token, it's blank — but don't assume.
  • SOQL injection. Never interpolate user input into q=. Bind via the query endpoint's parameters or escape ', \, and control chars. The Symfony bundle doesn't protect you here and neither will a naive port.
  • Field casing is strict. Id, Name, CreatedDate, MyField__c. id returns INVALID_FIELD. Normalize keys on the way in and out; don't rely on Str::camel for the outbound payload.
  • Pin the API version. The bundle's default version will drift from what you tested. Set SF_API_VERSION explicitly and upgrade deliberately — Salesforce retires versions on a published schedule.
  • Rate limits and API allocation. Every org has a 24h request budget visible at /services/data/vXX.X/limits. Instrument your client with a counter and log Sforce-Limit-Info response headers. Batch aggressively.
  • Bulk API is asynchronous. POST /jobs/ingest returns a job ID; you must poll GET /jobs/ingest/{id} until JobComplete, then fetch successfulResults/failedResults CSVs. Don't assume the 200 means records landed.
  • Symfony version constraints. If you go sidecar, check the bundle's symfony/* constraints against your PHP version before committing — the Jan 2025 release targets Symfony 6/7, and this package has zero dependents, so nobody else has hit the edge cases for you.
  • No community, no docs. Zero stars, zero dependents, single maintainer. Budget for reading source rather than Stack Overflow. The upside: MIT license and a small surface area — you can own a fork comfortably.
  • Extension points don't translate. The bundle exposes Symfony compiler passes and service overrides for customization. In Laravel the equivalents are $this->app->extend() and constructor injection — don't try to mimic the bundle's tag-based wiring.
  • Debugging. Log raw request/response bodies at debug level behind a SF_DEBUG flag, redacting Authorization. The failure modes are almost always auth (token/credentials), field names, or validation rules — the raw 400 body tells you which, and Laravel's Http::dd() is your fastest tool.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo