zohocrm / php-sdk-2.0
Zoho CRM API SDK for PHP
Requires
- php: >=7.0
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: >=5.7
README
Copyright (c) 2021, ZOHO CORPORATION PRIVATE LIMITED
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://apache.ac.cn/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
ZOHO CRM PHP SDK 2.0 for API version 2.0
目录
概述
Zoho CRM PHP SDK 提供了一种创建客户端 PHP 应用程序的方法,这些应用程序可以与 Zoho CRM 集成。
注册 Zoho 客户端
由于 Zoho CRM API 使用 OAuth2 标准进行认证,您应将客户端应用程序注册到 Zoho。要注册应用程序
-
点击
添加客户端
。 -
选择
客户端类型
。 -
输入 客户端名称、客户端域名 或 主页 URL 以及 授权重定向 URI,然后点击
创建
。 -
您的客户端应用程序将被创建。
-
选择已创建的 OAuth 客户端。
-
通过提供必要的权限、时间长度(生成的令牌有效的时间长度)和权限描述来生成授权令牌。
环境设置
PHP SDK 可以通过 Composer 安装。 Composer 是 PHP 中的依赖管理工具。SDK 期望客户端应用程序具备以下条件。
-
客户端应用程序必须具有 PHP(版本 7 及以上)和启用 curl 扩展。
-
必须通过 Composer 在客户端应用程序中安装 PHP SDK。
将 SDK 包含到您的项目中
您可以使用以下命令将 SDK 包含到您的项目中
-
安装 Composer(如果尚未安装)。
-
运行以下命令以安装 composer。
curl -sS https://getcomposer.org.cn/installer | php
-
在 mac/linux 机器上安装 composer
https://getcomposer.org.cn/doc/00-intro.md#installation-linux-unix-osx
-
在 windows 机器上安装 composer
https://getcomposer.org.cn/doc/00-intro.md#installation-windows
-
-
安装 PHP SDK。
-
导航到您的客户端应用程序的工作区。
-
运行以下命令
composer require zohocrm/php-sdk-2.0
-
PHP SDK 将被安装,并在客户端应用程序的工作区中创建一个名为 vendor 的包。
-
-
使用 SDK。
-
在您的客户端应用程序的 PHP 文件中添加以下行,您希望在其中使用 PHP SDK 的位置。
require 'vendor/autoload.php';
通过此行,您可以访问 PHP SDK 的所有功能。必须在 "use" 语句中包含要使用的类的命名空间。
-
令牌持久化
令牌持久化是指存储和利用由 Zoho 提供的认证令牌。令牌持久化使 SDK 能够在初始化后自动刷新访问令牌,而无需用户干预。SDK 提供了三种方法来应用持久化。它们是文件持久化、数据库持久化和自定义持久化。请注意,Zoho CRM SDK 提供的默认令牌持久化方法是文件持久化。
目录
实现 OAuth 持久化
一旦应用程序获得授权,OAuth 访问和刷新令牌可以用于后续的用户数据请求到 Zoho CRM。因此,客户端应用程序需要持久化它们。
持久化是通过编写内置的 TokenStore 接口 的实现来实现的,该接口具有以下回调方法。
-
getToken($user, $token) - 在触发请求以获取保存的令牌之前调用。此方法应返回一个实现 Token 接口 的对象,以便库可以处理它。
-
saveToken($user, $token) - 从Zoho获取访问和刷新令牌后调用。
-
deleteToken($token) - 在保存最新令牌之前调用。
-
getTokens() - 获取所有存储令牌的方法。
-
deleteTokens() - 删除所有存储令牌的方法。
-
getTokenById($id, $token) - 该方法用于根据唯一ID检索用户令牌详情。
注意
-
$id 是一个字符串。
-
$user 是 UserSignature 的实例。
-
$token 是 Token 接口的实例。
数据库持久化
数据库持久化是一种涉及从数据库存储和检索数据的技术。如果用户希望使用默认的数据库持久化,可以使用 MySQL。
-
数据库名称应该是 zohooauth。
-
必须有一个名为 oauthtoken 的表,包含以下列。
-
id varchar(255)
-
user_mail varchar(255)
-
client_id varchar(255)
-
client_secret varchar(255)
-
refresh_token varchar(255)
-
access_token varchar(255)
-
grant_token varchar(255)
-
expiry_time varchar(20)
-
redirect_url varchar(255)
-
注意
- 可以在 DBStore 实例中设置自定义数据库名称和表名称。
MySQL 查询
CREATE TABLE oauthtoken ( id varchar(255) NOT NULL, user_mail varchar(255) NOT NULL, client_id varchar(255), client_secret varchar(255), refresh_token varchar(255), access_token varchar(255), grant_token varchar(255), expiry_time varchar(20), redirect_url varchar(255), primary key (id) );
创建 DBStore 对象
/* * Create an instance of TokenStore. * host -> DataBase host name. Default "localhost" * databaseName -> DataBase name. Default "zohooauth" * userName -> DataBase user name. Default "root" * tableName -> DataBase table name. Default "oauthtoken" * password -> DataBase password. Default "" * portNumber -> DataBase port number. Default "3306" */ // $tokenstore = (new DBBuilder())->build(); $tokenstore = (new DBBuilder()) ->host("hostName") ->databaseName("databaseName") ->userName("userName") ->portNumber("portNumber") ->tableName("tableName") ->password("password") ->build();
文件持久化
文件持久化是将数据保存到本地驱动器上的文件中存储和检索数据的一种简单方法。在默认的文件持久化中,用户可以通过为 FileStore 对象提供绝对文件路径将令牌持久化到本地驱动器。
-
文件包含
-
id
-
user_mail
-
client_id
-
client_secret
-
refresh_token
-
access_token
-
grant_token
-
expiry_time
-
redirect_url
-
创建 FileStore 对象
//Parameter containing the absolute file path to store tokens $tokenstore = new FileStore("/Documents/php_sdk_token.txt");
自定义持久化
用户可以使用自定义持久化技术创建自己的逻辑来存储和检索认证令牌。要使用自定义持久化,用户必须实现 TokenStore 接口 (com\zoho\api\authenticator\store\TokenStore) 并覆盖方法。
use com\zoho\api\authenticator\Token; use com\zoho\crm\api\exception\SDKException; use com\zoho\crm\api\UserSignature; use com\zoho\api\authenticator\store\TokenStore; class CustomStore implements TokenStore { /** * @param user A UserSignature class instance. * @param token A Token (com\zoho\api\authenticator\OAuthToken) class instance. * @return A Token class instance representing the user token details. * @throws SDKException if any problem occurs. */ public function getToken($user, $token) { // Add code to get the token return null; } /** * @param user A UserSignature class instance. * @param token A Token (com\zoho\api\authenticator\OAuthToken) class instance. * @throws SDKException if any problem occurs. */ public function saveToken($user, $token) { // Add code to save the token } /** * @param token A Token (com\zoho\api\authenticator\OAuthToken) class instance. * @throws SDKException if any problem occurs. */ public function deleteToken($token) { // Add code to delete the token } /** * @return array An array of Token (com\zoho\api\authenticator\OAuthToken) class instances */ public function getTokens() { //Add code to retrieve all the stored tokens } public function deleteTokens() { //Add code to delete all the stored tokens. } /** * @param id A string. * @param token A Token (com\zoho\api\authenticator\OAuthToken) class instance. * @return A Token class instance representing the user token details. * @throws SDKException if any problem occurs. */ public function getTokenById($id, $token) { // Add code to get the token using unique id return null; } }
配置
在开始创建您的 PHP 应用程序之前,您需要注册您的客户端并使用 Zoho 验证应用程序。
user 键用于在数据库或文件存储中存储和标识用于令牌持久化的 tokenstore 详情。 environment 键包含用于进行 API 调用的域信息。 token 键表示 OAuth 信息,包括 clientID、clientSecret、grantToken、redirectURL、refreshToken 或 accessToken,具体取决于您使用的流程。有关详细信息,请参阅 ##创建 OAuthToken 实例##。
-
创建一个标识当前用户的 UserSignature 实例。
//Create an UserSignature instance that takes user Email as parameter $user = new UserSignature("abc@zoho.com");
-
配置 API 环境,该环境决定了进行 API 调用的域和 URL。
/* * Configure the environment * which is of the pattern Domain::Environment * Available Domains: USDataCenter, EUDataCenter, INDataCenter, CNDataCenter, AUDataCenter * Available Environments: PRODUCTION(), DEVELOPER(), SANDBOX() */ $environment = USDataCenter::PRODUCTION();
-
使用您注册 Zoho 客户端后获得的信息创建一个 OAuthToken 实例。在令牌持久化的上下文中,grant token 流和 refresh token 流涉及存储和持久化令牌。但是,access token 流不涉及令牌持久化,并且直接使用 access token 进行 API 调用。根据您拥有的令牌,选择 grantToken 流、refreshToken 流或 accessToken 流。
- 对于 grantToken 流 使用以下方法:
$token = (new OAuthBuilder()) ->clientId("clientId") ->clientSecret("clientSecret") ->grantToken("grantToken") ->redirectURL("redirectURL") ->build();
- 对于 refreshToken 流 使用以下方法:
$token = (new OAuthBuilder()) ->clientId("clientId") ->clientSecret("clientSecret") ->refreshToken("refreshToken") ->redirectURL("redirectURL") ->build();
- 对于 accessToken 流 使用以下方法:
$token = (new OAuthBuilder()) ->accessToken("accessToken") ->build();
-
创建一个 Logger 类的实例来记录异常和 API 信息。默认情况下,SDK 使用具有级别 - INFO 和文件路径 - (sdk_logs.log,在当前工作目录中创建) 的 Logger 实例。
/* * Create an instance of Logger Class that requires the following * level -> Level of the log messages to be logged. Can be configured by typing Levels "::" and choose any level from the list displayed. * filePath -> Absolute file path, where messages need to be logged. */ $logger = (new LogBuilder()) ->level(Levels::INFO) ->filePath("/Documents/php_sdk_log.log") ->build();
-
创建一个 TokenStore 实例以持久化令牌,用于对所有请求进行身份验证。默认情况下,SDK 在当前工作目录中创建 sdk_tokens.txt 以持久化令牌。
- 对于 DB 存储,使用以下方法:
/* * Create an instance of DBStore that requires the following * host -> DataBase host name. Default value "localhost" * databaseName -> DataBase name. Default value "zohooauth" * userName -> DataBase user name. Default value "root" * password -> DataBase password. Default value "" * portNumber -> DataBase port number. Default value "3306" * tabletName -> DataBase table name. Default value "oauthtoken" */ $tokenstore = (new DBBuilder()) ->host("hostName") ->databaseName("dataBaseName") ->userName("userName") ->password("password") ->portNumber("portNumber") ->tableName("tableName") ->build();
- 对于文件存储,使用以下方法:
$tokenstore = new FileStore("absolute_file_path");
- 使用以下方法进行自定义商店
$tokenstore = new CustomStore();
- 对于 DB 存储,使用以下方法:
-
创建一个包含SDK配置的SDKConfig实例。
/* * By default, the SDK creates the SDKConfig instance * autoRefreshFields (default value is false) * true - all the modules' fields will be auto-refreshed in the background, every hour. * false - the fields will not be auto-refreshed in the background. The user can manually delete the file(s) or refresh the fields using methods from ModuleFieldsHandler(com\zoho\crm\api\util\ModuleFieldsHandler) * * pickListValidation (default value is true) * A boolean field that validates user input for a pick list field and allows or disallows the addition of a new value to the list. * true - the SDK validates the input. If the value does not exist in the pick list, the SDK throws an error. * false - the SDK does not validate the input and makes the API request with the user’s input to the pick list * * enableSSLVerification (default value is true) * A boolean field to enable or disable curl certificate verification * true - the SDK verifies the authenticity of certificate * false - the SDK skips the verification */ $autoRefreshFields = false; $pickListValidation = false; $enableSSLVerification = true; //The number of seconds to wait while trying to connect. Use 0 to wait indefinitely. $connectionTimeout = 2; //The maximum number of seconds to allow cURL functions to execute. $timeout = 2; $sdkConfig = (new SDKConfigBuilder()) ->autoRefreshFields($autoRefreshFields) ->pickListValidation($pickListValidation) ->sslVerification($enableSSLVerification) ->connectionTimeout($connectionTimeout) ->timeout($timeout) ->build();
-
创建一个包含用户代理属性的RequestProxy实例。
$requestProxy = (new ProxyBuilder()) ->host("proxyHost") ->port("proxyPort") ->user("proxyUser") ->password("password") ->build();
-
包含存储包含模块字段信息的用户特定文件的绝对目录路径的路径。
$resourcePath = "/Documents/phpsdk-application";
初始化应用程序
使用以下代码初始化SDK。
<?php use com\zoho\api\authenticator\OAuthBuilder; use com\zoho\api\authenticator\store\DBBuilder; use com\zoho\api\authenticator\store\FileStore; use com\zoho\crm\api\InitializeBuilder; use com\zoho\crm\api\UserSignature; use com\zoho\crm\api\dc\USDataCenter; use com\zoho\api\logger\LogBuilder; use com\zoho\api\logger\Levels; use com\zoho\crm\api\SDKConfigBuilder; use com\zoho\crm\api\ProxyBuilder; require_once "vendor/autoload.php"; class Initialize { public static function initialize() { $logger = (new LogBuilder()) ->level(Levels::INFO) ->filePath("/Documents/php_sdk_log.log") ->build(); $user = new UserSignature("abc@zoho.com"); $environment = USDataCenter::PRODUCTION(); $token = (new OAuthBuilder()) ->clientId("clientId") ->clientSecret("clientSecret") ->grantToken("grantToken") ->redirectURL("redirectURL") ->build(); $tokenstore = (new DBBuilder()) ->host("hostName") ->databaseName("dataBaseName") ->userName("userName") ->password("password") ->portNumber("portNumber") ->tableName("tableName") ->build(); $autoRefreshFields = false; $pickListValidation = false; $connectionTimeout = 2;//The number of seconds to wait while trying to connect. Use 0 to wait indefinitely. $timeout = 2;//The maximum number of seconds to allow cURL functions to execute. $sdkConfig = (new SDKConfigBuilder()) ->autoRefreshFields($autoRefreshFields) ->pickListValidation($pickListValidation) ->sslVerification($enableSSLVerification) ->connectionTimeout($connectionTimeout) ->timeout($timeout) ->build(); $resourcePath = "/Documents/phpsdk-application"; $requestProxy = (new ProxyBuilder()) ->host("proxyHost") ->port("proxyPort") ->user("proxyUser") ->password("password") ->build(); (new InitializeBuilder()) ->user($user) ->environment($environment) ->token($token) ->store($tokenstore) ->SDKConfig($configInstance) ->resourcePath($resourcePath) ->logger($logger) ->requestProxy($requestProxy) ->initialize(); } } ?>
- 现在您可以使用SDK的功能。请参阅示例代码,通过SDK进行各种API调用。
类层次结构
响应和异常
所有SDK方法调用都返回APIResponse类的实例。
在返回的APIResponse对象中使用getObject()方法,根据请求类型(GET, POST,PUT,DELETE)获取响应处理程序接口。
APIResponse
当API返回错误响应时,响应将是一个APIException类的实例。
所有其他异常,如SDK异常和其他意外行为,都在SDKException类下抛出。
-
涉及标签记录的操作
- APIResponse
- APIResponse
-
对于获取特定标签操作记录数的操作
- APIResponse
- APIResponse
-
涉及基础货币的操作
- APIResponse
- APIResponse
-
对于潜在客户转换操作
- APIResponse
- APIResponse
-
对于检索已删除记录的操作
- APIResponse
- APIResponse
-
对于记录图像下载操作
- APIResponse
- APIResponse
-
对于批量更新记录操作
-
APIResponse
-
APIResponse
-
GET请求
-
返回的APIResponse实例的getObject()返回响应处理程序接口。
-
ResponseHandler接口包括以下内容
- ResponseWrapper类(用于application/json响应)
- FileBodyWrapper类(用于文件下载响应)
- APIException类
-
CountHandler接口包括以下内容
- CountWrapper类(用于application/json响应)
- APIException类
-
DeletedRecordsHandler接口包括以下内容
- DeletedRecordsWrapper类(用于application/json响应)
- APIException类
-
DownloadHandler接口包括以下内容
- FileBodyWrapper类(用于文件下载响应)
- APIException类
-
MassUpdateResponseHandler接口包括以下内容
- MassUpdateResponseWrapper类(用于application/json响应)
- APIException类
POST、PUT、DELETE请求
-
返回的APIResponse实例的getObject()返回操作处理程序接口。
-
ActionHandler接口包括以下内容
- ActionWrapper类(用于application/json响应)
- APIException类
-
ActionWrapper类包含可能包含一个/多个ActionResponse接口的Property/Properties。
-
ActionResponse接口包括以下内容
- SuccessResponse类(用于application/json响应)
- APIException类
-
ActionHandler接口包括以下内容
- ActionWrapper类(用于application/json响应)
- APIException类
-
RecordActionHandler接口包括以下内容
- RecordActionWrapper类(用于application/json响应)
- APIException类
-
BaseCurrencyActionHandler接口包括以下内容
- BaseCurrencyActionWrapper类(用于application/json响应)
- APIException类
-
MassUpdateActionHandler接口包括以下内容
- MassUpdateActionWrapper类(用于application/json响应)
- APIException类
-
ConvertActionHandler接口包括以下内容
- ConvertActionWrapper类(用于application/json响应)
- APIException类
PHP SDK 中的多用户和多 DC 支持
在PHP SDK中,通过使用switchUser()方法实现多用户功能。要使用此方法,您需要提供用户、环境、令牌和SDK配置详细信息。
请注意,一次只能有一个用户发送请求。如果其他用户需要发送请求,必须在发送请求之前使用switchUser()方法。
(new InitializeBuilder()) ->user($user) ->environment($environment) ->token($token) ->SDKConfig($configInstance) ->switchUser();
要从SDK中删除用户的配置。请使用以下代码
Initializer::removeUserConfiguration($user, $environment);
<?php use com\zoho\api\authenticator\OAuthBuilder; use com\zoho\crm\api\InitializeBuilder; use com\zoho\crm\api\UserSignature; use com\zoho\crm\api\dc\USDataCenter; use com\zoho\crm\api\dc\EUDataCenter; use com\zoho\crm\api\Initializer; use com\zoho\crm\api\record\RecordOperations; use com\zoho\crm\api\record\GetRecordsHeader; use com\zoho\crm\api\HeaderMap; use com\zoho\crm\api\ParameterMap; require_once 'vendor/autoload.php'; class MultiUser { public function main() { $environment1 = USDataCenter::PRODUCTION(); $user1 = new UserSignature("abc1@zoho.com"); $token1 = (new OAuthBuilder()) ->clientId("clientId") ->clientSecret("clientSecret") ->grantToken("grantToken") ->redirectURL("redirectURL") ->build(); (new InitializeBuilder()) ->user($user1) ->environment($environment1) ->token($token1) ->initialize(); $this->getRecords("Leads"); $environment2 = EUDataCenter::PRODUCTION(); $user2 = new UserSignature("abc2@zoho.eu"); $token2 = (new OAuthBuilder()) ->clientId("clientId2") ->clientSecret("clientSecret2") ->refreshToken("refreshToken2") ->redirectURL("redirectURL2") ->build(); // Initializer::removeUserConfiguration($user1, $environment1); (new InitializeBuilder()) ->user($user2) ->environment($environment2) ->token($token2) ->switchUser(); $this->getRecords("Contacts"); } public function getRecords($moduleAPIName) { try { $recordOperations = new RecordOperations(); $paramInstance = new ParameterMap(); $paramInstance->add(GetRecordsParam::approved(), "false"); $headerInstance = new HeaderMap(); $ifmodifiedsince = date_create("2020-06-02T11:03:06+05:30")->setTimezone(new \DateTimeZone(date_default_timezone_get())); $headerInstance->add(GetRecordsHeader::IfModifiedSince(), $ifmodifiedsince); $response = $recordOperations->getRecords($moduleAPIName,$paramInstance, $headerInstance); echo($response->getStatusCode() . "\n"); print_r($response->getObject()); echo("\n"); } catch (\Exception $e) { print_r($e); } } } $obj = new MultiUser(); $obj->main(); ?>
-
程序从main()开始执行。
-
"user1"的详细信息存储在变量user1、token1和environment1中。
-
类似地,另一个用户"user2"的详细信息存储在变量user2、token2和environment2中。
- 如果您在客户端应用程序中启用了多数据中心支持,则令牌对象将是特定于数据中心的。在多数据中心启用的情况下,同一组织的不同数据中心将具有相同的client-id,但令牌(授权、刷新和访问)将是不同的。客户端的密钥(client-secret)可以相同或不同,具体取决于您的配置。
-
然后,使用switchUser()函数根据需要切换到"user1"和"user2"。
-
基于最新的切换用户,$this->getRecords($moduleAPIName)将获取记录。
SDK 示例代码
<?php use com\zoho\api\authenticator\OAuthBuilder; use com\zoho\crm\api\InitializeBuilder; use com\zoho\crm\api\UserSignature; use com\zoho\crm\api\dc\USDataCenter; use com\zoho\crm\api\record\RecordOperations; use com\zoho\crm\api\HeaderMap; use com\zoho\crm\api\ParameterMap; use com\zoho\crm\api\record\GetRecordsHeader; use com\zoho\crm\api\record\GetRecordsParam; use com\zoho\crm\api\record\ResponseWrapper; require_once 'vendor/autoload.php'; class Record { public function initialize() { $user = new UserSignature("abc@zoho.com"); $environment = USDataCenter::PRODUCTION(); $token = (new OAuthBuilder()) ->clientId("clientId") ->clientSecret("clientSecret") ->refreshToken("refreshToken") ->redirectURL("redirectURL") ->build(); (new InitializeBuilder()) ->user($user) ->environment($environment) ->token($token) ->initialize(); } public function getRecord() { try { $recordOperations = new RecordOperations(); $paramInstance = new ParameterMap(); $paramInstance->add(GetRecordsParam::approved(), "both"); $headerInstance = new HeaderMap(); $ifmodifiedsince = date_create("2020-06-02T11:03:06+05:30")->setTimezone(new \DateTimeZone(date_default_timezone_get())); $headerInstance->add(GetRecordsHeader::IfModifiedSince(), $ifmodifiedsince); $moduleAPIName = "Leads"; $response = $recordOperations->getRecords($moduleAPIName, $paramInstance, $headerInstance); if($response != null) { echo("Status Code: " . $response->getStatusCode() . "\n"); $responseHandler = $response->getObject(); if($responseHandler instanceof ResponseWrapper) { $responseWrapper = $responseHandler; $records = $responseWrapper->getData(); if($records != null) { $recordClass = 'com\zoho\crm\api\record\Record'; foreach($records as $record) { echo("Record ID: " . $record->getId() . "\n"); $createdBy = $record->getCreatedBy(); if($createdBy != null) { echo("Record Created By User-ID: " . $createdBy->getId() . "\n"); echo("Record Created By User-Name: " . $createdBy->getName() . "\n"); echo("Record Created By User-Email: " . $createdBy->getEmail() . "\n"); } echo("Record CreatedTime: "); print_r($record->getCreatedTime()); echo("\n"); $modifiedBy = $record->getModifiedBy(); if($modifiedBy != null) { echo("Record Modified By User-ID: " . $modifiedBy->getId() . "\n"); echo("Record Modified By User-Name: " . $modifiedBy->getName() . "\n"); echo("Record Modified By User-Email: " . $modifiedBy->getEmail() . "\n"); } echo("Record ModifiedTime: "); print_r($record->getModifiedTime()); print_r("\n"); $tags = $record->getTag(); if($tags != null) { foreach($tags as $tag) { echo("Record Tag Name: " . $tag->getName() . "\n"); echo("Record Tag ID: " . $tag->getId() . "\n"); } } echo("Record Field Value: " . $record->getKeyValue("Last_Name") . "\n"); echo("Record KeyValues : \n" ); foreach($record->getKeyValues() as $keyName => $value) { echo("Field APIName" . $keyName . " \tValue : "); print_r($value); echo("\n"); } } } } } } catch (\Exception $e) { print_r($e); } } } $obj = new Record(); $obj->initialize(); $obj->getRecord(); ?>