loyaltycorp / sdkblueprint
Requires
- php: >=7.1
- ext-dom: *
- ext-json: *
- ext-libxml: *
- ext-mbstring: *
- ext-simplexml: *
- doctrine/annotations: ^1.6
- doctrine/cache: ^1.7
- eoneopay/utils: ^0.2
- guzzlehttp/guzzle: ^6.0
- symfony/expression-language: ^4.1
- symfony/intl: ^4.1
- symfony/property-access: ^4.1
- symfony/property-info: ^4.1
- symfony/serializer: ^4.1
Requires (Dev)
- eoneopay/standards: dev-master
- friendsofphp/php-cs-fixer: ^2.9
- indigophp/doctrine-annotation-autoload: ^0.1.0
- php-http/guzzle6-adapter: ^1.1
- phpmd/phpmd: ^2.6
- phpstan/phpstan: ^0.11
- phpstan/phpstan-phpunit: ^0.11
- phpstan/phpstan-strict-rules: ^0.11
- phpunit/phpunit: ^7.0
- roave/security-advisories: dev-master
- sebastian/phpcpd: ^4.0
- squizlabs/php_codesniffer: 3.*
- woohoolabs/yang: ^1.2
Suggests
- sensiolabs/security-checker: Check project's dependencies for known vulnerabilities
This package is auto-updated.
Last update: 2019-11-20 02:24:59 UTC
README
提供基础代码以开发PHP SDK的包。
内容
入门
SDK功能
使用SDK
错误和异常
入门
要求
在安装SDK之前,您的系统必须满足以下要求
- PHP >= 7.1
- php-dom
- php-json
- php-mbstring
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 |
验证给定值是否为有效的电子邮件地址 | |
实体 | 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\Entity
和LoyaltyCorp\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 |
在存储库上调用无效的魔法方法,或者在魔法方法中使用的属性不存在或不可变 |