loyaltycorp/sdkblueprint

此包已被废弃且不再维护。作者建议使用 eonx-com/sdkblueprint 包。

一个用于快速构建RESTful API SDK的库

安装: 325

依赖关系: 0

建议者: 0

安全: 0

星标: 0

关注者: 9

分支: 0

开放问题: 0

类型:package

v1.0.0-beta6 2019-09-24 05:41 UTC

README

提供基础代码以开发PHP SDK的包。

内容

入门
SDK功能
使用SDK
错误和异常

入门

要求

在安装SDK之前,您的系统必须满足以下要求

  1. PHP >= 7.1
  2. php-dom
  3. php-json
  4. php-mbstring
  5. allow_url_fopen 必须在您的 php.ini 文件中启用

安装

SDK通过composer安装

$ composer require loyaltycorp/sdkblueprint

SDK功能

SDK提供了一些全局功能以辅助开发。文档将使用一些SDK特定术语,这些术语在本节中进行了描述。

集合和存储库

SDK广泛使用集合和存储库来存储和检索数据

  • 集合用于包含数组的非关联数组
  • 存储库用于关联数组

集合和存储库有助于避免常见的运行时错误,例如在数组上发生 Undefined index 或当期望对象时出现 Trying to get property of non-object

扩展功能

集合和存储库包含一些扩展功能,这些功能允许更简单地访问项目

方法 返回 描述
__toString() string 项目以JSON格式
count() int 集合/存储库中的项目数
first() mixed 集合/存储库中的第一个项目
getNth(int) mixed 集合/存储库中的第n个项目
last() mixed 集合/存储库中的最后一个项目
toArray() array 递归地将所有集合/存储库解析为数组

集合和存储库都将自动将子数组转换为集合或存储库。

集合和存储库还实现了Traversable接口,允许它们像标准数组一样通过循环迭代。

集合

集合是一个具有扩展功能的非关联数组。

如果使用关联数组实例化集合,将抛出InvalidCollectionException异常。应使用关联数组使用存储库。

集合引用

对于集合,first()getNth()last()将返回项目引用,这允许就地更新。集合还有一个deleteNth()方法,用于从集合中删除一个项目,以及clear()方法,用于从集合中删除所有项目。

$collection = new \LoyaltyCorp\SdkBlueprint\Sdk\Collection([
	new \LoyaltyCorp\SdkBlueprint\Sdk\Repository(['name' => 'One']),
	new \LoyaltyCorp\SdkBlueprint\Sdk\Repository(['name' => 'Two']),
	new \LoyaltyCorp\SdkBlueprint\Sdk\Repository(['name' => 'Three']),
]);

$collection->toArray();
// 0 => ['name' => 'One']
// 1 => ['name' => 'Two']
// 2 => ['name' => 'Three']

// Get second item and update name
$second = $collection->getNth(2);
$second->getName(); // Two
$second->setName('Updated');
$collection->toArray();
// 0 => ['name' => 'One']
// 1 => ['name' => 'Updated']
// 2 => ['name' => 'Three']

// Remove first item, note that keys reset after deletion
$collection->deleteNth(1);
$collection->toArray();
// 0 => ['name' => 'Updated']
// 1 => ['name' => 'Three']

// References are chainable with repository functionality
$collection->first()->setName('First');
$collection->toArray();
// 0 => ['name' => 'First']
// 1 => ['name' => 'Three']

// Remove all items from collection
$collection->clear();
$collection->toArray();
//

存储库

存储库是一个具有扩展功能的关联数组容器。

存储库有四个用于访问数据的魔术方法

方法 返回 描述
getX() mixed 获取存储库中的属性值,如果未设置值则返回null
hasX() bool 如果存储库中存在具有非null值的属性,则返回true
isX() bool 专门用于布尔值,如果属性的值是真值,则返回true,否则返回false
setX(mixed) 存储库 在存储库中设置值。此方法可链式调用

如果使用无效属性使用魔术方法,例如不存在或无法设置的属性(如果尝试设置不可变的属性),将抛出UndefinedMethodException异常。

属性转换

属性以原始键存储,但魔术方法需要使用 StudlyCase 来访问数据

原始 Studly 示例
userid Userid getUserid()
user_id UserId getUserId()
userID UserId getUserId()

将存储库转换回数组时,将恢复原始键。

实体和资源

SDK使用实体和资源与API交互。

注意:实体和存储库上大多数不返回值的方法(如getX()hasX())是可链式的。

实体

实体表示API中的单个项目,例如客户。所有实体都扩展存储库,以便利用魔术获取器和设置器

属性和继承

实体提供一些属性来配置其行为,您可以直接设置属性值,如下所示

