ae/salesforce-rest-sdk

Salesforce Rest API 的 SDK

v2.0.1 2020-04-27 23:16 UTC

README

此 API 支持以下 Salesforce API 区域

  • 限制
  • 全局描述
  • SObject 描述
  • SObject CRUD
  • SObject 获取更新/删除
  • 复合 API
    • 批量处理
    • SObject 集合
  • 批量 API
  • 流式 API

安装

composer require ae/salesforce-rest-sdk

实例化 Rest 客户端

<?php

use AE\SalesforceRestSdk\Rest\Client;
use AE\SalesforceRestSdk\AuthProvider\OAuthProvider;

$client = new Client(
  new OAuthProvider(
      "SF_CLIENT_ID",
      "SF_CLIENT_SECRET",
      "https://login.salesforce.com",
      "SF_USER",
      "SF_PASS"
  ),
  "46.0", // optional version number, defaults to 44.0
  "MyAppName" // optional client app name, used when filtering out Change Data Events in the Streaming API
);

有关使用客户端应用程序名称与 Change Data Capture 的更多信息,请参阅 https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_event_fields_header.htm

如果您有返回到 redirectUrl 的授权代码并希望使用它,您可以这样做

<?php
use AE\SalesforceRestSdk\Rest\Client;
use AE\SalesforceRestSdk\AuthProvider\OAuthProvider;

$client = new Client(
  new OAuthProvider(
      "SF_CLIENT_ID",
      "SF_CLIENT_SECRET",
      "https://login.salesforce.com",
      null,
      null,
      OAuthProvider::GRANT_CODE,
      "https://your.redirect.uri",
      "THE_CODE_FROM_SALESFORCE"
  )
);

缓存的身份验证提供者

缓存的身份验证提供者提供了一种在请求之间保留有效凭据的方式,否则客户端每次实例化时都必须与 Salesforce 进行身份验证。

<?php
use AE\SalesforceRestSdk\Rest\Client;
use AE\SalesforceRestSdk\AuthProvider\CachedOAuthProvider;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

// Any adapter that uses Psr\Cache\CacheItemPoolInterface will work with the Cached Providers
$adapter = new FilesystemAdapter();

$client = new Client(
  new CachedOAuthProvider(
      $adapter,
      "SF_CLIENT_ID",
      "SF_CLIENT_SECRET",
      "https://login.salesforce.com",
      null,
      null,
      CachedOAuthProvider::GRANT_CODE,
      "https://your.redirect.uri",
      "THE_CODE_FROM_SALESFORCE"
  )
);

在没有框架的情况下使用 Composer 进行自动加载

如果您没有使用像 Symfony 这样为您处理注解注册的 PHP 框架,那么您必须自己这样做

<?php

use AE\SalesforceRestSdk\Rest\Client;
use AE\SalesforceRestSdk\AuthProvider\OAuthProvider;
use Doctrine\Common\Annotations\AnnotationRegistry;

$loader = require_once 'vendor/autoload.php';
AnnotationRegistry::registerLoader(array($loader, "loadClass"));

