这个 PHP 库包含
它还包含几个示例/部分类,用于实现联系人数据从源系统到 Sharpspring 的联系人/线索数据库的同步过程。这与 Sharpspring 线索的本地缓存配合使用,以最大限度地减少对 Sharpspring REST API 的更新调用。
客户端类可以独立使用,尽管这个库不是为此编写的。如果您想自行构建参数并自行解码结果:请继续。实例化它;调用 call() 方法。您不需要图书馆的其余部分。
Connection 类的目的是帮助您在与 Sharpspring 的 REST API 通信时不会感到困惑。它试图通过以下方式帮助解决这个问题:
(这里不讨论 LocalLeadCache 类。)
use SharpSpring RestApi Connection ;
use SharpSpring RestApi CurlClient ;
// One thing this library does not make super easy: starting. Separation of
// concerns is considered more important, so (since the actual API call was
// abstracted into CurlClient) creating a new connection takes 2 lines instead
// of 1:
$ client = new CurlClient ([ ' account_id ' => . . . , ' secret_key ' => . . . ]);
$ api = new Connection ( $ client );
// Get all leads updated after a certain time (notation in 'local' timezone,
// though there is no formal definition of what 'local' entails).
$ leads = $ api -> getLeadsDateRange ( ' 2017-01-15 10:00:00 ' );
该代码会针对遇到的任何奇怪情况抛出异常...除了一件事:除了您正在调用的特定 API/连接方法所期望的数组值之外,它在响应中看到的额外属性。默认情况下这些会被忽略;预计永远不会遇到他们。如果您希望记录这些内容,请将 PSR-3 兼容的记录器对象作为第二个参数传递给 Connection 构造函数。
在 Sharpspring REST API“对象”(数组)中,自定义字段由其系统名称引用,该系统名称会根据帐户而变化。为了能够编写更通用的代码,Connection 对象具有从自定义属性到字段系统名称的映射。设置此映射后(使用您自己选择的属性名称),REST API 调用中的任何“对象”参数都将其自定义属性名称自动转换为相应的字段系统名称。
假设您有鞋店的销售线索,其中有一个通过 Sharpspring UI 创建的鞋码自定义字段,其系统名称为 Shoes_size_384c1e3eacbb3。以下两个示例是等效的:
$ api -> createLead ([
' firstName ' => ' Roderik ' ,
' emailAddress ' => ' [email protected] ' ,
' shoe_size_384c1e3eacbb3 ' => 12 ,
]);
$ api -> setCustomProperties ( ' lead ' , [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ]);
$ api -> createLead ([
' firstName ' => ' Roderik ' ,
' emailAddress ' => ' [email protected] ' ,
' shoeSize ' => 12 ,
]);
// Note that system names will still be OK; after setCustomProperties is called,
// you can still send in [...,'shoe_size_384c1e3eacbb3' => 12, ...]. Just don't
// set values for _both_ the field name _and_ its property alias, because then
// the library does not guarantee which of the two will be used.
自动转换仅针对 API 调用参数中的“对象”进行。 API 调用返回的结果不会被篡改。如果您希望将 API 结果中的自定义字段系统名称转换回自定义属性名称,则需要明确执行此操作:
$ api -> setCustomProperties ( ' lead ' , [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ]);
$ leads = $ api -> getLeads ([ ' emailAddress ' => ' [email protected] ' ]);
$ lead = reset ( $ leads );
$ my_lead = $ api -> convertSystemNames ( ' lead ' , $ lead );
使用数组来表示 API“对象”就可以了。但您可能更喜欢为它们使用对象/类。 (它为您提供了 IDE 自动完成功能,这也最大限度地减少了 REST API 无法处理的属性名称大写错误的可能性)。
基类是 ValueObject,目前有一个 Lead 类,它实现了所有已知字段(带有关于 Sharpspring 的 API 文档过时的地方的注释)。
以下示例与上面相同:
/**
* If you have custom fields, you will want to define your own subclass:
*/
class ShoeStoreLead extends Lead
{
// Define your own properties:
public $ shoeSize ;
}
$ api -> setCustomProperties ( ' lead ' , [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ]);
// This is the create call from above. Note createLead() accepts ValueObjects as
// well as arrays.
$ lead = new ShoeStoreLead ();
$ lead -> firstName = ' Roderik ' ;
$ lead -> emailAddress = [email protected]';
$ lead -> shoeSize = 12 ;
$ api -> createLead ( $ lead );
// And this is the 'get' call which puts the result into a new object:
$ leads = $ api -> getLeads ([ ' emailAddress ' => ' [email protected] ' ]);
$ lead = reset ( $ leads );
$ my_lead = $ api -> convertSystemNames ( ' lead ' , $ lead );
$ my_lead_obj = new ShoeStoreLead ( $ my_lead );
显然,如果您没有任何自定义字段,那么此示例会变得更加简单(因为您不需要子类化 Lead 或使用 setCustomProperties() / ConvertSystemNames())。
在上面的示例中,ValueObject 不知道有关其属性到字段系统名称的映射的任何信息; Connection 对象为创建/更新操作处理此问题,在“获取”操作之后,您需要在构造对象之前将它们显式转换回自定义属性名称。
还有另一种方法:您可以在 ValueObject 而不是 Connection 中设置映射。
$ mapping = [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ];
// $api->setCustomProperties('lead', $mapping) is not called here.
// For create:
$ lead = new ShoeStoreLead ([], $ mapping );
$ lead -> firstName = ' Roderik ' ;
$ lead -> emailAddress = [email protected]';
$ lead -> shoeSize = 12 ;
$ api -> createLead ( $ lead );
// Note you could also add all the properties in the first argument of the
// constructor, instead of setting them individually - although that more or
// less defeats the purpose of using a ValueObject in the first place. Setting
// 'shoeSize' works just as well as 'shoe_size_384c1e3eacbb3', in that first
// argument. Just don't set values for _both_ the field name _and_ its property
// alias, because then the library does not guarantee which of the two will be
// used.
// For 'get':
$ leads = $ api -> getLeads ([ ' emailAddress ' => ' [email protected] ' ]);
$ lead = reset ( $ leads );
$ my_lead_obj = new ShoeStoreLead ( $ my_lead , $ mapping );
因此:对于具有自定义字段的 ValueObject,可以选择设置连接映射,或在 ValueObject 中设置。后者的优点是从 REST API 检索的数据会在构造函数中自动转换,但缺点是每次构造对象时都需要设置映射。
还有另一种方法:要么对对象内部的映射进行硬编码,例如:
// Override the parent's (empty) property mapping variable:
protected $_customProperties = ['shoeSize' => 'shoe_size_384c1e3eacbb3'];
...或者让您的自定义 ValueObject 子类的构造函数设置它(或从某个地方派生它)。这可能是针对您自己情况的代码。
选择您自己喜欢的方法。
Sharpspring REST API 的大多数奇怪行为已被该库记录或部分缓解/隐藏。但是,如果您打算基于 API 进行认真的工作,那么您至少应该了解一些事情,并决定是否需要考虑这些事情。
具有非标准字符的值(大致:将由 htmlspecialchars() 编码的字符)在 Sharpspring 中的存储方式有所不同,具体取决于它们是通过 REST API 插入还是通过 UI 输入。 (对于 UI,标准字段和自定义字段之间的情况也有所不同。)“<”甚至更奇怪:它有时以双重编码存储。血淋淋的细节在encoding.md中。该库能够减轻这种行为的唯一方法是让 CurlClient 始终对任何字段进行 HTML 解码,无论是否有必要。由于 HTML 解码是透明进行的,因此您可能不会看到此行为,但认真的应用程序仍应考虑这是否是一个问题。
updateLead 调用可以通过提交(至少)现有的“id”值以及更改后的电子邮件地址来更改现有潜在客户的电子邮件地址。但是,如果更改后的电子邮件碰巧已在另一个现有潜在客户中使用,则 API 将默默地放弃更新,但仍报告 success 。如果您将现有的联系人数据库(其中电子邮件地址不一定是唯一的)镜像到 Sharpspring 中,则这是一个潜在的问题。您需要仔细检查更新以查看它们是否成功。 (此类代码的一个示例位于 SharpspringSyncJob::finish() 中。)
(我欢迎任何有关这些错误已修复的报告。它们可能会;请参阅“警告”。)
Sharpspring 显然有时会在没有公告或文档/更改日志的情况下更改其 API 的行为(据我所知,他们根本没有这样做),甚至没有增加在线 API 文档中提到的 API 版本,该文档可以在登录后找到他们的客户网站。
由此看来,作为应用程序开发人员,您应该不断测试您的应用程序,因为您不能相信 Sharpspring 不会违反他们与您的“隐性合同”。因为 Sharpspring 显然并不认为他们与应用程序开发人员有“隐性合同”。
(在半年的时间里我开发这个库时,我对此有一些可疑的感觉,但我的基础是他们对 getLeadsDateRange 调用行为的改变(将“timestamp”参数设置为“更新”) - 它更改了参数和输出中的日期格式以及输出的内容,这会在使用 SharpspringSyncJob 类的生产系统中立即产生影响 - 报告错误。已发布的 API 版本仍然是 1.117,并且至少从 2016 年 11 月开始。
行为改变可能是由我报告的不一致引起的(我进行了一次简短的电子邮件交流,最终我发送了他们的 API 遇到的问题列表),我很高兴他们正在修复不一致的问题,但缺乏响应、变更日志或 API 版本更改仍然导致上述结论。我当然希望这将来会改变,并且这个警告可能会被删除,但现在看起来确实很相关。)
哦,看! https://help.sharpspring.com/hc/en-us/articles/115001069228-Open-API-Overview 现在提到他们有一个“v1”API 和一个“v1.2”API!第二个显然接受 UTC 日期输入(这是他们的 v1 API 直到 2017 年 7 月 26 日左右所做的)。没有提及输出日期的格式(在 v1 中也发生了更改),因此需要测试。该库目前仅支持 API v1,应该进行扩展。它不在我的候选名单上,因此欢迎 PR(或付费作业;))。
此代码已经过 Leads 和 ListMembers 的测试。存在更多 API 调用,但并非所有调用都经过广泛测试,有些还缺失。添加新的呼叫希望不是很多工作;欢迎拉取请求。
只需提交 PR 或以其他方式联系我。
“构建过程”(参见顶部的图标;类似的通过/失败消息将出现在 PR 上)仅根据 PHP5.6 / PSR2 检查编码标准。目前还没有单元测试,因为这只是 Sharpspring 周围的一层薄薄的代码。告诉我您是否认为应该进行测试以及哪些/为什么。 (显然,对实时 Sharpspring API进行全套测试会很好,但我想这是一个不同的问题和/或至少需要与他们进一步协调......)
我喜欢向世界贡献开源软件,也喜欢开放半封闭、文档不足的系统。如果这有用或者您有贡献,请大声告诉我。如果您需要完成集成工作,请联系我。 (我有使用其他几个系统的经验。)
该库已根据 MIT 许可证获得许可 - 有关详细信息,请参阅 LICENSE.md 文件。