class MyEntity extends Entity 
{
    /**
     * MyEntity constructor
     *
     * @param null|array $data
     */
    public function __construct(?array $data = null)
    {
        // Property value set directly in constructor
        $this->attributes = [ 
            //... 
        ];
    }
}

或者,您可以定义属性的设置函数。该函数必须返回一个数组,否则将抛出异常。定义函数如下

class MyEntity extends Entity 
{
    /**
     * Returns entity attributes as an array.
     *
     * @return array
     */
    protected function setAttributes(): array
    {
        return [
            //... 
        ];
    }
}

这种方式设置属性值允许您使用继承来覆盖/扩展父级的属性值,如下所示

class MyEntity extends Entity 
{
    /**
     * Returns entity attributes as an array.
     *
     * @return array
     */
    protected function setAttributes(): array
    {
        return \array_merge(parent::setAttributes(), [
            //... 
        ]);
    }
}

以下是属性及其关联设置函数的列表

属性 设置器 描述
$attributes setAttributes():array 用于从实体构建请求的属性列表
$endpoints setEndpoints(): array 实体管理的URL列表
$endpointVersions setEndpointVersions(): array 特定端点的版本列表
$mappings setMappings(): array 将键与关联的存储库映射以解析响应内容
$mutable setMutable(): 数组 可以更新的属性列表
$repositories setRepositories(): 数组 实体的子存储库列表
$rules setRules(): 数组 实体的属性验证规则列表

资源

资源表示一组项目,例如客户。资源具有分页和过滤结果的功能

方法 默认 描述
limit(int) 100 返回的结果数量
page(int) 1 要获取的页
whereX(string) n/a 设置过滤器值

whereX() 方法与存储库上的获取器和设置器相同,并接受一个字符串值。

目前,过滤器仅适用于精确匹配,且区分大小写,例如 whereName('Bob')whereName('bob') 不同,API 将返回不同的结果。修饰符也不能用于查找大于或小于的值,传递给过滤器的值始终被解释为等于。

与其他魔法方法一样,如果属性无效,该方法将抛出 UndefinedMethodException

验证

实体和资源提供了一种简单的方法来实现处理请求之前的验证,以避免任何无效数据的 API 调用。验证通过在键中定义的 2 层深关联数组来定义,键是应用验证的 HTTP 方法,值是另一个数组,定义了每个属性的验证,如下所示

protected $rules = [
    'get' => [<attribute> => <rules>], // Apply validation to GET
    'post,put' => [<attribute> => <rules>] // Apply validation to POST and PUT
];

要为实体定义验证规则,您必须使用前面描述的验证规则数组覆盖 $rules 属性。如果您的验证规则定义需要更多的逻辑,而您无法通过属性执行,您可以定义 getValidationRules(): array 函数,该函数返回验证规则数组,如下所示

protected function setRules(): array
{
    return [
        'get' => [<attribute> => <rules>], // Apply validation to GET
        'post,put' => [<attribute> => <rules>] // Apply validation to POST and PUT
    ];
}
验证规则
名称 语法 描述
Email email 验证给定值是否为有效的电子邮件地址
实体 entity 验证给定值是否为 LoyaltyCorp\SdkBlueprint\Sdk\Entity 的实例
Enum enum:val1,val2,val3 验证给定值是否为配置的值之一
GreaterThan greaterThan: 验证给定值是否大于配置的整数
GreaterThanOrEqualTo greaterThanOrEqualTo: 验证给定值是否大于或等于配置的整数
Instance instance: 验证给定值是否为配置类的实例
Integer integer 验证给定值是否为整数
Length length: 验证给定值长度等于配置的整数
LessThan lessThan: 验证给定值低于配置的整数
LessThanOrEqualTo lessThanOrEqualTo: 验证给定值低于或等于配置的整数
MaxLength maxLength: 验证给定值长度低于或等于配置的整数
MinLength minLength: 验证给定值长度大于或等于配置的整数
NotEmpty notEmpty 验证给定值不为空
Numeric numeric 验证给定值是否为数值
Regex regex: 验证给定值是否与配置的正则表达式匹配
Required required 验证值已提供,保留零值和空数组
RequiredWith requiredWith:attr1,attr2,attrN... 验证如果配置的属性之一已提供,则值已提供
必需的(无提供) requiredWithout:attr1,attr2,attrN... 如果没有为当前属性提供值,验证配置的属性中至少有一个提供了值
类型 type:,... 验证给定值的类型与配置的类型(们)相同
URL url 验证给定值是否为有效的URL

响应

除非抛出预请求异常,否则SDK接收到的响应总是标准化的。即使API收到错误或Guzzle引发异常,也会发生这种情况。

每个响应都至少包含4个属性