$client = new Client(
   // ...

使用 SObject 客户端与 SObjects 一起工作

参考

<?php

//...

/** @var \AE\SalesforceRestSdk\Rest\SObject\Client $sObjectClient */
$sObjectClient = $client->getSObjectClient();

// Get basic metadata and recently used records for an object
$info = $sObjectClient->info("Account");

// Get very detailed metadata about an object
$describe = $sObjectClient->describe("Account");

// Get basic metadata info about all objects in SF
$globalDescribe = $sObjectClient->describeGlobal();

// Let's CRUD it up
$account = new \AE\SalesforceRestSdk\Model\SObject();

$sObjectClient->persist("Account", $account); // returns true if success

echo $account->Id; // outputs the SFID of the account

$account->MyCustomField__c = "Some Value I want to Save";

$sObjectClient->persist("Account", $account); // returns true on success

// Let's get new info from out account, pretend it was updated in SF
$account = $sObjectClient->get("Account", $account->Id, ["Name", "AnotherCoolField__c"]);

// Kill the account
$sObjectClient->remove("Account", $account);

// Query for more stuff
$result = $sObjectClient->query("SELECT Id, Name FROM Account");

echo $result->getTotalSize(); // OUtputs the total number of records for the query

var_dump($result->getRecords()); // SObject[]

while (!$result->isDone()) {
    // There are more records to be returned!
     // Just pass in the last result set and get the next batch
     // Lather, rinse, repeat until $result->isDone() === true;
    $result = $sObjectClient->query($result);
    
    var_dump($result->getRecords()); // CompositeSObject[]
}

// Query deleted and merged records, too
$result = $sObjectClient->queryAll(
    "SELECT Id, Name FROM Account",
     1000 // optional batch size, defaults to 2000, which is the max, min is 200
     );

// Search for something
$result = $sObjectClient->search("FIND {Some Query} IN ALL FIELDS");

var_dump($result->getSearchRecords()); // CompositeSObject[]

有关批量大小和 Sforce-Query-Options 头的更多信息,请参阅 https://developer.salesforce.com/docs/atlas.en-us.220.0.api_rest.meta/api_rest/headers_queryoptions.htm

需要注意的是,如果批量大小不是最佳性能,Salesforce 可能不会尊重批量大小

实例化流式客户端

参考

<?php
use AE\SalesforceRestSdk\Bayeux\BayeuxClient;
use AE\SalesforceRestSdk\AuthProvider\OAuthProvider;
use AE\SalesforceRestSdk\Bayeux\Transport\LongPollingTransport;

$client = new BayeuxClient(
      new LongPollingTransport(),
      new OAuthProvider(
          "SF_CLIENT_ID",
          "SF_CLIENT_SECRET",
          "https://login.salesforce.com",
          "SF_USER",
          "SF_PASS"
      ),
      "46.0" // optional version number, defaults to 44.0
 );

订阅 PushTopic

您可以使用上面的 Rest 客户端创建一个新的 PushTopic。主题只需在 Salesforce Org 中创建一次。所有自定义对象都受 Streaming API 支持,但是,并非所有标准对象都受支持。

支持的标准对象

  • 账户
  • 活动
  • 案例
  • 联系人
  • 合同行项目
  • 权益
  • 潜在客户
  • LiveChat 转录
  • 机会
  • 报价
  • 报价行项目
  • 服务合同
  • 任务

使用以下方法创建或更新任务的任务不会在流式 API 的任务对象主题中显示。

  • 潜在客户转换
  • 实体合并
  • 大量电子邮件联系人/潜在客户
<?php
use AE\SalesforceRestSdk\Bayeux\BayeuxClient;
use AE\SalesforceRestSdk\Bayeux\Consumer;
use AE\SalesforceRestSdk\Bayeux\ChannelInterface;
use AE\SalesforceRestSdk\Bayeux\Message;
use AE\SalesforceRestSdk\Bayeux\Extension\ReplayExtension;
use AE\SalesforceRestSdk\Bayeux\Extension\CachedReplayExtension;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

/** @var BayeuxClient $client */

// Getting a channel tells the client you want to subscribe to a topic
$channel = $client->getChannel('/topic/[YOUR_PUSH_TOPIC_NAME]');

// Give some durability to the messages on this channel by adding the ReplayExtension
$channel->addExtension(new ReplayExtension(ReplayExtension::REPLAY_SAVED));

// Using the CachedReplayExtension give greater durability in that it will remember the replay Id of the last
// message received and pick up where it left off, even if the process stops and restarts. If no messages for the
// channel topic have been received, it will use the value provided in the constructor.
// Again, Any Psr\Cache\CacheItemPoolInterface will do for the adapter parameter
$channel->addExtension(new CachedReplayExtension(new FilesystemAdapter(), CachedReplayExtension::REPLAY_SAVED));

// You can also apply extensions at the Client level, rather than the channel.
// In the case of the ReplayExtension, the last replayId will be remembered for each channel,
// however, if no messages have been received on the channel, the constructor argument is used
$client->addExtension(new CachedReplayExtension(new FilesystemAdapter(), CachedReplayExtension::REPLAY_SAVED));

// Register topic consumers prior to starting the client
$channel->subscribe(
    Consumer::create(function (ChannelInterface $channel, Message $message) {
        // This will be fired when the client receives a topic notification
        
        $payload = $message->getData();
        
        // The payload has information about the event that occurred
        $event = $payload->getEvent();
        
        echo $event->getType(); // "created", "updated", "undeleted", "deleted"
        echo $event->getCreatedDate()->format(\DATE_ISO8601); // outputs the datetime the event was created
        echo $event->getReplayId(); // This ia n ID used by the replay extension so it can pick up the feed where it left off
        
        $sobject = $payload->getSobject();
        
        echo $sobject->Id; // Get the Id
        echo $sobject->getFields(); // this outputs all the fields and their values that were in the create or update request
    })
);

// Start the client to begin receiving notifications;
$client->start();

$client->start(); 是一个阻塞调用,在此之后不会执行任何代码,直到客户端发生错误,导致它断开连接。

例如,客户端必须在每次收到通知后 40 秒内重新连接到流式服务器。如果它未能这样做,它将尝试重新握手以创建新的连接。如果那也失败了,那么客户端将断开连接,这将允许脚本的其他部分执行。

建议在单独的线程中运行流式客户端

分发通用事件

创建流式通道

在您可以分发通用事件之前,您必须创建一个流式通道。这可以通过多种方式完成

  1. 通过 Salesforce Classic UI,如此处所述
  2. 通过在 设置 > 用户界面 下启用 启用动态流式通道创建,然后使用如上所述的流式客户端订阅流式通道
  3. 流式通道是一个常规的 SObject,可以像创建一个一样创建它
<?php
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use AE\SalesforceRestSdk\Rest\Client;
use AE\SalesforceRestSdk\AuthProvider\CachedOAuthProvider;
use AE\SalesforceRestSdk\Model\SObject;

// Use the SObject Client to create a Streaming Channel

// Any adapter that uses Psr\Cache\CacheItemPoolInterface will work with the Cached Providers
$adapter = new FilesystemAdapter();

$client = new Client(
  new CachedOAuthProvider(
      $adapter,
      "SF_CLIENT_ID",
      "SF_CLIENT_SECRET",
      "https://login.salesforce.com",
      "SF_USERNAME",
      "SF_PASSWORD"
  )
);

$streamingChannel = new SObject([
    'name' => '/u/MY_AWESOME_TOPIC'
]);

$client->getSObjectClient()->persist('StreamingChannel', $streamingChannel);

向流频道发送通用事件

一旦创建了 StreamingChannel,就可以使用 GenericEventClient 将事件发送给它,该客户端依托于 SObject 客户端。让我们假设我们接下来继续使用上面的代码示例

<?php
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use AE\SalesforceRestSdk\Rest\Client;
use AE\SalesforceRestSdk\AuthProvider\CachedOAuthProvider;
use AE\SalesforceRestSdk\Model\SObject;
use AE\SalesforceRestSdk\Rest\GenericEventClient;
use AE\SalesforceRestSdk\Model\Rest\GenericEvent;
use AE\SalesforceRestSdk\Model\Rest\GenericEvents;

// ... Client and everything is defined as above

// Generic Event Client also takes a cache adapter which it uses to keep track of Ids for StreamingChannels. You can
// resuse the adapter given to the client if you wish. The keys won't conflict.
$geClient = new GenericEventClient($adapter, $client->getSObjectClient());

// Next we'll create a Generic Event to dispatch
$event = new GenericEvent();
$event->setPayload("This is the payload of the event. It has to be a string. But it could be XML or JSON data");

// You can also set which clients subscribing to the channel you want to receive your message,
// if you didn't want all of them getting it. Use the GenericEventClient to see which users are subscribed to the channel
$users = $geClient->getChannelSubscribers('/u/MY_AWESOME_TOPIC');
$event->setUserIds($users);

// Send the event to the Streaming Channel
$geClient->sendEvent('/u/MY_AWESOME_TOPIC', $event);

// Multiple events can also be sent at once
$events = GenericEvents::create([
    GenericEvent::create("Event payload magic here"),
    GenericEvent::create("More event payload magic here"),
]);

// Send the events to the Streaming Channel
$geClient->sendEvents('/u/MY_AWESOME_TOPIC', $events);

未来添加功能

  • 工具API
  • 元数据API