Cette bibliothèque PHP contient
Il contient également plusieurs exemples/classes partielles implémentant un processus de synchronisation des données de contact d'un système source dans la base de données de contacts/prospects de Sharpspring. Cela fonctionne avec un cache local de leads Sharpspring, afin de minimiser les appels de mise à jour vers l'API REST Sharpspring.
La classe client peut être utilisée de manière autonome, bien que cette bibliothèque n'ait pas été écrite pour cela. Si vous souhaitez vous charger de construire vos propres paramètres et décoder vous-même le résultat : allez-y. Instanciez-le ; appelez la méthode call(). Vous n'avez pas besoin du reste de la bibliothèque.
Le but de la classe Connection est de vous aider à ne pas vous tromper lors de la communication avec l'API REST de Sharpspring. Il essaie d’y contribuer des manières suivantes :
(La classe LocalLeadCache n'est pas abordée ici.)
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 ' );
Le code lève des exceptions pour tout ce qu'il rencontre d'étrange... sauf pour une chose : des propriétés supplémentaires qu'il voit dans la réponse, en plus de la ou des valeurs de tableau attendues par la méthode API/Connexion spécifique que vous appelez. Ceux-ci sont ignorés par défaut ; on ne s'attend pas à ce qu'ils soient un jour rencontrés. Si vous souhaitez que ces informations soient enregistrées, transmettez un objet enregistreur compatible PSR-3 comme deuxième argument au constructeur de connexion.
Dans les « objets » (tableaux) de l'API REST Sharpspring, les champs personnalisés sont désignés par leur nom système, qui change selon le compte. Pour permettre l'écriture de code plus général, l'objet Connection possède un mappage de la propriété personnalisée au nom du système de champ. Lorsque ce mappage est défini (avec votre propre choix de noms de propriété), tous les paramètres « objets » dans les appels d'API REST verront leurs noms de propriété personnalisés traduits automatiquement en noms de système de champs correspondants.
Supposons que vous ayez des prospects pour votre magasin de chaussures, avec un champ personnalisé pour la pointure que vous avez créé via l'interface utilisateur Sharpspring, dont le nom du système est shoe_size_384c1e3eacbb3. Les deux exemples suivants sont équivalents :
$ 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.
La conversion automatique n'est effectuée que pour les « objets » dans les paramètres d'appel de l'API. Les résultats renvoyés par les appels API ne sont pas falsifiés. Si vous souhaitez que les noms de système de champs personnalisés dans les résultats de l'API soient reconvertis en noms de propriétés personnalisées, vous devrez le faire explicitement :
$ api -> setCustomProperties ( ' lead ' , [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ]);
$ leads = $ api -> getLeads ([ ' emailAddress ' => ' [email protected] ' ]);
$ lead = reset ( $ leads );
$ my_lead = $ api -> convertSystemNames ( ' lead ' , $ lead );
Utiliser des tableaux pour la représentation « objet » de l’API est très bien. Mais vous préférerez peut-être utiliser des objets/classes pour eux. (Cela vous donne la saisie semi-automatique de l'EDI, ce qui minimise également le risque de noms de propriétés mal majuscules que l'API REST ne gère pas).
La classe de base est ValueObject et il existe actuellement une classe Lead qui implémente tous les champs connus (avec des commentaires sur les endroits où la documentation de l'API de Sharpspring est obsolète).
L'exemple suivant est égal à ci-dessus :
/**
* 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 );
Évidemment, si vous n'avez pas de champs personnalisés, cet exemple devient beaucoup plus simple (car vous n'avez pas besoin de sous-classer Lead ou d'utiliser setCustomProperties() / convertSystemNames()).
Dans l'exemple ci-dessus, ValueObject ne sait rien du mappage de ses propriétés aux noms de système de champs ; l'objet Connection gère cela pour les opérations de création/mise à jour, et après les opérations « obtenir », vous devez les reconvertir explicitement en noms de propriétés personnalisés avant de construire l'objet.
Il existe également un autre moyen : vous pouvez définir le mappage dans ValueObject au lieu de 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 );
Ainsi : pour les ValueObjects qui ont des champs personnalisés, il existe la possibilité de définir un mappage de la connexion ou de la définir dans ValueObject. Cette dernière présente l'avantage que les données récupérées de l'API REST sont automatiquement converties dans le constructeur, mais l'inconvénient est que le mappage doit être défini à chaque fois qu'un objet est construit.
Il existe une autre manière : soit coder en dur le mappage à l'intérieur de l'objet, comme :
// Override the parent's (empty) property mapping variable:
protected $_customProperties = ['shoeSize' => 'shoe_size_384c1e3eacbb3'];
...ou en faisant en sorte que le constructeur de votre sous-classe ValueObject personnalisé le définisse (ou le dérive de quelque part). Ce sera probablement un code spécifique à votre propre situation.
Choisissez votre propre approche préférée.
Le comportement le plus étrange de l'API REST Sharpspring a été documenté ou partiellement atténué/caché par cette bibliothèque. Cependant, si vous envisagez d'effectuer un travail sérieux basé sur l'API, vous devez au moins être conscient de certaines choses et décider si vous devez en tenir compte.
Les valeurs avec des caractères non standard (en gros : les caractères qui seraient codés par htmlspecialchars()) sont stockées différemment dans Sharpspring selon qu'elles sont insérées via l'API REST ou saisies via l'interface utilisateur. (Et pour l'interface utilisateur, les choses diffèrent également entre les champs standard et personnalisés.) Le « < » est encore plus étrange : il est parfois stocké en double codage. Les détails sanglants sont dans encoding.md. La seule façon pour cette bibliothèque d'atténuer ce comportement est que CurlClient décode toujours tous les champs en HTML, que cela soit nécessaire ou non. Étant donné que le décodage HTML s'effectue de manière transparente, vous ne verrez probablement pas ce comportement, mais une application sérieuse devrait quand même se demander s'il s'agit d'un problème.
L'appel updateLead peut modifier les adresses e-mail d'un prospect existant en soumettant (au moins) la valeur « id » existante avec l'adresse e-mail modifiée. Cependant, si l'e-mail modifié est déjà utilisé dans un autre prospect existant, l'API ignorera silencieusement la mise à jour mais signalera quand même le succès . Il s'agit d'un problème potentiel si vous mettez en miroir une base de données de contacts existante dans laquelle les adresses e-mail ne sont pas nécessairement uniques dans Sharpspring. Vous devrez revérifier vos mises à jour pour voir si elles ont réussi. (Un exemple d'un tel code se trouve dans SharpspringSyncJob::finish().)
(J'apprécierais tout rapport faisant état de la correction de ces bogues. Ils pourraient le faire ; voir « avertissement ».)
Sharpspring change apparemment parfois le comportement de son API sans annonce ni documentation/journaux de modifications (ce qu'ils ne font pas du tout, à ma connaissance), et même sans augmenter la version de l'API mentionnée dans la documentation de l'API en ligne qui peut être trouvée derrière une connexion à leur site client.
Ce qu'il faut retenir, semble-t-il, est qu'en tant que développeur d'applications, vous devriez constamment tester votre application, car vous ne pouvez pas faire confiance à Sharpspring pour ne pas rompre son « contrat implicite » avec vous. Parce que Sharpspring n'a apparemment pas le sentiment d'avoir un « contrat implicite » avec les développeurs d'applications.
(J'ai eu des sentiments suspects à ce sujet pendant que je développais cette bibliothèque pendant six mois, mais je me base sur leur changement de comportement de l'appel getLeadsDateRange (avec le paramètre 'timestamp' défini sur "update") - qui modifiait à la fois le format des dates dans les paramètres et la sortie, ainsi que le contenu de la sortie. Voir le code source. Cela entraînait un effet immédiat - des erreurs signalées - dans les systèmes de production qui utilisaient la classe SharpspringSyncJob. doit être corrigé d'urgence. La version publiée de l'API est toujours la 1.117 et ce depuis au moins novembre 2016.
Le changement de comportement a peut-être été causé par des incohérences signalées par moi (j'ai eu un court échange d'e-mails, qui s'est terminé par l'envoi d'une liste des problèmes rencontrés avec leur API), et je suis heureux qu'ils corrigent les incohérences, mais le manque de réponse, de journal des modifications ou de changement de version de l'API conduit toujours aux points à retenir ci-dessus. J'espère bien sûr que cela changera à l'avenir et que cet avertissement pourra être supprimé, mais il semble vraiment pertinent maintenant.)
Oh regarde ! https://help.sharpspring.com/hc/en-us/articles/115001069228-Open-API-Overview mentionne désormais qu'ils ont une API « v1 » et une API « v1.2 » ! Le second accepte apparemment la saisie de la date au format UTC (ce que faisait leur API v1 jusqu'au 26 juillet 2017 environ). Il n'y a aucune mention du format des dates de sortie (qui ont également été modifiées dans la v1), cela nécessiterait donc des tests. Cette bibliothèque ne fait actuellement que l'API v1 et devrait être étendue. Ce n'est pas sur ma liste restreinte, donc les PR (ou une mission rémunérée ;)) sont les bienvenus.
Ce code a été testé avec Leads et ListMembers. D'autres appels d'API sont présents, mais tous n'ont pas été testés de manière approfondie et certains sont manquants. J'espère que l'ajout de nouveaux appels ne représente pas beaucoup de travail ; les demandes de tirage sont les bienvenues.
Soumettez simplement un PR ou contactez-moi autrement.
Le « processus de construction » (voir l'icône en haut ; un message similaire de réussite/échec apparaîtra sur les PR) vérifie uniquement les normes de codage par rapport à PHP5.6/PSR2. Il n'y a pas encore de tests unitaires puisqu'il ne s'agit que d'une fine couche de code entourant Sharpspring. Dites-moi si vous pensez qu'il devrait y avoir des tests et lesquels/pourquoi. (Ce serait évidemment bien d'avoir une suite complète de tests sur l'API Sharpspring en direct , mais je suppose que c'est un problème différent et/ou nécessite au moins une coordination plus poussée avec eux...)
J'aime apporter des logiciels open source au monde et j'aime ouvrir des systèmes semi-fermés et sous-documentés. Faites-moi signe si cela est utile ou si vous avez une contribution. Contactez-moi si vous avez besoin d'un travail d'intégration. (J'ai de l'expérience avec plusieurs autres systèmes.)
Cette bibliothèque est sous licence MIT - voir le fichier LICENSE.md pour plus de détails.