PHPackages                             ylly/salesforcebundle - 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. [Framework](/categories/framework)
4. /
5. ylly/salesforcebundle

ActiveLibrary[Framework](/categories/framework)

ylly/salesforcebundle
=====================

Symfony Bundle for Salesforce

1.4.0(1y ago)2580↓86.3%proprietaryPHPPHP ^8.1

Since Mar 10Pushed 1y ago3 watchersCompare

[ Source](https://github.com/ylly/ylly_salesforcebundle_sf)[ Packagist](https://packagist.org/packages/ylly/salesforcebundle)[ RSS](/packages/ylly-salesforcebundle/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (19)Versions (19)Used By (0)

ylly\_salesforcebundle\_sf
==========================

[](#ylly_salesforcebundle_sf)

Bridge bundle for salesforce

- [Installation](#installation)
- [Usage for Querying salesforce](#usage-for-querying-salesforce)
- [Handling Webhooks](#webhooks)

Installation
============

[](#installation)

Installation for usage purpose
------------------------------

[](#installation-for-usage-purpose)

1**On the project you want to use this bundle:**

1. On *composer.json*, please add these lines :

```
"repositories": [
        {
            "type": "vcs",
            "url": "git@gitlab-azure.castelis.com:ylly/ylly_salesforcebundle_sf.git",
        }
    ],
```

```
"scripts": {
     "post-package-install": [
         "Ylly\\SalesforceBundle\\Composer\\ComposerScript::postPackageInstall"
     ],
     "pre-package-uninstall": [
         "Ylly\\SalesforceBundle\\Composer\\ComposerScript::prePackageUninstall"
     ]
 }
```

2. Run `composer require ylly/salesforcebundle:dev-{your-branch}`or `composer require ylly/salesforcebundle:{tag}`

Installation for development purpose on this bundle
---------------------------------------------------

[](#installation-for-development-purpose-on-this-bundle)

1. clone this project wherever you want.
2. **On the project you want to use this bundle:**
    1. On *composer.json*, please add these lines :

    ```
    "repositories": [
            {
                "type": "path",
                "url": "../ylly_salesforcebundle_sf",
                "options": {
                    "symlink": false
                }
            }
        ],
    ```

    2. Run `composer require ylly/salesforcebundle:dev-{your-branch}`

**Warning:** If you run this command inside the php container, it'll not work because the URL is a relative path. (Unless if the bundle project is inside the container but I don't think it's a good idea)

Enable the bundle
-----------------

[](#enable-the-bundle)

Since there is no flex recipe yet, you need to enable the bundle manually:

On your project, open `Bundle.php` and add this line :

```
Ylly\SalesforceBundle\YllySalesforceBundle::class => ['all' => true],
```

and then add, these parameters to you `.env` or `.env.local`

```
  (SALESFORCE_LOGIN_URL)
  (SALESFORCE_CLIENT_ID)
  (SALESFORCE_CLIENT_SECRET)
  (SALESFORCE_USERNAME)
  (SALESFORCE_PASSWORD)
  (bool:SALESFORCE_CACHE_TOKEN)

```

Usage for Querying salesforce
=============================

[](#usage-for-querying-salesforce)

### Configuration

[](#configuration)

If you want to configure the bundle, create `ylly_salesforce.yaml` in `config/packages`

```
ylly_salesforce:
  authentication:
    salesforce_login_url: '%env(SALESFORCE_LOGIN_URL)%'
    salesforce_client_id: '%env(SALESFORCE_CLIENT_ID)%'
    salesforce_client_secret: '%env(SALESFORCE_CLIENT_SECRET)%'
    salesforce_url_account: '%env(SALESFORCE_URL_ACCOUNT)%'
    salesforce_username: '%env(SALESFORCE_USERNAME)%'
    salesforce_password: '%env(SALESFORCE_PASSWORD)%'
    salesforce_grant_type: 'password' #type of grant
  api:
    salesforce_action_url: "%env(SALESFORCE_QUERY_URL)%"
    salesforce_query_url: "%env(SALESFORCE_ACTION_URL)%"
    salesforce_api_version: "%env(SALESFORCE_API_VERSION)%"
    salesforce_cache_token: '%env(bool:SALESFORCE_CACHE_TOKEN)%' #set this to true if you want to use the cached token
```

### Overriding the Salesforce Query Service

[](#overriding-the-salesforce-query-service)

If you want to override the SalesforceQueryService class, you'll need to use the **Decorator** Design pattern.

Fortunately, Since symfony 6.2, it's simple to do so.

On your server service class, use the Class attribute `AsDecorator`Where `YllySalesforceQueryService` is the original queryService.

Then give your service an YllySalesforceQueryService property named `inner`

```
use src\Service\SalesforceQueryService as YllySalesforceQueryService;use Symfony\Component\DependencyInjection\Attribute\AsDecorator;

#[AsDecorator(decorates: YllySalesforceQueryService::class)]
final class SalesforceQueryService
{
    private YllySalesforceQueryService $inner;
}
```

Then, instantiate it with constructor :

```
use Symfony\Component\DependencyInjection\Attribute\MapDecorated;
//...
public function __construct (#[MapDecorated] YllySalesforceQueryService $inner)
{
    $this->inner = $inner
}
```

Webhooks:
=========

[](#webhooks)

Webhooks salesforce are supported in this bundle.

a new `ylly_salesforce.yaml` has been created in the config/routes directory. You can update it if you want to change the default route.

The built-in controller will take care of received the salesforce webhooks, handle errors and return code.

### Supported webhooks formats

[](#supported-webhooks-formats)

2 formats are supported out of the BOX : XML and JSON according to content type in the webhook request.

You can add more format by adding new Notification Resolver implementing `NotificationResolverInterface` and create a Response Generator by implementing `ResponseGeneratorInterface`.

#### Json Format

[](#json-format)

Json NotificationResolver need this type of payload

```
{
    "type": "delete",
    "notifications": [
        {
            "object": "Account",
            "Id": "ADHERENT_SALESFORCE_ID"
        },
        {
            "object": "Adhesion__c",
            "Id": "SALESFORCEID"
        }
    ]
}
```

type : can be delete, update, create.

Json ResponseGeneator will return response like this :

```
{
   "success": "false",
   "message": "An error message"
}
```

#### XML format

[](#xml-format)

XML format is according to salesforce specification.

Webhooks handling
-----------------

[](#webhooks-handling)

By default the webhooks are **synchronously** handled. You can use symfony messenger to handle them **asynchronously**. [see below](#dealing-with-webhooks-asynchronously)

Custom header
-------------

[](#custom-header)

A custom Header will be added to the Request object `X-Webhook-From` with value `salesforce`, so you can always know if you are working inside the webhook request (can be useful to not send back modification to salesforce after receiving webhook if you have entity listener for exemple).

Webhooks Built-in service
-------------------------

[](#webhooks-built-in-service)

A Default service implementing `SalesforceWebhookMappingServiceInterface` exist in the bundle. But you may need to create a service that implements the `SalesforceWebhookMappingServiceInterface` to replace the default built-in.

The default built-in service use the [Mapping Bundle](https://github.com/Ehyiah/MappingBundle) to auto-map properties from DTO to the entity. So in your DTO use the MappingAware attribute eg : this will map the property of the DTO inside the property with the same name inside the Entity. and the email to the mail.

```
namespace App\DTO\SalesforceWebhookUserDTO;

#[MappingAware(target: User::class)]
class SalesforceWebhookUserDTO
{
   #[MappingAware]
   public string $lastname;

    #[MappingAware(target: 'mail')]
    public string $email;
}
```

You can subscribe to events that are dispatched within the bundle when handling webhooks. [see events webhook in details below](#Events)

### Create your own service

[](#create-your-own-service)

The default Service combined with the events should be enough to deal with the webhooks, but if you want you can create your own service that will replace the default built-in.

To create your own service :

- Just create a service that implements the interface, there is nothing more to do, no need to register or override the default built-in. The compiler pass do the work for you.
- In this service you will handle the logic (create/update/delete) to handle the records from salesforce. Check the default built-in service if you need some exemple.

Usage :
-------

[](#usage-)

### For each Salesforce Object :

[](#for-each-salesforce-object-)

- Create a DTO that extends the `AbstractSalesforceWebhookDTO`.
- Create a Denormalizer that implements the `SalesforceWebhookDenormalizerInterface` to handle the Denormalization from the received salesforce XML webhook. Inside this denormalizer map the date from the received XML to the DTO.

If you created a custom mappingService, and are not using the default built-in, Then in the Service implementing the `SalesforceWebhookMappingServiceInterface` just put your logic (the create/update/delete logic for each action). otherwise there is nothing else to do.

### Events

[](#events)

For each notification received from salesforce, one of `YllySalesforceWebhookEvents` type event is dispatched with the DTO as first argument after your `SalesforceWebhookMappingServiceInterface` service managed to handle it. So you can access your DTO inside the event subscriber.

A **notification** is an action (create/update/delete) for a single Entity. This bundle accept batch or single notification from salesforce.

### Ignore events

[](#ignore-events)

If you use built-in service, you can use the `$ignoreHandling` and `$skipEvents` variables in `AbstractSalesforceWebhookDTO::class` to ignore incoming notification and/or not sending events for this notification. Modify these variables in your custom normalizer.

Dealing with Webhooks asynchronously
------------------------------------

[](#dealing-with-webhooks-asynchronously)

For each call received by salesforce, we can receive more than one notification (max is 100 per call). If your process need heavy computation for exemple you may need to deal them asynchronously. In this case the number of notifications per batch can be customized (default is 20 per batch).

For each batch of salesforce notifications a new `WebhookHandleNotificationsMessage` is created.

Exemple of configuration in messenger.yaml configuration file

```
framework:
    messenger:
        transports:
            ylly_webhook_notifications_handle:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%?queue_name=ylly_webhook'
                retry_strategy:
                    max_retries: 5
                    delay: 2000
                    multiplier: 3

        routing:
            'Ylly\SalesforceBundle\Messenger\Message\WebhookHandleNotificationsMessage': 'ylly_webhook_notifications_handle'
```

And, as every asynchronous work start a worker to consume the queue, if you follow the exemple above with `bin/console messenger:consume ylly_webhook_notifications_handle`

Webhook Security
----------------

[](#webhook-security)

Webhook calls can be protected by Authentication at will

Please ensure these parameters are set up in your configuration

```
    ylly_salesforce:
       webhook:
           security:
               activate: '%env(bool:WEBHOOK_SECURITY_ACTIVATE)%' ### if the value is true then, a token check will be made.
               username: '%env(WEBHOOK_SECURITY_USERNAME)%'
               password: '%env(WEBHOOK_SECURITY_PASSWORD)%'
               secret: '%env(WEBHOOK_SECURITY_SECRET)%'
               token_ttl: '%env(int:WEBHOOK_SECURITY_TOKEN_TTL)%' ### token's ttl in second
```

Please set up environment variable as you need to.

### Avoiding login check conflict issue

[](#avoiding-login-check-conflict-issue)

If you use JWT plugin on your project, you could encounter trouble with token check due to this JWT plugin. To solve that, add another firewall to your security.

```
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        webhook_salesforce:
            pattern: ^/api/external/webhook/salesforce
            stateless: true
            entry_point: ~
        login:
            pattern: ^/api/login
            stateless: true
```

**Important: Webhook firewall must be BEFORE another api firewall. And don't forget to change the pattern according to your needs**

### Example Request Body/response for Login

[](#example-request-bodyresponse-for-login)

Request body

```
{
   "username": "string",
   "password": "string"
}
```

Response

```
{
  "token": "eyxxxxxx.yyyyyyy.zzzzzz"
}
```

Using the token add `Bearer {{your token}}` on Authorization header

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance43

Moderate activity, may be stable

Popularity17

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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

Every ~43 days

Recently: every ~32 days

Total

18

Last Release

478d ago

Major Versions

0.1.0 → 1.0.02024-05-13

### Community

Maintainers

![](https://www.gravatar.com/avatar/73162a7f8bb82c57c453c11671608f59e3c87bf7f76724826b369d01a25e87a8?d=identicon)[ylly](/maintainers/ylly)

---

Top Contributors

[![Ehyiah](https://avatars.githubusercontent.com/u/22179288?v=4)](https://github.com/Ehyiah "Ehyiah (26 commits)")

###  Code Quality

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ylly-salesforcebundle/health.svg)

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

###  Alternatives

[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M577](/packages/shopware-core)[chameleon-system/chameleon-base

The Chameleon System core.

1028.6k5](/packages/chameleon-system-chameleon-base)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.1k17.8k](/packages/prestashop-prestashop)[oro/platform

Business Application Platform (BAP)

645143.5k115](/packages/oro-platform)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M737](/packages/sylius-sylius)

PHPackages © 2026

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