PHPackages                             lyonstahl/salesforce - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. lyonstahl/salesforce

ActiveLibrary[HTTP &amp; Networking](/categories/http)

lyonstahl/salesforce
====================

A library that provides a simple and intuitive way to interact with Salesforce API

1.0.0(2y ago)061Apache-2.0PHPPHP &gt;=7.3

Since Sep 28Pushed 2y agoCompare

[ Source](https://github.com/lyonstahl/salesforce)[ Packagist](https://packagist.org/packages/lyonstahl/salesforce)[ RSS](/packages/lyonstahl-salesforce/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (2)Versions (2)Used By (0)

Salesforce REST API Client
==========================

[](#salesforce-rest-api-client)

Installation
------------

[](#installation)

Ensure you have [composer](http://getcomposer.org) installed, then run the following command:

```
composer require lyonstahl/salesforce

```

That will fetch the library and its dependencies inside your vendor folder.

If you want a simple API for bulding SOQL queries, we suggest [lyonstahl/soql-builder](https://github.com/lyonstahl/soql-builder)

Requirements
------------

[](#requirements)

- [PHP 7.3+](https://www.php.net)
- [Composer 2.0+](https://getcomposer.org)

Features
--------

[](#features)

- OAuth with password grant type
- Create, update, delete, upsert, and query records
- Object representation of Salesforce records with LyonStahl\\Salesforce\\Record
- Field validation and object mapping
- Extendable code: add custom objects or validation rules

Setting up a Connected App
--------------------------

[](#setting-up-a-connected-app)

Before you begin, you need to have set up a "Connected App" in Salesforce and get a `consumerKey`, `consumerSecret`, `username`, and `password` to allow Api access.

*Note, this process may vary depending on changes to the Salesforce website, or on your Salesforce account and settings.*

*Check [Salesforce's Help Docs](https://help.salesforce.com/s/articleView?id=sf.connected_app_create.htm) to verify.*

1. Log into to your Salesforce org
2. Click on Setup in the upper right-hand menu
3. Under Build click Create → Apps
4. Scroll to the bottom and click "New" under Connected Apps.
5. Enter the following details for the remote application:
    - Connected App Name
    - API Name
    - Contact Email
    - Under the API dropdown, enable OAuth Settings
    - Callback URL
    - Select Access Scope (If you need a refresh token, specify it here)
6. Click Save, and store your access credentials in a safe place.

Usage
-----

[](#usage)

Creating a new Api client and connecting:

```
use LyonStahl\Salesforce\Authenticator\Password;
use LyonStahl\Salesforce\Client;

// Provide endpoint and any Guzzle options in Password::create(), endoint defaults to login.salesforce.com
$auth = Password::create(['endpoint' => 'https://test.salesforce.com/'])->authenticate([
    "client_id" => $YOUR_CONSUMER_KEY,
    "client_secret" => $YOUR_CONSUMER_SECRET,
    "username" => $YOUR_SALESFORCE_USERNAME,
    "password" => $YOUR_SALESFORCE_PASSWORD_AND_SECURITY_TOKEN
]);

// Here you may also provide object mappings and desired Salesforce API version
$salesforce = new Client($auth, [], 59);
```

The following examples use a Salesforce object named `Example` that has a field `Name`.

Executing Basic SOQL Queries:

```
$select = "SELECT Id, Name FROM Example LIMIT 100";
foreach ($salesforce->query($select) as $object) {
    echo "Example {$object->Id} ({$object->Name})\n";
    // outputs something like "Example 5003000000D8cuIQAA (Bob)"
}
```

If you need to use php values in your query, put `{tokens}` in your SOQL and pass the values separately via `query()`'s second argument. The values will be properly quoted and escaped based on their type, and interpolated into the query:

```
$select = "SELECT Id, Name FROM Example WHERE Name={name} LIMIT 100";
$name = 'Bob';
foreach ($salesforce->query($select, ['name' => $name]) as $object) {
    echo "Example {$object->Id} ({$object->Name})\n";
    // outputs something like "Example 5003000000D8cuIQAA (Bob)"
}
```

Fetching a Record by Id:

```
$id = "5003000000D8cuIQAA";
$bob = $salesforce->get("Example", $id);
echo "Hello, {$bob->Name}\n";
// outputs something like "Hello, Bob"
```

Creating a new Record:

```
use LyonStahl\Salesforce\Record;

$linda = $salesforce->create(new Record("Example", ["Name" => "Linda"]));
echo "Example {$linda->Id} ({$linda->Name})";
// outputs something like "Example 5003000000D8cuIQAA (Linda)"
```

Updating an existing Record:

```
$bob->Name = "Roberto";
$roberto = $salesforce->update($bob);
echo "Hello, {$roberto->Name}\n";
// outputs "Hello, Roberto"
```

Deleting a Record:

```
$ded = $salesforce->delete($bob);
var_dump($ded->Id);
// outputs "NULL"
```

Advanced Usage
--------------

[](#advanced-usage)

### Extending the Record class

[](#extending-the-record-class)

The included `LyonStahl\Salesforce\Record` class can be used without modification as a generic "salesforce record" implementation - it will automatically set properties based on what's fetched from the Api. However, the intent is that applications will extend from it and define the properties needed for each of their Salesforce objects. This allows for a consistent schema that your code can rely on, and even lets you implement some level of validation directly in your application.

To build your own Salesforce Object, you must:

- extend from `LyonStahl\Salesforce\Record`
- define the object fields as public properties
- list any properties that must not be included in update() calls (e.g., renamed fields, nested objects or object lists) in UNEDITABLE\_FIELDS.
- add any necessary logic in `setField()` (e.g., building a new object if your record has a relation)
- add any desired logic in `validateField()`

Using our "Example" object from above,

```
use LyonStahl\Salesforce\Record;

class Example extends Record
{
    public const TYPE = "Example";

    public ?string $Name = null;
}
```

### Inline Records and Record Lists

[](#inline-records-and-record-lists)

SOQL allows queries for nested objects and queries, which appear in results as inline records and query results respectively. This library does understand results from such queries, but your Record subclasses must define properties in a particular way to support them.

For example, a query similar to `SELECT Manager.Id, Manager.Name, (SELECT Id, Name FROM Members) FROM Teams` would require a Record class like so:

```
use LyonStahl\Salesforce\Record;
use LyonStahl\Salesforce\Result;
use Example;

class Team extends Record
{
    public const TYPE = "Team";

    protected const UNEDITABLE_FIELDS = [
        "Manager",
        "Members",
        ...parent::UNEDITABLE_FIELDS
    ];

    public ?Example $Manager = null;
    public ?Result $Members = null;
}
```

Where there is an inline object, the property should be typed as the corresponding Record subclass. For any record type where you're not making a Record subclass, type the property as `Record` — though this is obviously less useful.

Where there is a subquery, the property should be typed as a `Result` instance. Among other things, this allows the Result to support paginated subqueries.

### Object Mapping

[](#object-mapping)

Finally, to allow the Api Client take advantage of your subclasses, you must provide an `$objectMap` so it knows which PHP classes correspond to which Salesforce record types. Without this, you'll end up with generic Record instances for everything. Nested Results will be provided the same `$objectMap` as their parent Result instance.

```
$salesforce = new Client(
    $password->authenticate([...$credentials]),
    [Example::TYPE => Example::class, Team::TYPE => Team::class]
);
```

### Field Validation

[](#field-validation)

Some basic validation functions are included in `LyonStahl\Salesforce\Validator`. These methods all take the value to validate as the first argument, and can have other arguments depending on needs. Follow this same pattern to implement additional validation functions for your own objects as needed.

```
use LyonStahl\Salesforce\Record;
use LyonStahl\Salesforce\Validator;

class Example extends Record
{
    public ?string $Name = null;

    protected function validateField(string $field) : void {
        switch ($field) {
            case "Name":
                Validator::characterLength($this->Name, 2, 100);
                return;
            default:
                parent::validateField($field);
                return;
        }
    }
}
```

### Handling Errors

[](#handling-errors)

All Runtime Exceptions thrown from this library will be an instance of `LyonStahl\Salesforce\Error`.

Exceptions are grouped into the following types:

- `LyonStahl\Salesforce\Exceptions\SalesforceException`:

    Errors originating from the Salesforce API, including HTTP errors (e.g., connection timeouts)
- `LyonStahl\Salesforce\Exceptions\AuthException`:

    Authentication failures or attempts to use the HttpClient before authentication has succeeded
- `LyonStahl\Salesforce\Exceptions\ResultException`:

    Errors parsing or handling Salesforce Api results or records; these will usually indicate a problem in your custom Record classes
- `LyonStahl\Salesforce\Exceptions\UsageException`:

    Errors arising from incorrect library usage; these will usually indicate a runtime problem in your application code
- `LyonStahl\Salesforce\Exceptions\ValidationException`:

    Validation errors.

Running for development with Docker
-----------------------------------

[](#running-for-development-with-docker)

We have included a Dockerfile to make it easy to run the tests and debug the code. You must have Docker installed. The following commands will build the image and run the container:

1. `docker build -t lyonstahl/salesforce --build-arg PHP_VERSION=8 .`
2. `docker run -it --rm -v ${PWD}:/var/www/sapi lyonstahl/salesforce sh`

Debugging with XDebug in VSCode
-------------------------------

[](#debugging-with-xdebug-in-vscode)

Docker image is configured with XDebug. To debug the code with VSCode, follow these steps:

1. Install the [PHP Debug extension](https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug) in VSCode
2. Add a new PHP Debug configuration in VSCode:

    ```
    {
        "name": "XDebug Docker",
        "type": "php",
        "request": "launch",
        "port": 9003,
        "pathMappings": {
            "/var/www/sapi/": "${workspaceRoot}/"
        }
    }

    ```
3. `docker run -it --rm -v ${PWD}:/var/www/sapi --add-host host.docker.internal:host-gateway lyonstahl/salesforce sh`
4. Start debugging in VSCode with the 'XDebug Docker' configuration.

Testing
-------

[](#testing)

This library ships with PHPUnit for development. Composer file has been configured with some scripts, run the following command to run the tests:

```
composer test

```

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity37

Early-stage or recently created project

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

954d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/5c62eb11675fca05cf626660aff044739bdcd80bfa3e2dab8a6afda763c219d5?d=identicon)[PAXANDDOS](/maintainers/PAXANDDOS)

---

Top Contributors

[![adrian-enspired](https://avatars.githubusercontent.com/u/796525?v=4)](https://github.com/adrian-enspired "adrian-enspired (17 commits)")[![bjsmasth](https://avatars.githubusercontent.com/u/5401401?v=4)](https://github.com/bjsmasth "bjsmasth (16 commits)")[![laszlof](https://avatars.githubusercontent.com/u/1486486?v=4)](https://github.com/laszlof "laszlof (10 commits)")[![PAXANDDOS](https://avatars.githubusercontent.com/u/40315177?v=4)](https://github.com/PAXANDDOS "PAXANDDOS (4 commits)")[![clwells](https://avatars.githubusercontent.com/u/8984720?v=4)](https://github.com/clwells "clwells (2 commits)")

---

Tags

apirestsalesforcesapi

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/lyonstahl-salesforce/health.svg)

```
[![Health](https://phpackages.com/badges/lyonstahl-salesforce/health.svg)](https://phpackages.com/packages/lyonstahl-salesforce)
```

###  Alternatives

[onesignal/onesignal-php-api

A powerful way to send personalized messages at scale and build effective customer engagement strategies. Learn more at onesignal.com

34170.2k2](/packages/onesignal-onesignal-php-api)[ory/hydra-client

Documentation for all of Ory Hydra's APIs.

17435.9k](/packages/ory-hydra-client)[hgg/pardot

Pardot API library for building custom CRM connectors

2399.6k](/packages/hgg-pardot)[whatarmy/fedex-rest

New FedEx Rest API wrapper

2440.5k1](/packages/whatarmy-fedex-rest)[dreamfactory/df-core

DreamFactory(tm) Core Components

1651.7k20](/packages/dreamfactory-df-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
