Эта библиотека PHP содержит
Он также содержит несколько примеров/частичных классов, реализующих процесс синхронизации контактных данных из исходной системы в базу данных контактов/лидов Sharpspring. Это работает с локальным кешем потенциальных клиентов Sharpspring, чтобы свести к минимуму вызовы обновления к REST API Sharpspring.
Клиентский класс можно использовать автономно, хотя эта библиотека не была написана для этого. Если вы хотите самостоятельно позаботиться о построении собственных параметров и расшифровке результата: вперед. Создайте его экземпляр; вызовите метод call(). Остальная часть библиотеки вам не нужна.
Цель класса Connection — помочь вам не запутаться при общении с REST API Sharpspring. Он пытается помочь в этом следующими способами:
(Класс 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.
В «объектах» (массивах) REST API Sharpspring настраиваемые поля ссылаются на их системное имя, которое меняется для каждой учетной записи. Чтобы обеспечить возможность написания более общего кода, объект Connection имеет сопоставление настраиваемого свойства с именем системы полей. Когда это сопоставление установлено (с вашим собственным выбором имен свойств), любые параметры «объектов» в вызовах REST API будут иметь имена своих пользовательских свойств, автоматически преобразуемые в соответствующие имена системы полей.
Предположим, у вас есть потенциальные клиенты для вашего обувного магазина с настраиваемым полем для размера обуви, которое вы создали через пользовательский интерфейс Sharpspring, системное имя которого выглядит как 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, который реализует все известные поля (с комментариями о том, где документация по API Sharpspring устарела).
Следующий пример аналогичен приведенному выше:
/**
* 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 установил его (или получил его откуда-то). Скорее всего, это будет код, специфичный для вашей ситуации.
Выберите предпочитаемый вами подход.
Наиболее странное поведение REST API Sharpspring было задокументировано или частично смягчено/скрыто с помощью этой библиотеки. Однако, если вы собираетесь выполнять серьезную работу на основе API, есть несколько вещей, о которых вам следует как минимум знать, и решить, нужно ли вам их принимать во внимание.
Значения с нестандартными символами (примерно: символы, которые будут закодированы с помощью htmlspecialchars()) хранятся в Sharpspring по-разному в зависимости от того, вставляются ли они через REST API или через пользовательский интерфейс. (А что касается пользовательского интерфейса, стандартные и настраиваемые поля также различаются.) Символ «<» еще более странный: иногда он хранится в двойном кодировании. Более кровавые подробности — в кодировке.md. Единственный способ, с помощью которого эта библиотека смогла смягчить такое поведение, — это то, что CurlClient всегда декодирует HTML-код любых полей, независимо от того, необходимо это или нет. Поскольку декодирование HTML происходит прозрачно, вы, скорее всего, не увидите такого поведения, но серьезное приложение все равно должно учитывать, является ли это проблемой.
Вызов updateLead может изменить адреса электронной почты существующего интереса, отправив (по крайней мере) существующее значение «id» вместе с измененным адресом электронной почты. Однако, если измененный адрес электронной почты уже используется в другом существующем лиде, API автоматически отменит обновление , но все равно сообщит об успехе . Это потенциальная проблема, если вы зеркалируете существующую базу данных контактов, адреса электронной почты которой не обязательно уникальны, в Sharpspring. Вам нужно будет дважды проверить свои обновления, чтобы убедиться, что они прошли успешно. (Один пример такого кода — в SharpspringSyncJob::finish().)
(Я буду рад любым сообщениям об исправлении этих ошибок. Возможно, см. «предупреждение».)
Sharpspring, по-видимому, иногда меняет поведение своего API без объявления или документации/списков изменений (насколько мне известно, ни того, ни другого они вообще не делают) и даже без увеличения версии API, упомянутой в онлайн-документации по API, которую можно найти после входа в систему для входа в систему. их клиентский сайт.
Вывод из этого, похоже, заключается в том, что как разработчик приложений вы должны постоянно тестировать свое приложение, потому что вы не можете доверять Sharpspring в том, что он не нарушит свой «неявный контракт» с вами. Потому что Sharpspring, очевидно, не считает, что у них есть «неявный контракт» с разработчиками приложений.
(У меня были некоторые подозрительные чувства по этому поводу, пока я разрабатывал эту библиотеку в течение полугода, но я основываю это на изменении поведения вызова getLeadsDateRange (с параметром 'timestamp', установленным в значение «обновление»), которое изменило как формат дат в параметрах и выводе, так и содержимое вывода. См. исходный код. Это привело к немедленным последствиям — сообщениям об ошибках — в производственных системах, в которых использовался класс SharpspringSyncJob. требует экстренного исправления. Опубликованная версия API по-прежнему 1.117, выпущенная как минимум с ноября 2016 года.
Изменение поведения могло быть вызвано несоответствиями, о которых я сообщил (у меня был короткий обмен электронными письмами, который закончился тем, что я отправил список проблем, возникших с их API), и я рад, что они исправляют несоответствия, но отсутствие ответа, журнала изменений или изменения версии API по-прежнему приводит к вышеуказанному выводу. Я, конечно, надеюсь, что в будущем это изменится и это предупреждение можно будет удалить, но сейчас оно действительно кажется уместным.)
О, смотри! https://help.sharpspring.com/hc/en-us/articles/115001069228-Open-API-Overview теперь упоминает, что у них есть API «v1» и API «v1.2»! Второй, очевидно, принимает ввод даты в формате UTC (что и делал их API v1 примерно до 26 июля 2017 года). Нет упоминания о формате выходных дат (который также был изменен в версии 1), так что это потребует тестирования. Эта библиотека в настоящее время поддерживает только API v1 и должна быть расширена. Его нет в моем списке, поэтому пиар (или оплачиваемое задание ;)) приветствуются.
Этот код был протестирован с использованием Leads и ListMembers. Присутствуют и другие вызовы API, но не все из них были тщательно протестированы, а некоторые отсутствуют. Надеемся, добавление новых вызовов не составит большого труда; запросы на вытягивание приветствуются.
Просто отправьте PR или иным образом свяжитесь со мной.
«Процесс сборки» (см. значок вверху; аналогичное сообщение пройдено/не пройдено в PR) проверяет только стандарты кодирования на соответствие PHP5.6/PSR2. Модульных тестов пока нет, поскольку это всего лишь тонкий слой кода вокруг Sharpspring. Скажите, считаете ли вы, что тесты должны быть и какие/почему. (Очевидно, было бы неплохо иметь полный набор тестов для живого API Sharpspring , но я думаю, что это другая проблема и/или, по крайней мере, требует дальнейшей координации с ними...)
Мне нравится предлагать миру программное обеспечение с открытым исходным кодом, и мне нравится открывать полузакрытые, недокументированные системы. Поблагодарите меня, если это полезно или вы можете внести свой вклад. Свяжитесь со мной, если вам нужна работа по интеграции. (У меня есть опыт работы с несколькими другими системами.)
Эта библиотека лицензируется по лицензии MIT — подробности см. в файле LICENSE.md.