scriptotek / alma-client
与一些Alma API交互的包
Requires
- php: >=7.1
- ext-json: *
- danmichaelo/quitesimplexmlelement: ^1.0
- http-interop/http-factory-discovery: ^1.4
- php-http/client-common: ^1.9 || ^2.0
- psr/http-client-implementation: ^1.0
- psr/http-factory-implementation: ^1.0
- psr/http-message: ^1.0
- scriptotek/marc: ^2.0 || dev-master
- scriptotek/sru-client: ^0.7
- symfony/polyfill-php73: ^1.11
Requires (Dev)
- bossa/phpspec2-expect: ^2.1 || ^3.0
- http-interop/http-factory-guzzle: ^1.0
- php-http/guzzle6-adapter: ^1.1 || ^2.0
- php-http/mock-client: ^1.0
- phpspec/phpspec: ^5.0 || ^6.0
- squizlabs/php_codesniffer: ^3.3
- wp-cli/php-cli-tools: ^0.11.1
README
php-alma-client
一个简单的PHP包,用于处理Alma REST APIs。不支持SOAP API。目前,此包支持Bibs(读写)、用户和数据分析(只读)。它集成了php-marc以编辑MARC记录。如果此包不符合您的需求,您可以查看替代的php-alma包。
目录
- 使用Composer安装
- 初始化客户端
- 快速入门
- 关于延迟加载和存在检查的说明
- Bibs:书目记录、馆藏、表示、组合
- 用户、借阅、费用和请求
- 分析报告
- 任务列表
- 作业
- 错误自动重试
- Laravel集成
- 未来计划
由 gh-md-toc 创建
使用Composer安装
使用 Composer 安装带有HTTP库(如Guzzle)的sru-client
composer require scriptotek/alma-client php-http/guzzle6-adapter http-interop/http-factory-guzzle
我们使用 HTTP发现 来发现 HTTP客户端 和 HTTP工厂 实现,因此Guzzle可以与其他任何 PSR-17/PSR-18-兼容的库交换。
初始化客户端
首先,使用您在 Ex Libris开发者网络 获取的API密钥启动新的客户端
require_once('vendor/autoload.php'); use Scriptotek\Alma\Client as AlmaClient; use Scriptotek\Sru\Client as SruClient; $alma = new AlmaClient('MY_SECRET_API_KEY', 'eu');
其中 'eu'
是欧洲的地区代码(使用 'na'
表示北美或 'ap'
表示亚太地区)。默认情况下,API入口点URL根据地区代码生成,但如果您通过代理连接到API,则可以配置不同的URL
$alma = new AlmaClient('MY_SECRET_API_KEY')
->setEntryPoint('https://gw-uio.intark.uh-it.no/alma/v1');
如果您的Alma实例连接到网络区域,并且您想要处理那里的Bibs记录,您还可以添加网络区域的API密钥
$alma->nz->setKey('MY_SECRET_NETWORK_ZONE_API_KEY');
如果您需要搜索支持,请连接 SRU客户端
$alma->setSruClient(new SruClient( 'https://bibsys-k.alma.exlibrisgroup.com/view/sru/47BIBSYS_UBO', ['version' => '1.2'] ));
您还可以将SRU客户端连接到网络区域SRU服务
$alma->nz->setSruClient(new SruClient( 'https://bibsys-k.alma.exlibrisgroup.com/view/sru/47BIBSYS_NETWORK', ['version' => '1.2'] ));
快速入门
该库通过 $alma->bibs
、用户($alma->users
)、分析报告($alma->analytics
)、图书馆($alma->libraries
)、任务列表($alma->taskLists
)和作业($alma->jobs
)提供对Bibs、馆藏和项目的访问。
获取Bib记录
$bib = $alma->bibs->get('990114012304702204');
关于延迟加载和存在检查的说明
懒加载:注意客户端使用懒加载来减少HTTP请求的数量。当实例化对象时不会发出请求,而是在请求数据时才会发出请求。因此,在这种情况下,第一次调用getRecord()
时才会发出获取持证记录的HTTP请求。然后,响应会被缓存在对象中以供重用。同样,在这种情况下,不会为Bib记录发出HTTP请求,因为我们没有从该记录请求任何数据。
通常情况下,图书馆会延迟加载数据,直到实际需要时,这种做法称为懒加载。这意味着您可以初始化一个Bib
对象,并回显MMS ID,而不需要进行任何网络请求,因为目前尚不需要获取任何数据。
$bib = $alma->bibs->get('9901140123047044111'); echo $bib->mms_id;
如果您请求Bib对象上的其他任何内容,例如标题,数据将自动从网络上获取并填充到对象中。
echo $bib->title;
如果资源不存在,此时会抛出ResourceNotFound
异常。因此,您可以像这样处理该情况。
$bib = $alma->bibs->get('9901140123047044111'); try { echo $bib->title; } catch (\Scriptotek\Alma\Exception\ResourceNotFound $exc) { // Handle the case when the record doesn't exist }
但您也可以使用exists()
方法,这通常更方便。
$bib = $alma->bibs->get('9901140123047044111'); if (!$bib->exists()) { // Handle the case when the record doesn't exist }
Bibs:书目记录、馆藏、表示、组合
获取单个记录
可以通过MMS ID或条形码来获取书目记录。
$bib = $alma->bibs->get('990114012304702204');
或通过条形码
$bib = $alma->bibs->fromBarcode('92nf02526');
注意:如果找不到条形码,此方法和下面的两个方法都会返回null。
此外,还有两个使用SRU搜索的查找方法,要求您已连接SRU客户端。第一个允许您使用通用的CQL查询。
$bib = $alma->bibs->findOne('alma.all_for_ui="9788299308922"');
第二个是查找ISBN记录的简称。
$bib = $alma->bibs->fromIsbn('9788299308922');
上述所有方法都返回单个Bib
记录,如果未找到则返回null
。
MARC21记录
MARC21记录以$bib->record
的形式作为php-marc
Record
对象提供,该对象扩展自File_MARC_Record
,这意味着您可以使用所有File_MARC方法以及php-marc的便利方法。
搜索记录
如果您已连接SRU客户端(如上所述),可以使用CQL搜索语法进行搜索。
foreach ($alma->bibs->search('alma.dewey_decimal_class_number=530.12') as $bib) { $marcRecord = $bib->record; echo "$marcRecord->id: $marcRecord->title\n"; }
从网络区域获取相关记录
如果您已配置网络区域API密钥(见上),可以轻松获取与机构区域记录连接的网络区域记录。
$nzBib = $bib->getNzRecord();
编辑记录
可以使用File_MARC_Record
接口(见File_MARC文档)编辑MARC21记录,然后使用Bib
对象的save()
方法将其保存回Alma。以下示例中,我们删除了一个主题标题并添加了另一个。
$bib = $alma->bibs->get('990114012304702204'); foreach ($bib->record->getSubjects() as $subject) { if ($subject->vocabulary == 'noubomn' && (string) $subject == 'Boating with dogs') { $subject->delete(); } } $bib->record->appendField(new File_MARC_Data_Field('650', [ new File_MARC_Subfield('a', 'Boating with cats'), new File_MARC_Subfield('2', 'noubomn'), ], null, '0')); $bib->save();
馆藏和项目
Bib
对象通过holdings
迭代器提供对馆藏的简单访问。
$bib = $alma->bibs->get('990310361044702204'); foreach ($bib->holdings as $holding) { echo "{$holding->holding_id} {$holding->call_number}"; }
与Bib
对象一样,Holding
对象的MARC记录可以通过getRecord()
方法或record
属性获取。
$holding = $alma->bibs['990310361044702204']->holdings['22102913020002204']; $marcRecord = $holding->record;
注意:编辑馆藏记录尚不支持。将在未来添加。
可以以与从Bib获取馆藏相同的方式列出项目。
$bib = $alma->bibs->get('990310361044702204'); foreach ($bib->holdings as $holding) { foreach ($holding->items as $item) { echo "{$item->holding_id} {$item->pid} {$item->barcode} : "; echo "{$item->location->desc} {$item->call_number} : "; echo "{$item->base_status->desc} {$item->process_type->desc}"; echo "\n"; } }
在这种情况下,客户端发出一个请求来获取馆藏列表,然后对每个馆藏发出一个请求来获取项目。
通过条形码获取项目
有一个特殊的入口点可以按条形码检索项目。
$item = $alma->items->fromBarcode('92nf02526');
电子组合和集合
电子组合和集合以与馆藏相同的方式在Bib
对象上提供。
$bib = $alma->bibs->get('990310361044702204'); foreach ($bib->portfolios as $portfolio) { echo "{$portfolio->portfolio_id} {$portfolio->electronic_collection->service->link} "; echo "{$portfolio->electronic_collection->public_name}\n"; }
$bib = $alma->bibs->get('990310361044702204'); foreach ($bib->electronic_collections as $collection) { echo "{$collection->public_name}"; }
数字表示和文件
$bib = $alma->bibs->get('990310361044702204'); foreach ($bib->representations as $rep) { echo "{$rep->representation_id} {$rep->label}\n"; foreach ($rep->files as $rep_file) { echo "{$rep_file->label} {$rep_file->thumbnail_url}\n"; } }
用户、借阅、费用和请求
注意:编辑尚未实现。
搜索
示例
foreach ($alma->users->search('last_name~Heggø AND first_name~Dan') as $user) { echo "{$user->first_name} {$user->last_name} ({$user->primary_id})\n"; }
借阅
示例
foreach ($user->loans as $loan) { echo "{$loan->due_date} {$loan->title}\n"; }
注意,$user->loans
是一个迭代器。要获取数组,可以使用iterator_to_array($user->loans)
。
费用
示例
printf('Total: %s %s', $user->fees->total_sum, $user->fees->currency); foreach ($user->fees as $fee) { echo "{$fee->type->value}\t{$fee->balance}\t{$fee->title}\n"; }
请求
示例
foreach ($user->requests as $request) { echo json_encode($request, JSON_PRETTY_PRINT); }
也可以从Bib
对象或Item
对象检索请求。
分析报告
要从单个报告中检索结果
$report = $alma->analytics->get('/shared/Alma/Item Historical Events/Reports/Items went into temporary location'); foreach ($report as $row) { echo implode("\t", $row) . "\n"; }
行通过一个生成器返回,该生成器负责检索更多行直到结果集耗尽,因此您无需考虑继续。如果您只想获取部分行,您必须自己退出循环。
列名
列名可以通过 headers
访问
$report = $alma->analytics->get('/shared/Alma/Item Historical Events/Reports/Items went into temporary location'); foreach ($report->headers as $header) { echo "$header\n"; }
列名也可以用来访问特定行的列
foreach ($report as $row) { echo $row['Title'] . "\n"; }
如果您想使用与Analytics中定义的不同列名,也可以通过传递一个数组来覆盖它们,该数组必须遵循报告中列的相同顺序
$report = $alma->analytics->get( '/shared/Alma/Item Historical Events/Reports/Items went into temporary location', [ 'mms_id', 'receiving_date', ] ); foreach ($report->rows as $row) { echo $row->mms_id . ": " . $row->receiving_date . "\n"; }
过滤器
此方法还接受一个过滤器。
$report = $alma->analytics->get( '/shared/Alma/Item Historical Events/Reports/Items went into temporary location', [ 'mms_id', 'receiving_date', ], '<sawx:expr op="greaterOrEqual" xsi:type="sawx:comparison" xmlns:sawx="com.siebel.analytics.web/expression/v1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <sawx:expr xsi:type="sawx:sqlExpression">"Physical Item Details"."Receiving Date"</sawx:expr> <sawx:expr xsi:type="sawx:sqlExpression">TIMESTAMPADD(SQL_TSI_DAY, -1, CURRENT_DATE)</sawx:expr> </sawx:expr>', ); foreach ($report->rows as $row) { echo $row->mms_id . ": " . $row->receiving_date . "\n"; }
关于过滤器的官方文档不多,API的错误响应通常也不太有用,但这篇博客文章中提供了一些有用的提示。
我的经验是,在报告中包含一个“被提示”的过滤器是非常必要的。否则,查询将返回一个 400 No more rows to fetch
(经过长时间的等待)。
此外,我使用纯SQL过滤器没有成功。在OBI中,您可以将过滤器转换为SQL。结果看起来像这样
<sawx:expr xmlns:saw="com.siebel.analytics.web/report/v1.1" xmlns:sawx="com.siebel.analytics.web/expression/v1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="sawx:sawx:sql">"Physical Item Details"."Receiving Date" >= TIMESTAMPADD(SQL_TSI_DAY, -1, CURRENT_DATE)</sawx:expr>
但是与API一起使用时,响应与忘记包含“被提示”过滤器时的响应相同:长时间的等待后,出现“400 No more rows to fetch”。
任务列表
借阅请求
$library = $alma->conf->libraries['LIBRARY_CODE']; $requests = $alma->taskLists->getLendingRequests($library, [ 'printed' => 'N', 'status' => 'REQUEST_CREATED_LEND', ]); foreach ($requests as $request) { echo "- {$request->request_id} {$request->status}\n"; }
注意:截至2018-10-13,有一个bug阻止您检索超过100个借阅请求。
请求的资源(从书架上选择)
$library = $alma->libraries['LIBRARY_CODE']; $requests = $alma->taskLists->getRequestedResources($library, 'DEFAULT_CIRC_DESK', [ 'printed' => 'N', ]); foreach ($requests as $request) { echo "- {$request->resource_metadata->title} {$request->resource_metadata->mms_id->value}\n"; }
作业
列出作业
列出所有作业及其实例
foreach ($alma->jobs as $job) { echo "[{$job->id}] {$job->name} / {$job->description}\n"; foreach ($job->instances as $instance) { echo " [{$instance->id}] Status: {$instance->status->desc}\n"; } }
这是一个生成器,因此您可以在完整列表检索到之前开始处理结果(它以10个作业的批次检索作业)。
检索特定作业的信息
$job = $alma->jobs['M43'];
提交作业
$instance = $alma->jobs['M43']->submit();
错误自动重试
如果客户端从Alma收到429(速率限制)响应,它将默认暂停一段时间(默认为0.5秒)并重试请求一个可配置的次数(默认为10次),然后放弃并抛出 Scriptotek\Alma\Exception\MaxNumberOfAttemptsExhausted
。最大尝试次数和暂停时间都可以配置。
$client->maxAttempts = 5; $client->sleepTimeOnRetry = 3; // seconds
如果客户端收到5XX服务器错误,它默认不会重试请求,但这可以配置。当检索大型Analytics报告时,这可能很有用,因为这些报告有间歇性失败的趋势。
$client->maxAttemptsOnServerError = 10; $client->sleepTimeOnServerError = 10; // seconds
当重试次数耗尽时,将抛出 Scriptotek\Alma\Exception\RequestFailed
异常。
Laravel集成
此项目包含一个可自动发现的ServiceProvider和Facade。运行
$ php artisan vendor:publish --provider="Scriptotek\Alma\Laravel\ServiceProvider"
以创建 config/alma.php
配置文件。
如果您使用的是Laravel 5.4或更早版本,您必须手动将ServiceProvider添加到您的 config/app.php
中的 $providers
数组。
Scriptotek\Alma\Laravel\ServiceProvider::class,
以及Facade
'Alma' => Scriptotek\Alma\Laravel\Facade::class,
自定义HTTP客户端堆栈
如果Laravel的Service Container包含一个绑定到 Psr\Http\Client\ClientInterface
的PSR-18 HTTP客户端,Alma Client将使用该实现而不是实例化自己的HTTP客户端。
以下是一个示例ServiceProvider,它使用php-http/client-common的一些中间件注册了一个HTTP客户端
<?php namespace App\Providers; use Http\Client\Common\Plugin\ContentLengthPlugin; use Http\Client\Common\Plugin\ErrorPlugin; use Http\Client\Common\Plugin\RetryPlugin; use Http\Client\Common\PluginClient; use Http\Factory\Discovery\HttpClient; use Illuminate\Support\ServiceProvider; use Psr\Http\Client\ClientInterface; class HttpServiceProvider extends ServiceProvider { public function register() { $this->app->singleton(ClientInterface::class, function($app) { return new PluginClient( HttpClient::client(), [ new ContentLengthPlugin(), new RetryPlugin([ 'retries' => 10, ]), new ErrorPlugin(), ] ); }); } }
未来计划
- 更好的编辑支持,可能更好地与php-marc包集成以提供流畅的编辑界面
$bib = $alma->bibs->get('990114012304702204'); // a Bib object $bib->record->subjects->add([ 'term' => 'Boating with cats', 'vocabulary' => noubomn' ]); $bib->save()
- 支持创建记录和用户
$bib = new Bib(); $alma->bibs->store($bib);