属性 类型 描述
code int API返回的代码
message string API返回的错误或成功消息
status_code int 响应中的HTTP状态码
successful bool 请求是否成功

成功的响应还将包括一个或多个属性,用于访问API返回的数据,具体请参阅端点特定文档。

验证响应

响应包含一个isSuccessful()方法,应使用此方法验证请求是否成功。即使返回错误,即使带有成功的HTTP状态码,此方法也是正确设置的。

实现SDK

这将提供一个关于如何实现SDK的基本概述。

定义你的实体和资源

首先要做的是创建你的实体和资源对象。确保它们分别扩展了LoyaltyCorp\SdkBlueprint\Sdk\EntityLoyaltyCorp\SdkBlueprint\Sdk\Resource

定义你的响应

一旦定义了实体和资源,创建你的响应对象,它扩展了LoyaltyCorp\SdkBlueprint\Sdk\Response并通过其$repositories属性定义了实体映射。

实例化客户端

您可以直接使用响应对象实例化客户端。

$client = new \LoyaltyCorp\SdkBlueprint\Sdk\Client($response);
高级用法
设置基本URL

默认情况下,URL是http://localhost,如果您想使用另一个URL,可以实例化\LoyaltyCorp\SdkBlueprint\Sdk\Parsers\JsonRequestParser对象,调用其上的setBaseUrl(string $baseUrl),并将其作为客户端构造函数的第二个参数传递。

$requestParser = new JsonRequestParser();
$requestParser->setBaseUrl('https://api.loyaltycorp.com.au');

$client = new \LoyaltyCorp\SdkBlueprint\Sdk\Client($response, $requestParser);

URL必须是有效的,如果提供了无效的URL,将抛出InvalidBaseUrlException

自定义响应体格式

客户端使用一个实现\LoyaltyCorp\SdkBlueprint\Sdk\Interfaces\ResponseParserInterface的对象来解析来自API的响应体。默认的ResponseParser使用内置的json_decode()函数,如果您想使用其他解析逻辑,可以创建一个新的实现ResponseParserInterface的对象,并将其作为第三个参数传递给客户端构造函数。

$responseParser = new MyCustomerResponseParser();

$client = new \LoyaltyCorp\SdkBlueprint\Sdk\Client($response, $requestParser, $responseParser);
自定义Guzzle客户端

您可以将Guzzle客户端实例传递给SDK客户端构造函数。如果您在应用程序中使用的现有客户端具有增强的日志记录、调试、连接要求或错误处理,这将非常有用。

$guzzle = new \GuzzleHttp\Client(['proxy' => '192.168.16.1:10']);
$client = new \EoneoPaySdk\Client($response, $requestParser, $responseParser, $guzzle);

发起请求

所有请求都是通过将实体或资源传递到EoneoPay SDK客户端实例中的方法来发起的。客户端有四种与API交互的方法

方法 描述
create(entity) 创建实体
delete(entity) 删除实体
get(entity) 获取实体
list(resource) 获取资源的所有实体
update(entity) 更新实体

并非所有实体都支持所有CRUD方法,如果实体不支持特定的方法,将抛出MethodNotSupportedException异常。

每个端点的文档中提供了每个请求的示例代码。

现有实体

某些方法需要现有实体来执行操作。现有实体可以是以下之一:

  • 通过按id获取方法检索到的实体
  • 之前已创建并存储的实体
  • 之前已检索并存储的实体

现有实体必须是正确的类,如果您存储的是实体数据而不是实体本身,您必须首先使用存储的数据实例化实体。

错误和异常

错误

API返回的错误将通过Response实例优雅地处理。

如果发生错误,则响应将:

  • 没有实体/资源特定的属性
  • 通过isSuccessful()返回false
  • 通过getCode()返回API错误代码
  • 通过getMessage()返回API错误消息
  • 通过getStatusCode()返回HTTP状态代码

异常

如果出现问题,将抛出异常

异常 原因
AttributeNotSetException 请求需要一个不存在的值,例如在没有将其附加到客户的情况下添加银行账户
EndpointValidationFailedException 请求的实体在请求之前的验证失败
InvalidBaseUrlException 设置的base url不是一个有效的url
InvalidCollectionException 使用无效数据实例化了集合
InvalidConfigurationException API密钥缺失或未从.env文件中加载
InvalidEntityException 使用无效数据实例化了实体
InvalidEntityConnectionException 尝试连接到不兼容的实体
InvalidValueFromSetterException 实体定义了不返回预期类型的魔法setter函数
MethodNotSupportedException 尝试在不支持它的实体上调用方法,例如在只支持get的实体上调用create
UndefinedMethodException 在存储库上调用无效的魔法方法,或者在魔法方法中使用的属性不存在或不可变