Perpustakaan PHP ini berisi
Ini juga berisi beberapa kelas contoh/parsial yang menerapkan proses sinkronisasi data kontak dari sistem sumber ke dalam database kontak/prospek Sharpspring. Ini berfungsi dengan cache lokal lead Sharpspring, untuk meminimalkan panggilan pembaruan ke Sharpspring REST API.
Kelas klien dapat digunakan secara mandiri, meskipun perpustakaan ini tidak ditulis untuk itu. Jika Anda ingin membuat parameter Anda sendiri dan mendekode hasilnya sendiri: silakan. Buat contoh; memanggil metode panggilan(). Anda tidak memerlukan sisa perpustakaan.
Tujuan dari kelas Connection adalah untuk membantu Anda agar tidak bingung dalam berkomunikasi dengan REST API Sharpspring. Ia mencoba membantu hal ini dengan cara berikut:
(Kelas LocalLeadCache tidak dibahas di sini.)
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 ' );
Kode ini memberikan pengecualian untuk segala hal aneh yang ditemuinya... kecuali untuk satu hal: properti tambahan yang dilihatnya dalam respons, selain nilai array yang diharapkan oleh metode API/Koneksi tertentu yang Anda panggil. Ini diabaikan secara default; diperkirakan mereka tidak akan pernah ditemui. Jika Anda ingin mencatatnya, teruskan objek logger yang kompatibel dengan PSR-3 sebagai argumen kedua ke konstruktor Koneksi.
Dalam 'objek' (array) Sharpspring REST API, bidang khusus dirujuk berdasarkan nama sistemnya, yang berubah per akun. Untuk mengaktifkan penulisan kode yang lebih umum, objek Connection memiliki pemetaan dari properti khusus ke nama sistem bidang. Ketika pemetaan ini diatur (dengan nama properti pilihan Anda sendiri), parameter 'objek' apa pun dalam panggilan REST API akan membuat nama properti kustomnya diterjemahkan secara otomatis ke nama sistem bidang yang sesuai.
Katakanlah Anda memiliki prospek untuk toko sepatu Anda, dengan bidang khusus untuk ukuran sepatu yang Anda buat melalui UI Sharpspring, yang nama sistemnya keluar sebagai shoe_size_384c1e3eacbb3. Dua contoh berikut ini setara:
$ 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.
Konversi otomatis hanya dilakukan untuk 'objek' dalam parameter panggilan API. Hasil yang dikembalikan dari panggilan API tidak diubah. Jika Anda ingin nama sistem bidang khusus dalam hasil API dikonversi kembali ke nama properti khusus, Anda perlu melakukan ini secara eksplisit:
$ api -> setCustomProperties ( ' lead ' , [ ' shoeSize ' => ' shoe_size_384c1e3eacbb3 ' ]);
$ leads = $ api -> getLeads ([ ' emailAddress ' => ' [email protected] ' ]);
$ lead = reset ( $ leads );
$ my_lead = $ api -> convertSystemNames ( ' lead ' , $ lead );
Menggunakan array untuk representasi 'objek' API tidak masalah. Tetapi Anda mungkin lebih suka menggunakan objek/kelas untuknya. (Ini memberi Anda pelengkapan otomatis IDE, yang juga meminimalkan kemungkinan kesalahan penggunaan huruf besar pada nama properti yang tidak ditangani oleh REST API).
Kelas dasarnya adalah ValueObject dan saat ini ada kelas Lead yang mengimplementasikan semua bidang yang diketahui (dengan komentar tentang dokumentasi API Sharpspring yang sudah usang).
Contoh berikut sama dengan di atas:
/**
* 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 );
Jelasnya, jika Anda tidak memiliki bidang khusus maka contoh ini menjadi jauh lebih sederhana (karena Anda tidak perlu membuat subkelas Lead atau menggunakan setCustomProperties() / convertSystemNames()).
Dalam contoh di atas, ValueObject tidak mengetahui apa pun tentang pemetaan propertinya ke nama sistem bidang; objek Connection menangani ini untuk operasi buat/perbarui, dan setelah operasi 'dapatkan' Anda perlu mengonversinya secara eksplisit kembali ke nama properti khusus sebelum membuat objek.
Ada juga cara lain: Anda dapat mengatur pemetaan di ValueObject alih-alih 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 );
Jadi: untuk ValueObjects yang memiliki bidang khusus, ada opsi untuk mengatur pemetaan koneksi, atau mengaturnya di ValueObject. Yang terakhir ini memiliki keuntungan bahwa data yang diambil dari REST API secara otomatis dikonversi di konstruktor, namun kelemahannya adalah pemetaan perlu disetel setiap kali suatu objek dibuat.
Ada cara lain: melakukan hardcoding pemetaan di dalam objek, seperti:
// Override the parent's (empty) property mapping variable:
protected $_customProperties = ['shoeSize' => 'shoe_size_384c1e3eacbb3'];
...atau membuat konstruktor subkelas ValueObject khusus Anda menyetelnya (atau mendapatkannya dari suatu tempat). Itu kemungkinan besar merupakan kode khusus untuk situasi Anda sendiri.
Pilih pendekatan pilihan Anda sendiri.
Perilaku paling aneh dari Sharpspring REST API telah didokumentasikan atau sebagian dimitigasi/disembunyikan oleh perpustakaan ini. Namun jika Anda akan melakukan pekerjaan serius berdasarkan API, ada beberapa hal yang setidaknya harus Anda waspadai, dan putuskan apakah Anda perlu mempertimbangkan hal ini.
Nilai dengan karakter non-standar (kira-kira: karakter yang akan dikodekan oleh htmlspecialchars()) disimpan di Sharpspring secara berbeda bergantung pada apakah nilai tersebut dimasukkan melalui REST API atau dimasukkan melalui UI. (Dan untuk UI, ada perbedaan antara bidang standar dan khusus.) Tanda '<' bahkan lebih aneh lagi: terkadang disimpan dengan kode ganda. Detail berdarahnya ada di coding.md. Satu-satunya cara perpustakaan ini dapat memitigasi perilaku tersebut adalah dengan CurlClient untuk selalu mendekode HTML bidang apa pun, baik diperlukan atau tidak. Karena decoding HTML terjadi secara transparan, Anda mungkin tidak akan melihat perilaku ini, namun aplikasi yang serius tetap harus mempertimbangkan apakah ini merupakan masalah.
Panggilan updateLead dapat mengubah alamat email prospek yang ada dengan mengirimkan (setidaknya) nilai 'id' yang ada bersama dengan alamat email yang diubah. Namun jika email yang diubah ternyata sudah digunakan di prospek lain yang sudah ada, API akan secara diam-diam membuang pembaruan namun tetap melaporkan keberhasilan . Ini adalah masalah potensial jika Anda mencerminkan database kontak yang sudah ada yang alamat emailnya belum tentu unik, ke Sharpspring. Anda perlu memeriksa ulang pembaruan Anda untuk melihat apakah pembaruan tersebut berhasil. (Salah satu contoh kode tersebut ada di SharpspringSyncJob::finish().)
(Saya menyambut baik laporan apa pun tentang perbaikan bug ini. Mungkin saja; lihat 'peringatan'.)
Sharpspring rupanya terkadang mengubah perilaku API mereka tanpa pengumuman atau dokumentasi/changelog (sepengetahuan saya tidak ada yang melakukannya sama sekali), dan bahkan tanpa meningkatkan versi API yang disebutkan dalam dokumentasi API online yang dapat ditemukan di belakang login ke situs pelanggan mereka.
Tampaknya, kesimpulan dari hal ini adalah sebagai pengembang aplikasi Anda harus terus-menerus menguji aplikasi Anda karena Anda tidak dapat mempercayai Sharpspring untuk tidak melanggar 'kontrak implisit' mereka dengan Anda. Pasalnya Sharpspring rupanya tidak merasa memiliki 'kontrak implisit' dengan pengembang aplikasi.
(Saya memiliki perasaan curiga tentang hal ini ketika saya mengembangkan perpustakaan ini selama setengah tahun, tetapi yang saya dasarkan adalah perubahan perilaku panggilan getLeadsDateRange (dengan parameter 'cap waktu' disetel ke "update") - yang mengubah format tanggal dalam parameter dan output, dan konten output. Lihat kode sumber. Hal ini menyebabkan efek langsung -kesalahan dilaporkan- dalam sistem produksi yang menggunakan kelas SharpspringSyncJob, yang memiliki menjadi ditambal darurat. Versi API yang dipublikasikan masih 1.117 dan sudah ada setidaknya sejak November 2016.
Perubahan perilaku mungkin disebabkan oleh ketidakkonsistenan yang saya laporkan (saya melakukan pertukaran email singkat, yang berakhir dengan saya mengirimkan daftar masalah yang dihadapi dengan API mereka), dan saya senang mereka memperbaiki ketidakkonsistenan, tetapi kekurangannya respons, log perubahan, atau perubahan versi API masih mengarah pada kesimpulan di atas. Tentu saja saya berharap hal ini akan berubah di masa mendatang dan peringatan ini dapat dihapus, namun tampaknya hal ini relevan untuk saat ini.)
Oh lihat! https://help.sharspring.com/hc/en-us/articles/115001069228-Open-API-Overview sekarang menyebutkan bahwa mereka memiliki API 'v1' dan API 'v1.2'! Yang kedua tampaknya menerima input tanggal sebagai UTC (yang dilakukan API v1 mereka hingga sekitar 26 Juli 2017). Tidak disebutkan format tanggal keluaran (yang juga diubah di v1), sehingga perlu pengujian. Perpustakaan ini saat ini hanya menjalankan API v1 dan harus diperluas. Itu tidak ada dalam daftar pendek saya jadi PR (atau tugas berbayar;)) diterima.
Kode ini telah diuji dengan Leads dan ListMembers. Ada lebih banyak panggilan API tetapi tidak semuanya telah diuji secara ekstensif dan ada pula yang hilang. Menambahkan panggilan baru semoga tidak merepotkan; permintaan tarik disambut.
Kirimkan saja PR atau hubungi saya.
'Proses pembangunan' (lihat ikon di atas; pesan lulus/gagal serupa akan muncul di PR) hanya memeriksa standar pengkodean terhadap PHP5.6/PSR2. Belum ada pengujian unit karena ini hanyalah lapisan tipis kode yang membungkus Sharpspring. Beri tahu saya jika menurut Anda harus ada tes dan apa/mengapa. (Tentu saja akan menyenangkan untuk memiliki serangkaian pengujian lengkap terhadap API Sharpspring langsung , tapi saya rasa itu masalah yang berbeda dan/atau setidaknya memerlukan koordinasi lebih lanjut dengan mereka...)
Saya suka menyumbangkan perangkat lunak sumber terbuka kepada dunia dan saya suka membuka sistem setengah tertutup yang tidak terdokumentasi. Beri saya sapaan jika ini berguna atau jika Anda memiliki kontribusi. Hubungi saya jika Anda perlu menyelesaikan pekerjaan integrasi. (Saya punya pengalaman dengan beberapa sistem lain.)
Perpustakaan ini dilisensikan di bawah Lisensi MIT - lihat file LICENSE.md untuk detailnya.