robgridley / pace-api
EFI Pace API 客户端
Requires
- php: >=7.1.0
- ext-fileinfo: *
- ext-soap: *
- doctrine/inflector: ^1.4 || ^2.0
- nesbot/carbon: ^1.20 || ^2.0
Requires (Dev)
- mockery/mockery: ^1.3
- phpunit/phpunit: ^8.5
- symfony/var-dumper: ^5.0
README
这是一个非官方的PHP客户端库,用于EFI Pace的SOAP API,由一名Pace管理员和PHP开发者创建。此库对一些约定进行了假设,以使您的使用更加方便。
安装
通过 Composer 安装
$ composer require robgridley/pace-api
测试
为 Model
、KeyCollection
和 XPath\Builder
类提供100%代码覆盖率的PHPUnit测试。
运行测试
$ composer test
待办事项
- 为剩余的类编写测试
- 实现剩余的Pace服务(例如“InvokeProcess”)
配置
您需要创建一个带有“允许远程API使用”启用的Pace系统用户。
use Pace\Client as Pace; use Pace\Soap\Factory as SoapFactory; $pace = new Pace(new SoapFactory(), 'epace-staging.domain.com', 'apiuser', 'apipassword');
CRUDD
创建对象
要创建 Pace 中的新对象,从 Pace 客户端获取模型,设置其属性,然后调用 save()
方法。您可以通过调用 model()
方法或使用动态属性来检索模型实例。
$csr = $pace->model('CSR'); // or the shorter, prettier: $csr = $pace->csr; $csr->name = 'John Smith'; $csr->email = 'jsmith@domain.com'; $csr->save();
读取对象
您可以通过主键读取对象,这将返回一个单独的模型。
$csr = $pace->csr->read(1); echo $csr->email; // prints "jsmith@domain.com"
复合键由冒号分隔。
$jobPart = $pace->jobPart->read('12345:01');
更新对象
除了创建对象外,save()
方法还用于更新现有对象。
$csr = $pace->csr->read(1); $csr->active = false; $csr->save();
复制对象
要复制现有对象,首先加载现有对象,可选地修改其属性,然后调用 duplicate()
方法。将返回一个新的模型实例,并将现有模型恢复到其原始状态。
duplicate()
方法接受一个可选参数:新的主键值。如果您不提供主键,则 Pace 在大多数情况下会自动递增。
$csr = $pace->csr->read(1); $csr->name = 'Jane Smith'; $newCsr = $csr->duplicate(); echo $csr->name; // prints "John Smith" echo $newCsr->name; // prints "Jane Smith"
删除对象
delete()
方法接受一个可选参数:模型的唯一键名称。如果没有提供,它将进行猜测。
$csr = $pace->csr->read(1); $csr->delete();
查找对象
基础
Pace的Web服务使用XPath表达式来查找对象。包含的XPath.Builder
类负责将PHP原生类型转换为XPath表达式,并使您的过滤器更易于阅读(在PHP编辑器中)。
查找多个对象
$jobs = $pace->job ->filter('adminStatus/@openJob', true) ->filter('@jobType', 1) ->find();
上述操作返回一个模型集合。
查找单个对象
$csr = $pace->csr->filter('@name', 'Jane Smith')->first();
上述操作返回单个模型实例。
运算符
客户端支持 Pace 支持的所有运算符:=
、!=
、<
、>
、<=
、>=
。还支持 startsWith()
和 contains()
。
$millionPlus = $pace->salesPerson->filter('@annualQuota', '>=', 1000000)->find(); $coated = $pace->inventoryItem->contains('@description', 'C2S')->find(); $tango = $pace->inventoryItem->startsWith('@description', 'Tango')->find();
分组过滤器
有时您可能需要分组过滤器以创建更复杂的条件。
$customers = $pace->customer ->filter('@state', 'ON') ->filter(function ($xpath) { $xpath->filter('@city', 'Toronto'); $xpath->orFilter('@city', 'Ottawa'); }) ->find();
如您所见,传递闭包创建一组嵌套的条件。
排序
使用 sort()
方法对结果进行排序。该方法接受两个参数:一个用于指定排序字段的XPath表达式和一个布尔值,用于确定方向,默认值为 false(升序)。您可以链式调用多个排序,尽管我不确定 Pace 是否有限制。
$jobs = $pace->job ->filter('adminStatus/@openJob', true) ->sort('customer/@custName') ->sort('@job', true) ->find();
日期
日期会自动转换为和从 Carbon 实例。如果您想了解这是如何发生的,请查看 Soap\DateTimeMapper
和 Soap\Factory
类。
键集合
查找对象SOAP调用的原始结果是主键数组。模型类会自动将该数组封装在KeyCollection对象中,为您提供一系列便利,并防止不必要的调用读取对象服务,只按需加载模型。
您可以将KeyCollection像数组一样循环遍历。每次迭代时都会加载模型,所以如果例如您退出循环,剩余的模型将不会被加载。
$estimates = $pace->estimate->filter('@entryDate', '>=', Carbon::yesterday())->find(); foreach ($estimates as $estimate) { if ($estimate->enteredBy == 'jsmith') { echo "John has entered an estimate since yesterday!" break; } }
KeyCollection还具有许多有用的方法,如all()
、paginate()
和first()
。事实上,之前单独对象查找的示例只是对KeyCollection::first()
方法的快捷方式。
关系
加载相关模型
您可以通过动态方法自动加载相关模型。
对于“属于”关系,模型属性名和外部模型类型必须匹配。例如,Customer对象有一个名为'csr'的属性,其中包含'CSR'对象类型的主键。
以下返回单个模型。
$customer = $pace->customer->read('HOUSE'); $houseCsr = $customer->csr();
要加载“拥有多个”相关模型,调用外部模型类型的驼峰式复数形式。假设外部模型将父模型的主键存储在以父模型类型命名的属性中。例如,'Job'对象将'Customer'对象的主键存储在名为'customer'的属性中。
以下返回一个XPath\Builder
对象。您可以选择性地添加额外的相关模型过滤器。
$customer = $pace->customer->read('HOUSE'); $houseJobs = $customer->jobs()->filter('@adminStatus', 'O')->get();
如果您发现一个违反常规的对象,可以直接调用公共的belongsTo()
和hasMany()
方法。
以下两个示例是相同的。
$notes = $customer->customerNotes()->get(); $notes = $customer->hasMany('CustomerNote', 'customer', 'id')->get();
在第一个示例中,所有必要的参数都是猜测的。在第二个示例中明确提供了它们。
复合键
已添加对加载具有复合键的相关模型的初始支持。调用hasMany()
或belongsTo()
方法,传递包含字段名称(包含键)并用冒号分隔的字符串。
$jobPart = $pace->jobPart->read('12345:01'); $jobMaterials = $jobPart->hasMany('JobMaterial', 'job:jobPart')->get();
关联相关模型
如果您要关联的模型具有可猜测的主键,则可以将模型作为属性值分配。否则,您需要显式分配主键值。
$batch = $pace->inventoryBatch; $batch->save(); // save the model to generate a primary key $line = $pace->inventoryLine; $line->inventoryBatch = $batch;
事务
您可以将操作包装在数据库事务中,以便在发生错误时回滚所有调用。使用事务的好处是可以将事件处理器推迟到所有API调用完成。
注意:事务服务是在Pace 29.0-1704中引入的。
使用闭包
使用transaction()
方法在数据库事务中执行操作。如果发生服务器端错误,Pace将回滚事务,并且如果抛出PHP异常,API客户端将自动回滚事务。如果闭包执行成功,且没有服务器端错误,则提交事务。
$pace->transaction(function () use ($pace) { $job = $pace->model('Job'); $job->customer = 'HOUSE'; $job->description = 'Test Order'; $job->jobType = 10; $job->adminStatus = 'O'; $job->save(); $jobPart = $job->jobParts()->first(); $jobMaterial = $pace->model('JobMaterial'); $jobMaterial->job = $jobPart->job; $jobMaterial->jobPart = $jobPart->jobPart; $jobMaterial->inventoryItem = 'ABC123'; $jobMaterial->plannedQuantity = 100; $jobMaterial->save(); throw new Exception('Just kidding. Roll it back.'); });
手动使用事务
或者,您可以手动调用startTransaction()
、rollbackTransaction()
和commitTransaction()
方法。
$pace->startTransaction(); $csr = $pace->model('CSR'); $csr->name = 'Definitely Not Evil'; $csr->save(); if ($csr->id == 666) { // Oh no. They are evil! $pace->rollbackTransaction(); } else { $pace->commitTransaction(); }
JSON
Model和KeyCollection类都实现了JsonSerializable
接口,将任一类转换为字符串将生成JSON。
// print a JSON representation of the House account echo $pace->customer->read('HOUSE');
附件
附加文件
要将文件附加到模型,您只需指定其名称和内容。库会处理猜测MIME类型和编码内容。
$job = $pace->model('Job')->read('12345'); $attachment = $job->attachFile('test.txt', file_get_contents('test.txt')); $attachment->description = 'A test file'; $attachment->save();
attachFile()
方法返回FileAttachment模型,您可以设置类别、描述等。只有当您更改任何属性时才调用save()
方法。
您还可以通过指定字段的名称将文件附加到字段。这在整个Pace中用于标志、照片、布局等。
$company = $pace->model('Company')->read('001'); $company->attachFile('logo.png', file_get_contents('logo.png'), 'logo');
检索附加文件
模型关联的文件通过特殊的关系方法检索。它类似于“多对一”关系,并返回一个 XPath.Builder
实例。
$attachments = $job->fileAttachments()->get();
使用 filter()
限制结果到一个字段或一种文件类型。
$logo = $company->fileAttachments()->filter('@field', 'logo')->first(); $spreadsheets = $job->fileAttachments()->filter('@ext', 'xls')->get();
最后,在 FileAttachment 模型上调用 getContent()
以读取文件内容。库会自动为您解码内容。
$attachment->getContent();
报告
使用报告生成器流畅地运行报告。
传递参数
使用 parameter()
或 namedParameter()
方法向报告传递参数。 parameter()
方法接受两个参数:报告参数 ID 和值。
$pace->report(1000) ->parameter(10001, '2019-12-01') ->parameter(10002, '2019-12-31') ->parameter(10003, 'D');
namedParameter()
方法通过名称查找报告参数 ID。
$pace->report(1000) ->namedParameter('Start Date', '2019-12-01') ->namedParameter('End Date', '2019-12-31') ->namedParameter('Report Format', 'D');
需要基础对象的报告
某些报告需要基础对象。使用 baseObjectKey()
方法传递模型或主键。
$job = $pace->model('Job')->read('90000'); $pace->report(100) ->baseObjectKey($job) ->namedParameter('Include Kit Detail', 'N');
获取报告
报告生成器的 get()
方法返回一个 Report\File
实例,它有两个公共方法:getContent()
返回报告文件内容,getMediaType()
返回文件的媒体(MIME)类型。
$file = $pace->report(200)->get(); if ($file->getMediaType() == 'application/vnd.ms-excel') { file_put_contents('report.xls', $file->getContent()); }
打印报告
使用 print()
方法将报告打印到默认打印机。如果报告没有配置默认打印机,Pace API 将抛出 SOAP 错误。
$pace->report(100) ->baseObjectKey('90000') ->namedParameter('Include Kit Detail', 'N') ->print();
版本
识别服务器上运行的 Pace 版本。
$pace->version();
上述将返回
array(4) {
["string"]=>
string(24) "27.12-750 (201512111349)"
["major"]=>
int(27)
["minor"]=>
int(12)
["patch"]=>
int(750)
}