이 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/Connection 메서드에서 예상하는 배열 값 외에 응답에서 확인되는 추가 속성입니다. 이는 기본적으로 무시됩니다. 이러한 문제가 발생할 것으로 예상되지는 않습니다. 이를 기록하려면 PSR-3 호환 로거 객체를 Connection 생성자의 두 번째 인수로 전달하십시오.
Sharpspring REST API '객체'(배열)에서 사용자 정의 필드는 계정별로 변경되는 시스템 이름으로 참조됩니다. 보다 일반적인 코드를 작성할 수 있도록 연결 개체에는 사용자 정의 속성에서 필드 시스템 이름으로의 매핑이 있습니다. 이 매핑이 설정되면(자신이 선택한 속성 이름을 사용하여) REST API 호출의 모든 '객체' 매개변수는 해당 사용자 정의 속성 이름을 해당 필드 시스템 이름으로 자동으로 변환합니다.
시스템 이름이 shoe_size_384c1e3eacbb3으로 나온 Sharpspring UI를 통해 생성한 신발 사이즈에 대한 사용자 정의 필드가 있는 신발 가게에 대한 리드가 있다고 가정해 보겠습니다. 다음 두 예는 동일합니다.
$ 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 객체는 생성/업데이트 작업을 위해 이를 처리하며, 'get' 작업 후에는 객체를 구성하기 전에 이를 사용자 정의 속성 이름으로 명시적으로 다시 변환해야 합니다.
또 다른 방법도 있습니다. Connection 대신 ValueObject에서 매핑을 설정할 수 있습니다.
$ 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()로 인코딩되는 문자)가 포함된 값은 REST API를 통해 삽입되는지, UI를 통해 입력되는지에 따라 Sharpspring에 다르게 저장됩니다. (그리고 UI의 경우 표준 필드와 사용자 정의 필드의 상황도 다릅니다.) '<'는 더 이상합니다. 때로는 이중 인코딩되어 저장되기도 합니다. 자세한 내용은 인코딩.md에 있습니다. 이 라이브러리가 해당 동작을 완화할 수 있는 유일한 방법은 CurlClient가 필요 여부에 관계없이 항상 모든 필드를 HTML로 디코딩하는 것입니다. HTML 디코딩이 투명하게 발생하기 때문에 이 동작을 볼 수는 없지만 심각한 응용 프로그램에서는 이것이 문제인지 여부를 고려해야 합니다.
updateLead 호출은 변경된 이메일 주소와 함께 기존 'id' 값을 (적어도) 제출하여 기존 리드의 이메일 주소를 변경할 수 있습니다. 그러나 변경된 이메일이 이미 다른 기존 리드에서 사용되는 경우 API는 자동으로 업데이트를 삭제 하지만 여전히 성공을 보고합니다 . 이는 전자 메일 주소가 반드시 고유하지 않은 기존 연락처 데이터베이스를 Sharpspring으로 미러링하는 경우 잠재적인 문제입니다. 업데이트가 성공했는지 다시 확인해야 합니다. (이러한 코드의 한 예는 SharpspringSyncJob::finish()에 있습니다.)
(이러한 버그가 수정되었다는 보고를 환영합니다. 그럴 수도 있습니다. '경고'를 참조하세요.)
Sharpspring은 발표나 문서/변경 로그 없이(내가 아는 한 전혀 수행하지 않는) API의 동작을 변경하는 경우가 있으며 로그인 뒤에 있는 온라인 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로 날짜 입력을 허용하는 것으로 보입니다(2017년 7월 26일 경까지 v1 API가 수행한 작업). 출력 날짜 형식(v1에서도 변경됨)에 대한 언급이 없으므로 테스트가 필요합니다. 이 라이브러리는 현재 API v1만 수행하므로 확장되어야 합니다. 내 후보 목록에 없으므로 PR(또는 유료 과제;))을 환영합니다.
이 코드는 Leads 및 ListMembers로 테스트되었습니다. 더 많은 API 호출이 있지만 모두 광범위하게 테스트되지 않았으며 일부는 누락되었습니다. 새로운 통화를 추가하는 것은 많은 작업이 아니길 바랍니다. 풀 요청을 환영합니다.
PR을 제출하거나 저에게 연락해주세요.
'빌드 프로세스'(상단 아이콘 참조, 유사한 통과/실패 메시지가 PR에 표시됨)는 PHP5.6/PSR2에 대한 코딩 표준만 확인합니다. 이것은 Sharpspring을 감싸는 얇은 코드 레이어이기 때문에 아직 단위 테스트가 없습니다. 테스트가 있어야 한다고 생각하는지, 어떤 테스트/이유가 있는지 알려주세요. ( 라이브 Sharpspring API 에 대한 전체 테스트 세트를 보유하는 것은 분명히 좋을 것입니다. 그러나 그것은 다른 문제이거나 적어도 그들과의 추가 조정이 필요하다고 생각합니다...)
저는 오픈 소스 소프트웨어를 세상에 공헌하는 것을 좋아하고, 반 폐쇄적이고 문서화되지 않은 시스템을 공개하는 것을 좋아합니다. 이 내용이 유용하거나 도움이 되셨다면 저에게 알려주세요. 통합 작업이 필요하면 저에게 연락하세요. (다른 시스템에서도 경험이 있습니다.)
이 라이브러리는 MIT 라이선스에 따라 라이선스가 부여됩니다. 자세한 내용은 LICENSE.md 파일을 참조하세요.