Diese PHP-Bibliothek enthält
Es enthält außerdem mehrere Beispiel-/Teilklassen, die einen Synchronisierungsprozess von Kontaktdaten aus einem Quellsystem in die Kontakt-/Leads-Datenbank von Sharpspring implementieren. Dies funktioniert mit einem lokalen Cache von Sharpspring-Leads, um Aktualisierungsaufrufe an die Sharpspring-REST-API zu minimieren.
Die Client-Klasse kann eigenständig verwendet werden, obwohl diese Bibliothek nicht dafür geschrieben wurde. Wenn Sie sich um die Erstellung Ihrer eigenen Parameter und die Dekodierung des Ergebnisses kümmern möchten, fahren Sie fort. Instanziieren Sie es; Rufen Sie die Methode call() auf. Den Rest der Bibliothek benötigen Sie nicht.
Das Ziel der Connection-Klasse besteht darin , Ihnen bei der Kommunikation mit der REST-API von Sharpspring zu helfen . Es versucht dabei auf folgende Weise zu helfen:
(Die LocalLeadCache-Klasse wird hier nicht besprochen.)
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 ' );
Der Code löst Ausnahmen für alles Seltsame aus, auf das er stößt ... mit Ausnahme einer Sache: zusätzliche Eigenschaften, die er in der Antwort sieht, zusätzlich zu den Array-Werten, die von der spezifischen API/Verbindungsmethode, die Sie aufrufen, erwartet werden. Diese werden standardmäßig ignoriert; Es ist nicht zu erwarten, dass sie jemals angetroffen werden. Wenn Sie diese protokollieren möchten, übergeben Sie ein PSR-3-kompatibles Logger-Objekt als zweites Argument an den Verbindungskonstruktor.
In „Objekten“ (Arrays) der Sharpspring REST API werden benutzerdefinierte Felder mit ihrem Systemnamen bezeichnet, der sich je nach Konto ändert. Um das Schreiben von allgemeinerem Code zu ermöglichen, verfügt das Connection-Objekt über eine Zuordnung von der benutzerdefinierten Eigenschaft zum Feldsystemnamen. Wenn diese Zuordnung festgelegt ist (mit von Ihnen selbst gewählten Eigenschaftsnamen), werden die benutzerdefinierten Eigenschaftsnamen aller „Objekte“-Parameter in REST-API-Aufrufen automatisch in die entsprechenden Feldsystemnamen übersetzt.
Angenommen, Sie haben Leads für Ihr Schuhgeschäft mit einem benutzerdefinierten Feld für die Schuhgröße, das Sie über die Sharpspring-Benutzeroberfläche erstellt haben und dessen Systemname „shoe_size_384c1e3eacbb3“ lautet. Die folgenden zwei Beispiele sind äquivalent:
$ 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.
Die automatische Konvertierung erfolgt nur für „Objekte“ in API-Aufrufparametern. Von API-Aufrufen zurückgegebene Ergebnisse werden nicht manipuliert. Wenn Sie möchten, dass benutzerdefinierte Feldsystemnamen in API-Ergebnissen wieder in Ihre benutzerdefinierten Eigenschaftsnamen konvertiert werden, müssen Sie dies explizit tun:
$ api -> setCustomProperties ( ' lead ' , [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ]);
$ leads = $ api -> getLeads ([ ' emailAddress ' => ' [email protected] ' ]);
$ lead = reset ( $ leads );
$ my_lead = $ api -> convertSystemNames ( ' lead ' , $ lead );
Die Verwendung von Arrays für die API-Objektdarstellung ist völlig in Ordnung. Möglicherweise bevorzugen Sie jedoch die Verwendung von Objekten/Klassen dafür. (Es ermöglicht Ihnen die automatische IDE-Vervollständigung, wodurch auch das Risiko falsch geschriebener Eigenschaftsnamen minimiert wird, die von der REST-API nicht verarbeitet werden.)
Die Basisklasse ist ValueObject und derzeit gibt es eine Lead-Klasse, die alle bekannten Felder implementiert (mit Kommentaren dazu, wo die API-Dokumentation von Sharpspring veraltet ist).
Das folgende Beispiel entspricht dem oben:
/**
* 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 );
Wenn Sie keine benutzerdefinierten Felder haben, wird dieses Beispiel natürlich viel einfacher (da Sie keine Unterklasse von Lead erstellen oder setCustomProperties()/convertSystemNames() verwenden müssen).
Im obigen Beispiel weiß das ValueObject nichts über die Zuordnung seiner Eigenschaften zu Feldsystemnamen; Das Connection-Objekt übernimmt dies für Erstellungs-/Aktualisierungsvorgänge. Nach „Get“-Vorgängen müssen Sie diese explizit wieder in benutzerdefinierte Eigenschaftsnamen konvertieren, bevor Sie das Objekt erstellen.
Es gibt auch eine andere Möglichkeit: Sie können die Zuordnung im ValueObject statt in der Connection festlegen.
$ 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 );
Also: Für ValueObjects mit benutzerdefinierten Feldern gibt es die Möglichkeit, eine Zuordnung der Verbindung festzulegen oder diese im ValueObject festzulegen. Letzteres hat den Vorteil, dass von der REST-API abgerufene Daten automatisch im Konstruktor konvertiert werden, hat jedoch den Nachteil, dass die Zuordnung bei jedem Aufbau eines Objekts festgelegt werden muss.
Es gibt noch einen anderen Weg: Entweder die Zuordnung innerhalb des Objekts fest codieren, wie zum Beispiel:
// Override the parent's (empty) property mapping variable:
protected $_customProperties = ['shoeSize' => 'shoe_size_384c1e3eacbb3'];
... oder den Konstruktor Ihrer benutzerdefinierten ValueObject-Unterklasse festlegen (oder von irgendwoher ableiten). Das wird wahrscheinlich ein Code sein, der speziell auf Ihre eigene Situation zugeschnitten ist.
Wählen Sie Ihren bevorzugten Ansatz.
Das seltsamste Verhalten der Sharpspring REST API wurde von dieser Bibliothek dokumentiert oder teilweise abgeschwächt/versteckt. Wenn Sie jedoch ernsthafte Arbeiten auf Basis der API durchführen möchten, sollten Sie sich zumindest einiger Dinge bewusst sein und entscheiden, ob Sie diese berücksichtigen müssen.
Werte mit nicht standardmäßigen Zeichen (ungefähr: Zeichen, die von htmlspecialchars() codiert würden) werden in Sharpspring unterschiedlich gespeichert, je nachdem, ob sie über die REST-API eingefügt oder über die Benutzeroberfläche eingegeben werden. (Und für die Benutzeroberfläche gibt es auch Unterschiede zwischen Standard- und benutzerdefinierten Feldern.) Das „<“ ist noch seltsamer: Es wird manchmal doppelt codiert gespeichert. Die blutrünstigen Details finden Sie in der Datei „encoding.md“. Die einzige Möglichkeit, wie diese Bibliothek dieses Verhalten abmildern konnte, besteht darin, dass CurlClient alle Felder immer HTML-dekodiert, unabhängig davon, ob dies erforderlich ist oder nicht. Da die HTML-Dekodierung transparent erfolgt, werden Sie dieses Verhalten wahrscheinlich nicht bemerken, eine seriöse Anwendung sollte jedoch dennoch prüfen, ob dies ein Problem darstellt.
Der updateLead-Aufruf kann die E-Mail-Adressen eines vorhandenen Leads ändern, indem (mindestens) der vorhandene „id“-Wert zusammen mit der geänderten E-Mail-Adresse übermittelt wird. Wenn die geänderte E-Mail-Adresse jedoch bereits in einem anderen bestehenden Lead verwendet wird, verwirft die API die Aktualisierung stillschweigend , meldet jedoch weiterhin den Erfolg . Dies stellt ein potenzielles Problem dar, wenn Sie eine vorhandene Kontaktdatenbank, in der E-Mail-Adressen nicht unbedingt eindeutig sind, in Sharpspring spiegeln. Sie müssen Ihre Aktualisierungen noch einmal überprüfen, um festzustellen, ob sie erfolgreich waren. (Ein Beispiel für einen solchen Code ist SharpspringSyncJob::finish().)
(Ich würde mich über jeden Bericht über die Behebung dieser Fehler freuen. Das könnte der Fall sein; siehe „Warnung“.)
Sharpspring ändert offenbar manchmal das Verhalten seiner API ohne Ankündigung oder Dokumentation/Änderungsprotokolle (was sie meines Wissens überhaupt nicht tun) und sogar ohne die API-Version zu erhöhen, die in der Online-API-Dokumentation erwähnt wird, die hinter einer Anmeldung bei zu finden ist ihre Kundenseite.
Die Schlussfolgerung daraus scheint zu sein, dass Sie als Anwendungsentwickler Ihre Anwendung ständig testen sollten, da Sie sich nicht darauf verlassen können, dass Sharpspring seinen „impliziten Vertrag“ mit Ihnen nicht bricht. Denn Sharpspring hat offenbar nicht das Gefühl, einen „impliziten Vertrag“ mit Anwendungsentwicklern zu haben.
(Während ich diese Bibliothek im Laufe eines halben Jahres entwickelte, hatte ich einige misstrauische Gefühle, aber ich stütze mich dabei auf die Verhaltensänderung beim getLeadsDateRange-Aufruf (wobei der Parameter „timestamp“ auf eingestellt ist). „update“) – wodurch sich sowohl das Format der Datumsangaben in Parametern und der Ausgabe als auch der Inhalt der Ausgabe änderte. Dies führte zu sofortigen Auswirkungen – gemeldeten Fehlern – in Produktionssystemen, die die SharpspringSyncJob-Klasse verwendeten musste dringend gepatcht werden. Die veröffentlichte API-Version ist immer noch 1.117 und das bereits seit mindestens November 2016.
Die Verhaltensänderung wurde möglicherweise durch von mir gemeldete Inkonsistenzen verursacht (ich hatte einen kurzen E-Mail-Austausch, der damit endete, dass ich eine Liste der mit ihrer API aufgetretenen Probleme verschickte), und ich bin froh, dass sie Inkonsistenzen beheben, aber der Mangel Antwort-, Changelog- oder API-Versionsänderungen führen immer noch zu der oben genannten Erkenntnis. Ich hoffe natürlich, dass sich dies in Zukunft ändert und diese Warnung möglicherweise gelöscht wird, aber sie scheint jetzt wirklich relevant zu sein.)
Oh schau! https://help.sharpspring.com/hc/en-us/articles/115001069228-Open-API-Overview erwähnt jetzt, dass sie eine „v1“-API und eine „v1.2“-API haben! Der zweite akzeptiert offenbar die Datumseingabe als UTC (was ihre v1-API bis etwa zum 26. Juli 2017 tat). Das Format der Ausgabedaten (die in Version 1 ebenfalls geändert wurden) wird nicht erwähnt, sodass dies getestet werden müsste. Diese Bibliothek unterstützt derzeit nur API v1 und sollte erweitert werden. Es steht nicht auf meiner engeren Auswahlliste, daher sind PRs (oder ein bezahlter Auftrag ;)) willkommen.
Dieser Code wurde mit Leads und ListMembers getestet. Es sind weitere API-Aufrufe vorhanden, aber nicht alle wurden ausführlich getestet und einige fehlen. Das Hinzufügen neuer Anrufe ist hoffentlich nicht viel Arbeit; Pull-Anfragen sind willkommen.
Reichen Sie einfach eine PR ein oder kontaktieren Sie mich auf andere Weise.
Der „Build-Prozess“ (siehe Symbol oben; eine ähnliche Meldung „Bestanden/fehlgeschlagen“ wird auf PRs angezeigt) überprüft nur Codierungsstandards anhand von PHP5.6/PSR2. Es gibt noch keine Unit-Tests, da es sich lediglich um eine dünne Codeschicht handelt, die Sharpspring umhüllt. Sagen Sie mir, ob es Ihrer Meinung nach Tests geben sollte und welche/warum. (Es wäre natürlich schön, eine vollständige Suite von Tests für die Live-Sharpspring-API zu haben, aber ich denke, das ist ein anderes Problem und/oder erfordert zumindest eine weitere Abstimmung mit ihnen ...)
Ich mag es, der Welt Open-Source-Software zur Verfügung zu stellen und ich mag es, halbgeschlossene, unzureichend dokumentierte Systeme zu öffnen. Begrüßen Sie mich, wenn dies hilfreich ist oder Sie einen Beitrag leisten können. Kontaktieren Sie mich, wenn Sie Integrationsarbeit benötigen. (Ich habe Erfahrung mit mehreren anderen Systemen.)
Diese Bibliothek ist unter der MIT-Lizenz lizenziert – Einzelheiten finden Sie in der Datei LICENSE.md.